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    }