1 package org.apache.maven.shared.release.config;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.OutputStream;
29 import java.util.Map;
30 import java.util.Properties;
31
32 import org.apache.maven.model.Scm;
33 import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder.BuilderReleaseDescriptor;
34 import org.apache.maven.shared.release.scm.IdentifiedScm;
35 import org.codehaus.plexus.component.annotations.Component;
36 import org.codehaus.plexus.component.annotations.Requirement;
37 import org.codehaus.plexus.logging.AbstractLogEnabled;
38 import org.codehaus.plexus.util.StringUtils;
39 import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
40 import org.sonatype.plexus.components.cipher.PlexusCipherException;
41 import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
42 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
43 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException;
44 import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
45 import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
46
47
48
49
50
51
52 @Component( role = ReleaseDescriptorStore.class, hint = "properties" )
53 public class PropertiesReleaseDescriptorStore
54 extends AbstractLogEnabled
55 implements ReleaseDescriptorStore
56 {
57
58
59
60
61
62 @Requirement( role = SecDispatcher.class, hint = "mng-4384" )
63 private DefaultSecDispatcher secDispatcher;
64
65 @Override
66 public ReleaseDescriptorBuilder read( ReleaseDescriptorBuilder mergeDescriptor )
67 throws ReleaseDescriptorStoreException
68 {
69 return read( mergeDescriptor, getDefaultReleasePropertiesFile( mergeDescriptor.build() ) );
70 }
71
72
73
74
75
76
77
78
79 public ReleaseDescriptorBuilder read( File file )
80 throws ReleaseDescriptorStoreException
81 {
82 return read( null, file );
83 }
84
85
86
87
88
89
90
91
92
93 public ReleaseDescriptorBuilder read( ReleaseDescriptorBuilder mergeDescriptor, File file )
94 throws ReleaseDescriptorStoreException
95 {
96 Properties properties = new Properties();
97
98 try ( InputStream inStream = new FileInputStream( file ) )
99 {
100 properties.load( inStream );
101 }
102 catch ( FileNotFoundException e )
103 {
104 getLogger().debug( file.getName() + " not found - using empty properties" );
105 }
106 catch ( IOException e )
107 {
108 throw new ReleaseDescriptorStoreException(
109 "Error reading properties file '" + file.getName() + "': " + e.getMessage(), e );
110 }
111
112 try
113 {
114 decryptProperties( properties );
115 }
116 catch ( IllegalStateException | SecDispatcherException | PlexusCipherException e )
117 {
118 getLogger().debug( e.getMessage() );
119 }
120
121 ReleaseDescriptorBuilder builder;
122 if ( mergeDescriptor != null )
123 {
124 builder = mergeDescriptor;
125 }
126 else
127 {
128 builder = new ReleaseDescriptorBuilder();
129 }
130
131 ReleaseUtils.copyPropertiesToReleaseDescriptor( properties, builder );
132
133 return builder;
134 }
135
136 @Override
137 public void write( ReleaseDescriptor config )
138 throws ReleaseDescriptorStoreException
139 {
140 write( (BuilderReleaseDescriptor) config, getDefaultReleasePropertiesFile( config ) );
141 }
142
143 @Override
144 public void delete( ReleaseDescriptor config )
145 {
146 File file = getDefaultReleasePropertiesFile( config );
147 if ( file.exists() )
148 {
149 file.delete();
150 }
151 }
152
153
154
155
156
157
158
159
160
161 public void write( BuilderReleaseDescriptor config, File file )
162 throws ReleaseDescriptorStoreException
163 {
164 Properties properties = new Properties();
165 properties.setProperty( "completedPhase", config.getCompletedPhase() );
166 if ( config.isCommitByProject() )
167 {
168 properties.setProperty( "commitByProject", "true" );
169 }
170 properties.setProperty( "scm.url", config.getScmSourceUrl() );
171 if ( config.getScmId() != null )
172 {
173 properties.setProperty( "scm.id", config.getScmId() );
174 }
175 if ( config.getScmUsername() != null )
176 {
177 properties.setProperty( "scm.username", config.getScmUsername() );
178 }
179 if ( config.getScmPassword() != null )
180 {
181 String password = config.getScmPassword();
182 try
183 {
184 password = encryptAndDecorate( password );
185 }
186 catch ( IllegalStateException | SecDispatcherException | PlexusCipherException e )
187 {
188 getLogger().debug( e.getMessage() );
189 }
190 properties.setProperty( "scm.password", password );
191 }
192 if ( config.getScmPrivateKey() != null )
193 {
194 properties.setProperty( "scm.privateKey", config.getScmPrivateKey() );
195 }
196 if ( config.getScmPrivateKeyPassPhrase() != null )
197 {
198 String passPhrase = config.getScmPrivateKeyPassPhrase();
199 try
200 {
201 passPhrase = encryptAndDecorate( passPhrase );
202 }
203 catch ( IllegalStateException | SecDispatcherException | PlexusCipherException e )
204 {
205 getLogger().debug( e.getMessage() );
206 }
207 properties.setProperty( "scm.passphrase", passPhrase );
208 }
209 if ( config.getScmTagBase() != null )
210 {
211 properties.setProperty( "scm.tagBase", config.getScmTagBase() );
212 }
213 if ( config.getScmBranchBase() != null )
214 {
215 properties.setProperty( "scm.branchBase", config.getScmBranchBase() );
216 }
217 if ( config.getScmReleaseLabel() != null )
218 {
219 properties.setProperty( "scm.tag", config.getScmReleaseLabel() );
220 }
221 if ( config.getScmTagNameFormat() != null )
222 {
223 properties.setProperty( "scm.tagNameFormat", config.getScmTagNameFormat() );
224 }
225 if ( config.getScmCommentPrefix() != null )
226 {
227 properties.setProperty( "scm.commentPrefix", config.getScmCommentPrefix() );
228 }
229 if ( config.getScmDevelopmentCommitComment() != null )
230 {
231 properties.setProperty( "scm.developmentCommitComment", config.getScmDevelopmentCommitComment() );
232 }
233 if ( config.getScmReleaseCommitComment() != null )
234 {
235 properties.setProperty( "scm.releaseCommitComment", config.getScmReleaseCommitComment() );
236 }
237 if ( config.getScmBranchCommitComment() != null )
238 {
239 properties.setProperty( "scm.branchCommitComment", config.getScmBranchCommitComment() );
240 }
241 if ( config.getScmRollbackCommitComment() != null )
242 {
243 properties.setProperty( "scm.rollbackCommitComment", config.getScmRollbackCommitComment() );
244 }
245 if ( config.getAdditionalArguments() != null )
246 {
247 properties.setProperty( "exec.additionalArguments", config.getAdditionalArguments() );
248 }
249 if ( config.getPomFileName() != null )
250 {
251 properties.setProperty( "exec.pomFileName", config.getPomFileName() );
252 }
253 if ( !config.getActivateProfiles().isEmpty() )
254 {
255 properties.setProperty( "exec.activateProfiles",
256 StringUtils.join( config.getActivateProfiles().iterator(), "," ) );
257 }
258 if ( config.getPreparationGoals() != null )
259 {
260 properties.setProperty( "preparationGoals", config.getPreparationGoals() );
261 }
262 if ( config.getCompletionGoals() != null )
263 {
264 properties.setProperty( "completionGoals", config.getCompletionGoals() );
265 }
266 if ( config.getProjectVersionPolicyId() != null )
267 {
268 properties.setProperty( "projectVersionPolicyId", config.getProjectVersionPolicyId() );
269 }
270 if ( config.getProjectNamingPolicyId() != null )
271 {
272 properties.setProperty( "projectNamingPolicyId", config.getProjectNamingPolicyId() );
273 }
274 if ( config.getReleaseStrategyId() != null )
275 {
276 properties.setProperty( "releaseStrategyId", config.getReleaseStrategyId() );
277 }
278
279 properties.setProperty( "exec.snapshotReleasePluginAllowed",
280 Boolean.toString( config.isSnapshotReleasePluginAllowed() ) );
281
282 properties.setProperty( "remoteTagging", Boolean.toString( config.isRemoteTagging() ) );
283
284 properties.setProperty( "pinExternals", Boolean.toString( config.isPinExternals() ) );
285
286 properties.setProperty( "pushChanges", Boolean.toString( config.isPushChanges() ) );
287
288 if ( config.getWorkItem() != null )
289 {
290 properties.setProperty( "workItem", config.getWorkItem() );
291 }
292
293 if ( config.getAutoResolveSnapshots() != null )
294 {
295 properties.setProperty( "autoResolveSnapshots", config.getAutoResolveSnapshots() );
296 }
297
298
299
300
301
302 for ( Map.Entry<String, ReleaseStageVersions> entry : config.getProjectVersions().entrySet() )
303 {
304 if ( entry.getValue().getRelease() != null )
305 {
306 properties.setProperty( "project.rel." + entry.getKey(), entry.getValue().getRelease() );
307 }
308 if ( entry.getValue().getDevelopment() != null )
309 {
310 properties.setProperty( "project.dev." + entry.getKey(), entry.getValue().getDevelopment() );
311 }
312 }
313
314 for ( Map.Entry<String, Scm> entry : config.getOriginalScmInfo().entrySet() )
315 {
316 Scm scm = entry.getValue();
317 String prefix = "project.scm." + entry.getKey();
318 if ( scm != null )
319 {
320 if ( scm.getConnection() != null )
321 {
322 properties.setProperty( prefix + ".connection", scm.getConnection() );
323 }
324 if ( scm.getDeveloperConnection() != null )
325 {
326 properties.setProperty( prefix + ".developerConnection", scm.getDeveloperConnection() );
327 }
328 if ( scm.getUrl() != null )
329 {
330 properties.setProperty( prefix + ".url", scm.getUrl() );
331 }
332 if ( scm.getTag() != null )
333 {
334 properties.setProperty( prefix + ".tag", scm.getTag() );
335 }
336 if ( scm instanceof IdentifiedScm )
337 {
338 IdentifiedScm identifiedScm = (IdentifiedScm) scm;
339 if ( identifiedScm.getId() != null )
340 {
341 properties.setProperty( prefix + ".id", identifiedScm.getId() );
342 }
343 }
344 }
345 else
346 {
347 properties.setProperty( prefix + ".empty", "true" );
348 }
349 }
350
351 if ( ( config.getResolvedSnapshotDependencies() != null )
352 && ( config.getResolvedSnapshotDependencies().size() > 0 ) )
353 {
354 processResolvedDependencies( properties, config.getResolvedSnapshotDependencies() );
355 }
356
357 try ( OutputStream outStream = new FileOutputStream( file ) )
358 {
359 properties.store( outStream, "release configuration" );
360 }
361 catch ( IOException e )
362 {
363 throw new ReleaseDescriptorStoreException(
364 "Error writing properties file '" + file.getName() + "': " + e.getMessage(), e );
365 }
366 }
367
368 private void processResolvedDependencies( Properties prop, Map<String, ReleaseStageVersions> resolvedDependencies )
369 {
370 for ( Map.Entry<String, ReleaseStageVersions> currentEntry : resolvedDependencies.entrySet() )
371 {
372 ReleaseStageVersions versionMap = currentEntry.getValue();
373
374 prop.setProperty( "dependency." + currentEntry.getKey() + ".release",
375 versionMap.getRelease() );
376 prop.setProperty( "dependency." + currentEntry.getKey() + ".development",
377 versionMap.getDevelopment() );
378 }
379 }
380
381 private static File getDefaultReleasePropertiesFile( ReleaseDescriptor mergeDescriptor )
382 {
383 return new File( mergeDescriptor.getWorkingDirectory(), "release.properties" );
384 }
385
386 private void decryptProperties( Properties properties )
387 throws IllegalStateException, SecDispatcherException, PlexusCipherException
388 {
389 String[] keys = new String[] { "scm.password", "scm.passphrase" };
390
391 for ( String key : keys )
392 {
393 String value = properties.getProperty( key );
394 if ( value != null )
395 {
396 properties.put( key, decrypt( value ) );
397 }
398 }
399 }
400
401
402 private String encryptAndDecorate( String passwd )
403 throws IllegalStateException, SecDispatcherException, PlexusCipherException
404 {
405 final String master = getMaster();
406
407 DefaultPlexusCipher cipher = new DefaultPlexusCipher();
408 String masterPasswd = cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION );
409 return cipher.encryptAndDecorate( passwd, masterPasswd );
410 }
411
412 private String decrypt( String value ) throws IllegalStateException, SecDispatcherException, PlexusCipherException
413 {
414 final String master = getMaster();
415
416 DefaultPlexusCipher cipher = new DefaultPlexusCipher();
417 String masterPasswd = cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION );
418 return cipher.decryptDecorated( value, masterPasswd );
419 }
420
421 private String getMaster() throws SecDispatcherException
422 {
423 String configurationFile = secDispatcher.getConfigurationFile();
424
425 if ( configurationFile.startsWith( "~" ) )
426 {
427 configurationFile = System.getProperty( "user.home" ) + configurationFile.substring( 1 );
428 }
429
430 String file = System.getProperty( DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile );
431
432 String master = null;
433
434 SettingsSecurity sec = SecUtil.read( file, true );
435 if ( sec != null )
436 {
437 master = sec.getMaster();
438 }
439
440 if ( master == null )
441 {
442 throw new IllegalStateException( "Master password is not set in the setting security file: " + file );
443 }
444
445 return master;
446 }
447
448 }