~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to contrib/NGit/NGit.Transport/URIish.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
This code is derived from jgit (http://eclipse.org/jgit).
 
3
Copyright owners are documented in jgit's IP log.
 
4
 
 
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
 
9
 
 
10
All rights reserved.
 
11
 
 
12
Redistribution and use in source and binary forms, with or
 
13
without modification, are permitted provided that the following
 
14
conditions are met:
 
15
 
 
16
- Redistributions of source code must retain the above copyright
 
17
  notice, this list of conditions and the following disclaimer.
 
18
 
 
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.
 
23
 
 
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
 
27
  written permission.
 
28
 
 
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.
 
42
*/
 
43
 
 
44
using System;
 
45
using System.Text;
 
46
using NGit;
 
47
using Sharpen;
 
48
 
 
49
namespace NGit.Transport
 
50
{
 
51
        /// <summary>
 
52
        /// This URI like construct used for referencing Git archives over the net, as
 
53
        /// well as locally stored archives.
 
54
        /// </summary>
 
55
        /// <remarks>
 
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.
 
60
        /// </remarks>
 
61
        [System.Serializable]
 
62
        public class URIish
 
63
        {
 
64
                /// <summary>
 
65
                /// Part of a pattern which matches the scheme part (git, http, ...) of an
 
66
                /// URI.
 
67
                /// </summary>
 
68
                /// <remarks>
 
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
 
72
                /// </remarks>
 
73
                private static readonly string SCHEME_P = "([a-z][a-z0-9+-]+)://";
 
74
 
 
75
                /// <summary>Part of a pattern which matches the optional user/password part (e.g.</summary>
 
76
                /// <remarks>
 
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
 
80
                /// the password
 
81
                /// </remarks>
 
82
                private static readonly string OPT_USER_PWD_P = "(?:([^\\\\/:@]+)(?::([^\\\\/]+))?@)?";
 
83
 
 
84
                /// <summary>Part of a pattern which matches the host part of URIs.</summary>
 
85
                /// <remarks>
 
86
                /// Part of a pattern which matches the host part of URIs. Defines one
 
87
                /// capturing group containing the host name.
 
88
                /// </remarks>
 
89
                private static readonly string HOST_P = "([^\\\\/:]+)";
 
90
 
 
91
                /// <summary>Part of a pattern which matches the optional port part of URIs.</summary>
 
92
                /// <remarks>
 
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.
 
95
                /// </remarks>
 
96
                private static readonly string OPT_PORT_P = "(?::(\\d+))?";
 
97
 
 
98
                /// <summary>Part of a pattern which matches the ~username part (e.g.</summary>
 
99
                /// <remarks>
 
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.
 
102
                /// </remarks>
 
103
                private static readonly string USER_HOME_P = "(?:/~(?:[^\\\\/]+))";
 
104
 
 
105
                /// <summary>Part of a pattern which matches the optional drive letter in paths (e.g.
 
106
                ///     </summary>
 
107
                /// <remarks>
 
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.
 
110
                /// </remarks>
 
111
                private static readonly string OPT_DRIVE_LETTER_P = "(?:[A-Za-z]:)?";
 
112
 
 
113
                /// <summary>Part of a pattern which matches a relative path.</summary>
 
114
                /// <remarks>
 
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.
 
117
                /// </remarks>
 
118
                private static readonly string RELATIVE_PATH_P = "(?:(?:[^\\\\/]+[\\\\/])*[^\\\\/]+[\\\\/]?)";
 
119
 
 
120
                /// <summary>Part of a pattern which matches a relative or absolute path.</summary>
 
121
                /// <remarks>
 
122
                /// Part of a pattern which matches a relative or absolute path. Defines no
 
123
                /// capturing group.
 
124
                /// </remarks>
 
125
                private static readonly string PATH_P = "(" + OPT_DRIVE_LETTER_P + "[\\\\/]?" + RELATIVE_PATH_P
 
126
                         + ")";
 
127
 
 
128
                private const long serialVersionUID = 1L;
 
129
 
 
130
                /// <summary>
 
131
                /// A pattern matching standard URI: </br>
 
132
                /// <code>scheme "://" user_password? hostname? portnumber? path</code>
 
133
                /// </summary>
 
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
                        ) + "[\\\\/])" + ")?" + "(.+)?" + "$");
 
137
 
 
138
                /// <summary>A pattern matching the reference to a local file.</summary>
 
139
                /// <remarks>
 
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.
 
142
                /// </remarks>
 
143
                private static readonly Sharpen.Pattern LOCAL_FILE = Sharpen.Pattern.Compile("^" 
 
144
                        + "([\\\\/]?" + PATH_P + ")" + "$");
 
145
 
 
146
                /// <summary>
 
147
                /// A pattern matching a URI for the scheme 'file' which has only ':/' as
 
148
                /// separator between scheme and path.
 
149
                /// </summary>
 
150
                /// <remarks>
 
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.
 
154
                /// </remarks>
 
155
                private static readonly Sharpen.Pattern SINGLE_SLASH_FILE_URI = Sharpen.Pattern.Compile
 
156
                        ("^" + "(file):([\\\\/](?![\\\\/])" + PATH_P + ")$");
 
157
 
 
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
 
161
                         + ")$");
 
162
 
 
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 +
 
166
                         ")$");
 
167
 
 
168
                private string scheme;
 
169
 
 
170
                private string path;
 
171
 
 
172
                private string user;
 
173
 
 
174
                private string pass;
 
175
 
 
176
                private int port = -1;
 
177
 
 
178
                private string host;
 
179
 
 
180
                /// <summary>
 
181
                /// Parse and construct an
 
182
                /// <see cref="URIish">URIish</see>
 
183
                /// from a string
 
184
                /// </summary>
 
185
                /// <param name="s"></param>
 
186
                /// <exception cref="Sharpen.URISyntaxException">Sharpen.URISyntaxException</exception>
 
187
                public URIish(string s)
 
188
                {
 
189
                        //
 
190
                        //
 
191
                        // start a group containing hostname and all options only
 
192
                        // availabe when a hostname is there
 
193
                        //
 
194
                        //
 
195
                        //
 
196
                        // open a catpuring group the the user-home-dir part
 
197
                        //
 
198
                        //
 
199
                        // close the optional group containing hostname
 
200
                        //
 
201
                        //
 
202
                        //
 
203
                        //
 
204
                        //
 
205
                        //
 
206
                        //
 
207
                        //
 
208
                        //
 
209
                        //
 
210
                        //
 
211
                        //
 
212
                        //
 
213
                        //
 
214
                        //
 
215
                        //
 
216
                        //
 
217
                        Matcher matcher = SINGLE_SLASH_FILE_URI.Matcher(s);
 
218
                        if (matcher.Matches())
 
219
                        {
 
220
                                scheme = matcher.Group(1);
 
221
                                path = CleanLeadingSlashes(matcher.Group(2), scheme);
 
222
                        }
 
223
                        else
 
224
                        {
 
225
                                matcher = FULL_URI.Matcher(s);
 
226
                                if (matcher.Matches())
 
227
                                {
 
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)
 
233
                                        {
 
234
                                                port = System.Convert.ToInt32(matcher.Group(5));
 
235
                                        }
 
236
                                        path = CleanLeadingSlashes(N2e(matcher.Group(6)) + N2e(matcher.Group(7)), scheme);
 
237
                                }
 
238
                                else
 
239
                                {
 
240
                                        matcher = RELATIVE_SCP_URI.Matcher(s);
 
241
                                        if (matcher.Matches())
 
242
                                        {
 
243
                                                user = matcher.Group(1);
 
244
                                                pass = matcher.Group(2);
 
245
                                                host = matcher.Group(3);
 
246
                                                path = matcher.Group(4);
 
247
                                        }
 
248
                                        else
 
249
                                        {
 
250
                                                matcher = ABSOLUTE_SCP_URI.Matcher(s);
 
251
                                                if (matcher.Matches())
 
252
                                                {
 
253
                                                        user = matcher.Group(1);
 
254
                                                        pass = matcher.Group(2);
 
255
                                                        host = matcher.Group(3);
 
256
                                                        path = matcher.Group(4);
 
257
                                                }
 
258
                                                else
 
259
                                                {
 
260
                                                        matcher = LOCAL_FILE.Matcher(s);
 
261
                                                        if (matcher.Matches())
 
262
                                                        {
 
263
                                                                path = matcher.Group(1);
 
264
                                                        }
 
265
                                                        else
 
266
                                                        {
 
267
                                                                throw new URISyntaxException(s, JGitText.Get().cannotParseGitURIish);
 
268
                                                        }
 
269
                                                }
 
270
                                        }
 
271
                                }
 
272
                        }
 
273
                }
 
274
 
 
275
                private string N2e(string s)
 
276
                {
 
277
                        if (s == null)
 
278
                        {
 
279
                                return string.Empty;
 
280
                        }
 
281
                        else
 
282
                        {
 
283
                                return s;
 
284
                        }
 
285
                }
 
286
 
 
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)
 
290
                {
 
291
                        if (p.Length >= 3 && p[0] == '/' && p[2] == ':' && (p[1] >= 'A' && p[1] <= 'Z' ||
 
292
                                 p[1] >= 'a' && p[1] <= 'z'))
 
293
                        {
 
294
                                return Sharpen.Runtime.Substring(p, 1);
 
295
                        }
 
296
                        else
 
297
                        {
 
298
                                if (s != null && p.Length >= 2 && p[0] == '/' && p[1] == '~')
 
299
                                {
 
300
                                        return Sharpen.Runtime.Substring(p, 1);
 
301
                                }
 
302
                                else
 
303
                                {
 
304
                                        return p;
 
305
                                }
 
306
                        }
 
307
                }
 
308
 
 
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>
 
312
                public URIish(Uri u)
 
313
                {
 
314
                        scheme = u.Scheme;
 
315
                        path = u.AbsolutePath;
 
316
                        string ui = u.GetUserInfo();
 
317
                        if (ui != null)
 
318
                        {
 
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);
 
322
                        }
 
323
                        port = u.Port;
 
324
                        host = u.GetHost();
 
325
                }
 
326
 
 
327
                /// <summary>Create an empty, non-configured URI.</summary>
 
328
                /// <remarks>Create an empty, non-configured URI.</remarks>
 
329
                public URIish()
 
330
                {
 
331
                }
 
332
 
 
333
                private URIish(NGit.Transport.URIish u)
 
334
                {
 
335
                        // Configure nothing.
 
336
                        this.scheme = u.scheme;
 
337
                        this.path = u.path;
 
338
                        this.user = u.user;
 
339
                        this.pass = u.pass;
 
340
                        this.port = u.port;
 
341
                        this.host = u.host;
 
342
                }
 
343
 
 
344
                /// <returns>true if this URI references a repository on another system.</returns>
 
345
                public virtual bool IsRemote()
 
346
                {
 
347
                        return GetHost() != null;
 
348
                }
 
349
 
 
350
                /// <returns>host name part or null</returns>
 
351
                public virtual string GetHost()
 
352
                {
 
353
                        return host;
 
354
                }
 
355
 
 
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)
 
361
                {
 
362
                        NGit.Transport.URIish r = new NGit.Transport.URIish(this);
 
363
                        r.host = n;
 
364
                        return r;
 
365
                }
 
366
 
 
367
                /// <returns>protocol name or null for local references</returns>
 
368
                public virtual string GetScheme()
 
369
                {
 
370
                        return scheme;
 
371
                }
 
372
 
 
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)
 
378
                {
 
379
                        NGit.Transport.URIish r = new NGit.Transport.URIish(this);
 
380
                        r.scheme = n;
 
381
                        return r;
 
382
                }
 
383
 
 
384
                /// <returns>path name component</returns>
 
385
                public virtual string GetPath()
 
386
                {
 
387
                        return path;
 
388
                }
 
389
 
 
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)
 
395
                {
 
396
                        NGit.Transport.URIish r = new NGit.Transport.URIish(this);
 
397
                        r.path = n;
 
398
                        return r;
 
399
                }
 
400
 
 
401
                /// <returns>user name requested for transfer or null</returns>
 
402
                public virtual string GetUser()
 
403
                {
 
404
                        return user;
 
405
                }
 
406
 
 
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)
 
412
                {
 
413
                        NGit.Transport.URIish r = new NGit.Transport.URIish(this);
 
414
                        r.user = n;
 
415
                        return r;
 
416
                }
 
417
 
 
418
                /// <returns>password requested for transfer or null</returns>
 
419
                public virtual string GetPass()
 
420
                {
 
421
                        return pass;
 
422
                }
 
423
 
 
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)
 
429
                {
 
430
                        NGit.Transport.URIish r = new NGit.Transport.URIish(this);
 
431
                        r.pass = n;
 
432
                        return r;
 
433
                }
 
434
 
 
435
                /// <returns>port number requested for transfer or -1 if not explicit</returns>
 
436
                public virtual int GetPort()
 
437
                {
 
438
                        return port;
 
439
                }
 
440
 
 
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)
 
446
                {
 
447
                        NGit.Transport.URIish r = new NGit.Transport.URIish(this);
 
448
                        r.port = n > 0 ? n : -1;
 
449
                        return r;
 
450
                }
 
451
 
 
452
                public override int GetHashCode()
 
453
                {
 
454
                        int hc = 0;
 
455
                        if (GetScheme() != null)
 
456
                        {
 
457
                                hc = hc * 31 + GetScheme().GetHashCode();
 
458
                        }
 
459
                        if (GetUser() != null)
 
460
                        {
 
461
                                hc = hc * 31 + GetUser().GetHashCode();
 
462
                        }
 
463
                        if (GetPass() != null)
 
464
                        {
 
465
                                hc = hc * 31 + GetPass().GetHashCode();
 
466
                        }
 
467
                        if (GetHost() != null)
 
468
                        {
 
469
                                hc = hc * 31 + GetHost().GetHashCode();
 
470
                        }
 
471
                        if (GetPort() > 0)
 
472
                        {
 
473
                                hc = hc * 31 + GetPort();
 
474
                        }
 
475
                        if (GetPath() != null)
 
476
                        {
 
477
                                hc = hc * 31 + GetPath().GetHashCode();
 
478
                        }
 
479
                        return hc;
 
480
                }
 
481
 
 
482
                public override bool Equals(object obj)
 
483
                {
 
484
                        if (!(obj is NGit.Transport.URIish))
 
485
                        {
 
486
                                return false;
 
487
                        }
 
488
                        NGit.Transport.URIish b = (NGit.Transport.URIish)obj;
 
489
                        if (!Eq(GetScheme(), b.GetScheme()))
 
490
                        {
 
491
                                return false;
 
492
                        }
 
493
                        if (!Eq(GetUser(), b.GetUser()))
 
494
                        {
 
495
                                return false;
 
496
                        }
 
497
                        if (!Eq(GetPass(), b.GetPass()))
 
498
                        {
 
499
                                return false;
 
500
                        }
 
501
                        if (!Eq(GetHost(), b.GetHost()))
 
502
                        {
 
503
                                return false;
 
504
                        }
 
505
                        if (GetPort() != b.GetPort())
 
506
                        {
 
507
                                return false;
 
508
                        }
 
509
                        if (!Eq(GetPath(), b.GetPath()))
 
510
                        {
 
511
                                return false;
 
512
                        }
 
513
                        return true;
 
514
                }
 
515
 
 
516
                private static bool Eq(string a, string b)
 
517
                {
 
518
                        if (a == b)
 
519
                        {
 
520
                                return true;
 
521
                        }
 
522
                        if (a == null || b == null)
 
523
                        {
 
524
                                return false;
 
525
                        }
 
526
                        return a.Equals(b);
 
527
                }
 
528
 
 
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()
 
533
                {
 
534
                        return Format(true);
 
535
                }
 
536
 
 
537
                public override string ToString()
 
538
                {
 
539
                        return Format(false);
 
540
                }
 
541
 
 
542
                private string Format(bool includePassword)
 
543
                {
 
544
                        StringBuilder r = new StringBuilder();
 
545
                        if (GetScheme() != null)
 
546
                        {
 
547
                                r.Append(GetScheme());
 
548
                                r.Append("://");
 
549
                        }
 
550
                        if (GetUser() != null)
 
551
                        {
 
552
                                r.Append(GetUser());
 
553
                                if (includePassword && GetPass() != null)
 
554
                                {
 
555
                                        r.Append(':');
 
556
                                        r.Append(GetPass());
 
557
                                }
 
558
                        }
 
559
                        if (GetHost() != null)
 
560
                        {
 
561
                                if (GetUser() != null)
 
562
                                {
 
563
                                        r.Append('@');
 
564
                                }
 
565
                                r.Append(GetHost());
 
566
                                if (GetScheme() != null && GetPort() > 0)
 
567
                                {
 
568
                                        r.Append(':');
 
569
                                        r.Append(GetPort());
 
570
                                }
 
571
                        }
 
572
                        if (GetPath() != null)
 
573
                        {
 
574
                                if (GetScheme() != null)
 
575
                                {
 
576
                                        if (!GetPath().StartsWith("/"))
 
577
                                        {
 
578
                                                r.Append('/');
 
579
                                        }
 
580
                                }
 
581
                                else
 
582
                                {
 
583
                                        if (GetHost() != null)
 
584
                                        {
 
585
                                                r.Append(':');
 
586
                                        }
 
587
                                }
 
588
                                r.Append(GetPath());
 
589
                        }
 
590
                        return r.ToString();
 
591
                }
 
592
 
 
593
                /// <summary>Get the "humanish" part of the path.</summary>
 
594
                /// <remarks>
 
595
                /// Get the "humanish" part of the path. Some examples of a 'humanish' part
 
596
                /// for a full path:
 
597
                /// <table>
 
598
                /// <tr>
 
599
                /// <th>Path</th>
 
600
                /// <th>Humanish part</th>
 
601
                /// </tr>
 
602
                /// <tr>
 
603
                /// <td><code>/path/to/repo.git</code></td>
 
604
                /// <td rowspan="4"><code>repo</code></td>
 
605
                /// </tr>
 
606
                /// <tr>
 
607
                /// <td><code>/path/to/repo.git/</code></td>
 
608
                /// </tr>
 
609
                /// <tr>
 
610
                /// <td><code>/path/to/repo/.git</code></td>
 
611
                /// </tr>
 
612
                /// <tr>
 
613
                /// <td><code>/path/to/repo/</code></td>
 
614
                /// </tr>
 
615
                /// <tr>
 
616
                /// <td><code>/path//to</code></td>
 
617
                /// <td>an empty string</td>
 
618
                /// </tr>
 
619
                /// </table>
 
620
                /// </remarks>
 
621
                /// <returns>
 
622
                /// the "humanish" part of the path. May be an empty string. Never
 
623
                /// <code>null</code>
 
624
                /// .
 
625
                /// </returns>
 
626
                /// <exception cref="System.ArgumentException">
 
627
                /// if it's impossible to determine a humanish part, or path is
 
628
                /// <code>null</code>
 
629
                /// or empty
 
630
                /// </exception>
 
631
                /// <seealso cref="GetPath()">GetPath()</seealso>
 
632
                public virtual string GetHumanishName()
 
633
                {
 
634
                        if (string.Empty.Equals(GetPath()) || GetPath() == null)
 
635
                        {
 
636
                                throw new ArgumentException();
 
637
                        }
 
638
                        string[] elements = GetPath().Split("/");
 
639
                        if (elements.Length == 0)
 
640
                        {
 
641
                                throw new ArgumentException();
 
642
                        }
 
643
                        string result = elements[elements.Length - 1];
 
644
                        if (Constants.DOT_GIT.Equals(result))
 
645
                        {
 
646
                                result = elements[elements.Length - 2];
 
647
                        }
 
648
                        else
 
649
                        {
 
650
                                if (result.EndsWith(Constants.DOT_GIT_EXT))
 
651
                                {
 
652
                                        result = Sharpen.Runtime.Substring(result, 0, result.Length - Constants.DOT_GIT_EXT
 
653
                                                .Length);
 
654
                                }
 
655
                        }
 
656
                        return result;
 
657
                }
 
658
        }
 
659
}