001 package org.apache.maven.scm.provider.svn;
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
022 import org.apache.maven.scm.CommandParameters;
023 import org.apache.maven.scm.ScmException;
024 import org.apache.maven.scm.ScmFileSet;
025 import org.apache.maven.scm.ScmResult;
026 import org.apache.maven.scm.command.add.AddScmResult;
027 import org.apache.maven.scm.command.blame.BlameScmResult;
028 import org.apache.maven.scm.command.branch.BranchScmResult;
029 import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
030 import org.apache.maven.scm.command.checkin.CheckInScmResult;
031 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
032 import org.apache.maven.scm.command.diff.DiffScmResult;
033 import org.apache.maven.scm.command.export.ExportScmResult;
034 import org.apache.maven.scm.command.info.InfoScmResult;
035 import org.apache.maven.scm.command.list.ListScmResult;
036 import org.apache.maven.scm.command.mkdir.MkdirScmResult;
037 import org.apache.maven.scm.command.remove.RemoveScmResult;
038 import org.apache.maven.scm.command.status.StatusScmResult;
039 import org.apache.maven.scm.command.tag.TagScmResult;
040 import org.apache.maven.scm.command.update.UpdateScmResult;
041 import org.apache.maven.scm.provider.AbstractScmProvider;
042 import org.apache.maven.scm.provider.ScmProviderRepository;
043 import org.apache.maven.scm.provider.svn.command.SvnCommand;
044 import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
045 import org.apache.maven.scm.provider.svn.util.SvnUtil;
046 import org.apache.maven.scm.repository.ScmRepositoryException;
047 import org.apache.maven.scm.repository.UnknownRepositoryStructure;
048 import org.codehaus.plexus.util.StringUtils;
049
050 import java.io.File;
051 import java.util.ArrayList;
052 import java.util.List;
053
054 /**
055 * SCM Provider for Subversion
056 *
057 * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
058 *
059 */
060 public abstract class AbstractSvnScmProvider
061 extends AbstractScmProvider
062 {
063 // ----------------------------------------------------------------------
064 //
065 // ----------------------------------------------------------------------
066
067 private static class ScmUrlParserResult
068 {
069 private List<String> messages = new ArrayList<String>();
070
071 private ScmProviderRepository repository;
072 }
073
074 // ----------------------------------------------------------------------
075 // ScmProvider Implementation
076 // ----------------------------------------------------------------------
077
078 /**
079 * {@inheritDoc}
080 */
081 public String getScmSpecificFilename()
082 {
083 return ".svn";
084 }
085
086 /**
087 * {@inheritDoc}
088 */
089 public ScmProviderRepository makeProviderScmRepository( String scmSpecificUrl, char delimiter )
090 throws ScmRepositoryException
091 {
092 ScmUrlParserResult result = parseScmUrl( scmSpecificUrl );
093
094 if ( result.messages.size() > 0 )
095 {
096 throw new ScmRepositoryException( "The scm url is invalid.", result.messages );
097 }
098
099 return result.repository;
100 }
101
102 /**
103 * {@inheritDoc}
104 */
105 public ScmProviderRepository makeProviderScmRepository( File path )
106 throws ScmRepositoryException, UnknownRepositoryStructure
107 {
108 if ( path == null )
109 {
110 throw new NullPointerException( "Path argument is null" );
111 }
112
113 if ( !path.isDirectory() )
114 {
115 throw new ScmRepositoryException( path.getAbsolutePath() + " isn't a valid directory." );
116 }
117
118 if ( !new File( path, ".svn" ).exists() )
119 {
120 throw new ScmRepositoryException( path.getAbsolutePath() + " isn't a svn checkout directory." );
121 }
122
123 try
124 {
125 return makeProviderScmRepository( getRepositoryURL( path ), ':' );
126 }
127 catch ( ScmException e )
128 {
129 // XXX We should allow throwing of SCMException.
130 throw new ScmRepositoryException( "Error executing info command", e );
131 }
132 }
133
134 protected abstract String getRepositoryURL( File path )
135 throws ScmException;
136
137 /**
138 * {@inheritDoc}
139 */
140 public List<String> validateScmUrl( String scmSpecificUrl, char delimiter )
141 {
142 List<String> messages = new ArrayList<String>();
143 try
144 {
145 makeProviderScmRepository( scmSpecificUrl, delimiter );
146 }
147 catch ( ScmRepositoryException e )
148 {
149 messages = e.getValidationMessages();
150 }
151 return messages;
152 }
153
154 /**
155 * {@inheritDoc}
156 */
157 public String getScmType()
158 {
159 return "svn";
160 }
161
162 // ----------------------------------------------------------------------
163 //
164 // ----------------------------------------------------------------------
165
166 private ScmUrlParserResult parseScmUrl( String scmSpecificUrl )
167 {
168 ScmUrlParserResult result = new ScmUrlParserResult();
169
170 String url = scmSpecificUrl;
171
172 // ----------------------------------------------------------------------
173 // Do some sanity checking of the SVN url
174 // ----------------------------------------------------------------------
175
176 if ( url.startsWith( "file" ) )
177 {
178 if ( !url.startsWith( "file://" ) )
179 {
180 result.messages.add( "A svn 'file' url must be on the form 'file://[hostname]/'." );
181
182 return result;
183 }
184 }
185 else if ( url.startsWith( "https" ) )
186 {
187 if ( !url.startsWith( "https://" ) )
188 {
189 result.messages.add( "A svn 'http' url must be on the form 'https://'." );
190
191 return result;
192 }
193 }
194 else if ( url.startsWith( "http" ) )
195 {
196 if ( !url.startsWith( "http://" ) )
197 {
198 result.messages.add( "A svn 'http' url must be on the form 'http://'." );
199
200 return result;
201 }
202 }
203 // Support of tunnels: svn+xxx with xxx defined in subversion conf file
204 else if ( url.startsWith( "svn+" ) )
205 {
206 if ( url.indexOf( "://" ) < 0 )
207 {
208 result.messages.add( "A svn 'svn+xxx' url must be on the form 'svn+xxx://'." );
209
210 return result;
211 }
212 else
213 {
214 String tunnel = url.substring( "svn+".length(), url.indexOf( "://" ) );
215
216 //ssh is always an allowed tunnel
217 if ( !"ssh".equals( tunnel ) )
218 {
219 SvnConfigFileReader reader = new SvnConfigFileReader();
220 if ( SvnUtil.getSettings().getConfigDirectory() != null )
221 {
222 reader.setConfigDirectory( new File( SvnUtil.getSettings().getConfigDirectory() ) );
223 }
224
225 if ( StringUtils.isEmpty( reader.getProperty( "tunnels", tunnel ) ) )
226 {
227 result.messages.add(
228 "The tunnel '" + tunnel + "' isn't defined in your subversion configuration file." );
229
230 return result;
231 }
232 }
233 }
234 }
235 else if ( url.startsWith( "svn" ) )
236 {
237 if ( !url.startsWith( "svn://" ) )
238 {
239 result.messages.add( "A svn 'svn' url must be on the form 'svn://'." );
240
241 return result;
242 }
243 }
244 else
245 {
246 result.messages.add( url + " url isn't a valid svn URL." );
247
248 return result;
249 }
250
251 result.repository = new SvnScmProviderRepository( url );
252
253 return result;
254 }
255
256 protected abstract SvnCommand getAddCommand();
257
258 /**
259 * {@inheritDoc}
260 */
261 public AddScmResult add( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
262 throws ScmException
263 {
264 return (AddScmResult) executeCommand( getAddCommand(), repository, fileSet, parameters );
265 }
266
267 protected abstract SvnCommand getBranchCommand();
268
269 /**
270 * {@inheritDoc}
271 */
272 protected BranchScmResult branch( ScmProviderRepository repository, ScmFileSet fileSet,
273 CommandParameters parameters )
274 throws ScmException
275 {
276 return (BranchScmResult) executeCommand( getBranchCommand(), repository, fileSet, parameters );
277 }
278
279 protected abstract SvnCommand getChangeLogCommand();
280
281 /**
282 * {@inheritDoc}
283 */
284 public ChangeLogScmResult changelog( ScmProviderRepository repository, ScmFileSet fileSet,
285 CommandParameters parameters )
286 throws ScmException
287 {
288 return (ChangeLogScmResult) executeCommand( getChangeLogCommand(), repository, fileSet, parameters );
289 }
290
291 protected abstract SvnCommand getCheckInCommand();
292
293 /**
294 * {@inheritDoc}
295 */
296 public CheckInScmResult checkin( ScmProviderRepository repository, ScmFileSet fileSet,
297 CommandParameters parameters )
298 throws ScmException
299 {
300 return (CheckInScmResult) executeCommand( getCheckInCommand(), repository, fileSet, parameters );
301 }
302
303 protected abstract SvnCommand getCheckOutCommand();
304
305 /**
306 * {@inheritDoc}
307 */
308 public CheckOutScmResult checkout( ScmProviderRepository repository, ScmFileSet fileSet,
309 CommandParameters parameters )
310 throws ScmException
311 {
312 return (CheckOutScmResult) executeCommand( getCheckOutCommand(), repository, fileSet, parameters );
313 }
314
315 protected abstract SvnCommand getDiffCommand();
316
317 /**
318 * {@inheritDoc}
319 */
320 public DiffScmResult diff( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
321 throws ScmException
322 {
323 return (DiffScmResult) executeCommand( getDiffCommand(), repository, fileSet, parameters );
324 }
325
326 protected abstract SvnCommand getExportCommand();
327
328 /**
329 * {@inheritDoc}
330 */
331 protected ExportScmResult export( ScmProviderRepository repository, ScmFileSet fileSet,
332 CommandParameters parameters )
333 throws ScmException
334 {
335 return (ExportScmResult) executeCommand( getExportCommand(), repository, fileSet, parameters );
336 }
337
338 protected abstract SvnCommand getRemoveCommand();
339
340 /**
341 * {@inheritDoc}
342 */
343 public RemoveScmResult remove( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
344 throws ScmException
345 {
346 return (RemoveScmResult) executeCommand( getRemoveCommand(), repository, fileSet, parameters );
347 }
348
349 protected abstract SvnCommand getStatusCommand();
350
351 /**
352 * {@inheritDoc}
353 */
354 public StatusScmResult status( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
355 throws ScmException
356 {
357 return (StatusScmResult) executeCommand( getStatusCommand(), repository, fileSet, parameters );
358 }
359
360 protected abstract SvnCommand getTagCommand();
361
362 /**
363 * {@inheritDoc}
364 */
365 public TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
366 throws ScmException
367 {
368 return (TagScmResult) executeCommand( getTagCommand(), repository, fileSet, parameters );
369 }
370
371 protected abstract SvnCommand getUpdateCommand();
372
373 /**
374 * {@inheritDoc}
375 */
376 public UpdateScmResult update( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
377 throws ScmException
378 {
379 return (UpdateScmResult) executeCommand( getUpdateCommand(), repository, fileSet, parameters );
380 }
381
382 protected ScmResult executeCommand( SvnCommand command, ScmProviderRepository repository, ScmFileSet fileSet,
383 CommandParameters parameters )
384 throws ScmException
385 {
386 command.setLogger( getLogger() );
387
388 return command.execute( repository, fileSet, parameters );
389 }
390
391 protected abstract SvnCommand getListCommand();
392
393 /**
394 * {@inheritDoc}
395 */
396 public ListScmResult list( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
397 throws ScmException
398 {
399 SvnCommand cmd = getListCommand();
400
401 return (ListScmResult) executeCommand( cmd, repository, fileSet, parameters );
402 }
403
404 protected abstract SvnCommand getInfoCommand();
405
406 public InfoScmResult info( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
407 throws ScmException
408 {
409 SvnCommand cmd = getInfoCommand();
410
411 return (InfoScmResult) executeCommand( cmd, repository, fileSet, parameters );
412 }
413
414 /**
415 * {@inheritDoc}
416 */
417 protected BlameScmResult blame( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
418 throws ScmException
419 {
420 SvnCommand cmd = getBlameCommand();
421
422 return (BlameScmResult) executeCommand( cmd, repository, fileSet, parameters );
423 }
424
425 protected abstract SvnCommand getBlameCommand();
426
427 /**
428 * {@inheritDoc}
429 */
430 public MkdirScmResult mkdir( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
431 throws ScmException
432 {
433 SvnCommand cmd = getMkdirCommand();
434
435 return (MkdirScmResult) executeCommand( cmd, repository, fileSet, parameters );
436 }
437
438 protected abstract SvnCommand getMkdirCommand();
439
440 /**
441 * @param repository
442 * @param parameters
443 * @return true if remote url exists
444 * @throws ScmException
445 * @since 1.8
446 */
447 public abstract boolean remoteUrlExist( ScmProviderRepository repository, CommandParameters parameters )
448 throws ScmException;
449 }