Package org.vafer.jdeb

Source Code of org.vafer.jdeb.ControlBuilder

/*
* Copyright 2014 The jdeb developers.
*
* 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.vafer.jdeb;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.text.ParseException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.GZIPOutputStream;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.NullOutputStream;
import org.apache.tools.ant.DirectoryScanner;
import org.vafer.jdeb.debian.BinaryPackageControlFile;
import org.vafer.jdeb.mapping.PermMapper;
import org.vafer.jdeb.utils.FilteredFile;
import org.vafer.jdeb.utils.InformationInputStream;
import org.vafer.jdeb.utils.Utils;
import org.vafer.jdeb.utils.VariableResolver;

/**
* Builds the control archive of the Debian package.
*/
class ControlBuilder {
   
    /** The name of the package maintainer scripts */
    private static final Set<String> MAINTAINER_SCRIPTS = new HashSet<String>(Arrays.asList("preinst", "postinst", "prerm", "postrm", "config"));

    /** The name of the other control files subject to token substitution */
    private static final Set<String> CONFIGURATION_FILENAMES = new HashSet<String>(Arrays.asList("conffiles", "templates", "triggers"));

    private Console console;
    private VariableResolver resolver;
    private final String openReplaceToken;
    private final String closeReplaceToken;

    ControlBuilder(Console console, VariableResolver resolver, String openReplaceToken, String closeReplaceToken) {
        this.console = console;
        this.resolver = resolver;
        this.openReplaceToken = openReplaceToken;
        this.closeReplaceToken = closeReplaceToken;
    }

    /**
     * Build control archive of the deb
     *
     * @param packageControlFile the package control file
     * @param controlFiles the other control information files (maintainer scripts, etc)
     * @param dataSize  the size of the installed package
     * @param checksums the md5 checksums of the files in the data archive
     * @param output
     * @return
     * @throws java.io.FileNotFoundException
     * @throws java.io.IOException
     * @throws java.text.ParseException
     */
    void buildControl(BinaryPackageControlFile packageControlFile, File[] controlFiles, List<String> conffiles, StringBuilder checksums, File output) throws IOException, ParseException {
        final File dir = output.getParentFile();
        if (dir != null && (!dir.exists() || !dir.isDirectory())) {
            throw new IOException("Cannot write control file at '" + output.getAbsolutePath() + "'");
        }

        final TarArchiveOutputStream outputStream = new TarArchiveOutputStream(new GZIPOutputStream(new FileOutputStream(output)));
        outputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
       
        boolean foundConffiles = false;
       
        // create the final package control file out of the "control" file, copy all other files, ignore the directories
        for (File file : controlFiles) {
            if (file.isDirectory()) {
                // warn about the misplaced directory, except for directories ignored by default (.svn, cvs, etc)
                if (!isDefaultExcludes(file)) {
                    console.warn("Found directory '" + file + "' in the control directory. Maybe you are pointing to wrong dir?");
                }
                continue;
            }

            if ("conffiles".equals(file.getName())) {
                foundConffiles = true;
            }
           
            if (CONFIGURATION_FILENAMES.contains(file.getName()) || MAINTAINER_SCRIPTS.contains(file.getName())) {
                FilteredFile configurationFile = new FilteredFile(new FileInputStream(file), resolver);
                configurationFile.setOpenToken(openReplaceToken);
                configurationFile.setCloseToken(closeReplaceToken);
                addControlEntry(file.getName(), configurationFile.toString(), outputStream);

            } else if (!"control".equals(file.getName())) {
                // initialize the information stream to guess the type of the file
                InformationInputStream infoStream = new InformationInputStream(new FileInputStream(file));
                Utils.copy(infoStream, NullOutputStream.NULL_OUTPUT_STREAM);
                infoStream.close();

                // fix line endings for shell scripts
                InputStream in = new FileInputStream(file);
                if (infoStream.isShell() && !infoStream.hasUnixLineEndings()) {
                    byte[] buf = Utils.toUnixLineEndings(in);
                    in = new ByteArrayInputStream(buf);
                }
               
                addControlEntry(file.getName(), IOUtils.toString(in), outputStream);
               
                in.close();
            }
        }
       
        if ((conffiles != null) && (conffiles.size() > 0)) {
            if (foundConffiles) {
                console.info("Found file 'conffiles' in the control directory. Skipping conffiles generation.");
            } else {
                addControlEntry("conffiles", createPackageConffilesFile(conffiles), outputStream);
            }
        } else if ((conffiles != null) && (conffiles.size() == 0)) {
            console.info("Skipping 'conffiles' generation. No entries provided.");
        }

        if (packageControlFile == null) {
            throw new FileNotFoundException("No 'control' file found in " + controlFiles.toString());
        }
       
        addControlEntry("control", packageControlFile.toString(), outputStream);
        addControlEntry("md5sums", checksums.toString(), outputStream);

        outputStream.close();
    }
   
    private String createPackageConffilesFile(final List<String> conffiles) {
        StringBuilder content = new StringBuilder();
       
        if (conffiles != null && !conffiles.isEmpty()) {
            for (String nextFileName : conffiles) {
                content.append(nextFileName).append("\n");
            }
        }

        return content.toString();
    }
   
   
    /**
     * Creates a package control file from the specified file and adds the
     * <tt>Date</tt>, <tt>Distribution</tt> and <tt>Urgency</tt> fields if missing.
     * The <tt>Installed-Size</tt> field is also initialized to the actual size of
     * the package. The <tt>Maintainer</tt> field is overridden by the <tt>DEBEMAIL</tt>
     * and <tt>DEBFULLNAME</tt> environment variables if defined.
     *
     * @param file       the control file
     * @param pDataSize  the size of the installed package
     */
    public BinaryPackageControlFile createPackageControlFile(File file, BigInteger pDataSize) throws IOException, ParseException {
        FilteredFile controlFile = new FilteredFile(new FileInputStream(file), resolver);
        BinaryPackageControlFile packageControlFile = new BinaryPackageControlFile(controlFile.toString());
       
        if (packageControlFile.get("Distribution") == null) {
            packageControlFile.set("Distribution", "unknown");
        }

        if (packageControlFile.get("Urgency") == null) {
            packageControlFile.set("Urgency", "low");
        }

        packageControlFile.set("Installed-Size", pDataSize.divide(BigInteger.valueOf(1024)).toString());

        // override the Version if the DEBVERSION environment variable is defined
        final String debVersion = System.getenv("DEBVERSION");
        if (debVersion != null) {
            packageControlFile.set("Version", debVersion);
            console.debug("Using version'" + debVersion + "' from the environment variables.");
        }


        // override the Maintainer field if the DEBFULLNAME and DEBEMAIL environment variables are defined
        final String debFullName = System.getenv("DEBFULLNAME");
        final String debEmail = System.getenv("DEBEMAIL");

        if (debFullName != null && debEmail != null) {
            final String maintainer = debFullName + " <" + debEmail + ">";
            packageControlFile.set("Maintainer", maintainer);
            console.debug("Using maintainer '" + maintainer + "' from the environment variables.");
        }
       
        return packageControlFile;
    }


    private static void addControlEntry(final String pName, final String pContent, final TarArchiveOutputStream pOutput) throws IOException {
        final byte[] data = pContent.getBytes("UTF-8");

        final TarArchiveEntry entry = new TarArchiveEntry("./" + pName, true);
        entry.setSize(data.length);
        entry.setNames("root", "root");
       
        if (MAINTAINER_SCRIPTS.contains(pName)) {
            entry.setMode(PermMapper.toMode("755"));
        } else {
            entry.setMode(PermMapper.toMode("644"));
        }
       
        pOutput.putArchiveEntry(entry);
        pOutput.write(data);
        pOutput.closeArchiveEntry();
    }
   
    /**
     * Tells if the specified directory is ignored by default (.svn, cvs, etc)
     *
     * @param directory
     */
    private boolean isDefaultExcludes(File directory) {
        for (String pattern : DirectoryScanner.getDefaultExcludes()) {
            if (DirectoryScanner.match(pattern, directory.getAbsolutePath().replace("\\", "/"))) {
                return true;
            }
        }
       
        return false;
    }
}
TOP

Related Classes of org.vafer.jdeb.ControlBuilder

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.