Java tutorial
/** * Copyright (c) 2013 Puppet Labs, Inc. and other contributors, as listed below. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Puppet Labs */ package com.puppetlabs.geppetto.forge.impl; import static com.puppetlabs.geppetto.diagnostic.Diagnostic.ERROR; import static com.puppetlabs.geppetto.diagnostic.Diagnostic.INFO; import static com.puppetlabs.geppetto.diagnostic.Diagnostic.WARNING; import static com.puppetlabs.geppetto.forge.Forge.FORGE; import static com.puppetlabs.geppetto.forge.Forge.METADATA_JSON_NAME; import static com.puppetlabs.geppetto.forge.Forge.MODULE_FILE_FILTER; import static com.puppetlabs.geppetto.forge.Forge.PUBLISHER; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.zip.GZIPInputStream; import org.apache.http.HttpStatus; import org.apache.http.client.HttpResponseException; import com.google.inject.Inject; import com.google.inject.name.Named; import com.puppetlabs.geppetto.common.os.FileUtils; import com.puppetlabs.geppetto.common.os.StreamUtil; import com.puppetlabs.geppetto.diagnostic.Diagnostic; import com.puppetlabs.geppetto.diagnostic.ExceptionDiagnostic; import com.puppetlabs.geppetto.forge.AlreadyPublishedException; import com.puppetlabs.geppetto.forge.Cache; import com.puppetlabs.geppetto.forge.Forge; import com.puppetlabs.geppetto.forge.ForgeService; import com.puppetlabs.geppetto.forge.client.ForgeException; import com.puppetlabs.geppetto.forge.model.Dependency; import com.puppetlabs.geppetto.forge.model.Metadata; import com.puppetlabs.geppetto.forge.model.MetadataRepository; import com.puppetlabs.geppetto.forge.model.ModuleName; import com.puppetlabs.geppetto.forge.util.ModuleUtils; import com.puppetlabs.geppetto.forge.util.TarUtils; import com.puppetlabs.geppetto.forge.v2.model.Release; import com.puppetlabs.geppetto.forge.v2.service.ModuleService; import com.puppetlabs.geppetto.forge.v2.service.ReleaseService; import com.puppetlabs.geppetto.semver.VersionRange; class ForgeServiceImpl implements ForgeService { @Inject private Cache cache; @Inject private ModuleService moduleService; @Inject private ReleaseService releaseService; @Inject private MetadataRepository metadataRepo; @Inject @Named(MODULE_FILE_FILTER) private FileFilter moduleFileFilter; @Inject private Forge forgeUtil; @Override public Collection<File> downloadDependencies(Iterable<Metadata> metadatas, File importedModulesDir, Diagnostic result) throws IOException { Set<Dependency> unresolvedCollector = new HashSet<Dependency>(); Set<Metadata> releasesToDownload = resolveDependencies(metadatas, unresolvedCollector); for (Dependency unresolved : unresolvedCollector) result.addChild(new Diagnostic(WARNING, FORGE, String.format("Unable to resolve dependency: %s:%s", unresolved.getName(), unresolved.getVersionRequirement().toString()))); if (!releasesToDownload.isEmpty()) { importedModulesDir.mkdirs(); List<File> importedModuleLocations = new ArrayList<File>(); StringBuilder bld = new StringBuilder("Installing dependent module "); int pfxLen = bld.length(); for (Metadata release : releasesToDownload) { bld.setLength(pfxLen); release.getName().toString(bld); bld.append(':'); release.getVersion().toString(bld); result.addChild(new Diagnostic(INFO, FORGE, bld.toString())); bld.setLength(0); ModuleUtils.buildFileName(release.getName(), release.getVersion(), bld); File moduleDir = new File(importedModulesDir, bld.toString()); install(release, moduleDir, true, false); importedModuleLocations.add(moduleDir); } return importedModuleLocations; } if (unresolvedCollector.isEmpty()) result.addChild(new Diagnostic(INFO, FORGE, "No additional dependencies were detected")); return Collections.emptyList(); } @Override public Metadata install(Metadata release, File destination, boolean destinationIncludesTopFolder, boolean force) throws IOException { return install(release.getName(), VersionRange.exact(release.getVersion()), destination, destinationIncludesTopFolder, force); } @Override public Metadata install(ModuleName moduleName, VersionRange range, File destination, boolean destinationIncludesTopFolder, boolean force) throws IOException { if (moduleService == null || cache == null) throw new UnsupportedOperationException( "Unable to install since no module service is configured. Was a serviceURL provided in the preferences?"); List<Release> releases = moduleService.getReleases(moduleName.getOwner(), moduleName.getName(), null); if (releases.isEmpty()) throw new FileNotFoundException("No releases found for module '" + moduleName + '\''); Release best = null; for (Release release : releases) if ((best == null || release.getVersion().compareTo(best.getVersion()) > 0) && (range == null || range.isIncluded(release.getVersion()))) best = release; if (best == null) throw new FileNotFoundException( "No releases matching '" + range + "' found for module '" + moduleName + '\''); if (!destinationIncludesTopFolder) // Use module name as the default destination = new File(destination, moduleName.getName()); if (destination.exists()) { if (!force) throw new IOException("Destination folder is not empty: " + destination.getAbsolutePath()); // Don't remove .project, .settings, .git, .svn, etc. if they are present. FileUtils.rmR(destination, FileUtils.DEFAULT_EXCLUDES); } File moduleFile = cache.retrieve(best.getFullName(), best.getVersion()); // Unpack closes its input. TarUtils.unpack(new GZIPInputStream(new FileInputStream(moduleFile)), destination, true, null); return forgeUtil.loadJSONMetadata(new File(destination, METADATA_JSON_NAME)); } @Override public void publish(File moduleArchive, boolean dryRun, Diagnostic result) throws IOException { if (releaseService == null) throw new UnsupportedOperationException( "Unable to publish since no release service is configured. Was a serviceURL provided in the preferences?"); Metadata metadata = forgeUtil.getMetadataFromPackage(moduleArchive); if (metadata == null) throw new ForgeException("No \"metadata.json\" found in archive: " + moduleArchive.getAbsolutePath()); if (metadata.getName() == null) throw new ForgeException( "The \"metadata.json\" found in archive: " + moduleArchive.getAbsolutePath() + " has no name"); if (metadata.getVersion() == null) throw new ForgeException("The \"metadata.json\" found in archive: " + moduleArchive.getAbsolutePath() + " has no version"); try { if (metadataRepo.resolve(metadata.getName(), metadata.getVersion()) != null) throw new AlreadyPublishedException("Module " + metadata.getName() + ':' + metadata.getVersion() + " has already been published"); } catch (HttpResponseException e) { // A SC_NOT_FOUND can be expected and is OK. if (e.getStatusCode() != HttpStatus.SC_NOT_FOUND) throw new ForgeException("Unable to check module existence on the forge: " + e.getMessage()); } if (dryRun) { result.addChild(new Diagnostic(INFO, PUBLISHER, "Module file " + moduleArchive.getName() + " would have been uploaded (but wasn't since this is a dry run)")); return; } InputStream gzInput = new FileInputStream(moduleArchive); try { ModuleName name = metadata.getName(); releaseService.create(name.getOwner(), name.getName(), "Published using GitHub trigger", gzInput, moduleArchive.length()); result.addChild(new Diagnostic(INFO, PUBLISHER, "Module file " + moduleArchive.getName() + " has been uploaded")); } finally { StreamUtil.close(gzInput); } } public void publishAll(File[] builtModules, boolean dryRun, Diagnostic result) { boolean noPublishingMade = true; for (File builtModule : builtModules) { String name = builtModule.getName(); if (!(name.endsWith(".tar.gz") || name.endsWith(".tgz"))) continue; try { publish(builtModule, dryRun, result); noPublishingMade = false; continue; } catch (AlreadyPublishedException e) { result.addChild(new Diagnostic(WARNING, PUBLISHER, e.getMessage())); continue; } catch (ForgeException e) { result.addChild(new Diagnostic(ERROR, PUBLISHER, e.getMessage())); } catch (Exception e) { result.addChild(new ExceptionDiagnostic(ERROR, PUBLISHER, "Unable to publish module " + builtModule.getName(), e)); } return; } if (noPublishingMade) { result.addChild(new Diagnostic(INFO, PUBLISHER, "All modules have already been published at their current version")); } } @Override public Set<Metadata> resolveDependencies(Iterable<Metadata> metadatas, Set<Dependency> unresolvedCollector) throws IOException { // Resolve missing dependencies Set<Dependency> deps = new HashSet<Dependency>(); for (Metadata metadata : metadatas) deps.addAll(metadata.getDependencies()); // Remove the dependencies that appoints modules that we have in the // workspace Iterator<Dependency> depsItor = deps.iterator(); nextDep: while (depsItor.hasNext()) { Dependency dep = depsItor.next(); for (Metadata metadata : metadatas) if (dep.matches(metadata)) { depsItor.remove(); continue nextDep; } } // Resolve remaining dependencies Set<Metadata> releasesToDownload = new HashSet<Metadata>(); if (!deps.isEmpty()) { if (metadataRepo == null) throw new UnsupportedOperationException( "Unable to resolve dependencies since no forge service is configured. Was a serviceURL provided in the preferences?"); for (Dependency dep : deps) releasesToDownload.addAll(metadataRepo.deepResolve(dep, unresolvedCollector)); } return releasesToDownload; } }