blob: 262b21d4a90dd90c525a41e38ddc5814b20ce5d7 [file] [log] [blame]
package org.apache.maven.shared.release.config;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import java.util.Properties;
import org.apache.maven.model.Scm;
import org.apache.maven.shared.release.config.ReleaseDescriptorBuilder.BuilderReleaseDescriptor;
import org.apache.maven.shared.release.scm.IdentifiedScm;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.util.StringUtils;
import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
import org.sonatype.plexus.components.cipher.PlexusCipherException;
import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException;
import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
/**
* Read and write release configuration and state from a properties file.
*
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
*/
@Component( role = ReleaseDescriptorStore.class, hint = "properties" )
public class PropertiesReleaseDescriptorStore
extends AbstractLogEnabled
implements ReleaseDescriptorStore
{
/**
* When this plugin requires Maven 3.0 as minimum, this component can be removed and o.a.m.s.c.SettingsDecrypter be
* used instead.
*/
@Requirement( role = SecDispatcher.class, hint = "mng-4384" )
private DefaultSecDispatcher secDispatcher;
@Override
public ReleaseDescriptorBuilder read( ReleaseDescriptorBuilder mergeDescriptor )
throws ReleaseDescriptorStoreException
{
return read( mergeDescriptor, getDefaultReleasePropertiesFile( mergeDescriptor.build() ) );
}
public ReleaseDescriptorBuilder read( File file )
throws ReleaseDescriptorStoreException
{
return read( null, file );
}
public ReleaseDescriptorBuilder read( ReleaseDescriptorBuilder mergeDescriptor, File file )
throws ReleaseDescriptorStoreException
{
Properties properties = new Properties();
try ( InputStream inStream = new FileInputStream( file ) )
{
properties.load( inStream );
}
catch ( FileNotFoundException e )
{
getLogger().debug( file.getName() + " not found - using empty properties" );
}
catch ( IOException e )
{
throw new ReleaseDescriptorStoreException(
"Error reading properties file '" + file.getName() + "': " + e.getMessage(), e );
}
ReleaseDescriptorBuilder builder;
if ( mergeDescriptor != null )
{
builder = mergeDescriptor;
}
else
{
builder = new ReleaseDescriptorBuilder();
}
ReleaseUtils.copyPropertiesToReleaseDescriptor( properties, builder );
return builder;
}
@Override
public void write( ReleaseDescriptor config )
throws ReleaseDescriptorStoreException
{
write( (BuilderReleaseDescriptor) config, getDefaultReleasePropertiesFile( config ) );
}
@Override
public void delete( ReleaseDescriptor config )
{
File file = getDefaultReleasePropertiesFile( config );
if ( file.exists() )
{
file.delete();
}
}
public void write( BuilderReleaseDescriptor config, File file )
throws ReleaseDescriptorStoreException
{
Properties properties = new Properties();
properties.setProperty( "completedPhase", config.getCompletedPhase() );
if ( config.isCommitByProject() ) //default is false
{
properties.setProperty( "commitByProject", "true" );
}
properties.setProperty( "scm.url", config.getScmSourceUrl() );
if ( config.getScmId() != null )
{
properties.setProperty( "scm.id", config.getScmId() );
}
if ( config.getScmUsername() != null )
{
properties.setProperty( "scm.username", config.getScmUsername() );
}
if ( config.getScmPassword() != null )
{
String password = config.getScmPassword();
try
{
password = encryptAndDecorate( password );
}
catch ( IllegalStateException | SecDispatcherException | PlexusCipherException e )
{
getLogger().debug( e.getMessage() );
}
properties.setProperty( "scm.password", password );
}
if ( config.getScmPrivateKey() != null )
{
properties.setProperty( "scm.privateKey", config.getScmPrivateKey() );
}
if ( config.getScmPrivateKeyPassPhrase() != null )
{
String passPhrase = config.getScmPrivateKeyPassPhrase();
try
{
passPhrase = encryptAndDecorate( passPhrase );
}
catch ( IllegalStateException | SecDispatcherException | PlexusCipherException e )
{
getLogger().debug( e.getMessage() );
}
properties.setProperty( "scm.passphrase", passPhrase );
}
if ( config.getScmTagBase() != null )
{
properties.setProperty( "scm.tagBase", config.getScmTagBase() );
}
if ( config.getScmBranchBase() != null )
{
properties.setProperty( "scm.branchBase", config.getScmBranchBase() );
}
if ( config.getScmReleaseLabel() != null )
{
properties.setProperty( "scm.tag", config.getScmReleaseLabel() );
}
if ( config.getScmTagNameFormat() != null )
{
properties.setProperty( "scm.tagNameFormat", config.getScmTagNameFormat() );
}
if ( config.getScmCommentPrefix() != null )
{
properties.setProperty( "scm.commentPrefix", config.getScmCommentPrefix() );
}
if ( config.getScmDevelopmentCommitComment() != null )
{
properties.setProperty( "scm.developmentCommitComment", config.getScmDevelopmentCommitComment() );
}
if ( config.getScmReleaseCommitComment() != null )
{
properties.setProperty( "scm.releaseCommitComment", config.getScmReleaseCommitComment() );
}
if ( config.getScmBranchCommitComment() != null )
{
properties.setProperty( "scm.branchCommitComment", config.getScmBranchCommitComment() );
}
if ( config.getScmRollbackCommitComment() != null )
{
properties.setProperty( "scm.rollbackCommitComment", config.getScmRollbackCommitComment() );
}
if ( config.getAdditionalArguments() != null )
{
properties.setProperty( "exec.additionalArguments", config.getAdditionalArguments() );
}
if ( config.getPomFileName() != null )
{
properties.setProperty( "exec.pomFileName", config.getPomFileName() );
}
if ( !config.getActivateProfiles().isEmpty() )
{
properties.setProperty( "exec.activateProfiles",
StringUtils.join( config.getActivateProfiles().iterator(), "," ) );
}
if ( config.getPreparationGoals() != null )
{
properties.setProperty( "preparationGoals", config.getPreparationGoals() );
}
if ( config.getCompletionGoals() != null )
{
properties.setProperty( "completionGoals", config.getCompletionGoals() );
}
if ( config.getProjectVersionPolicyId() != null )
{
properties.setProperty( "projectVersionPolicyId", config.getProjectVersionPolicyId() );
}
if ( config.getProjectNamingPolicyId() != null )
{
properties.setProperty( "projectNamingPolicyId", config.getProjectNamingPolicyId() );
}
if ( config.getReleaseStrategyId() != null )
{
properties.setProperty( "releaseStrategyId", config.getReleaseStrategyId() );
}
properties.setProperty( "exec.snapshotReleasePluginAllowed",
Boolean.toString( config.isSnapshotReleasePluginAllowed() ) );
properties.setProperty( "remoteTagging", Boolean.toString( config.isRemoteTagging() ) );
properties.setProperty( "pushChanges", Boolean.toString( config.isPushChanges() ) );
if ( config.getWorkItem() != null )
{
properties.setProperty( "workItem", config.getWorkItem() );
}
// others boolean properties are not written to the properties file because the value from the caller is always
// used
for ( Map.Entry<String, ReleaseStageVersions> entry : config.getProjectVersions().entrySet() )
{
if ( entry.getValue().getRelease() != null )
{
properties.setProperty( "project.rel." + entry.getKey(), entry.getValue().getRelease() );
}
if ( entry.getValue().getDevelopment() != null )
{
properties.setProperty( "project.dev." + entry.getKey(), entry.getValue().getDevelopment() );
}
}
for ( Map.Entry<String, Scm> entry : config.getOriginalScmInfo().entrySet() )
{
Scm scm = entry.getValue();
String prefix = "project.scm." + entry.getKey();
if ( scm != null )
{
if ( scm.getConnection() != null )
{
properties.setProperty( prefix + ".connection", scm.getConnection() );
}
if ( scm.getDeveloperConnection() != null )
{
properties.setProperty( prefix + ".developerConnection", scm.getDeveloperConnection() );
}
if ( scm.getUrl() != null )
{
properties.setProperty( prefix + ".url", scm.getUrl() );
}
if ( scm.getTag() != null )
{
properties.setProperty( prefix + ".tag", scm.getTag() );
}
if ( scm instanceof IdentifiedScm )
{
IdentifiedScm identifiedScm = (IdentifiedScm) scm;
if ( identifiedScm.getId() != null )
{
properties.setProperty( prefix + ".id", identifiedScm.getId() );
}
}
}
else
{
properties.setProperty( prefix + ".empty", "true" );
}
}
if ( ( config.getResolvedSnapshotDependencies() != null )
&& ( config.getResolvedSnapshotDependencies().size() > 0 ) )
{
processResolvedDependencies( properties, config.getResolvedSnapshotDependencies() );
}
try ( OutputStream outStream = new FileOutputStream( file ) )
{
properties.store( outStream, "release configuration" );
}
catch ( IOException e )
{
throw new ReleaseDescriptorStoreException(
"Error writing properties file '" + file.getName() + "': " + e.getMessage(), e );
}
}
private void processResolvedDependencies( Properties prop, Map<String, ReleaseStageVersions> resolvedDependencies )
{
for ( Map.Entry<String, ReleaseStageVersions> currentEntry : resolvedDependencies.entrySet() )
{
ReleaseStageVersions versionMap = currentEntry.getValue();
prop.setProperty( "dependency." + currentEntry.getKey() + ".release",
versionMap.getRelease() );
prop.setProperty( "dependency." + currentEntry.getKey() + ".development",
versionMap.getDevelopment() );
}
}
private static File getDefaultReleasePropertiesFile( ReleaseDescriptor mergeDescriptor )
{
return new File( mergeDescriptor.getWorkingDirectory(), "release.properties" );
}
// From org.apache.maven.cli.MavenCli.encryption(CliRequest)
private String encryptAndDecorate( String passwd )
throws IllegalStateException, SecDispatcherException, PlexusCipherException
{
String configurationFile = secDispatcher.getConfigurationFile();
if ( configurationFile.startsWith( "~" ) )
{
configurationFile = System.getProperty( "user.home" ) + configurationFile.substring( 1 );
}
String file = System.getProperty( DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile );
String master = null;
SettingsSecurity sec = SecUtil.read( file, true );
if ( sec != null )
{
master = sec.getMaster();
}
if ( master == null )
{
throw new IllegalStateException( "Master password is not set in the setting security file: " + file );
}
DefaultPlexusCipher cipher = new DefaultPlexusCipher();
String masterPasswd = cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION );
return cipher.encryptAndDecorate( passwd, masterPasswd );
}
}