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         String url = scmSpecificUrl;
218 
219         // ----------------------------------------------------------------------
220         // Do some sanity checking of the SVN url
221         // ----------------------------------------------------------------------
222 
223         if ( url.startsWith( "file" ) )
224         {
225             if ( !url.startsWith( "file://" ) )
226             {
227                 result.messages.add( "A svn 'file' url must be on the form 'file://[hostname]/'." );
228 
229                 return result;
230             }
231         }
232         else if ( url.startsWith( "https" ) )
233         {
234             if ( !url.startsWith( "https://" ) )
235             {
236                 result.messages.add( "A svn 'http' url must be on the form 'https://'." );
237 
238                 return result;
239             }
240         }
241         else if ( url.startsWith( "http" ) )
242         {
243             if ( !url.startsWith( "http://" ) )
244             {
245                 result.messages.add( "A svn 'http' url must be on the form 'http://'." );
246 
247                 return result;
248             }
249         }
250         // Support of tunnels: svn+xxx with xxx defined in subversion conf file
251         else if ( url.startsWith( "svn+" ) )
252         {
253             if ( url.indexOf( "://" ) < 0 )
254             {
255                 result.messages.add( "A svn 'svn+xxx' url must be on the form 'svn+xxx://'." );
256 
257                 return result;
258             }
259             else
260             {
261                 String tunnel = url.substring( "svn+".length(), url.indexOf( "://" ) );
262 
263                 //ssh is always an allowed tunnel
264                 if ( !"ssh".equals( tunnel ) )
265                 {
266                     SvnConfigFileReader reader = new SvnConfigFileReader();
267                     if ( SvnUtil.getSettings().getConfigDirectory() != null )
268                     {
269                         reader.setConfigDirectory( new File( SvnUtil.getSettings().getConfigDirectory() ) );
270                     }
271 
272                     if ( StringUtils.isEmpty( reader.getProperty( "tunnels", tunnel ) ) )
273                     {
274                         result.messages.add(
275                             "The tunnel '" + tunnel + "' isn't defined in your subversion configuration file." );
276 
277                         return result;
278                     }
279                 }
280             }
281         }
282         else if ( url.startsWith( "svn" ) )
283         {
284             if ( !url.startsWith( "svn://" ) )
285             {
286                 result.messages.add( "A svn 'svn' url must be on the form 'svn://'." );
287 
288                 return result;
289             }
290         }
291         else
292         {
293             result.messages.add( url + " url isn't a valid svn URL." );
294 
295             return result;
296         }
297 
298         result.repository = new SvnScmProviderRepository( url );
299 
300         return result;
301     }
302 
303     protected abstract SvnCommand getAddCommand();
304 
305     /**
306      * {@inheritDoc}
307      */
308     public AddScmResult add( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
309         throws ScmException
310     {
311         return (AddScmResult) executeCommand( getAddCommand(), repository, fileSet, parameters );
312     }
313 
314     protected abstract SvnCommand getBranchCommand();
315 
316     /**
317      * {@inheritDoc}
318      */
319     protected BranchScmResult branch( ScmProviderRepository repository, ScmFileSet fileSet,
320                                       CommandParameters parameters )
321         throws ScmException
322     {
323         return (BranchScmResult) executeCommand( getBranchCommand(), repository, fileSet, parameters );
324     }
325 
326     protected abstract SvnCommand getChangeLogCommand();
327 
328     /**
329      * {@inheritDoc}
330      */
331     public ChangeLogScmResult changelog( ScmProviderRepository repository, ScmFileSet fileSet,
332                                          CommandParameters parameters )
333         throws ScmException
334     {
335         return (ChangeLogScmResult) executeCommand( getChangeLogCommand(), repository, fileSet, parameters );
336     }
337 
338     protected abstract SvnCommand getCheckInCommand();
339 
340     /**
341      * {@inheritDoc}
342      */
343     public CheckInScmResult checkin( ScmProviderRepository repository, ScmFileSet fileSet,
344                                      CommandParameters parameters )
345         throws ScmException
346     {
347         return (CheckInScmResult) executeCommand( getCheckInCommand(), repository, fileSet, parameters );
348     }
349 
350     protected abstract SvnCommand getCheckOutCommand();
351 
352     /**
353      * {@inheritDoc}
354      */
355     public CheckOutScmResult checkout( ScmProviderRepository repository, ScmFileSet fileSet,
356                                        CommandParameters parameters )
357         throws ScmException
358     {
359         return (CheckOutScmResult) executeCommand( getCheckOutCommand(), repository, fileSet, parameters );
360     }
361 
362     protected abstract SvnCommand getDiffCommand();
363 
364     /**
365      * {@inheritDoc}
366      */
367     public DiffScmResult diff( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
368         throws ScmException
369     {
370         return (DiffScmResult) executeCommand( getDiffCommand(), repository, fileSet, parameters );
371     }
372 
373     protected abstract SvnCommand getExportCommand();
374 
375     /**
376      * {@inheritDoc}
377      */
378     protected ExportScmResult export( ScmProviderRepository repository, ScmFileSet fileSet,
379                                       CommandParameters parameters )
380         throws ScmException
381     {
382         return (ExportScmResult) executeCommand( getExportCommand(), repository, fileSet, parameters );
383     }
384 
385     protected abstract SvnCommand getRemoveCommand();
386 
387     /**
388      * {@inheritDoc}
389      */
390     public RemoveScmResult remove( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
391         throws ScmException
392     {
393         return (RemoveScmResult) executeCommand( getRemoveCommand(), repository, fileSet, parameters );
394     }
395 
396     protected abstract SvnCommand getStatusCommand();
397 
398     /**
399      * {@inheritDoc}
400      */
401     public StatusScmResult status( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
402         throws ScmException
403     {
404         return (StatusScmResult) executeCommand( getStatusCommand(), repository, fileSet, parameters );
405     }
406 
407     protected abstract SvnCommand getTagCommand();
408 
409     /**
410      * {@inheritDoc}
411      */
412     public TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
413         throws ScmException
414     {
415         return (TagScmResult) executeCommand( getTagCommand(), repository, fileSet, parameters );
416     }
417 
418     protected abstract SvnCommand getUntagCommand();
419 
420     /**
421      * {@inheritDoc}
422      */
423     @Override
424     public UntagScmResult untag( ScmRepository repository, ScmFileSet fileSet, CommandParameters parameters )
425         throws ScmException
426     {
427         return (UntagScmResult) executeCommand( getUntagCommand(), repository.getProviderRepository(),
428                                                 fileSet, parameters );
429     }
430 
431     protected abstract SvnCommand getUpdateCommand();
432 
433     /**
434      * {@inheritDoc}
435      */
436     public UpdateScmResult update( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
437         throws ScmException
438     {
439         return (UpdateScmResult) executeCommand( getUpdateCommand(), repository, fileSet, parameters );
440     }
441 
442     protected ScmResult executeCommand( SvnCommand command, ScmProviderRepository repository, ScmFileSet fileSet,
443                                         CommandParameters parameters )
444         throws ScmException
445     {
446         command.setLogger( getLogger() );
447 
448         return command.execute( repository, fileSet, parameters );
449     }
450 
451     protected abstract SvnCommand getListCommand();
452 
453     /**
454      * {@inheritDoc}
455      */
456     public ListScmResult list( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
457         throws ScmException
458     {
459         SvnCommand cmd = getListCommand();
460 
461         return (ListScmResult) executeCommand( cmd, repository, fileSet, parameters );
462     }
463 
464     protected abstract SvnCommand getInfoCommand();
465 
466     public InfoScmResult info( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
467         throws ScmException
468     {
469         SvnCommand cmd = getInfoCommand();
470 
471         return (InfoScmResult) executeCommand( cmd, repository, fileSet, parameters );
472     }
473 
474     /**
475      * {@inheritDoc}
476      */
477     protected BlameScmResult blame( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
478         throws ScmException
479     {
480         SvnCommand cmd = getBlameCommand();
481 
482         return (BlameScmResult) executeCommand( cmd, repository, fileSet, parameters );
483     }
484 
485     protected abstract SvnCommand getBlameCommand();
486 
487     /**
488      * {@inheritDoc}
489      */
490     public MkdirScmResult mkdir( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
491         throws ScmException
492     {
493         SvnCommand cmd = getMkdirCommand();
494 
495         return (MkdirScmResult) executeCommand( cmd, repository, fileSet, parameters );
496     }
497 
498     protected abstract SvnCommand getMkdirCommand();
499 
500     /**
501      * @param repository
502      * @param parameters
503      * @return true if remote url exists
504      * @throws ScmException
505      * @since 1.8
506      */
507     public abstract boolean remoteUrlExist( ScmProviderRepository repository, CommandParameters parameters )
508         throws ScmException;
509 }