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