001package org.apache.maven.scm.provider.svn.svnexe.command;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.File;
023import java.io.FileOutputStream;
024import java.io.IOException;
025import java.io.PrintStream;
026import java.util.List;
027
028import org.apache.maven.scm.log.ScmLogger;
029import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
030import org.apache.maven.scm.provider.svn.util.SvnUtil;
031import org.codehaus.plexus.util.Os;
032import org.codehaus.plexus.util.StringUtils;
033import org.codehaus.plexus.util.cli.CommandLineException;
034import org.codehaus.plexus.util.cli.CommandLineUtils;
035import org.codehaus.plexus.util.cli.Commandline;
036import org.codehaus.plexus.util.cli.StreamConsumer;
037
038/**
039 * Command line construction utility.
040 *
041 * @author Brett Porter
042 * @author Olivier Lamy
043 *
044 */
045public final class SvnCommandLineUtils
046{
047    private SvnCommandLineUtils()
048    {
049    }
050
051    public static void addTarget( Commandline cl, List<File> files )
052        throws IOException
053    {
054        if ( files == null || files.isEmpty() )
055        {
056            return;
057        }
058
059        StringBuilder sb = new StringBuilder();
060        String ls = System.getProperty( "line.separator" );
061        for ( File f : files )
062        {
063            sb.append( f.getPath().replace( '\\', '/' ) );
064            sb.append( ls );
065        }
066
067        File targets = File.createTempFile( "maven-scm-", "-targets" );
068        PrintStream out = new PrintStream( new FileOutputStream( targets ) );
069        out.print( sb.toString() );
070        out.flush();
071        out.close();
072
073        cl.createArg().setValue( "--targets" );
074        cl.createArg().setValue( targets.getAbsolutePath() );
075
076        targets.deleteOnExit();
077    }
078
079    public static Commandline getBaseSvnCommandLine( File workingDirectory, SvnScmProviderRepository repository )
080    {
081        Commandline cl = new Commandline();
082
083        cl.setExecutable( "svn" );
084        try
085        {
086            cl.addSystemEnvironment();
087            cl.addEnvironment( "LC_MESSAGES", "C" );
088        }
089        catch ( Exception e )
090        {
091            //Do nothing
092        }
093
094        if ( workingDirectory != null )
095        {
096            cl.setWorkingDirectory( workingDirectory.getAbsolutePath() );
097        }
098
099        if ( !StringUtils.isEmpty( System.getProperty( "maven.scm.svn.config_directory" ) ) )
100        {
101            cl.createArg().setValue( "--config-dir" );
102            cl.createArg().setValue( System.getProperty( "maven.scm.svn.config_directory" ) );
103        }
104        else if ( !StringUtils.isEmpty( SvnUtil.getSettings().getConfigDirectory() ) )
105        {
106            cl.createArg().setValue( "--config-dir" );
107            cl.createArg().setValue( SvnUtil.getSettings().getConfigDirectory() );
108        }
109
110        boolean hasAuthInfo = false; 
111        if ( repository != null && !StringUtils.isEmpty( repository.getUser() ) )
112        {
113            hasAuthInfo = true; 
114            cl.createArg().setValue( "--username" );
115            cl.createArg().setValue( repository.getUser() );
116        }
117
118        if ( repository != null && !StringUtils.isEmpty( repository.getPassword() ) )
119        {
120            hasAuthInfo = true; 
121            cl.createArg().setValue( "--password" );
122            cl.createArg().setValue( repository.getPassword() );
123        }
124
125        // [by Lenik] don't overwrite existing auth cache by default. 
126        if ( hasAuthInfo && !SvnUtil.getSettings().isUseAuthCache() ) 
127        {
128            cl.createArg().setValue( "--no-auth-cache" ); 
129        }
130        
131        if ( SvnUtil.getSettings().isUseNonInteractive() ) {
132            cl.createArg().setValue( "--non-interactive" );
133        }
134        
135        if (SvnUtil.getSettings().isTrustServerCert()) {
136            cl.createArg().setValue( "--trust-server-cert" );
137        }
138
139        return cl;
140    }
141
142    public static int execute( Commandline cl, StreamConsumer consumer, CommandLineUtils.StringStreamConsumer stderr,
143                               ScmLogger logger )
144        throws CommandLineException
145    {
146        // SCM-482: force English resource bundle
147        cl.addEnvironment( "LC_MESSAGES", "en" );
148
149        int exitCode = CommandLineUtils.executeCommandLine( cl, consumer, stderr );
150
151        exitCode = checkIfCleanUpIsNeeded( exitCode, cl, consumer, stderr, logger );
152
153        return exitCode;
154    }
155
156    public static int execute( Commandline cl, CommandLineUtils.StringStreamConsumer stdout,
157                               CommandLineUtils.StringStreamConsumer stderr, ScmLogger logger )
158        throws CommandLineException
159    {
160        int exitCode = CommandLineUtils.executeCommandLine( cl, stdout, stderr );
161
162        exitCode = checkIfCleanUpIsNeeded( exitCode, cl, stdout, stderr, logger );
163
164        return exitCode;
165    }
166
167    private static int checkIfCleanUpIsNeeded( int exitCode, Commandline cl, StreamConsumer consumer,
168                                               CommandLineUtils.StringStreamConsumer stderr, ScmLogger logger )
169        throws CommandLineException
170    {
171        if ( exitCode != 0 && stderr.getOutput() != null && stderr.getOutput().indexOf( "'svn cleanup'" ) > 0
172            && stderr.getOutput().indexOf( "'svn help cleanup'" ) > 0 )
173        {
174            if ( logger.isInfoEnabled() )
175            {
176                logger.info( "Svn command failed due to some locks in working copy. We try to run a 'svn cleanup'." );
177            }
178
179            if ( executeCleanUp( cl.getWorkingDirectory(), consumer, stderr, logger ) == 0 )
180            {
181                exitCode = CommandLineUtils.executeCommandLine( cl, consumer, stderr );
182            }
183        }
184        return exitCode;
185    }
186
187    public static int executeCleanUp( File workinDirectory, StreamConsumer stdout, StreamConsumer stderr )
188        throws CommandLineException
189    {
190        return executeCleanUp( workinDirectory, stdout, stderr, null );
191    }
192
193    public static int executeCleanUp( File workinDirectory, StreamConsumer stdout, StreamConsumer stderr,
194                                      ScmLogger logger )
195        throws CommandLineException
196    {
197        Commandline cl = new Commandline();
198
199        cl.setExecutable( "svn" );
200
201        cl.setWorkingDirectory( workinDirectory.getAbsolutePath() );
202
203        if ( logger != null )
204        {
205            if ( logger.isInfoEnabled() )
206            {
207                logger.info( "Executing: " + SvnCommandLineUtils.cryptPassword( cl ) );
208                logger.info( "Working directory: " + cl.getWorkingDirectory().getAbsolutePath() );
209            }
210        }
211
212        return CommandLineUtils.executeCommandLine( cl, stdout, stderr );
213    }
214
215    public static String cryptPassword( Commandline cl )
216    {
217        String clString = cl.toString();
218
219        int pos = clString.indexOf( "--password" );
220
221        if ( pos > 0 )
222        {
223            String beforePassword = clString.substring( 0, pos + "--password ".length() );
224            String afterPassword = clString.substring( pos + "--password ".length() );
225            afterPassword = afterPassword.substring( afterPassword.indexOf( ' ' ) );
226            if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
227            {
228                clString = beforePassword + "*****" + afterPassword;
229            }
230            else
231            {
232                clString = beforePassword + "'*****'" + afterPassword;
233            }
234        }
235
236        return clString;
237    }
238}