diff --git a/docs/maven.md b/docs/maven.md index 0b8eab1fc..b7a1b97a7 100644 --- a/docs/maven.md +++ b/docs/maven.md @@ -103,19 +103,19 @@ tarball archive, or a file. You can add as many data elements to your dataSet as you'd like. The `data` element has the following options: -Element | Description | Required ----------------- | ---------------------------------------------------------------------------- | ------------------------------------ -src | The directory, tarball, file to include in the package | Yes -dst | New filename at destination (type must be `file`) | No -linkName | The path of the link (type must be `link`) | Yes for link -linkTarget | The target of the link (type must be `link`) | Yes for link -type | Type of the data source. (archive, directory, file, link or template) | No; but will be Yes in the future -missingSrc | Fail if src file/folder is missing (ignore or fail) | No; defaults to `fail` -includes | A comma seperated list of files to include from the directory or tarball | No; defaults to all files -excludes | A comma seperated list of files to exclude from the directory or tarball | No; defaults to no exclutions -conffile | A boolean value to define if the files should be included in the conffiles | No; defaults to `false` -mapper | The files to exclude from the directory or tarball | No -paths/(path..) | One or more string literal paths that will created in the package | No; Yes for type `template` +Element | Description | Required +---------------- | ------------------------------------------------------------------------------- | ------------------------------------ +src | The directory, tarball, file, man-page to include in the package | Yes +dst | New filename at destination (type must be `file` or `man-page`) | No +linkName | The path of the link (type must be `link`) | Yes for link +linkTarget | The target of the link (type must be `link`) | Yes for link +type | Type of the data source. (archive, directory, file, link, man-page or template) | No; but will be Yes in the future +missingSrc | Fail if src file/folder is missing (ignore or fail) | No; defaults to `fail` +includes | A comma seperated list of files to include from the directory or tarball | No; defaults to all files +excludes | A comma seperated list of files to exclude from the directory or tarball | No; defaults to no exclutions +conffile | A boolean value to define if the files should be included in the conffiles | No; defaults to `false` +mapper | The files to exclude from the directory or tarball | No +paths/(path..) | One or more string literal paths that will created in the package | No; Yes for type `template` There are different kinds of mappers that can be selected via the `type` argument. The most common one is the 'perm' mapper. @@ -218,6 +218,12 @@ include a directory, a tarball, and a file in your deb package and then sign it true + + + man-page + /a/path/to/manpage.1 + + ${project.build.directory}/data @@ -241,6 +247,7 @@ include a directory, a tarball, and a file in your deb package and then sign it ``` If you don't want to store your key information in the POM you can store this is your settings.xml, here's an example settings.xml: +```xml @@ -256,5 +263,6 @@ If you don't want to store your key information in the POM you can store this is jdeb-signing +``` keyring, key and passphrase can then be omitted from the POM entirely. diff --git a/src/main/java/org/vafer/jdeb/ant/Data.java b/src/main/java/org/vafer/jdeb/ant/Data.java index 78756af2b..f80e2ab10 100644 --- a/src/main/java/org/vafer/jdeb/ant/Data.java +++ b/src/main/java/org/vafer/jdeb/ant/Data.java @@ -22,12 +22,11 @@ import java.util.Collection; import java.util.Iterator; +import org.apache.tools.ant.Project; import org.apache.tools.ant.types.PatternSet; import org.vafer.jdeb.DataConsumer; import org.vafer.jdeb.DataProducer; -import org.vafer.jdeb.producers.DataProducerArchive; -import org.vafer.jdeb.producers.DataProducerDirectory; -import org.vafer.jdeb.producers.DataProducerFile; +import org.vafer.jdeb.producers.*; /** * Ant "data" element acting as a factory for DataProducers. @@ -82,36 +81,44 @@ public void produce( final DataConsumer pReceiver ) throws IOException { throw new FileNotFoundException("Data source not found : " + src); } - org.vafer.jdeb.mapping.Mapper[] mappers = new org.vafer.jdeb.mapping.Mapper[mapperWrapper.size()]; + final org.vafer.jdeb.mapping.Mapper[] mappers = new org.vafer.jdeb.mapping.Mapper[mapperWrapper.size()]; final Iterator it = mapperWrapper.iterator(); for (int i = 0; i < mappers.length; i++) { mappers[i] = it.next().createMapper(); } - if ("file".equalsIgnoreCase(type)) { - new DataProducerFile( - src, - destinationName, - getIncludePatterns(getProject()), - getExcludePatterns(getProject()), - mappers - ).produce(pReceiver); - - } else if ("archive".equalsIgnoreCase(type)) { - new DataProducerArchive( - src, - getIncludePatterns(getProject()), - getExcludePatterns(getProject()), - mappers - ).produce(pReceiver); - - } else if ("directory".equalsIgnoreCase(type)) { - new DataProducerDirectory( - src, - getIncludePatterns(getProject()), - getExcludePatterns(getProject()), - mappers - ).produce(pReceiver); + final Project project = getProject(); + + ProducerFactory.KnownType knownType = ProducerFactory.KnownType.forString(type); + + if (knownType == null) { + return; } + + final DataProducer p = ProducerFactory.create(knownType, new ProducerFactory.Params() { + @Override + public File getSource() { + return src; + } + @Override + public String getDestination() { + return destinationName; + } + @Override + public String[] getIncludePatterns() { + return Data.this.getIncludePatterns(project); + } + + @Override + public String[] getExcludePatterns() { + return Data.this.getExcludePatterns(project); + } + + @Override + public org.vafer.jdeb.mapping.Mapper[] getMappers() { + return mappers; + } + }); + p.produce(pReceiver); } } diff --git a/src/main/java/org/vafer/jdeb/maven/Data.java b/src/main/java/org/vafer/jdeb/maven/Data.java index a8e13f191..7b3e8f92a 100644 --- a/src/main/java/org/vafer/jdeb/maven/Data.java +++ b/src/main/java/org/vafer/jdeb/maven/Data.java @@ -26,11 +26,7 @@ import org.apache.maven.plugins.annotations.Parameter; import org.vafer.jdeb.DataConsumer; import org.vafer.jdeb.DataProducer; -import org.vafer.jdeb.producers.DataProducerArchive; -import org.vafer.jdeb.producers.DataProducerDirectory; -import org.vafer.jdeb.producers.DataProducerFile; -import org.vafer.jdeb.producers.DataProducerLink; -import org.vafer.jdeb.producers.DataProducerPathTemplate; +import org.vafer.jdeb.producers.*; import static org.vafer.jdeb.maven.MissingSourceBehavior.*; @@ -148,62 +144,84 @@ public String[] splitPatterns( String patterns ) { } public void produce( final DataConsumer pReceiver ) throws IOException { - org.vafer.jdeb.mapping.Mapper[] mappers = null; - if (mapper != null) { - mappers = new org.vafer.jdeb.mapping.Mapper[] { mapper.createMapper() }; - } + final org.vafer.jdeb.mapping.Mapper[] mappers = + mapper == null + ? null + : new org.vafer.jdeb.mapping.Mapper[] { mapper.createMapper() }; - // link type + ProducerFactory.KnownType knownType = ProducerFactory.KnownType.forString(type); - if ("link".equalsIgnoreCase(type)) { - if (linkName == null) { - throw new RuntimeException("linkName is not set"); - } - if (linkTarget == null) { - throw new RuntimeException("linkTarget is not set"); - } + if (knownType == null) { + throw new IOException(buildUnknownTypeMessage(type, src)); + } - new DataProducerLink(linkName, linkTarget, symlink, includePatterns, excludePatterns, mappers).produce(pReceiver); - return; + if (knownType.requiresSource() && (src == null || !src.exists())) { + if (IGNORE == missingSrc) { + return; + } + throw new FileNotFoundException("Data source not found : " + src); } - // template type + final DataProducer p = ProducerFactory.create(knownType, new ProducerFactory.Params() { + @Override + public File getSource() { + return src; + } + @Override + public String getDestination() { + return dst; + } + @Override + public String getLink() { + return linkName; + } + @Override + public String getLinkTarget() { + return linkTarget; + } - if ("template".equalsIgnoreCase(type)) { - if (paths == null || paths.length == 0) { - throw new RuntimeException("paths is not set"); + @Override + public boolean isSimlink() { + return symlink; } - new DataProducerPathTemplate(paths, includePatterns, excludePatterns, mappers).produce(pReceiver); - return; - } + @Override + public String[] getTemplatePaths() { + return paths; + } - // Types that require src to exist + @Override + public String[] getIncludePatterns() { + return includePatterns; + } - if (src == null || !src.exists()) { - if (missingSrc == IGNORE) { - return; - } else { - throw new FileNotFoundException("Data source not found : " + src); + @Override + public String[] getExcludePatterns() { + return excludePatterns; } - } - if ("file".equalsIgnoreCase(type)) { - new DataProducerFile(src, dst, includePatterns, excludePatterns, mappers).produce(pReceiver); - return; - } + @Override + public org.vafer.jdeb.mapping.Mapper[] getMappers() { + return mappers; + } + }); - if ("archive".equalsIgnoreCase(type)) { - new DataProducerArchive(src, includePatterns, excludePatterns, mappers).produce(pReceiver); - return; - } + p.produce(pReceiver); + } - if ("directory".equalsIgnoreCase(type)) { - new DataProducerDirectory(src, includePatterns, excludePatterns, mappers).produce(pReceiver); - return; + private static String buildUnknownTypeMessage( final String type, + final File src ) { + final StringBuilder b = new StringBuilder("Unknown type '"); + b.append(type).append("' ("); + for (ProducerFactory.KnownType t : ProducerFactory.KnownType.values()) { + if (t.ordinal() != 0) { + b.append("|"); + } + b.append(t.shortName()); } + b.append(") for ").append(src); + return b.toString(); - throw new IOException("Unknown type '" + type + "' (file|directory|archive|template|link) for " + src); } } diff --git a/src/main/java/org/vafer/jdeb/producers/AbstractDataProducer.java b/src/main/java/org/vafer/jdeb/producers/AbstractDataProducer.java index 47d87646a..386972cd8 100644 --- a/src/main/java/org/vafer/jdeb/producers/AbstractDataProducer.java +++ b/src/main/java/org/vafer/jdeb/producers/AbstractDataProducer.java @@ -27,6 +27,9 @@ */ public abstract class AbstractDataProducer implements DataProducer { + protected final static int ROOT_UID = 0; + protected final static String ROOT_NAME = "root"; + private final String[] includes; private final String[] excludes; private final Mapper[] mappers; diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerDirectory.java b/src/main/java/org/vafer/jdeb/producers/DataProducerDirectory.java index 70eff71e2..2f82f5cd2 100644 --- a/src/main/java/org/vafer/jdeb/producers/DataProducerDirectory.java +++ b/src/main/java/org/vafer/jdeb/producers/DataProducerDirectory.java @@ -18,7 +18,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.tools.ant.DirectoryScanner; @@ -72,12 +71,7 @@ public void produce( final DataConsumer pReceiver ) throws IOException { dirname += "/"; } - TarArchiveEntry entry = new TarArchiveEntry(dirname, true); - entry.setUserId(0); - entry.setUserName("root"); - entry.setGroupId(0); - entry.setGroupName("root"); - entry.setMode(TarArchiveEntry.DEFAULT_DIR_MODE); + TarArchiveEntry entry = Producers.defaultDirEntryWithName(dirname); entry = map(entry); @@ -99,23 +93,13 @@ public void produce( final DataConsumer pReceiver ) throws IOException { filename = filename.replace(File.separatorChar, '/'); } - TarArchiveEntry entry = new TarArchiveEntry(filename, true); - entry.setUserId(0); - entry.setUserName("root"); - entry.setGroupId(0); - entry.setGroupName("root"); - entry.setMode(TarArchiveEntry.DEFAULT_FILE_MODE); + TarArchiveEntry entry = Producers.defaultFileEntryWithName(filename); entry = map(entry); entry.setSize(file.length()); - final InputStream inputStream = new FileInputStream(file); - try { - pReceiver.onEachFile(inputStream, entry.getName(), entry.getLinkName(), entry.getUserName(), entry.getUserId(), entry.getGroupName(), entry.getGroupId(), entry.getMode(), entry.getSize()); - } finally { - inputStream.close(); - } + Producers.produceInputStreamWithEntry(pReceiver, new FileInputStream(file), entry); } } diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerFile.java b/src/main/java/org/vafer/jdeb/producers/DataProducerFile.java index 455f81153..ee94a7227 100644 --- a/src/main/java/org/vafer/jdeb/producers/DataProducerFile.java +++ b/src/main/java/org/vafer/jdeb/producers/DataProducerFile.java @@ -18,7 +18,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.vafer.jdeb.DataConsumer; @@ -51,23 +50,13 @@ public void produce( final DataConsumer pReceiver ) throws IOException { fileName = file.getName(); } - TarArchiveEntry entry = new TarArchiveEntry(fileName, true); - entry.setUserId(0); - entry.setUserName("root"); - entry.setGroupId(0); - entry.setGroupName("root"); - entry.setMode(TarArchiveEntry.DEFAULT_FILE_MODE); + TarArchiveEntry entry = Producers.defaultFileEntryWithName(fileName); entry = map(entry); entry.setSize(file.length()); - final InputStream inputStream = new FileInputStream(file); - try { - pReceiver.onEachFile(inputStream, entry.getName(), entry.getLinkName(), entry.getUserName(), entry.getUserId(), entry.getGroupName(), entry.getGroupId(), entry.getMode(), entry.getSize()); - } finally { - inputStream.close(); - } + Producers.produceInputStreamWithEntry(pReceiver, new FileInputStream(file), entry); } } diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerFileSet.java b/src/main/java/org/vafer/jdeb/producers/DataProducerFileSet.java index b4eaf4de7..3f3ecd47a 100644 --- a/src/main/java/org/vafer/jdeb/producers/DataProducerFileSet.java +++ b/src/main/java/org/vafer/jdeb/producers/DataProducerFileSet.java @@ -42,10 +42,10 @@ public DataProducerFileSet( final FileSet fileset ) { } public void produce( final DataConsumer pReceiver ) throws IOException { - String user = "root"; - int uid = 0; - String group = "root"; - int gid = 0; + String user = Producers.ROOT_NAME; + int uid = Producers.ROOT_UID; + String group = Producers.ROOT_NAME; + int gid = Producers.ROOT_UID; int filemode = TarEntry.DEFAULT_FILE_MODE; int dirmode = TarEntry.DEFAULT_DIR_MODE; String prefix = ""; diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerLink.java b/src/main/java/org/vafer/jdeb/producers/DataProducerLink.java index 69c851f8e..185df01d7 100644 --- a/src/main/java/org/vafer/jdeb/producers/DataProducerLink.java +++ b/src/main/java/org/vafer/jdeb/producers/DataProducerLink.java @@ -46,10 +46,10 @@ public void produce( final DataConsumer pReceiver ) throws IOException { TarArchiveEntry entry = new TarArchiveEntry(path, symlink ? TarArchiveEntry.LF_SYMLINK : TarArchiveEntry.LF_LINK); entry.setLinkName(linkName); - entry.setUserId(0); - entry.setUserName("root"); - entry.setGroupId(0); - entry.setGroupName("root"); + entry.setUserId(ROOT_UID); + entry.setUserName(ROOT_NAME); + entry.setGroupId(ROOT_UID); + entry.setGroupName(ROOT_NAME); entry.setMode(TarArchiveEntry.DEFAULT_FILE_MODE); entry = map(entry); diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerManPage.java b/src/main/java/org/vafer/jdeb/producers/DataProducerManPage.java new file mode 100644 index 000000000..d5b31df71 --- /dev/null +++ b/src/main/java/org/vafer/jdeb/producers/DataProducerManPage.java @@ -0,0 +1,167 @@ +/* + * Copyright 2013 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.producers; + +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.compressors.CompressorException; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.vafer.jdeb.Compression; +import org.vafer.jdeb.DataConsumer; +import org.vafer.jdeb.mapping.Mapper; +import org.vafer.jdeb.utils.Utils; + +import java.io.*; +import java.util.zip.Deflater; +import java.util.zip.GZIPOutputStream; + +/** + * DataProducer representing a man page entry. + * + * Ensures that man page is compressed with appropriate compression level + * and is placed to correct location. + * + * @author Roman Kashitsyn + */ +public class DataProducerManPage extends AbstractDataProducer { + + private final static int DEFAULT_CATEGORY = 1; + private final static int BAD_CATEGORY = -1; + private final static Compression COMPRESSOR = Compression.GZIP; + private final static String MAN_PAGE_PREFIX = "/usr/share/man/man"; + + final File file; + + final String destination; + + public DataProducerManPage( final File pFile, + String pDestinationName, + String[] pIncludes, + String[] pExcludes, + Mapper[] pMapper ) { + super(pIncludes, pExcludes, pMapper); + file = pFile; + destination = makeDestination(pDestinationName, pFile); + } + + @Override + public void produce( final DataConsumer receiver ) throws IOException { + + TarArchiveEntry entry = Producers.defaultFileEntryWithName(destination); + + entry = map(entry); + + if (isCompressedFile(FilenameUtils.getExtension(file.getName()))) { + entry.setSize(file.length()); + Producers.produceInputStreamWithEntry(receiver, new FileInputStream(file), entry); + } else { + produceCompressedPage(receiver, entry); + } + } + + private static boolean isCompressedFile( final String extension ) { + + return Compression.toEnum(extension) != null; + } + + private void produceCompressedPage( final DataConsumer receiver, + final TarArchiveEntry entry ) throws IOException { + try { + final byte[] pageBytes = getCompressedPageBytes(); + entry.setSize(pageBytes.length); + Producers.produceInputStreamWithEntry(receiver, new ByteArrayInputStream(pageBytes), entry); + } catch (CompressorException e) { + throw new IOException(e); + } + } + + private byte[] getCompressedPageBytes() throws IOException, CompressorException { + InputStream inputStream = null; + final ByteArrayOutputStream inMemoryOut = new ByteArrayOutputStream(); + final OutputStream compressedOut = new GZIPOutputStream(inMemoryOut) { + { + def.setLevel(Deflater.BEST_COMPRESSION); + } + }; + + try { + inputStream = new BufferedInputStream(new FileInputStream(file)); + Utils.copy(inputStream, compressedOut); + } finally { + IOUtils.closeQuietly(compressedOut); + IOUtils.closeQuietly(inputStream); + } + + // Updating compression level to avoid the lintian + // `manpage-not-compressed-with-max-compression` error + return setBestCompressionFlag(inMemoryOut.toByteArray()); + } + + /** + * Sets XFLAG header field to BEST COMPRESSION. + * See http://www.gzip.org/zlib/rfc-gzip.html for details. + * + * @param bytes compressed file bytes, must be a valid GZIP file + * @return augmented file bytes + */ + private static byte[] setBestCompressionFlag( final byte[] bytes ) { + + final int XFLAG_HEADER_INDEX = 8; + final byte BEST_COMPRESSION_FLAG = 2; + + bytes[XFLAG_HEADER_INDEX] = BEST_COMPRESSION_FLAG; + return bytes; + } + + static String makeDestination( final String dest, final File file ) { + if (dest != null && dest.length() > 0) { + return dest; + } + + String fileName = file.getName(); + final String extension = FilenameUtils.getExtension(fileName); + + if (isCompressedFile(extension)) { + final String fileNameWithoutSuffix = FilenameUtils.removeExtension(fileName); + final int category = extractCategory(fileNameWithoutSuffix); + fileName = addCategory(fileNameWithoutSuffix, extension, category); + } else { + final int category = extractCategory(fileName); + final String newExtension = COMPRESSOR.getExtension().substring(1); + fileName = addCategory(fileName, newExtension, category); + } + + return fileName; + } + + private static String addCategory( final String base, + final String extension, + final int category ) { + if (category == BAD_CATEGORY) { + return MAN_PAGE_PREFIX + DEFAULT_CATEGORY + "/" + + base + "." + DEFAULT_CATEGORY + "." + extension; + } + return MAN_PAGE_PREFIX + category + "/" + base + "." + extension; + } + + private static int extractCategory( final String fileName ) { + final String suffix = FilenameUtils.getExtension(fileName); + if (suffix.length() != 1 || !Character.isDigit(suffix.charAt(0))) { + return BAD_CATEGORY; + } + return suffix.charAt(0) - '0'; + } +} diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerPathTemplate.java b/src/main/java/org/vafer/jdeb/producers/DataProducerPathTemplate.java index bd6cfd079..821ec567f 100644 --- a/src/main/java/org/vafer/jdeb/producers/DataProducerPathTemplate.java +++ b/src/main/java/org/vafer/jdeb/producers/DataProducerPathTemplate.java @@ -33,12 +33,7 @@ public DataProducerPathTemplate( String[] pLiteralPaths, String[] pIncludes, Str public void produce( DataConsumer pReceiver ) throws IOException { for (String literalPath : literalPaths) { - TarArchiveEntry entry = new TarArchiveEntry(literalPath, true); - entry.setUserId(0); - entry.setUserName("root"); - entry.setGroupId(0); - entry.setGroupName("root"); - entry.setMode(TarArchiveEntry.DEFAULT_DIR_MODE); + TarArchiveEntry entry = Producers.defaultDirEntryWithName(literalPath); entry = map(entry); diff --git a/src/main/java/org/vafer/jdeb/producers/ProducerFactory.java b/src/main/java/org/vafer/jdeb/producers/ProducerFactory.java new file mode 100644 index 000000000..3c52f604a --- /dev/null +++ b/src/main/java/org/vafer/jdeb/producers/ProducerFactory.java @@ -0,0 +1,187 @@ +/* + * Copyright 2013 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.producers; + +import org.vafer.jdeb.DataProducer; +import org.vafer.jdeb.mapping.Mapper; + +import java.io.File; + +/** + * Factory to create data producers at runtime. + * + * @author Roman Kashitsyn + */ +public class ProducerFactory { + + private ProducerFactory() { + } + + /** + * Enumeration of all known producer types. + */ + public enum KnownType { + FILE("file", true), + ARCHIVE("archive", true), + DIRECTORY("directory", true), + MAN_PAGE("man-page", true), + LINK("link", false), + TEMPLATE("template", false); + + private final String name; + private final boolean requiresSource; + + private KnownType( final String name, + boolean requiresSource ) { + this.name = name; + this.requiresSource = requiresSource; + } + + public boolean requiresSource() { + return requiresSource; + } + + public String shortName() { + return name; + } + + public static KnownType forString( final String typeName ) { + for (KnownType type : values()) { + if (type.shortName().equalsIgnoreCase(typeName)) { + return type; + } + } + return null; + } + } + + public static abstract class Params { + public File getSource() { + return null; + } + + public String getDestination() { + return null; + } + + public String getLink() { + return null; + } + + public String getLinkTarget() { + return null; + } + + public String[] getIncludePatterns() { + return null; + } + + public String[] getExcludePatterns() { + return null; + } + + public String[] getTemplatePaths() { + return null; + } + + public boolean isSimlink() { + return false; + } + + public Mapper[] getMappers() { + return null; + } + } + + /** + * Creates a data producer in runtime. + * + * @param type producer type + * @param params parameter provider + * @return producer or null if null type is given + * @throws java.lang.IllegalArgumentException if required parameters are missing + */ + public static DataProducer create( final KnownType type, + final Params params ) { + switch (type) { + case FILE: + return new DataProducerFile( + params.getSource(), + params.getDestination(), + params.getIncludePatterns(), + params.getExcludePatterns(), + params.getMappers() + ); + + case ARCHIVE: + return new DataProducerArchive( + params.getSource(), + params.getIncludePatterns(), + params.getExcludePatterns(), + params.getMappers() + ); + + case DIRECTORY: + return new DataProducerDirectory( + params.getSource(), + params.getIncludePatterns(), + params.getExcludePatterns(), + params.getMappers() + ); + case TEMPLATE: + final String[] paths = params.getTemplatePaths(); + if (paths == null || paths.length == 0) { + throw new IllegalArgumentException("paths is not set"); + } + + return new DataProducerPathTemplate( + paths, + params.getIncludePatterns(), + params.getExcludePatterns(), + params.getMappers() + ); + case LINK: + final String linkName = params.getLink(); + final String linkTarget = params.getLinkTarget(); + + if (linkName == null) { + throw new IllegalArgumentException("linkName is not set"); + } + if (linkTarget == null) { + throw new IllegalArgumentException("linkTarget is not set"); + } + + return new DataProducerLink( + linkName, + linkTarget, + params.isSimlink(), + params.getIncludePatterns(), + params.getExcludePatterns(), + params.getMappers() + ); + case MAN_PAGE: + return new DataProducerManPage( + params.getSource(), + params.getDestination(), + params.getIncludePatterns(), + params.getExcludePatterns(), + params.getMappers() + ); + default: + return null; + } + } +} diff --git a/src/main/java/org/vafer/jdeb/producers/Producers.java b/src/main/java/org/vafer/jdeb/producers/Producers.java new file mode 100644 index 000000000..e5d1d4496 --- /dev/null +++ b/src/main/java/org/vafer/jdeb/producers/Producers.java @@ -0,0 +1,88 @@ +/* + * Copyright 2013 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.producers; + +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; + +import org.apache.commons.io.IOUtils; +import org.vafer.jdeb.DataConsumer; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Package-private utility class with common producers functionality. + * + * @author Roman Kashitsyn + */ +class Producers { + + final static int ROOT_UID = 0; + final static String ROOT_NAME = "root"; + + private Producers() {} + + + /** + * Creates a tar file entry with defaults parameters. + * @param entryName the entry name + * @return file entry with reasonable defaults + */ + static TarArchiveEntry defaultFileEntryWithName( final String entryName ) { + TarArchiveEntry entry = new TarArchiveEntry(entryName, true); + entry.setUserId(ROOT_UID); + entry.setUserName(ROOT_NAME); + entry.setGroupId(ROOT_UID); + entry.setGroupName(ROOT_NAME); + entry.setMode(TarArchiveEntry.DEFAULT_FILE_MODE); + return entry; + } + + /** + * Creates a tar directory entry with defaults parameters. + * @param dirName the directory name + * @return dir entry with reasonable defaults + */ + static TarArchiveEntry defaultDirEntryWithName( final String dirName ) { + TarArchiveEntry entry = new TarArchiveEntry(dirName, true); + entry.setUserId(ROOT_UID); + entry.setUserName(ROOT_NAME); + entry.setGroupId(ROOT_UID); + entry.setGroupName(ROOT_NAME); + entry.setMode(TarArchiveEntry.DEFAULT_DIR_MODE); + return entry; + } + + + /** + * Feeds input stream to data consumer using metadata from tar entry. + * @param consumer the consumer + * @param inputStream the stream to feed + * @param entry the entry to use for metadata + * @throws IOException on consume error + */ + static void produceInputStreamWithEntry( final DataConsumer consumer, + final InputStream inputStream, + final TarArchiveEntry entry ) throws IOException { + try { + consumer.onEachFile(inputStream, entry.getName(), entry.getLinkName(), entry.getUserName(), entry.getUserId(), + entry.getGroupName(), entry.getGroupId(), entry.getMode(), entry.getSize()); + } finally { + IOUtils.closeQuietly(inputStream); + } + } + +} diff --git a/src/test/java/org/vafer/jdeb/maven/DataTestCase.java b/src/test/java/org/vafer/jdeb/maven/DataTestCase.java index fb894918b..b1f5d90c6 100644 --- a/src/test/java/org/vafer/jdeb/maven/DataTestCase.java +++ b/src/test/java/org/vafer/jdeb/maven/DataTestCase.java @@ -20,6 +20,7 @@ import java.io.IOException; import junit.framework.TestCase; +import org.vafer.jdeb.producers.ProducerFactory; /* * Admittedly not the nicest way to assert that failOnMissingSrc functions. However, the best that can be done without @@ -27,6 +28,8 @@ */ public class DataTestCase extends TestCase { + private static final ProducerFactory.KnownType fileType = ProducerFactory.KnownType.FILE; + private Data data; private File missingFile; private File file; @@ -56,6 +59,7 @@ public void testFailOnUnknownValue() throws IOException { public void testFailOnMissingSrcDefaultFileMissing() throws IOException { try { data.setSrc(missingFile); + data.setType(fileType.shortName()); data.produce(null); fail(); } catch (FileNotFoundException expected) { @@ -65,11 +69,13 @@ public void testFailOnMissingSrcDefaultFileMissing() throws IOException { public void testFailOnMissingSrcIgnoreFileMissing() throws IOException { data.setSrc(missingFile); data.setMissingSrc("ignore"); + data.setType(fileType.shortName()); data.produce(null); } public void testFailOnMissingSrcIgnoreFileMissingVaryInput() throws IOException { data.setSrc(missingFile); + data.setType(fileType.shortName()); data.setMissingSrc(" IGNORE "); data.produce(null); } @@ -77,6 +83,7 @@ public void testFailOnMissingSrcIgnoreFileMissingVaryInput() throws IOException public void testFailOnMissingSrcFailFileMissing() throws IOException { try { data.setSrc(missingFile); + data.setType(fileType.shortName()); data.setMissingSrc("fail"); data.produce(null); fail(); diff --git a/src/test/java/org/vafer/jdeb/producers/DataProducerManPageTest.java b/src/test/java/org/vafer/jdeb/producers/DataProducerManPageTest.java new file mode 100644 index 000000000..1a2d1c2e2 --- /dev/null +++ b/src/test/java/org/vafer/jdeb/producers/DataProducerManPageTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2013 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.producers; + +import junit.framework.TestCase; + +import java.io.File; + +import static org.vafer.jdeb.producers.DataProducerManPage.makeDestination; + +/** + * @author Roman Kashitsyn + */ +public class DataProducerManPageTest extends TestCase { + + private static final String[][] TEST_TABLE = { + /* given destination | file name | expected result */ + {null, "page.1", "/usr/share/man/man1/page.1.gz"}, + {"/some/fixed/location", "page.1", "/some/fixed/location"}, + {"/some/fixed/location", "page.1.gz", "/some/fixed/location"}, + {"", "/some/page.2.gz", "/usr/share/man/man2/page.2.gz"}, + {"", "/some/page.7.bz2", "/usr/share/man/man7/page.7.bz2"}, + {"", "page", "/usr/share/man/man1/page.1.gz"}, + {"", "page.-1", "/usr/share/man/man1/page.-1.1.gz"}, + {"", "page.txt", "/usr/share/man/man1/page.txt.1.gz"} + }; + + public void testMakeDestination() throws Exception { + for (final String[] tuple : TEST_TABLE) { + final String result = tuple[2]; + assertEquals(result, makeDestination(tuple[0], new File(tuple[1]))); + } + } +}