Show More
@@ -381,6 +381,14 b' web::' | |||||
381 | Default is false. |
|
381 | Default is false. | |
382 | allowpull;; |
|
382 | allowpull;; | |
383 | Whether to allow pulling from the repository. Default is true. |
|
383 | Whether to allow pulling from the repository. Default is true. | |
|
384 | allow_push;; | |||
|
385 | Whether to allow pushing to the repository. If empty or not set, | |||
|
386 | push is not allowed. If the special value "*", any remote user | |||
|
387 | can push, including unauthenticated users. Otherwise, the remote | |||
|
388 | user must have been authenticated, and the authenticated user name | |||
|
389 | must be present in this list (separated by whitespace or ","). | |||
|
390 | The contents of the allow_push list are examined after the | |||
|
391 | deny_push list. | |||
384 | allowzip;; |
|
392 | allowzip;; | |
385 | (DEPRECATED) Whether to allow .zip downloading of repo revisions. |
|
393 | (DEPRECATED) Whether to allow .zip downloading of repo revisions. | |
386 | Default is false. This feature creates temporary files. |
|
394 | Default is false. This feature creates temporary files. | |
@@ -391,6 +399,13 b' web::' | |||||
391 | contact;; |
|
399 | contact;; | |
392 | Name or email address of the person in charge of the repository. |
|
400 | Name or email address of the person in charge of the repository. | |
393 | Default is "unknown". |
|
401 | Default is "unknown". | |
|
402 | deny_push;; | |||
|
403 | Whether to deny pushing to the repository. If empty or not set, | |||
|
404 | push is not denied. If the special value "*", all remote users | |||
|
405 | are denied push. Otherwise, unauthenticated users are all denied, | |||
|
406 | and any authenticated user name present in this list (separated by | |||
|
407 | whitespace or ",") is also denied. The contents of the deny_push | |||
|
408 | list are examined before the allow_push list. | |||
394 | description;; |
|
409 | description;; | |
395 | Textual description of the repository's purpose or contents. |
|
410 | Textual description of the repository's purpose or contents. | |
396 | Default is "unknown". |
|
411 | Default is "unknown". | |
@@ -407,6 +422,9 b' web::' | |||||
407 | Maximum number of files to list per changeset. Default is 10. |
|
422 | Maximum number of files to list per changeset. Default is 10. | |
408 | port;; |
|
423 | port;; | |
409 | Port to listen on. Default is 8000. |
|
424 | Port to listen on. Default is 8000. | |
|
425 | push_ssl;; | |||
|
426 | Whether to require that inbound pushes be transported over SSL to | |||
|
427 | prevent password sniffing. Default is true. | |||
410 | style;; |
|
428 | style;; | |
411 | Which template map style to use. |
|
429 | Which template map style to use. | |
412 | templates;; |
|
430 | templates;; |
@@ -10,6 +10,7 b'' | |||||
10 | */ |
|
10 | */ | |
11 |
|
11 | |||
12 | #include <Python.h> |
|
12 | #include <Python.h> | |
|
13 | #include <stdint.h> | |||
13 | #include <stdlib.h> |
|
14 | #include <stdlib.h> | |
14 | #include <string.h> |
|
15 | #include <string.h> | |
15 |
|
16 |
@@ -379,11 +379,20 b' def dodiff(fp, ui, repo, node1, node2, f' | |||||
379 | if node2: |
|
379 | if node2: | |
380 | change = repo.changelog.read(node2) |
|
380 | change = repo.changelog.read(node2) | |
381 | mmap2 = repo.manifest.read(change[0]) |
|
381 | mmap2 = repo.manifest.read(change[0]) | |
382 | date2 = util.datestr(change[2]) |
|
382 | _date2 = util.datestr(change[2]) | |
|
383 | def date2(f): | |||
|
384 | return _date2 | |||
383 | def read(f): |
|
385 | def read(f): | |
384 | return repo.file(f).read(mmap2[f]) |
|
386 | return repo.file(f).read(mmap2[f]) | |
385 | else: |
|
387 | else: | |
386 |
|
|
388 | tz = util.makedate()[1] | |
|
389 | _date2 = util.datestr() | |||
|
390 | def date2(f): | |||
|
391 | try: | |||
|
392 | return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz)) | |||
|
393 | except IOError, err: | |||
|
394 | if err.errno != errno.ENOENT: raise | |||
|
395 | return _date2 | |||
387 | def read(f): |
|
396 | def read(f): | |
388 | return repo.wread(f) |
|
397 | return repo.wread(f) | |
389 |
|
398 | |||
@@ -401,17 +410,17 b' def dodiff(fp, ui, repo, node1, node2, f' | |||||
401 | if f in mmap: |
|
410 | if f in mmap: | |
402 | to = repo.file(f).read(mmap[f]) |
|
411 | to = repo.file(f).read(mmap[f]) | |
403 | tn = read(f) |
|
412 | tn = read(f) | |
404 | fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text, |
|
413 | fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text, | |
405 | showfunc=showfunc, ignorews=ignorews)) |
|
414 | showfunc=showfunc, ignorews=ignorews)) | |
406 | for f in added: |
|
415 | for f in added: | |
407 | to = None |
|
416 | to = None | |
408 | tn = read(f) |
|
417 | tn = read(f) | |
409 | fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text, |
|
418 | fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text, | |
410 | showfunc=showfunc, ignorews=ignorews)) |
|
419 | showfunc=showfunc, ignorews=ignorews)) | |
411 | for f in removed: |
|
420 | for f in removed: | |
412 | to = repo.file(f).read(mmap[f]) |
|
421 | to = repo.file(f).read(mmap[f]) | |
413 | tn = None |
|
422 | tn = None | |
414 | fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text, |
|
423 | fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text, | |
415 | showfunc=showfunc, ignorews=ignorews)) |
|
424 | showfunc=showfunc, ignorews=ignorews)) | |
416 |
|
425 | |||
417 | def trimuser(ui, name, rev, revcache): |
|
426 | def trimuser(ui, name, rev, revcache): |
@@ -11,34 +11,60 b' from demandload import *' | |||||
11 | from i18n import gettext as _ |
|
11 | from i18n import gettext as _ | |
12 | demandload(globals(), "localrepo bundlerepo httprepo sshrepo statichttprepo") |
|
12 | demandload(globals(), "localrepo bundlerepo httprepo sshrepo statichttprepo") | |
13 |
|
13 | |||
|
14 | def bundle(ui, path): | |||
|
15 | if path.startswith('bundle://'): | |||
|
16 | path = path[9:] | |||
|
17 | else: | |||
|
18 | path = path[7:] | |||
|
19 | s = path.split("+", 1) | |||
|
20 | if len(s) == 1: | |||
|
21 | repopath, bundlename = "", s[0] | |||
|
22 | else: | |||
|
23 | repopath, bundlename = s | |||
|
24 | return bundlerepo.bundlerepository(ui, repopath, bundlename) | |||
|
25 | ||||
|
26 | def hg(ui, path): | |||
|
27 | ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n")) | |||
|
28 | return httprepo.httprepository(ui, path.replace("hg://", "http://")) | |||
|
29 | ||||
|
30 | def local_(ui, path, create=0): | |||
|
31 | return localrepo.localrepository(ui, path, create) | |||
|
32 | ||||
|
33 | def old_http(ui, path): | |||
|
34 | ui.warn(_("old-http:// syntax is deprecated, " | |||
|
35 | "please use static-http:// instead\n")) | |||
|
36 | return statichttprepo.statichttprepository( | |||
|
37 | ui, path.replace("old-http://", "http://")) | |||
|
38 | ||||
|
39 | def static_http(ui, path): | |||
|
40 | return statichttprepo.statichttprepository( | |||
|
41 | ui, path.replace("static-http://", "http://")) | |||
|
42 | ||||
|
43 | protocols = { | |||
|
44 | 'bundle': bundle, | |||
|
45 | 'file': local_, | |||
|
46 | 'hg': hg, | |||
|
47 | 'http': lambda ui, path: httprepo.httprepository(ui, path), | |||
|
48 | 'https': lambda ui, path: httprepo.httpsrepository(ui, path), | |||
|
49 | 'old-http': old_http, | |||
|
50 | 'ssh': lambda ui, path: sshrepo.sshrepository(ui, path), | |||
|
51 | 'static-http': static_http, | |||
|
52 | None: local_, | |||
|
53 | } | |||
|
54 | ||||
14 | def repository(ui, path=None, create=0): |
|
55 | def repository(ui, path=None, create=0): | |
15 |
|
|
56 | scheme = path | |
16 | if path.startswith("http://"): |
|
57 | if scheme: | |
17 | return httprepo.httprepository(ui, path) |
|
58 | c = scheme.find(':') | |
18 | if path.startswith("https://"): |
|
59 | scheme = c >= 0 and scheme[:c] | |
19 | return httprepo.httpsrepository(ui, path) |
|
60 | if not scheme: scheme = None | |
20 | if path.startswith("hg://"): |
|
61 | try: | |
21 | ui.warn(_("hg:// syntax is deprecated, " |
|
62 | ctor = protocols[scheme] | |
22 | "please use http:// instead\n")) |
|
63 | if create: | |
23 | return httprepo.httprepository( |
|
64 | return ctor(ui, path, create) | |
24 | ui, path.replace("hg://", "http://")) |
|
65 | return ctor(ui, path) | |
25 | if path.startswith("old-http://"): |
|
66 | except KeyError: | |
26 | ui.warn(_("old-http:// syntax is deprecated, " |
|
67 | raise util.Abort(_('protocol "%s" not known') % scheme) | |
27 | "please use static-http:// instead\n")) |
|
68 | except TypeError: | |
28 | return statichttprepo.statichttprepository( |
|
69 | raise util.Abort(_('cannot create new repository over "%s" protocol') % | |
29 | ui, path.replace("old-http://", "http://")) |
|
70 | (scheme or 'file')) | |
30 | if path.startswith("static-http://"): |
|
|||
31 | return statichttprepo.statichttprepository( |
|
|||
32 | ui, path.replace("static-http://", "http://")) |
|
|||
33 | if path.startswith("ssh://"): |
|
|||
34 | return sshrepo.sshrepository(ui, path) |
|
|||
35 | if path.startswith("bundle://"): |
|
|||
36 | path = path[9:] |
|
|||
37 | s = path.split("+", 1) |
|
|||
38 | if len(s) == 1: |
|
|||
39 | repopath, bundlename = "", s[0] |
|
|||
40 | else: |
|
|||
41 | repopath, bundlename = s |
|
|||
42 | return bundlerepo.bundlerepository(ui, repopath, bundlename) |
|
|||
43 |
|
||||
44 | return localrepo.localrepository(ui, path, create) |
|
@@ -10,7 +10,7 b' import os' | |||||
10 | import os.path |
|
10 | import os.path | |
11 | import mimetypes |
|
11 | import mimetypes | |
12 | from mercurial.demandload import demandload |
|
12 | from mercurial.demandload import demandload | |
13 | demandload(globals(), "re zlib ConfigParser cStringIO") |
|
13 | demandload(globals(), "re zlib ConfigParser cStringIO sys tempfile") | |
14 | demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,templater") |
|
14 | demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,templater") | |
15 | demandload(globals(), "mercurial.hgweb.request:hgrequest") |
|
15 | demandload(globals(), "mercurial.hgweb.request:hgrequest") | |
16 | demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile") |
|
16 | demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile") | |
@@ -835,7 +835,97 b' class hgweb(object):' | |||||
835 | or self.t("error", error="%r not found" % fname)) |
|
835 | or self.t("error", error="%r not found" % fname)) | |
836 |
|
836 | |||
837 | def do_capabilities(self, req): |
|
837 | def do_capabilities(self, req): | |
838 | resp = '' |
|
838 | resp = 'unbundle' | |
839 | req.httphdr("application/mercurial-0.1", length=len(resp)) |
|
839 | req.httphdr("application/mercurial-0.1", length=len(resp)) | |
840 | req.write(resp) |
|
840 | req.write(resp) | |
841 |
|
841 | |||
|
842 | def check_perm(self, req, op, default): | |||
|
843 | '''check permission for operation based on user auth. | |||
|
844 | return true if op allowed, else false. | |||
|
845 | default is policy to use if no config given.''' | |||
|
846 | ||||
|
847 | user = req.env.get('REMOTE_USER') | |||
|
848 | ||||
|
849 | deny = self.repo.ui.config('web', 'deny_' + op, '') | |||
|
850 | deny = deny.replace(',', ' ').split() | |||
|
851 | ||||
|
852 | if deny and (not user or deny == ['*'] or user in deny): | |||
|
853 | return False | |||
|
854 | ||||
|
855 | allow = self.repo.ui.config('web', 'allow_' + op, '') | |||
|
856 | allow = allow.replace(',', ' ').split() | |||
|
857 | ||||
|
858 | return (allow and (allow == ['*'] or user in allow)) or default | |||
|
859 | ||||
|
860 | def do_unbundle(self, req): | |||
|
861 | def bail(response, headers={}): | |||
|
862 | length = int(req.env['CONTENT_LENGTH']) | |||
|
863 | for s in util.filechunkiter(req, limit=length): | |||
|
864 | # drain incoming bundle, else client will not see | |||
|
865 | # response when run outside cgi script | |||
|
866 | pass | |||
|
867 | req.httphdr("application/mercurial-0.1", headers=headers) | |||
|
868 | req.write('0\n') | |||
|
869 | req.write(response) | |||
|
870 | ||||
|
871 | # require ssl by default, auth info cannot be sniffed and | |||
|
872 | # replayed | |||
|
873 | ssl_req = self.repo.ui.configbool('web', 'push_ssl', True) | |||
|
874 | if ssl_req and not req.env.get('HTTPS'): | |||
|
875 | bail(_('ssl required\n')) | |||
|
876 | return | |||
|
877 | ||||
|
878 | # do not allow push unless explicitly allowed | |||
|
879 | if not self.check_perm(req, 'push', False): | |||
|
880 | bail(_('push not authorized\n'), | |||
|
881 | headers={'status': '401 Unauthorized'}) | |||
|
882 | return | |||
|
883 | ||||
|
884 | req.httphdr("application/mercurial-0.1") | |||
|
885 | ||||
|
886 | their_heads = req.form['heads'][0].split(' ') | |||
|
887 | ||||
|
888 | def check_heads(): | |||
|
889 | heads = map(hex, self.repo.heads()) | |||
|
890 | return their_heads == [hex('force')] or their_heads == heads | |||
|
891 | ||||
|
892 | # fail early if possible | |||
|
893 | if not check_heads(): | |||
|
894 | bail(_('unsynced changes\n')) | |||
|
895 | return | |||
|
896 | ||||
|
897 | # do not lock repo until all changegroup data is | |||
|
898 | # streamed. save to temporary file. | |||
|
899 | ||||
|
900 | fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-') | |||
|
901 | fp = os.fdopen(fd, 'wb+') | |||
|
902 | try: | |||
|
903 | length = int(req.env['CONTENT_LENGTH']) | |||
|
904 | for s in util.filechunkiter(req, limit=length): | |||
|
905 | fp.write(s) | |||
|
906 | ||||
|
907 | lock = self.repo.lock() | |||
|
908 | try: | |||
|
909 | if not check_heads(): | |||
|
910 | req.write('0\n') | |||
|
911 | req.write(_('unsynced changes\n')) | |||
|
912 | return | |||
|
913 | ||||
|
914 | fp.seek(0) | |||
|
915 | ||||
|
916 | # send addchangegroup output to client | |||
|
917 | ||||
|
918 | old_stdout = sys.stdout | |||
|
919 | sys.stdout = cStringIO.StringIO() | |||
|
920 | ||||
|
921 | try: | |||
|
922 | ret = self.repo.addchangegroup(fp, 'serve') | |||
|
923 | req.write('%d\n' % ret) | |||
|
924 | req.write(sys.stdout.getvalue()) | |||
|
925 | finally: | |||
|
926 | sys.stdout = old_stdout | |||
|
927 | finally: | |||
|
928 | lock.release() | |||
|
929 | finally: | |||
|
930 | fp.close() | |||
|
931 | os.unlink(tempname) |
@@ -18,6 +18,9 b' class hgrequest(object):' | |||||
18 | self.form = cgi.parse(self.inp, self.env, keep_blank_values=1) |
|
18 | self.form = cgi.parse(self.inp, self.env, keep_blank_values=1) | |
19 | self.will_close = True |
|
19 | self.will_close = True | |
20 |
|
20 | |||
|
21 | def read(self, count=-1): | |||
|
22 | return self.inp.read(count) | |||
|
23 | ||||
21 | def write(self, *things): |
|
24 | def write(self, *things): | |
22 | for thing in things: |
|
25 | for thing in things: | |
23 | if hasattr(thing, "__iter__"): |
|
26 | if hasattr(thing, "__iter__"): | |
@@ -42,9 +45,9 b' class hgrequest(object):' | |||||
42 | self.out.write("%s: %s\r\n" % header) |
|
45 | self.out.write("%s: %s\r\n" % header) | |
43 | self.out.write("\r\n") |
|
46 | self.out.write("\r\n") | |
44 |
|
47 | |||
45 | def httphdr(self, type, filename=None, length=0): |
|
48 | def httphdr(self, type, filename=None, length=0, headers={}): | |
46 |
|
49 | headers = headers.items() | ||
47 |
headers |
|
50 | headers.append(('Content-type', type)) | |
48 | if filename: |
|
51 | if filename: | |
49 | headers.append(('Content-disposition', 'attachment; filename=%s' % |
|
52 | headers.append(('Content-disposition', 'attachment; filename=%s' % | |
50 | filename)) |
|
53 | filename)) |
@@ -10,7 +10,7 b' from remoterepo import *' | |||||
10 | from i18n import gettext as _ |
|
10 | from i18n import gettext as _ | |
11 | from demandload import * |
|
11 | from demandload import * | |
12 | demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib") |
|
12 | demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib") | |
13 | demandload(globals(), "keepalive") |
|
13 | demandload(globals(), "errno keepalive tempfile socket") | |
14 |
|
14 | |||
15 | class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm): |
|
15 | class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm): | |
16 | def __init__(self, ui): |
|
16 | def __init__(self, ui): | |
@@ -69,6 +69,22 b' def netlocunsplit(host, port, user=None,' | |||||
69 | return userpass + '@' + hostport |
|
69 | return userpass + '@' + hostport | |
70 | return hostport |
|
70 | return hostport | |
71 |
|
71 | |||
|
72 | class httpconnection(keepalive.HTTPConnection): | |||
|
73 | # must be able to send big bundle as stream. | |||
|
74 | ||||
|
75 | def send(self, data): | |||
|
76 | if isinstance(data, str): | |||
|
77 | keepalive.HTTPConnection.send(self, data) | |||
|
78 | else: | |||
|
79 | # if auth required, some data sent twice, so rewind here | |||
|
80 | data.seek(0) | |||
|
81 | for chunk in util.filechunkiter(data): | |||
|
82 | keepalive.HTTPConnection.send(self, chunk) | |||
|
83 | ||||
|
84 | class httphandler(keepalive.HTTPHandler): | |||
|
85 | def http_open(self, req): | |||
|
86 | return self.do_open(httpconnection, req) | |||
|
87 | ||||
72 | class httprepository(remoterepository): |
|
88 | class httprepository(remoterepository): | |
73 | def __init__(self, ui, path): |
|
89 | def __init__(self, ui, path): | |
74 | self.caps = None |
|
90 | self.caps = None | |
@@ -86,7 +102,7 b' class httprepository(remoterepository):' | |||||
86 |
|
102 | |||
87 | proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') |
|
103 | proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') | |
88 | proxyauthinfo = None |
|
104 | proxyauthinfo = None | |
89 |
handler = |
|
105 | handler = httphandler() | |
90 |
|
106 | |||
91 | if proxyurl: |
|
107 | if proxyurl: | |
92 | # proxy can be proper url or host[:port] |
|
108 | # proxy can be proper url or host[:port] | |
@@ -154,6 +170,8 b' class httprepository(remoterepository):' | |||||
154 | self.caps = self.do_read('capabilities').split() |
|
170 | self.caps = self.do_read('capabilities').split() | |
155 | except hg.RepoError: |
|
171 | except hg.RepoError: | |
156 | self.caps = () |
|
172 | self.caps = () | |
|
173 | self.ui.debug(_('capabilities: %s\n') % | |||
|
174 | (' '.join(self.caps or ['none']))) | |||
157 | return self.caps |
|
175 | return self.caps | |
158 |
|
176 | |||
159 | capabilities = property(get_caps) |
|
177 | capabilities = property(get_caps) | |
@@ -165,13 +183,19 b' class httprepository(remoterepository):' | |||||
165 | raise util.Abort(_('operation not supported over http')) |
|
183 | raise util.Abort(_('operation not supported over http')) | |
166 |
|
184 | |||
167 | def do_cmd(self, cmd, **args): |
|
185 | def do_cmd(self, cmd, **args): | |
|
186 | data = args.pop('data', None) | |||
|
187 | headers = args.pop('headers', {}) | |||
168 | self.ui.debug(_("sending %s command\n") % cmd) |
|
188 | self.ui.debug(_("sending %s command\n") % cmd) | |
169 | q = {"cmd": cmd} |
|
189 | q = {"cmd": cmd} | |
170 | q.update(args) |
|
190 | q.update(args) | |
171 | qs = urllib.urlencode(q) |
|
191 | qs = urllib.urlencode(q) | |
172 | cu = "%s?%s" % (self.url, qs) |
|
192 | cu = "%s?%s" % (self.url, qs) | |
173 | try: |
|
193 | try: | |
174 | resp = urllib2.urlopen(cu) |
|
194 | resp = urllib2.urlopen(urllib2.Request(cu, data, headers)) | |
|
195 | except urllib2.HTTPError, inst: | |||
|
196 | if inst.code == 401: | |||
|
197 | raise util.Abort(_('authorization failed')) | |||
|
198 | raise | |||
175 | except httplib.HTTPException, inst: |
|
199 | except httplib.HTTPException, inst: | |
176 | self.ui.debug(_('http error while sending %s command\n') % cmd) |
|
200 | self.ui.debug(_('http error while sending %s command\n') % cmd) | |
177 | self.ui.print_exc() |
|
201 | self.ui.print_exc() | |
@@ -249,7 +273,34 b' class httprepository(remoterepository):' | |||||
249 | return util.chunkbuffer(zgenerator(util.filechunkiter(f))) |
|
273 | return util.chunkbuffer(zgenerator(util.filechunkiter(f))) | |
250 |
|
274 | |||
251 | def unbundle(self, cg, heads, source): |
|
275 | def unbundle(self, cg, heads, source): | |
252 | raise util.Abort(_('operation not supported over http')) |
|
276 | # have to stream bundle to a temp file because we do not have | |
|
277 | # http 1.1 chunked transfer. | |||
|
278 | ||||
|
279 | fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-') | |||
|
280 | fp = os.fdopen(fd, 'wb+') | |||
|
281 | try: | |||
|
282 | for chunk in util.filechunkiter(cg): | |||
|
283 | fp.write(chunk) | |||
|
284 | length = fp.tell() | |||
|
285 | try: | |||
|
286 | rfp = self.do_cmd( | |||
|
287 | 'unbundle', data=fp, | |||
|
288 | headers={'content-length': length, | |||
|
289 | 'content-type': 'application/octet-stream'}, | |||
|
290 | heads=' '.join(map(hex, heads))) | |||
|
291 | try: | |||
|
292 | ret = int(rfp.readline()) | |||
|
293 | self.ui.write(rfp.read()) | |||
|
294 | return ret | |||
|
295 | finally: | |||
|
296 | rfp.close() | |||
|
297 | except socket.error, err: | |||
|
298 | if err[0] in (errno.ECONNRESET, errno.EPIPE): | |||
|
299 | raise util.Abort(_('push failed: %s'), err[1]) | |||
|
300 | raise util.Abort(err[1]) | |||
|
301 | finally: | |||
|
302 | fp.close() | |||
|
303 | os.unlink(tempname) | |||
253 |
|
304 | |||
254 | class httpsrepository(httprepository): |
|
305 | class httpsrepository(httprepository): | |
255 | pass |
|
306 | pass |
@@ -1115,9 +1115,8 b' class localrepository(object):' | |||||
1115 | # servers, http servers). |
|
1115 | # servers, http servers). | |
1116 |
|
1116 | |||
1117 | if 'unbundle' in remote.capabilities: |
|
1117 | if 'unbundle' in remote.capabilities: | |
1118 | self.push_unbundle(remote, force, revs) |
|
1118 | return self.push_unbundle(remote, force, revs) | |
1119 | else: |
|
1119 | return self.push_addchangegroup(remote, force, revs) | |
1120 | self.push_addchangegroup(remote, force, revs) |
|
|||
1121 |
|
1120 | |||
1122 | def prepush(self, remote, force, revs): |
|
1121 | def prepush(self, remote, force, revs): | |
1123 | base = {} |
|
1122 | base = {} |
@@ -23,13 +23,15 b'' | |||||
23 | #include <Python.h> |
|
23 | #include <Python.h> | |
24 | #include <stdlib.h> |
|
24 | #include <stdlib.h> | |
25 | #include <string.h> |
|
25 | #include <string.h> | |
|
26 | ||||
26 | #ifdef _WIN32 |
|
27 | #ifdef _WIN32 | |
27 | #ifdef _MSC_VER |
|
28 | # ifdef _MSC_VER | |
28 | #define inline __inline |
|
29 | /* msvc 6.0 has problems */ | |
|
30 | # define inline __inline | |||
29 | typedef unsigned long uint32_t; |
|
31 | typedef unsigned long uint32_t; | |
30 | #else |
|
32 | # else | |
31 | #include <stdint.h> |
|
33 | # include <stdint.h> | |
32 | #endif |
|
34 | # endif | |
33 | static uint32_t ntohl(uint32_t x) |
|
35 | static uint32_t ntohl(uint32_t x) | |
34 | { |
|
36 | { | |
35 | return ((x & 0x000000ffUL) << 24) | |
|
37 | return ((x & 0x000000ffUL) << 24) | | |
@@ -38,8 +40,10 b' static uint32_t ntohl(uint32_t x)' | |||||
38 | ((x & 0xff000000UL) >> 24); |
|
40 | ((x & 0xff000000UL) >> 24); | |
39 | } |
|
41 | } | |
40 | #else |
|
42 | #else | |
41 | #include <sys/types.h> |
|
43 | /* not windows */ | |
42 |
#include < |
|
44 | # include <sys/types.h> | |
|
45 | # include <arpa/inet.h> | |||
|
46 | # include <stdint.h> | |||
43 | #endif |
|
47 | #endif | |
44 |
|
48 | |||
45 | static char mpatch_doc[] = "Efficient binary patching."; |
|
49 | static char mpatch_doc[] = "Efficient binary patching."; |
@@ -821,16 +821,22 b' class chunkbuffer(object):' | |||||
821 | s, self.buf = self.buf[:l], buffer(self.buf, l) |
|
821 | s, self.buf = self.buf[:l], buffer(self.buf, l) | |
822 | return s |
|
822 | return s | |
823 |
|
823 | |||
824 |
def filechunkiter(f, size = |
|
824 | def filechunkiter(f, size=65536, limit=None): | |
825 |
"""Create a generator that produces |
|
825 | """Create a generator that produces the data in the file size | |
826 |
(default 65536) bytes at a time |
|
826 | (default 65536) bytes at a time, up to optional limit (default is | |
827 | bytes if the chunk is the last chunk in the file, or the file is a |
|
827 | to read all data). Chunks may be less than size bytes if the | |
828 | socket or some other type of file that sometimes reads less data |
|
828 | chunk is the last chunk in the file, or the file is a socket or | |
829 | than is requested.""" |
|
829 | some other type of file that sometimes reads less data than is | |
830 | s = f.read(size) |
|
830 | requested.""" | |
831 | while len(s) > 0: |
|
831 | assert size >= 0 | |
|
832 | assert limit is None or limit >= 0 | |||
|
833 | while True: | |||
|
834 | if limit is None: nbytes = size | |||
|
835 | else: nbytes = min(limit, size) | |||
|
836 | s = nbytes and f.read(nbytes) | |||
|
837 | if not s: break | |||
|
838 | if limit: limit -= len(s) | |||
832 | yield s |
|
839 | yield s | |
833 | s = f.read(size) |
|
|||
834 |
|
840 | |||
835 | def makedate(): |
|
841 | def makedate(): | |
836 | lt = time.localtime() |
|
842 | lt = time.localtime() |
General Comments 0
You need to be logged in to leave comments.
Login now