1 package org.apache.maven.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import org.codehaus.plexus.util.StringUtils;
22
23 /**
24 * Path tool for use with the DVSL toolbox. This class contains static
25 * methods to assist in determining path-related information such as
26 * relative paths.
27 *
28 * @author <a href="mailto:pete-apache-dev@kazmier.com">Pete Kazmier</a>
29 * @author <a href="mailto:vmassol@apache.org">Vincent Massol</a>
30 * @version $Id: DVSLPathTool.java 517014 2007-03-11 21:15:50Z ltheussl $
31 * @todo move to org.apache.maven.util or make a jelly tag
32 */
33 public class DVSLPathTool
34 {
35 /**
36 * Determines the relative path of a filename from a base directory.
37 * This method is useful in building relative links within pages of
38 * a web site. It provides similar functionality to Anakia's
39 * <code>$relativePath</code> context variable. The arguments to
40 * this method may contain either forward or backward slashes as
41 * file separators. The relative path returned is formed using
42 * forward slashes as it is expected this path is to be used as a
43 * link in a web page (again mimicking Anakia's behavior).
44 * <p/>
45 * This method is thread-safe.
46 *
47 * @param basedir The base directory.
48 * @param filename The filename that is relative to the base
49 * directory.
50 * @return The relative path of the filename from the base
51 * directory. This value is not terminated with a forward slash.
52 * A zero-length string is returned if: the filename is not relative to
53 * the base directory, <code>basedir</code> is null or zero-length,
54 * or <code>filename</code> is null or zero-length.
55 */
56 public static final String getRelativePath( String basedir, String filename )
57 {
58 basedir = uppercaseDrive( basedir );
59 filename = uppercaseDrive( filename );
60
61
62
63
64
65 if ( ( basedir == null ) || ( basedir.length() == 0 ) || ( filename == null ) || ( filename.length() == 0 )
66 || !filename.startsWith( basedir ) )
67 {
68 return "";
69 }
70
71
72
73
74
75
76 String separator = determineSeparator( filename );
77 basedir = StringUtils.chompLast( basedir, separator );
78 filename = StringUtils.chompLast( filename, separator );
79
80
81
82
83
84
85 String relativeFilename = filename.substring( basedir.length() );
86
87 return determineRelativePath( relativeFilename, separator );
88 }
89
90 /**
91 * Determines the relative path of a filename. This method is
92 * useful in building relative links within pages of a web site. It
93 * provides similar functionality to Anakia's
94 * <code>$relativePath</code> context variable. The argument to
95 * this method may contain either forward or backward slashes as
96 * file separators. The relative path returned is formed using
97 * forward slashes as it is expected this path is to be used as a
98 * link in a web page (again mimicking Anakia's behavior).
99 * <p/>
100 * This method is thread-safe.
101 *
102 * @param filename The filename to be parsed.
103 * @return The relative path of the filename. This value is not
104 * terminated with a forward slash. A zero-length string is
105 * returned if: <code>filename</code> is null or zero-length.
106 */
107 public static final String getRelativePath( String filename )
108 {
109 filename = uppercaseDrive( filename );
110
111 if ( ( filename == null ) || ( filename.length() == 0 ) )
112 {
113 return "";
114 }
115
116
117
118
119
120
121
122
123 String separator = determineSeparator( filename );
124 filename = StringUtils.chompLast( filename, separator );
125 if ( !filename.startsWith( separator ) )
126 {
127 filename = separator + filename;
128 }
129
130 return determineRelativePath( filename, separator );
131 }
132
133 /**
134 * Determines the directory component of a filename. This is useful
135 * within DVSL templates when used in conjunction with the DVSL's
136 * <code>$context.getAppValue("infilename")</code> to get the
137 * current directory that is currently being processed.
138 * <p/>
139 * This method is thread-safe.
140 *
141 * @param filename The filename to be parsed.
142 * @return The directory portion of the <code>filename</code>. If
143 * the filename does not contain a directory component, "." is
144 * returned.
145 */
146 public static final String getDirectoryComponent( String filename )
147 {
148 if ( ( filename == null ) || ( filename.length() == 0 ) )
149 {
150 return "";
151 }
152
153 String separator = determineSeparator( filename );
154 String directory = StringUtils.chomp( filename, separator );
155
156 if ( filename.equals( directory ) )
157 {
158 return ".";
159 }
160 else
161 {
162 return directory;
163 }
164 }
165
166 /**
167 * Determines the relative path of a filename. For each separator
168 * within the filename (except the leading if present), append the
169 * "../" string to the return value.
170 *
171 * @param filename The filename to parse.
172 * @param separator The separator used within the filename.
173 * @return The relative path of the filename. This value is not
174 * terminated with a forward slash. A zero-length string is
175 * returned if: the filename is zero-length.
176 */
177 private static final String determineRelativePath( String filename, String separator )
178 {
179 if ( filename.length() == 0 )
180 {
181 return "";
182 }
183
184
185
186
187
188
189 int slashCount = StringUtils.countMatches( filename, separator ) - 1;
190 if ( slashCount <= 0 )
191 {
192 return ".";
193 }
194
195
196
197
198
199
200 StringBuffer sb = new StringBuffer();
201 for ( int i = 0; i < slashCount; i++ )
202 {
203 sb.append( "../" );
204 }
205
206
207
208
209
210 return StringUtils.chop( sb.toString() );
211 }
212
213 /**
214 * Helper method to determine the file separator (forward or
215 * backward slash) used in a filename. The slash that occurs more
216 * often is returned as the separator.
217 *
218 * @param filename The filename parsed to determine the file
219 * separator.
220 * @return The file separator used within <code>filename</code>.
221 * This value is either a forward or backward slash.
222 */
223 private static final String determineSeparator( String filename )
224 {
225 int forwardCount = StringUtils.countMatches( filename, "/" );
226 int backwardCount = StringUtils.countMatches( filename, "\\" );
227
228 return forwardCount >= backwardCount ? "/" : "\\";
229 }
230
231 /**
232 * Cygwin prefers lowercase drive letters, but other parts of maven use uppercase
233 * @param path
234 * @return String
235 */
236 static final String uppercaseDrive( String path )
237 {
238 if ( path == null )
239 {
240 return null;
241 }
242 if ( ( path.length() >= 2 ) && ( path.charAt( 1 ) == ':' ) )
243 {
244 path = path.substring( 0, 1 ).toUpperCase() + path.substring( 1 );
245 }
246 return path;
247 }
248
249 /**
250 * Calculates the appropriate link given the preferred link and the relativePath of the document
251 * @param link
252 * @param relativePath
253 * @return String
254 */
255 public static final String calculateLink( String link, String relativePath )
256 {
257
258 if ( link.startsWith( "/site/" ) )
259 {
260 return link.substring( 5 );
261 }
262
263
264 if ( link.startsWith( "/absolute/" ) )
265 {
266 return link.substring( 10 );
267 }
268
269
270 if ( link.indexOf( ":" ) >= 0 )
271 {
272 return link;
273 }
274
275
276 if ( ".".equals( relativePath ) )
277 {
278 if ( link.startsWith( "/" ) )
279 {
280 return link.substring( 1 );
281 }
282 else
283 {
284 return link;
285 }
286 }
287
288
289 if ( relativePath.endsWith( "/" ) && link.startsWith( "/" ) )
290 {
291 return relativePath + "." + link.substring( 1 );
292 }
293
294 if ( relativePath.endsWith( "/" ) || link.startsWith( "/" ) )
295 {
296 return relativePath + link;
297 }
298
299 return relativePath + "/" + link;
300 }
301
302 }