/* * Copyright 2009 NCHOVY * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.krakenapps.pkg; import java.net.MalformedURLException; import java.net.URL; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.UnrecoverableKeyException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import org.krakenapps.api.AlreadyInstalledPackageException; import org.krakenapps.api.BundleDescriptor; import org.krakenapps.api.BundleRequirement; import org.krakenapps.api.MavenResolveException; import org.krakenapps.api.PackageDescriptor; import org.krakenapps.api.PackageIndex; import org.krakenapps.api.PackageManager; import org.krakenapps.api.PackageMetadata; import org.krakenapps.api.PackageNotFoundException; import org.krakenapps.api.PackageRepository; import org.krakenapps.api.PackageUpdatePlan; import org.krakenapps.api.PackageVersionHistory; import org.krakenapps.api.Script; import org.krakenapps.api.ScriptArgument; import org.krakenapps.api.ScriptContext; import org.krakenapps.api.ScriptUsage; import org.krakenapps.api.VersionRange; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PackageScript implements Script { private final Logger logger = LoggerFactory.getLogger(PackageScript.class.getName()); private ScriptContext context; private BundleContext bc; private PackageManager packageManager; public PackageScript(BundleContext bc, PackageManagerService packageManager) { this.bc = bc; this.packageManager = packageManager; } @Override public void setScriptContext(ScriptContext context) { this.context = context; } public void repositories(String[] args) { context.println("Package Repository"); context.println("--------------------"); for (PackageRepository repo : packageManager.getRepositories()) { String alias = repo.getAlias(); if (repo.isHttps()) { context.printf("[%s] %s, trust=%s, key=%s\n", alias, repo.getUrl().toString(), repo.getTrustStoreAlias(), repo.getKeyStoreAlias()); } else { if (repo.isAuthRequired()) alias += " (http-auth)"; context.printf("[%s] %s\n", alias, repo.getUrl().toString()); } } } @ScriptUsage(description = "add package repository", arguments = { @ScriptArgument(name = "alias", type = "string", description = "the alias of kraken package repository"), @ScriptArgument(name = "url", type = "string", description = "the url of kraken package repository") }) public void addRepository(String[] args) { try { String alias = args[0]; URL url = new URL(args[1]); packageManager.createRepository(PackageRepository.create(alias, url)); context.printf("repository [%s] added\n", alias); } catch (MalformedURLException e) { context.printf("invalid url format\n"); } catch (RuntimeException e) { context.printf("database failure\n"); } } @ScriptUsage(description = "add secure package repository", arguments = { @ScriptArgument(name = "alias", type = "string", description = "the alias of kraken package repository"), @ScriptArgument(name = "url", type = "string", description = "the url of kraken package repository"), @ScriptArgument(name = "trust store alias", type = "string", description = "the alias of kraken truststore"), @ScriptArgument(name = "key store alias", type = "string", description = "the alias of kraken keystore. if provided, client authentication will be used", optional = true) }) public void addSecureRepository(String[] args) { try { String alias = args[0]; URL url = new URL(args[1]); String trustStoreAlias = args[2]; String keyStoreAlias = args[3]; packageManager.createRepository(PackageRepository.createHttps(alias, url, trustStoreAlias, keyStoreAlias)); context.printf("secure repository [%s] added\n", alias); } catch (MalformedURLException e) { context.printf("invalid url format\n"); } catch (RuntimeException e) { context.printf("database failure\n"); } } @ScriptUsage(description = "remove package repository", arguments = { @ScriptArgument(name = "alias", type = "string", description = "the alias of kraken package repository") }) public void removeRepository(String[] args) { String alias = args[0]; try { packageManager.removeRepository(alias); context.printf("repository [%s] removed\n", alias); } catch (RuntimeException e) { context.println("database failure"); } } @ScriptUsage(description = "Set credential for repository http authentication", arguments = { @ScriptArgument(name = "alias", type = "string", description = "alias of the maven repository"), @ScriptArgument(name = "account", type = "string", description = "account for http authentication"), @ScriptArgument(name = "password", type = "string", description = "password for http authentication") }) public void setHttpAuth(String[] args) { PackageRepository repo = packageManager.getRepository(args[0]); if (repo == null) { context.println("package repository [" + args[0] + "] not found"); return; } repo.setAccount(args[1]); repo.setPassword(args[2]); repo.setAuthRequired(true); packageManager.updateRepository(repo); context.println("ok"); } @ScriptUsage(description = "Reset credential for repository http authentication", arguments = { @ScriptArgument(name = "alias", type = "string", description = "alias of the maven repository") }) public void resetHttpAuth(String[] args) { PackageRepository repo = packageManager.getRepository(args[0]); if (repo == null) { context.println("package repository [" + args[0] + "] not found"); return; } repo.setAccount(null); repo.setPassword(null); repo.setAuthRequired(false); packageManager.updateRepository(repo); context.println("ok"); } public void list(String[] args) { context.println("Installed Packages"); context.println("--------------------"); for (PackageDescriptor desc : packageManager.getInstalledPackages()) { context.printf("%s\t\t%s\n", desc.getName(), desc.getVersion()); } } public void installables(String[] args) { String keyword = (args.length > 0) ? args[0].toLowerCase() : null; SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); for (PackageIndex list : packageManager.getPackageIndexes()) { context.println(String.format("[%s] %s (%s)", list.getRepository().getAlias(), list.getDescription(), dateFormat.format(list.getCreated()))); for (PackageMetadata metadata : list.getPackages()) { if (keyword == null || metadata.getName().toLowerCase().contains(keyword)) { if (metadata != null) { context.println(String.format("\t%s (%s)", metadata.getName(), metadata.getDescription())); for (PackageVersionHistory ver : metadata.getVersions()) context.println(String.format("\t\t%s (%s)", ver.getVersion(), dateFormat.format(ver.getLastUpdated()))); } else { context.println("\t" + metadata); } } } context.println(""); } } public void search(String[] args) { // not yet implemented. } @ScriptUsage(description = "install new package", arguments = { @ScriptArgument(name = "package name", type = "string", description = "the name of kraken package"), @ScriptArgument(name = "version", type = "string", description = "the version of kraken package", optional = true) }) public void install(String[] args) { String packageName = args[0]; String version = null; if (args.length > 1) version = args[1]; try { packageManager.installPackage(packageName, version, new ProgressMonitorImpl(context)); context.println(""); context.println("Complete!"); } catch (AlreadyInstalledPackageException e) { context.println("Already installed package."); logger.error("kraken core: already installed package [{}]", packageName); } catch (PackageNotFoundException e) { context.println("Package not found."); logger.error("kraken core: package [{}] not found", packageName); } catch (MavenResolveException e) { context.println("Maven resolver failed: " + e.getMessage()); logger.error("kraken core: resolver failed", e); } catch (UnrecoverableKeyException e) { logger.error("kraken core: unrecoverable key", e); } catch (KeyManagementException e) { logger.error("kraken core: key management error", e); } catch (KeyStoreException e) { logger.error("kraken core: key store error", e); } catch (RuntimeException e) { if (e.getCause() instanceof BundleException) { context.println("Bundle exception: " + e.getMessage()); logger.error("kraken core: bundle error", e); } else { context.println("unknown error: " + e.getMessage()); logger.error("kraken core: unknown error", e); } } } @ScriptUsage(description = "update bundles and install missing bundles", arguments = { @ScriptArgument(name = "package name", type = "string", description = "the name of kraken package") }) public void repair(String[] args) { String packageName = args[0]; try { PackageVersionHistory history = packageManager.getLatestVersion(packageName); updatePackageInternal(packageName, history); } catch (PackageNotFoundException e) { context.println("Package not found"); } catch (InterruptedException e) { context.println("Interrupted"); } catch (MavenResolveException e) { context.println("Maven resolver failed"); e.printStackTrace(); } catch (BundleException e) { context.println("Bundle exception: " + e.getMessage()); e.printStackTrace(); } catch (UnrecoverableKeyException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } } @ScriptUsage(description = "check version and update package", arguments = { @ScriptArgument(name = "package name", type = "string", description = "the name of kraken package") }) public void update(String[] args) { String packageName = args[0]; try { PackageVersionHistory history = packageManager.checkUpdate(packageName); if (history == null) { PackageDescriptor desc = packageManager.findInstalledPackage(packageName); context.printf("%s %s is up to date\n", packageName, desc.getVersion()); return; } updatePackageInternal(packageName, history); } catch (PackageNotFoundException e) { context.println("Package not found"); } catch (InterruptedException e) { context.println("Interrupted"); } catch (MavenResolveException e) { context.println("Maven resolver failed"); e.printStackTrace(); } catch (BundleException e) { context.println("Bundle exception: " + e.getMessage()); e.printStackTrace(); } catch (UnrecoverableKeyException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } } private static class BundleOrder implements Comparator<BundleDescriptor> { @Override public int compare(BundleDescriptor o1, BundleDescriptor o2) { return (int) (o1.getBundleId() - o2.getBundleId()); } } private void updatePackageInternal(String packageName, PackageVersionHistory history) throws PackageNotFoundException, InterruptedException, MavenResolveException, BundleException, UnrecoverableKeyException, KeyManagementException, KeyStoreException { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); context.printf("Latest version found -> version: %s, last updated at: %s\n", history.getVersion(), dateFormat.format(history.getLastUpdated())); context.println("Resolving Dependencies"); // print summary PackageUpdatePlan dep = packageManager.getUpdatePlan(packageName, history.getVersion()); context.println("[ ID] Symbolic Name\t\t\t\t\tVersion"); context.println("------------------------------------------------------------------"); if (dep.getRemainingBundles().size() > 0) { context.println(""); context.println("Remaining Bundles"); List<BundleDescriptor> bundles = new ArrayList<BundleDescriptor>(dep.getRemainingBundles()); Collections.sort(bundles, new BundleOrder()); for (BundleDescriptor bundle : bundles) { context.printf("[%3d] %-49s %s\n", bundle.getBundleId(), bundle.getSymbolicName(), bundle.getVersion()); } } if (dep.getInstallingBundles().size() > 0) { context.println("Installing Bundles"); for (BundleRequirement req : dep.getInstallingBundles()) { VersionRange range = req.getVersionRange(); if (range.getLow().equals(range.getHigh())) { context.printf(" %-49s %s\n", req.getName(), req.getVersionRange().getHigh()); } else { context.printf(" %-49s (%s ~ %s)\n", req.getName(), req.getVersionRange().getLow(), req .getVersionRange().getHigh()); } } } if (dep.getRemovingBundles().size() > 0) { context.println(""); context.println("Removing Bundles"); List<BundleDescriptor> bundles = new ArrayList<BundleDescriptor>(dep.getRemovingBundles()); Collections.sort(bundles, new BundleOrder()); for (BundleDescriptor bundle : bundles) { context.printf("[%3d] %-49s %s\n", bundle.getBundleId(), bundle.getSymbolicName(), bundle.getVersion()); } } context.println(""); context.print("Is This OK? [y/N] "); String answer = context.readLine(); if (answer.equalsIgnoreCase("y")) { try { packageManager.updatePackage(packageName, history.getVersion(), new ProgressMonitorImpl(context)); context.println(""); context.println("Complete!"); } catch (RuntimeException e) { context.println("Database error occurred"); } } else { context.println("Canceled!"); } } @ScriptUsage(description = "uninstall package", arguments = { @ScriptArgument(name = "package name", type = "string", description = "the name of kraken package") }) public void uninstall(String[] args) { String packageName = args[0]; try { PackageDescriptor pkg = packageManager.findInstalledPackage(packageName); if (pkg == null) { context.println("Package not found"); return; } Map<String, List<PackageDescriptor>> dependMap = packageManager.checkUninstallDependency(packageName); List<BundleDescriptor> removingBundles = new ArrayList<BundleDescriptor>(); List<BundleDescriptor> remainingBundles = new ArrayList<BundleDescriptor>(); // categorize List<BundleDescriptor> relatedBundles = new ArrayList<BundleDescriptor>(packageManager.findRelatedBundles(pkg)); Collections.sort(relatedBundles, new BundleOrder()); for (BundleDescriptor bundle : relatedBundles) { if (dependMap.containsKey(bundle.getSymbolicName())) remainingBundles.add(bundle); else removingBundles.add(bundle); } // print context.println("[ ID] Symbolic Name\t\t\t\t\tVersion"); context.println("------------------------------------------------------------------"); context.println("Removing Bundles: "); for (BundleDescriptor bundle : removingBundles) { context.printf("[%3d] %-49s %s\n", bundle.getBundleId(), bundle.getSymbolicName(), bundle.getVersion()); } if (remainingBundles.size() > 0) { context.println(""); context.println("Remaining Bundles: "); for (BundleDescriptor bundle : remainingBundles) { List<PackageDescriptor> packages = dependMap.get(bundle.getSymbolicName()); context.printf("[%3d] %-49s %s\n", bundle.getBundleId(), bundle.getSymbolicName(), bundle.getVersion()); context.printf("\tused by [%s]\n", toPackageString(packages)); context.println(""); } } context.print("Is This OK? [y/N] "); String answer = context.readLine(); if (answer.equalsIgnoreCase("y")) { packageManager.uninstallPackage(packageName, new ProgressMonitorImpl(context)); } context.println(""); context.println("Complete!"); } catch (PackageNotFoundException e) { context.println("Package not found"); } catch (InterruptedException e) { context.println("Interrupted"); } catch (RuntimeException e) { context.println("Database error occurred"); } } public void export(String[] args) { context.println(new PackageDescWriter(bc)); } private String toPackageString(List<PackageDescriptor> packages) { StringBuilder b = new StringBuilder(1024); int i = 0; for (PackageDescriptor pkg : packages) { if (i++ != 0) b.append(", "); b.append(pkg.getName()); } return b.toString(); } }