Coverage Report - org.apache.maven.scm.provider.git.repository.GitScmProviderRepository
 
Classes in this File Line Coverage Branch Coverage Complexity
GitScmProviderRepository
84 %
105/124
76 %
72/94
4,786
 
 1  
 package org.apache.maven.scm.provider.git.repository;
 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 org.apache.maven.scm.ScmException;
 23  
 import org.apache.maven.scm.provider.ScmProviderRepository;
 24  
 import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost;
 25  
 
 26  
 import java.util.regex.Matcher;
 27  
 import java.util.regex.Pattern;
 28  
 
 29  
 /**
 30  
  * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
 31  
  * @author <a href="mailto:struberg@apache.org">Mark Struberg</a>
 32  
  * @version $Id: GitScmProviderRepository.java 1306864 2012-03-29 13:43:18Z olamy $
 33  
  */
 34  
 public class GitScmProviderRepository
 35  
     extends ScmProviderRepositoryWithHost
 36  
 {
 37  
 
 38  
     /**
 39  
      * sequence used to delimit the fetch URL
 40  
      */
 41  
     public static final String URL_DELIMITER_FETCH = "[fetch=]";
 42  
 
 43  
     /**
 44  
      * sequence used to delimit the push URL
 45  
      */
 46  
     public static final String URL_DELIMITER_PUSH = "[push=]";
 47  
 
 48  
     /**
 49  
      * this trails every protocol
 50  
      */
 51  
     public static final String PROTOCOL_SEPARATOR = "://";
 52  
 
 53  
     /**
 54  
      * use local file as transport
 55  
      */
 56  
     public static final String PROTOCOL_FILE = "file";
 57  
 
 58  
     /**
 59  
      * use gits internal protocol
 60  
      */
 61  
     public static final String PROTOCOL_GIT = "git";
 62  
 
 63  
     /**
 64  
      * use secure shell protocol
 65  
      */
 66  
     public static final String PROTOCOL_SSH = "ssh";
 67  
 
 68  
     /**
 69  
      * use the standard port 80 http protocol
 70  
      */
 71  
     public static final String PROTOCOL_HTTP = "http";
 72  
 
 73  
     /**
 74  
      * use the standard port 443 https protocol
 75  
      */
 76  
     public static final String PROTOCOL_HTTPS = "https";
 77  
 
 78  
     /**
 79  
      * use rsync for retrieving the data
 80  
      * TODO implement!
 81  
      */
 82  
     public static final String PROTOCOL_RSYNC = "rsync";
 83  
 
 84  1
     private static final Pattern HOST_AND_PORT_EXTRACTOR =
 85  
         Pattern.compile( "([^:/\\\\~]*)(?::(\\d*))?(?:([:/\\\\~])(.*))?" );
 86  
 
 87  
     /**
 88  
      * No special protocol specified. Git will either use git://
 89  
      * or ssh:// depending on whether we work locally or over the network
 90  
      */
 91  
     public static final String PROTOCOL_NONE = "";
 92  
 
 93  
     /**
 94  
      * this may either 'git' or 'jgit' depending on the underlying implementation being used
 95  
      */
 96  
     private String provider;
 97  
 
 98  
     /**
 99  
      * the URL used to fetch from the upstream repository
 100  
      */
 101  
     private RepositoryUrl fetchInfo;
 102  
 
 103  
     /**
 104  
      * the URL used to push to the upstream repository
 105  
      */
 106  
     private RepositoryUrl pushInfo;
 107  
 
 108  
     public GitScmProviderRepository( String url )
 109  
         throws ScmException
 110  27
     {
 111  27
         if ( url == null )
 112  
         {
 113  0
             throw new ScmException( "url must not be null" );
 114  
         }
 115  
 
 116  27
         if ( url.startsWith( URL_DELIMITER_FETCH ) )
 117  
         {
 118  1
             String fetch = url.substring( URL_DELIMITER_FETCH.length() );
 119  
 
 120  1
             int indexPushDelimiter = fetch.indexOf( URL_DELIMITER_PUSH );
 121  1
             if ( indexPushDelimiter >= 0 )
 122  
             {
 123  1
                 String push = fetch.substring( indexPushDelimiter + URL_DELIMITER_PUSH.length() );
 124  1
                 pushInfo = parseUrl( push );
 125  
 
 126  1
                 fetch = fetch.substring( 0, indexPushDelimiter );
 127  
             }
 128  
 
 129  1
             fetchInfo = parseUrl( fetch );
 130  
 
 131  1
             if ( pushInfo == null )
 132  
             {
 133  0
                 pushInfo = fetchInfo;
 134  
             }
 135  1
         }
 136  26
         else if ( url.startsWith( URL_DELIMITER_PUSH ) )
 137  
         {
 138  1
             String push = url.substring( URL_DELIMITER_PUSH.length() );
 139  
 
 140  1
             int indexFetchDelimiter = push.indexOf( URL_DELIMITER_FETCH );
 141  1
             if ( indexFetchDelimiter >= 0 )
 142  
             {
 143  1
                 String fetch = push.substring( indexFetchDelimiter + URL_DELIMITER_FETCH.length() );
 144  1
                 fetchInfo = parseUrl( fetch );
 145  
 
 146  1
                 push = push.substring( 0, indexFetchDelimiter );
 147  
             }
 148  
 
 149  1
             pushInfo = parseUrl( push );
 150  
 
 151  1
             if ( fetchInfo == null )
 152  
             {
 153  0
                 fetchInfo = pushInfo;
 154  
             }
 155  1
         }
 156  
         else
 157  
         {
 158  25
             fetchInfo = pushInfo = parseUrl( url );
 159  
         }
 160  
 
 161  
         // set the default values for backward compatibility from the push url
 162  
         // because it's more likely that the push URL contains 'better' credentials
 163  27
         setUser( pushInfo.getUserName() );
 164  27
         setPassword( pushInfo.getPassword() );
 165  27
         setHost( pushInfo.getHost() );
 166  27
         if ( pushInfo.getPort() != null && pushInfo.getPort().length() > 0 )
 167  
         {
 168  5
             setPort( Integer.parseInt( pushInfo.getPort() ) );
 169  
         }
 170  27
     }
 171  
 
 172  
     public GitScmProviderRepository( String url, String user, String password )
 173  
         throws ScmException
 174  
     {
 175  0
         this( url );
 176  
 
 177  0
         setUser( user );
 178  
 
 179  0
         setPassword( password );
 180  0
     }
 181  
 
 182  
     /**
 183  
      * @return either 'git' or 'jgit' depending on the underlying implementation being used
 184  
      */
 185  
     public String getProvider()
 186  
     {
 187  0
         return provider;
 188  
     }
 189  
 
 190  
     public RepositoryUrl getFetchInfo()
 191  
     {
 192  0
         return fetchInfo;
 193  
     }
 194  
 
 195  
     public RepositoryUrl getPushInfo()
 196  
     {
 197  0
         return pushInfo;
 198  
     }
 199  
 
 200  
 
 201  
     /**
 202  
      * @return the URL used to fetch from the upstream repository
 203  
      */
 204  
     public String getFetchUrl()
 205  
     {
 206  26
         return getUrl( fetchInfo );
 207  
     }
 208  
 
 209  
     /**
 210  
      * @return the URL used to push to the upstream repository
 211  
      */
 212  
     public String getPushUrl()
 213  
     {
 214  2
         return getUrl( pushInfo );
 215  
     }
 216  
 
 217  
 
 218  
     /**
 219  
      * Parse the given url string and store all the extracted
 220  
      * information in a {@code RepositoryUrl}
 221  
      *
 222  
      * @param url to parse
 223  
      * @return filled with the information from the given URL
 224  
      * @throws ScmException
 225  
      */
 226  
     private RepositoryUrl parseUrl( String url )
 227  
         throws ScmException
 228  
     {
 229  29
         RepositoryUrl repoUrl = new RepositoryUrl();
 230  
 
 231  29
         url = parseProtocol( repoUrl, url );
 232  29
         url = parseUserInfo( repoUrl, url );
 233  29
         url = parseHostAndPort( repoUrl, url );
 234  
         // the rest of the url must be the path to the repository on the server
 235  29
         repoUrl.setPath( url );
 236  29
         return repoUrl;
 237  
     }
 238  
 
 239  
 
 240  
     /**
 241  
      * @param repoUrl
 242  
      * @return
 243  
      */
 244  
     private String getUrl( RepositoryUrl repoUrl )
 245  
     {
 246  56
         StringBuilder urlSb = new StringBuilder( repoUrl.getProtocol() );
 247  56
         boolean urlSupportsUserInformation = false;
 248  
 
 249  56
         if ( PROTOCOL_SSH.equals( repoUrl.getProtocol() ) ||
 250  
             PROTOCOL_RSYNC.equals( repoUrl.getProtocol() ) ||
 251  
             PROTOCOL_GIT.equals( repoUrl.getProtocol() ) ||
 252  
             PROTOCOL_HTTP.equals( repoUrl.getProtocol() ) ||
 253  
             PROTOCOL_HTTPS.equals( repoUrl.getProtocol() ) ||
 254  
             PROTOCOL_NONE.equals( repoUrl.getProtocol() ) )
 255  
         {
 256  46
             urlSupportsUserInformation = true;
 257  
         }
 258  
 
 259  56
         if ( repoUrl.getProtocol() != null && repoUrl.getProtocol().length() > 0 )
 260  
         {
 261  50
             urlSb.append( "://" );
 262  
         }
 263  
 
 264  
         // add user information if given and allowed for the protocol
 265  56
         if ( urlSupportsUserInformation )
 266  
         {
 267  46
             String userName = repoUrl.getUserName();
 268  
             // if specified on the commandline or other configuration, we take this.
 269  46
             if ( getUser() != null && getUser().length() > 0 )
 270  
             {
 271  38
                 userName = getUser();
 272  
             }
 273  
 
 274  46
             String password = repoUrl.getPassword();
 275  46
             if ( getPassword() != null && getPassword().length() > 0 )
 276  
             {
 277  16
                 password = getPassword();
 278  
             }
 279  
 
 280  46
             if ( userName != null && userName.length() > 0 )
 281  
             {
 282  38
                 urlSb.append( userName );
 283  
 
 284  38
                 if ( password != null && password.length() > 0 )
 285  
                 {
 286  16
                     urlSb.append( ':' ).append( password );
 287  
                 }
 288  
 
 289  38
                 urlSb.append( '@' );
 290  
             }
 291  
         }
 292  
 
 293  
         // add host and port information
 294  56
         urlSb.append( repoUrl.getHost() );
 295  56
         if ( repoUrl.getPort() != null && repoUrl.getPort().length() > 0 )
 296  
         {
 297  10
             urlSb.append( ':' ).append( repoUrl.getPort() );
 298  
         }
 299  
 
 300  
         // finaly we add the path to the repo on the host
 301  56
         urlSb.append( repoUrl.getPath() );
 302  
 
 303  56
         return urlSb.toString();
 304  
     }
 305  
 
 306  
     /**
 307  
      * Parse the protocol from the given url and fill it into the given RepositoryUrl.
 308  
      *
 309  
      * @param repoUrl
 310  
      * @param url
 311  
      * @return the given url with the protocol parts removed
 312  
      */
 313  
     private String parseProtocol( RepositoryUrl repoUrl, String url )
 314  
         throws ScmException
 315  
     {
 316  
         // extract the protocol
 317  29
         if ( url.startsWith( PROTOCOL_FILE + PROTOCOL_SEPARATOR ) )
 318  
         {
 319  5
             repoUrl.setProtocol( PROTOCOL_FILE );
 320  
         }
 321  24
         else if ( url.startsWith( PROTOCOL_HTTPS + PROTOCOL_SEPARATOR ) )
 322  
         {
 323  4
             repoUrl.setProtocol( PROTOCOL_HTTPS );
 324  
         }
 325  20
         else if ( url.startsWith( PROTOCOL_HTTP + PROTOCOL_SEPARATOR ) )
 326  
         {
 327  7
             repoUrl.setProtocol( PROTOCOL_HTTP );
 328  
         }
 329  13
         else if ( url.startsWith( PROTOCOL_SSH + PROTOCOL_SEPARATOR ) )
 330  
         {
 331  8
             repoUrl.setProtocol( PROTOCOL_SSH );
 332  
         }
 333  5
         else if ( url.startsWith( PROTOCOL_GIT + PROTOCOL_SEPARATOR ) )
 334  
         {
 335  2
             repoUrl.setProtocol( PROTOCOL_GIT );
 336  
         }
 337  3
         else if ( url.startsWith( PROTOCOL_RSYNC + PROTOCOL_SEPARATOR ) )
 338  
         {
 339  0
             repoUrl.setProtocol( PROTOCOL_RSYNC );
 340  
         }
 341  
         else
 342  
         {
 343  
             // when no protocol is specified git will pick either ssh:// or git://
 344  
             // depending on whether we work locally or over the network
 345  3
             repoUrl.setProtocol( PROTOCOL_NONE );
 346  3
             return url;
 347  
         }
 348  
 
 349  26
         url = url.substring( repoUrl.getProtocol().length() + 3 );
 350  
 
 351  26
         return url;
 352  
     }
 353  
 
 354  
     /**
 355  
      * Parse the user information from the given url and fill
 356  
      * user name and password into the given RepositoryUrl.
 357  
      *
 358  
      * @param repoUrl
 359  
      * @param url
 360  
      * @return the given url with the user parts removed
 361  
      */
 362  
     private String parseUserInfo( RepositoryUrl repoUrl, String url )
 363  
         throws ScmException
 364  
     {
 365  
         // extract user information
 366  29
         int indexAt = url.indexOf( '@' );
 367  29
         if ( indexAt >= 0 )
 368  
         {
 369  17
             String userInfo = url.substring( 0, indexAt );
 370  17
             int indexPwdSep = userInfo.indexOf( ':' );
 371  17
             if ( indexPwdSep < 0 )
 372  
             {
 373  11
                 repoUrl.setUserName( userInfo );
 374  
             }
 375  
             else
 376  
             {
 377  6
                 repoUrl.setUserName( userInfo.substring( 0, indexPwdSep ) );
 378  6
                 repoUrl.setPassword( userInfo.substring( indexPwdSep + 1 ) );
 379  
             }
 380  
 
 381  17
             url = url.substring( indexAt + 1 );
 382  
         }
 383  29
         return url;
 384  
     }
 385  
 
 386  
     /**
 387  
      * Parse server and port from the given url and fill it into the
 388  
      * given RepositoryUrl.
 389  
      *
 390  
      * @param repoUrl
 391  
      * @param url
 392  
      * @return the given url with the server parts removed
 393  
      * @throws ScmException
 394  
      */
 395  
     private String parseHostAndPort( RepositoryUrl repoUrl, String url )
 396  
         throws ScmException
 397  
     {
 398  
 
 399  29
         repoUrl.setPort( "" );
 400  29
         repoUrl.setHost( "" );
 401  
 
 402  29
         if ( PROTOCOL_FILE.equals( repoUrl.getProtocol() ) )
 403  
         {
 404  
             // a file:// URL doesn't need any further parsing as it cannot contain a port, etc
 405  5
             return url;
 406  
         }
 407  
         else
 408  
         {
 409  
 
 410  24
             Matcher hostAndPortMatcher = HOST_AND_PORT_EXTRACTOR.matcher( url );
 411  24
             if ( hostAndPortMatcher.matches() )
 412  
             {
 413  24
                 if ( hostAndPortMatcher.groupCount() > 1 && hostAndPortMatcher.group( 1 ) != null )
 414  
                 {
 415  24
                     repoUrl.setHost( hostAndPortMatcher.group( 1 ) );
 416  
                 }
 417  24
                 if ( hostAndPortMatcher.groupCount() > 2 && hostAndPortMatcher.group( 2 ) != null )
 418  
                 {
 419  5
                     repoUrl.setPort( hostAndPortMatcher.group( 2 ) );
 420  
                 }
 421  
 
 422  24
                 StringBuilder computedUrl = new StringBuilder();
 423  24
                 if ( hostAndPortMatcher.group( hostAndPortMatcher.groupCount() - 1 ) != null )
 424  
                 {
 425  15
                     computedUrl.append( hostAndPortMatcher.group( hostAndPortMatcher.groupCount() - 1 ) );
 426  
                 }
 427  24
                 if ( hostAndPortMatcher.group( hostAndPortMatcher.groupCount() ) != null )
 428  
                 {
 429  15
                     computedUrl.append( hostAndPortMatcher.group( hostAndPortMatcher.groupCount() ) );
 430  
                 }
 431  24
                 return computedUrl.toString();
 432  
             }
 433  
             else
 434  
             {
 435  
                 // Pattern doesn't match, let's return the original url
 436  0
                 return url;
 437  
             }
 438  
         }
 439  
     }
 440  
 
 441  
 
 442  
     /**
 443  
      * {@inheritDoc}
 444  
      */
 445  
     public String getRelativePath( ScmProviderRepository ancestor )
 446  
     {
 447  0
         if ( ancestor instanceof GitScmProviderRepository )
 448  
         {
 449  0
             GitScmProviderRepository gitAncestor = (GitScmProviderRepository) ancestor;
 450  
 
 451  
             //X TODO review!
 452  0
             String url = getFetchUrl();
 453  0
             String path = url.replaceFirst( gitAncestor.getFetchUrl() + "/", "" );
 454  
 
 455  0
             if ( !path.equals( url ) )
 456  
             {
 457  0
                 return path;
 458  
             }
 459  
         }
 460  0
         return null;
 461  
     }
 462  
 
 463  
     /**
 464  
      * {@inheritDoc}
 465  
      */
 466  
     public String toString()
 467  
     {
 468  
         // yes we really like to check if those are the exact same instance!
 469  26
         if ( fetchInfo == pushInfo )
 470  
         {
 471  24
             return getUrl( fetchInfo );
 472  
         }
 473  2
         return URL_DELIMITER_FETCH + getUrl( fetchInfo ) +
 474  
             URL_DELIMITER_PUSH + getUrl( pushInfo );
 475  
     }
 476  
 
 477  
 }