001 /*
002 * Copyright 2010 The Apache Software Foundation.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.vafer.jdeb.maven;
017
018 import java.io.File;
019 import java.io.FileInputStream;
020 import java.text.ParseException;
021 import java.util.ArrayList;
022 import java.util.Collection;
023 import java.util.HashMap;
024 import java.util.Map;
025
026 import org.apache.maven.plugin.MojoExecutionException;
027 import org.apache.maven.project.MavenProjectHelper;
028 import org.apache.tools.tar.TarEntry;
029 import org.vafer.jdeb.Console;
030 import org.vafer.jdeb.DataConsumer;
031 import org.vafer.jdeb.DataProducer;
032 import org.vafer.jdeb.PackagingException;
033 import org.vafer.jdeb.descriptors.AbstractDescriptor;
034 import org.vafer.jdeb.utils.MapVariableResolver;
035 import org.vafer.jdeb.utils.Utils;
036 import org.vafer.jdeb.utils.VariableResolver;
037
038 /**
039 * Creates deb archive
040 *
041 * @goal jdeb
042 */
043 public class DebMojo extends AbstractPluginMojo {
044
045 /**
046 * @component
047 */
048 private MavenProjectHelper projectHelper;
049
050 /**
051 * Defines the pattern of the name of final artifacts. Possible
052 * substitutions are [[artifactId]] [[version]] [[extension]] and
053 * [[groupId]].
054 *
055 * @parameter expression="${namePattern}"
056 * default-value="[[artifactId]]_[[version]].[[extension]]"
057 */
058 private String namePattern;
059
060 /**
061 * Explicitly defines the final artifact name (without using the pattern)
062 *
063 * @parameter expression="${deb}"
064 */
065 private File deb;
066 private String debName;
067
068 /**
069 * Explicitly defines the path to the control directory. At least the
070 * control file is mandatory.
071 *
072 * @parameter expression="${controlDir}"
073 */
074 private File controlDir;
075
076 /**
077 * Explicitly define the file to read the changes from.
078 *
079 * @parameter expression="${changesIn}"
080 */
081 private File changesIn = null;
082 private String changesName;
083
084 /**
085 * Explicitly define the file where to write the changes to.
086 *
087 * @parameter expression="${changesIn}"
088 */
089 private File changesOut = null;
090
091 // /**
092 // * Explicitly define the file where to write the changes of the changes
093 // * input to.
094 // *
095 // * @parameter expression="${changesSave}"
096 // */
097 // private File changesSave = null;
098
099 // /**
100 // * The keyring file. Usually some/path/secring.gpg
101 // *
102 // * @parameter expression="${keyring}"
103 // */
104 // private File keyring = null;
105
106 // /**
107 // * The hex key id to use for signing.
108 // *
109 // * @parameter expression="${key}"
110 // */
111 // private String key = null;
112
113 // /**
114 // * The passphrase for the key to sign the changes file.
115 // *
116 // * @parameter expression="${passhrase}"
117 // */
118 // private String passphrase = null;
119
120 // /**
121 // * The compression method used for the data file (none, gzip or bzip2)
122 // *
123 // * @parameter expression="${compression}" default-value="gzip"
124 // */
125 // private String compression;
126
127 /**
128 * The location where all package files will be installed. By default, all
129 * packages are installed in /opt (see the FHS here:
130 * http://www.pathname.com/
131 * fhs/pub/fhs-2.3.html#OPTADDONAPPLICATIONSOFTWAREPACKAGES)
132 *
133 * @parameter expression="${installDir}"
134 * default-value="/opt/${project.artifactId}"
135 */
136 private String installDir;
137 private String openReplaceToken = "[[";
138 private String closeReplaceToken = "]]";
139
140 /**
141 * The type of attached artifact
142 *
143 * @parameter default-value="deb"
144 */
145 private String type;
146
147 /**
148 * The classifier of attached artifact
149 *
150 * @parameter
151 */
152 private String classifier;
153
154 /**
155 * "data" entries used to determine which files should be added to this deb.
156 * The "data" entries may specify a tarball (tar.gz, tar.bz2, tgz), a
157 * directory, or a normal file. An entry would look something like this in
158 * your pom.xml:
159 *
160 * <pre>
161 * <build>
162 * <plugins>
163 * <plugin>
164 * <artifactId>jdeb</artifactId>
165 * <groupId>org.vafer</groupId>
166 * ...
167 * <configuration>
168 * ...
169 * <dataSet>
170 * <data>
171 * <src>${project.basedir}/target/my_archive.tar.gz</src>
172 * <include>...</include>
173 * <exclude>...</exclude>
174 * <mapper>
175 * <type>perm</type>
176 * <strip>1</strip>
177 * <prefix>/somewhere/else</prefix>
178 * <user>santbj</user>
179 * <group>santbj</group>
180 * <mode>600</mode>
181 * </mapper>
182 * </data>
183 * <data>
184 * <src>${project.build.directory}/data</src>
185 * <include></include>
186 * <exclude>**/.svn</exclude>
187 * <mapper>
188 * <type>ls</type>
189 * <src>mapping.txt</src>
190 * </mapper>
191 * </data>
192 * <data>
193 * <src>${project.basedir}/README.txt</src>
194 * </data>
195 * </dataSet>
196 * </configuration>
197 * </plugins>
198 * </build>
199 * </pre>
200 *
201 * @parameter expression="${dataSet}"
202 */
203 private Data[] dataSet;
204 private Collection dataProducers = new ArrayList();
205
206 public void setData(Data[] pData) {
207 dataSet = pData;
208 dataProducers.clear();
209 if (pData != null) {
210 for (int i = 0; i < pData.length; i++) {
211 dataProducers.add(pData[i]);
212 }
213 }
214 }
215
216 public void setOpenReplaceToken(String openReplaceToken) {
217 this.openReplaceToken = openReplaceToken;
218 AbstractDescriptor.setOpenToken(openReplaceToken);
219 }
220
221 public void setCloseReplaceToken(String closeReplaceToken) {
222 this.closeReplaceToken = closeReplaceToken;
223 AbstractDescriptor.setCloseToken(closeReplaceToken);
224 }
225
226 protected VariableResolver initializeVariableResolver(Map variables) {
227 variables.put("name", getProject().getName());
228 variables.put("artifactId", getProject().getArtifactId());
229 variables.put("groupId", getProject().getGroupId());
230 variables.put("version", getProject().getVersion().replace('-', '+'));
231 variables.put("description", getProject().getDescription());
232 variables.put("extension", "deb");
233 return new MapVariableResolver(variables);
234 }
235
236 protected File getDebFile() {
237 // if not specified try to the default
238 if (deb == null) {
239 deb = new File(buildDirectory, debName);
240 }
241 return deb;
242 }
243
244 protected File getControlDir() {
245 // if not specified try to the default
246 if (controlDir == null) {
247 controlDir = new File(getProject().getBasedir(), "src/deb/control");
248 getLog().info(
249 "Using default path to control directory " + controlDir);
250 }
251 return controlDir;
252 }
253
254 protected File getControlFile() {
255 return new File(controlDir, "control");
256 }
257
258 protected String getInstallDir() {
259 // if not specified try to the default
260 if (installDir == null) {
261 installDir = "/opt/" + getProject().getArtifactId();
262 getLog().info("Using default path to install directory " + installDir);
263 }
264 return installDir;
265 }
266
267 protected File getChangesInFile() {
268 // if not specified try to the default
269 if (changesIn == null) {
270 final File f = new File(getProject().getBasedir(), "CHANGES.txt");
271 if (f.exists() && f.isFile() && f.canRead()) {
272 changesIn = f;
273 }
274 }
275 return changesIn;
276 }
277
278 protected File getChangesOutFile() {
279 // if not specified try to the default
280 if (changesOut == null) {
281 changesOut = new File(buildDirectory, changesName);
282 }
283 return changesOut;
284 }
285
286 /**
287 * Main entry point
288 *
289 * @throws MojoExecutionException on error
290 */
291 public void execute() throws MojoExecutionException {
292 Map variables = new HashMap();
293 final VariableResolver resolver = initializeVariableResolver(variables);
294 try {
295 // expand name pattern
296 debName = Utils.replaceVariables(resolver, namePattern, openReplaceToken, closeReplaceToken);
297 variables.put("extension", "changes");
298 changesName = Utils.replaceVariables(resolver, namePattern, openReplaceToken, closeReplaceToken);
299 } catch (ParseException e) {
300 throw new MojoExecutionException("Failed parsing artifact name pattern", e);
301 }
302
303 deb = getDebFile();
304 changesIn = getChangesInFile();
305 changesOut = getChangesOutFile();
306 controlDir = getControlDir();
307
308 setData(dataSet);
309
310 // If there are no dataProducers, then we'll add a single producer that
311 // processes the
312 // maven artifact file (be it a jar, war, etc.)
313 if (dataProducers.isEmpty()) {
314 final File file = getProject().getArtifact().getFile();
315 dataProducers.add(new DataProducer() {
316 public void produce(final DataConsumer receiver) {
317 try {
318 receiver.onEachFile(new FileInputStream(file),
319 new File(new File(getInstallDir()), file.getName()).getAbsolutePath(), "",
320 "root", 0, "root", 0,
321 TarEntry.DEFAULT_FILE_MODE, file.length());
322 } catch (Exception e) {
323 getLog().error(e);
324 }
325 }
326 });
327 }
328
329 Console infoConsole = new Console() {
330 public void println(String s) {
331 getLog().info(s);
332 }
333 };
334 try {
335 DebMaker debMaker = new DebMaker(infoConsole, deb, controlDir, dataProducers, resolver);
336 debMaker.makeDeb();
337 getLog().info("Attaching created debian archive " + deb);
338 projectHelper.attachArtifact(getProject(), type, classifier, deb);
339 } catch (PackagingException e) {
340 getLog().error("Failed to create debian package " + deb, e);
341 throw new MojoExecutionException("Failed to create debian package " + deb, e);
342 }
343 }
344 }