001    /*
002     * Copyright 2005 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.ant;
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.apache.tools.ant.BuildException;
025    import org.apache.tools.ant.taskdefs.MatchingTask;
026    import org.apache.tools.ant.taskdefs.Tar;
027    import org.apache.tools.ant.types.FileSet;
028    import org.vafer.jdeb.Console;
029    import org.vafer.jdeb.DataProducer;
030    import org.vafer.jdeb.Processor;
031    import org.vafer.jdeb.changes.TextfileChangesProvider;
032    import org.vafer.jdeb.descriptors.PackageDescriptor;
033    import org.vafer.jdeb.producers.FileSetDataProducer;
034    
035    /**
036     * AntTask for creating debian archives.
037     * Even supports signed changes files.
038     * 
039     * @author Torsten Curdt <tcurdt@vafer.org>
040     */
041                    
042    public class DebAntTask extends MatchingTask {
043    
044            /** The Debian package produced */
045            private File deb;
046    
047            /** The directory containing the control files to build the package */
048            private File control;
049    
050            /** The file containing the PGP keys */
051            private File keyring;
052    
053            /** The key to use in the keyring */
054            private String key;
055    
056            /** The passphrase for the key to sign the changes file */
057            private String passphrase;
058    
059            /** The file to read the changes from */
060            private File changesIn;
061    
062            /** The file where to write the changes to */
063            private File changesOut;
064    
065            /** The file where to write the changes of the changes input to */
066            private File changesSave;
067    
068            /** The compression method used for the data file (none, gzip or bzip2) */
069            private String compression = "gzip";
070    
071            /** Trigger the verbose mode detailing all operations */
072            private boolean verbose;
073    
074            private Collection dataProducers = new ArrayList();
075    
076    
077            public void setDestfile( File deb ) {
078            this.deb = deb;
079        }
080        
081        public void setControl( File control ) {
082            this.control = control;
083        }
084    
085        public void setChangesIn( File changes ) {
086            this.changesIn = changes;
087        }
088    
089        public void setChangesOut( File changes ) {
090            this.changesOut = changes;
091        }
092    
093        public void setChangesSave( File changes ) {
094            this.changesSave = changes;
095        }
096    
097        public void setKeyring( File keyring ) {
098            this.keyring = keyring;
099        }
100    
101        public void setKey( String key ) {
102            this.key = key;
103        }
104        
105        public void setPassphrase( String passphrase ) {
106            this.passphrase = passphrase;
107        }
108    
109            public void setCompression(String compression) {
110                    this.compression = compression;
111            }
112    
113            public void setVerbose(boolean verbose) {
114                    this.verbose = verbose;
115            }
116    
117            public void addFileSet(FileSet fileset) {
118                    dataProducers.add(new FileSetDataProducer(fileset));
119            }
120    
121            public void addTarFileSet(Tar.TarFileSet fileset) {
122                    dataProducers.add(new FileSetDataProducer(fileset));
123            }
124    
125            public void addData( Data data ) {
126            dataProducers.add(data);
127        }
128        
129        private boolean isPossibleOutput( File file ) {
130    
131            if (file.exists()) {
132                    return file.isFile() && file.canWrite();
133            }
134    
135            return true;
136        }
137        
138            public void execute() {
139                    
140                    if (control == null || !control.isDirectory()) {
141                            throw new BuildException("You need to point the 'control' attribute to the control directory.");
142                    }
143    
144                    if (changesIn != null) {
145                            
146                            if (!changesIn.isFile() || !changesIn.canRead()) {
147                                    throw new BuildException("The 'changesIn' attribute needs to point to a readable file. " + changesIn + " was not found/readable.");                             
148                            }
149    
150                            if (changesOut == null) {
151                                    throw new BuildException("A 'changesIn' without a 'changesOut' does not make much sense.");
152                            }
153                            
154                            if (!isPossibleOutput(changesOut)) {
155                                    throw new BuildException("Cannot write the output for 'changesOut' to " + changesOut);                          
156                            }
157    
158                            if (changesSave != null && !isPossibleOutput(changesSave)) {
159                                    throw new BuildException("Cannot write the output for 'changesSave' to " + changesSave);                                
160                            }
161                            
162                    } else {
163                            if (changesOut != null || changesSave != null) {
164                                    throw new BuildException("The 'changesOut' or 'changesSave' attributes may only be used when there is a 'changesIn' specified.");                                                       
165                            }
166                    }
167    
168                    if (!"gzip".equals(compression) && !"bzip2".equals(compression) && !"none".equals(compression)) {
169                            throw new BuildException("The compression method '" + compression + "' is not supported");
170                    }
171                                    
172                    if (dataProducers.size() == 0) {
173                            throw new BuildException("You need to provide at least one reference to a tgz or directory with data.");
174                    }
175    
176                    if (deb == null) {
177                            throw new BuildException("You need to point the 'destfile' attribute to where the deb is supposed to be created.");
178                    }
179                    
180                    final File[] controlFiles = control.listFiles();
181                    
182                    final DataProducer[] data = new DataProducer[dataProducers.size()];
183                    dataProducers.toArray(data);
184                    
185                    final Processor processor = new Processor(new Console() {
186                            public void println(String s) {
187                                    if (verbose) {
188                                            log(s);
189                                    }
190                            }
191                    }, null);
192                    
193                    final PackageDescriptor packageDescriptor;
194                    try {
195                            
196                            log("Creating debian package: " + deb);
197                            
198                            packageDescriptor = processor.createDeb(controlFiles, data, deb, compression);
199    
200                    } catch (Exception e) {
201                            throw new BuildException("Failed to create debian package " + deb, e);
202                    }
203    
204                    final TextfileChangesProvider changesProvider;
205                    
206                    try {
207                            if (changesOut == null) {
208                                    return;
209                            }
210    
211                            log("Creating changes file: " + changesOut);
212    
213                            // for now only support reading the changes form a textfile provider
214                            changesProvider = new TextfileChangesProvider(new FileInputStream(changesIn), packageDescriptor);
215                            
216                            processor.createChanges(packageDescriptor, changesProvider, (keyring!=null)?new FileInputStream(keyring):null, key, passphrase, new FileOutputStream(changesOut));
217                                                    
218                    } catch (Exception e) {
219                            throw new BuildException("Failed to create debian changes file " + changesOut, e);
220                    }
221    
222                    try {
223                            if (changesSave == null) {
224                                    return;
225                            }
226    
227                            log("Saving changes to file: " + changesSave);
228    
229                            changesProvider.save(new FileOutputStream(changesSave));
230                            
231                    } catch (Exception e) {
232                            throw new BuildException("Failed to save debian changes file " + changesSave, e);
233                    }
234                                    
235            }
236    }