2 * Copyright (C) 2009, Mykola Nikishov <mn@mn.com.ua>
3 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
4 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5 * and other copyright owners as documented in the project's IP log.
7 * This program and the accompanying materials are made available
8 * under the terms of the Eclipse Distribution License v1.0 which
9 * accompanies this distribution, is reproduced below, and is
10 * available at http://www.eclipse.org/org/documents/edl-v10.php
12 * All rights reserved.
14 * Redistribution and use in source and binary forms, with or
15 * without modification, are permitted provided that the following
18 * - Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
21 * - Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials provided
24 * with the distribution.
26 * - Neither the name of the Eclipse Foundation, Inc. nor the
27 * names of its contributors may be used to endorse or promote
28 * products derived from this software without specific prior
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
32 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
33 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
36 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
38 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
40 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
43 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 package org
.eclipse
.jgit
.transport
;
48 import java
.net
.URISyntaxException
;
50 import java
.util
.regex
.Matcher
;
51 import java
.util
.regex
.Pattern
;
53 import org
.eclipse
.jgit
.lib
.Constants
;
56 * This URI like construct used for referencing Git archives over the net, as
57 * well as locally stored archives. The most important difference compared to
58 * RFC 2396 URI's is that no URI encoding/decoding ever takes place. A space or
59 * any special character is written as-is.
62 private static final Pattern FULL_URI
= Pattern
63 .compile("^(?:([a-z][a-z0-9+-]+)://(?:([^/]+?)(?::([^/]+?))?@)?(?:([^/]+?))?(?::(\\d+))?)?((?:[A-Za-z]:)?/.+)$");
65 private static final Pattern SCP_URI
= Pattern
66 .compile("^(?:([^@]+?)@)?([^:]+?):(.+)$");
68 private String scheme
;
76 private int port
= -1;
81 * Parse and construct an {@link URIish} from a string
84 * @throws URISyntaxException
86 public URIish(String s
) throws URISyntaxException
{
87 s
= s
.replace('\\', '/');
88 Matcher matcher
= FULL_URI
.matcher(s
);
89 if (matcher
.matches()) {
90 scheme
= matcher
.group(1);
91 user
= matcher
.group(2);
92 pass
= matcher
.group(3);
93 host
= matcher
.group(4);
94 if (matcher
.group(5) != null)
95 port
= Integer
.parseInt(matcher
.group(5));
96 path
= matcher
.group(6);
97 if (path
.length() >= 3
98 && path
.charAt(0) == '/'
99 && path
.charAt(2) == ':'
100 && (path
.charAt(1) >= 'A' && path
.charAt(1) <= 'Z'
101 || path
.charAt(1) >= 'a' && path
.charAt(1) <= 'z'))
102 path
= path
.substring(1);
104 matcher
= SCP_URI
.matcher(s
);
105 if (matcher
.matches()) {
106 user
= matcher
.group(1);
107 host
= matcher
.group(2);
108 path
= matcher
.group(3);
110 throw new URISyntaxException(s
, "Cannot parse Git URI-ish");
115 * Construct a URIish from a standard URL.
118 * the source URL to convert from.
120 public URIish(final URL u
) {
121 scheme
= u
.getProtocol();
124 final String ui
= u
.getUserInfo();
126 final int d
= ui
.indexOf(':');
127 user
= d
< 0 ? ui
: ui
.substring(0, d
);
128 pass
= d
< 0 ?
null : ui
.substring(d
+ 1);
135 /** Create an empty, non-configured URI. */
137 // Configure nothing.
140 private URIish(final URIish u
) {
141 this.scheme
= u
.scheme
;
150 * @return true if this URI references a repository on another system.
152 public boolean isRemote() {
153 return getHost() != null;
157 * @return host name part or null
159 public String
getHost() {
164 * Return a new URI matching this one, but with a different host.
167 * the new value for host.
168 * @return a new URI with the updated value.
170 public URIish
setHost(final String n
) {
171 final URIish r
= new URIish(this);
177 * @return protocol name or null for local references
179 public String
getScheme() {
184 * Return a new URI matching this one, but with a different scheme.
187 * the new value for scheme.
188 * @return a new URI with the updated value.
190 public URIish
setScheme(final String n
) {
191 final URIish r
= new URIish(this);
197 * @return path name component
199 public String
getPath() {
204 * Return a new URI matching this one, but with a different path.
207 * the new value for path.
208 * @return a new URI with the updated value.
210 public URIish
setPath(final String n
) {
211 final URIish r
= new URIish(this);
217 * @return user name requested for transfer or null
219 public String
getUser() {
224 * Return a new URI matching this one, but with a different user.
227 * the new value for user.
228 * @return a new URI with the updated value.
230 public URIish
setUser(final String n
) {
231 final URIish r
= new URIish(this);
237 * @return password requested for transfer or null
239 public String
getPass() {
244 * Return a new URI matching this one, but with a different password.
247 * the new value for password.
248 * @return a new URI with the updated value.
250 public URIish
setPass(final String n
) {
251 final URIish r
= new URIish(this);
257 * @return port number requested for transfer or -1 if not explicit
259 public int getPort() {
264 * Return a new URI matching this one, but with a different port.
267 * the new value for port.
268 * @return a new URI with the updated value.
270 public URIish
setPort(final int n
) {
271 final URIish r
= new URIish(this);
272 r
.port
= n
> 0 ? n
: -1;
276 public int hashCode() {
278 if (getScheme() != null)
279 hc
= hc
* 31 + getScheme().hashCode();
280 if (getUser() != null)
281 hc
= hc
* 31 + getUser().hashCode();
282 if (getPass() != null)
283 hc
= hc
* 31 + getPass().hashCode();
284 if (getHost() != null)
285 hc
= hc
* 31 + getHost().hashCode();
287 hc
= hc
* 31 + getPort();
288 if (getPath() != null)
289 hc
= hc
* 31 + getPath().hashCode();
293 public boolean equals(final Object obj
) {
294 if (!(obj
instanceof URIish
))
296 final URIish b
= (URIish
) obj
;
297 if (!eq(getScheme(), b
.getScheme()))
299 if (!eq(getUser(), b
.getUser()))
301 if (!eq(getPass(), b
.getPass()))
303 if (!eq(getHost(), b
.getHost()))
305 if (getPort() != b
.getPort())
307 if (!eq(getPath(), b
.getPath()))
312 private static boolean eq(final String a
, final String b
) {
315 if (a
== null || b
== null)
321 * Obtain the string form of the URI, with the password included.
323 * @return the URI, including its password field, if any.
325 public String
toPrivateString() {
329 public String
toString() {
330 return format(false);
333 private String
format(final boolean includePassword
) {
334 final StringBuilder r
= new StringBuilder();
335 if (getScheme() != null) {
336 r
.append(getScheme());
340 if (getUser() != null) {
342 if (includePassword
&& getPass() != null) {
348 if (getHost() != null) {
349 if (getUser() != null)
352 if (getScheme() != null && getPort() > 0) {
358 if (getPath() != null) {
359 if (getScheme() != null) {
360 if (!getPath().startsWith("/"))
362 } else if (getHost() != null)
371 * Get the "humanish" part of the path. Some examples of a 'humanish' part
376 * <th>Humanish part</th>
379 * <td><code>/path/to/repo.git</code></td>
380 * <td rowspan="4"><code>repo</code></td>
383 * <td><code>/path/to/repo.git/</code></td>
386 * <td><code>/path/to/repo/.git</code></td>
389 * <td><code>/path/to/repo/</code></td>
392 * <td><code>/path//to</code></td>
393 * <td>an empty string</td>
397 * @return the "humanish" part of the path. May be an empty string. Never
399 * @throws IllegalArgumentException
400 * if it's impossible to determine a humanish part, or path is
401 * {@code null} or empty
404 public String
getHumanishName() throws IllegalArgumentException
{
405 if ("".equals(getPath()) || getPath() == null)
406 throw new IllegalArgumentException();
407 String
[] elements
= getPath().split("/");
408 if (elements
.length
== 0)
409 throw new IllegalArgumentException();
410 String result
= elements
[elements
.length
- 1];
411 if (Constants
.DOT_GIT
.equals(result
))
412 result
= elements
[elements
.length
- 2];
413 else if (result
.endsWith(DOT_GIT
))
414 result
= result
.substring(0, result
.length() - DOT_GIT
.length());