package org.apache.maven.wagon;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.io.File;
import java.util.StringTokenizer;

Various path (URL) manipulation routines
Author:Michal Maczka
/** * Various path (URL) manipulation routines * * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a> * */
public final class PathUtils { private PathUtils() { }
Returns the directory path portion of a file specification string. Matches the equally named unix command.
Returns:The directory portion excluding the ending file separator.
/** * Returns the directory path portion of a file specification string. * Matches the equally named unix command. * * @return The directory portion excluding the ending file separator. */
public static String dirname( final String path ) { final int i = path.lastIndexOf( "/" ); return ( ( i >= 0 ) ? path.substring( 0, i ) : "" ); }
Returns the filename portion of a file specification string.
Returns:The filename string with extension.
/** * Returns the filename portion of a file specification string. * * @return The filename string with extension. */
public static String filename( final String path ) { final int i = path.lastIndexOf( "/" ); return ( ( i >= 0 ) ? path.substring( i + 1 ) : path ); } public static String[] dirnames( final String path ) { final String dirname = PathUtils.dirname( path ); return split( dirname, "/", -1 ); } private static String[] split( final String str, final String separator, final int max ) { final StringTokenizer tok; if ( separator == null ) { // Null separator means we're using StringTokenizer's default // delimiter, which comprises all whitespace characters. tok = new StringTokenizer( str ); } else { tok = new StringTokenizer( str, separator ); } int listSize = tok.countTokens(); if ( max > 0 && listSize > max ) { listSize = max; } final String[] list = new String[listSize]; int i = 0; int lastTokenBegin; int lastTokenEnd = 0; while ( tok.hasMoreTokens() ) { if ( max > 0 && i == listSize - 1 ) { // In the situation where we hit the max yet have // tokens left over in our input, the last list // element gets all remaining text. final String endToken = tok.nextToken(); lastTokenBegin = str.indexOf( endToken, lastTokenEnd ); list[i] = str.substring( lastTokenBegin ); break; } else { list[i] = tok.nextToken(); lastTokenBegin = str.indexOf( list[i], lastTokenEnd ); lastTokenEnd = lastTokenBegin + list[i].length(); } i++; } return list; }
Return the host name (Removes protocol and path from the URL) E.g: for input http://www.codehause.org this method will return www.apache.org
Params:
  • url – the url
Returns:the host name
/** * Return the host name (Removes protocol and path from the URL) E.g: for input * <code>http://www.codehause.org</code> this method will return <code>www.apache.org</code> * * @param url the url * @return the host name */
public static String host( final String url ) { if ( url == null || url.length() == 0 ) { return "localhost"; } String authorization = authorization( url ); int index = authorization.indexOf( '@' ); String host = ( index >= 0 ) ? authorization.substring( index + 1 ) : authorization; // In case we have IPv6 in the host portion of url // we have to remove brackets '[' and ']' return ( ( host.charAt( 0 ) == '[' ) && ( host.charAt( host.length() - 1 ) == ']' ) ) ? host.substring( 1, host.length() - 1 ) : host; }
This was changed from private to package local so that it can be unit tested.
/** * This was changed from private to package local so that it can be unit tested. */
static String authorization( final String url ) { if ( url == null ) { return "localhost"; } String protocol = PathUtils.protocol( url ); if ( protocol == null || protocol.equalsIgnoreCase( "file" ) ) { return "localhost"; } String host = url; if ( protocol.equalsIgnoreCase( "scm" ) ) { // skip over type host = host.substring( host.indexOf( ":", 4 ) + 1 ).trim(); } protocol = PathUtils.protocol( host ); if ( protocol.equalsIgnoreCase( "file" ) ) { return "localhost"; } // skip over protocol host = host.substring( host.indexOf( ":" ) + 1 ).trim(); if ( host.startsWith( "//" ) ) { host = host.substring( 2 ); } int pos = host.indexOf( "/" ); if ( pos > 0 ) { host = host.substring( 0, pos ); } pos = host.indexOf( '@' ); pos = ( pos > 0 ) ? endOfHostPosition( host, pos ) : endOfHostPosition( host, 0 ); if ( pos > 0 ) { host = host.substring( 0, pos ); } return host; } private static int endOfHostPosition( String host, int pos ) { // if this is IPv6 then it will be in IPv6 Literal Addresses in URL's format // see: http://www.ietf.org/rfc/rfc2732.txt int endOfIPv6Pos = host.indexOf( ']', pos ); return ( endOfIPv6Pos > 0 ) ? endOfIPv6Pos + 1 : host.indexOf( ":", pos ); }
/** Return the protocol name.
E.g: for input http://www.codehause.org this method will return http
Params:
  • url – the url
Returns:the host name
/** * /** * Return the protocol name. * <br/> * E.g: for input * <code>http://www.codehause.org</code> this method will return <code>http</code> * * @param url the url * @return the host name */
public static String protocol( final String url ) { final int pos = url.indexOf( ":" ); if ( pos == -1 ) { return ""; } return url.substring( 0, pos ).trim(); }
Params:
  • url –
Returns:the port or WagonConstants.UNKNOWN_PORT if not existent
/** * @param url * @return the port or {@link WagonConstants#UNKNOWN_PORT} if not existent */
public static int port( String url ) { final String protocol = PathUtils.protocol( url ); if ( protocol == null || protocol.equalsIgnoreCase( "file" ) ) { return WagonConstants.UNKNOWN_PORT; } final String authorization = PathUtils.authorization( url ); if ( authorization == null ) { return WagonConstants.UNKNOWN_PORT; } if ( protocol.equalsIgnoreCase( "scm" ) ) { // skip over type url = url.substring( url.indexOf( ":", 4 ) + 1 ).trim(); } if ( url.regionMatches( true, 0, "file:", 0, 5 ) || url.regionMatches( true, 0, "local:", 0, 6 ) ) { return WagonConstants.UNKNOWN_PORT; } // skip over protocol url = url.substring( url.indexOf( ":" ) + 1 ).trim(); if ( url.startsWith( "//" ) ) { url = url.substring( 2 ); } int start = authorization.length(); if ( url.length() > start && url.charAt( start ) == ':' ) { int end = url.indexOf( '/', start ); if ( end == start + 1 ) { // it is :/ return WagonConstants.UNKNOWN_PORT; } if ( end == -1 ) { end = url.length(); } return Integer.parseInt( url.substring( start + 1, end ) ); } else { return WagonConstants.UNKNOWN_PORT; } }
Derive the path portion of the given URL.
Params:
  • url – the repository URL
Returns:the basedir of the repository
@todoneed to URL decode for spaces?
/** * Derive the path portion of the given URL. * * @param url the repository URL * @return the basedir of the repository * @todo need to URL decode for spaces? */
public static String basedir( String url ) { String protocol = PathUtils.protocol( url ); String retValue = null; if ( protocol.equalsIgnoreCase( "scm" ) ) { // skip over SCM bits if ( url.regionMatches( true, 0, "scm:svn:", 0, 8 ) ) { url = url.substring( url.indexOf( ":", 4 ) + 1 ); protocol = PathUtils.protocol( url ); } } if ( protocol.equalsIgnoreCase( "file" ) ) { retValue = url.substring( protocol.length() + 1 ); retValue = decode( retValue ); // special case: if omitted // on protocol, keep path as is if ( retValue.startsWith( "//" ) ) { retValue = retValue.substring( 2 ); if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) ) { // special case: if there is a windows drive letter, then keep the original return value retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 ); } else { // Now we expect the host int index = retValue.indexOf( "/" ); if ( index >= 0 ) { retValue = retValue.substring( index + 1 ); } // special case: if there is a windows drive letter, then keep the original return value if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) ) { retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 ); } else if ( index >= 0 ) { // leading / was previously stripped retValue = "/" + retValue; } } } // special case: if there is a windows drive letter using |, switch to : if ( retValue.length() >= 2 && retValue.charAt( 1 ) == '|' ) { retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 ); } } else { final String authorization = PathUtils.authorization( url ); final int port = PathUtils.port( url ); int pos = 0; if ( protocol.equalsIgnoreCase( "scm" ) ) { pos = url.indexOf( ":", 4 ) + 1; pos = url.indexOf( ":", pos ) + 1; } else { int index = url.indexOf( "://" ); if ( index != -1 ) { pos = index + 3; } } pos += authorization.length(); if ( port != WagonConstants.UNKNOWN_PORT ) { pos = pos + Integer.toString( port ).length() + 1; } if ( url.length() > pos ) { retValue = url.substring( pos ); if ( retValue.startsWith( ":" ) ) { // this is for :/ after the host retValue = retValue.substring( 1 ); } // one module may be allowed in the path in CVS retValue = retValue.replace( ':', '/' ); } } if ( retValue == null ) { retValue = "/"; } return retValue.trim(); }
Decodes the specified (portion of a) URL. Note: This decoder assumes that ISO-8859-1 is used to convert URL-encoded octets to characters.
Params:
  • url – The URL to decode, may be null.
Returns:The decoded URL or null if the input was null.
/** * Decodes the specified (portion of a) URL. <strong>Note:</strong> This decoder assumes that ISO-8859-1 is used to * convert URL-encoded octets to characters. * * @param url The URL to decode, may be <code>null</code>. * @return The decoded URL or <code>null</code> if the input was <code>null</code>. */
private static String decode( String url ) { String decoded = url; if ( url != null ) { int pos = -1; while ( ( pos = decoded.indexOf( '%', pos + 1 ) ) >= 0 ) { if ( pos + 2 < decoded.length() ) { String hexStr = decoded.substring( pos + 1, pos + 3 ); char ch = (char) Integer.parseInt( hexStr, 16 ); decoded = decoded.substring( 0, pos ) + ch + decoded.substring( pos + 3 ); } } } return decoded; } public static String user( String url ) { String host = authorization( url ); int index = host.indexOf( '@' ); if ( index > 0 ) { String userInfo = host.substring( 0, index ); index = userInfo.indexOf( ':' ); if ( index > 0 ) { return userInfo.substring( 0, index ); } else if ( index < 0 ) { return userInfo; } } return null; } public static String password( String url ) { String host = authorization( url ); int index = host.indexOf( '@' ); if ( index > 0 ) { String userInfo = host.substring( 0, index ); index = userInfo.indexOf( ':' ); if ( index >= 0 ) { return userInfo.substring( index + 1 ); } } return null; } // TODO: move to plexus-utils or use something appropriate from there public static String toRelative( File basedir, String absolutePath ) { String relative; absolutePath = absolutePath.replace( '\\', '/' ); String basedirPath = basedir.getAbsolutePath().replace( '\\', '/' ); if ( absolutePath.startsWith( basedirPath ) ) { relative = absolutePath.substring( basedirPath.length() ); if ( relative.startsWith( "/" ) ) { relative = relative.substring( 1 ); } if ( relative.length() <= 0 ) { relative = "."; } } else { relative = absolutePath; } return relative; } }