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     * @version $Id: AbstractSvnScmProvider.java 1380486 2012-09-04 08:33:18Z olamy $
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    }