Package com.puppetlabs.geppetto.forge.impl

Source Code of com.puppetlabs.geppetto.forge.impl.ForgeImpl

/**
* 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 java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import com.google.gson.Gson;
import com.google.inject.Inject;
import com.google.inject.Singleton;
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.forge.ERB;
import com.puppetlabs.geppetto.forge.Forge;
import com.puppetlabs.geppetto.forge.ForgeService;
import com.puppetlabs.geppetto.forge.MetadataExtractor;
import com.puppetlabs.geppetto.forge.model.Metadata;
import com.puppetlabs.geppetto.forge.model.ModuleName;
import com.puppetlabs.geppetto.forge.util.Checksums;
import com.puppetlabs.geppetto.forge.util.ModuleUtils;
import com.puppetlabs.geppetto.forge.util.TarUtils;
import com.puppetlabs.geppetto.forge.util.TarUtils.FileCatcher;
import com.puppetlabs.geppetto.semver.Version;

@Singleton
class ForgeImpl implements Forge {
  @Inject
  private ERB erb;

  @Inject
  private Gson gson;

  @Inject
  @Named(MODULE_FILE_FILTER)
  private FileFilter moduleFileFilter;

  @Inject
  Set<MetadataExtractor> metadataExtractors;

  private static Comparator<MetadataExtractor> extractorComparator = new Comparator<MetadataExtractor>() {
    @Override
    public int compare(MetadataExtractor a, MetadataExtractor b) {
      return a.getCardinal() - b.getCardinal();
    }
  };

  @Override
  public File build(File moduleSource, File destination, FileFilter fileFilter, Metadata[] resultingMetadata,
      byte[][] resultingMD5, Diagnostic result) throws IOException {
    if(fileFilter == null)
      fileFilter = moduleFileFilter;

    File[] extractedFrom = new File[1];

    Metadata md = createFromModuleDirectory(moduleSource, true, fileFilter, extractedFrom, result);
    if(result.getSeverity() >= ERROR)
      return null;

    if(resultingMetadata != null)
      resultingMetadata[0] = md;

    if(md == null)
      // Metadata could not be read. Errors are in result
      return null;

    for(File tst = destination; tst != null; tst = tst.getParentFile()) {
      if(fileFilter.accept(tst))
        // Destination folder might reside inside of the module when it
        // has been excluded.
        break;

      if(tst.equals(moduleSource))
        throw new IllegalArgumentException("Destination cannot reside within the module itself");
    }

    ModuleName fullName = md.getName();
    Version ver = md.getVersion();
    if(fullName == null || ver == null)
      // Reason has been added to the Diagnostic result
      return null;

    /**
     * Copy the module to the location where it's being built. Ensure that it's
     * an empty location prior to that.
     */
    StringBuilder bld = new StringBuilder();
    ModuleUtils.buildFileName(fullName, ver, bld);
    String fullNameWithVersion = bld.toString();
    bld.append(".tar.gz");
    String zipArchiveName = bld.toString();

    File destModuleDir = new File(destination, fullNameWithVersion);
    if(!destination.mkdirs())
      FileUtils.rmR(destModuleDir);

    FileUtils.cpR(moduleSource, destModuleDir, fileFilter, false, true);

    File metadataJSON = new File(destModuleDir, METADATA_JSON_NAME);
    if(!extractedFrom[0].getName().equals(METADATA_JSON_NAME))
      internalSaveJSONMetadata(md, metadataJSON);

    final File moduleArchive = new File(destination, zipArchiveName);
    OutputStream out = new GZIPOutputStream(new FileOutputStream(moduleArchive));
    if(resultingMD5 == null)
      // Pack closes its output
      TarUtils.pack(destModuleDir, out, null, true, null);
    else {
      MessageDigest digest = Checksums.getMessageDigest();
      DigestOutputStream digestOut = new DigestOutputStream(out, digest);

      // Pack closes its output
      TarUtils.pack(destModuleDir, digestOut, null, true, null);
      resultingMD5[0] = digest.digest();
    }
    return moduleArchive;
  }

  @Override
  public List<File> changes(File path, FileFilter fileFilter) throws IOException {
    if(fileFilter == null)
      fileFilter = moduleFileFilter;
    Metadata md = loadJSONMetadata(new File(path, METADATA_JSON_NAME));
    List<File> result = new ArrayList<File>();
    Checksums.appendChangedFiles(md.getChecksums(), path, result, fileFilter);
    return result;
  }

  @Override
  public Metadata createFromModuleDirectory(File moduleDirectory, boolean includeTypesAndChecksums,
      FileFilter filter, File[] extractedFrom, Diagnostic result) throws IOException {

    if(filter == null)
      filter = moduleFileFilter;

    if(extractedFrom == null)
      extractedFrom = new File[1];

    Metadata md = null;
    for(MetadataExtractor extractor : getMetadataExtractors())
      if(extractor.canExtractFrom(moduleDirectory, filter)) {
        md = extractor.parseMetadata(moduleDirectory, includeTypesAndChecksums, filter, extractedFrom, result);
        break;
      }

    if(result == null)
      return md;

    if(md == null) {
      result.addChild(new Diagnostic(ERROR, FORGE, "No Module Metadata found in directory " +
          moduleDirectory.getAbsolutePath()));
      return null;
    }
    return md;
  }

  @Override
  public Collection<File> findModuleRoots(File modulesRoot, FileFilter fileFilter) {
    if(fileFilter == null)
      fileFilter = moduleFileFilter;
    return ModuleUtils.findModuleRoots(modulesRoot, fileFilter, getMetadataExtractors());
  }

  @Override
  public void generate(File destination, Metadata metadata) throws IOException {
    if(!(destination.mkdirs() || destination.exists()))
      throw new IOException(destination + " could not be created");

    InputStream input = ForgeService.class.getResourceAsStream("/templates/generator.zip");
    if(input == null)
      throw new FileNotFoundException("Unable to find zipped template for generate");

    ZipInputStream template = new ZipInputStream(input);
    try {
      installTemplate(metadata, destination, template);
    }
    finally {
      template.close();
    }
  }

  public List<MetadataExtractor> getMetadataExtractors() {
    ArrayList<MetadataExtractor> extractors = new ArrayList<MetadataExtractor>(metadataExtractors);
    Collections.sort(extractors, extractorComparator);
    return extractors;
  }

  @Override
  public Metadata getMetadataFromPackage(File builtModule) throws IOException {
    InputStream input = new FileInputStream(builtModule);
    try {
      final Metadata[] mdReceiver = new Metadata[1];
      TarUtils.unpack(new GZIPInputStream(input), null, true, new FileCatcher() {
        @Override
        public boolean accept(String fileName) {
          return METADATA_JSON_NAME.equals(fileName);
        }

        @Override
        public boolean catchData(String fileName, InputStream fileData) {
          InputStreamReader reader = new InputStreamReader(fileData);
          mdReceiver[0] = gson.fromJson(reader, Metadata.class);
          return true; // We're done. Skip further processing
        }
      });
      return mdReceiver[0];
    }
    finally {
      input.close();
    }
  }

  @Override
  public boolean hasModuleMetadata(File moduleDirectory, FileFilter filter) {
    if(filter == null)
      filter = moduleFileFilter;
    for(MetadataExtractor extractor : metadataExtractors)
      if(extractor.canExtractFrom(moduleDirectory, filter))
        return true;
    return false;
  }

  private void installTemplate(Metadata metadata, File destinationBase, ZipInputStream template) throws IOException {

    ZipEntry zipEntry;
    while((zipEntry = template.getNextEntry()) != null) {
      String name = zipEntry.getName();
      if(zipEntry.isDirectory()) {
        File destination = new File(destinationBase, name);
        if(!destination.mkdirs())
          throw new IOException(destination + " could not be created");
        continue;
      }

      if(name.endsWith(".erb")) {
        File destination = new File(destinationBase, name.substring(0, name.length() - 4));
        BufferedReader reader = new BufferedReader(new InputStreamReader(template));
        BufferedWriter writer = new BufferedWriter(new FileWriter(destination));
        try {
          erb.generate(metadata, reader, writer);
        }
        finally {
          StreamUtil.close(writer);
        }
      }
      else {
        File destination = new File(destinationBase, name);
        FileUtils.cp(template, destination.getParentFile(), destination.getName());
      }
    }
  }

  private void internalSaveJSONMetadata(Metadata md, File jsonFile) throws IOException {
    Writer writer = new BufferedWriter(new FileWriter(jsonFile));
    try {
      gson.toJson(md, writer);
    }
    finally {
      StreamUtil.close(writer);
    }
  }

  @Override
  public boolean isMetadataFile(String source) {
    if(source != null) {
      for(MetadataExtractor extractor : metadataExtractors)
        if(source.equals(extractor.getPrimarySource()))
          return true;
    }
    return false;
  }

  public Metadata loadJSONMetadata(File jsonFile) throws IOException {
    Reader reader = new BufferedReader(new FileReader(jsonFile));
    try {
      Metadata md = gson.fromJson(reader, Metadata.class);
      return md;
    }
    finally {
      StreamUtil.close(reader);
    }
  }

  @Override
  public Metadata loadModulefile(File moduleFile, Diagnostic diagnostic) throws IOException {
    Metadata metadata = new Metadata();
    ModuleUtils.parseModulefile(moduleFile, metadata, diagnostic);
    return metadata;
  }

  public void saveJSONMetadata(Metadata md, File jsonFile) throws IOException {
    internalSaveJSONMetadata(new Metadata(md), jsonFile);
  }

  @Override
  public void saveModulefile(Metadata md, File moduleFile) throws IOException {
    ModuleUtils.saveAsModulefile(md, moduleFile);
  }
}
TOP

Related Classes of com.puppetlabs.geppetto.forge.impl.ForgeImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.