View Javadoc
1   package org.apache.maven.shared.release.config;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import javax.inject.Inject;
23  import javax.inject.Named;
24  import javax.inject.Singleton;
25  
26  import java.io.File;
27  import java.io.FileInputStream;
28  import java.io.FileNotFoundException;
29  import java.io.FileOutputStream;
30  import java.io.IOException;
31  import java.io.InputStream;
32  import java.io.OutputStream;
33  import java.util.Map;
34  import java.util.Properties;
35  
36  import org.apache.maven.model.Scm;
37  import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder.BuilderReleaseDescriptor;
38  import org.apache.maven.shared.release.scm.IdentifiedScm;
39  import org.apache.maven.shared.release.util.MavenCrypto;
40  import org.apache.maven.shared.release.util.MavenCrypto.MavenCryptoException;
41  import org.codehaus.plexus.util.StringUtils;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  import static java.util.Objects.requireNonNull;
46  
47  /**
48   * Read and write release configuration and state from a properties file.
49   *
50   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
51   */
52  @Singleton
53  @Named( "properties" )
54  public class PropertiesReleaseDescriptorStore
55          implements ReleaseDescriptorStore
56  {
57      private final Logger logger = LoggerFactory.getLogger( getClass() );
58  
59      private final MavenCrypto mavenCrypto;
60  
61      @Inject
62      public PropertiesReleaseDescriptorStore( MavenCrypto mavenCrypto )
63      {
64          this.mavenCrypto = requireNonNull( mavenCrypto );
65      }
66  
67      @Override
68      public ReleaseDescriptorBuilder read( ReleaseDescriptorBuilder mergeDescriptor )
69              throws ReleaseDescriptorStoreException
70      {
71          return read( mergeDescriptor, getDefaultReleasePropertiesFile( mergeDescriptor.build() ) );
72      }
73  
74      /**
75       * <p>read.</p>
76       *
77       * @param file a {@link java.io.File} object
78       * @return a {@link org.apache.maven.shared.release.config.ReleaseDescriptorBuilder} object
79       * @throws org.apache.maven.shared.release.config.ReleaseDescriptorStoreException if any.
80       */
81      public ReleaseDescriptorBuilder read( File file )
82              throws ReleaseDescriptorStoreException
83      {
84          return read( null, file );
85      }
86  
87      /**
88       * <p>read.</p>
89       *
90       * @param mergeDescriptor a {@link org.apache.maven.shared.release.config.ReleaseDescriptorBuilder} object
91       * @param file            a {@link java.io.File} object
92       * @return a {@link org.apache.maven.shared.release.config.ReleaseDescriptorBuilder} object
93       * @throws org.apache.maven.shared.release.config.ReleaseDescriptorStoreException if any.
94       */
95      public ReleaseDescriptorBuilder read( ReleaseDescriptorBuilder mergeDescriptor, File file )
96              throws ReleaseDescriptorStoreException
97      {
98          Properties properties = new Properties();
99  
100         try ( InputStream inStream = new FileInputStream( file ) )
101         {
102             properties.load( inStream );
103         }
104         catch ( FileNotFoundException e )
105         {
106             logger.debug( file.getName() + " not found - using empty properties" );
107         }
108         catch ( IOException e )
109         {
110             throw new ReleaseDescriptorStoreException(
111                     "Error reading properties file '" + file.getName() + "': " + e.getMessage(), e );
112         }
113 
114         try
115         {
116             mavenCrypto.decryptProperties( properties );
117         }
118         catch ( MavenCryptoException e )
119         {
120             logger.debug( e.getMessage() );
121         }
122 
123         ReleaseDescriptorBuilder builder;
124         if ( mergeDescriptor != null )
125         {
126             builder = mergeDescriptor;
127         }
128         else
129         {
130             builder = new ReleaseDescriptorBuilder();
131         }
132 
133         ReleaseUtils.copyPropertiesToReleaseDescriptor( properties, builder );
134 
135         return builder;
136     }
137 
138     @Override
139     public void write( ReleaseDescriptor config )
140             throws ReleaseDescriptorStoreException
141     {
142         write( (BuilderReleaseDescriptor) config, getDefaultReleasePropertiesFile( config ) );
143     }
144 
145     @Override
146     public void delete( ReleaseDescriptor config )
147     {
148         File file = getDefaultReleasePropertiesFile( config );
149         if ( file.exists() )
150         {
151             file.delete();
152         }
153     }
154 
155     /**
156      * <p>write.</p>
157      *
158      * @param config a {@link org.apache.maven.shared.release.config.ReleaseDescriptorBuilder.BuilderReleaseDescriptor}
159      *               object
160      * @param file   a {@link java.io.File} object
161      * @throws org.apache.maven.shared.release.config.ReleaseDescriptorStoreException if any.
162      */
163     public void write( BuilderReleaseDescriptor config, File file )
164             throws ReleaseDescriptorStoreException
165     {
166         Properties properties = new Properties();
167         properties.setProperty( "completedPhase", config.getCompletedPhase() );
168         if ( config.isCommitByProject() ) //default is false
169         {
170             properties.setProperty( "commitByProject", "true" );
171         }
172         properties.setProperty( "scm.url", config.getScmSourceUrl() );
173         if ( config.getScmId() != null )
174         {
175             properties.setProperty( "scm.id", config.getScmId() );
176         }
177         if ( config.getScmUsername() != null )
178         {
179             properties.setProperty( "scm.username", config.getScmUsername() );
180         }
181         if ( config.getScmPassword() != null )
182         {
183             String password = config.getScmPassword();
184             try
185             {
186                 password = mavenCrypto.encryptAndDecorate( password );
187             }
188             catch ( MavenCryptoException e )
189             {
190                 logger.debug( e.getMessage() );
191             }
192             properties.setProperty( "scm.password", password );
193         }
194         if ( config.getScmPrivateKey() != null )
195         {
196             properties.setProperty( "scm.privateKey", config.getScmPrivateKey() );
197         }
198         if ( config.getScmPrivateKeyPassPhrase() != null )
199         {
200             String passPhrase = config.getScmPrivateKeyPassPhrase();
201             try
202             {
203                 passPhrase = mavenCrypto.encryptAndDecorate( passPhrase );
204             }
205             catch ( MavenCryptoException e )
206             {
207                 logger.debug( e.getMessage() );
208             }
209             properties.setProperty( "scm.passphrase", passPhrase );
210         }
211         if ( config.getScmTagBase() != null )
212         {
213             properties.setProperty( "scm.tagBase", config.getScmTagBase() );
214         }
215         if ( config.getScmBranchBase() != null )
216         {
217             properties.setProperty( "scm.branchBase", config.getScmBranchBase() );
218         }
219         if ( config.getScmReleaseLabel() != null )
220         {
221             properties.setProperty( "scm.tag", config.getScmReleaseLabel() );
222         }
223         if ( config.getScmTagNameFormat() != null )
224         {
225             properties.setProperty( "scm.tagNameFormat", config.getScmTagNameFormat() );
226         }
227         if ( config.getScmCommentPrefix() != null )
228         {
229             properties.setProperty( "scm.commentPrefix", config.getScmCommentPrefix() );
230         }
231         if ( config.getScmDevelopmentCommitComment() != null )
232         {
233             properties.setProperty( "scm.developmentCommitComment", config.getScmDevelopmentCommitComment() );
234         }
235         if ( config.getScmReleaseCommitComment() != null )
236         {
237             properties.setProperty( "scm.releaseCommitComment", config.getScmReleaseCommitComment() );
238         }
239         if ( config.getScmBranchCommitComment() != null )
240         {
241             properties.setProperty( "scm.branchCommitComment", config.getScmBranchCommitComment() );
242         }
243         if ( config.getScmRollbackCommitComment() != null )
244         {
245             properties.setProperty( "scm.rollbackCommitComment", config.getScmRollbackCommitComment() );
246         }
247         if ( config.getAdditionalArguments() != null )
248         {
249             properties.setProperty( "exec.additionalArguments", config.getAdditionalArguments() );
250         }
251         if ( config.getPomFileName() != null )
252         {
253             properties.setProperty( "exec.pomFileName", config.getPomFileName() );
254         }
255         if ( !config.getActivateProfiles().isEmpty() )
256         {
257             properties.setProperty( "exec.activateProfiles",
258                     StringUtils.join( config.getActivateProfiles().iterator(), "," ) );
259         }
260         if ( config.getPreparationGoals() != null )
261         {
262             properties.setProperty( "preparationGoals", config.getPreparationGoals() );
263         }
264         if ( config.getCompletionGoals() != null )
265         {
266             properties.setProperty( "completionGoals", config.getCompletionGoals() );
267         }
268         if ( config.getProjectVersionPolicyId() != null )
269         {
270             properties.setProperty( "projectVersionPolicyId", config.getProjectVersionPolicyId() );
271         }
272         if ( config.getProjectNamingPolicyId() != null )
273         {
274             properties.setProperty( "projectNamingPolicyId", config.getProjectNamingPolicyId() );
275         }
276         if ( config.getReleaseStrategyId() != null )
277         {
278             properties.setProperty( "releaseStrategyId", config.getReleaseStrategyId() );
279         }
280 
281         properties.setProperty( "exec.snapshotReleasePluginAllowed",
282                 Boolean.toString( config.isSnapshotReleasePluginAllowed() ) );
283 
284         properties.setProperty( "remoteTagging", Boolean.toString( config.isRemoteTagging() ) );
285 
286         properties.setProperty( "pinExternals", Boolean.toString( config.isPinExternals() ) );
287 
288         properties.setProperty( "pushChanges", Boolean.toString( config.isPushChanges() ) );
289 
290         if ( config.getWorkItem() != null )
291         {
292             properties.setProperty( "workItem", config.getWorkItem() );
293         }
294 
295         if ( config.getAutoResolveSnapshots() != null )
296         {
297             properties.setProperty( "autoResolveSnapshots", config.getAutoResolveSnapshots() );
298         }
299 
300         // others boolean properties are not written to the properties file because the value from the caller is always
301         // used
302 
303 
304         for ( Map.Entry<String, ReleaseStageVersions> entry : config.getProjectVersions().entrySet() )
305         {
306             if ( entry.getValue().getRelease() != null )
307             {
308                 properties.setProperty( "project.rel." + entry.getKey(), entry.getValue().getRelease() );
309             }
310             if ( entry.getValue().getDevelopment() != null )
311             {
312                 properties.setProperty( "project.dev." + entry.getKey(), entry.getValue().getDevelopment() );
313             }
314         }
315 
316         for ( Map.Entry<String, Scm> entry : config.getOriginalScmInfo().entrySet() )
317         {
318             Scm scm = entry.getValue();
319             String prefix = "project.scm." + entry.getKey();
320             if ( scm != null )
321             {
322                 if ( scm.getConnection() != null )
323                 {
324                     properties.setProperty( prefix + ".connection", scm.getConnection() );
325                 }
326                 if ( scm.getDeveloperConnection() != null )
327                 {
328                     properties.setProperty( prefix + ".developerConnection", scm.getDeveloperConnection() );
329                 }
330                 if ( scm.getUrl() != null )
331                 {
332                     properties.setProperty( prefix + ".url", scm.getUrl() );
333                 }
334                 if ( scm.getTag() != null )
335                 {
336                     properties.setProperty( prefix + ".tag", scm.getTag() );
337                 }
338                 if ( scm instanceof IdentifiedScm )
339                 {
340                     IdentifiedScm identifiedScm = (IdentifiedScm) scm;
341                     if ( identifiedScm.getId() != null )
342                     {
343                         properties.setProperty( prefix + ".id", identifiedScm.getId() );
344                     }
345                 }
346             }
347             else
348             {
349                 properties.setProperty( prefix + ".empty", "true" );
350             }
351         }
352 
353         if ( ( config.getResolvedSnapshotDependencies() != null )
354                 && ( config.getResolvedSnapshotDependencies().size() > 0 ) )
355         {
356             processResolvedDependencies( properties, config.getResolvedSnapshotDependencies() );
357         }
358 
359         try ( OutputStream outStream = new FileOutputStream( file ) )
360         {
361             properties.store( outStream, "release configuration" );
362         }
363         catch ( IOException e )
364         {
365             throw new ReleaseDescriptorStoreException(
366                     "Error writing properties file '" + file.getName() + "': " + e.getMessage(), e );
367         }
368     }
369 
370     private void processResolvedDependencies( Properties prop, Map<String, ReleaseStageVersions> resolvedDependencies )
371     {
372         for ( Map.Entry<String, ReleaseStageVersions> currentEntry : resolvedDependencies.entrySet() )
373         {
374             ReleaseStageVersions versionMap = currentEntry.getValue();
375 
376             prop.setProperty( "dependency." + currentEntry.getKey() + ".release",
377                     versionMap.getRelease() );
378             prop.setProperty( "dependency." + currentEntry.getKey() + ".development",
379                     versionMap.getDevelopment() );
380         }
381     }
382 
383     private static File getDefaultReleasePropertiesFile( ReleaseDescriptor mergeDescriptor )
384     {
385         return new File( mergeDescriptor.getWorkingDirectory(), "release.properties" );
386     }
387 }