[jdeb] 01/09: Imported Upstream version 1.0.2~git20130829
Tony Mancill
tmancill at moszumanska.debian.org
Sun Aug 31 05:56:52 UTC 2014
This is an automated email from the git hooks/post-receive script.
tmancill pushed a commit to branch master
in repository jdeb.
commit 924c939157902fea5193bc7beaa07b87de5b0ec5
Author: tony mancill <tmancill at debian.org>
Date: Tue May 20 22:10:33 2014 -0700
Imported Upstream version 1.0.2~git20130829
---
.gitignore | 12 +
.travis.yml | 6 +
HISTORY.md | 132 +++++++
LICENSE.txt | 201 ++++++++++
NOTICE.md | 2 +
README.md | 36 ++
TODO.md | 1 +
contrib/eclipse-formatting-profile.xml | 283 ++++++++++++++
contrib/maven_scanpackages.sh | 93 +++++
docs/ant.md | 168 ++++++++
docs/maven.md | 220 +++++++++++
pom.xml | 281 ++++++++++++++
src/examples/ant/build.xml | 49 +++
src/examples/ant/src/deb/control/control | 7 +
.../main/java/org/vafer/jdeb/examples/Main.java | 7 +
src/examples/maven/CHANGES.txt | 2 +
src/examples/maven/pom.xml | 80 ++++
src/examples/maven/src/deb/control/control | 7 +
src/examples/maven/src/deb/control/postinst | 1 +
src/examples/maven/src/deb/control/postrm | 1 +
src/examples/maven/src/deb/control/preinst | 1 +
src/examples/maven/src/deb/control/prerm | 1 +
src/examples/maven/src/deb/init.d/myservice | 0
.../main/java/org/vafer/jdeb/examples/Main.java | 7 +
src/it/no-datasets/pom.xml | 33 ++
src/it/no-datasets/src/deb/control/control | 7 +
.../main/java/org/vafer/jdeb/examples/Main.java | 7 +
src/it/no-datasets/verify.groovy | 1 +
src/it/pom-only/pom.xml | 34 ++
src/it/pom-only/src/deb/control/control | 7 +
src/it/pom-only/verify.groovy | 1 +
src/it/settings.xml | 35 ++
.../java/org/vafer/jdeb/ChangesFileBuilder.java | 80 ++++
src/main/java/org/vafer/jdeb/Compression.java | 82 ++++
src/main/java/org/vafer/jdeb/Console.java | 29 ++
src/main/java/org/vafer/jdeb/ControlBuilder.java | 208 ++++++++++
src/main/java/org/vafer/jdeb/DataBuilder.java | 307 +++++++++++++++
src/main/java/org/vafer/jdeb/DataConsumer.java | 34 ++
src/main/java/org/vafer/jdeb/DataProducer.java | 29 ++
src/main/java/org/vafer/jdeb/DebMaker.java | 383 ++++++++++++++++++
.../java/org/vafer/jdeb/PackagingException.java | 43 +++
src/main/java/org/vafer/jdeb/ant/Data.java | 107 ++++++
src/main/java/org/vafer/jdeb/ant/DebAntTask.java | 173 +++++++++
src/main/java/org/vafer/jdeb/ant/Link.java | 109 ++++++
src/main/java/org/vafer/jdeb/ant/Mapper.java | 104 +++++
src/main/java/org/vafer/jdeb/ant/TaskConsole.java | 45 +++
.../java/org/vafer/jdeb/changes/ChangeSet.java | 105 +++++
.../org/vafer/jdeb/changes/ChangesProvider.java | 22 ++
.../jdeb/changes/TextfileChangesProvider.java | 143 +++++++
.../jdeb/debian/BinaryPackageControlFile.java | 85 ++++
.../java/org/vafer/jdeb/debian/ChangesFile.java | 102 +++++
.../java/org/vafer/jdeb/debian/ControlField.java | 130 +++++++
.../java/org/vafer/jdeb/debian/ControlFile.java | 153 ++++++++
src/main/java/org/vafer/jdeb/mapping/LsMapper.java | 237 ++++++++++++
src/main/java/org/vafer/jdeb/mapping/Mapper.java | 30 ++
.../java/org/vafer/jdeb/mapping/NullMapper.java | 31 ++
.../java/org/vafer/jdeb/mapping/PermMapper.java | 107 ++++++
.../org/vafer/jdeb/maven/AbstractPluginMojo.java | 47 +++
src/main/java/org/vafer/jdeb/maven/Data.java | 217 +++++++++++
src/main/java/org/vafer/jdeb/maven/DebMojo.java | 427 +++++++++++++++++++++
src/main/java/org/vafer/jdeb/maven/Mapper.java | 104 +++++
.../vafer/jdeb/maven/MissingSourceBehavior.java | 20 +
.../java/org/vafer/jdeb/maven/MojoConsole.java | 44 +++
.../vafer/jdeb/producers/AbstractDataProducer.java | 80 ++++
.../vafer/jdeb/producers/DataProducerArchive.java | 151 ++++++++
.../jdeb/producers/DataProducerDirectory.java | 129 +++++++
.../org/vafer/jdeb/producers/DataProducerFile.java | 74 ++++
.../vafer/jdeb/producers/DataProducerFileSet.java | 87 +++++
.../org/vafer/jdeb/producers/DataProducerLink.java | 60 +++
.../jdeb/producers/DataProducerPathTemplate.java | 51 +++
.../java/org/vafer/jdeb/signing/PGPSigner.java | 152 ++++++++
.../java/org/vafer/jdeb/utils/FilteredFile.java | 70 ++++
.../vafer/jdeb/utils/InformationInputStream.java | 187 +++++++++
.../vafer/jdeb/utils/InformationOutputStream.java | 58 +++
.../org/vafer/jdeb/utils/MapVariableResolver.java | 39 ++
src/main/java/org/vafer/jdeb/utils/Utils.java | 187 +++++++++
.../org/vafer/jdeb/utils/VariableResolver.java | 29 ++
src/main/resources/org/vafer/jdeb/ant/antlib.xml | 4 +
src/test/java/org/vafer/jdeb/ArchiveVisitor.java | 31 ++
src/test/java/org/vafer/jdeb/ArchiveWalker.java | 96 +++++
.../java/org/vafer/jdeb/DataBuilderTestCase.java | 82 ++++
src/test/java/org/vafer/jdeb/DebMakerTestCase.java | 157 ++++++++
.../java/org/vafer/jdeb/EmptyDataProducer.java | 28 ++
src/test/java/org/vafer/jdeb/NullConsole.java | 28 ++
.../org/vafer/jdeb/ant/AntSelectorTestCase.java | 30 ++
.../org/vafer/jdeb/ant/DebAntTaskTestCase.java | 308 +++++++++++++++
.../changes/TextfileChangesProviderTestCase.java | 79 ++++
.../org/vafer/jdeb/debian/ChangesFileTestCase.java | 36 ++
.../vafer/jdeb/debian/ControlFieldTestCase.java | 44 +++
.../jdeb/debian/PackageControlFileTestCase.java | 91 +++++
.../org/vafer/jdeb/mapping/LsMapperTestCase.java | 101 +++++
.../java/org/vafer/jdeb/maven/DataTestCase.java | 122 ++++++
.../DataProducerPathTemplateTestCase.java | 115 ++++++
.../org/vafer/jdeb/signing/PGPSignerTestCase.java | 74 ++++
.../org/vafer/jdeb/utils/FilteredFileTestCase.java | 69 ++++
.../jdeb/utils/InformationInputStreamTestCase.java | 87 +++++
.../java/org/vafer/jdeb/utils/UtilsTestCase.java | 97 +++++
src/test/resources/org/vafer/gpg/fingerprint.txt | 4 +
src/test/resources/org/vafer/gpg/pubring.gpg | Bin 0 -> 1182 bytes
src/test/resources/org/vafer/gpg/secring.gpg | Bin 0 -> 1331 bytes
src/test/resources/org/vafer/jdeb/ar/data.ar | Bin 0 -> 216 bytes
.../resources/org/vafer/jdeb/changes/changes.txt | 2 +
.../resources/org/vafer/jdeb/deb/control/control | 12 +
.../resources/org/vafer/jdeb/deb/control/postinst | 4 +
.../resources/org/vafer/jdeb/deb/control/prerm | 4 +
src/test/resources/org/vafer/jdeb/deb/data.tar.bz2 | Bin 0 -> 164 bytes
src/test/resources/org/vafer/jdeb/deb/data.tgz | Bin 0 -> 148 bytes
src/test/resources/org/vafer/jdeb/deb/data.zip | Bin 0 -> 221 bytes
.../org/vafer/jdeb/deb/data/test/testfile | 1 +
.../resources/org/vafer/jdeb/deb/test/testfile4 | 1 +
.../org/vafer/jdeb/utils/utf16be-lf-bom.txt | Bin 0 -> 22 bytes
.../resources/org/vafer/jdeb/utils/utf16be-lf.txt | Bin 0 -> 20 bytes
.../org/vafer/jdeb/utils/utf16le-lf-bom.txt | Bin 0 -> 22 bytes
.../resources/org/vafer/jdeb/utils/utf16le-lf.txt | Bin 0 -> 20 bytes
.../resources/org/vafer/jdeb/utils/utf8-crlf.txt | 1 +
.../resources/org/vafer/jdeb/utils/utf8-lf-bom.txt | 1 +
.../resources/org/vafer/jdeb/utils/utf8-lf.txt | 1 +
src/test/resources/testbuild.xml | 114 ++++++
118 files changed, 8638 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5f74209
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+.DS_Store
+.classpath
+.project
+.settings
+target
+eclipse
+dependency-reduced-pom.xml
+*.iml
+*.iws
+*.ipr
+/.idea
+.release
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..1c86c94
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,6 @@
+language: java
+jdk:
+ - oraclejdk7
+ - oraclejdk6
+ - openjdk7
+ - openjdk6
diff --git a/HISTORY.md b/HISTORY.md
new file mode 100644
index 0000000..bf3d6ae
--- /dev/null
+++ b/HISTORY.md
@@ -0,0 +1,132 @@
+## Version 1.1, released ?
+
+* [ADD] xz compression support
+* [ADD] Added link support to the Ant task
+* [ADD] Support permission in (hard) link setup
+* [FIX] On Windows, parent directories are now created automatically when adding files to the data archive
+* [CHG] Links are now symbolic by default
+
+
+## Version 1.0.1, released 28.02.2013
+
+* [ADD] Override version via environment variable DEBVERSION
+* [FIX] Use the joint copyright
+* [FIX] Fixed the maven to debian version mapping
+
+
+## Version 1.0, released 10.01.2013
+
+* [ADD] Support for symbolic links (Maven only)
+* [FIX] Unresolved variables in package maintainer scripts no longer break the build
+* [CHG] Use "_all" as architecture postfix by default
+
+
+## Version 0.11, released 14.07.2012
+
+* [ADD] Added "timestamped" maven config to turn "SNAPSHOT" into a timestamp
+* [ADD] Added "verbose" maven config option to show/hide INFO logs
+* [ADD] Expand variables in configuration files "conffiles", "preinst", "postinst", "prerm", "postrm"
+* [ADD] Added a "template" data type to create dirs
+* [ADD] Added "missingSrc" maven config to control behavior on missing files/folders
+* [CHG] Use "~" instead of "+" when converting from a SNAPSHOT version
+* [REM] Deprecated PrefixMapper was removed (use PermMapper instead)
+
+
+## Version 0.10, released 18.02.2012
+
+Polishing and regression fixes
+
+* [FIX] Don't throw exception when detecting zip archives
+* [FIX] Make sure to close the tar output stream
+* [CHG] Have warn/info level on messages
+* [CHG] Fix line endings for control files
+* [ADD] Access to all Maven variables
+
+
+## Version 0.9, released 17.12.2011
+
+Some smaller fixes, Support for the 1.8 format, Changes support working.
+
+* [FIX] Default path for changes file with Maven
+* [FIX] Unresolved variables are now treated as null
+* [CHG] "Changes" support version 1.8
+* [CHG] Warn if control files have non-unix line endings
+* [CHG] Throw an exception for unknown mappers
+* [REM] InvalidDescriptorException, wasn't really used anyway
+* [ADD] Added an "attach" attribute to specify whether maven artifact should be attached to project.
+* [ADD] Provide SHA1, SHA256 and not just MD5 for descriptors
+* [ADD] Provide "project.version" when using maven
+
+
+## Version 0.8, released 27.06.2010
+
+Lot of refactoring and support for configuration on the maven plugin. Easier permission mapping.
+
+* [CHG] Default maven artifact type is now "deb" instead of "deb-archive".
+* [CHG] Switched to commons compress for archive building.
+* [CHG] Renamed the maven goal from "deb" to "jdeb" to be more consistent.
+* [CHG] Maven goal no longer attached to execution phase by default. (see examples)
+* [CHG] Deprecated "FileSetDataProducer" in favor of "DataProducerFileSet"
+* [ADD] Added a "type" attribute to the "data" elements.
+* [ADD] New options to the maven plugin to configure the attached artifact.
+* [ADD] Added Examples for ant and maven.
+* [ADD] New "file" data source.
+
+
+## Version 0.7, released 18.08.2008
+
+Proper closing of streams!
+Many improvements on the Ant task.
+Quite a few fixes related to locale settings.
+Support for bzip2 and more descriptor keys.
+
+* [FIX] English locale for date format.
+* [FIX] Proper installation size to be kbytes instead of bytes.
+* [FIX] Close streams properly.
+* [CHG] The Ant task now breaks on errors.
+* [ADD] Support for bzip2 compression in data element of the Ant task.
+* [ADD] Compression attribute to specify data file compression (bzip2, gzip, none).
+* [ADD] More package descriptor keys (Pre-Depends, Recommends, Suggests, Breaks, Enhances, Homepage>).
+* [ADD] Verbose attribute for the Ant task.
+* [ADD] The Ant task now accepts tarfileset elements.
+
+
+## Version 0.6, released 11.01.2008
+
+* [FIX] Fixed the trailing linefeed in the 'changes' section of the changes file.
+
+
+## Version 0.5, released 26.11.2007
+
+* [FIX] Fixed the 'ls' parsing.
+* [CHG] Switched to ArInputStream/ArOutputStream.
+* [REM] Removed deprecated ant task delegate.
+* [ADD] Added "changesSave" attribute to save release information to. No longer saving those information to "changesIn".
+
+
+## Version 0.4, released 20.09.2007
+
+* [FIX] Fixed mapper support.
+* [CHG] Changed lookup from environment (DEBEMAIL, DEBFULLNAME) to overrule the descriptor.
+* [REM] Removed deprecated prefix/strip syntax.
+* [ADD] Added support for multiple mappers.
+* [ADD] Added more fields to the package descriptor.
+
+
+## Version 0.3, released 15.09.2007
+
+* [ADD] Added maintainer lookup from environment (DEBEMAIL, DEBFULLNAME).
+* [ADD] Added plugin implementation for maven.
+* [ADD] Added stricter descriptor validation.
+
+
+## Version 0.2, released 21.08.2007
+
+* [FIX] Fixed the delete of the temporary files.
+* [ADD] Added support for signed changes files.
+* [ADD] Added support for mapping ownerships and rights.
+
+
+## Version 0.1, released 19.02.2007
+
+Initial release.
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/NOTICE.md b/NOTICE.md
new file mode 100644
index 0000000..01a15f7
--- /dev/null
+++ b/NOTICE.md
@@ -0,0 +1,2 @@
+The jdeb project is under a joint copyright of the developers listed in the pom.xml file.
+Thanks to all the contributors listed for their patches and contributions.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..16850e9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,36 @@
+[![Build Status](https://secure.travis-ci.org/tcurdt/jdeb.png)](http://travis-ci.org/tcurdt/jdeb)
+
+# Debian packages in Java
+
+This library provides an Ant task and a Maven plugin to create Debian packages
+from Java builds in a truly cross platform manner. Build your Debian packages
+on any platform that has Java support. Windows, Linux, OS X - it doesn't require
+additional native tools installed. The API underneath is well abstracted and
+can easily be adopted for other areas as well.
+
+Check the documentation on how to use it with [Maven](http://github.com/tcurdt/jdeb/blob/master/docs/maven.md)
+or [Ant](http://github.com/tcurdt/jdeb/blob/master/docs/ant.md). Especially don't forget to check out the
+[examples](http://github.com/tcurdt/jdeb/blob/master/src/examples/). Current
+[javadocs](http://tcurdt.github.com/jdeb/release/1.0.1/apidocs/) and a source
+[xref](http://tcurdt.github.com/jdeb/release/1.0.1/xref/) is also available.
+
+
+## Where to get it
+
+The jars are available in the [Maven central repository](http://repo1.maven.org/maven2/org/vafer/jdeb/).
+The source releases you can get in the [download section](http://github.com/tcurdt/jdeb/downloads).
+
+If feel adventures or want to help out feel free to get the latest code
+[via git](http://github.com/tcurdt/jdeb/tree/master).
+
+ git clone git://github.com/tcurdt/jdeb.git
+
+
+## Related projects
+
+Some links to other cross platform tools to package Linux applications:
+
+* [ant-deb-task](http://code.google.com/p/ant-deb-task)
+* [jRPM](http://jrpm.sourceforge.net)
+* [RedLine](http://www.freecompany.org/redline)
+* [Install-Toolkit](http://install-toolkit.sourceforge.net)
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..e70921c
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1 @@
+please see https://github.com/tcurdt/jdeb/issues
\ No newline at end of file
diff --git a/contrib/eclipse-formatting-profile.xml b/contrib/eclipse-formatting-profile.xml
new file mode 100644
index 0000000..15365db
--- /dev/null
+++ b/contrib/eclipse-formatting-profile.xml
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<profiles version="12">
+<profile kind="CodeFormatterProfile" name="jdeb" version="12">
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
+<setting id="org.eclipse.jdt.core.compiler.source" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="240"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="8"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
+<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
+<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="240"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.5"/>
+<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
+</profile>
+</profiles>
diff --git a/contrib/maven_scanpackages.sh b/contrib/maven_scanpackages.sh
new file mode 100644
index 0000000..43f690b
--- /dev/null
+++ b/contrib/maven_scanpackages.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+###############################################################################
+#
+# Update debian repository indexes.
+#
+# It actually makes maven repositories expose a debian index.
+#
+# It also create a "virtual" stable debian repository in which is selected only
+# stable releases (filter milestonnes and release candidates).
+#
+# Requirements:
+# * This script is based on dpkg-scanpackages. It is provided by dpkg-dev package.
+# * The script expect to find (configurable)
+# ** a "releases" folder containing a maven repository with the deployed
+# releases
+# ** a "snapshots" folder containing a maven repository with the deployed
+# snaphots
+# ** make sure the "stable" folder exists if you want a filtered stable debian
+# repository
+#
+# Setup:
+# You need to set the $ROOT_REP variable to where your maven repositories are
+# located.
+#
+###############################################################################
+
+ROOT_REP=/home/maven/public_html
+SNAPSHOTS_REP="snapshots"
+RELEASES_REP="releases"
+STABLE_REP="stable"
+
+cd "$ROOT_REP"
+
+## snapshots
+if [ -d $SNAPSHOTS_REP ]; then
+ echo "Generates snapshots index"
+
+ dpkg-scanpackages -m $SNAPSHOTS_REP /dev/null > $SNAPSHOTS_REP/Packages.tmp && mv -f $SNAPSHOTS_REP/Packages.tmp $SNAPSHOTS_REP/Packages
+ gzip -9c $SNAPSHOTS_REP/Packages > $SNAPSHOTS_REP/Packages.gz.tmp && mv -f $SNAPSHOTS_REP/Packages.gz.tmp $SNAPSHOTS_REP/Packages.gz
+
+ rm -rf $SNAPSHOTS_REP/Release $SNAPSHOTS_REP/Release.gpg
+ apt-ftparchive -c=$SNAPSHOTS_REP/Release.conf release $SNAPSHOTS_REP > $SNAPSHOTS_REP/Release
+ gpg -abs --default-key 0398E391 -o $SNAPSHOTS_REP/Release.gpg $SNAPSHOTS_REP/Release
+fi
+
+## releases
+if [ -d $RELEASES_REP ]; then
+ echo "Generates releases index"
+
+ dpkg-scanpackages -m $RELEASES_REP /dev/null > $RELEASES_REP/Packages.tmp && mv -f $RELEASES_REP/Packages.tmp $RELEASES_REP/Packages
+ gzip -9c $RELEASES_REP/Packages > $RELEASES_REP/Packages.gz.tmp && mv -f $RELEASES_REP/Packages.gz.tmp $RELEASES_REP/Packages.gz
+
+ rm -rf $RELEASES_REP/Release $RELEASES_REP/Release.gpg
+ apt-ftparchive -c=$RELEASES_REP/Release.conf release $RELEASES_REP > $RELEASES_REP/Release
+ gpg -abs --default-key 0398E391 -o $RELEASES_REP/Release.gpg $RELEASES_REP/Release
+fi
+
+## stable
+if [ -d stable ]; then
+ echo "Generates stable index"
+
+ rm -rf /tmp/stable_scanpackages
+ mkdir -p /tmp/stable_scanpackages/$RELEASES_REP
+
+ function link_package ()
+ {
+ basepath=`dirname $1`
+ basepath=${basepath##$ROOT_REP/}
+ basepath=${basepath%*/}
+ mkdir -p $basepath
+ fullpath=`readlink -f $1`
+ ln -sf $fullpath "/tmp/stable_scanpackages/$basepath"
+ }
+
+ cd /tmp/stable_scanpackages/
+
+ for i in $(find "$ROOT_REP/$RELEASES_REP" -name "*.[0-9][0-9].deb" ) ; do
+ link_package $i
+ done
+
+ for i in $(find "$ROOT_REP/$RELEASES_REP" -name "*.[0-9].deb" ) ; do
+ link_package $i
+ done
+
+ dpkg-scanpackages -m $RELEASES_REP /dev/null > "$ROOT_REP/$STABLE_REP/Packages.tmp" && mv -f "$ROOT_REP/$STABLE_REP/Packages.tmp" "$ROOT_REP/$STABLE_REP/Packages"
+ gzip -9c "$ROOT_REP/$STABLE_REP/Packages" > "$ROOT_REP/$STABLE_REP/Packages.gz.tmp" && mv -f "$ROOT_REP/$STABLE_REP/Packages.gz.tmp" "$ROOT_REP/$STABLE_REP/Packages.gz"
+
+ cd "$ROOT_REP"
+
+ rm -rf $STABLE_REP/Release $STABLE_REP/Release.gpg
+ apt-ftparchive -c=$STABLE_REP/Release.conf release $STABLE_REP > $STABLE_REP/Release
+ gpg -abs --default-key 0398E391 -o $STABLE_REP/Release.gpg $STABLE_REP/Release
+fi
diff --git a/docs/ant.md b/docs/ant.md
new file mode 100644
index 0000000..a27cb87
--- /dev/null
+++ b/docs/ant.md
@@ -0,0 +1,168 @@
+# How to use jdeb with Ant
+
+Attribute | Description | Required
+------------- | ---------------------------------------------------------------------------- | --------------------------
+destfile | The debian package to be generated | Yes
+control | The directory containing the control files | Yes
+compression | Compression method for the data file (`gzip`, `bzip2`, `xz` or `none`) | No; defaults to `gzip`
+verbose | Print detailed info during the package generation | No; defaults to `false`
+keyring | The file containing the PGP keys | No
+key | The name of the key to be used in the keyring | No
+passphrase | The passphrase to use the key | No
+changesIn | The changes to add | No
+changesOut | The changes file generated | No
+changesSave | The merged changes file | No
+
+The jdeb Ant task can package up a directory as Debian package. You have to
+provide the control files defining meta information about the package (except
+the `md5sums` which gets created automatically). It creates the archive
+and if you want even a signed changes file.
+
+```xml
+ <target name="package">
+ <taskdef name="deb" classname="org.vafer.jdeb.ant.DebAntTask"/>
+ <copy todir="${deb}/control">
+ <fileset dir="src/main/resources/deb/control"/>
+ <filterset begintoken="[[" endtoken="]]">
+ <filter token="version" value="${version}"/>
+ <filter token="name" value="${ant.project.name}"/>
+ </filterset>
+ </copy>
+ <deb destfile="jdeb.deb" control="${deb}/control">
+ <data src="src/main/resources/deb/data" type="directory">
+ <exclude name="**/.svn"/>
+ </data>
+ </deb>
+ </target>
+```
+
+For cross platform builds it might be important to retain permissions,
+ownerships and links. When you provide the original tar as input the meta data
+will be kept intact gets included directly into the deb. You can apply simple
+modifications like prefixing or stripping of paths though.
+
+```xml
+ <deb destfile="jdeb.deb" control="${deb}/control">
+ <data src="src/release.tgz" type="archive">
+ <mapper type="perm" strip="1" prefix="/somewhere/else"/>
+ <exclude name="**/.svn"/>
+ </data>
+ </deb>
+```
+
+For more complex permission and ownership adjustments you can use a "ls"
+mapper. It allows you to define permissions and ownerships in a text file and
+even under Windows you will be able to build your debian package.
+
+```xml
+ <deb destfile="jdeb.deb" control="${deb}/control">
+ <data src="src/release.tgz" type="archive">
+ <mapper type="ls" src="mapping.txt" />
+ </data>
+ </deb>
+```
+
+The mapper will apply the output of an "ls -laR > mapping.txt" command
+that should look like this
+
+ ./trunk/target/test-classes/org/vafer/dependency:
+ total 176
+ drwxr-xr-x 23 tcurdt tcurdt 782 Jun 25 03:48 .
+ drwxr-xr-x 3 tcurdt tcurdt 102 Jun 25 03:48 ..
+ -rw-r--r-- 1 tcurdt tcurdt 2934 Jun 25 03:48 DependenciesTestCase.class
+ -rw-r--r-- 1 tcurdt tcurdt 2176 Jun 25 03:48 WarTestCase.class
+ drwxr-xr-x 4 tcurdt tcurdt 136 Jun 25 03:48 classes
+
+It's also possible to use a `fileset` or even a `tarfileset` to
+specify the set of files to include with their permissions :
+
+```xml
+ <deb destfile="jdeb.deb" control="${deb}/control">
+ <tarfileset dir="src/main/resources/deb/data"
+ prefix="/somewhere/else"
+ filemode="600"
+ username="tcurdt"
+ group="tcurdt"/>
+ </deb>
+```
+
+Links can be added by specifying a `link` element:
+
+```xml
+ <deb destfile="jdeb.deb" control="${deb}/control">
+ <link name="/usr/share/java/foo.jar" target="/usr/share/java/foo-1.0.jar"/>
+ </deb>
+```
+
+Here are the supported attributes on the `link` element:
+
+Attribute | Description | Required
+------------- | ------------------------------------------------------ | -----------------------
+name | The path of the link | Yes
+target | The target of the link | Yes
+symbolic | The type of the link (`true`: symbolic, `false`: hard) | No; defaults to `true`
+uid | Numerical uid | No; defaults to 0
+gid | Numerical gid | No; defaults to 0
+user | User name | No; defaults to "root"
+group | User group | No; defaults to "root"
+mode | Permissions as octet | No; deftauls to 777
+
+## Changes file
+
+In order to also create a changes file you will need to provide the input and
+output of the changes. The input file is a much simpler file where you should
+list your changes. Every change should be starting with the " * " and one line
+only.
+
+ * changes for the next release
+ release distribution=staging, date=20:13 17.08.2007,version=1.4+r89114,urgency=low,by=Torsten Curdt <torsten at vafer.org>
+ * debian changes support
+
+When you do a release jdeb will add (or complete!) the release line and create
+a debian format standard changes file for you. (Don't forget to commit changes
+jdeb did to the file.) From Ant you have to call jdeb like this
+
+```xml
+ <deb destfile="jdeb.deb"
+ control="${deb}/control"
+ changesIn="changes.txt"
+ changesOut="jdeb.changes">
+ <data src="some/dir"/>
+ </deb>
+```
+
+If you also provide a `changesSave` attribute the jdeb will add release
+information to the original input and write out the new file.
+
+```xml
+ <deb destfile="jdeb.deb"
+ control="${deb}/control"
+ changesIn="changes.txt"
+ changesOut="jdeb.changes"
+ changesSave="changes.txt">
+ <data src="some/dir"/>
+ </deb>
+```
+
+## Signing changes
+
+To have the changes be signed, make sure you have the
+[BouncyCastle OpenPGP/BCPG jar](http://www.bouncycastle.org/latest_releases.html) in your
+classpath (just copy it into the `$ANT_HOME/lib` folder - next to jdeb).
+Then you can sign your changes file with:
+
+```xml
+ <deb destfile="jdeb.deb"
+ control="${deb}/control"
+ changesIn="changes.txt"
+ changesOut="jdeb.changes"
+ key="2E074D8F"
+ passphrase="secret"
+ keyring="/Users/tcurdt/.gnupg/secring.gpg">
+ <data src="some/dir"/>
+ </deb>
+```
+
+<b>Security Note</b>: Hard coding the passphrase in the `<deb>` task can be a serious
+security hole. Consider using variable substitution and asking the passphrase
+to the user with the `<input>` task, or retrieving it from a secured `.properties` file.
diff --git a/docs/maven.md b/docs/maven.md
new file mode 100644
index 0000000..83e825c
--- /dev/null
+++ b/docs/maven.md
@@ -0,0 +1,220 @@
+# How to use jdeb with Maven
+
+Generating a default Debian package with maven is particular easy. Just add
+the plugin to your POM like this
+
+```xml
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>jdeb</artifactId>
+ <groupId>org.vafer</groupId>
+ <version>1.0</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>jdeb</goal>
+ </goals>
+ <configuration>
+ <dataSet>
+ <data>
+ <src>${project.build.directory}/${project.build.finalName}.jar</src>
+ <type>file</type>
+ <mapper>
+ <type>perm</type>
+ <prefix>/usr/share/jdeb/lib</prefix>
+ </mapper>
+ </data>
+ </dataSet>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+```
+
+At least the one main control file is required to control the creation of the
+debian package. This required control file should be found in the control
+directory. By default the control file name is also `control` which gives a
+path of `src/deb/control/control` by default. This control file contains the
+metadata about the Debian package. Usually it will look something along the lines of
+
+ Package: [[name]]
+ Version: [[version]]
+ Section: misc
+ Priority: optional
+ Architecture: all
+ Depends: jdk (>= 1.5)
+ Maintainer: Torsten Curdt <torsten at something.com>
+ Description: jetty java servlet container
+ Distribution: development
+
+
+If the environment variables `DEBEMAIL` and `DEBFULLNAME` are both set this
+will overrule the `Maintainer` field set in there. The `Installed-Size` will
+also be injected. If a changes file is used, the `Distribution` usually comes
+from that file. The default changes file is called `CHANGES.txt`. See below
+for the syntax of the content of the changes file.
+
+Property replacement will also occur in any of the standard debian control
+files: conffiles, preinst, postinst, prerm, postrm. This allows dynamic
+configuration of the form:
+
+ /etc/[[artifactId]]/[[artifactId]].properties
+ /etc/[[artifactId]]/log4j.xml
+
+If you now do a `mvn clean install`, the `deb` goal will be called and
+artifacts consisting of the deb and potentially the changes file will
+automatically be attached to the project.
+
+The jdeb maven plugin also supports a variety of configuration options. These
+configuration options provide the same features available in the jdeb ant
+task. To configure the jdeb maven plugin, populate the jdeb configuration
+section with any of the following options:
+
+Element | Description | Required
+------------- | ---------------------------------------------------------------------------- | -----------------------------------------------------------------
+deb | The debian package to be generated | No; defaults to `${buildDirectory}/${artifactId}_${version}.deb`
+type | Artifact type | No; defaults to `deb`
+classifier | Artifact classifier | No; defaults to ''
+controlDir | The directory containing the control files | No; defaults to `src/deb/control`
+installDir | The default directory for the project artifact if no data section is present | No; defaults to `/opt/${artifactId}`
+dataSet | A list of directories, tarballs, or files to include in the deb package | No; defaults to include your maven artifact
+changesIn | The changes to add | No
+changesOut | The changes file generated | No
+changesSave | (NYI) The merged changes file | No
+compression | (NYI) Compression method for the data file (`gzip`, `bzip2`, `xz` or `none`) | No; defaults to `gzip`
+keyring | (NYI) The file containing the PGP keys | No
+key | (NYI) The name of the key to be used in the keyring | No
+passphrase | (NYI) The passphrase to use the key | No
+attach | Attach artifact to project | No; defaults to `true`
+submodules | Execute the goal on all sub-modules | No; defaults to `true`
+timestamped | Turn SNAPSHOT into timestamps | No; defaults to `false`
+verbose | Verbose logging | No; defaults to `true`, will be `false` in the future
+
+If you use the `dataSet` element, you'll need to populate it with a one or
+more `data` elements. A `data` element is used to specify a directory, a
+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
+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.
+
+Element | Description | Required
+------------- | ----------------------------------------------------- | -----------------------
+type | 'perm' | Yes
+prefix | Add this prefix to the files | No; defaults to ""
+uid | Numerical uid | No; defaults to 0
+gid | Numerical gid | No; defaults to 0
+user | User name | No; defaults to "root"
+group | User group | No; defaults to "root"
+filemode | File permissions as octet | No; deftauls to 644
+dirmode | Dir permissions as octet | No; defaults to 755
+strip | Strip n path components from the original file | No; defaults to 0
+
+Below is an example of how you could configure your jdeb maven plugin to
+include a directory, a tarball, and a file in your deb package:
+
+```xml
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>jdeb</artifactId>
+ <groupId>org.vafer</groupId>
+ <version>1.0</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>jdeb</goal>
+ </goals>
+ <configuration>
+
+ <dataSet>
+
+ <!-- Tarball example -->
+ <data>
+ <src>${project.basedir}/target/my_archive.tar.gz</src>
+ <type>archive</type>
+ <includes>...</includes>
+ <excludes>...</excludes>
+ <mapper>
+ <type>perm</type>
+ <strip>1</strip>
+ <prefix>/somewhere/else</prefix>
+ <user>tcurdt</user>
+ <group>tcurdt</group>
+ <filemode>600</filemode>
+ </mapper>
+ </data>
+
+ <!-- Directory example -->
+ <data>
+ <src>${project.build.directory}/data</src>
+ <type>directory</type>
+ <includes/>
+ <excludes>**/.svn</excludes>
+ <mapper>
+ <type>ls</type>
+ <src>mapping.txt</src>
+ </mapper>
+ </data>
+
+ <!-- File example -->
+ <data>
+ <src>${project.basedir}/README.txt</src>
+ <dst>README</dst>
+ <type>file</type>
+ <missingSrc>ignore</missingSrc>
+ </data>
+
+ <!-- Template example -->
+ <data>
+ <type>template</type>
+ <paths>
+ <path>/etc/${artifactId}</path>
+ <path>/var/lib/${artifactId}</path>
+ <path>/var/log/${artifactId}</path>
+ <path>/var/run/${artifactId}</path>
+ </paths>
+ </data>
+
+ <!-- Hard link example -->
+ <data>
+ <type>link</type>
+ <linkName>/a/path/on/the/target/fs</linkName>
+ <linkTarget>/a/link/to/the/scr/file</linkTarget>
+ <symlink>false</symlink>
+ </data>
+
+ <!-- Symbolic link example -->
+ <data>
+ <type>link</type>
+ <linkName>/a/path/on/the/target/fs</linkName>
+ <linkTarget>/a/sym/link/to/the/scr/file</linkTarget>
+ <symlink>true</symlink>
+ </data>
+ </dataSet>
+
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+```
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..d6d4991
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.vafer</groupId>
+ <artifactId>jdeb</artifactId>
+ <packaging>maven-plugin</packaging>
+ <name>jdeb</name>
+ <version>1.0.2-SNAPSHOT</version>
+ <description>
+ This library provides an Ant task and a Maven plugin to create Debian packages from Java builds in a truly cross
+ platform manner. Build your Debian packages on any platform that has Java support. Windows, Linux, OS X - it doesn't
+ require additional native tools installed.
+ </description>
+ <url>http://github.com/tcurdt/jdeb</url>
+ <developers>
+ <developer>
+ <id>tcurdt</id>
+ <name>Torsten Curdt</name>
+ <email>tcurdt at apache.org</email>
+ <roles><role>Lead Developer</role></roles>
+ <timezone>+1</timezone>
+ </developer>
+ <developer>
+ <id>ebourg</id>
+ <name>Emmanuel Bourg</name>
+ <email>ebourg at apache.org</email>
+ <timezone>+1</timezone>
+ </developer>
+ <developer>
+ <id>tmortagne</id>
+ <name>Thomas Mortagne</name>
+ <email>thomas.mortagne at gmail.com</email>
+ <timezone>+1</timezone>
+ </developer>
+ </developers>
+ <contributors>
+ <contributor><name>Bryan Sant</name></contributor>
+ <contributor><name>Christian Rigdon</name></contributor>
+ <contributor><name>Elliot West</name></contributor>
+ <contributor><name>Jeroen Rosenberg</name></contributor>
+ <contributor><name>Manuel Woelker</name></contributor>
+ <contributor><name>Patrick Schultz</name></contributor>
+ <contributor><name>Petr Kozelka</name></contributor>
+ <contributor><name>Scott Kuehn</name></contributor>
+ <contributor><name>Ralph van Etten</name></contributor>
+ <contributor><name>Alexander Horz</name></contributor>
+ </contributors>
+ <licenses>
+ <license>
+ <name>Apache License 2</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <connection>scm:git:git://github.com:tcurdt/jdeb.git</connection>
+ <developerConnection>scm:git:git://github.com:tcurdt/jdeb.git</developerConnection>
+ <url>http://github.com/tcurdt/jdeb/tree/master</url>
+ </scm>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <maven.compiler.source>1.6</maven.compiler.source>
+ <maven.compiler.target>1.6</maven.compiler.target>
+ </properties>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>3.1</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ <encoding>${project.build.sourceEncoding}</encoding>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>1.7.1</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <!-- <dependencyReducedPomLocation>${basedir}/target/dependency-reduced-pom.xml</dependencyReducedPomLocation> -->
+ <minimizeJar>true</minimizeJar>
+ <artifactSet>
+ <includes>
+ <include>org.apache.commons:commons-compress</include>
+ <include>commons-io:commons-io</include>
+ </includes>
+ </artifactSet>
+ <relocations>
+ <relocation>
+ <pattern>org.apache.commons</pattern>
+ <shadedPattern>org.vafer.jdeb.shaded.compress</shadedPattern>
+ </relocation>
+ </relocations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.11</version>
+ <configuration>
+ <forkMode>never</forkMode>
+ <includes>
+ <include>**/*TestCase.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/Abstract*</exclude>
+ </excludes>
+ <testFailureIgnore>false</testFailureIgnore>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.6</version>
+ <configuration>
+ <!-- <debug>true</debug> -->
+ <projectsDirectory>src/it</projectsDirectory>
+ <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+ <preBuildHookScript>setup</preBuildHookScript>
+ <postBuildHookScript>verify</postBuildHookScript>
+ <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
+ <settingsFile>src/it/settings.xml</settingsFile>
+ <pomIncludes>
+ <pomInclude>*/pom.xml</pomInclude>
+ </pomIncludes>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <!--
+ <goal>verify</goal>
+ <goal>install</goal>
+ -->
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <!-- mvn versions:display-dependency-updates -->
+ <!-- mvn versions:display-plugin-updates -->
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-compress</artifactId>
+ <version>1.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-core</artifactId>
+ <version>2.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>2.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-project</artifactId>
+ <version>2.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-artifact</artifactId>
+ <version>2.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-utils</artifactId>
+ <version>1.4.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant</artifactId>
+ <version>1.7.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpg-jdk15on</artifactId>
+ <version>1.48</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.2</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <reporting>
+ <excludeDefaults>true</excludeDefaults>
+ <outputDirectory>${project.build.directory}/site</outputDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-project-info-reports-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <dependencyDetailsEnabled>false</dependencyDetailsEnabled>
+ <dependencyLocationsEnabled>false</dependencyLocationsEnabled>
+ </configuration>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>project-team</report>
+ <report>dependencies</report>
+ <report>license</report>
+ <report>scm</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.8.1</version>
+ <configuration>
+ <linksource>true</linksource>
+ <links>
+ <link>http://java.sun.com/javase/6/docs/api</link>
+ </links>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ <version>2.12</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <version>2.7.1</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jxr-plugin</artifactId>
+ <version>2.3</version>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>taglist-maven-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <tags>
+ <tag>FIXME</tag>
+ <tag>TODO</tag>
+ <tag>@todo</tag>
+ <tag>@deprecated</tag>
+ </tags>
+ <aggregate>true</aggregate>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
diff --git a/src/examples/ant/build.xml b/src/examples/ant/build.xml
new file mode 100644
index 0000000..3af211e
--- /dev/null
+++ b/src/examples/ant/build.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<project name="jdeb-example" default="package">
+
+ <property name="version" value="1.0"/>
+ <property name="description" value="Some description"/>
+ <property name="src.dir" value="${basedir}/src"/>
+ <property name="build.dir" value="${basedir}/build"/>
+
+ <target name="clean">
+ <delete dir="${build.dir}"/>
+ </target>
+
+ <target name="compile">
+ <mkdir dir="${build.dir}/classes"/>
+ <javac srcdir="src/main/java" destdir="${build.dir}/classes" includeantruntime="false"/>
+ </target>
+
+ <target name="jar" depends="compile">
+ <mkdir dir="${build.dir}/jar"/>
+ <jar destfile="${build.dir}/jar/${ant.project.name}-${version}.jar" basedir="${build.dir}/classes">
+ <manifest>
+ <attribute name="Main-Class" value="org.vafer.jdeb.example.Main"/>
+ </manifest>
+ </jar>
+ </target>
+
+ <target name="package" depends="jar">
+ <taskdef name="deb" classname="org.vafer.jdeb.ant.DebAntTask"/>
+
+ <copy todir="${build.dir}/deb/control">
+ <fileset dir="src/deb/control"/>
+ <filterset begintoken="[[" endtoken="]]">
+ <filter token="version" value="${version}"/>
+ <filter token="description" value="${description}"/>
+ <filter token="name" value="${ant.project.name}"/>
+ </filterset>
+ </copy>
+
+ <deb destfile="${build.dir}/${ant.project.name}.deb" control="${build.dir}/deb/control" verbose="true">
+
+ <data src="${build.dir}/jar/${ant.project.name}-${version}.jar" type="file">
+ <mapper type="perm" prefix="/usr/share/jdeb/lib"/>
+ </data>
+
+ </deb>
+
+ </target>
+
+</project>
\ No newline at end of file
diff --git a/src/examples/ant/src/deb/control/control b/src/examples/ant/src/deb/control/control
new file mode 100644
index 0000000..6cfaa51
--- /dev/null
+++ b/src/examples/ant/src/deb/control/control
@@ -0,0 +1,7 @@
+Package: [[name]]
+Version: [[version]]
+Section: misc
+Priority: low
+Architecture: all
+Description: [[description]]
+Maintainer: tcurdt at vafer.org
diff --git a/src/examples/ant/src/main/java/org/vafer/jdeb/examples/Main.java b/src/examples/ant/src/main/java/org/vafer/jdeb/examples/Main.java
new file mode 100644
index 0000000..62a2434
--- /dev/null
+++ b/src/examples/ant/src/main/java/org/vafer/jdeb/examples/Main.java
@@ -0,0 +1,7 @@
+package org.vafer.jdeb.examples;
+
+public class Main {
+ public static void main(String[] args) {
+ System.out.println("jdeb example!");
+ }
+}
diff --git a/src/examples/maven/CHANGES.txt b/src/examples/maven/CHANGES.txt
new file mode 100644
index 0000000..abd3035
--- /dev/null
+++ b/src/examples/maven/CHANGES.txt
@@ -0,0 +1,2 @@
+release date=20:13 15.12.2011,version=0.9,urgency=low,by=Torsten Curdt <torsten at youknowwhere.org>,distribution=unknown
+ * lots of fixes here
diff --git a/src/examples/maven/pom.xml b/src/examples/maven/pom.xml
new file mode 100644
index 0000000..9a61bc5
--- /dev/null
+++ b/src/examples/maven/pom.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.vafer</groupId>
+ <artifactId>jdeb-example</artifactId>
+ <version>1.0</version>
+ <description>description from pom</description>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>jdeb</artifactId>
+ <groupId>org.vafer</groupId>
+ <version>1.0</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>jdeb</goal>
+ </goals>
+ <configuration>
+ <verbose>true</verbose>
+ <controlDir>${basedir}/src/deb/control</controlDir>
+ <dataSet>
+
+ <data>
+ <src>${project.build.directory}/${project.build.finalName}.jar</src>
+ <type>file</type>
+ <mapper>
+ <type>perm</type>
+ <prefix>/usr/share/jdeb/lib</prefix>
+ <user>loader</user>
+ <group>loader</group>
+ </mapper>
+ </data>
+
+ <data>
+ <type>link</type>
+ <symlink>true</symlink>
+ <linkName>/usr/share/java/jdeb.jar</linkName>
+ <linkTarget>/usr/share/jdeb/lib/${project.build.finalName}.jar</linkTarget>
+ </data>
+
+ <data>
+ <src>${basedir}/src/deb/init.d</src>
+ <type>directory</type>
+ <mapper>
+ <type>perm</type>
+ <prefix>/etc/init.d</prefix>
+ <user>loader</user>
+ <group>loader</group>
+ </mapper>
+ </data>
+
+ <data>
+ <type>template</type>
+ <paths>
+ <path>etc/${project.artifactId}</path>
+ <path>var/lib/${project.artifactId}</path>
+ <path>var/log/${project.artifactId}</path>
+ <path>var/run/${project.artifactId}</path>
+ </paths>
+ <mapper>
+ <type>perm</type>
+ <user>loader</user>
+ <group>loader</group>
+ </mapper>
+ </data>
+
+ </dataSet>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/src/examples/maven/src/deb/control/control b/src/examples/maven/src/deb/control/control
new file mode 100644
index 0000000..6cfaa51
--- /dev/null
+++ b/src/examples/maven/src/deb/control/control
@@ -0,0 +1,7 @@
+Package: [[name]]
+Version: [[version]]
+Section: misc
+Priority: low
+Architecture: all
+Description: [[description]]
+Maintainer: tcurdt at vafer.org
diff --git a/src/examples/maven/src/deb/control/postinst b/src/examples/maven/src/deb/control/postinst
new file mode 100644
index 0000000..1a24852
--- /dev/null
+++ b/src/examples/maven/src/deb/control/postinst
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/src/examples/maven/src/deb/control/postrm b/src/examples/maven/src/deb/control/postrm
new file mode 100644
index 0000000..1a24852
--- /dev/null
+++ b/src/examples/maven/src/deb/control/postrm
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/src/examples/maven/src/deb/control/preinst b/src/examples/maven/src/deb/control/preinst
new file mode 100644
index 0000000..1a24852
--- /dev/null
+++ b/src/examples/maven/src/deb/control/preinst
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/src/examples/maven/src/deb/control/prerm b/src/examples/maven/src/deb/control/prerm
new file mode 100644
index 0000000..1a24852
--- /dev/null
+++ b/src/examples/maven/src/deb/control/prerm
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/src/examples/maven/src/deb/init.d/myservice b/src/examples/maven/src/deb/init.d/myservice
new file mode 100644
index 0000000..e69de29
diff --git a/src/examples/maven/src/main/java/org/vafer/jdeb/examples/Main.java b/src/examples/maven/src/main/java/org/vafer/jdeb/examples/Main.java
new file mode 100644
index 0000000..ab2399c
--- /dev/null
+++ b/src/examples/maven/src/main/java/org/vafer/jdeb/examples/Main.java
@@ -0,0 +1,7 @@
+package org.vafer.jdeb.examples;
+
+public class Main {
+ public static void main(String[] args) {
+ System.out.println("jdeb example!");
+ }
+}
diff --git a/src/it/no-datasets/pom.xml b/src/it/no-datasets/pom.xml
new file mode 100644
index 0000000..66400ef
--- /dev/null
+++ b/src/it/no-datasets/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.vafer</groupId>
+ <artifactId>jdeb-it</artifactId>
+ <version>1.0</version>
+ <description>description from pom</description>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.vafer</groupId>
+ <artifactId>jdeb</artifactId>
+ <version>@project.version@</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>jdeb</goal>
+ </goals>
+ <configuration>
+ <verbose>true</verbose>
+ <controlDir>${basedir}/src/deb/control</controlDir>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/src/it/no-datasets/src/deb/control/control b/src/it/no-datasets/src/deb/control/control
new file mode 100644
index 0000000..6cfaa51
--- /dev/null
+++ b/src/it/no-datasets/src/deb/control/control
@@ -0,0 +1,7 @@
+Package: [[name]]
+Version: [[version]]
+Section: misc
+Priority: low
+Architecture: all
+Description: [[description]]
+Maintainer: tcurdt at vafer.org
diff --git a/src/it/no-datasets/src/main/java/org/vafer/jdeb/examples/Main.java b/src/it/no-datasets/src/main/java/org/vafer/jdeb/examples/Main.java
new file mode 100644
index 0000000..62a2434
--- /dev/null
+++ b/src/it/no-datasets/src/main/java/org/vafer/jdeb/examples/Main.java
@@ -0,0 +1,7 @@
+package org.vafer.jdeb.examples;
+
+public class Main {
+ public static void main(String[] args) {
+ System.out.println("jdeb example!");
+ }
+}
diff --git a/src/it/no-datasets/verify.groovy b/src/it/no-datasets/verify.groovy
new file mode 100644
index 0000000..d2980bc
--- /dev/null
+++ b/src/it/no-datasets/verify.groovy
@@ -0,0 +1 @@
+assert new File( basedir, 'target/jdeb-it_1.0_all.deb' ).exists();
diff --git a/src/it/pom-only/pom.xml b/src/it/pom-only/pom.xml
new file mode 100644
index 0000000..6a0cc16
--- /dev/null
+++ b/src/it/pom-only/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.vafer</groupId>
+ <artifactId>jdeb-it</artifactId>
+ <version>1.0</version>
+ <packaging>pom</packaging>
+ <description>description from pom</description>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.vafer</groupId>
+ <artifactId>jdeb</artifactId>
+ <version>@project.version@</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>jdeb</goal>
+ </goals>
+ <configuration>
+ <verbose>true</verbose>
+ <controlDir>${basedir}/src/deb/control</controlDir>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/src/it/pom-only/src/deb/control/control b/src/it/pom-only/src/deb/control/control
new file mode 100644
index 0000000..6cfaa51
--- /dev/null
+++ b/src/it/pom-only/src/deb/control/control
@@ -0,0 +1,7 @@
+Package: [[name]]
+Version: [[version]]
+Section: misc
+Priority: low
+Architecture: all
+Description: [[description]]
+Maintainer: tcurdt at vafer.org
diff --git a/src/it/pom-only/verify.groovy b/src/it/pom-only/verify.groovy
new file mode 100644
index 0000000..d2980bc
--- /dev/null
+++ b/src/it/pom-only/verify.groovy
@@ -0,0 +1 @@
+assert new File( basedir, 'target/jdeb-it_1.0_all.deb' ).exists();
diff --git a/src/it/settings.xml b/src/it/settings.xml
new file mode 100644
index 0000000..2d90068
--- /dev/null
+++ b/src/it/settings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<settings>
+ <profiles>
+ <profile>
+ <id>it-repo</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <repositories>
+ <repository>
+ <id>local.central</id>
+ <url>@localRepositoryUrl@</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>local.central</id>
+ <url>@localRepositoryUrl@</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </pluginRepository>
+ </pluginRepositories>
+ </profile>
+ </profiles>
+</settings>
diff --git a/src/main/java/org/vafer/jdeb/ChangesFileBuilder.java b/src/main/java/org/vafer/jdeb/ChangesFileBuilder.java
new file mode 100644
index 0000000..5da3367
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/ChangesFileBuilder.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2013 The Apache Software Foundation.
+ *
+ * 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.File;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.output.NullOutputStream;
+import org.vafer.jdeb.changes.ChangesProvider;
+import org.vafer.jdeb.debian.BinaryPackageControlFile;
+import org.vafer.jdeb.debian.ChangesFile;
+import org.vafer.jdeb.utils.InformationOutputStream;
+
+/**
+ * Builds the Debian changes file.
+ */
+class ChangesFileBuilder {
+
+ public ChangesFile createChanges(BinaryPackageControlFile packageControlFile, File binaryPackage, ChangesProvider changesProvider) throws IOException, PackagingException {
+
+ ChangesFile changesFile = new ChangesFile();
+ changesFile.setChanges(changesProvider.getChangesSets());
+ changesFile.initialize(packageControlFile);
+
+ changesFile.set("Date", ChangesFile.DATE_FORMAT.format(new Date()));
+
+ try {
+ // compute the checksums of the binary package
+ InformationOutputStream md5output = new InformationOutputStream(new NullOutputStream(), MessageDigest.getInstance("MD5"));
+ InformationOutputStream sha1output = new InformationOutputStream(md5output, MessageDigest.getInstance("SHA1"));
+ InformationOutputStream sha256output = new InformationOutputStream(sha1output, MessageDigest.getInstance("SHA-256"));
+
+ FileUtils.copyFile(binaryPackage, sha256output);
+
+ // Checksums-Sha1:
+ // 56ef4c6249dc3567fd2967f809c42d1f9b61adf7 45964 jdeb.deb
+ changesFile.set("Checksums-Sha1", sha1output.getHexDigest() + " " + binaryPackage.length() + " " + binaryPackage.getName());
+
+ // Checksums-Sha256:
+ // 38c6fa274eb9299a69b739bcbdbd05c7ffd1d8d6472f4245ed732a25c0e5d616 45964 jdeb.deb
+ changesFile.set("Checksums-Sha256", sha256output.getHexDigest() + " " + binaryPackage.length() + " " + binaryPackage.getName());
+
+ StringBuilder files = new StringBuilder(md5output.getHexDigest());
+ files.append(' ').append(binaryPackage.length());
+ files.append(' ').append(packageControlFile.get("Section"));
+ files.append(' ').append(packageControlFile.get("Priority"));
+ files.append(' ').append(binaryPackage.getName());
+ changesFile.set("Files", files.toString());
+
+ } catch (NoSuchAlgorithmException e) {
+ throw new PackagingException("Unable to compute the checksums for " + binaryPackage, e);
+ }
+
+ if (!changesFile.isValid()) {
+ throw new PackagingException("Changes file fields are invalid " + changesFile.invalidFields() +
+ ". The following fields are mandatory: " + changesFile.getMandatoryFields() +
+ ". Please check your pom.xml/build.xml and your control file.");
+ }
+
+ return changesFile;
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/Compression.java b/src/main/java/org/vafer/jdeb/Compression.java
new file mode 100644
index 0000000..5ab1a6c
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/Compression.java
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+import java.io.OutputStream;
+
+import org.apache.commons.compress.compressors.CompressorException;
+import org.apache.commons.compress.compressors.CompressorStreamFactory;
+
+/**
+ * Compression method used for the data file.
+ *
+ * @author Emmanuel Bourg
+ */
+public enum Compression {
+
+ NONE(""),
+ GZIP(".gz"),
+ BZIP2(".bz2"),
+ XZ(".xz");
+
+ private String extension;
+
+ private Compression(String extension) {
+ this.extension = extension;
+ }
+
+ /**
+ * Returns the extension of the compression method
+ */
+ public String getExtension() {
+ return extension;
+ }
+
+ public OutputStream toCompressedOutputStream(OutputStream out) throws CompressorException {
+ switch (this) {
+ case GZIP:
+ return new CompressorStreamFactory().createCompressorOutputStream("gz", out);
+ case BZIP2:
+ return new CompressorStreamFactory().createCompressorOutputStream("bzip2", out);
+ case XZ:
+ return new CompressorStreamFactory().createCompressorOutputStream("xz", out);
+ default:
+ return out;
+ }
+ }
+
+ /**
+ * Returns the compression method corresponding to the specified name.
+ * The matching is case insensitive.
+ *
+ * @param name the name of the compression method
+ * @return the compression method, or null if not recognized
+ */
+ public static Compression toEnum(String name) {
+ if ("gzip".equalsIgnoreCase(name) || "gz".equalsIgnoreCase(name)) {
+ return GZIP;
+ } else if ("bzip2".equalsIgnoreCase(name) || "bz2".equalsIgnoreCase(name)) {
+ return BZIP2;
+ } else if ("xz".equalsIgnoreCase(name)) {
+ return XZ;
+ } else if ("none".equalsIgnoreCase(name)) {
+ return NONE;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/Console.java b/src/main/java/org/vafer/jdeb/Console.java
new file mode 100644
index 0000000..b0b21cf
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/Console.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/**
+ * Plug in your favorite log implementation.
+ *
+ * @author Torsten Curdt
+ */
+public interface Console {
+
+ void info( String s );
+
+ void warn( String s );
+
+}
diff --git a/src/main/java/org/vafer/jdeb/ControlBuilder.java b/src/main/java/org/vafer/jdeb/ControlBuilder.java
new file mode 100644
index 0000000..fdb4e7e
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/ControlBuilder.java
@@ -0,0 +1,208 @@
+/*
+ * 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;
+
+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.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;
+
+ ControlBuilder(Console console, VariableResolver resolver) {
+ this.console = console;
+ this.resolver = resolver;
+ }
+
+ /**
+ * 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, 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);
+
+ // 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.info("Found directory '" + file + "' in the control directory. Maybe you are pointing to wrong dir?");
+ }
+ continue;
+ }
+
+ if (CONFIGURATION_FILENAMES.contains(file.getName()) || MAINTAINER_SCRIPTS.contains(file.getName())) {
+ FilteredFile configurationFile = new FilteredFile(new FileInputStream(file), resolver);
+ 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 (packageControlFile == null) {
+ throw new FileNotFoundException("No 'control' file found in " + Arrays.toString(controlFiles));
+ }
+
+ addControlEntry("control", packageControlFile.toString(), outputStream);
+ addControlEntry("md5sums", checksums.toString(), outputStream);
+
+ outputStream.close();
+ }
+
+
+ /**
+ * 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.info("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.info("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;
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/DataBuilder.java b/src/main/java/org/vafer/jdeb/DataBuilder.java
new file mode 100644
index 0000000..4768fe4
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/DataBuilder.java
@@ -0,0 +1,307 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
+import org.apache.commons.compress.archivers.tar.TarConstants;
+import org.apache.commons.compress.archivers.zip.ZipEncoding;
+import org.apache.commons.compress.archivers.zip.ZipEncodingHelper;
+import org.apache.commons.compress.compressors.CompressorException;
+import org.vafer.jdeb.utils.Utils;
+
+/**
+ * Builds the data archive of the Debian package.
+ */
+class DataBuilder {
+
+ private Console console;
+
+ private ZipEncoding encoding;
+
+ private static final class Total {
+ private BigInteger count = BigInteger.valueOf(0);
+
+ public void add( long size ) {
+ count = count.add(BigInteger.valueOf(size));
+ }
+
+ public String toString() {
+ return "" + count;
+ }
+ }
+
+ DataBuilder(Console console) {
+ this.console = console;
+ this.encoding = ZipEncodingHelper.getZipEncoding(null);
+ }
+
+ private void checkField(String name, int length) throws IOException {
+ if (name != null) {
+ ByteBuffer b = encoding.encode(name);
+ if (b.limit() > length) {
+ throw new IllegalArgumentException("Field '" + name + "' too long, maximum is " + length);
+ }
+ }
+ }
+
+ /**
+ * Build the data archive of the deb from the provided DataProducers
+ *
+ * @param producers
+ * @param output
+ * @param checksums
+ * @param compression the compression method used for the data file
+ * @return
+ * @throws java.security.NoSuchAlgorithmException
+ * @throws java.io.IOException
+ * @throws org.apache.commons.compress.compressors.CompressorException
+ */
+ BigInteger buildData(Collection<DataProducer> producers, File output, final StringBuilder checksums, Compression compression) throws NoSuchAlgorithmException, IOException, CompressorException {
+
+ final File dir = output.getParentFile();
+ if (dir != null && (!dir.exists() || !dir.isDirectory())) {
+ throw new IOException("Cannot write data file at '" + output.getAbsolutePath() + "'");
+ }
+
+ final TarArchiveOutputStream tarOutputStream = new TarArchiveOutputStream(compression.toCompressedOutputStream(new FileOutputStream(output)));
+ tarOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
+
+ final MessageDigest digest = MessageDigest.getInstance("MD5");
+
+ final Total dataSize = new Total();
+
+ final List<String> addedDirectories = new ArrayList<String>();
+ final DataConsumer receiver = new DataConsumer() {
+ public void onEachDir( String dirname, String linkname, String user, int uid, String group, int gid, int mode, long size ) throws IOException {
+ // Check link name
+ checkField(linkname, TarConstants.NAMELEN);
+ // Check user name
+ checkField(user, TarConstants.UNAMELEN);
+ // Check group name
+ checkField(group, TarConstants.GNAMELEN);
+
+ dirname = fixPath(dirname);
+
+ createParentDirectories(dirname, user, uid, group, gid);
+
+ // The directory passed in explicitly by the caller also gets the passed-in mode. (Unlike
+ // the parent directories for now. See related comments at "int mode =" in
+ // createParentDirectories, including about a possible bug.)
+ createDirectory(dirname, user, uid, group, gid, mode, 0);
+
+ console.info("dir: " + dirname);
+ }
+
+ public void onEachFile( InputStream inputStream, String filename, String linkname, String user, int uid, String group, int gid, int mode, long size ) throws IOException {
+ // Check link name
+ checkField(linkname, TarConstants.NAMELEN);
+ // Check user name
+ checkField(user, TarConstants.UNAMELEN);
+ // Check group name
+ checkField(group, TarConstants.GNAMELEN);
+
+ filename = fixPath(filename);
+
+ createParentDirectories(filename, user, uid, group, gid);
+
+ final TarArchiveEntry entry = new TarArchiveEntry(filename, true);
+
+ entry.setUserName(user);
+ entry.setUserId(uid);
+ entry.setGroupName(group);
+ entry.setGroupId(gid);
+ entry.setMode(mode);
+ entry.setSize(size);
+
+ tarOutputStream.putArchiveEntry(entry);
+
+ dataSize.add(size);
+ digest.reset();
+
+ Utils.copy(inputStream, new DigestOutputStream(tarOutputStream, digest));
+
+ final String md5 = Utils.toHex(digest.digest());
+
+ tarOutputStream.closeArchiveEntry();
+
+ console.info(
+ "file:" + entry.getName() +
+ " size:" + entry.getSize() +
+ " mode:" + entry.getMode() +
+ " linkname:" + entry.getLinkName() +
+ " username:" + entry.getUserName() +
+ " userid:" + entry.getUserId() +
+ " groupname:" + entry.getGroupName() +
+ " groupid:" + entry.getGroupId() +
+ " modtime:" + entry.getModTime() +
+ " md5: " + md5
+ );
+
+ // append to file md5 list
+ checksums.append(md5).append(" ").append(entry.getName()).append('\n');
+ }
+
+ public void onEachLink(String path, String linkname, boolean symlink, String user, int uid, String group, int gid, int mode) throws IOException {
+ // Check link name
+ checkField(linkname, TarConstants.NAMELEN);
+ // Check user name
+ checkField(user, TarConstants.UNAMELEN);
+ // Check group name
+ checkField(group, TarConstants.GNAMELEN);
+
+ path = fixPath(path);
+
+ createParentDirectories(path, user, uid, group, gid);
+
+ final TarArchiveEntry entry = new TarArchiveEntry(path, symlink ? TarArchiveEntry.LF_SYMLINK : TarArchiveEntry.LF_LINK);
+ entry.setLinkName(linkname);
+
+ entry.setUserName(user);
+ entry.setUserId(uid);
+ entry.setGroupName(group);
+ entry.setGroupId(gid);
+ entry.setMode(mode);
+
+ tarOutputStream.putArchiveEntry(entry);
+ tarOutputStream.closeArchiveEntry();
+
+ console.info(
+ "link:" + entry.getName() +
+ " mode:" + entry.getMode() +
+ " linkname:" + entry.getLinkName() +
+ " username:" + entry.getUserName() +
+ " userid:" + entry.getUserId() +
+ " groupname:" + entry.getGroupName() +
+ " groupid:" + entry.getGroupId()
+ );
+ }
+
+
+ private void createDirectory( String directory, String user, int uid, String group, int gid, int mode, long size ) throws IOException {
+ // All dirs should end with "/" when created, or the test DebAndTaskTestCase.testTarFileSet() thinks its a file
+ // and so thinks it has the wrong permission.
+ // This consistency also helps when checking if a directory already exists in addedDirectories.
+
+ if (!directory.endsWith("/")) {
+ directory += "/";
+ }
+
+ if (!addedDirectories.contains(directory)) {
+ TarArchiveEntry entry = new TarArchiveEntry(directory, true);
+ entry.setUserName(user);
+ entry.setUserId(uid);
+ entry.setGroupName(group);
+ entry.setGroupId(gid);
+ entry.setMode(mode);
+ entry.setSize(size);
+
+ tarOutputStream.putArchiveEntry(entry);
+ tarOutputStream.closeArchiveEntry();
+ addedDirectories.add(directory); // so addedDirectories consistently have "/" for finding duplicates.
+ }
+ }
+
+ private void createParentDirectories( String filename, String user, int uid, String group, int gid ) throws IOException {
+ String dirname = fixPath(new File(filename).getParent());
+
+ // Debian packages must have parent directories created
+ // before sub-directories or files can be installed.
+ // For example, if an entry of ./usr/lib/foo/bar existed
+ // in a .deb package, but the ./usr/lib/foo directory didn't
+ // exist, the package installation would fail. The .deb must
+ // then have an entry for ./usr/lib/foo and then ./usr/lib/foo/bar
+
+ if (dirname == null) {
+ return;
+ }
+
+ // The loop below will create entries for all parent directories
+ // to ensure that .deb packages will install correctly.
+ String[] pathParts = dirname.split("/");
+ String parentDir = "./";
+ for (int i = 1; i < pathParts.length; i++) {
+ parentDir += pathParts[i] + "/";
+ // Make it so the dirs can be traversed by users.
+ // We could instead try something more granular, like setting the directory
+ // permission to 'rx' for each of the 3 user/group/other read permissions
+ // found on the file being added (ie, only if "other" has read
+ // permission on the main node, then add o+rx permission on all the containing
+ // directories, same w/ user & group), and then also we'd have to
+ // check the parentDirs collection of those already added to
+ // see if those permissions need to be similarly updated. (Note, it hasn't
+ // been demonstrated, but there might be a bug if a user specifically
+ // requests a directory with certain permissions,
+ // that has already been auto-created because it was a parent, and if so, go set
+ // the user-requested mode on that directory instead of this automatic one.)
+ // But for now, keeping it simple by making every dir a+rx. Examples are:
+ // drw-r----- fs/fs # what you get with setMode(mode)
+ // drwxr-xr-x fs/fs # Usable. Too loose?
+ int mode = TarArchiveEntry.DEFAULT_DIR_MODE;
+
+ createDirectory(parentDir, user, uid, group, gid, mode, 0);
+ }
+ }
+ };
+
+ try {
+ for (DataProducer data : producers) {
+ data.produce(receiver);
+ }
+ } finally {
+ tarOutputStream.close();
+ }
+
+ console.info("Total size: " + dataSize);
+
+ return dataSize.count;
+ }
+
+ private String fixPath( String path ) {
+ if (path == null || path.equals(".")) {
+ return path;
+ }
+
+ // If we're receiving directory names from Windows, then we'll convert to use slash
+ // This does eliminate the ability to use of a backslash in a directory name on *NIX,
+ // but in practice, this is a non-issue
+ if (path.contains("\\")) {
+ path = path.replace('\\', '/');
+ }
+ // ensure the path is like : ./foo/bar
+ if (path.startsWith("/")) {
+ path = "." + path;
+ } else if (!path.startsWith("./")) {
+ path = "./" + path;
+ }
+ return path;
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/DataConsumer.java b/src/main/java/org/vafer/jdeb/DataConsumer.java
new file mode 100644
index 0000000..d108888
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/DataConsumer.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A DataConsumer consumes Data produced from a producer.
+ *
+ * @author Torsten Curdt
+ */
+public interface DataConsumer {
+
+ void onEachDir( String dirname, String linkname, String user, int uid, String group, int gid, int mode, long size ) throws IOException;
+
+ void onEachFile( InputStream input, String filename, String linkname, String user, int uid, String group, int gid, int mode, long size ) throws IOException;
+
+ void onEachLink( String path, String linkName, boolean symlink, String user, int uid, String group, int gid, int mode) throws IOException;
+
+}
diff --git a/src/main/java/org/vafer/jdeb/DataProducer.java b/src/main/java/org/vafer/jdeb/DataProducer.java
new file mode 100644
index 0000000..4218bf2
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/DataProducer.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+import java.io.IOException;
+
+/**
+ * Provides Data to a DataConsumer.
+ *
+ * @author Torsten Curdt
+ */
+public interface DataProducer {
+
+ void produce( DataConsumer receiver ) throws IOException;
+
+}
diff --git a/src/main/java/org/vafer/jdeb/DebMaker.java b/src/main/java/org/vafer/jdeb/DebMaker.java
new file mode 100644
index 0000000..1254dc4
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/DebMaker.java
@@ -0,0 +1,383 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+import org.apache.commons.compress.archivers.ar.ArArchiveEntry;
+import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream;
+import org.apache.commons.io.IOUtils;
+import org.vafer.jdeb.changes.ChangeSet;
+import org.vafer.jdeb.changes.ChangesProvider;
+import org.vafer.jdeb.changes.TextfileChangesProvider;
+import org.vafer.jdeb.debian.BinaryPackageControlFile;
+import org.vafer.jdeb.debian.ChangesFile;
+import org.vafer.jdeb.signing.PGPSigner;
+import org.vafer.jdeb.utils.Utils;
+import org.vafer.jdeb.utils.VariableResolver;
+
+/**
+ * A generic class for creating Debian archives. Even supports signed changes
+ * files.
+ *
+ * @author Torsten Curdt
+ * @author Bryan Sant
+ */
+public class DebMaker {
+
+ /** A console to output log message with */
+ private Console console;
+
+ /** The Debian package produced */
+ private File deb;
+
+ /** The directory containing the control files to build the package */
+ private File control;
+
+ /** The name of the package. Default value if not specified in the control file */
+ private String packageName;
+
+ /** The section of the package. Default value if not specified in the control file */
+ private String section = "java";
+
+ /** The dependencies of the package. Default value if not specified in the control file */
+ private String depends = "default-jre | java6-runtime";
+
+ /** The description of the package. Default value if not specified in the control file */
+ private String description;
+
+ /** The homepage of the application. Default value if not specified in the control file */
+ private String homepage;
+
+ /** The file containing the PGP keys */
+ private File keyring;
+
+ /** The key to use in the keyring */
+ private String key;
+
+ /** The passphrase for the key to sign the changes file */
+ private String passphrase;
+
+ /** The file to read the changes from */
+ private File changesIn;
+
+ /** The file where to write the changes to */
+ private File changesOut;
+
+ /** The file where to write the changes of the changes input to */
+ private File changesSave;
+
+ /** The compression method used for the data file (none, gzip, bzip2 or xz) */
+ private String compression = "gzip";
+
+ private VariableResolver variableResolver;
+
+ private final Collection<DataProducer> dataProducers = new ArrayList<DataProducer>();
+
+
+ public DebMaker(Console console, Collection<DataProducer> dataProducers) {
+ this.console = console;
+ this.dataProducers.addAll(dataProducers);
+ }
+
+ public void setDeb(File deb) {
+ this.deb = deb;
+ }
+
+ public void setControl(File control) {
+ this.control = control;
+ }
+
+ public void setPackage(String packageName) {
+ this.packageName = packageName;
+ }
+
+ public void setSection(String section) {
+ this.section = section;
+ }
+
+ public void setDepends(String depends) {
+ this.depends = depends;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public void setHomepage(String homepage) {
+ this.homepage = homepage;
+ }
+
+ public void setChangesIn(File changes) {
+ this.changesIn = changes;
+ }
+
+ public void setChangesOut(File changes) {
+ this.changesOut = changes;
+ }
+
+ public void setChangesSave(File changes) {
+ this.changesSave = changes;
+ }
+
+ public void setKeyring(File keyring) {
+ this.keyring = keyring;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public void setPassphrase(String passphrase) {
+ this.passphrase = passphrase;
+ }
+
+ public void setCompression(String compression) {
+ this.compression = compression;
+ }
+
+ public void setResolver(VariableResolver variableResolver) {
+ this.variableResolver = variableResolver;
+ }
+
+ private boolean isWritableFile(File file) {
+ return !file.exists() || file.isFile() && file.canWrite();
+ }
+
+ /**
+ * Validates the input parameters.
+ */
+ public void validate() throws PackagingException {
+ if (control == null || !control.isDirectory()) {
+ throw new PackagingException("The 'control' attribute doesn't point to a directory.");
+ }
+
+ if (changesIn != null) {
+
+ if (changesIn.exists() && (!changesIn.isFile() || !changesIn.canRead())) {
+ throw new PackagingException("The 'changesIn' setting needs to point to a readable file. " + changesIn + " was not found/readable.");
+ }
+
+ if (changesOut != null && !isWritableFile(changesOut)) {
+ throw new PackagingException("Cannot write the output for 'changesOut' to " + changesOut);
+ }
+
+ if (changesSave != null && !isWritableFile(changesSave)) {
+ throw new PackagingException("Cannot write the output for 'changesSave' to " + changesSave);
+ }
+
+ } else {
+ if (changesOut != null || changesSave != null) {
+ throw new PackagingException("The 'changesOut' or 'changesSave' settings may only be used when there is a 'changesIn' specified.");
+ }
+ }
+
+ if (Compression.toEnum(compression) == null) {
+ throw new PackagingException("The compression method '" + compression + "' is not supported (expected 'none', 'gzip', 'bzip2' or 'xz')");
+ }
+
+ if (deb == null) {
+ throw new PackagingException("You need to specify where the deb file is supposed to be created.");
+ }
+
+ if (dataProducers.size() == 0) {
+ throw new PackagingException("You need to provide at least one reference to a tgz or directory with data.");
+ }
+ }
+
+ public void makeDeb() throws PackagingException {
+ BinaryPackageControlFile packageControlFile;
+ try {
+ console.info("Creating debian package: " + deb);
+
+ packageControlFile = createDeb(Compression.toEnum(compression));
+
+ } catch (Exception e) {
+ throw new PackagingException("Failed to create debian package " + deb, e);
+ }
+
+ makeChangesFiles(packageControlFile);
+ }
+
+ private void makeChangesFiles(final BinaryPackageControlFile packageControlFile) throws PackagingException {
+ if (changesOut == null) {
+ changesOut = new File(deb.getParentFile(), deb.getName().replace(".deb", ".changes"));
+ }
+
+ ChangesProvider changesProvider;
+ FileOutputStream out = null;
+
+ try {
+ console.info("Creating changes file: " + changesOut);
+
+ out = new FileOutputStream(changesOut);
+
+ if (changesIn != null && changesIn.exists()) {
+ // read the changes form a textfile provider
+ changesProvider = new TextfileChangesProvider(new FileInputStream(changesIn), packageControlFile);
+ } else {
+ // create an empty changelog
+ changesProvider = new ChangesProvider() {
+ @Override
+ public ChangeSet[] getChangesSets() {
+ return new ChangeSet[] {
+ new ChangeSet(packageControlFile.get("Package"), packageControlFile.get("Version"), new Date(),
+ "stable", "low", packageControlFile.get("Maintainer"), new String[0])
+ };
+ }
+ };
+ }
+
+ ChangesFileBuilder builder = new ChangesFileBuilder();
+ ChangesFile changesFile = builder.createChanges(packageControlFile, deb, changesProvider);
+
+ if (keyring != null && key != null && passphrase != null) {
+ console.info("Signing the changes file with the key " + key);
+ PGPSigner signer = new PGPSigner(new FileInputStream(keyring), key, passphrase);
+ signer.clearSign(changesFile.toString(), out);
+ } else {
+ out.write(changesFile.toString().getBytes("UTF-8"));
+ }
+ out.flush();
+
+ } catch (Exception e) {
+ throw new PackagingException("Failed to create the Debian changes file " + changesOut, e);
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+
+ if (changesSave == null || !(changesProvider instanceof TextfileChangesProvider)) {
+ return;
+ }
+
+ try {
+ console.info("Saving changes to file: " + changesSave);
+
+ ((TextfileChangesProvider) changesProvider).save(new FileOutputStream(changesSave));
+
+ } catch (Exception e) {
+ throw new PackagingException("Failed to save debian changes file " + changesSave, e);
+ }
+ }
+
+ /**
+ * Create the debian archive with from the provided control files and data producers.
+ *
+ * @param pControlFiles
+ * @param pData
+ * @param deb
+ * @param compression the compression method used for the data file
+ * @return BinaryPackageControlFile
+ * @throws PackagingException
+ */
+ public BinaryPackageControlFile createDeb(Compression compression) throws PackagingException {
+ File tempData = null;
+ File tempControl = null;
+
+ try {
+ tempData = File.createTempFile("deb", "data");
+ tempControl = File.createTempFile("deb", "control");
+
+ console.info("Building data");
+ DataBuilder dataBuilder = new DataBuilder(console);
+ StringBuilder md5s = new StringBuilder();
+ BigInteger size = dataBuilder.buildData(dataProducers, tempData, md5s, compression);
+
+ console.info("Building control");
+ ControlBuilder controlBuilder = new ControlBuilder(console, variableResolver);
+ BinaryPackageControlFile packageControlFile = controlBuilder.createPackageControlFile(new File(control, "control"), size);
+ if (packageControlFile.get("Package") == null) {
+ packageControlFile.set("Package", packageName);
+ }
+ if (packageControlFile.get("Depends") == null) {
+ packageControlFile.set("Depends", depends);
+ }
+ if (packageControlFile.get("Section") == null) {
+ packageControlFile.set("Section", section);
+ }
+ if (packageControlFile.get("Description") == null) {
+ packageControlFile.set("Description", description);
+ }
+ if (packageControlFile.get("Homepage") == null) {
+ packageControlFile.set("Homepage", homepage);
+ }
+
+ controlBuilder.buildControl(packageControlFile, control.listFiles(), md5s, tempControl);
+
+ if (!packageControlFile.isValid()) {
+ throw new PackagingException("Control file fields are invalid " + packageControlFile.invalidFields() +
+ ". The following fields are mandatory: " + packageControlFile.getMandatoryFields() +
+ ". Please check your pom.xml/build.xml and your control file.");
+ }
+
+ deb.getParentFile().mkdirs();
+
+
+ ArArchiveOutputStream ar = new ArArchiveOutputStream(new FileOutputStream(deb));
+
+ addTo(ar, "debian-binary", "2.0\n");
+ addTo(ar, "control.tar.gz", tempControl);
+ addTo(ar, "data.tar" + compression.getExtension(), tempData);
+
+ ar.close();
+
+ return packageControlFile;
+
+ } catch (Exception e) {
+ throw new PackagingException("Could not create deb package", e);
+ } finally {
+ if (tempData != null) {
+ if (!tempData.delete()) {
+ console.warn("Could not delete the temporary file " + tempData);
+ }
+ }
+ if (tempControl != null) {
+ if (!tempControl.delete()) {
+ console.warn("Could not delete the temporary file " + tempControl);
+ }
+ }
+ }
+ }
+
+ private void addTo(ArArchiveOutputStream pOutput, String pName, String pContent) throws IOException {
+ final byte[] content = pContent.getBytes();
+ pOutput.putArchiveEntry(new ArArchiveEntry(pName, content.length));
+ pOutput.write(content);
+ pOutput.closeArchiveEntry();
+ }
+
+ private void addTo(ArArchiveOutputStream pOutput, String pName, File pContent) throws IOException {
+ pOutput.putArchiveEntry(new ArArchiveEntry(pName, pContent.length()));
+
+ final InputStream input = new FileInputStream(pContent);
+ try {
+ Utils.copy(input, pOutput);
+ } finally {
+ input.close();
+ }
+
+ pOutput.closeArchiveEntry();
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/PackagingException.java b/src/main/java/org/vafer/jdeb/PackagingException.java
new file mode 100644
index 0000000..5fddfd7
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/PackagingException.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+/**
+ * Something went wrong while building the package
+ *
+ * @author Torsten Curdt
+ */
+public final class PackagingException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public PackagingException() {
+ super();
+ }
+
+ public PackagingException( String message, Throwable cause ) {
+ super(message, cause);
+ }
+
+ public PackagingException( String message ) {
+ super(message);
+ }
+
+ public PackagingException( Throwable cause ) {
+ super(cause);
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/ant/Data.java b/src/main/java/org/vafer/jdeb/ant/Data.java
new file mode 100644
index 0000000..b32872f
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/ant/Data.java
@@ -0,0 +1,107 @@
+/*
+ * 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.ant;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+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;
+
+/**
+ * Ant "data" element acting as a factory for DataProducers.
+ * So far Archive and Directory producers are supported.
+ * Both support the usual ant pattern set matching.
+ *
+ * @author Torsten Curdt
+ */
+public final class Data extends PatternSet implements DataProducer {
+
+ private final Collection<Mapper> mapperWrapper = new ArrayList<Mapper>();
+
+ private File src;
+
+ private String type;
+
+ private String destinationName;
+
+ public void setSrc(File src) {
+ this.src = src;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public void setDst(String destinationName) {
+ this.destinationName = destinationName;
+ }
+
+ public void addMapper(Mapper mapper) {
+ mapperWrapper.add(mapper);
+ }
+
+ public void produce( final DataConsumer pReceiver ) throws IOException {
+
+ if (src == null || !src.exists()) {
+ throw new FileNotFoundException("Data source not found : " + src);
+ }
+
+ org.vafer.jdeb.mapping.Mapper[] mappers = new org.vafer.jdeb.mapping.Mapper[mapperWrapper.size()];
+ final Iterator<Mapper> 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);
+ }
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/ant/DebAntTask.java b/src/main/java/org/vafer/jdeb/ant/DebAntTask.java
new file mode 100644
index 0000000..bf8ea43
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/ant/DebAntTask.java
@@ -0,0 +1,173 @@
+/*
+ * 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.ant;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.Tar;
+import org.apache.tools.ant.types.FileSet;
+import org.vafer.jdeb.Console;
+import org.vafer.jdeb.DataProducer;
+import org.vafer.jdeb.DebMaker;
+import org.vafer.jdeb.PackagingException;
+import org.vafer.jdeb.producers.DataProducerFileSet;
+
+/**
+ * AntTask for creating debian archives.
+ *
+ * @author Torsten Curdt
+ */
+public class DebAntTask extends MatchingTask {
+
+ /** The Debian package produced */
+ private File deb;
+
+ /** The directory containing the control files to build the package */
+ private File control;
+
+ /** The file containing the PGP keys */
+ private File keyring;
+
+ /** The key to use in the keyring */
+ private String key;
+
+ /** The passphrase for the key to sign the changes file */
+ private String passphrase;
+
+ /** The file to read the changes from */
+ private File changesIn;
+
+ /** The file where to write the changes to */
+ private File changesOut;
+
+ /** The file where to write the changes of the changes input to */
+ private File changesSave;
+
+ /** The compression method used for the data file (none, gzip, bzip2 or xz) */
+ private String compression = "gzip";
+
+ /** Trigger the verbose mode detailing all operations */
+ private boolean verbose;
+
+ private Collection<Link> links = new ArrayList<Link>();
+
+ private Collection<DataProducer> dataProducers = new ArrayList<DataProducer>();
+
+
+ public void setDestfile( File deb ) {
+ this.deb = deb;
+ }
+
+ public void setControl( File control ) {
+ this.control = control;
+ }
+
+ public void setChangesIn( File changes ) {
+ this.changesIn = changes;
+ }
+
+ public void setChangesOut( File changes ) {
+ this.changesOut = changes;
+ }
+
+ public void setChangesSave( File changes ) {
+ this.changesSave = changes;
+ }
+
+ public void setKeyring( File keyring ) {
+ this.keyring = keyring;
+ }
+
+ public void setKey( String key ) {
+ this.key = key;
+ }
+
+ public void setPassphrase( String passphrase ) {
+ this.passphrase = passphrase;
+ }
+
+ public void setCompression( String compression ) {
+ this.compression = compression;
+ }
+
+ public void setVerbose( boolean verbose ) {
+ this.verbose = verbose;
+ }
+
+ public void addFileSet( FileSet fileset ) {
+ dataProducers.add(new DataProducerFileSet(fileset));
+ }
+
+ public void addTarFileSet( Tar.TarFileSet fileset ) {
+ dataProducers.add(new DataProducerFileSet(fileset));
+ }
+
+ public void addData( Data data ) {
+ dataProducers.add(data);
+ }
+
+ public void addLink( Link link ) {
+ links.add(link);
+ }
+
+ public void execute() {
+ // add the data producers for the links
+ for (Link link : links) {
+ dataProducers.add(link.toDataProducer());
+ }
+
+ // validate the type of the <data> elements
+ for (DataProducer dataProducer : dataProducers) {
+ if (dataProducer instanceof Data) {
+ Data data = (Data) dataProducer;
+ if (data.getType() == null) {
+ throw new BuildException("The type of the data element wasn't specified (expected 'file', 'directory' or 'archive')");
+ } else if (!Arrays.asList("file", "directory", "archive").contains(data.getType().toLowerCase())) {
+ throw new BuildException("The type '" + data.getType() + "' of the data element is unknown (expected 'file', 'directory' or 'archive')");
+ }
+ }
+ }
+
+ Console console = new TaskConsole(this, verbose);
+
+ DebMaker debMaker = new DebMaker(console, dataProducers);
+ debMaker.setDeb(deb);
+ debMaker.setControl(control);
+ debMaker.setChangesIn(changesIn);
+ debMaker.setChangesOut(changesOut);
+ debMaker.setChangesSave(changesSave);
+ debMaker.setKeyring(keyring);
+ debMaker.setKey(key);
+ debMaker.setPassphrase(passphrase);
+ debMaker.setCompression(compression);
+
+ try {
+ debMaker.validate();
+ debMaker.makeDeb();
+
+ } catch (PackagingException e) {
+ log("Failed to create the Debian package " + deb, e, Project.MSG_ERR);
+ throw new BuildException("Failed to create the Debian package " + deb, e);
+ }
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/ant/Link.java b/src/main/java/org/vafer/jdeb/ant/Link.java
new file mode 100644
index 0000000..7a7a928
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/ant/Link.java
@@ -0,0 +1,109 @@
+/*
+ * 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.ant;
+
+import org.apache.commons.compress.archivers.zip.UnixStat;
+import org.vafer.jdeb.DataProducer;
+import org.vafer.jdeb.mapping.PermMapper;
+import org.vafer.jdeb.producers.DataProducerLink;
+
+/**
+ * Defines a symbolic or hard link.
+ *
+ * @author Emmanuel Bourg
+ * @version $Revision$, $Date$
+ */
+public final class Link {
+
+ private String name;
+ private String target;
+ private boolean symbolic = true;
+ private String username = "root";
+ private String group = "root";
+ private int uid = 0;
+ private int gid = 0;
+ private int mode = UnixStat.LINK_FLAG | UnixStat.DEFAULT_LINK_PERM;
+
+ DataProducer toDataProducer() {
+ org.vafer.jdeb.mapping.Mapper mapper = new PermMapper(uid, gid, username, group, mode, mode, 0, null);
+ return new DataProducerLink(name, target, symbolic, null, null, new org.vafer.jdeb.mapping.Mapper[]{mapper});
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+ public boolean isSymbolic() {
+ return symbolic;
+ }
+
+ public void setSymbolic(boolean symbolic) {
+ this.symbolic = symbolic;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getGroup() {
+ return group;
+ }
+
+ public void setGroup(String group) {
+ this.group = group;
+ }
+
+ public int getUid() {
+ return uid;
+ }
+
+ public void setUid(int uid) {
+ this.uid = uid;
+ }
+
+ public int getGid() {
+ return gid;
+ }
+
+ public void setGid(int gid) {
+ this.gid = gid;
+ }
+
+ public int getMode() {
+ return mode;
+ }
+
+ public void setMode(String mode) {
+ this.mode = UnixStat.LINK_FLAG | Integer.parseInt(mode, 8);
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/ant/Mapper.java b/src/main/java/org/vafer/jdeb/ant/Mapper.java
new file mode 100644
index 0000000..e99dd1b
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/ant/Mapper.java
@@ -0,0 +1,104 @@
+/*
+ * 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.ant;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.vafer.jdeb.mapping.LsMapper;
+import org.vafer.jdeb.mapping.PermMapper;
+
+/**
+ * Ant "mapper" element acting as factory for the entry mapper.
+ * Supported types: ls, perm
+ *
+ * @author Torsten Curdt
+ */
+public final class Mapper {
+
+ private String mapperType = "perm";
+ private File src;
+
+ private String prefix;
+ private int strip;
+ private int uid = -1;
+ private int gid = -1;
+ private String user;
+ private String group;
+ private int fileMode = -1;
+ private int dirMode = -1;
+
+ public void setType( final String pType ) {
+ mapperType = pType;
+ }
+
+ public void setSrc( final File pSrc ) {
+ src = pSrc;
+ }
+
+
+ public void setPrefix( final String pPrefix ) {
+ prefix = pPrefix;
+ }
+
+ public void setStrip( final int pStrip ) {
+ strip = pStrip;
+ }
+
+
+ public void setUid( final int pUid ) {
+ uid = pUid;
+ }
+
+ public void setGid( final int pGid ) {
+ gid = pGid;
+ }
+
+ public void setUser( final String pUser ) {
+ user = pUser;
+ }
+
+ public void setGroup( final String pGroup ) {
+ group = pGroup;
+ }
+
+ public void setFileMode( final int pFileMode ) {
+ fileMode = pFileMode;
+ }
+
+ public void setDirMode( int pDirMode ) {
+ dirMode = pDirMode;
+ }
+
+ public org.vafer.jdeb.mapping.Mapper createMapper() throws IOException {
+
+ if ("perm".equalsIgnoreCase(mapperType)) {
+ return new PermMapper(uid, gid, user, group, fileMode, dirMode, strip, prefix);
+ }
+
+ if ("ls".equalsIgnoreCase(mapperType)) {
+ try {
+ return new LsMapper(new FileInputStream(src));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ throw new IOException("Unknown mapper type '" + mapperType + "'");
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/ant/TaskConsole.java b/src/main/java/org/vafer/jdeb/ant/TaskConsole.java
new file mode 100644
index 0000000..066455f
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/ant/TaskConsole.java
@@ -0,0 +1,45 @@
+/*
+ * 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.ant;
+
+import org.apache.tools.ant.Task;
+import org.vafer.jdeb.Console;
+
+/**
+ * Console implementation for Ant tasks.
+ */
+class TaskConsole implements Console {
+
+ private final Task task;
+ private final boolean verbose;
+
+ public TaskConsole(Task task, boolean verbose) {
+ this.task = task;
+ this.verbose = verbose;
+ }
+
+ public void info(String message) {
+ if (verbose) {
+ task.log(message);
+ }
+ }
+
+ public void warn(String message) {
+ task.log(message);
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/changes/ChangeSet.java b/src/main/java/org/vafer/jdeb/changes/ChangeSet.java
new file mode 100644
index 0000000..4ebc3c5
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/changes/ChangeSet.java
@@ -0,0 +1,105 @@
+/*
+ * 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.changes;
+
+import java.util.Date;
+
+/**
+ * A ChangeSet basically reflect a release as defined in the changes file.
+ *
+ * <pre>
+ * package (version) distribution(s); urgency=urgency
+ * [optional blank line(s), stripped]
+ * * change details
+ * more change details
+ * [blank line(s), included in output of dpkg-parsechangelog]
+ * * even more change details
+ * [optional blank line(s), stripped]
+ * -- maintainer name <email address>[two spaces] date
+ * </pre>
+ *
+ * @author Torsten Curdt
+ * @see <a href="http://www.debian.org/doc/debian-policy/ch-source.html#s-dpkgchangelog">Debian Policy Manual - Debian changelog</a>
+ */
+public final class ChangeSet {
+
+ private final String packageName;
+ private final String version;
+ private final Date date;
+ private final String distribution;
+ private final String urgency;
+ private final String changedBy;
+ private final String[] changes;
+
+ public ChangeSet(String packageName, String version, Date date, String distribution, String urgency, String changedBy, String[] changes) {
+ this.packageName = packageName;
+ this.version = version;
+ this.date = date;
+ this.distribution = distribution;
+ this.urgency = urgency;
+ this.changedBy = changedBy;
+ this.changes = changes;
+ }
+
+ public String getPackage() {
+ return packageName;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public String getDistribution() {
+ return distribution;
+ }
+
+ public String getUrgency() {
+ return urgency;
+ }
+
+ public String getChangedBy() {
+ return changedBy;
+ }
+
+ public String[] getChanges() {
+ return changes;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(getTitle()).append('\n');
+
+ if (changes.length > 0) {
+ sb.append("\n");
+ }
+
+ for (String change : changes) {
+ sb.append(" * ").append(change).append('\n');
+ }
+
+ return sb.toString();
+ }
+
+ private String getTitle() {
+ return getPackage() + " (" + getVersion() + ") " + getDistribution() + "; urgency=" + getUrgency();
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/changes/ChangesProvider.java b/src/main/java/org/vafer/jdeb/changes/ChangesProvider.java
new file mode 100644
index 0000000..235ded8
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/changes/ChangesProvider.java
@@ -0,0 +1,22 @@
+/*
+ * 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.changes;
+
+public interface ChangesProvider {
+
+ ChangeSet[] getChangesSets();
+
+}
diff --git a/src/main/java/org/vafer/jdeb/changes/TextfileChangesProvider.java b/src/main/java/org/vafer/jdeb/changes/TextfileChangesProvider.java
new file mode 100644
index 0000000..ed97531
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/changes/TextfileChangesProvider.java
@@ -0,0 +1,143 @@
+/*
+ * 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.changes;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+import org.vafer.jdeb.debian.BinaryPackageControlFile;
+
+/**
+ * Gets the changes from a changes file. The first entry are the current changes.
+ * The release line will be added. Example:
+ *
+ * release date=22:13 19.08.2007,version=1.5+r90114,urgency=low,by=Torsten Curdt <torsten at vafer.org>
+ * * debian changes support
+ * release date=20:13 17.08.2007,version=1.4+r89114,urgency=low,by=Torsten Curdt <torsten at vafer.org>
+ * * debian changes support
+ *
+ * @author Torsten Curdt
+ */
+public final class TextfileChangesProvider implements ChangesProvider {
+
+ private final ChangeSet[] changeSets;
+
+ private DateFormat fmt = new SimpleDateFormat("HH:mm dd.MM.yyyy");
+
+ public TextfileChangesProvider( final InputStream pInput, final BinaryPackageControlFile packageControlFile ) throws IOException, ParseException {
+
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(pInput));
+
+ String packageName = packageControlFile.get("Package");
+ String version = packageControlFile.get("Version");
+ Date date = new Date();
+ String distribution = packageControlFile.get("Distribution");
+ String urgency = packageControlFile.get("Urgency");
+ String changedBy = packageControlFile.get("Maintainer");
+ Collection<String> changesColl = new ArrayList<String>();
+ Collection<ChangeSet> changeSetColl = new ArrayList<ChangeSet>();
+
+
+ while (true) {
+ final String line = reader.readLine();
+ if (line == null) {
+ final String[] changes = changesColl.toArray(new String[changesColl.size()]);
+ final ChangeSet changeSet = new ChangeSet(packageName, version, date, distribution, urgency, changedBy, changes);
+ changeSetColl.add(changeSet);
+ break;
+ }
+
+ if (line.startsWith("release ")) {
+
+ if (changesColl.size() > 0) {
+ final String[] changes = changesColl.toArray(new String[changesColl.size()]);
+ final ChangeSet changeSet = new ChangeSet(packageName, version, date, distribution, urgency, changedBy, changes);
+ changeSetColl.add(changeSet);
+ changesColl.clear();
+ }
+
+ final String[] tokens = line.substring("release ".length()).split(",");
+ for (String token : tokens) {
+ final String[] lr = token.trim().split("=");
+ final String key = lr[0];
+ final String value = lr[1];
+
+ if ("urgency".equals(key)) {
+ urgency = value;
+ } else if ("by".equals(key)) {
+ changedBy = value;
+ } else if ("date".equals(key)) {
+ date = fmt.parse(value);
+ } else if ("version".equals(key)) {
+ version = value;
+ } else if ("distribution".equals(key)) {
+ distribution = value;
+ }
+ }
+ continue;
+ }
+
+ if (line.startsWith(" * ")) {
+ changesColl.add(line.substring(" * ".length()));
+ continue;
+ }
+
+ throw new ParseException("Unknown line syntax [" + line + "]", 0);
+ }
+
+ reader.close();
+
+ changeSets = changeSetColl.toArray(new ChangeSet[changeSetColl.size()]);
+ }
+
+ public void save(OutputStream pOutput) throws IOException {
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(pOutput));
+
+ for (ChangeSet changeSet : changeSets) {
+ writer.write("release ");
+ writer.write("date=" + fmt.format(changeSet.getDate()) + ",");
+ writer.write("version=" + changeSet.getVersion() + ",");
+ writer.write("urgency=" + changeSet.getUrgency() + ",");
+ writer.write("by=" + changeSet.getChangedBy() + ",");
+ writer.write("distribution=" + changeSet.getDistribution());
+ writer.write("\n");
+
+ for (String change : changeSet.getChanges()) {
+ writer.write(" * ");
+ writer.write(change);
+ writer.write("\n");
+ }
+ }
+
+ writer.close();
+ }
+
+ public ChangeSet[] getChangesSets() {
+ return changeSets;
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/debian/BinaryPackageControlFile.java b/src/main/java/org/vafer/jdeb/debian/BinaryPackageControlFile.java
new file mode 100644
index 0000000..274b53d
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/debian/BinaryPackageControlFile.java
@@ -0,0 +1,85 @@
+/*
+ * 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.debian;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.ParseException;
+
+/**
+ * Binary package control file.
+ *
+ * @see <a href="http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-binarycontrolfiles">Debian Policy Manual - Binary package control files</a>
+ * @author Torsten Curdt
+ */
+public final class BinaryPackageControlFile extends ControlFile {
+
+ private static final ControlField[] FIELDS = {
+ new ControlField("Package", true),
+ new ControlField("Source"),
+ new ControlField("Version", true),
+ new ControlField("Section", true),
+ new ControlField("Priority", true),
+ new ControlField("Architecture", true),
+ new ControlField("Essential"),
+ new ControlField("Depends"),
+ new ControlField("Pre-Depends"),
+ new ControlField("Recommends"),
+ new ControlField("Suggests"),
+ new ControlField("Breaks"),
+ new ControlField("Enhances"),
+ new ControlField("Conflicts"),
+ new ControlField("Provides"),
+ new ControlField("Replaces"),
+ new ControlField("Installed-Size"),
+ new ControlField("Maintainer", true),
+ new ControlField("Description", true, ControlField.Type.MULTILINE),
+ new ControlField("Homepage")
+ };
+
+ public BinaryPackageControlFile() {
+ set("Architecture", "all");
+ set("Priority", "optional");
+ }
+
+ public BinaryPackageControlFile(String input) throws IOException, ParseException {
+ parse(input);
+ }
+
+ public BinaryPackageControlFile(InputStream input) throws IOException, ParseException {
+ parse(input);
+ }
+
+ @Override
+ protected ControlField[] getFields() {
+ return FIELDS;
+ }
+
+ /**
+ * Returns the short description of the package. The short description
+ * consists in the first line of the Description field.
+ *
+ * @return
+ */
+ public String getShortDescription() {
+ if (get("Description") == null) {
+ return null;
+ }
+
+ return get("Description").split("\n")[0];
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/debian/ChangesFile.java b/src/main/java/org/vafer/jdeb/debian/ChangesFile.java
new file mode 100644
index 0000000..49bc6b9
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/debian/ChangesFile.java
@@ -0,0 +1,102 @@
+/*
+ * 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.debian;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+
+import org.vafer.jdeb.changes.ChangeSet;
+
+/**
+ * Reflecting a changes file
+ *
+ * @see <a href="http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-debianchangesfiles">Debian Policy Manual - Debian changes files</a>
+ * @author Torsten Curdt
+ */
+public final class ChangesFile extends ControlFile {
+
+ public static final DateFormat DATE_FORMAT = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH); // RFC 2822 format
+
+ private static final ControlField[] FIELDS = {
+ new ControlField("Format", true),
+ new ControlField("Date", true),
+ new ControlField("Source", true),
+ new ControlField("Binary", true),
+ new ControlField("Architecture", true),
+ new ControlField("Version", true),
+ new ControlField("Distribution", true),
+ new ControlField("Urgency", true),
+ new ControlField("Maintainer", true),
+ new ControlField("Changed-By"),
+ new ControlField("Description", true, ControlField.Type.MULTILINE, true),
+ new ControlField("Changes", true, ControlField.Type.MULTILINE, true),
+ new ControlField("Closes"),
+ new ControlField("Checksums-Sha1", true, ControlField.Type.MULTILINE, true),
+ new ControlField("Checksums-Sha256", true, ControlField.Type.MULTILINE, true),
+ new ControlField("Files", true, ControlField.Type.MULTILINE, true)
+ };
+
+ public ChangesFile() {
+ set("Format", "1.8");
+ set("Distribution", "stable");
+ }
+
+ /**
+ * Initializes the fields on the changes file with the values of the specified
+ * binary package control file.
+ *
+ * @param packageControlFile
+ */
+ public void initialize(BinaryPackageControlFile packageControlFile) {
+ set("Binary", packageControlFile.get("Package"));
+ set("Source", packageControlFile.get("Package"));
+ set("Architecture", packageControlFile.get("Architecture"));
+ set("Version", packageControlFile.get("Version"));
+ set("Maintainer", packageControlFile.get("Maintainer"));
+ set("Changed-By", packageControlFile.get("Maintainer"));
+
+ StringBuilder description = new StringBuilder();
+ description.append(packageControlFile.get("Package"));
+ if (packageControlFile.get("Description") != null) {
+ description.append(" - ");
+ description.append(packageControlFile.getShortDescription());
+ }
+ set("Description", description.toString());
+ }
+
+ public void setChanges(ChangeSet[] changeSets) {
+ StringBuilder sb = new StringBuilder();
+
+ if (changeSets.length > 0) {
+ final ChangeSet mostRecentChangeSet = changeSets[0];
+ set("Urgency", mostRecentChangeSet.getUrgency());
+ set("Changed-By", mostRecentChangeSet.getChangedBy());
+
+ for (ChangeSet changeSet : changeSets) {
+ sb.append(changeSet.toString());
+ }
+ }
+
+ set("Changes", sb.toString());
+ }
+
+ @Override
+ protected ControlField[] getFields() {
+ return FIELDS;
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/debian/ControlField.java b/src/main/java/org/vafer/jdeb/debian/ControlField.java
new file mode 100644
index 0000000..73e37ba
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/debian/ControlField.java
@@ -0,0 +1,130 @@
+/*
+ * 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.debian;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+
+/**
+ * A field of a control file. This class is immutable.
+ *
+ * @author Emmanuel Bourg
+ */
+public class ControlField {
+
+ /**
+ * The format of a field.
+ */
+ public enum Type {
+ /** Value on a single line */
+ SIMPLE,
+ /** Value on multiple lines, space characters are ignored */
+ FOLDED,
+ /** Value on multiple lines, space characters are preserved */
+ MULTILINE
+ }
+
+ /** The name of the field */
+ private String name;
+
+ /** Tells if the field is mandatory */
+ private boolean mandatory;
+
+ /** The type of the field */
+ private Type type = Type.SIMPLE;
+
+ /** Tells is the first line of the field must be empty (for MULTILINE values only) */
+ private boolean firstLineEmpty;
+
+
+ public ControlField(String name) {
+ this(name, false);
+ }
+
+ public ControlField(String name, boolean mandatory) {
+ this(name, mandatory, Type.SIMPLE);
+ }
+
+ public ControlField(String name, boolean mandatory, Type type) {
+ this(name, mandatory, type, false);
+ }
+
+ public ControlField(String name, boolean mandatory, Type type, boolean firstLineEmpty) {
+ this.name = name;
+ this.mandatory = mandatory;
+ this.type = type;
+ this.firstLineEmpty = firstLineEmpty;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isMandatory() {
+ return mandatory;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public boolean isFirstLineEmpty() {
+ return firstLineEmpty;
+ }
+
+ /**
+ * Returns the field with the specified value properly formatted. Multiline
+ * values are automatically indented, and dots are added on the empty lines.
+ *
+ * <pre>
+ * Field-Name: value
+ * </pre>
+ */
+ public String format(String value) {
+ StringBuilder s = new StringBuilder();
+
+ if (value != null && value.trim().length() > 0) {
+ boolean continuationLine = false;
+
+ s.append(getName()).append(":");
+ if (isFirstLineEmpty()) {
+ s.append("\n");
+ continuationLine = true;
+ }
+
+ try {
+ BufferedReader reader = new BufferedReader(new StringReader(value));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (continuationLine && line.trim().length() == 0) {
+ // put a dot on the empty continuation lines
+ s.append(" .\n");
+ } else {
+ s.append(" ").append(line).append("\n");
+ }
+
+ continuationLine = true;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return s.toString();
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/debian/ControlFile.java b/src/main/java/org/vafer/jdeb/debian/ControlFile.java
new file mode 100644
index 0000000..00c8b10
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/debian/ControlFile.java
@@ -0,0 +1,153 @@
+/*
+ * 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.debian;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A control file as specified by the <a href="http://www.debian.org/doc/debian-policy/ch-controlfields.html">Debian policy</a>.
+ *
+ * @author Torsten Curdt
+ */
+public abstract class ControlFile {
+
+ protected final Map<String, String> values = new LinkedHashMap<String, String>();
+
+ public void parse(String input) throws IOException, ParseException {
+ parse(new ByteArrayInputStream(input.getBytes("UTF-8")));
+ }
+
+ public void parse(InputStream input) throws IOException, ParseException {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
+ StringBuilder buffer = new StringBuilder();
+ String field = null;
+ int linenr = 0;
+ while (true) {
+ final String line = reader.readLine();
+
+ if (line == null) {
+ if (buffer.length() > 0) {
+ // flush value of the previous field
+ set(field, buffer.toString());
+ }
+ break;
+ }
+
+ linenr++;
+
+ if (line.length() == 0) {
+ throw new ParseException("Empty line", linenr);
+ }
+
+ final char first = line.charAt(0);
+ if (Character.isLetter(first)) {
+
+ // new field
+
+ if (buffer.length() > 0) {
+ // flush value of the previous field
+ set(field, buffer.toString());
+ buffer = new StringBuilder();
+ }
+
+
+ final int i = line.indexOf(':');
+
+ if (i < 0) {
+ throw new ParseException("Line misses ':' delimiter", linenr);
+ }
+
+ field = line.substring(0, i);
+ buffer.append(line.substring(i + 1).trim());
+
+ continue;
+ }
+
+ // continuing old value, lines with only a dot are ignored
+ buffer.append('\n');
+ if (!".".equals(line.substring(1).trim())) {
+ buffer.append(line.substring(1));
+ }
+ }
+ reader.close();
+
+ }
+
+ public void set(final String field, final String value) {
+ if (!"".equals(value)) {
+ values.put(field, value);
+ }
+ }
+
+ public String get(String field) {
+ return values.get(field);
+ }
+
+ protected abstract ControlField[] getFields();
+
+ public List<String> getMandatoryFields() {
+ List<String> fields = new ArrayList<String>();
+
+ for (ControlField field : getFields()) {
+ if (field.isMandatory()) {
+ fields.add(field.getName());
+ }
+ }
+
+ return fields;
+ }
+
+ public boolean isValid() {
+ return invalidFields().size() == 0;
+ }
+
+ public Set<String> invalidFields() {
+ Set<String> invalid = new HashSet<String>();
+
+ for (ControlField field : getFields()) {
+ if (field.isMandatory() && get(field.getName()) == null) {
+ invalid.add(field.getName());
+ }
+ }
+
+ return invalid;
+ }
+
+ public String toString(ControlField... fields) {
+ StringBuilder s = new StringBuilder();
+ for (ControlField field : fields) {
+ String value = values.get(field.getName());
+ s.append(field.format(value));
+ }
+ return s.toString();
+ }
+
+ public String toString() {
+ return toString(getFields());
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/mapping/LsMapper.java b/src/main/java/org/vafer/jdeb/mapping/LsMapper.java
new file mode 100644
index 0000000..fdf19c5
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/mapping/LsMapper.java
@@ -0,0 +1,237 @@
+/*
+ * 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.mapping;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+
+/**
+ * Reads permissions and ownerships from a "ls -laR > mapping.txt" dump and
+ * maps entries accordingly.
+ *
+ * @author Torsten Curdt
+ */
+public final class LsMapper implements Mapper {
+
+ private final Map<String, TarArchiveEntry> mapping;
+
+
+ public final static class ParseError extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public ParseError( String message ) {
+ super(message);
+ }
+ }
+
+
+ public LsMapper( final InputStream pInput ) throws IOException, ParseError {
+ mapping = parse(pInput);
+ }
+
+ /*
+./trunk/target/test-classes/org/vafer/dependency:
+total 176
+drwxr-xr-x 23 tcurdt tcurdt 782 Jun 25 03:48 .
+drwxr-xr-x 3 tcurdt tcurdt 102 Jun 25 03:48 ..
+-rw-r--r-- 1 tcurdt tcurdt 2934 Jun 25 03:48 DependenciesTestCase.class
+-rw-r--r-- 1 tcurdt tcurdt 786 Jun 25 03:48 JarCombiningTestCase$1.class
+-rw-r--r-- 1 tcurdt tcurdt 2176 Jun 25 03:48 WarTestCase.class
+drwxr-xr-x 4 tcurdt tcurdt 136 Jun 25 03:48 classes
+
+./trunk/target/test-classes/org/vafer/dependency/classes:
+ */
+
+ final private Pattern basePattern = Pattern.compile("^\\./(.*):$");
+ final private Pattern totalPattern = Pattern.compile("^total ([0-9]+)$");
+ final private Pattern dirPattern = Pattern.compile("^d([rwx-]{9})\\s+([0-9]+)\\s+(\\S*)\\s+(\\S*)\\s+([0-9]+)\\s+(.*)\\s+[\\.]{1,2}$");
+ final private Pattern filePattern = Pattern.compile("^([d-])([rwx-]{9})\\s+([0-9]+)\\s+(\\S*)\\s+(\\S*)\\s+([0-9]+)\\s+(.*)\\s+(.*)$");
+ final private Pattern newlinePattern = Pattern.compile("$");
+
+ private String readBase( final BufferedReader reader ) throws IOException, ParseError {
+ final String line = reader.readLine();
+ if (line == null) {
+ return null;
+ }
+ final Matcher matcher = basePattern.matcher(line);
+ if (!matcher.matches()) {
+ throw new ParseError("expected base line but got \"" + line + "\"");
+ }
+ return matcher.group(1);
+ }
+
+ private String readTotal( final BufferedReader reader ) throws IOException, ParseError {
+ final String line = reader.readLine();
+ final Matcher matcher = totalPattern.matcher(line);
+ if (!matcher.matches()) {
+ throw new ParseError("expected total line but got \"" + line + "\"");
+ }
+ return matcher.group(1);
+ }
+
+ private TarArchiveEntry readDir( final BufferedReader reader, final String base ) throws IOException, ParseError {
+ final String current = reader.readLine();
+ final Matcher currentMatcher = dirPattern.matcher(current);
+ if (!currentMatcher.matches()) {
+ throw new ParseError("expected dirline but got \"" + current + "\"");
+ }
+
+ final String parent = reader.readLine();
+ final Matcher parentMatcher = dirPattern.matcher(parent);
+ if (!parentMatcher.matches()) {
+ throw new ParseError("expected dirline but got \"" + parent + "\"");
+ }
+
+ final TarArchiveEntry entry = new TarArchiveEntry(base, true);
+
+ entry.setMode(convertModeFromString(currentMatcher.group(1)));
+ entry.setUserName(currentMatcher.group(3));
+ entry.setGroupName(currentMatcher.group(4));
+
+ return entry;
+ }
+
+
+ private int convertModeFromString( final String mode ) {
+
+ final char[] m = mode.toCharArray();
+ /*
+ -rwxrwxrwx
+
+ 4000 set-user-ID-on-execution bit
+ 2000 set-user-ID-on-execution bit
+ 1000 sticky bit
+ 0400 allow read by owner.
+ 0200 allow write by owner.
+ 0100 execute / search
+ 0040 allow read by group members.
+ 0020 allow write by group members.
+ 0010 execute / search
+ 0004 allow read by others.
+ 0002 allow write by others.
+ 0001 execute / search
+ */
+ // TODO: simplified - needs fixing
+ int sum = 0;
+ int bit = 1;
+ for (int i = m.length - 1; i >= 0; i--) {
+ if (m[i] != '-') {
+ sum += bit;
+ }
+ bit += bit;
+ }
+ return sum;
+ }
+
+ private TarArchiveEntry readFile( final BufferedReader reader, final String base ) throws IOException, ParseError {
+
+ while (true) {
+ final String line = reader.readLine();
+
+ if (line == null) {
+ return null;
+ }
+
+ final Matcher currentMatcher = filePattern.matcher(line);
+ if (!currentMatcher.matches()) {
+ final Matcher newlineMatcher = newlinePattern.matcher(line);
+ if (newlineMatcher.matches()) {
+ return null;
+ }
+ throw new ParseError("expected file line but got \"" + line + "\"");
+ }
+
+ final String type = currentMatcher.group(1);
+ if (type.startsWith("-")) {
+ final TarArchiveEntry entry = new TarArchiveEntry(base + "/" + currentMatcher.group(8), true);
+
+ entry.setMode(convertModeFromString(currentMatcher.group(2)));
+ entry.setUserName(currentMatcher.group(4));
+ entry.setGroupName(currentMatcher.group(5));
+
+ return entry;
+ }
+ }
+
+ }
+
+ private Map<String, TarArchiveEntry> parse( final InputStream pInput ) throws IOException, ParseError {
+ final Map<String, TarArchiveEntry> mapping = new HashMap<String, TarArchiveEntry>();
+
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(pInput));
+
+ boolean first = true;
+ while (true) {
+
+ final String base;
+ if (first) {
+ base = "";
+ first = false;
+ } else {
+ base = readBase(reader);
+ if (base == null) {
+ break;
+ }
+ }
+
+ readTotal(reader);
+ final TarArchiveEntry dir = readDir(reader, base);
+ mapping.put(dir.getName(), dir);
+
+ while (true) {
+ final TarArchiveEntry file = readFile(reader, base);
+
+ if (file == null) {
+ break;
+ }
+
+ mapping.put(file.getName(), file);
+ }
+ }
+
+ return mapping;
+ }
+
+ public TarArchiveEntry map( final TarArchiveEntry pEntry ) {
+
+ final TarArchiveEntry entry = mapping.get(pEntry.getName());
+
+ if (entry != null) {
+
+ final TarArchiveEntry newEntry = new TarArchiveEntry(entry.getName(), true);
+ newEntry.setUserId(entry.getUserId());
+ newEntry.setGroupId(entry.getGroupId());
+ newEntry.setUserName(entry.getUserName());
+ newEntry.setGroupName(entry.getGroupName());
+ newEntry.setMode(entry.getMode());
+ newEntry.setSize(entry.getSize());
+
+ return newEntry;
+ }
+
+ return pEntry;
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/mapping/Mapper.java b/src/main/java/org/vafer/jdeb/mapping/Mapper.java
new file mode 100644
index 0000000..1229fda
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/mapping/Mapper.java
@@ -0,0 +1,30 @@
+/*
+ * 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.mapping;
+
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+
+
+/**
+ * Maps one entry to another. So you modify ownerships permissions etc in a Mapper.
+ *
+ * @author Torsten Curdt
+ */
+public interface Mapper {
+
+ public TarArchiveEntry map( final TarArchiveEntry entry );
+
+}
diff --git a/src/main/java/org/vafer/jdeb/mapping/NullMapper.java b/src/main/java/org/vafer/jdeb/mapping/NullMapper.java
new file mode 100644
index 0000000..de5b115
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/mapping/NullMapper.java
@@ -0,0 +1,31 @@
+/*
+ * 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.mapping;
+
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+
+public final class NullMapper implements Mapper {
+
+ public static final Mapper INSTANCE = new NullMapper();
+
+ private NullMapper() {
+ }
+
+ public TarArchiveEntry map( final TarArchiveEntry pEntry ) {
+ return pEntry;
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/mapping/PermMapper.java b/src/main/java/org/vafer/jdeb/mapping/PermMapper.java
new file mode 100644
index 0000000..f3c6701
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/mapping/PermMapper.java
@@ -0,0 +1,107 @@
+/*
+ * 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.mapping;
+
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.vafer.jdeb.utils.Utils;
+
+/**
+ * Applies a uniform set of permissions and ownership to all entries.
+ *
+ * @author Bryan Sant
+ */
+public final class PermMapper implements Mapper {
+
+ private final int strip;
+ private final String prefix;
+ private int uid = -1;
+ private int gid = -1;
+ private String user;
+ private String group;
+ private int fileMode = -1;
+ private int dirMode = -1;
+
+ public static int toMode( String modeString ) {
+ int mode = -1;
+ if (modeString != null && modeString.length() > 0) {
+ mode = Integer.parseInt(modeString, 8);
+ }
+ return mode;
+ }
+
+ public PermMapper( int uid, int gid, String user, String group, int fileMode, int dirMode, int strip, String prefix ) {
+ this.strip = strip;
+ this.prefix = (prefix == null) ? "" : prefix;
+ this.uid = uid;
+ this.gid = gid;
+ this.user = user;
+ this.group = group;
+ this.fileMode = fileMode;
+ this.dirMode = dirMode;
+ }
+
+ public PermMapper( int uid, int gid, String user, String group, String fileMode, String dirMode, int strip, String prefix ) {
+ this(uid, gid, user, group, toMode(fileMode), toMode(dirMode), strip, prefix);
+ }
+
+ public TarArchiveEntry map( final TarArchiveEntry entry ) {
+ final String name = entry.getName();
+
+ final TarArchiveEntry newEntry = new TarArchiveEntry(prefix + '/' + Utils.stripPath(strip, name), true);
+
+ // Set ownership
+ if (uid > -1) {
+ newEntry.setUserId(uid);
+ } else {
+ newEntry.setUserId(entry.getUserId());
+ }
+ if (gid > -1) {
+ newEntry.setGroupId(gid);
+ } else {
+ newEntry.setGroupId(entry.getGroupId());
+ }
+ if (user != null) {
+ newEntry.setUserName(user);
+ } else {
+ newEntry.setUserName(entry.getUserName());
+ }
+ if (group != null) {
+ newEntry.setGroupName(group);
+ } else {
+ newEntry.setGroupName(entry.getGroupName());
+ }
+
+ // Set permissions
+ if (newEntry.isDirectory()) {
+ if (dirMode > -1) {
+ newEntry.setMode(dirMode);
+ } else {
+ newEntry.setMode(entry.getMode());
+ }
+ } else {
+ if (fileMode > -1) {
+ newEntry.setMode(fileMode);
+ } else {
+ newEntry.setMode(entry.getMode());
+
+ }
+ }
+
+ newEntry.setSize(entry.getSize());
+
+ return newEntry;
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/maven/AbstractPluginMojo.java b/src/main/java/org/vafer/jdeb/maven/AbstractPluginMojo.java
new file mode 100644
index 0000000..de3cf65
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/maven/AbstractPluginMojo.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.maven;
+
+import java.io.File;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.project.MavenProject;
+
+public abstract class AbstractPluginMojo extends AbstractMojo {
+
+ /**
+ * @parameter expression="${project}"
+ * @required
+ * @readonly
+ */
+ private MavenProject project;
+
+ /**
+ * @parameter expression="${project.build.directory}"
+ * @required
+ * @readonly
+ */
+ protected File buildDirectory;
+
+ protected MavenProject getProject() {
+ if (project.getExecutionProject() != null) {
+ return project.getExecutionProject();
+ }
+
+ return project;
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/maven/Data.java b/src/main/java/org/vafer/jdeb/maven/Data.java
new file mode 100644
index 0000000..0f1dd41
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/maven/Data.java
@@ -0,0 +1,217 @@
+/*
+ * 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.maven;
+
+import static org.vafer.jdeb.maven.MissingSourceBehavior.FAIL;
+import static org.vafer.jdeb.maven.MissingSourceBehavior.IGNORE;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+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;
+
+/**
+ * Maven "data" element acting as a factory for DataProducers. So far Archive and
+ * Directory producers are supported. Both support the usual ant pattern set
+ * matching.
+ *
+ * @author Bryan Sant
+ */
+public final class Data implements DataProducer {
+
+ private File src;
+
+ /**
+ * @parameter expression="${src}"
+ */
+ public void setSrc( File src ) {
+ this.src = src;
+ }
+
+ private String dst;
+
+ /**
+ * @parameter expression="${dst}"
+ */
+ public void setDst( String dst ) {
+ this.dst = dst;
+ }
+
+ private String type;
+
+ /**
+ * @parameter expression="${type}"
+ */
+ public void setType( String type ) {
+ this.type = type;
+ }
+
+ private MissingSourceBehavior missingSrc = FAIL;
+
+ /**
+ * @parameter expression="${missingSrc}"
+ */
+ public void setMissingSrc( String missingSrc ) {
+ MissingSourceBehavior value = MissingSourceBehavior.valueOf(missingSrc.trim().toUpperCase());
+ if (value == null) {
+ throw new IllegalArgumentException("Unknown " + MissingSourceBehavior.class.getSimpleName() + ": " + missingSrc);
+ }
+ this.missingSrc = value;
+ }
+
+ private String linkName;
+
+ /**
+ * @parameter expression="${linkName}"
+ */
+ public void setLinkName(String linkName) {
+ this.linkName = linkName;
+ }
+
+ private String linkTarget;
+
+ /**
+ * @parameter expression="${linkTarget}"
+ */
+ public void setLinkTarget(String linkTarget) {
+ this.linkTarget = linkTarget;
+ }
+
+ private boolean symlink = true;
+
+ /**
+ * @parameter expression="${symlink}"
+ */
+ public void setSymlink(boolean symlink) {
+ this.symlink = symlink;
+ }
+
+ private String[] includePatterns;
+
+ /**
+ * @parameter expression="${includes}" alias="includes"
+ */
+ public void setIncludes( String includes ) {
+ includePatterns = splitPatterns(includes);
+ }
+
+ private String[] excludePatterns;
+
+ /**
+ * @parameter expression="${excludes}" alias="excludes"
+ */
+ public void setExcludes( String excludes ) {
+ excludePatterns = splitPatterns(excludes);
+ }
+
+ /**
+ * @parameter expression="${mapper}"
+ */
+ private Mapper mapper;
+
+ /**
+ * @parameter expression="${paths}"
+ */
+ private String[] paths;
+
+ /* For testing only */
+ void setPaths( String[] paths ) {
+ this.paths = paths;
+ }
+
+ public String[] splitPatterns( String patterns ) {
+ String[] result = null;
+ if (patterns != null && patterns.length() > 0) {
+ List<String> tokens = new ArrayList<String>();
+ StringTokenizer tok = new StringTokenizer(patterns, ", ", false);
+ while (tok.hasMoreTokens()) {
+ tokens.add(tok.nextToken());
+ }
+ result = tokens.toArray(new String[tokens.size()]);
+ }
+ return result;
+ }
+
+ 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() };
+ }
+
+ // link 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");
+ }
+
+ new DataProducerLink(linkName, linkTarget, symlink, includePatterns, excludePatterns, mappers).produce(pReceiver);
+ return;
+ }
+
+ // template type
+
+ if ("template".equalsIgnoreCase(type)) {
+ if (paths == null || paths.length == 0) {
+ throw new RuntimeException("paths is not set");
+ }
+
+ new DataProducerPathTemplate(paths, includePatterns, excludePatterns, mappers).produce(pReceiver);
+ return;
+ }
+
+ // Types that require src to exist
+
+ if (src == null || !src.exists()) {
+ if (missingSrc == IGNORE) {
+ return;
+ } else {
+ throw new FileNotFoundException("Data source not found : " + src);
+ }
+ }
+
+ if ("file".equalsIgnoreCase(type)) {
+ new DataProducerFile(src, dst, includePatterns, excludePatterns, mappers).produce(pReceiver);
+ return;
+ }
+
+ if ("archive".equalsIgnoreCase(type)) {
+ new DataProducerArchive(src, includePatterns, excludePatterns, mappers).produce(pReceiver);
+ return;
+ }
+
+ if ("directory".equalsIgnoreCase(type)) {
+ new DataProducerDirectory(src, includePatterns, excludePatterns, mappers).produce(pReceiver);
+ return;
+ }
+
+ throw new IOException("Unknown type '" + type + "' (file|directory|archive|template|link) for " + src);
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/maven/DebMojo.java b/src/main/java/org/vafer/jdeb/maven/DebMojo.java
new file mode 100644
index 0000000..9d67332
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/maven/DebMojo.java
@@ -0,0 +1,427 @@
+/*
+ * 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.maven;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectHelper;
+import org.apache.tools.tar.TarEntry;
+import org.vafer.jdeb.Console;
+import org.vafer.jdeb.DataConsumer;
+import org.vafer.jdeb.DataProducer;
+import org.vafer.jdeb.DebMaker;
+import org.vafer.jdeb.PackagingException;
+import org.vafer.jdeb.utils.FilteredFile;
+import org.vafer.jdeb.utils.MapVariableResolver;
+import org.vafer.jdeb.utils.Utils;
+import org.vafer.jdeb.utils.VariableResolver;
+
+/**
+ * Creates deb archive
+ *
+ * @goal jdeb
+ * @phase package
+ */
+public class DebMojo extends AbstractPluginMojo {
+
+ /**
+ * @component
+ */
+ private MavenProjectHelper projectHelper;
+
+ /**
+ * Defines the name of deb package.
+ *
+ * @parameter
+ */
+ private String name;
+
+ /**
+ * Defines the pattern of the name of final artifacts. Possible
+ * substitutions are [[baseDir]] [[buildDir]] [[artifactId]] [[version]]
+ * [[extension]] and [[groupId]].
+ *
+ * @parameter default-value="[[buildDir]]/[[artifactId]]_[[version]]_all.[[extension]]"
+ */
+ private String deb;
+
+ /**
+ * Explicitly defines the path to the control directory. At least the
+ * control file is mandatory.
+ *
+ * @parameter default-value="[[baseDir]]/src/deb/control"
+ */
+ private String controlDir;
+
+ /**
+ * Explicitly define the file to read the changes from.
+ *
+ * @parameter default-value="[[baseDir]]/CHANGES.txt"
+ */
+ private String changesIn;
+
+ /**
+ * Explicitly define the file where to write the changes to.
+ *
+ * @parameter default-value="[[buildDir]]/[[artifactId]]_[[version]]_all.changes"
+ */
+ private String changesOut;
+
+ /**
+ * Explicitly define the file where to write the changes of the changes
+ * input to.
+ *
+ * @parameter default-value="[[baseDir]]/CHANGES.txt"
+ */
+ private String changesSave;
+
+ /**
+ * The compression method used for the data file (none, gzip, bzip2 or xz)
+ *
+ * @parameter default-value="gzip"
+ */
+ private String compression;
+
+
+ /**
+ * Boolean option whether to attach the artifact to the project
+ *
+ * @parameter default-value="true"
+ */
+ private String attach;
+
+ /**
+ * The location where all package files will be installed. By default, all
+ * packages are installed in /opt (see the FHS here:
+ * http://www.pathname.com/
+ * fhs/pub/fhs-2.3.html#OPTADDONAPPLICATIONSOFTWAREPACKAGES)
+ *
+ * @parameter default-value="/opt/[[artifactId]]"
+ */
+ private String installDir;
+
+
+ /**
+ * The type of attached artifact
+ *
+ * @parameter default-value="deb"
+ */
+ private String type;
+
+ /**
+ * The project base directory
+ *
+ * @parameter default-value="${basedir}"
+ * @required
+ * @readonly
+ */
+ private File baseDir;
+
+ /**
+ * Run the plugin on all sub-modules.
+ * If set to false, the plugin will be run in the same folder where the
+ * mvn command was invoked
+ *
+ * @parameter expression="${submodules}" default-value="true"
+ */
+ private boolean submodules;
+
+ /**
+ * The Maven Session Object
+ *
+ * @parameter expression="${session}"
+ * @required
+ * @readonly
+ */
+ private MavenSession session;
+
+ /**
+ * The classifier of attached artifact
+ *
+ * @parameter
+ */
+ private String classifier;
+
+ /**
+ * "data" entries used to determine which files should be added to this deb.
+ * The "data" entries may specify a tarball (tar.gz, tar.bz2, tgz), a
+ * directory, or a normal file. An entry would look something like this in
+ * your pom.xml:
+ *
+ * <pre>
+ * <build>
+ * <plugins>
+ * <plugin>
+ * <artifactId>jdeb</artifactId>
+ * <groupId>org.vafer</groupId>
+ * ...
+ * <configuration>
+ * ...
+ * <dataSet>
+ * <data>
+ * <src>${project.basedir}/target/my_archive.tar.gz</src>
+ * <include>...</include>
+ * <exclude>...</exclude>
+ * <mapper>
+ * <type>perm</type>
+ * <strip>1</strip>
+ * <prefix>/somewhere/else</prefix>
+ * <user>santbj</user>
+ * <group>santbj</group>
+ * <mode>600</mode>
+ * </mapper>
+ * </data>
+ * <data>
+ * <src>${project.build.directory}/data</src>
+ * <include></include>
+ * <exclude>**/.svn</exclude>
+ * <mapper>
+ * <type>ls</type>
+ * <src>mapping.txt</src>
+ * </mapper>
+ * </data>
+ * <data>
+ * <type>link</type>
+ * <linkName>/a/path/on/the/target/fs</linkName>
+ * <linkTarget>/a/sym/link/to/the/scr/file</linkTarget>
+ * <symlink>true</symlink>
+ * </data>
+ * <data>
+ * <src>${project.basedir}/README.txt</src>
+ * </data>
+ * </dataSet>
+ * </configuration>
+ * </plugins>
+ * </build>
+ * </pre>
+ *
+ * @parameter expression="${dataSet}"
+ */
+ private Data[] dataSet;
+
+ /**
+ * When SNAPSHOT version replace <code>SNAPSHOT</code> with current date
+ * and time to make sure each build is unique.
+ *
+ * @parameter expression="${timestamped}" default-value="false"
+ */
+ private boolean timestamped;
+
+ /**
+ * If verbose is true info messages also get logged.
+ * Will be changed to "false" in future versions.
+ * Left to "true" for the transition.
+ *
+ * @parameter expression="${verbose}" default-value="true"
+ */
+ private boolean verbose;
+
+ /* end of parameters */
+
+ private String openReplaceToken = "[[";
+ private String closeReplaceToken = "]]";
+ private Collection<DataProducer> dataProducers = new ArrayList<DataProducer>();
+
+ public void setOpenReplaceToken( String openReplaceToken ) {
+ this.openReplaceToken = openReplaceToken;
+ // FIXME yuck!
+ FilteredFile.setOpenToken(openReplaceToken);
+ }
+
+ public void setCloseReplaceToken( String closeReplaceToken ) {
+ this.closeReplaceToken = closeReplaceToken;
+ // FIXME yuck!
+ FilteredFile.setCloseToken(closeReplaceToken);
+ }
+
+ protected void setData( Data[] dataSet ) {
+ this.dataSet = dataSet;
+ dataProducers.clear();
+ if (dataSet != null) {
+ Collections.addAll(dataProducers, dataSet);
+ }
+ }
+
+ protected VariableResolver initializeVariableResolver( Map<String, String> variables ) {
+ ((Map) variables).putAll(getProject().getProperties());
+ ((Map) variables).putAll(System.getProperties());
+ variables.put("name", name != null ? name : getProject().getName());
+ variables.put("artifactId", getProject().getArtifactId());
+ variables.put("groupId", getProject().getGroupId());
+ variables.put("version", getProjectVersion());
+ variables.put("description", getProject().getDescription());
+ variables.put("extension", "deb");
+ variables.put("baseDir", getProject().getBasedir().getAbsolutePath());
+ variables.put("buildDir", buildDirectory.getAbsolutePath());
+ variables.put("project.version", getProject().getVersion());
+ variables.put("url", getProject().getUrl());
+
+ return new MapVariableResolver(variables);
+ }
+
+ /**
+ * Doc some cleanup and conversion on the Maven project version.
+ * <ul>
+ * <li>any "-" is replaced by "+"</li>
+ * <li>"SNAPSHOT" is replaced with the current time and date, prepended by "~"</li>
+ * </ul>
+ *
+ * @return the Maven project version
+ */
+ private String getProjectVersion() {
+ return Utils.convertToDebianVersion(getProject().getVersion(), this.timestamped ? session.getStartTime() : null);
+ }
+
+ /**
+ * @return whether or not Maven is currently operating in the execution root
+ */
+ private boolean isSubmodule() {
+ // FIXME there must be a better way
+ return !session.getExecutionRootDirectory().equalsIgnoreCase(baseDir.toString());
+ }
+
+ /**
+ * @return whether or not the main artifact was created
+ */
+ private boolean hasMainArtifact() {
+ final MavenProject project = getProject();
+ final Artifact artifact = project.getArtifact();
+ return artifact.getFile() != null && artifact.getFile().isFile();
+ }
+
+ /**
+ * Main entry point
+ *
+ * @throws MojoExecutionException on error
+ */
+ @Override
+ public void execute() throws MojoExecutionException {
+
+ final MavenProject project = getProject();
+
+ if (isSubmodule() && !submodules) {
+ getLog().info("skipping sub module: jdeb executing at top-level only");
+ return;
+ }
+
+ setData(dataSet);
+
+ Console console = new MojoConsole(getLog(), verbose);
+
+ final VariableResolver resolver = initializeVariableResolver(new HashMap<String, String>());
+
+ final File debFile = new File(Utils.replaceVariables(resolver, deb, openReplaceToken, closeReplaceToken));
+ final File controlDirFile = new File(Utils.replaceVariables(resolver, controlDir, openReplaceToken, closeReplaceToken));
+ final File installDirFile = new File(Utils.replaceVariables(resolver, installDir, openReplaceToken, closeReplaceToken));
+ final File changesInFile = new File(Utils.replaceVariables(resolver, changesIn, openReplaceToken, closeReplaceToken));
+ final File changesOutFile = new File(Utils.replaceVariables(resolver, changesOut, openReplaceToken, closeReplaceToken));
+ final File changesSaveFile = new File(Utils.replaceVariables(resolver, changesSave, openReplaceToken, closeReplaceToken));
+
+ // if there are no producers defined we try to use the artifacts
+ if (dataProducers.isEmpty()) {
+
+ if (!hasMainArtifact()) {
+
+ final String packaging = project.getPackaging();
+ if ("pom".equalsIgnoreCase(packaging)) {
+ getLog().warn("Creating empty debian package.");
+ } else {
+ throw new MojoExecutionException(
+ "Nothing to include into the debian package. " +
+ "Did you maybe forget to add a <data> tag or call the plugin directly?");
+ }
+
+ } else {
+
+ Set<Artifact> artifacts = new HashSet<Artifact>();
+
+ artifacts.add(project.getArtifact());
+
+ for (Artifact artifact : (Set<Artifact>) project.getArtifacts()) {
+ artifacts.add(artifact);
+ }
+
+ for (Artifact artifact : (List<Artifact>) project.getAttachedArtifacts()) {
+ artifacts.add(artifact);
+ }
+
+ for (Artifact artifact : artifacts) {
+ final File file = artifact.getFile();
+ if (file != null) {
+ dataProducers.add(new DataProducer() {
+ @Override
+ public void produce( final DataConsumer receiver ) {
+ try {
+ receiver.onEachFile(
+ new FileInputStream(file),
+ new File(installDirFile, file.getName()).getAbsolutePath(),
+ "",
+ "root", 0, "root", 0,
+ TarEntry.DEFAULT_FILE_MODE,
+ file.length());
+ } catch (Exception e) {
+ getLog().error(e);
+ }
+ }
+ });
+ } else {
+ getLog().error("No file for artifact " + artifact);
+ }
+ }
+ }
+ }
+
+ try {
+ DebMaker debMaker = new DebMaker(console, dataProducers);
+ debMaker.setDeb(debFile);
+ debMaker.setControl(controlDirFile);
+ debMaker.setPackage(getProject().getArtifactId());
+ debMaker.setDescription(getProject().getDescription());
+ debMaker.setHomepage(getProject().getUrl());
+ debMaker.setChangesIn(changesInFile);
+ debMaker.setChangesOut(changesOutFile);
+ debMaker.setChangesSave(changesSaveFile);
+ debMaker.setCompression(compression);
+ debMaker.setResolver(resolver);
+ debMaker.validate();
+ debMaker.makeDeb();
+
+ // Always attach unless explicitly set to false
+ if ("true".equalsIgnoreCase(attach)) {
+ getLog().info("Attaching created debian archive " + debFile);
+ projectHelper.attachArtifact(project, type, classifier, debFile);
+ }
+
+ } catch (PackagingException e) {
+ getLog().error("Failed to create debian package " + debFile, e);
+ throw new MojoExecutionException("Failed to create debian package " + debFile, e);
+ }
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/maven/Mapper.java b/src/main/java/org/vafer/jdeb/maven/Mapper.java
new file mode 100644
index 0000000..d44a3d2
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/maven/Mapper.java
@@ -0,0 +1,104 @@
+/*
+ * 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.maven;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.vafer.jdeb.mapping.LsMapper;
+import org.vafer.jdeb.mapping.NullMapper;
+import org.vafer.jdeb.mapping.PermMapper;
+
+/**
+ * Maven "mapper" element acting as factory for the entry mapper.
+ * Supported types: ls, perm
+ *
+ * @author Bryan Sant
+ */
+public final class Mapper {
+
+ /**
+ * @parameter
+ * @required
+ */
+ private String type;
+
+ /**
+ * @parameter
+ */
+ private int uid = -1;
+
+ /**
+ * @parameter
+ */
+ private int gid = -1;
+
+ /**
+ * @parameter
+ */
+ private String user;
+
+ /**
+ * @parameter
+ */
+ private String group;
+
+ /**
+ * @parameter
+ */
+ private String filemode;
+
+ /**
+ * @parameter
+ */
+ private String dirmode;
+
+ /**
+ * @parameter
+ */
+ private String prefix;
+
+ /**
+ * @parameter
+ */
+ private int strip;
+
+ /**
+ * @parameter
+ */
+ private File src;
+
+
+ public org.vafer.jdeb.mapping.Mapper createMapper() throws IOException {
+
+ if ("ls".equalsIgnoreCase(type)) {
+ try {
+ return new LsMapper(new FileInputStream(src));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ if ("perm".equalsIgnoreCase(type)) {
+ return new PermMapper(uid, gid, user, group, filemode, dirmode, strip, prefix);
+ }
+
+ /* NullMapper required for DataProducerPathTemplate */
+ return NullMapper.INSTANCE;
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/maven/MissingSourceBehavior.java b/src/main/java/org/vafer/jdeb/maven/MissingSourceBehavior.java
new file mode 100644
index 0000000..684e871
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/maven/MissingSourceBehavior.java
@@ -0,0 +1,20 @@
+/*
+ * 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.maven;
+
+public enum MissingSourceBehavior {
+ IGNORE, FAIL
+}
diff --git a/src/main/java/org/vafer/jdeb/maven/MojoConsole.java b/src/main/java/org/vafer/jdeb/maven/MojoConsole.java
new file mode 100644
index 0000000..da78148
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/maven/MojoConsole.java
@@ -0,0 +1,44 @@
+/*
+ * 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.maven;
+
+import org.apache.maven.plugin.logging.Log;
+import org.vafer.jdeb.Console;
+
+/**
+ * Console implementation for Maven plugins.
+ */
+class MojoConsole implements Console {
+
+ private final Log log;
+ private final boolean verbose;
+
+ public MojoConsole(Log log, boolean verbose) {
+ this.log = log;
+ this.verbose = verbose;
+ }
+
+ public void info(String s) {
+ if (verbose) {
+ log.info(s);
+ }
+ }
+
+ public void warn(String s) {
+ log.warn(s);
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/producers/AbstractDataProducer.java b/src/main/java/org/vafer/jdeb/producers/AbstractDataProducer.java
new file mode 100644
index 0000000..47d8764
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/producers/AbstractDataProducer.java
@@ -0,0 +1,80 @@
+/*
+ * 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.tools.ant.types.selectors.SelectorUtils;
+import org.vafer.jdeb.DataProducer;
+import org.vafer.jdeb.mapping.Mapper;
+
+/**
+ * Base Producer class providing including/excluding.
+ *
+ * @author Torsten Curdt
+ */
+public abstract class AbstractDataProducer implements DataProducer {
+
+ private final String[] includes;
+ private final String[] excludes;
+ private final Mapper[] mappers;
+
+
+ public AbstractDataProducer( final String[] pIncludes, final String[] pExcludes, final Mapper[] pMapper ) {
+ excludes = (pExcludes != null) ? pExcludes : new String[0];
+ includes = (pIncludes != null) ? pIncludes : new String[] { "**" };
+ mappers = (pMapper != null) ? pMapper : new Mapper[0];
+ }
+
+ public boolean isIncluded( final String pName ) {
+ if (!isIncluded(pName, includes)) {
+ return false;
+ }
+ if (isExcluded(pName, excludes)) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isIncluded( String name, String[] includes ) {
+ for (String include : includes) {
+ if (SelectorUtils.matchPath(include, name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ private boolean isExcluded( String name, String[] excludes ) {
+ for (String exclude : excludes) {
+ if (SelectorUtils.matchPath(exclude, name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public TarArchiveEntry map( final TarArchiveEntry pEntry ) {
+
+ TarArchiveEntry entry = pEntry;
+
+ for (Mapper mapper : mappers) {
+ entry = mapper.map(entry);
+ }
+
+ return entry;
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerArchive.java b/src/main/java/org/vafer/jdeb/producers/DataProducerArchive.java
new file mode 100644
index 0000000..8160759
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/producers/DataProducerArchive.java
@@ -0,0 +1,151 @@
+/*
+ * 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 java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.archivers.ArchiveStreamFactory;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
+import org.apache.commons.compress.compressors.CompressorException;
+import org.apache.commons.compress.compressors.CompressorInputStream;
+import org.apache.commons.compress.compressors.CompressorStreamFactory;
+import org.vafer.jdeb.DataConsumer;
+import org.vafer.jdeb.DataProducer;
+import org.vafer.jdeb.mapping.Mapper;
+
+/**
+ * Providing data from an archive keeping permissions and ownerships.
+ *
+ * @author Torsten Curdt
+ */
+public final class DataProducerArchive extends AbstractDataProducer implements DataProducer {
+
+ private final File archive;
+
+ public DataProducerArchive( final File pArchive, final String[] pIncludes, final String[] pExcludes, final Mapper[] pMappers ) {
+ super(pIncludes, pExcludes, pMappers);
+ archive = pArchive;
+ }
+
+ public void produce( final DataConsumer pReceiver ) throws IOException {
+
+ InputStream is = new BufferedInputStream(new FileInputStream(archive));
+
+ CompressorInputStream compressorInputStream = null;
+
+ try {
+ compressorInputStream = new CompressorStreamFactory().createCompressorInputStream(is);
+ } catch (CompressorException e) {
+ // expected if the input file is a zip archive
+ }
+
+ if (compressorInputStream != null) {
+ is = new BufferedInputStream(compressorInputStream);
+ }
+
+ ArchiveInputStream archiveInputStream = null;
+
+ try {
+ archiveInputStream = new ArchiveStreamFactory().createArchiveInputStream(is);
+ } catch (ArchiveException e) {
+ throw new IOException("Unsupported archive format: " + archive, e);
+ }
+
+ EntryConverter converter = null;
+
+ if (archiveInputStream instanceof TarArchiveInputStream) {
+
+ converter = new EntryConverter() {
+ public TarArchiveEntry convert( ArchiveEntry entry ) {
+ TarArchiveEntry src = (TarArchiveEntry) entry;
+ TarArchiveEntry dst = new TarArchiveEntry(src.getName(), true);
+
+ dst.setSize(src.getSize());
+ dst.setGroupName(src.getGroupName());
+ dst.setGroupId(src.getGroupId());
+ dst.setUserId(src.getUserId());
+ dst.setMode(src.getMode());
+ dst.setModTime(src.getModTime());
+
+ return dst;
+ }
+ };
+
+ } else if (archiveInputStream instanceof ZipArchiveInputStream) {
+
+ converter = new EntryConverter() {
+ public TarArchiveEntry convert( ArchiveEntry entry ) {
+ ZipArchiveEntry src = (ZipArchiveEntry) entry;
+ TarArchiveEntry dst = new TarArchiveEntry(src.getName(), true);
+
+ dst.setSize(src.getSize());
+ dst.setMode(src.getUnixMode());
+ dst.setModTime(src.getTime());
+
+ return dst;
+ }
+ };
+
+ } else {
+ throw new IOException("Unsupported archive format: " + archive);
+ }
+
+
+ try {
+ while (true) {
+
+ ArchiveEntry archiveEntry = archiveInputStream.getNextEntry();
+
+ if (archiveEntry == null) {
+ break;
+ }
+
+ if (!isIncluded(archiveEntry.getName())) {
+ continue;
+ }
+
+ TarArchiveEntry entry = converter.convert(archiveEntry);
+
+ entry = map(entry);
+
+ if (entry.isDirectory()) {
+ pReceiver.onEachDir(entry.getName(), entry.getLinkName(), entry.getUserName(), entry.getUserId(), entry.getGroupName(), entry.getGroupId(), entry.getMode(), entry.getSize());
+ continue;
+ }
+ pReceiver.onEachFile(archiveInputStream, entry.getName(), entry.getLinkName(), entry.getUserName(), entry.getUserId(), entry.getGroupName(), entry.getGroupId(), entry.getMode(), entry.getSize());
+ }
+
+ } finally {
+ if (archiveInputStream != null) {
+ archiveInputStream.close();
+ }
+ }
+ }
+
+ private interface EntryConverter {
+ public TarArchiveEntry convert( ArchiveEntry entry );
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerDirectory.java b/src/main/java/org/vafer/jdeb/producers/DataProducerDirectory.java
new file mode 100644
index 0000000..70eff71
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/producers/DataProducerDirectory.java
@@ -0,0 +1,129 @@
+/*
+ * 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 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;
+import org.vafer.jdeb.DataConsumer;
+import org.vafer.jdeb.DataProducer;
+import org.vafer.jdeb.mapping.Mapper;
+import org.vafer.jdeb.utils.Utils;
+
+/**
+ * DataProducer iterating over a directory.
+ * For cross-platform permissions and ownerships you probably want to use a Mapper, too.
+ *
+ * @author Torsten Curdt
+ */
+public final class DataProducerDirectory extends AbstractDataProducer implements DataProducer {
+
+ private final DirectoryScanner scanner = new DirectoryScanner();
+
+ public DataProducerDirectory( final File pDir, final String[] pIncludes, final String[] pExcludes, final Mapper[] pMappers ) {
+ super(pIncludes, pExcludes, pMappers);
+ scanner.setBasedir(pDir);
+ scanner.setIncludes(pIncludes);
+ scanner.setExcludes(pExcludes);
+ scanner.setCaseSensitive(true);
+ scanner.setFollowSymlinks(true);
+ }
+
+ public void produce( final DataConsumer pReceiver ) throws IOException {
+
+ scanner.scan();
+
+ final File baseDir = scanner.getBasedir();
+
+ for (String dir : scanner.getIncludedDirectories()) {
+ final File file = new File(baseDir, dir);
+ String dirname = getFilename(baseDir, file);
+
+ if ("".equals(dirname)) {
+ continue;
+ }
+
+ if (!isIncluded(dirname)) {
+ continue;
+ }
+
+ if ('/' != File.separatorChar) {
+ dirname = dirname.replace(File.separatorChar, '/');
+ }
+
+ if (!dirname.endsWith("/")) {
+ 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);
+
+ entry = map(entry);
+
+ entry.setSize(0);
+
+ pReceiver.onEachDir(entry.getName(), entry.getLinkName(), entry.getUserName(), entry.getUserId(), entry.getGroupName(), entry.getGroupId(), entry.getMode(), entry.getSize());
+ }
+
+
+ for (String f : scanner.getIncludedFiles()) {
+ final File file = new File(baseDir, f);
+ String filename = getFilename(baseDir, file);
+
+ if (!isIncluded(filename)) {
+ continue;
+ }
+
+ if ('/' != File.separatorChar) {
+ 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);
+
+ 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();
+ }
+ }
+ }
+
+ private String getFilename( File root, File file ) {
+
+ final String relativeFilename = file.getAbsolutePath().substring(root.getAbsolutePath().length());
+
+ return Utils.stripLeadingSlash(relativeFilename);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerFile.java b/src/main/java/org/vafer/jdeb/producers/DataProducerFile.java
new file mode 100644
index 0000000..17fb3bd
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/producers/DataProducerFile.java
@@ -0,0 +1,74 @@
+/*
+ * 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 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;
+import org.vafer.jdeb.DataProducer;
+import org.vafer.jdeb.mapping.Mapper;
+
+/**
+ * DataProducer representing a single file
+ * For cross-platform permissions and ownerships you probably want to use a Mapper, too.
+ *
+ * @author Torsten Curdt
+ */
+public final class DataProducerFile extends AbstractDataProducer implements DataProducer {
+
+ private final File file;
+
+ private final String destinationName;
+
+ public DataProducerFile( final File pFile, String pDestinationName, String[] pIncludes, String[] pExcludes, Mapper[] pMapper ) {
+ super(pIncludes, pExcludes, pMapper);
+ file = pFile;
+ destinationName = pDestinationName;
+ }
+
+ public void produce( final DataConsumer pReceiver ) throws IOException {
+ String fileName;
+ if (destinationName != null && destinationName.trim().length() > 0) {
+ fileName = destinationName.trim();
+ } else {
+ 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);
+
+ 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();
+ }
+
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerFileSet.java b/src/main/java/org/vafer/jdeb/producers/DataProducerFileSet.java
new file mode 100644
index 0000000..b4eaf4d
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/producers/DataProducerFileSet.java
@@ -0,0 +1,87 @@
+/*
+ * 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 java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.taskdefs.Tar;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.tar.TarEntry;
+import org.vafer.jdeb.DataConsumer;
+import org.vafer.jdeb.DataProducer;
+
+/**
+ * DataProducer providing data from an Ant fileset. TarFileSets are also
+ * supported with their permissions.
+ *
+ * @author Emmanuel Bourg
+ */
+public final class DataProducerFileSet implements DataProducer {
+
+ private final FileSet fileset;
+
+ public DataProducerFileSet( final FileSet fileset ) {
+ this.fileset = fileset;
+ }
+
+ public void produce( final DataConsumer pReceiver ) throws IOException {
+ String user = "root";
+ int uid = 0;
+ String group = "root";
+ int gid = 0;
+ int filemode = TarEntry.DEFAULT_FILE_MODE;
+ int dirmode = TarEntry.DEFAULT_DIR_MODE;
+ String prefix = "";
+
+ if (fileset instanceof Tar.TarFileSet) {
+ Tar.TarFileSet tarfileset = (Tar.TarFileSet) fileset;
+ user = tarfileset.getUserName();
+ uid = tarfileset.getUid();
+ group = tarfileset.getGroup();
+ gid = tarfileset.getGid();
+ filemode = tarfileset.getMode();
+ dirmode = tarfileset.getDirMode(tarfileset.getProject());
+ prefix = tarfileset.getPrefix(tarfileset.getProject());
+ }
+
+ final DirectoryScanner scanner = fileset.getDirectoryScanner(fileset.getProject());
+ scanner.scan();
+
+ final File basedir = scanner.getBasedir();
+
+ for (String directory : scanner.getIncludedDirectories()) {
+ String name = directory.replace('\\', '/');
+
+ pReceiver.onEachDir(prefix + "/" + name, null, user, uid, group, gid, dirmode, 0);
+ }
+
+ for (String filename : scanner.getIncludedFiles()) {
+ final String name = filename.replace('\\', '/');
+ final File file = new File(basedir, name);
+
+ final InputStream inputStream = new FileInputStream(file);
+ try {
+ pReceiver.onEachFile(inputStream, prefix + "/" + name, null, user, uid, group, gid, filemode, file.length());
+ } finally {
+ inputStream.close();
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerLink.java b/src/main/java/org/vafer/jdeb/producers/DataProducerLink.java
new file mode 100644
index 0000000..69c851f
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/producers/DataProducerLink.java
@@ -0,0 +1,60 @@
+/*
+ * 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 java.io.IOException;
+
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.vafer.jdeb.DataConsumer;
+import org.vafer.jdeb.DataProducer;
+import org.vafer.jdeb.mapping.Mapper;
+
+/**
+ * DataProducer representing a single file
+ * For cross-platform permissions and ownerships you probably want to use a Mapper, too.
+ *
+ * @author Thomas Mortagne
+ */
+public final class DataProducerLink extends AbstractDataProducer implements DataProducer {
+
+ private final String path;
+ private final String linkName;
+ private final boolean symlink;
+
+ public DataProducerLink(final String path, final String linkName, final boolean symlink, String[] pIncludes, String[] pExcludes, Mapper[] pMapper) {
+ super(pIncludes, pExcludes, pMapper);
+ this.path = path;
+ this.symlink = symlink;
+ this.linkName = linkName;
+ }
+
+ @Override
+ 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.setMode(TarArchiveEntry.DEFAULT_FILE_MODE);
+
+ entry = map(entry);
+
+ pReceiver.onEachLink(path, linkName, symlink, entry.getUserName(), entry.getUserId(), entry.getGroupName(), entry.getGroupId(), entry.getMode());
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/producers/DataProducerPathTemplate.java b/src/main/java/org/vafer/jdeb/producers/DataProducerPathTemplate.java
new file mode 100644
index 0000000..bd6cfd0
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/producers/DataProducerPathTemplate.java
@@ -0,0 +1,51 @@
+/*
+ * 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 java.io.IOException;
+
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.vafer.jdeb.DataConsumer;
+import org.vafer.jdeb.DataProducer;
+import org.vafer.jdeb.mapping.Mapper;
+
+public class DataProducerPathTemplate extends AbstractDataProducer implements DataProducer {
+
+ private final String[] literalPaths;
+
+ public DataProducerPathTemplate( String[] pLiteralPaths, String[] pIncludes, String[] pExcludes, Mapper[] pMapper ) {
+ super(pIncludes, pExcludes, pMapper);
+ literalPaths = pLiteralPaths;
+ }
+
+ 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);
+
+ entry = map(entry);
+
+ entry.setSize(0);
+
+ pReceiver.onEachDir(entry.getName(), entry.getLinkName(), entry.getUserName(), entry.getUserId(), entry.getGroupName(), entry.getGroupId(), entry.getMode(), entry.getSize());
+ }
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/signing/PGPSigner.java b/src/main/java/org/vafer/jdeb/signing/PGPSigner.java
new file mode 100644
index 0000000..b2af9e5
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/signing/PGPSigner.java
@@ -0,0 +1,152 @@
+/*
+ * 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.signing;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.security.GeneralSecurityException;
+import java.util.Iterator;
+
+import org.bouncycastle.bcpg.ArmoredOutputStream;
+import org.bouncycastle.bcpg.BCPGOutputStream;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.PGPSecretKeyRing;
+import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
+import org.bouncycastle.openpgp.PGPSignature;
+import org.bouncycastle.openpgp.PGPSignatureGenerator;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
+import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
+import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
+
+/**
+ * Signing with OpenPGP.
+ *
+ * @author Torsten Curdt
+ * @author Emmanuel Bourg
+ */
+public class PGPSigner {
+
+ private static final byte[] EOL = "\r\n".getBytes(Charset.forName("UTF-8"));
+
+ private PGPPrivateKey privateKey;
+
+ public PGPSigner(InputStream keyring, String keyId, String passphrase) throws IOException, PGPException {
+ PGPSecretKey secretKey = getSecretKey(keyring, keyId);
+ privateKey = secretKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(passphrase.toCharArray()));
+ }
+
+ /**
+ * Creates a clear sign signature over the input data. (Not detached)
+ *
+ * @param input the content to be signed
+ * @param output the output destination of the signature
+ */
+ public void clearSign(String input, OutputStream output) throws IOException, PGPException, GeneralSecurityException {
+ clearSign(new ByteArrayInputStream(input.getBytes("UTF-8")), output);
+ }
+
+ /**
+ * Creates a clear sign signature over the input data. (Not detached)
+ *
+ * @param input the content to be signed
+ * @param output the output destination of the signature
+ */
+ public void clearSign(InputStream input, OutputStream output) throws IOException, PGPException, GeneralSecurityException {
+ int digest = PGPUtil.SHA1;
+
+ PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(privateKey.getPublicKeyPacket().getAlgorithm(), digest));
+ signatureGenerator.init(PGPSignature.CANONICAL_TEXT_DOCUMENT, privateKey);
+
+ ArmoredOutputStream armoredOutput = new ArmoredOutputStream(output);
+ armoredOutput.beginClearText(digest);
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(input));
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ // trailing spaces must be removed for signature calculation (see http://tools.ietf.org/html/rfc4880#section-7.1)
+ byte[] data = trim(line).getBytes("UTF-8");
+
+ armoredOutput.write(data);
+ armoredOutput.write(EOL);
+
+ signatureGenerator.update(data);
+ signatureGenerator.update(EOL);
+ }
+
+ armoredOutput.endClearText();
+
+ PGPSignature signature = signatureGenerator.generate();
+ signature.encode(new BCPGOutputStream(armoredOutput));
+
+ armoredOutput.close();
+ }
+
+ /**
+ * Returns the secret key matching the specified identifier.
+ *
+ * @param input the input stream containing the keyring collection
+ * @param keyId the 4 bytes identifier of the key
+ */
+ private PGPSecretKey getSecretKey(InputStream input, String keyId) throws IOException, PGPException {
+ PGPSecretKeyRingCollection keyrings = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(input));
+
+ Iterator rIt = keyrings.getKeyRings();
+
+ while (rIt.hasNext()) {
+ PGPSecretKeyRing kRing = (PGPSecretKeyRing) rIt.next();
+ Iterator kIt = kRing.getSecretKeys();
+
+ while (kIt.hasNext()) {
+ PGPSecretKey key = (PGPSecretKey) kIt.next();
+
+ if (key.isSigningKey() && Long.toHexString(key.getKeyID() & 0xFFFFFFFFL).equals(keyId.toLowerCase())) {
+ return key;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Trim the trailing spaces.
+ *
+ * @param line
+ */
+ private String trim(String line) {
+ char[] chars = line.toCharArray();
+ int len = chars.length;
+
+ while (len > 0) {
+ if (!Character.isWhitespace(chars[len - 1])) {
+ break;
+ }
+ len--;
+ }
+
+ return line.substring(0, len);
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/utils/FilteredFile.java b/src/main/java/org/vafer/jdeb/utils/FilteredFile.java
new file mode 100644
index 0000000..c6f2beb
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/utils/FilteredFile.java
@@ -0,0 +1,70 @@
+/*
+ * 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.utils;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FilteredFile {
+
+ private static String openToken = "[[";
+ private static String closeToken = "]]";
+ private List<String> lines = new ArrayList<String>();
+
+ public FilteredFile(InputStream in, VariableResolver resolver) throws IOException {
+ parse(in, resolver);
+ }
+
+ public static void setOpenToken(String token) {
+ openToken = token;
+ }
+
+ public static void setCloseToken(String token) {
+ closeToken = token;
+ }
+
+ private void parse(InputStream in, VariableResolver resolver) throws IOException {
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new InputStreamReader(in));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (resolver != null) {
+ lines.add(Utils.replaceVariables(resolver, line, openToken, closeToken));
+ } else {
+ lines.add(line);
+ }
+ }
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ for (String line : lines) {
+ builder.append(line).append('\n');
+ }
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/utils/InformationInputStream.java b/src/main/java/org/vafer/jdeb/utils/InformationInputStream.java
new file mode 100644
index 0000000..7907176
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/utils/InformationInputStream.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.utils;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+public final class InformationInputStream extends FilterInputStream {
+
+ private long i;
+ private long ascii;
+ private long nonascii;
+ private long cr;
+ private long lf;
+ private long zero;
+
+ private final Map<BOM, Integer> bomPositions = new HashMap<BOM, Integer>();
+ private final Map<Shell, Integer> shellPositions = new HashMap<Shell, Integer>();
+
+ /**
+ * Byte Order Marks
+ */
+ private enum BOM {
+ NONE(null),
+ UTF8("UTF-8", 0xEF, 0xBB, 0xBF),
+ UTF16LE("UTF-16LE", 0xFF, 0xFE),
+ UTF16BE("UTF-16BE", 0xFE, 0xFF);
+
+ int[] sequence;
+ String encoding;
+
+ private BOM( String encoding, int... sequence ) {
+ this.encoding = encoding;
+ this.sequence = sequence;
+ }
+ }
+
+ /**
+ * Shebang for shell scripts in various encodings.
+ */
+ private enum Shell {
+ NONE,
+ ASCII(0x23, 0x21),
+ UTF16BE(0x00, 0x23, 0x00, 0x21),
+ UTF16LE(0x23, 0x00, 0x21, 0x00);
+
+ int[] header;
+
+ private Shell( int... header ) {
+ this.header = header;
+ }
+ }
+
+ private BOM bom = BOM.NONE;
+ private Shell shell = Shell.NONE;
+
+ public InformationInputStream( InputStream in ) {
+ super(in);
+ }
+
+ public boolean hasBom() {
+ return bom != BOM.NONE;
+ }
+
+ public boolean isShell() {
+ return shell != Shell.NONE;
+ }
+
+ public boolean hasUnixLineEndings() {
+ return cr == 0;
+ }
+
+ public String getEncoding() {
+ String encoding = bom.encoding;
+
+ if (encoding == null) {
+ // guess the encoding from the shebang
+ if (shell == Shell.UTF16BE) {
+ encoding = BOM.UTF16BE.encoding;
+ } else if (shell == Shell.UTF16LE) {
+ encoding = BOM.UTF16LE.encoding;
+ }
+ }
+
+ return encoding;
+ }
+
+ private void add( int c ) {
+ if (i < 10) {
+ if (shell == Shell.NONE) {
+ for (Shell shell : Shell.values()) {
+ int position = shellPositions.containsKey(shell) ? shellPositions.get(shell) : 0;
+ if (position < shell.header.length) {
+ if (c == shell.header[position]) {
+ shellPositions.put(shell, position + 1);
+ } else {
+ shellPositions.put(shell, 0);
+ }
+ } else {
+ this.shell = shell;
+ }
+ }
+ }
+
+ if (bom == BOM.NONE) {
+ for (BOM bom : BOM.values()) {
+ int position = bomPositions.containsKey(bom) ? bomPositions.get(bom) : 0;
+ if (position < bom.sequence.length) {
+ if (c == bom.sequence[position] && position == i) {
+ bomPositions.put(bom, position + 1);
+ } else {
+ bomPositions.put(bom, 0);
+ }
+ } else {
+ this.bom = bom;
+ }
+ }
+ }
+ }
+
+ i++;
+
+ if (c == '\n') {
+ lf++;
+ return;
+ }
+ if (c == '\r') {
+ cr++;
+ return;
+ }
+ if (c >= ' ' && c <= '~') {
+ ascii++;
+ return;
+ }
+ if (c == 0) {
+ zero++;
+ return;
+ }
+ nonascii++;
+ }
+
+ public int read() throws IOException {
+ int b = super.read();
+ if (b != -1) {
+ add(b & 0xFF);
+ }
+ return b;
+ }
+
+ public int read( byte[] b, int off, int len ) throws IOException {
+ int length = super.read(b, off, len);
+ for (int i = 0; i < length; i++) {
+ add(b[off + i] & 0xFF);
+ }
+ return length;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("{");
+ sb.append("total=").append(i);
+ sb.append(",noascii=").append(nonascii);
+ sb.append(",ascii=").append(ascii);
+ sb.append(",cr=").append(cr);
+ sb.append(",lf=").append(lf);
+ sb.append(",zero=").append(zero);
+ sb.append("}");
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/utils/InformationOutputStream.java b/src/main/java/org/vafer/jdeb/utils/InformationOutputStream.java
new file mode 100644
index 0000000..63f11c4
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/utils/InformationOutputStream.java
@@ -0,0 +1,58 @@
+/*
+ * 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.utils;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+
+/**
+ * Convenience class to provide digest info and length of a stream.
+ *
+ * ATTENTION: don't use outside of jdeb
+ *
+ * @author Torsten Curdt <tcurdt at vafer.org>
+ */
+public class InformationOutputStream extends DigestOutputStream {
+
+ private final MessageDigest digest;
+ private long size;
+
+ public InformationOutputStream( OutputStream pStream, MessageDigest pDigest ) {
+ super(pStream, pDigest);
+ digest = pDigest;
+ size = 0;
+ }
+
+ public String getHexDigest() {
+ return Utils.toHex(digest.digest());
+ }
+
+ public void write( byte[] b, int off, int len ) throws IOException {
+ super.write(b, off, len);
+ size += len;
+ }
+
+ public void write( int b ) throws IOException {
+ super.write(b);
+ size++;
+ }
+
+ public long getSize() {
+ return size;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/vafer/jdeb/utils/MapVariableResolver.java b/src/main/java/org/vafer/jdeb/utils/MapVariableResolver.java
new file mode 100644
index 0000000..de50343
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/utils/MapVariableResolver.java
@@ -0,0 +1,39 @@
+/*
+ * 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.utils;
+
+import java.util.Map;
+
+/**
+ * Resolve variables based on a Map.
+ *
+ * ATTENTION: don't use outside of jdeb
+ *
+ * @author Torsten Curdt <tcurdt at vafer.org>
+ */
+public final class MapVariableResolver implements VariableResolver {
+
+ private final Map<String, String> map;
+
+ public MapVariableResolver( Map<String, String> map ) {
+ this.map = map;
+ }
+
+ public String get( String key ) {
+ return map.get(key);
+ }
+
+}
diff --git a/src/main/java/org/vafer/jdeb/utils/Utils.java b/src/main/java/org/vafer/jdeb/utils/Utils.java
new file mode 100644
index 0000000..b078f22
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/utils/Utils.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.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.Date;
+import java.text.SimpleDateFormat;
+
+import org.apache.tools.ant.filters.FixCrLfFilter;
+import org.apache.tools.ant.util.ReaderInputStream;
+
+/**
+ * Simple utils functions.
+ *
+ * ATTENTION: don't use outside of jdeb
+ *
+ * @author Torsten Curdt <tcurdt at vafer.org>
+ */
+public final class Utils {
+
+ public static int copy( final InputStream pInput, final OutputStream pOutput ) throws IOException {
+ final byte[] buffer = new byte[2048];
+ int count = 0;
+ int n;
+ while (-1 != (n = pInput.read(buffer))) {
+ pOutput.write(buffer, 0, n);
+ count += n;
+ }
+ return count;
+ }
+
+ public static String toHex( final byte[] bytes ) {
+ final StringBuilder sb = new StringBuilder();
+
+ for (byte b : bytes) {
+ sb.append(Integer.toHexString((b >> 4) & 0x0f));
+ sb.append(Integer.toHexString(b & 0x0f));
+ }
+
+ return sb.toString();
+ }
+
+ public static String stripPath( final int p, final String s ) {
+
+ if (p <= 0) {
+ return s;
+ }
+
+ int x = 0;
+ for (int i = 0; i < p; i++) {
+ x = s.indexOf('/', x + 1);
+ if (x < 0) {
+ return s;
+ }
+ }
+
+ return s.substring(x + 1);
+ }
+
+ public static String stripLeadingSlash( final String s ) {
+ if (s == null) {
+ return s;
+ }
+ if (s.length() == 0) {
+ return s;
+ }
+ if (s.charAt(0) == '/' || s.charAt(0) == '\\') {
+ return s.substring(1);
+ }
+ return s;
+ }
+
+
+ /**
+ * Substitute the variables in the given expression with the
+ * values from the resolver
+ *
+ * @param pResolver
+ * @param pExpression
+ */
+ public static String replaceVariables( final VariableResolver pResolver, final String pExpression, final String pOpen, final String pClose ) {
+ final char[] open = pOpen.toCharArray();
+ final char[] close = pClose.toCharArray();
+
+ final StringBuilder out = new StringBuilder();
+ StringBuilder sb = new StringBuilder();
+ char[] watch = open;
+ int w = 0;
+ for (char c : pExpression.toCharArray()) {
+ if (c == watch[w]) {
+ w++;
+ if (watch.length == w) {
+ // found the full token to watch for
+
+ if (watch == open) {
+ // found open
+ out.append(sb);
+ sb = new StringBuilder();
+ // search for close
+ watch = close;
+ } else {
+ // found close
+ final String variable = pResolver.get(sb.toString());
+ if (variable != null) {
+ out.append(variable);
+ } else {
+ out.append(pOpen);
+ out.append(sb);
+ out.append(pClose);
+ }
+ sb = new StringBuilder();
+ // search for open
+ watch = open;
+ }
+ w = 0;
+ }
+ } else {
+
+ if (w > 0) {
+ sb.append(watch, 0, w);
+ }
+
+ sb.append(c);
+
+ w = 0;
+ }
+ }
+
+ if (watch == close) {
+ out.append(open);
+ }
+ out.append(sb);
+
+ return out.toString();
+ }
+
+ /**
+ * Replaces new line delimiters in the input stream with the Unix line feed.
+ *
+ * @param input
+ */
+ public static byte[] toUnixLineEndings( InputStream input ) throws IOException {
+ String encoding = "ISO-8859-1";
+ FixCrLfFilter filter = new FixCrLfFilter(new InputStreamReader(input, encoding));
+ filter.setEol(FixCrLfFilter.CrLf.newInstance("unix"));
+
+ ByteArrayOutputStream filteredFile = new ByteArrayOutputStream();
+ Utils.copy(new ReaderInputStream(filter, encoding), filteredFile);
+
+ return filteredFile.toByteArray();
+ }
+
+ /**
+ * convert to debian version format
+ */
+ public static String convertToDebianVersion( String version, Date timestamp ) {
+ version = version.replace('-', '+');
+ if (version.endsWith("+SNAPSHOT")) {
+ version = version.substring(0, version.length() - "+SNAPSHOT".length());
+ version += "~";
+
+ if (timestamp != null) {
+ version += new SimpleDateFormat("yyyyMMddHHmmss").format(timestamp);
+ } else {
+ version += "SNAPSHOT";
+ }
+ }
+ return version;
+ }
+}
diff --git a/src/main/java/org/vafer/jdeb/utils/VariableResolver.java b/src/main/java/org/vafer/jdeb/utils/VariableResolver.java
new file mode 100644
index 0000000..9e71ce8
--- /dev/null
+++ b/src/main/java/org/vafer/jdeb/utils/VariableResolver.java
@@ -0,0 +1,29 @@
+/*
+ * 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.utils;
+
+/**
+ * Interface for resolving variables.
+ * See Utils.replaceVariables()
+ *
+ * ATTENTION: don't use outside of jdeb
+ *
+ * @author Torsten Curdt <tcurdt at vafer.org>
+ */
+
+public interface VariableResolver {
+ public String get( final String pKey );
+}
diff --git a/src/main/resources/org/vafer/jdeb/ant/antlib.xml b/src/main/resources/org/vafer/jdeb/ant/antlib.xml
new file mode 100644
index 0000000..210d6a0
--- /dev/null
+++ b/src/main/resources/org/vafer/jdeb/ant/antlib.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<antlib>
+ <taskdef name="jdeb" classname="org.vafer.jdeb.ant.DebAntTask" />
+</antlib>
diff --git a/src/test/java/org/vafer/jdeb/ArchiveVisitor.java b/src/test/java/org/vafer/jdeb/ArchiveVisitor.java
new file mode 100644
index 0000000..5c3ebc1
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/ArchiveVisitor.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2013 Emmanuel Bourg
+ *
+ * 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.IOException;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+
+/**
+ * Callback used for inspecting an archive.
+ *
+ * @author Emmanuel Bourg
+ */
+public interface ArchiveVisitor<E extends ArchiveEntry> {
+
+ void visit(E entry, byte[] content) throws IOException;
+}
diff --git a/src/test/java/org/vafer/jdeb/ArchiveWalker.java b/src/test/java/org/vafer/jdeb/ArchiveWalker.java
new file mode 100644
index 0000000..4fa02ee
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/ArchiveWalker.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 Emmanuel Bourg
+ *
+ * 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.IOException;
+import java.io.InputStream;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.zip.GZIPInputStream;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.archivers.ar.ArArchiveEntry;
+import org.apache.commons.compress.archivers.ar.ArArchiveInputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
+import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
+
+/**
+ * Support class for inspecting the content of an archive.
+ *
+ * @author Emmanuel Bourg
+ */
+public class ArchiveWalker {
+
+ public static void walk(ArchiveInputStream in, ArchiveVisitor visitor) throws IOException {
+ try {
+ ArchiveEntry entry;
+ while ((entry = in.getNextEntry()) != null) {
+ byte[] content = new byte[(int) entry.getSize()];
+ if (entry.getSize() > 0) {
+ int length = in.read(content);
+ if (length != entry.getSize()) {
+ throw new IOException("Couldn't read entry " + entry.getName() + " : read " + length + ", expected " + entry.getSize());
+ }
+ }
+
+ visitor.visit(entry, content);
+ }
+ } finally {
+ in.close();
+ }
+ }
+
+ public static boolean walkControl(File deb, final ArchiveVisitor<TarArchiveEntry> visitor) throws IOException {
+ return walkEmbedded(deb, "control.tar", visitor, Compression.GZIP);
+ }
+
+ public static boolean walkData(File deb, final ArchiveVisitor<TarArchiveEntry> visitor, final Compression compression) throws IOException {
+ return walkEmbedded(deb, "data.tar", visitor, compression);
+ }
+
+ public static boolean walkEmbedded(File deb, final String name, final ArchiveVisitor<TarArchiveEntry> visitor, final Compression compression) throws IOException {
+ final AtomicBoolean found = new AtomicBoolean(false);
+ ArArchiveInputStream in = new ArArchiveInputStream(new FileInputStream(deb));
+ ArchiveWalker.walk(in, new ArchiveVisitor<ArArchiveEntry>() {
+ public void visit(ArArchiveEntry entry, byte[] content) throws IOException {
+ if (entry.getName().equals(name + compression.getExtension())) {
+ InputStream in = new ByteArrayInputStream(content);
+ if (compression == Compression.GZIP) {
+ in = new GZIPInputStream(in);
+ } else if (compression == Compression.XZ) {
+ in = new XZCompressorInputStream(in);
+ } else if (compression == Compression.BZIP2) {
+ in = new BZip2CompressorInputStream(in);
+ }
+
+ ArchiveWalker.walk(new TarArchiveInputStream(in), new ArchiveVisitor<TarArchiveEntry>() {
+ public void visit(TarArchiveEntry entry, byte[] content) throws IOException {
+ found.set(true);
+ visitor.visit(entry, content);
+ }
+ });
+ }
+ }
+ });
+ return found.get();
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/DataBuilderTestCase.java b/src/test/java/org/vafer/jdeb/DataBuilderTestCase.java
new file mode 100644
index 0000000..5a0bc17
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/DataBuilderTestCase.java
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+import org.vafer.jdeb.producers.DataProducerFile;
+import org.vafer.jdeb.producers.DataProducerFileSet;
+
+public class DataBuilderTestCase extends TestCase {
+
+ /**
+ * Checks if the file paths in the md5sums file use only unix file separators
+ * (this test can only fail on Windows)
+ */
+ public void testBuildDataWithFileSet() throws Exception {
+ DataBuilder builder = new DataBuilder(new NullConsole());
+
+ Project project = new Project();
+ project.setCoreLoader(getClass().getClassLoader());
+ project.init();
+
+ FileSet fileset = new FileSet();
+ fileset.setDir(new File(getClass().getResource("deb/data").toURI()));
+ fileset.setIncludes("**/*");
+ fileset.setProject(project);
+
+ StringBuilder md5s = new StringBuilder();
+ builder.buildData(Arrays.asList((DataProducer) new DataProducerFileSet(fileset)), new File("target/data.tar"), md5s, Compression.GZIP);
+
+ assertTrue("empty md5 file", md5s.length() > 0);
+ assertFalse("windows path separator found", md5s.indexOf("\\") != -1);
+ }
+
+ public void testCreateParentDirectories() throws Exception {
+ File archive = new File("target/data.tar");
+ if (archive.exists()) {
+ archive.delete();
+ }
+
+ DataBuilder builder = new DataBuilder(new NullConsole());
+
+ DataProducer producer = new DataProducerFile(new File("pom.xml"), "/usr/share/myapp/pom.xml", null, null, null);
+
+ builder.buildData(Arrays.asList(producer), archive, new StringBuilder(), Compression.NONE);
+
+ int count = 0;
+ TarArchiveInputStream in = null;
+ try {
+ in = new TarArchiveInputStream(new FileInputStream(archive));
+ while (in.getNextTarEntry() != null) {
+ count++;
+ }
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+
+ assertEquals("entries", 4, count);
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/DebMakerTestCase.java b/src/test/java/org/vafer/jdeb/DebMakerTestCase.java
new file mode 100644
index 0000000..7eaf17c
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/DebMakerTestCase.java
@@ -0,0 +1,157 @@
+/*
+ * 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;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.utils.IOUtils;
+import org.apache.commons.io.output.NullOutputStream;
+import org.vafer.jdeb.debian.BinaryPackageControlFile;
+import org.vafer.jdeb.producers.DataProducerArchive;
+import org.vafer.jdeb.producers.DataProducerDirectory;
+import org.vafer.jdeb.producers.DataProducerLink;
+import org.vafer.jdeb.utils.InformationInputStream;
+import org.vafer.jdeb.utils.MapVariableResolver;
+
+public class DebMakerTestCase extends TestCase {
+
+ public void testCreation() throws Exception {
+
+ File control = new File(getClass().getResource("deb/control/control").toURI());
+ File archive1 = new File(getClass().getResource("deb/data.tgz").toURI());
+ File archive2 = new File(getClass().getResource("deb/data.tar.bz2").toURI());
+ File archive3 = new File(getClass().getResource("deb/data.zip").toURI());
+ File directory = new File(getClass().getResource("deb/data").toURI());
+
+ DataProducer[] data = new DataProducer[] {
+ new DataProducerArchive(archive1, null, null, null),
+ new DataProducerArchive(archive2, null, null, null),
+ new DataProducerArchive(archive3, null, null, null),
+ new DataProducerDirectory(directory, null, new String[] { "**/.svn/**" }, null),
+ new DataProducerLink("/link/path-element.ext", "/link/target-element.ext", true, null, null, null)
+ };
+
+ File deb = File.createTempFile("jdeb", ".deb");
+
+ DebMaker maker = new DebMaker(new NullConsole(), Arrays.asList(data));
+ maker.setControl(new File(getClass().getResource("deb/control").toURI()));
+ maker.setDeb(deb);
+
+ BinaryPackageControlFile packageControlFile = maker.createDeb(Compression.GZIP);
+
+ assertTrue(packageControlFile.isValid());
+
+ final Map<String, TarArchiveEntry> filesInDeb = new HashMap<String, TarArchiveEntry>();
+
+ ArchiveWalker.walkData(deb, new ArchiveVisitor<TarArchiveEntry>() {
+ public void visit(TarArchiveEntry entry, byte[] content) throws IOException {
+ filesInDeb.put(entry.getName(), entry);
+ }
+ }, Compression.GZIP);
+
+ assertTrue("testfile wasn't found in the package", filesInDeb.containsKey("./test/testfile"));
+ assertTrue("testfile2 wasn't found in the package", filesInDeb.containsKey("./test/testfile2"));
+ assertTrue("testfile3 wasn't found in the package", filesInDeb.containsKey("./test/testfile3"));
+ assertTrue("testfile4 wasn't found in the package", filesInDeb.containsKey("./test/testfile4"));
+ assertTrue("/link/path-element.ext wasn't found in the package", filesInDeb.containsKey("./link/path-element.ext"));
+ assertEquals("/link/path-element.ext has wrong link target", "/link/target-element.ext", filesInDeb.get("./link/path-element.ext").getLinkName());
+
+ assertTrue("Cannot delete the file " + deb, deb.delete());
+ }
+
+ public void testControlFilesPermissions() throws Exception {
+ File deb = new File("target/test-classes/test-control.deb");
+ if (deb.exists() && !deb.delete()) {
+ fail("Couldn't delete " + deb);
+ }
+
+ Collection<DataProducer> producers = Arrays.asList(new DataProducer[] {new EmptyDataProducer()});
+ DebMaker maker = new DebMaker(new NullConsole(), producers);
+ maker.setDeb(deb);
+ maker.setControl(new File("target/test-classes/org/vafer/jdeb/deb/control"));
+
+ maker.createDeb(Compression.NONE);
+
+ // now reopen the package and check the control files
+ assertTrue("package not build", deb.exists());
+
+ boolean found = ArchiveWalker.walkControl(deb, new ArchiveVisitor<TarArchiveEntry>() {
+ public void visit(TarArchiveEntry entry, byte[] content) throws IOException {
+ assertFalse("directory found in the control archive", entry.isDirectory());
+ assertTrue("prefix", entry.getName().startsWith("./"));
+
+ InformationInputStream infoStream = new InformationInputStream(new ByteArrayInputStream(content));
+ IOUtils.copy(infoStream, NullOutputStream.NULL_OUTPUT_STREAM);
+
+ if (infoStream.isShell()) {
+ assertTrue("Permissions on " + entry.getName() + " should be 755", entry.getMode() == 0755);
+ } else {
+ assertTrue("Permissions on " + entry.getName() + " should be 644", entry.getMode() == 0644);
+ }
+
+ assertTrue(entry.getName() + " doesn't have Unix line endings", infoStream.hasUnixLineEndings());
+
+ assertEquals("user", "root", entry.getUserName());
+ assertEquals("group", "root", entry.getGroupName());
+ }
+ });
+
+ assertTrue("Control files not found in the package", found);
+ }
+
+ public void testControlFilesVariables() throws Exception {
+ File deb = new File("target/test-classes/test-control.deb");
+ if (deb.exists() && !deb.delete()) {
+ fail("Couldn't delete " + deb);
+ }
+
+ Map<String, String> variables = new HashMap<String, String>();
+ variables.put("name", "jdeb");
+ variables.put("version", "1.0");
+
+ Collection<DataProducer> producers = Arrays.asList(new DataProducer[] {new EmptyDataProducer()});
+ DebMaker maker = new DebMaker(new NullConsole(), producers);
+ maker.setDeb(deb);
+ maker.setControl(new File("target/test-classes/org/vafer/jdeb/deb/control"));
+ maker.setResolver(new MapVariableResolver(variables));
+
+ maker.createDeb(Compression.NONE);
+
+ // now reopen the package and check the control files
+ assertTrue("package not build", deb.exists());
+
+ boolean found = ArchiveWalker.walkControl(deb, new ArchiveVisitor<TarArchiveEntry>() {
+ public void visit(TarArchiveEntry entry, byte[] content) throws IOException {
+ if (entry.getName().contains("postinst") || entry.getName().contains("prerm")) {
+ String body = new String(content, "ISO-8859-1");
+ assertFalse("Variables not replaced in the control file " + entry.getName(), body.contains("[[name]] [[version]]"));
+ assertTrue("Expected variables not found in the control file " + entry.getName(), body.contains("jdeb 1.0"));
+ }
+ }
+ });
+
+ assertTrue("Control files not found in the package", found);
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/EmptyDataProducer.java b/src/test/java/org/vafer/jdeb/EmptyDataProducer.java
new file mode 100644
index 0000000..9b38ca6
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/EmptyDataProducer.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+import java.io.IOException;
+
+/**
+ * @author Emmanuel Bourg
+ */
+public class EmptyDataProducer implements DataProducer {
+
+ public void produce(DataConsumer receiver) throws IOException {
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/NullConsole.java b/src/test/java/org/vafer/jdeb/NullConsole.java
new file mode 100644
index 0000000..97a8f85
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/NullConsole.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+public class NullConsole implements Console {
+
+ @Override
+ public void info(String s) {
+ }
+
+ @Override
+ public void warn(String s) {
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/ant/AntSelectorTestCase.java b/src/test/java/org/vafer/jdeb/ant/AntSelectorTestCase.java
new file mode 100644
index 0000000..05beec9
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/ant/AntSelectorTestCase.java
@@ -0,0 +1,30 @@
+/*
+ * 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.ant;
+
+import junit.framework.TestCase;
+import org.apache.tools.ant.types.selectors.SelectorUtils;
+
+public final class AntSelectorTestCase extends TestCase {
+
+ public void testExclusion() throws Exception {
+ assertTrue("should match",
+ SelectorUtils.matchPath("**/bin/**", "/some/bin/stuff"));
+ assertFalse("should not match",
+ SelectorUtils.matchPath("**/bin/**", "/some/stuff"));
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/ant/DebAntTaskTestCase.java b/src/test/java/org/vafer/jdeb/ant/DebAntTaskTestCase.java
new file mode 100644
index 0000000..ee553ca
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/ant/DebAntTaskTestCase.java
@@ -0,0 +1,308 @@
+/*
+ * 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.ant;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import junit.framework.TestCase;
+import org.apache.commons.compress.archivers.ar.ArArchiveEntry;
+import org.apache.commons.compress.archivers.ar.ArArchiveInputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
+import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DefaultLogger;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.tar.TarInputStream;
+import org.vafer.jdeb.ArchiveVisitor;
+import org.vafer.jdeb.ArchiveWalker;
+import org.vafer.jdeb.Compression;
+
+/**
+ * @author Emmanuel Bourg
+ */
+public final class DebAntTaskTestCase extends TestCase {
+
+ private Project project;
+
+ protected void setUp() throws Exception {
+ project = new Project();
+ project.setCoreLoader(getClass().getClassLoader());
+ project.init();
+
+ File buildFile = new File("target/test-classes/testbuild.xml");
+ project.setBaseDir(buildFile.getParentFile());
+
+ final ProjectHelper helper = ProjectHelper.getProjectHelper();
+ helper.parse(project, buildFile);
+
+ // remove the package previously build
+ File deb = new File("target/test.deb");
+ if (deb.exists()) {
+ assertTrue("Unable to remove the test archive", deb.delete());
+ }
+ }
+
+ public void testMissingControl() {
+ try {
+ project.executeTarget("missing-control");
+ fail("No exception thrown");
+ } catch (BuildException e) {
+ // expected
+ }
+ }
+
+ public void testInvalidControl() {
+ try {
+ project.executeTarget("invalid-control");
+ fail("No exception thrown");
+ } catch (BuildException e) {
+ // expected
+ }
+ }
+
+ public void testMissingDestFile() {
+ try {
+ project.executeTarget("missing-destfile");
+ fail("No exception thrown");
+ } catch (BuildException e) {
+ // expected
+ }
+ }
+
+ public void testEmptyPackage() {
+ try {
+ project.executeTarget("empty-package");
+ fail("No exception thrown");
+ } catch (BuildException e) {
+ // expected
+ }
+ }
+
+ public void testPackageWithArchive() {
+ project.executeTarget("with-archive");
+
+ assertTrue("package not build", new File("target/test-classes/test.deb").exists());
+ }
+
+ public void testPackageWithMissingArchive() {
+ try {
+ project.executeTarget("with-missing-archive");
+ fail("No exception thrown");
+ } catch (BuildException e) {
+ // expected
+ }
+ }
+
+ public void testPackageWithDirectory() {
+ project.executeTarget("with-directory");
+
+ assertTrue("package not build", new File("target/test-classes/test.deb").exists());
+ }
+
+ public void testPackageWithMissingDirectory() {
+ try {
+ project.executeTarget("with-missing-directory");
+ fail("No exception thrown");
+ } catch (BuildException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Redirects the Ant output to the specified stream.
+ */
+ private void redirectOutput( OutputStream out ) {
+ DefaultLogger logger = new DefaultLogger();
+ logger.setOutputPrintStream(new PrintStream(out));
+ logger.setMessageOutputLevel(Project.MSG_INFO);
+ project.addBuildListener(logger);
+ }
+
+ public void testVerboseEnabled() {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ redirectOutput(out);
+
+ project.executeTarget("verbose-enabled");
+
+ assertTrue(out.toString().contains("Total size"));
+ }
+
+ public void testVerboseDisabled() {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ redirectOutput(out);
+
+ project.executeTarget("verbose-disabled");
+
+ assertTrue(!out.toString().contains("Total size"));
+ }
+
+ public void testMissingDataType() {
+ try {
+ project.executeTarget("missing-data-type");
+ fail("No exception thrown");
+ } catch (BuildException e) {
+ // expected
+ }
+ }
+
+ public void testUnknownDataType() {
+ try {
+ project.executeTarget("unknown-data-type");
+ fail("No exception thrown");
+ } catch (BuildException e) {
+ // expected
+ }
+ }
+
+ public void testFileSet() {
+ project.executeTarget("fileset");
+
+ assertTrue("package not build", new File("target/test-classes/test.deb").exists());
+ }
+
+ public void testTarFileSet() throws Exception {
+ project.executeTarget("tarfileset");
+
+ File deb = new File("target/test-classes/test.deb");
+ assertTrue("package not build", deb.exists());
+
+ ArchiveWalker.walkData(deb, new ArchiveVisitor<TarArchiveEntry>() {
+ public void visit(TarArchiveEntry entry, byte[] content) throws IOException {
+ assertTrue("prefix: " + entry.getName(), entry.getName().startsWith("./foo/"));
+ if (entry.isDirectory()) {
+ assertEquals("directory mode (" + entry.getName() + ")", 040700, entry.getMode());
+ } else {
+ assertEquals("file mode (" + entry.getName() + ")", 0100600, entry.getMode());
+ }
+ assertEquals("user", "ebourg", entry.getUserName());
+ assertEquals("group", "ebourg", entry.getGroupName());
+ }
+ }, Compression.GZIP);
+ }
+
+ public void testLink() throws Exception {
+ project.executeTarget("link");
+
+ File deb = new File("target/test-classes/test.deb");
+ assertTrue("package not build", deb.exists());
+
+ final AtomicBoolean linkFound = new AtomicBoolean(false);
+
+ ArchiveWalker.walkData(deb, new ArchiveVisitor<TarArchiveEntry>() {
+ public void visit(TarArchiveEntry entry, byte[] content) throws IOException {
+ if (entry.isSymbolicLink()) {
+ linkFound.set(true);
+ assertEquals("link mode (" + entry.getName() + ")", 0120755, entry.getMode());
+ }
+ assertEquals("user", "ebourg", entry.getUserName());
+ assertEquals("group", "ebourg", entry.getGroupName());
+ }
+ }, Compression.GZIP);
+
+ assertTrue("Link not found", linkFound.get());
+ }
+
+ public void testUnkownCompression() throws Exception {
+ try {
+ project.executeTarget("unknown-compression");
+ fail("No exception thrown");
+ } catch (BuildException e) {
+ // expected
+ }
+ }
+
+ public void testBZip2Compression() throws Exception {
+ project.executeTarget("bzip2-compression");
+
+ File deb = new File("target/test-classes/test.deb");
+ assertTrue("package not build", deb.exists());
+
+ final AtomicBoolean found = new AtomicBoolean(false);
+
+ ArArchiveInputStream in = new ArArchiveInputStream(new FileInputStream(deb));
+ ArchiveWalker.walk(in, new ArchiveVisitor<ArArchiveEntry>() {
+ public void visit(ArArchiveEntry entry, byte[] content) throws IOException {
+ if (entry.getName().equals("data.tar.bz2")) {
+ found.set(true);
+
+ assertEquals("header 0", (byte) 'B', content[0]);
+ assertEquals("header 1", (byte) 'Z', content[1]);
+
+ TarInputStream tar = new TarInputStream(new BZip2CompressorInputStream(new ByteArrayInputStream(content)));
+ while ((tar.getNextEntry()) != null) ;
+ tar.close();
+ }
+ }
+ });
+
+ assertTrue("bz2 file not found", found.get());
+ }
+
+ public void testXZCompression() throws Exception {
+ project.executeTarget("xz-compression");
+
+ File deb = new File("target/test-classes/test.deb");
+ assertTrue("package not build", deb.exists());
+
+ final AtomicBoolean found = new AtomicBoolean(false);
+
+ ArArchiveInputStream in = new ArArchiveInputStream(new FileInputStream(deb));
+ ArchiveWalker.walk(in, new ArchiveVisitor<ArArchiveEntry>() {
+ public void visit(ArArchiveEntry entry, byte[] content) throws IOException {
+ if (entry.getName().equals("data.tar.xz")) {
+ found.set(true);
+
+ assertEquals("header 0", (byte) 0xFD, content[0]);
+ assertEquals("header 1", (byte) '7', content[1]);
+ assertEquals("header 2", (byte) 'z', content[2]);
+ assertEquals("header 3", (byte) 'X', content[3]);
+ assertEquals("header 4", (byte) 'Z', content[4]);
+ assertEquals("header 5", (byte) '\0', content[5]);
+
+ TarInputStream tar = new TarInputStream(new XZCompressorInputStream(new ByteArrayInputStream(content)));
+ while ((tar.getNextEntry()) != null) ;
+ tar.close();
+ }
+ }
+ });
+
+ assertTrue("xz file not found", found.get());
+ }
+
+ public void testNoCompression() throws Exception {
+ project.executeTarget("no-compression");
+
+ File deb = new File("target/test-classes/test.deb");
+ assertTrue("package not build", deb.exists());
+
+ boolean found = ArchiveWalker.walkData(deb, new ArchiveVisitor<TarArchiveEntry>() {
+ public void visit(TarArchiveEntry entry, byte[] content) throws IOException {
+ }
+ }, Compression.NONE);
+
+ assertTrue("tar file not found", found);
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/changes/TextfileChangesProviderTestCase.java b/src/test/java/org/vafer/jdeb/changes/TextfileChangesProviderTestCase.java
new file mode 100644
index 0000000..e36a3d9
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/changes/TextfileChangesProviderTestCase.java
@@ -0,0 +1,79 @@
+/*
+ * 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.changes;
+
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+import org.vafer.jdeb.debian.BinaryPackageControlFile;
+
+public final class TextfileChangesProviderTestCase extends TestCase {
+
+ public void testParsing() throws Exception {
+
+ final String input =
+ " * change1\n" +
+ " * change2\n" +
+ "release date=14:00 13.01.2007, version=12324, urgency=low, by=tcurdt at joost.com\n" +
+ " * change1\n" +
+ " * change2\n" +
+ "release date=12:00 10.01.2007, version=10324, urgency=low, by=tcurdt at joost.com\n" +
+ " * change1\n" +
+ " * change2\n";
+
+ BinaryPackageControlFile packageControlFile = new BinaryPackageControlFile();
+ packageControlFile.set("Package", "package");
+ packageControlFile.set("Version", "version");
+ packageControlFile.set("Distribution", "distribution");
+ packageControlFile.set("Date", "Mon, 20 Aug 2007 15:25:57 +0200");
+
+ final TextfileChangesProvider provider = new TextfileChangesProvider(new ByteArrayInputStream(input.getBytes("UTF-8")), packageControlFile);
+ final ChangeSet[] changeSets = provider.getChangesSets();
+
+ assertNotNull(changeSets);
+ assertEquals(3, changeSets.length);
+ }
+
+ public void testDistributionFromChangesProvider() throws Exception {
+
+ final String input =
+ "release distribution=production\n" +
+ " * change1\n" +
+ " * change2\n" +
+ "release distribution=staging, date=14:00 13.01.2007, version=12324, urgency=low, by=tcurdt at joost.com\n" +
+ " * change1\n" +
+ " * change2\n" +
+ "release distribution=development, date=12:00 10.01.2007, version=10324, urgency=low, by=tcurdt at joost.com\n" +
+ " * change1\n" +
+ " * change2\n";
+
+ BinaryPackageControlFile packageControlFile = new BinaryPackageControlFile();
+ packageControlFile.set("Package", "package");
+ packageControlFile.set("Version", "version");
+ packageControlFile.set("Date", "Mon, 20 Aug 2007 15:25:57 +0200");
+
+ final TextfileChangesProvider provider = new TextfileChangesProvider(new ByteArrayInputStream(input.getBytes("UTF-8")), packageControlFile);
+ final ChangeSet[] changeSets = provider.getChangesSets();
+
+ assertNotNull(changeSets);
+ assertEquals(3, changeSets.length);
+
+ assertEquals("production", changeSets[0].getDistribution());
+ assertEquals("staging", changeSets[1].getDistribution());
+ assertEquals("development", changeSets[2].getDistribution());
+ }
+
+}
diff --git a/src/test/java/org/vafer/jdeb/debian/ChangesFileTestCase.java b/src/test/java/org/vafer/jdeb/debian/ChangesFileTestCase.java
new file mode 100644
index 0000000..c8e68aa
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/debian/ChangesFileTestCase.java
@@ -0,0 +1,36 @@
+/*
+ * 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.debian;
+
+import junit.framework.TestCase;
+import org.vafer.jdeb.changes.ChangeSet;
+
+public final class ChangesFileTestCase extends TestCase {
+
+ public void testToString() throws Exception {
+ BinaryPackageControlFile packageControlFile = new BinaryPackageControlFile();
+ packageControlFile.set("Package", "test-package");
+ packageControlFile.set("Description", "This is\na description\non several lines");
+ packageControlFile.set("Version", "1.0");
+
+ ChangesFile changes = new ChangesFile();
+ changes.setChanges(new ChangeSet[0]);
+ changes.initialize(packageControlFile);
+
+ assertEquals("1.0", changes.get("Version"));
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/debian/ControlFieldTestCase.java b/src/test/java/org/vafer/jdeb/debian/ControlFieldTestCase.java
new file mode 100644
index 0000000..35ce579
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/debian/ControlFieldTestCase.java
@@ -0,0 +1,44 @@
+/*
+ * 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.debian;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Emmanuel Bourg
+ * @version $Revision$, $Date$
+ */
+public class ControlFieldTestCase extends TestCase {
+
+ public void testFormatSimpleValue() {
+ ControlField field = new ControlField("Field-Name");
+
+ assertEquals("Field-Name: value\n", field.format("value"));
+ }
+
+ public void testFormatMultilineValue1() {
+ ControlField field = new ControlField("Field-Name", false, ControlField.Type.MULTILINE);
+
+ assertEquals("Field-Name: value1\n value2\n .\n value3\n", field.format("value1\nvalue2\n\nvalue3"));
+ }
+
+ public void testFormatMultilineValue2() {
+ ControlField field = new ControlField("Field-Name", false, ControlField.Type.MULTILINE, true);
+
+ assertEquals("Field-Name:\n value1\n value2\n .\n value3\n", field.format("value1\nvalue2\n\nvalue3"));
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/debian/PackageControlFileTestCase.java b/src/test/java/org/vafer/jdeb/debian/PackageControlFileTestCase.java
new file mode 100644
index 0000000..7c18587
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/debian/PackageControlFileTestCase.java
@@ -0,0 +1,91 @@
+/*
+ * 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.debian;
+
+import java.io.FileInputStream;
+import java.text.ParseException;
+
+import junit.framework.TestCase;
+
+public final class PackageControlFileTestCase extends TestCase {
+
+ public void testParse() throws Exception {
+ String input =
+ "Key1: Value1\n" +
+ "Key2: Value2\n" +
+ " Value2.1\n" +
+ " Value2.2\n" +
+ "Key3: Value3\n";
+
+ BinaryPackageControlFile d = new BinaryPackageControlFile(input);
+ assertFalse(d.isValid());
+
+ assertEquals("key 1", "Value1", d.get("Key1"));
+ assertEquals("key 2", "Value2\nValue2.1\nValue2.2", d.get("Key2"));
+ assertEquals("key 3", "Value3", d.get("Key3"));
+ }
+
+ public void testToString() throws Exception {
+ BinaryPackageControlFile packageControlFile = new BinaryPackageControlFile();
+ packageControlFile.set("Package", "test-package");
+ packageControlFile.set("Description", "This is\na description\non several lines");
+ packageControlFile.set("Version", "1.0");
+
+ String s = packageControlFile.toString();
+
+ BinaryPackageControlFile packageControlFile2 = new BinaryPackageControlFile(s);
+ assertEquals("Package", packageControlFile.get("Package"), packageControlFile2.get("Package"));
+ assertEquals("Description", packageControlFile.get("Description"), packageControlFile2.get("Description"));
+ assertEquals("Version 3", packageControlFile.get("Version"), packageControlFile2.get("Version"));
+ }
+
+ public void testEmptyLines() throws Exception {
+ String input =
+ "Key1: Value1\n" +
+ "Key2: Value2\n" +
+ "\n";
+ try {
+ new BinaryPackageControlFile(input);
+ fail("Should throw a ParseException");
+ } catch (ParseException e) {
+ }
+ }
+
+ public void testGetShortDescription() {
+ BinaryPackageControlFile packageControlFile = new BinaryPackageControlFile();
+
+ assertNull(packageControlFile.getShortDescription());
+
+ packageControlFile.set("Description", "This is the short description\nThis is the loooooong description");
+
+ assertEquals("short description", "This is the short description", packageControlFile.getShortDescription());
+
+ packageControlFile.set("Description", "\nThere is no short description");
+
+ assertEquals("short description", "", packageControlFile.getShortDescription());
+ }
+
+ public void testGetDescription() throws Exception {
+ BinaryPackageControlFile packageControlFile = new BinaryPackageControlFile();
+ packageControlFile.parse(new FileInputStream("target/test-classes/org/vafer/jdeb/deb/control/control"));
+
+ assertEquals("Description", "revision @REVISION@, test package\n" +
+ "This is a sample package control file.\n\n" +
+ "Use for testing purposes only.",
+ packageControlFile.get("Description"));
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/mapping/LsMapperTestCase.java b/src/test/java/org/vafer/jdeb/mapping/LsMapperTestCase.java
new file mode 100644
index 0000000..309759b
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/mapping/LsMapperTestCase.java
@@ -0,0 +1,101 @@
+/*
+ * 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.mapping;
+
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.vafer.jdeb.mapping.LsMapper.ParseError;
+
+public final class LsMapperTestCase extends TestCase {
+
+ private final static String output =
+ "total 0\n" +
+ "drwxr-xr-x 23 tcurdt tcurdt 782 Jun 25 03:48 .\n" +
+ "drwxr-xr-x 3 tcurdt tcurdt 102 Jun 25 03:48 ..\n" +
+ "\n" +
+ "./trunk/target/test-classes/org/vafer/dependency:\n" +
+ "total 176\n" +
+ "drwxr-xr-x 23 tcurdt tcurdt 782 Jun 25 03:48 .\n" +
+ "drwxr-xr-x 3 tcurdt tcurdt 102 Jun 25 03:48 ..\n" +
+ "-rw-r--r-- 1 tcurdt tcurdt 2934 Jun 25 03:48 DependenciesTestCase.class\n" +
+ "-rw-r--r-- 1 tcurdt tcurdt 786 Jun 25 03:48 JarCombiningTestCase$1.class\n" +
+ "drwxr-xr-x 4 tcurdt tcurdt 136 Jun 25 03:48 classes\n" +
+ "\n" +
+ "./trunk/src/test-classes/org/vafer/dependency:\n" +
+ "total 76\n" +
+ "drwxr-xr-x 23 tcurdt tcurdt 782 Jun 25 03:48 .\n" +
+ "drwxr-xr-x 3 tcurdt tcurdt 102 Jun 25 03:48 ..\n" +
+ "-rw-r--r-- 1 tcurdt tcurdt 2934 Jun 25 03:48 DependenciesTestCase.class\n" +
+ "-rw-r--r-- 1 tcurdt tcurdt 786 Jun 25 03:48 JarCombiningTestCase$1.class\n" +
+ "drwxr-xr-x 4 tcurdt tcurdt 136 Jun 25 03:48 classes\n" +
+ "\n";
+
+ public void testModes() throws Exception {
+ final ByteArrayInputStream is = new ByteArrayInputStream(output.getBytes("UTF-8"));
+
+ final Mapper mapper = new LsMapper(is);
+
+ final TarArchiveEntry entry1 = mapper.map(new TarArchiveEntry("trunk/target/test-classes/org/vafer/dependency", true));
+
+ assertEquals(493, entry1.getMode());
+ assertEquals("tcurdt", entry1.getUserName());
+ assertEquals("tcurdt", entry1.getGroupName());
+
+ final TarArchiveEntry entry2 = mapper.map(new TarArchiveEntry("trunk/target/test-classes/org/vafer/dependency/DependenciesTestCase.class", true));
+
+ assertEquals(420, entry2.getMode());
+ assertEquals("tcurdt", entry2.getUserName());
+ assertEquals("tcurdt", entry2.getGroupName());
+ }
+
+ public void testSuccessfulParsing() throws Exception {
+ final ByteArrayInputStream is = new ByteArrayInputStream(output.getBytes("UTF-8"));
+
+ final Mapper mapper = new LsMapper(is);
+
+ final TarArchiveEntry unknown = new TarArchiveEntry("xyz", true);
+ assertSame(unknown, mapper.map(unknown));
+
+ final TarArchiveEntry known = new TarArchiveEntry("trunk/target/test-classes/org/vafer/dependency", true);
+ final TarArchiveEntry knownMapped = mapper.map(known);
+
+ assertNotSame(known, knownMapped);
+
+ }
+
+ public void testPrematureEOF() throws Exception {
+ final ByteArrayInputStream is = new ByteArrayInputStream(output.substring(0, 200).getBytes("UTF-8"));
+
+ try {
+ new LsMapper(is);
+ fail("should fail to parse");
+ } catch (ParseError e) {
+ }
+ }
+
+ public void testWrongFormat() throws Exception {
+ final ByteArrayInputStream is = new ByteArrayInputStream("asas\n".getBytes("UTF-8"));
+
+ try {
+ new LsMapper(is);
+ fail("should fail to parse");
+ } catch (ParseError e) {
+ }
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/maven/DataTestCase.java b/src/test/java/org/vafer/jdeb/maven/DataTestCase.java
new file mode 100644
index 0000000..fb89491
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/maven/DataTestCase.java
@@ -0,0 +1,122 @@
+/*
+ * 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.maven;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+/*
+ * Admittedly not the nicest way to assert that failOnMissingSrc functions. However, the best that can be done without
+ * refactoring, mocking, or extending the scope of the test beyond this unit.
+ */
+public class DataTestCase extends TestCase {
+
+ private Data data;
+ private File missingFile;
+ private File file;
+
+ protected void setUp() throws Exception {
+ data = new Data();
+ missingFile = new File("this-file-does-not-exist");
+ file = File.createTempFile(getClass().getSimpleName(), "dat");
+ }
+
+ protected void tearDown() throws Exception {
+ if (file != null) {
+ file.delete();
+ }
+ }
+
+ public void testFailOnUnknownValue() throws IOException {
+ try {
+ data.setSrc(missingFile);
+ data.setMissingSrc("not a value value");
+ data.produce(null);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testFailOnMissingSrcDefaultFileMissing() throws IOException {
+ try {
+ data.setSrc(missingFile);
+ data.produce(null);
+ fail();
+ } catch (FileNotFoundException expected) {
+ }
+ }
+
+ public void testFailOnMissingSrcIgnoreFileMissing() throws IOException {
+ data.setSrc(missingFile);
+ data.setMissingSrc("ignore");
+ data.produce(null);
+ }
+
+ public void testFailOnMissingSrcIgnoreFileMissingVaryInput() throws IOException {
+ data.setSrc(missingFile);
+ data.setMissingSrc(" IGNORE ");
+ data.produce(null);
+ }
+
+ public void testFailOnMissingSrcFailFileMissing() throws IOException {
+ try {
+ data.setSrc(missingFile);
+ data.setMissingSrc("fail");
+ data.produce(null);
+ fail();
+ } catch (FileNotFoundException expected) {
+ }
+ }
+
+ public void testFailOnMissingSrcDefaultFileExists() throws IOException {
+ IOException unknownTypeException = null;
+ try {
+ data.setSrc(file);
+ data.produce(null);
+ } catch (IOException expected) {
+ unknownTypeException = expected;
+ }
+ assertTrue(unknownTypeException.getMessage().startsWith("Unknown type"));
+ }
+
+ public void testFailOnMissingSrcIgnoreFileExists() throws IOException {
+ IOException unknownTypeException = null;
+ try {
+ data.setSrc(file);
+ data.setMissingSrc("ignore");
+ data.produce(null);
+ } catch (IOException expected) {
+ unknownTypeException = expected;
+ }
+ assertTrue(unknownTypeException.getMessage().startsWith("Unknown type"));
+ }
+
+ public void testFailOnMissingSrcFailFileExists() throws IOException {
+ IOException unknownTypeException = null;
+ try {
+ data.setSrc(file);
+ data.setMissingSrc("fail");
+ data.produce(null);
+ } catch (IOException expected) {
+ unknownTypeException = expected;
+ }
+ assertTrue(unknownTypeException.getMessage().startsWith("Unknown type"));
+ }
+
+}
diff --git a/src/test/java/org/vafer/jdeb/producers/DataProducerPathTemplateTestCase.java b/src/test/java/org/vafer/jdeb/producers/DataProducerPathTemplateTestCase.java
new file mode 100644
index 0000000..60ac425
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/producers/DataProducerPathTemplateTestCase.java
@@ -0,0 +1,115 @@
+/*
+ * 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 java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.vafer.jdeb.DataConsumer;
+import org.vafer.jdeb.DataProducer;
+import org.vafer.jdeb.mapping.Mapper;
+
+public class DataProducerPathTemplateTestCase extends TestCase {
+
+ private static final String[] INCLUDES = { };
+ private static final String[] EXCLUDES = { };
+
+ private CaptureDataConsumer captureDataConsumer = new CaptureDataConsumer();
+
+ private Mapper[] mappers = new Mapper[0];
+ private DataProducer dataProducer;
+
+ public void testTypical() throws Exception {
+
+ String[] paths = { "/var/log", "/var/lib" };
+ dataProducer = new DataProducerPathTemplate(paths, INCLUDES, EXCLUDES, mappers);
+ dataProducer.produce(captureDataConsumer);
+
+ assertEquals(2, captureDataConsumer.invocations.size());
+
+ CaptureDataConsumer.Invocation invocation = captureDataConsumer.invocations.get(0);
+ assertEquals(invocation.dirname, "/var/log");
+ assertEquals(invocation.gid, 0);
+ assertEquals(invocation.group, "root");
+ assertEquals(invocation.linkname, "");
+ assertEquals(invocation.mode, TarArchiveEntry.DEFAULT_DIR_MODE);
+ assertEquals(invocation.size, 0);
+ assertEquals(invocation.uid, 0);
+ assertEquals(invocation.user, "root");
+
+ invocation = captureDataConsumer.invocations.get(1);
+ assertEquals(invocation.dirname, "/var/lib");
+ assertEquals(invocation.gid, 0);
+ assertEquals(invocation.group, "root");
+ assertEquals(invocation.linkname, "");
+ assertEquals(invocation.mode, TarArchiveEntry.DEFAULT_DIR_MODE);
+ assertEquals(invocation.size, 0);
+ assertEquals(invocation.uid, 0);
+ assertEquals(invocation.user, "root");
+ }
+
+ public class CaptureDataConsumer implements DataConsumer {
+
+ private List<Invocation> invocations;
+
+ public CaptureDataConsumer() {
+ invocations = new ArrayList<Invocation>();
+ }
+
+ @Override
+ public void onEachDir( String dirname, String linkname, String user, int uid, String group, int gid, int mode, long size ) throws IOException {
+ invocations.add(new Invocation(dirname, linkname, user, uid, group, gid, mode, size));
+ }
+
+ @Override
+ public void onEachFile( InputStream input, String filename, String linkname, String user, int uid, String group, int gid, int mode, long size ) throws IOException {
+ }
+
+ @Override
+ public void onEachLink(String path, String linkName, boolean symlink, String user, int uid, String group, int gid, int mode) throws IOException {
+ }
+
+ private class Invocation {
+
+ private String dirname;
+ private String linkname;
+ private String user;
+ private int uid;
+ private String group;
+ private int gid;
+ private int mode;
+ private long size;
+
+ private Invocation( String dirname, String linkname, String user, int uid, String group, int gid, int mode, long size ) throws IOException {
+ this.dirname = dirname;
+ this.linkname = linkname;
+ this.user = user;
+ this.uid = uid;
+ this.group = group;
+ this.gid = gid;
+ this.mode = mode;
+ this.size = size;
+ }
+
+ }
+
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/signing/PGPSignerTestCase.java b/src/test/java/org/vafer/jdeb/signing/PGPSignerTestCase.java
new file mode 100644
index 0000000..0e1c087
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/signing/PGPSignerTestCase.java
@@ -0,0 +1,74 @@
+/*
+ * 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.signing;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public final class PGPSignerTestCase extends TestCase {
+
+ public void testClearSign() throws Exception {
+
+ final InputStream ring = getClass().getClassLoader().getResourceAsStream("org/vafer/gpg/secring.gpg");
+
+ assertNotNull(ring);
+
+ String input = "TEST1 \n-TEST2 \n \nTEST3 \n";
+
+ final String expectedOutputStr =
+ "-----BEGIN PGP SIGNED MESSAGE-----\n" +
+ "Hash: SHA1\n" +
+ "\n" +
+ "TEST1\n" +
+ "- -TEST2\n" +
+ "\n" +
+ "TEST3\n" +
+ "-----BEGIN PGP SIGNATURE-----\n" +
+ "Version: BCPG v1.48\n" +
+ "\n" +
+ "iEYEARECABAFAkax1rgJEHM9pIAuB02PAABIJgCghFmoCJCZ0CGiqgVLGGPd/Yh5\n" +
+ "FQQAnRVqvI2ij45JQSHYJBblZ0Vv2meN\n" +
+ "=aAAT\n" +
+ "-----END PGP SIGNATURE-----\n";
+
+ final byte[] expectedOutput = expectedOutputStr.getBytes("UTF-8");
+
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ PGPSigner signer = new PGPSigner(ring, "2E074D8F", "test");
+ signer.clearSign(input, os);
+
+ final byte[] output = fixCRLF(os.toByteArray());
+
+ final int from = expectedOutputStr.indexOf("iEYEAREC");
+ final int until = expectedOutputStr.indexOf("=aAAT") + 5;
+ Arrays.fill(output, from, until, (byte) '?');
+ Arrays.fill(expectedOutput, from, until, (byte) '?');
+
+ assertEquals(new String(expectedOutput), new String(output));
+ }
+
+ private byte[] fixCRLF(byte[] b) {
+ String s = new String(b);
+ s = s.replaceAll("\r\n", "\n");
+ return s.getBytes();
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/utils/FilteredFileTestCase.java b/src/test/java/org/vafer/jdeb/utils/FilteredFileTestCase.java
new file mode 100644
index 0000000..e2d6eb8
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/utils/FilteredFileTestCase.java
@@ -0,0 +1,69 @@
+/*
+ * 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.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import org.apache.tools.ant.util.ReaderInputStream;
+import org.vafer.jdeb.debian.BinaryPackageControlFile;
+
+public class FilteredFileTestCase extends TestCase {
+
+ private VariableResolver variableResolver;
+
+ protected void setUp() throws Exception {
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("artifactId", "jdeb");
+ map.put("myProperty1", "custom1");
+ map.put("myProperty2", "custom2");
+ variableResolver = new MapVariableResolver(map);
+ }
+
+ public void testTokenSubstitution() throws Exception {
+ InputStream in = new ReaderInputStream(new StringReader("#!/bin/sh\ncat [[artifactId]][[myProperty1]] \necho '[[myProperty2]]'\n"));
+
+ FilteredFile placeHolder = new FilteredFile(in, variableResolver);
+
+ String actual = placeHolder.toString();
+ assertEquals("#!/bin/sh\ncat jdebcustom1 \necho 'custom2'\n", actual);
+ }
+
+ public void testVariableSubstitution() throws Exception {
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("VERSION", "1.2");
+ map.put("MAINTAINER", "Torsten Curdt <tcurdt at vafer.org>");
+
+ String controlFile =
+ "Version: [[VERSION]]\n"
+ + "Maintainer: [[MAINTAINER]]\n"
+ + "NoResolve1: test[[test\n"
+ + "NoResolve2: [[test]]\n";
+
+ FilteredFile filteredFile = new FilteredFile(new ByteArrayInputStream(controlFile.getBytes()), new MapVariableResolver(map));
+
+ BinaryPackageControlFile d = new BinaryPackageControlFile(filteredFile.toString());
+
+ assertEquals("1.2", d.get("Version"));
+ assertEquals("Torsten Curdt <tcurdt at vafer.org>", d.get("Maintainer"));
+ assertEquals("test[[test", d.get("NoResolve1"));
+ assertEquals("[[test]]", d.get("NoResolve2"));
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/utils/InformationInputStreamTestCase.java b/src/test/java/org/vafer/jdeb/utils/InformationInputStreamTestCase.java
new file mode 100644
index 0000000..478e5a6
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/utils/InformationInputStreamTestCase.java
@@ -0,0 +1,87 @@
+/*
+ * 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.utils;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+public class InformationInputStreamTestCase extends TestCase {
+
+ private InputStream getStream( String file ) {
+ return getClass().getClassLoader().getResourceAsStream("org/vafer/jdeb/utils/" + file);
+ }
+
+ public void testUTF8CRLF() throws Exception {
+ InformationInputStream informationStream = new InformationInputStream(getStream("utf8-crlf.txt"));
+ Utils.copy(informationStream, new ByteArrayOutputStream());
+ assertTrue("Should be windows line endings", !informationStream.hasUnixLineEndings());
+ assertTrue("Shebang not detected", informationStream.isShell());
+ assertTrue("BOM detected", !informationStream.hasBom());
+ assertEquals("Encoding", null, informationStream.getEncoding());
+ }
+
+ public void testUTF8() throws Exception {
+ InformationInputStream informationStream = new InformationInputStream(getStream("utf8-lf.txt"));
+ Utils.copy(informationStream, new ByteArrayOutputStream());
+ assertTrue("Shebang not detected", informationStream.isShell());
+ assertTrue("BOM detected", !informationStream.hasBom());
+ assertEquals("Encoding", null, informationStream.getEncoding());
+ }
+
+ public void testUTF8BOM() throws Exception {
+ InformationInputStream informationStream = new InformationInputStream(getStream("utf8-lf-bom.txt"));
+ Utils.copy(informationStream, new ByteArrayOutputStream());
+ assertTrue("Shebang not detected", informationStream.isShell());
+ assertTrue("BOM not detected", informationStream.hasBom());
+ assertEquals("Encoding", "UTF-8", informationStream.getEncoding());
+ }
+
+ public void testUTF16BE() throws Exception {
+ InformationInputStream informationStream = new InformationInputStream(getStream("utf16be-lf.txt"));
+ Utils.copy(informationStream, new ByteArrayOutputStream());
+ assertTrue("Shebang not detected", informationStream.isShell());
+ assertTrue("BOM detected", !informationStream.hasBom());
+ assertEquals("Encoding", "UTF-16BE", informationStream.getEncoding());
+ }
+
+ public void testUTF16BEBOM() throws Exception {
+ InformationInputStream informationStream = new InformationInputStream(getStream("utf16be-lf-bom.txt"));
+ Utils.copy(informationStream, new ByteArrayOutputStream());
+ assertTrue("Shebang not detected", informationStream.isShell());
+ assertTrue("BOM not detected", informationStream.hasBom());
+ assertEquals("Encoding", "UTF-16BE", informationStream.getEncoding());
+ }
+
+ public void testUTF16LE() throws Exception {
+ InformationInputStream informationStream = new InformationInputStream(getStream("utf16le-lf.txt"));
+ Utils.copy(informationStream, new ByteArrayOutputStream());
+ assertTrue("Shebang not detected", informationStream.isShell());
+ assertTrue("BOM detected", !informationStream.hasBom());
+ assertEquals("Encoding", "UTF-16LE", informationStream.getEncoding());
+ }
+
+ public void testUTF16LEBOM() throws Exception {
+ InformationInputStream informationStream = new InformationInputStream(getStream("utf16le-lf-bom.txt"));
+ Utils.copy(informationStream, new ByteArrayOutputStream());
+ assertTrue("Shebang not detected", informationStream.isShell());
+ assertTrue("BOM not detected", informationStream.hasBom());
+ assertEquals("Encoding", "UTF-16LE", informationStream.getEncoding());
+ }
+}
diff --git a/src/test/java/org/vafer/jdeb/utils/UtilsTestCase.java b/src/test/java/org/vafer/jdeb/utils/UtilsTestCase.java
new file mode 100644
index 0000000..e7b4777
--- /dev/null
+++ b/src/test/java/org/vafer/jdeb/utils/UtilsTestCase.java
@@ -0,0 +1,97 @@
+/*
+ * 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.utils;
+
+
+import java.io.ByteArrayInputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import junit.framework.TestCase;
+
+public class UtilsTestCase extends TestCase {
+
+ public void testStripPath() throws Exception {
+ assertEquals("foo/bar", Utils.stripPath(0, "foo/bar"));
+
+ assertEquals("bar", Utils.stripPath(1, "foo/bar"));
+
+ assertEquals("bar/baz", Utils.stripPath(1, "foo/bar/baz"));
+ assertEquals("baz", Utils.stripPath(2, "foo/bar/baz"));
+
+ assertEquals("foo/", Utils.stripPath(0, "foo/"));
+ assertEquals("", Utils.stripPath(1, "foo/"));
+ assertEquals("foo/", Utils.stripPath(2, "foo/"));
+ }
+
+ private String convert(String s) throws Exception {
+ byte[] data = Utils.toUnixLineEndings(new ByteArrayInputStream(s.getBytes("UTF-8")));
+ return new String(data, "UTF-8");
+ }
+
+ public void testNewlineConversionLF() throws Exception {
+ String expected = "test\ntest\n\ntest\n";
+ String actual = convert("test\ntest\n\ntest");
+ assertEquals(expected, actual);
+ }
+
+ public void testNewlineConversionCRLF() throws Exception {
+ String expected = "test\ntest\n\ntest\n";
+ String actual = convert("test\r\ntest\r\n\r\ntest");
+ assertEquals(expected, actual);
+ }
+
+ public void testNewlineConversionCR() throws Exception {
+ String expected = "test\ntest\n\ntest\n";
+ String actual = convert("test\rtest\r\rtest");
+ assertEquals(expected, actual);
+ }
+
+ public void testReplaceVariables() {
+ Map<String, String> variables = new HashMap<String, String>();
+ variables.put("version", "1.2.3");
+ variables.put("name", "jdeb");
+ variables.put("url", "https://github.com/tcurdt/jdeb");
+
+ VariableResolver resolver = new MapVariableResolver(variables);
+
+ // main case
+ String result = Utils.replaceVariables(resolver, "Version: [[version]]", "[[", "]]");
+ assertEquals("Version: 1.2.3", result);
+
+ // multiple variables in the same expression
+ result = Utils.replaceVariables(resolver, "[[name]] [[version]]", "[[", "]]");
+ assertEquals("jdeb 1.2.3", result);
+
+ // collision with script syntax
+ result = Utils.replaceVariables(resolver, "if [[ \"${HOST_TYPE}\" -eq \"admin\" ]] ; then", "[[", "]]");
+ assertEquals("if [[ \"${HOST_TYPE}\" -eq \"admin\" ]] ; then", result);
+
+ // mixed valid and unknown variables
+ result = Utils.replaceVariables(resolver, "[[name]] [[test]]", "[[", "]]");
+ assertEquals("jdeb [[test]]", result);
+ }
+
+ public void testVersionConversion() {
+ Calendar cal = new GregorianCalendar(2013, 02-1, 17);
+ assertEquals("should match", "1.0", Utils.convertToDebianVersion("1.0", null));
+ assertEquals("should match", "1.0~SNAPSHOT", Utils.convertToDebianVersion("1.0+SNAPSHOT", null));
+ assertEquals("should match", "1.0~20130217000000", Utils.convertToDebianVersion("1.0+SNAPSHOT", cal.getTime()));
+ }
+}
diff --git a/src/test/resources/org/vafer/gpg/fingerprint.txt b/src/test/resources/org/vafer/gpg/fingerprint.txt
new file mode 100644
index 0000000..07837c4
--- /dev/null
+++ b/src/test/resources/org/vafer/gpg/fingerprint.txt
@@ -0,0 +1,4 @@
+pub 1024D/2E074D8F 2007-08-02
+ Key fingerprint = 5A17 CB12 37F0 85BC 8264 E649 733D A480 2E07 4D8F
+uid Unit test user (only for testing) <test at vafer.org>
+sub 2048g/5E8CA506 2007-08-02
diff --git a/src/test/resources/org/vafer/gpg/pubring.gpg b/src/test/resources/org/vafer/gpg/pubring.gpg
new file mode 100644
index 0000000..c3c67a8
Binary files /dev/null and b/src/test/resources/org/vafer/gpg/pubring.gpg differ
diff --git a/src/test/resources/org/vafer/gpg/secring.gpg b/src/test/resources/org/vafer/gpg/secring.gpg
new file mode 100644
index 0000000..6658556
Binary files /dev/null and b/src/test/resources/org/vafer/gpg/secring.gpg differ
diff --git a/src/test/resources/org/vafer/jdeb/ar/data.ar b/src/test/resources/org/vafer/jdeb/ar/data.ar
new file mode 100644
index 0000000..531480f
Binary files /dev/null and b/src/test/resources/org/vafer/jdeb/ar/data.ar differ
diff --git a/src/test/resources/org/vafer/jdeb/changes/changes.txt b/src/test/resources/org/vafer/jdeb/changes/changes.txt
new file mode 100644
index 0000000..8d16f99
--- /dev/null
+++ b/src/test/resources/org/vafer/jdeb/changes/changes.txt
@@ -0,0 +1,2 @@
+release date=20:13 17.08.2007,version=1.4+r89114,urgency=low,by=Torsten Curdt <torsten at vafer.org>
+ * debian changes support
\ No newline at end of file
diff --git a/src/test/resources/org/vafer/jdeb/deb/control/control b/src/test/resources/org/vafer/jdeb/deb/control/control
new file mode 100644
index 0000000..226eca2
--- /dev/null
+++ b/src/test/resources/org/vafer/jdeb/deb/control/control
@@ -0,0 +1,12 @@
+Package: test
+Version: 1.0.1
+Section: misc
+Priority: optional
+Architecture: i386
+Depends: some-package
+Maintainer: John Doe <john at doe.org>
+Distribution: development
+Description: revision @REVISION@, test package
+ This is a sample package control file.
+ .
+ Use for testing purposes only.
diff --git a/src/test/resources/org/vafer/jdeb/deb/control/postinst b/src/test/resources/org/vafer/jdeb/deb/control/postinst
new file mode 100644
index 0000000..44c84cd
--- /dev/null
+++ b/src/test/resources/org/vafer/jdeb/deb/control/postinst
@@ -0,0 +1,4 @@
+#!/bin/sh
+#
+# Post installation script for [[name]] [[version]]
+#
diff --git a/src/test/resources/org/vafer/jdeb/deb/control/prerm b/src/test/resources/org/vafer/jdeb/deb/control/prerm
new file mode 100644
index 0000000..475c5de
--- /dev/null
+++ b/src/test/resources/org/vafer/jdeb/deb/control/prerm
@@ -0,0 +1,4 @@
+#!/bin/sh
+#
+# Pre removal script for [[name]] [[version]]
+#
diff --git a/src/test/resources/org/vafer/jdeb/deb/data.tar.bz2 b/src/test/resources/org/vafer/jdeb/deb/data.tar.bz2
new file mode 100644
index 0000000..f2e1e53
Binary files /dev/null and b/src/test/resources/org/vafer/jdeb/deb/data.tar.bz2 differ
diff --git a/src/test/resources/org/vafer/jdeb/deb/data.tgz b/src/test/resources/org/vafer/jdeb/deb/data.tgz
new file mode 100644
index 0000000..d208640
Binary files /dev/null and b/src/test/resources/org/vafer/jdeb/deb/data.tgz differ
diff --git a/src/test/resources/org/vafer/jdeb/deb/data.zip b/src/test/resources/org/vafer/jdeb/deb/data.zip
new file mode 100644
index 0000000..7186f01
Binary files /dev/null and b/src/test/resources/org/vafer/jdeb/deb/data.zip differ
diff --git a/src/test/resources/org/vafer/jdeb/deb/data/test/testfile b/src/test/resources/org/vafer/jdeb/deb/data/test/testfile
new file mode 100644
index 0000000..e7cbb71
--- /dev/null
+++ b/src/test/resources/org/vafer/jdeb/deb/data/test/testfile
@@ -0,0 +1 @@
+testfile
\ No newline at end of file
diff --git a/src/test/resources/org/vafer/jdeb/deb/test/testfile4 b/src/test/resources/org/vafer/jdeb/deb/test/testfile4
new file mode 100644
index 0000000..e0a0ee6
--- /dev/null
+++ b/src/test/resources/org/vafer/jdeb/deb/test/testfile4
@@ -0,0 +1 @@
+testfile4
\ No newline at end of file
diff --git a/src/test/resources/org/vafer/jdeb/utils/utf16be-lf-bom.txt b/src/test/resources/org/vafer/jdeb/utils/utf16be-lf-bom.txt
new file mode 100644
index 0000000..ef566e6
Binary files /dev/null and b/src/test/resources/org/vafer/jdeb/utils/utf16be-lf-bom.txt differ
diff --git a/src/test/resources/org/vafer/jdeb/utils/utf16be-lf.txt b/src/test/resources/org/vafer/jdeb/utils/utf16be-lf.txt
new file mode 100755
index 0000000..5004043
Binary files /dev/null and b/src/test/resources/org/vafer/jdeb/utils/utf16be-lf.txt differ
diff --git a/src/test/resources/org/vafer/jdeb/utils/utf16le-lf-bom.txt b/src/test/resources/org/vafer/jdeb/utils/utf16le-lf-bom.txt
new file mode 100644
index 0000000..9445f81
Binary files /dev/null and b/src/test/resources/org/vafer/jdeb/utils/utf16le-lf-bom.txt differ
diff --git a/src/test/resources/org/vafer/jdeb/utils/utf16le-lf.txt b/src/test/resources/org/vafer/jdeb/utils/utf16le-lf.txt
new file mode 100755
index 0000000..ade2a1a
Binary files /dev/null and b/src/test/resources/org/vafer/jdeb/utils/utf16le-lf.txt differ
diff --git a/src/test/resources/org/vafer/jdeb/utils/utf8-crlf.txt b/src/test/resources/org/vafer/jdeb/utils/utf8-crlf.txt
new file mode 100644
index 0000000..0774808
--- /dev/null
+++ b/src/test/resources/org/vafer/jdeb/utils/utf8-crlf.txt
@@ -0,0 +1 @@
+#!/bin/sh
diff --git a/src/test/resources/org/vafer/jdeb/utils/utf8-lf-bom.txt b/src/test/resources/org/vafer/jdeb/utils/utf8-lf-bom.txt
new file mode 100755
index 0000000..3c55952
--- /dev/null
+++ b/src/test/resources/org/vafer/jdeb/utils/utf8-lf-bom.txt
@@ -0,0 +1 @@
+#! /bin/sh
\ No newline at end of file
diff --git a/src/test/resources/org/vafer/jdeb/utils/utf8-lf.txt b/src/test/resources/org/vafer/jdeb/utils/utf8-lf.txt
new file mode 100644
index 0000000..ee600ae
--- /dev/null
+++ b/src/test/resources/org/vafer/jdeb/utils/utf8-lf.txt
@@ -0,0 +1 @@
+#! /bin/sh
\ No newline at end of file
diff --git a/src/test/resources/testbuild.xml b/src/test/resources/testbuild.xml
new file mode 100644
index 0000000..56acc50
--- /dev/null
+++ b/src/test/resources/testbuild.xml
@@ -0,0 +1,114 @@
+<project name="JDeb Ant tests">
+
+ <taskdef name="deb" classname="org.vafer.jdeb.ant.DebAntTask"/>
+
+ <target name="missing-control">
+ <deb destfile="test.deb"/>
+ </target>
+
+ <target name="invalid-control">
+ <deb destfile="test.deb" control="testbuild.xml"/>
+ </target>
+
+ <target name="missing-destfile">
+ <deb control="org/vafer/jdeb/deb/control">
+ <data src="org/vafer/jdeb/deb/invalid.tgz" type="archive"/>
+ </deb>
+ </target>
+
+ <target name="empty-package">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control"/>
+ </target>
+
+ <target name="with-archive">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control">
+ <data src="org/vafer/jdeb/deb/data.tgz" type="archive"/>
+ </deb>
+ </target>
+
+ <target name="with-missing-archive">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control">
+ <data src="org/vafer/jdeb/deb/invalid.tgz" type="archive"/>
+ </deb>
+ </target>
+
+ <target name="with-directory">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control">
+ <data src="org/vafer/jdeb/deb/data" type="directory"/>
+ </deb>
+ </target>
+
+ <target name="with-missing-directory">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control">
+ <data src="org/vafer/jdeb/deb/invalid" type="directory"/>
+ </deb>
+ </target>
+
+ <target name="verbose-enabled">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control" verbose="true">
+ <data src="org/vafer/jdeb/deb/data" type="directory"/>
+ </deb>
+ </target>
+
+ <target name="verbose-disabled">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control" verbose="false">
+ <data src="org/vafer/jdeb/deb/data" type="directory"/>
+ </deb>
+ </target>
+
+ <target name="missing-data-type">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control" verbose="false">
+ <data src="org/vafer/jdeb/deb/data"/>
+ </deb>
+ </target>
+
+ <target name="unknown-data-type">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control" verbose="false">
+ <data src="org/vafer/jdeb/deb/data" type="container"/>
+ </deb>
+ </target>
+
+ <target name="fileset">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control">
+ <fileset dir="org/vafer/jdeb/deb/data"/>
+ </deb>
+ </target>
+
+ <target name="tarfileset">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control">
+ <tarfileset dir="org/vafer/jdeb/deb/data" prefix="foo" dirmode="700" filemode="600" username="ebourg" group="ebourg"/>
+ </deb>
+ </target>
+
+ <target name="link">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control">
+ <tarfileset dir="org/vafer/jdeb/deb/data" prefix="foo" dirmode="700" filemode="600" username="ebourg" group="ebourg"/>
+ <link name="/usr/share/java/foo.jar" target="/usr/share/java/foo-1.0.jar" username="ebourg" group="ebourg" mode="755"/>
+ </deb>
+ </target>
+
+ <target name="unknown-compression">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control" compression="rar">
+ <fileset dir="org/vafer/jdeb/deb/data"/>
+ </deb>
+ </target>
+
+ <target name="bzip2-compression">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control" compression="bzip2">
+ <fileset dir="org/vafer/jdeb/deb/data"/>
+ </deb>
+ </target>
+
+ <target name="xz-compression">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control" compression="xz">
+ <fileset dir="org/vafer/jdeb/deb/data"/>
+ </deb>
+ </target>
+
+ <target name="no-compression">
+ <deb destfile="test.deb" control="org/vafer/jdeb/deb/control" compression="none">
+ <fileset dir="org/vafer/jdeb/deb/data"/>
+ </deb>
+ </target>
+
+</project>
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jdeb.git
More information about the pkg-java-commits
mailing list