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.maven;
017    
018    import java.io.File;
019    import java.io.FileInputStream;
020    import java.io.FileOutputStream;
021    import java.text.ParseException;
022    import java.util.HashMap;
023    import java.util.Map;
024    
025    import org.apache.maven.plugin.MojoExecutionException;
026    import org.apache.maven.project.MavenProjectHelper;
027    import org.apache.tools.tar.TarEntry;
028    import org.vafer.jdeb.Console;
029    import org.vafer.jdeb.DataConsumer;
030    import org.vafer.jdeb.DataProducer;
031    import org.vafer.jdeb.Processor;
032    import org.vafer.jdeb.changes.TextfileChangesProvider;
033    import org.vafer.jdeb.descriptors.PackageDescriptor;
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 deb
042     * @requiresDependencyResolution compile
043     * @execute phase="package"
044     */
045    public final class DebMojo extends AbstractPluginMojo {
046    
047            /**
048         * @component
049         */
050        private MavenProjectHelper projectHelper;
051    
052        /**
053         * Defines the pattern of the name of final artifacts.
054         * Possible substitutions are [[artifactId]] [[version]] [[extension]] and [[groupId]].
055         * 
056         * @parameter expression="${namePattern}" 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        
067        /**
068         * Explicitly defines the path to the control directory. At least the control file is mandatory. 
069         * 
070         * @parameter expression="${controlDir}"
071         */    
072        private File controlDir;
073        
074        /**
075         * Explicitly define the file to read the changes from. 
076         * 
077         * @parameter expression="${changesIn}"
078         */    
079        private File changesIn = null;
080    
081        /**
082         * Explicitly define the file where to write the changes to. 
083         * 
084         * @parameter expression="${changesIn}"
085         */    
086        private File changesOut = null;
087    
088        /**
089         * Explicitly define the file where to write the changes of the changes input to. 
090         * 
091         * @parameter expression="${changesSave}"
092         */    
093        private File changesSave = null;
094        
095        /**
096         * The keyring file. Usually some/path/secring.gpg
097         * 
098         * @parameter expression="${keyring}"
099         */         
100        private File keyring = null;
101    
102        /**
103         * The hex key id to use for signing. 
104         * 
105         * @parameter expression="${key}"
106         */         
107            private String key = null;
108    
109        /**
110         * The passphrase for the key to sign the changes file. 
111         * 
112         * @parameter expression="${passhrase}"
113         */         
114            private String passphrase = null;
115        
116        /**
117         * If not defaultPath is specified this  
118         * 
119         * @parameter expression="${defaultPath}" default-value="/srv/jetty/www"
120         */         
121            private String defaultPath = "/srv/jetty/www";
122    
123            /**
124             * TODO: make configurable
125             */
126            private DataProducer[] dataProducers = null;
127            
128            
129            /**
130         * Main entry point
131         * @throws MojoExecutionException on error
132         */
133        public void execute()
134            throws MojoExecutionException
135        {
136            // expand name pattern
137            final String debName;
138            final String changesName;       
139    
140            final Map variables = new HashMap();
141            variables.put("name", getProject().getName());
142            variables.put("artifactId", getProject().getArtifactId());
143            variables.put("groupId", getProject().getGroupId());
144            variables.put("version", getProject().getVersion().replace('-', '+'));
145            variables.put("description", getProject().getDescription());
146            variables.put("extension", "deb");      
147            final VariableResolver resolver = new MapVariableResolver(variables);
148    
149            try
150            {
151                    debName = Utils.replaceVariables(resolver, namePattern, "[[", "]]"); 
152                    
153                    variables.put("extension", "changes");          
154                    changesName = Utils.replaceVariables(resolver, namePattern, "[[", "]]"); 
155                    }
156            catch (ParseException e)
157            {
158                            throw new MojoExecutionException("Failed parsing artifact name pattern", e);
159                    }
160    
161            // if not specified try to the default
162            if (deb == null)
163            {
164                            deb = new File(buildDirectory, debName);
165            }
166    
167            // if not specified try to the default
168            if (changesIn == null)
169            {
170                    final File f = new File(getProject().getBasedir(), "CHANGES.txt");
171                    if (f.exists() && f.isFile() && f.canRead())
172                    {
173                            changesIn = f;
174                    }
175            }
176            
177            // if not specified try to the default
178            if (changesOut == null)
179            {
180                            changesOut = new File(buildDirectory, changesName);
181            }
182            
183            // if not specified try to the default
184            if (controlDir == null)
185            {
186                    controlDir = new File(getProject().getBasedir(), "src/deb/control");
187                    getLog().info("Using default path to control directory " + controlDir);
188            }
189            
190            // make sure we have at least the mandatory control directory
191            if (!controlDir.exists() || !controlDir.isDirectory())
192            {
193                    throw new MojoExecutionException(controlDir + " needs to be a directory");
194            }
195            
196            // make sure we have at least the mandatory control file
197            final File controlFile = new File(controlDir, "control");
198            if (!controlFile.exists() || !controlFile.isFile() || !controlFile.canRead())
199            {
200                    throw new MojoExecutionException(controlFile + " is mandatory");
201            }
202            
203            final File file = getProject().getArtifact().getFile();
204                    final File[] controlFiles = controlDir.listFiles();
205                    
206                    
207                    if (dataProducers == null)
208                    {
209                            dataProducers = new DataProducer[] { new DataProducer() {
210                            public void produce( final DataConsumer receiver ) {
211                                    try {
212                                            receiver.onEachFile(new FileInputStream(file), new File(new File(defaultPath), file.getName()).getAbsolutePath(), "", "root", 0, "root", 0, TarEntry.DEFAULT_FILE_MODE, file.length());
213                                    } catch (Exception e) {
214                                            getLog().error(e);
215                                    }
216                            }}};
217                    }
218    
219                    
220                    final Processor processor = new Processor(
221                                    new Console()
222                                    {
223                                            public void println( final String s )
224                                            {
225                                                    getLog().info(s);
226                                            }                       
227                                    },
228                                    resolver
229                    );
230                    
231                    final PackageDescriptor packageDescriptor;
232                    try
233                    {
234    
235                            packageDescriptor = processor.createDeb(controlFiles, dataProducers, deb, "gzip");
236    
237                            getLog().info("Attaching created debian archive " + deb);
238                            projectHelper.attachArtifact( getProject(), "deb-archive", deb.getName(), deb );
239                    }
240                    catch (Exception e)
241                    {
242                            getLog().error("Failed to create debian package " + deb, e);
243                            throw new MojoExecutionException("Failed to create debian package " + deb, e);
244                    }       
245    
246                    if (changesIn == null)
247                    {
248                            return;
249                    }
250                    
251                    
252                    final TextfileChangesProvider changesProvider;
253                    
254                    try
255                    {
256    
257                            // for now only support reading the changes form a text file provider
258                            changesProvider = new TextfileChangesProvider(new FileInputStream(changesIn), packageDescriptor);
259                            
260                            processor.createChanges(packageDescriptor, changesProvider, (keyring!=null)?new FileInputStream(keyring):null, key, passphrase, new FileOutputStream(changesOut));
261    
262                            getLog().info("Attaching created debian changes file " + changesOut);
263                            projectHelper.attachArtifact( getProject(), "deb-changes", changesOut.getName(), changesOut );
264                    }
265                    catch (Exception e)
266                    {
267                            getLog().error("Failed to create debian changes file " + changesOut, e);
268                            throw new MojoExecutionException("Failed to create debian changes file " + changesOut, e);
269                    }       
270    
271        
272                    try {
273                            if (changesSave == null) {
274                                    return;
275                            }
276    
277                            changesProvider.save(new FileOutputStream(changesSave));
278    
279                            getLog().info("Saved release information to file " + changesSave);
280                            
281                    } catch (Exception e) {
282                            getLog().error("Failed to save release information to file " + changesSave);
283                            throw new MojoExecutionException("Failed to save release information to file " + changesSave, e);
284                    }    
285        }    
286    
287    }