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.io.FileOutputStream;
021 import java.util.ArrayList;
022 import java.util.Collection;
023
024 import org.vafer.jdeb.Console;
025 import org.vafer.jdeb.DataProducer;
026 import org.vafer.jdeb.PackagingException;
027 import org.vafer.jdeb.Processor;
028 import org.vafer.jdeb.changes.TextfileChangesProvider;
029 import org.vafer.jdeb.descriptors.PackageDescriptor;
030 import org.vafer.jdeb.utils.VariableResolver;
031
032 /**
033 * TODO generalize with DebAntTask
034 *
035 * A generic class for creating debian archives. Even supports signed changes
036 * files.
037 *
038 * This class is largely based on the DebAntTask class, and provides the same
039 * featues to maven developers that the ant task provides to ant developers.
040 *
041 * @see org.vafer.jdeb.ant.DebAntTask
042 * @author Bryan Sant <bryan.sant@gmail.com>
043 */
044 public class DebMaker {
045
046 /** A console to output log message with */
047 private Console console;
048
049 /** The Debian package produced */
050 private File deb;
051
052 /** The directory containing the control files to build the package */
053 private File control;
054
055 /** The file containing the PGP keys */
056 private File keyring;
057
058 /** The key to use in the keyring */
059 private String key;
060
061 /** The passphrase for the key to sign the changes file */
062 private String passphrase;
063
064 /** The file to read the changes from */
065 private File changesIn;
066
067 /** The file where to write the changes to */
068 private File changesOut;
069
070 /** The file where to write the changes of the changes input to */
071 private File changesSave;
072
073 /** The compression method used for the data file (none, gzip or bzip2) */
074 private String compression = "gzip";
075
076 private final VariableResolver variableResolver;
077
078
079 private final Collection dataProducers;
080
081 public DebMaker(Console console, VariableResolver variableResolver) {
082 this(console, null, null, null, variableResolver);
083 }
084
085 public DebMaker(Console console, File deb, File controlDir, VariableResolver variableResolver) {
086 this(console, deb, controlDir, null, variableResolver);
087 }
088
089 public DebMaker(Console console, File deb, File controlDir, Collection dataProducers, VariableResolver variableResolver) {
090 this.console = console;
091 this.deb = deb;
092 this.control = controlDir;
093 this.variableResolver = variableResolver;
094 if (dataProducers != null) {
095 this.dataProducers = dataProducers;
096 } else {
097 this.dataProducers = new ArrayList();
098 }
099 }
100
101 public void setDeb(File deb) {
102 this.deb = deb;
103 }
104
105 public void setControl(File control) {
106 this.control = control;
107 }
108
109 public void setChangesIn(File changes) {
110 this.changesIn = changes;
111 }
112
113 public void setChangesOut(File changes) {
114 this.changesOut = changes;
115 }
116
117 public void setChangesSave(File changes) {
118 this.changesSave = changes;
119 }
120
121 public void setKeyring(File keyring) {
122 this.keyring = keyring;
123 }
124
125 public void setKey(String key) {
126 this.key = key;
127 }
128
129 public void setPassphrase(String passphrase) {
130 this.passphrase = passphrase;
131 }
132
133 public void setCompression(String compression) {
134 this.compression = compression;
135 }
136
137 /**
138 * Adds a new data source to the deb. The new data source may point to a
139 * single file, a directory, or a tarball.
140 *
141 * @param file
142 * The data source to add
143 */
144 public void addData(File file) {
145 final Data data = new Data();
146 data.setSrc(file);
147 dataProducers.add(data);
148 }
149
150 public void addData(Data data) {
151 dataProducers.add(data);
152 }
153
154 private boolean isPossibleOutput(File file) {
155
156 if (file.exists()) {
157 return file.isFile() && file.canWrite();
158 }
159
160 return true;
161 }
162
163 public void makeDeb() throws PackagingException {
164
165 if (control == null || !control.isDirectory()) {
166 throw new PackagingException(
167 "You must specify a valid 'control' directory.");
168 }
169
170 if (changesIn != null) {
171
172 if (!changesIn.isFile() || !changesIn.canRead()) {
173 throw new PackagingException(
174 "The 'changesIn' setting needs to point to a readable file. "
175 + changesIn + " was not found/readable.");
176 }
177
178 if (changesOut == null) {
179 throw new PackagingException(
180 "A 'changesIn' without a 'changesOut' does not make much sense.");
181 }
182
183 if (!isPossibleOutput(changesOut)) {
184 throw new PackagingException(
185 "Cannot write the output for 'changesOut' to "
186 + changesOut);
187 }
188
189 if (changesSave != null && !isPossibleOutput(changesSave)) {
190 throw new PackagingException(
191 "Cannot write the output for 'changesSave' to "
192 + changesSave);
193 }
194
195 } else {
196 if (changesOut != null || changesSave != null) {
197 throw new PackagingException(
198 "The 'changesOut' or 'changesSave' settings may only be used when there is a 'changesIn' specified.");
199 }
200 }
201
202 if (!"gzip".equals(compression) && !"bzip2".equals(compression)
203 && !"none".equals(compression)) {
204 throw new PackagingException("The compression method '"
205 + compression + "' is not supported");
206 }
207
208 if (dataProducers.size() == 0) {
209 throw new PackagingException(
210 "You need to provide at least one reference to a tgz or directory with data.");
211 }
212
213 if (deb == null) {
214 throw new PackagingException(
215 "You need to specify where the deb file is supposed to be created.");
216 }
217
218 final File[] controlFiles = control.listFiles();
219
220 final DataProducer[] data = new DataProducer[dataProducers.size()];
221 dataProducers.toArray(data);
222
223 final Processor processor = new Processor(console, variableResolver);
224
225 final PackageDescriptor packageDescriptor;
226 try {
227
228 console.println("Creating debian package: " + deb);
229
230 packageDescriptor = processor.createDeb(controlFiles, data, deb, compression);
231
232 } catch (Exception e) {
233 throw new PackagingException("Failed to create debian package " + deb, e);
234 }
235
236 final TextfileChangesProvider changesProvider;
237
238 try {
239 if (changesOut == null) {
240 return;
241 }
242
243 console.println("Creating changes file: " + changesOut);
244
245 // for now only support reading the changes form a textfile provider
246 changesProvider = new TextfileChangesProvider(new FileInputStream(
247 changesIn), packageDescriptor);
248
249 processor.createChanges(packageDescriptor, changesProvider,
250 (keyring != null) ? new FileInputStream(keyring) : null,
251 key, passphrase, new FileOutputStream(changesOut));
252
253 } catch (Exception e) {
254 throw new PackagingException(
255 "Failed to create debian changes file " + changesOut, e);
256 }
257
258 try {
259 if (changesSave == null) {
260 return;
261 }
262
263 console.println("Saving changes to file: " + changesSave);
264
265 changesProvider.save(new FileOutputStream(changesSave));
266
267 } catch (Exception e) {
268 throw new PackagingException("Failed to save debian changes file " + changesSave, e);
269 }
270
271 }
272 }