Coverage Report - org.apache.maven.wagon.PathUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
PathUtils
92%
148/160
81%
97/120
5,214
 
 1  
 package org.apache.maven.wagon;
 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.StringTokenizer;
 24  
 
 25  
 /**
 26  
  * Various path (URL) manipulation routines
 27  
  *
 28  
  * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>
 29  
  * @version $Id: PathUtils.java 944160 2010-05-14 09:03:38Z bentmann $
 30  
  */
 31  
 public final class PathUtils
 32  
 {
 33  
     private PathUtils()
 34  0
     {
 35  0
     }
 36  
     
 37  
     /**
 38  
      * Returns the directory path portion of a file specification string.
 39  
      * Matches the equally named unix command.
 40  
      *
 41  
      * @return The directory portion excluding the ending file separator.
 42  
      */
 43  
     public static String dirname( final String path )
 44  
     {
 45  4
         final int i = path.lastIndexOf( "/" );
 46  
 
 47  4
         return ( ( i >= 0 ) ? path.substring( 0, i ) : "" );
 48  
     }
 49  
 
 50  
     /**
 51  
      * Returns the filename portion of a file specification string.
 52  
      *
 53  
      * @return The filename string with extension.
 54  
      */
 55  
     public static String filename( final String path )
 56  
     {
 57  3
         final int i = path.lastIndexOf( "/" );
 58  3
         return ( ( i >= 0 ) ? path.substring( i + 1 ) : path );
 59  
     }
 60  
 
 61  
     public static String[] dirnames( final String path )
 62  
     {
 63  1
         final String dirname = PathUtils.dirname( path );
 64  1
         return split( dirname, "/", -1 );
 65  
 
 66  
     }
 67  
 
 68  
     private static String[] split( final String str, final String separator, final int max )
 69  
     {
 70  
         final StringTokenizer tok;
 71  
 
 72  1
         if ( separator == null )
 73  
         {
 74  
             // Null separator means we're using StringTokenizer's default
 75  
             // delimiter, which comprises all whitespace characters.
 76  0
             tok = new StringTokenizer( str );
 77  
         }
 78  
         else
 79  
         {
 80  1
             tok = new StringTokenizer( str, separator );
 81  
         }
 82  
 
 83  1
         int listSize = tok.countTokens();
 84  
 
 85  1
         if ( max > 0 && listSize > max )
 86  
         {
 87  0
             listSize = max;
 88  
         }
 89  
 
 90  1
         final String[] list = new String[listSize];
 91  
 
 92  1
         int i = 0;
 93  
 
 94  
         int lastTokenBegin;
 95  1
         int lastTokenEnd = 0;
 96  
 
 97  3
         while ( tok.hasMoreTokens() )
 98  
         {
 99  2
             if ( max > 0 && i == listSize - 1 )
 100  
             {
 101  
                 // In the situation where we hit the max yet have
 102  
                 // tokens left over in our input, the last list
 103  
                 // element gets all remaining text.
 104  0
                 final String endToken = tok.nextToken();
 105  
 
 106  0
                 lastTokenBegin = str.indexOf( endToken, lastTokenEnd );
 107  
 
 108  0
                 list[i] = str.substring( lastTokenBegin );
 109  
 
 110  0
                 break;
 111  
 
 112  
             }
 113  
             else
 114  
             {
 115  2
                 list[i] = tok.nextToken();
 116  
 
 117  2
                 lastTokenBegin = str.indexOf( list[i], lastTokenEnd );
 118  
 
 119  2
                 lastTokenEnd = lastTokenBegin + list[i].length();
 120  
             }
 121  
 
 122  2
             i++;
 123  
         }
 124  1
         return list;
 125  
     }
 126  
 
 127  
     /**
 128  
      * Return the host name (Removes protocol and path from the URL) E.g: for input
 129  
      * <code>http://www.codehause.org</code> this method will return <code>www.apache.org</code>
 130  
      *
 131  
      * @param url the url
 132  
      * @return the host name
 133  
      */
 134  
     public static String host( final String url )
 135  
     {
 136  50
         String authorization = authorization( url );
 137  50
         int index = authorization.indexOf( '@' );
 138  50
         if ( index >= 0 )
 139  
         {
 140  14
             return authorization.substring( index + 1 );
 141  
         }
 142  
         else
 143  
         {
 144  36
             return authorization;
 145  
         }
 146  
     }
 147  
 
 148  
     /**
 149  
      * This was changed from private to package local so that it can be unit tested.
 150  
      */
 151  
     static String authorization( final String url )
 152  
     {
 153  234
         if ( url == null )
 154  
         {
 155  1
             return "localhost";
 156  
         }
 157  
 
 158  233
         final String protocol = PathUtils.protocol( url );
 159  
 
 160  233
         if ( protocol == null || protocol.equalsIgnoreCase( "file" ) )
 161  
         {
 162  9
             return "localhost";
 163  
         }
 164  
 
 165  224
         String host = url;
 166  224
         if ( protocol.equalsIgnoreCase( "scm" ) )
 167  
         {
 168  
             // skip over type
 169  45
             host = host.substring( host.indexOf( ":", 4 ) + 1 ).trim();
 170  
         }
 171  
 
 172  
         // skip over protocol
 173  224
         host = host.substring( host.indexOf( ":" ) + 1 ).trim();
 174  224
         if ( host.startsWith( "//" ) )
 175  
         {
 176  96
             host = host.substring( 2 );
 177  
         }
 178  
 
 179  224
         int pos = host.indexOf( "/" );
 180  
 
 181  224
         if ( pos > 0 )
 182  
         {
 183  63
             host = host.substring( 0, pos );
 184  
         }
 185  
 
 186  224
         pos = host.indexOf( '@' );
 187  
 
 188  224
         if ( pos > 0 )
 189  
         {
 190  79
             pos = host.indexOf( ':', pos );
 191  
         }
 192  
         else
 193  
         {
 194  145
             pos = host.indexOf( ":" );
 195  
         }
 196  
 
 197  224
         if ( pos > 0 )
 198  
         {
 199  36
             host = host.substring( 0, pos );
 200  
         }
 201  224
         return host;
 202  
     }
 203  
 
 204  
     /**
 205  
      * /**
 206  
      * Return the protocol name.
 207  
      * <br/>
 208  
      * E.g: for input
 209  
      * <code>http://www.codehause.org</code> this method will return <code>http</code>
 210  
      *
 211  
      * @param url the url
 212  
      * @return the host name
 213  
      */
 214  
     public static String protocol( final String url )
 215  
     {
 216  424
         final int pos = url.indexOf( ":" );
 217  
 
 218  424
         if ( pos == -1 )
 219  
         {
 220  178
             return "";
 221  
         }
 222  246
         return url.substring( 0, pos ).trim();
 223  
     }
 224  
 
 225  
     /**
 226  
      * @param url
 227  
      * @return the port or {@link WagonConstants#UNKNOWN_PORT} if not existent
 228  
      */
 229  
     public static int port( String url )
 230  
     {
 231  
 
 232  87
         final String protocol = PathUtils.protocol( url );
 233  
 
 234  87
         if ( protocol == null || protocol.equalsIgnoreCase( "file" ) )
 235  
         {
 236  0
             return WagonConstants.UNKNOWN_PORT;
 237  
         }
 238  
 
 239  87
         final String authorization = PathUtils.authorization( url );
 240  
 
 241  87
         if ( authorization == null )
 242  
         {
 243  0
             return WagonConstants.UNKNOWN_PORT;
 244  
         }
 245  
 
 246  87
         if ( protocol.equalsIgnoreCase( "scm" ) )
 247  
         {
 248  
             // skip over type
 249  13
             url = url.substring( url.indexOf( ":", 4 ) + 1 ).trim();
 250  
         }
 251  
 
 252  87
         if ( url.regionMatches( true, 0, "file:", 0, 5 ) || url.regionMatches( true, 0, "local:", 0, 6 ) )
 253  
         {
 254  0
             return WagonConstants.UNKNOWN_PORT;
 255  
         }
 256  
 
 257  
         // skip over protocol
 258  87
         url = url.substring( url.indexOf( ":" ) + 1 ).trim();
 259  87
         if ( url.startsWith( "//" ) )
 260  
         {
 261  36
             url = url.substring( 2 );
 262  
         }
 263  
 
 264  87
         int start = authorization.length();
 265  
 
 266  87
         if ( url.length() > start && url.charAt( start ) == ':' )
 267  
         {
 268  21
             int end = url.indexOf( '/', start );
 269  
 
 270  21
             if ( end == start + 1 )
 271  
             {
 272  
                 // it is :/
 273  4
                 return WagonConstants.UNKNOWN_PORT;
 274  
             }
 275  
 
 276  17
             if ( end == -1 )
 277  
             {
 278  3
                 end = url.length();
 279  
             }
 280  
 
 281  17
             return Integer.parseInt( url.substring( start + 1, end ) );
 282  
         }
 283  
         else
 284  
         {
 285  66
             return WagonConstants.UNKNOWN_PORT;
 286  
         }
 287  
 
 288  
     }
 289  
 
 290  
     /**
 291  
      * Derive the path portion of the given URL.
 292  
      * 
 293  
      * @param url the repository URL
 294  
      * @return the basedir of the repository
 295  
      * @todo need to URL decode for spaces?
 296  
      */
 297  
     public static String basedir( String url )
 298  
     {
 299  67
         String protocol = PathUtils.protocol( url );
 300  
 
 301  67
         String retValue = null;
 302  
 
 303  67
         if ( protocol.equalsIgnoreCase( "scm" ) )
 304  
         {
 305  
             // skip over SCM bits
 306  14
             if ( url.regionMatches( true, 0, "scm:svn:", 0, 8 ) )
 307  
             {
 308  6
                 url = url.substring( url.indexOf( ":", 4 ) + 1 );
 309  6
                 protocol = PathUtils.protocol( url );
 310  
             }
 311  
         }
 312  
 
 313  67
         if ( protocol.equalsIgnoreCase( "file" ) )
 314  
         {
 315  16
             retValue = url.substring( protocol.length() + 1 );
 316  16
             retValue = decode( retValue );
 317  
             // special case: if omitted // on protocol, keep path as is
 318  16
             if ( retValue.startsWith( "//" ) )
 319  
             {
 320  13
                 retValue = retValue.substring( 2 );
 321  
 
 322  13
                 if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
 323  
                 {
 324  
                     // special case: if there is a windows drive letter, then keep the original return value
 325  3
                     retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
 326  
                 }
 327  
                 else
 328  
                 {
 329  
                     // Now we expect the host
 330  10
                     int index = retValue.indexOf( "/" );
 331  10
                     if ( index >= 0 )
 332  
                     {
 333  10
                         retValue = retValue.substring( index + 1 );
 334  
                     }
 335  
 
 336  
                     // special case: if there is a windows drive letter, then keep the original return value
 337  10
                     if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
 338  
                     {
 339  8
                         retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
 340  
                     }
 341  2
                     else if ( index >= 0 )
 342  
                     {
 343  
                         // leading / was previously stripped
 344  2
                         retValue = "/" + retValue;
 345  
                     }
 346  
                 }
 347  
             }
 348  
 
 349  
             // special case: if there is a windows drive letter using |, switch to :
 350  16
             if ( retValue.length() >= 2 && retValue.charAt( 1 ) == '|' )
 351  
             {
 352  1
                 retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
 353  
             }
 354  
         }
 355  
         else
 356  
         {
 357  51
             final String authorization = PathUtils.authorization( url );
 358  
 
 359  51
             final int port = PathUtils.port( url );
 360  
 
 361  51
             int pos = 0;
 362  
 
 363  51
             if ( protocol.equalsIgnoreCase( "scm" ) )
 364  
             {
 365  8
                 pos = url.indexOf( ":", 4 ) + 1;
 366  8
                 pos = url.indexOf( ":", pos ) + 1;
 367  
             }
 368  
             else
 369  
             {
 370  43
                 int index = url.indexOf( "://" );
 371  43
                 if ( index != -1 )
 372  
                 {
 373  23
                     pos = index + 3;
 374  
                 }
 375  
             }
 376  
 
 377  51
             pos += authorization.length();
 378  
 
 379  51
             if ( port != WagonConstants.UNKNOWN_PORT )
 380  
             {
 381  8
                 pos = pos + Integer.toString( port ).length() + 1;
 382  
             }
 383  
 
 384  51
             if ( url.length() > pos )
 385  
             {
 386  19
                 retValue = url.substring( pos );
 387  19
                 if ( retValue.startsWith( ":" ) )
 388  
                 {
 389  
                     // this is for :/ after the host
 390  3
                     retValue = retValue.substring( 1 );
 391  
                 }
 392  
 
 393  
                 // one module may be allowed in the path in CVS
 394  19
                 retValue = retValue.replace( ':', '/' );
 395  
             }
 396  
         }
 397  
 
 398  67
         if ( retValue == null )
 399  
         {
 400  32
             retValue = "/";
 401  
         }
 402  67
         return retValue.trim();
 403  
     }
 404  
 
 405  
     /**
 406  
      * Decodes the specified (portion of a) URL. <strong>Note:</strong> This decoder assumes that ISO-8859-1 is used to
 407  
      * convert URL-encoded octets to characters.
 408  
      * 
 409  
      * @param url The URL to decode, may be <code>null</code>.
 410  
      * @return The decoded URL or <code>null</code> if the input was <code>null</code>.
 411  
      */
 412  
     private static String decode( String url )
 413  
     {
 414  16
         String decoded = url;
 415  16
         if ( url != null )
 416  
         {
 417  16
             int pos = -1;
 418  27
             while ( ( pos = decoded.indexOf( '%', pos + 1 ) ) >= 0 )
 419  
             {
 420  11
                 if ( pos + 2 < decoded.length() )
 421  
                 {
 422  11
                     String hexStr = decoded.substring( pos + 1, pos + 3 );
 423  11
                     char ch = (char) Integer.parseInt( hexStr, 16 );
 424  11
                     decoded = decoded.substring( 0, pos ) + ch + decoded.substring( pos + 3 );
 425  11
                 }
 426  
             }
 427  
         }
 428  16
         return decoded;
 429  
     }
 430  
 
 431  
     public static String user( String url )
 432  
     {
 433  32
         String host = authorization( url );
 434  32
         int index = host.indexOf( '@' );
 435  32
         if ( index > 0 )
 436  
         {
 437  12
             String userInfo = host.substring( 0, index );
 438  12
             index = userInfo.indexOf( ':' );
 439  12
             if ( index > 0 )
 440  
             {
 441  6
                 return userInfo.substring( 0, index );
 442  
             }
 443  6
             else if ( index < 0 )
 444  
             {
 445  6
                 return userInfo;
 446  
             }
 447  
         }
 448  20
         return null;
 449  
     }
 450  
 
 451  
     public static String password( String url )
 452  
     {
 453  12
         String host = authorization( url );
 454  12
         int index = host.indexOf( '@' );
 455  12
         if ( index > 0 )
 456  
         {
 457  12
             String userInfo = host.substring( 0, index );
 458  12
             index = userInfo.indexOf( ':' );
 459  12
             if ( index >= 0 )
 460  
             {
 461  6
                 return userInfo.substring( index + 1 );
 462  
             }
 463  
         }
 464  6
         return null;
 465  
     }
 466  
 
 467  
     // TODO: move to plexus-utils or use something appropriate from there
 468  
     public static String toRelative( File basedir, String absolutePath )
 469  
     {
 470  
         String relative;
 471  
 
 472  6
         absolutePath = absolutePath.replace( '\\', '/' );
 473  6
         String basedirPath = basedir.getAbsolutePath().replace( '\\', '/' );
 474  
 
 475  6
         if ( absolutePath.startsWith( basedirPath ) )
 476  
         {
 477  6
             relative = absolutePath.substring( basedirPath.length() );
 478  6
             if ( relative.startsWith( "/" ) )
 479  
             {
 480  4
                 relative = relative.substring( 1 );
 481  
             }
 482  6
             if ( relative.length() <= 0 )
 483  
             {
 484  2
                 relative = ".";
 485  
             }
 486  
         }
 487  
         else
 488  
         {
 489  0
             relative = absolutePath;
 490  
         }
 491  
 
 492  6
         return relative;
 493  
     }
 494  
 }