2
This code is derived from jgit (http://eclipse.org/jgit).
3
Copyright owners are documented in jgit's IP log.
5
This program and the accompanying materials are made available
6
under the terms of the Eclipse Distribution License v1.0 which
7
accompanies this distribution, is reproduced below, and is
8
available at http://www.eclipse.org/org/documents/edl-v10.php
12
Redistribution and use in source and binary forms, with or
13
without modification, are permitted provided that the following
16
- Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
19
- Redistributions in binary form must reproduce the above
20
copyright notice, this list of conditions and the following
21
disclaimer in the documentation and/or other materials provided
22
with the distribution.
24
- Neither the name of the Eclipse Foundation, Inc. nor the
25
names of its contributors may be used to endorse or promote
26
products derived from this software without specific prior
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49
namespace NGit.Transport
52
/// This URI like construct used for referencing Git archives over the net, as
53
/// well as locally stored archives.
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.
65
/// Part of a pattern which matches the scheme part (git, http, ...) of an
69
/// Part of a pattern which matches the scheme part (git, http, ...) of an
70
/// URI. Defines one capturing group containing the scheme without the
71
/// trailing colon and slashes
73
private static readonly string SCHEME_P = "([a-z][a-z0-9+-]+)://";
75
/// <summary>Part of a pattern which matches the optional user/password part (e.g.</summary>
77
/// Part of a pattern which matches the optional user/password part (e.g.
78
/// root:pwd@ in git://root:pwd@host.xyz/a.git) of URIs. Defines two
79
/// capturing groups: the first containing the user and the second containing
82
private static readonly string OPT_USER_PWD_P = "(?:([^\\\\/:@]+)(?::([^\\\\/]+))?@)?";
84
/// <summary>Part of a pattern which matches the host part of URIs.</summary>
86
/// Part of a pattern which matches the host part of URIs. Defines one
87
/// capturing group containing the host name.
89
private static readonly string HOST_P = "([^\\\\/:]+)";
91
/// <summary>Part of a pattern which matches the optional port part of URIs.</summary>
93
/// Part of a pattern which matches the optional port part of URIs. Defines
94
/// one capturing group containing the port without the preceding colon.
96
private static readonly string OPT_PORT_P = "(?::(\\d+))?";
98
/// <summary>Part of a pattern which matches the ~username part (e.g.</summary>
100
/// Part of a pattern which matches the ~username part (e.g. /~root in
101
/// git://host.xyz/~root/a.git) of URIs. Defines no capturing group.
103
private static readonly string USER_HOME_P = "(?:/~(?:[^\\\\/]+))";
105
/// <summary>Part of a pattern which matches the optional drive letter in paths (e.g.
108
/// Part of a pattern which matches the optional drive letter in paths (e.g.
109
/// D: in file:///D:/a.txt). Defines no capturing group.
111
private static readonly string OPT_DRIVE_LETTER_P = "(?:[A-Za-z]:)?";
113
/// <summary>Part of a pattern which matches a relative path.</summary>
115
/// Part of a pattern which matches a relative path. Relative paths don't
116
/// start with slash or drive letters. Defines no capturing group.
118
private static readonly string RELATIVE_PATH_P = "(?:(?:[^\\\\/]+[\\\\/])*[^\\\\/]+[\\\\/]?)";
120
/// <summary>Part of a pattern which matches a relative or absolute path.</summary>
122
/// Part of a pattern which matches a relative or absolute path. Defines no
125
private static readonly string PATH_P = "(" + OPT_DRIVE_LETTER_P + "[\\\\/]?" + RELATIVE_PATH_P
128
private const long serialVersionUID = 1L;
131
/// A pattern matching standard URI: </br>
132
/// <code>scheme "://" user_password? hostname? portnumber? path</code>
134
private static readonly Sharpen.Pattern FULL_URI = Sharpen.Pattern.Compile("^" +
135
SCHEME_P + "(?:" + OPT_USER_PWD_P + HOST_P + OPT_PORT_P + "(" + (USER_HOME_P + "?"
136
) + "[\\\\/])" + ")?" + "(.+)?" + "$");
138
/// <summary>A pattern matching the reference to a local file.</summary>
140
/// A pattern matching the reference to a local file. This may be an absolute
141
/// path (maybe even containing windows drive-letters) or a relative path.
143
private static readonly Sharpen.Pattern LOCAL_FILE = Sharpen.Pattern.Compile("^"
144
+ "([\\\\/]?" + PATH_P + ")" + "$");
147
/// A pattern matching a URI for the scheme 'file' which has only ':/' as
148
/// separator between scheme and path.
151
/// A pattern matching a URI for the scheme 'file' which has only ':/' as
152
/// separator between scheme and path. Standard file URIs have '://' as
153
/// separator, but java.io.File.toURI() constructs those URIs.
155
private static readonly Sharpen.Pattern SINGLE_SLASH_FILE_URI = Sharpen.Pattern.Compile
156
("^" + "(file):([\\\\/](?![\\\\/])" + PATH_P + ")$");
158
/// <summary>A pattern matching a SCP URI's of the form user@host:path/to/repo.git</summary>
159
private static readonly Sharpen.Pattern RELATIVE_SCP_URI = Sharpen.Pattern.Compile
160
("^" + OPT_USER_PWD_P + HOST_P + ":(" + ("(?:" + USER_HOME_P + "[\\\\/])?") + RELATIVE_PATH_P
163
/// <summary>A pattern matching a SCP URI's of the form user@host:/path/to/repo.git</summary>
164
private static readonly Sharpen.Pattern ABSOLUTE_SCP_URI = Sharpen.Pattern.Compile
165
("^" + OPT_USER_PWD_P + "([^\\\\/:]{2,})" + ":(" + "[\\\\/]" + RELATIVE_PATH_P +
168
private string scheme;
176
private int port = -1;
181
/// Parse and construct an
182
/// <see cref="URIish">URIish</see>
185
/// <param name="s"></param>
186
/// <exception cref="Sharpen.URISyntaxException">Sharpen.URISyntaxException</exception>
187
public URIish(string s)
191
// start a group containing hostname and all options only
192
// availabe when a hostname is there
196
// open a catpuring group the the user-home-dir part
199
// close the optional group containing hostname
217
Matcher matcher = SINGLE_SLASH_FILE_URI.Matcher(s);
218
if (matcher.Matches())
220
scheme = matcher.Group(1);
221
path = CleanLeadingSlashes(matcher.Group(2), scheme);
225
matcher = FULL_URI.Matcher(s);
226
if (matcher.Matches())
228
scheme = matcher.Group(1);
229
user = matcher.Group(2);
230
pass = matcher.Group(3);
231
host = matcher.Group(4);
232
if (matcher.Group(5) != null)
234
port = System.Convert.ToInt32(matcher.Group(5));
236
path = CleanLeadingSlashes(N2e(matcher.Group(6)) + N2e(matcher.Group(7)), scheme);
240
matcher = RELATIVE_SCP_URI.Matcher(s);
241
if (matcher.Matches())
243
user = matcher.Group(1);
244
pass = matcher.Group(2);
245
host = matcher.Group(3);
246
path = matcher.Group(4);
250
matcher = ABSOLUTE_SCP_URI.Matcher(s);
251
if (matcher.Matches())
253
user = matcher.Group(1);
254
pass = matcher.Group(2);
255
host = matcher.Group(3);
256
path = matcher.Group(4);
260
matcher = LOCAL_FILE.Matcher(s);
261
if (matcher.Matches())
263
path = matcher.Group(1);
267
throw new URISyntaxException(s, JGitText.Get().cannotParseGitURIish);
275
private string N2e(string s)
287
// takes care to cut of a leading slash if a windows drive letter or a
288
// user-home-dir specifications are
289
private string CleanLeadingSlashes(string p, string s)
291
if (p.Length >= 3 && p[0] == '/' && p[2] == ':' && (p[1] >= 'A' && p[1] <= 'Z' ||
292
p[1] >= 'a' && p[1] <= 'z'))
294
return Sharpen.Runtime.Substring(p, 1);
298
if (s != null && p.Length >= 2 && p[0] == '/' && p[1] == '~')
300
return Sharpen.Runtime.Substring(p, 1);
309
/// <summary>Construct a URIish from a standard URL.</summary>
310
/// <remarks>Construct a URIish from a standard URL.</remarks>
311
/// <param name="u">the source URL to convert from.</param>
315
path = u.AbsolutePath;
316
string ui = u.GetUserInfo();
319
int d = ui.IndexOf(':');
320
user = d < 0 ? ui : Sharpen.Runtime.Substring(ui, 0, d);
321
pass = d < 0 ? null : Sharpen.Runtime.Substring(ui, d + 1);
327
/// <summary>Create an empty, non-configured URI.</summary>
328
/// <remarks>Create an empty, non-configured URI.</remarks>
333
private URIish(NGit.Transport.URIish u)
335
// Configure nothing.
336
this.scheme = u.scheme;
344
/// <returns>true if this URI references a repository on another system.</returns>
345
public virtual bool IsRemote()
347
return GetHost() != null;
350
/// <returns>host name part or null</returns>
351
public virtual string GetHost()
356
/// <summary>Return a new URI matching this one, but with a different host.</summary>
357
/// <remarks>Return a new URI matching this one, but with a different host.</remarks>
358
/// <param name="n">the new value for host.</param>
359
/// <returns>a new URI with the updated value.</returns>
360
public virtual NGit.Transport.URIish SetHost(string n)
362
NGit.Transport.URIish r = new NGit.Transport.URIish(this);
367
/// <returns>protocol name or null for local references</returns>
368
public virtual string GetScheme()
373
/// <summary>Return a new URI matching this one, but with a different scheme.</summary>
374
/// <remarks>Return a new URI matching this one, but with a different scheme.</remarks>
375
/// <param name="n">the new value for scheme.</param>
376
/// <returns>a new URI with the updated value.</returns>
377
public virtual NGit.Transport.URIish SetScheme(string n)
379
NGit.Transport.URIish r = new NGit.Transport.URIish(this);
384
/// <returns>path name component</returns>
385
public virtual string GetPath()
390
/// <summary>Return a new URI matching this one, but with a different path.</summary>
391
/// <remarks>Return a new URI matching this one, but with a different path.</remarks>
392
/// <param name="n">the new value for path.</param>
393
/// <returns>a new URI with the updated value.</returns>
394
public virtual NGit.Transport.URIish SetPath(string n)
396
NGit.Transport.URIish r = new NGit.Transport.URIish(this);
401
/// <returns>user name requested for transfer or null</returns>
402
public virtual string GetUser()
407
/// <summary>Return a new URI matching this one, but with a different user.</summary>
408
/// <remarks>Return a new URI matching this one, but with a different user.</remarks>
409
/// <param name="n">the new value for user.</param>
410
/// <returns>a new URI with the updated value.</returns>
411
public virtual NGit.Transport.URIish SetUser(string n)
413
NGit.Transport.URIish r = new NGit.Transport.URIish(this);
418
/// <returns>password requested for transfer or null</returns>
419
public virtual string GetPass()
424
/// <summary>Return a new URI matching this one, but with a different password.</summary>
425
/// <remarks>Return a new URI matching this one, but with a different password.</remarks>
426
/// <param name="n">the new value for password.</param>
427
/// <returns>a new URI with the updated value.</returns>
428
public virtual NGit.Transport.URIish SetPass(string n)
430
NGit.Transport.URIish r = new NGit.Transport.URIish(this);
435
/// <returns>port number requested for transfer or -1 if not explicit</returns>
436
public virtual int GetPort()
441
/// <summary>Return a new URI matching this one, but with a different port.</summary>
442
/// <remarks>Return a new URI matching this one, but with a different port.</remarks>
443
/// <param name="n">the new value for port.</param>
444
/// <returns>a new URI with the updated value.</returns>
445
public virtual NGit.Transport.URIish SetPort(int n)
447
NGit.Transport.URIish r = new NGit.Transport.URIish(this);
448
r.port = n > 0 ? n : -1;
452
public override int GetHashCode()
455
if (GetScheme() != null)
457
hc = hc * 31 + GetScheme().GetHashCode();
459
if (GetUser() != null)
461
hc = hc * 31 + GetUser().GetHashCode();
463
if (GetPass() != null)
465
hc = hc * 31 + GetPass().GetHashCode();
467
if (GetHost() != null)
469
hc = hc * 31 + GetHost().GetHashCode();
473
hc = hc * 31 + GetPort();
475
if (GetPath() != null)
477
hc = hc * 31 + GetPath().GetHashCode();
482
public override bool Equals(object obj)
484
if (!(obj is NGit.Transport.URIish))
488
NGit.Transport.URIish b = (NGit.Transport.URIish)obj;
489
if (!Eq(GetScheme(), b.GetScheme()))
493
if (!Eq(GetUser(), b.GetUser()))
497
if (!Eq(GetPass(), b.GetPass()))
501
if (!Eq(GetHost(), b.GetHost()))
505
if (GetPort() != b.GetPort())
509
if (!Eq(GetPath(), b.GetPath()))
516
private static bool Eq(string a, string b)
522
if (a == null || b == null)
529
/// <summary>Obtain the string form of the URI, with the password included.</summary>
530
/// <remarks>Obtain the string form of the URI, with the password included.</remarks>
531
/// <returns>the URI, including its password field, if any.</returns>
532
public virtual string ToPrivateString()
537
public override string ToString()
539
return Format(false);
542
private string Format(bool includePassword)
544
StringBuilder r = new StringBuilder();
545
if (GetScheme() != null)
547
r.Append(GetScheme());
550
if (GetUser() != null)
553
if (includePassword && GetPass() != null)
559
if (GetHost() != null)
561
if (GetUser() != null)
566
if (GetScheme() != null && GetPort() > 0)
572
if (GetPath() != null)
574
if (GetScheme() != null)
576
if (!GetPath().StartsWith("/"))
583
if (GetHost() != null)
593
/// <summary>Get the "humanish" part of the path.</summary>
595
/// Get the "humanish" part of the path. Some examples of a 'humanish' part
600
/// <th>Humanish part</th>
603
/// <td><code>/path/to/repo.git</code></td>
604
/// <td rowspan="4"><code>repo</code></td>
607
/// <td><code>/path/to/repo.git/</code></td>
610
/// <td><code>/path/to/repo/.git</code></td>
613
/// <td><code>/path/to/repo/</code></td>
616
/// <td><code>/path//to</code></td>
617
/// <td>an empty string</td>
622
/// the "humanish" part of the path. May be an empty string. Never
623
/// <code>null</code>
626
/// <exception cref="System.ArgumentException">
627
/// if it's impossible to determine a humanish part, or path is
628
/// <code>null</code>
631
/// <seealso cref="GetPath()">GetPath()</seealso>
632
public virtual string GetHumanishName()
634
if (string.Empty.Equals(GetPath()) || GetPath() == null)
636
throw new ArgumentException();
638
string[] elements = GetPath().Split("/");
639
if (elements.Length == 0)
641
throw new ArgumentException();
643
string result = elements[elements.Length - 1];
644
if (Constants.DOT_GIT.Equals(result))
646
result = elements[elements.Length - 2];
650
if (result.EndsWith(Constants.DOT_GIT_EXT))
652
result = Sharpen.Runtime.Substring(result, 0, result.Length - Constants.DOT_GIT_EXT