View Javadoc
1   package org.apache.maven.scm.provider.svn;
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 java.io.File;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.maven.scm.CommandParameters;
27  import org.apache.maven.scm.ScmException;
28  import org.apache.maven.scm.ScmFileSet;
29  import org.apache.maven.scm.ScmResult;
30  import org.apache.maven.scm.command.add.AddScmResult;
31  import org.apache.maven.scm.command.blame.BlameScmResult;
32  import org.apache.maven.scm.command.branch.BranchScmResult;
33  import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
34  import org.apache.maven.scm.command.checkin.CheckInScmResult;
35  import org.apache.maven.scm.command.checkout.CheckOutScmResult;
36  import org.apache.maven.scm.command.diff.DiffScmResult;
37  import org.apache.maven.scm.command.export.ExportScmResult;
38  import org.apache.maven.scm.command.info.InfoItem;
39  import org.apache.maven.scm.command.info.InfoScmResult;
40  import org.apache.maven.scm.command.list.ListScmResult;
41  import org.apache.maven.scm.command.mkdir.MkdirScmResult;
42  import org.apache.maven.scm.command.remove.RemoveScmResult;
43  import org.apache.maven.scm.command.status.StatusScmResult;
44  import org.apache.maven.scm.command.tag.TagScmResult;
45  import org.apache.maven.scm.command.untag.UntagScmResult;
46  import org.apache.maven.scm.command.update.UpdateScmResult;
47  import org.apache.maven.scm.provider.AbstractScmProvider;
48  import org.apache.maven.scm.provider.ScmProviderRepository;
49  import org.apache.maven.scm.provider.svn.command.SvnCommand;
50  import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
51  import org.apache.maven.scm.provider.svn.util.SvnUtil;
52  import org.apache.maven.scm.repository.ScmRepository;
53  import org.apache.maven.scm.repository.ScmRepositoryException;
54  import org.apache.maven.scm.repository.UnknownRepositoryStructure;
55  import org.codehaus.plexus.util.StringUtils;
56  
57  /**
58   * SCM Provider for Subversion
59   *
60   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
61   *
62   */
63  public abstract class AbstractSvnScmProvider
64      extends AbstractScmProvider
65  {
66      // ----------------------------------------------------------------------
67      //
68      // ----------------------------------------------------------------------
69  
70      private static class ScmUrlParserResult
71      {
72          private List<String> messages = new ArrayList<String>();
73  
74          private ScmProviderRepository repository;
75      }
76  
77      public static final String CURRENT_WORKING_DIRECTORY = "scmCheckWorkingDirectoryUrl.currentWorkingDirectory";
78  
79      // ----------------------------------------------------------------------
80      // ScmProvider Implementation
81      // ----------------------------------------------------------------------
82  
83      /**
84       * {@inheritDoc}
85       */
86      public String getScmSpecificFilename()
87      {
88          return ".svn";
89      }
90  
91      /**
92       * {@inheritDoc}
93       */
94      public ScmProviderRepository makeProviderScmRepository( String scmSpecificUrl, char delimiter )
95          throws ScmRepositoryException
96      {
97          ScmUrlParserResult result = parseScmUrl( scmSpecificUrl );
98  
99          if ( checkCurrentWorkingDirectoryUrl() )
100         {
101             getLogger().debug( "Checking svn info 'URL:' field matches current sources directory" );
102             try
103             {
104                 String workingDir = System.getProperty( CURRENT_WORKING_DIRECTORY );
105                 InfoScmResult info =
106                     info( result.repository, new ScmFileSet( new File( workingDir ) ), new CommandParameters() );
107 
108                 String url = findUrlInfoItem( info );
109                 String comparison = "'" + url + "' vs. '" + scmSpecificUrl + "'";
110                 getLogger().debug( "Comparing : " + comparison );
111                 if ( url != null && !url.equals( scmSpecificUrl ) )
112                 {
113                     result.messages.add( "Scm url does not match the value returned by svn info (" + comparison + ")" );
114                 }
115             }
116             catch ( ScmException e )
117             {
118                 throw new ScmRepositoryException( "An error occurred while trying to svn info", e );
119             }
120         }
121         if ( result.messages.size() > 0 )
122         {
123             throw new ScmRepositoryException( "The scm url is invalid.", result.messages );
124         }
125 
126 
127         return result.repository;
128     }
129 
130     private boolean checkCurrentWorkingDirectoryUrl()
131     {
132         return StringUtils.isNotEmpty( System.getProperty( CURRENT_WORKING_DIRECTORY ) );
133     }
134 
135     private String findUrlInfoItem( InfoScmResult infoScmResult )
136     {
137         for ( InfoItem infoItem : infoScmResult.getInfoItems() )
138         {
139             if ( infoItem.getURL() != null )
140             {
141                 getLogger().debug( "URL found: " + infoItem.getURL() );
142                 return infoItem.getURL();
143             }
144         }
145         getLogger().debug( "URL not found (command output=" + infoScmResult.getCommandOutput() + ")" );
146         return null;
147     }
148 
149     /**
150      * {@inheritDoc}
151      */
152     public ScmProviderRepository makeProviderScmRepository( File path )
153         throws ScmRepositoryException, UnknownRepositoryStructure
154     {
155         if ( path == null )
156         {
157             throw new NullPointerException( "Path argument is null" );
158         }
159 
160         if ( !path.isDirectory() )
161         {
162             throw new ScmRepositoryException( path.getAbsolutePath() + " isn't a valid directory." );
163         }
164 
165         if ( !new File( path, ".svn" ).exists() )
166         {
167             throw new ScmRepositoryException( path.getAbsolutePath() + " isn't a svn checkout directory." );
168         }
169 
170         try
171         {
172             return makeProviderScmRepository( getRepositoryURL( path ), ':' );
173         }
174         catch ( ScmException e )
175         {
176             // XXX We should allow throwing of SCMException.
177             throw new ScmRepositoryException( "Error executing info command", e );
178         }
179     }
180 
181     protected abstract String getRepositoryURL( File path )
182         throws ScmException;
183 
184     /**
185      * {@inheritDoc}
186      */
187     public List<String> validateScmUrl( String scmSpecificUrl, char delimiter )
188     {
189         List<String> messages = new ArrayList<String>();
190         try
191         {
192             makeProviderScmRepository( scmSpecificUrl, delimiter );
193         }
194         catch ( ScmRepositoryException e )
195         {
196             messages = e.getValidationMessages();
197         }
198         return messages;
199     }
200 
201     /**
202      * {@inheritDoc}
203      */
204     public String getScmType()
205     {
206         return "svn";
207     }
208 
209     // ----------------------------------------------------------------------
210     //
211     // ----------------------------------------------------------------------
212 
213     private ScmUrlParserResult parseScmUrl( String scmSpecificUrl )
214     {
215         ScmUrlParserResult result = new ScmUrlParserResult();
216 
217         // ----------------------------------------------------------------------
218         // Do some sanity checking of the SVN url
219         // ----------------------------------------------------------------------
220 
221         if ( scmSpecificUrl.startsWith( "file" ) )
222         {
223             if ( !scmSpecificUrl.startsWith( "file://" ) )
224             {
225                 result.messages.add( "A svn 'file' url must be on the form 'file://[hostname]/'." );
226 
227                 return result;
228             }
229         }
230         else if ( scmSpecificUrl.startsWith( "https" ) )
231         {
232             if ( !scmSpecificUrl.startsWith( "https://" ) )
233             {
234                 result.messages.add( "A svn 'http' url must be on the form 'https://'." );
235 
236                 return result;
237             }
238         }
239         else if ( scmSpecificUrl.startsWith( "http" ) )
240         {
241             if ( !scmSpecificUrl.startsWith( "http://" ) )
242             {
243                 result.messages.add( "A svn 'http' url must be on the form 'http://'." );
244 
245                 return result;
246             }
247         }
248         // Support of tunnels: svn+xxx with xxx defined in subversion conf file
249         else if ( scmSpecificUrl.startsWith( "svn+" ) )
250         {
251             if ( scmSpecificUrl.indexOf( "://" ) < 0 )
252             {
253                 result.messages.add( "A svn 'svn+xxx' url must be on the form 'svn+xxx://'." );
254 
255                 return result;
256             }
257             else
258             {
259                 String tunnel = scmSpecificUrl.substring( "svn+".length(), scmSpecificUrl.indexOf( "://" ) );
260 
261                 //ssh is always an allowed tunnel
262                 if ( !"ssh".equals( tunnel ) )
263                 {
264                     SvnConfigFileReader reader = new SvnConfigFileReader();
265                     if ( SvnUtil.getSettings().getConfigDirectory() != null )
266                     {
267                         reader.setConfigDirectory( new File( SvnUtil.getSettings().getConfigDirectory() ) );
268                     }
269 
270                     if ( StringUtils.isEmpty( reader.getProperty( "tunnels", tunnel ) ) )
271                     {
272                         result.messages.add(
273                             "The tunnel '" + tunnel + "' isn't defined in your subversion configuration file." );
274 
275                         return result;
276                     }
277                 }
278             }
279         }
280         else if ( scmSpecificUrl.startsWith( "svn" ) )
281         {
282             if ( !scmSpecificUrl.startsWith( "svn://" ) )
283             {
284                 result.messages.add( "A svn 'svn' url must be on the form 'svn://'." );
285 
286                 return result;
287             }
288         }
289         else
290         {
291             result.messages.add( scmSpecificUrl + " url isn't a valid svn URL." );
292 
293             return result;
294         }
295 
296         result.repository = new SvnScmProviderRepository( scmSpecificUrl );
297 
298         return result;
299     }
300 
301     protected abstract SvnCommand getAddCommand();
302 
303     /**
304      * {@inheritDoc}
305      */
306     public AddScmResult add( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
307         throws ScmException
308     {
309         return (AddScmResult) executeCommand( getAddCommand(), repository, fileSet, parameters );
310     }
311 
312     protected abstract SvnCommand getBranchCommand();
313 
314     /**
315      * {@inheritDoc}
316      */
317     protected BranchScmResult branch( ScmProviderRepository repository, ScmFileSet fileSet,
318                                       CommandParameters parameters )
319         throws ScmException
320     {
321         return (BranchScmResult) executeCommand( getBranchCommand(), repository, fileSet, parameters );
322     }
323 
324     protected abstract SvnCommand getChangeLogCommand();
325 
326     /**
327      * {@inheritDoc}
328      */
329     public ChangeLogScmResult changelog( ScmProviderRepository repository, ScmFileSet fileSet,
330                                          CommandParameters parameters )
331         throws ScmException
332     {
333         return (ChangeLogScmResult) executeCommand( getChangeLogCommand(), repository, fileSet, parameters );
334     }
335 
336     protected abstract SvnCommand getCheckInCommand();
337 
338     /**
339      * {@inheritDoc}
340      */
341     public CheckInScmResult checkin( ScmProviderRepository repository, ScmFileSet fileSet,
342                                      CommandParameters parameters )
343         throws ScmException
344     {
345         return (CheckInScmResult) executeCommand( getCheckInCommand(), repository, fileSet, parameters );
346     }
347 
348     protected abstract SvnCommand getCheckOutCommand();
349 
350     /**
351      * {@inheritDoc}
352      */
353     public CheckOutScmResult checkout( ScmProviderRepository repository, ScmFileSet fileSet,
354                                        CommandParameters parameters )
355         throws ScmException
356     {
357         return (CheckOutScmResult) executeCommand( getCheckOutCommand(), repository, fileSet, parameters );
358     }
359 
360     protected abstract SvnCommand getDiffCommand();
361 
362     /**
363      * {@inheritDoc}
364      */
365     public DiffScmResult diff( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
366         throws ScmException
367     {
368         return (DiffScmResult) executeCommand( getDiffCommand(), repository, fileSet, parameters );
369     }
370 
371     protected abstract SvnCommand getExportCommand();
372 
373     /**
374      * {@inheritDoc}
375      */
376     protected ExportScmResult export( ScmProviderRepository repository, ScmFileSet fileSet,
377                                       CommandParameters parameters )
378         throws ScmException
379     {
380         return (ExportScmResult) executeCommand( getExportCommand(), repository, fileSet, parameters );
381     }
382 
383     protected abstract SvnCommand getRemoveCommand();
384 
385     /**
386      * {@inheritDoc}
387      */
388     public RemoveScmResult remove( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
389         throws ScmException
390     {
391         return (RemoveScmResult) executeCommand( getRemoveCommand(), repository, fileSet, parameters );
392     }
393 
394     protected abstract SvnCommand getStatusCommand();
395 
396     /**
397      * {@inheritDoc}
398      */
399     public StatusScmResult status( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
400         throws ScmException
401     {
402         return (StatusScmResult) executeCommand( getStatusCommand(), repository, fileSet, parameters );
403     }
404 
405     protected abstract SvnCommand getTagCommand();
406 
407     /**
408      * {@inheritDoc}
409      */
410     public TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
411         throws ScmException
412     {
413         return (TagScmResult) executeCommand( getTagCommand(), repository, fileSet, parameters );
414     }
415 
416     protected abstract SvnCommand getUntagCommand();
417 
418     /**
419      * {@inheritDoc}
420      */
421     @Override
422     public UntagScmResult untag( ScmRepository repository, ScmFileSet fileSet, CommandParameters parameters )
423         throws ScmException
424     {
425         return (UntagScmResult) executeCommand( getUntagCommand(), repository.getProviderRepository(),
426                                                 fileSet, parameters );
427     }
428 
429     protected abstract SvnCommand getUpdateCommand();
430 
431     /**
432      * {@inheritDoc}
433      */
434     public UpdateScmResult update( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
435         throws ScmException
436     {
437         return (UpdateScmResult) executeCommand( getUpdateCommand(), repository, fileSet, parameters );
438     }
439 
440     protected ScmResult executeCommand( SvnCommand command, ScmProviderRepository repository, ScmFileSet fileSet,
441                                         CommandParameters parameters )
442         throws ScmException
443     {
444         command.setLogger( getLogger() );
445 
446         return command.execute( repository, fileSet, parameters );
447     }
448 
449     protected abstract SvnCommand getListCommand();
450 
451     /**
452      * {@inheritDoc}
453      */
454     public ListScmResult list( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
455         throws ScmException
456     {
457         SvnCommand cmd = getListCommand();
458 
459         return (ListScmResult) executeCommand( cmd, repository, fileSet, parameters );
460     }
461 
462     protected abstract SvnCommand getInfoCommand();
463 
464     public InfoScmResult info( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
465         throws ScmException
466     {
467         SvnCommand cmd = getInfoCommand();
468 
469         return (InfoScmResult) executeCommand( cmd, repository, fileSet, parameters );
470     }
471 
472     /**
473      * {@inheritDoc}
474      */
475     protected BlameScmResult blame( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
476         throws ScmException
477     {
478         SvnCommand cmd = getBlameCommand();
479 
480         return (BlameScmResult) executeCommand( cmd, repository, fileSet, parameters );
481     }
482 
483     protected abstract SvnCommand getBlameCommand();
484 
485     /**
486      * {@inheritDoc}
487      */
488     public MkdirScmResult mkdir( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
489         throws ScmException
490     {
491         SvnCommand cmd = getMkdirCommand();
492 
493         return (MkdirScmResult) executeCommand( cmd, repository, fileSet, parameters );
494     }
495 
496     protected abstract SvnCommand getMkdirCommand();
497 
498     /**
499      * @param repository
500      * @param parameters
501      * @return true if remote url exists
502      * @throws ScmException
503      * @since 1.8
504      */
505     public abstract boolean remoteUrlExist( ScmProviderRepository repository, CommandParameters parameters )
506         throws ScmException;
507 }