FTP protocol support - initial read support
Rafael Villar Burke
pachi at rvburke.com
Tue Feb 6 02:07:44 UTC 2007
I've tried to understand how FTP protocol support could be added to
Mercurial and, so far, I've taken the static-http support and tried to
tweak it to support read-only operation for FTP.
It looks like that, for adding a new protocol, the following is needed:
- a new key in the schemes dictionary in hg.py so the new protocol is
recognized, and a new repo class is provided as value for that key.
- the repo class must implement certain API, depending on its
capabilities. The existing statichttprepo.py and sshrepo.py classes look
like the most basic and most complete implementations in the current
code. A new ftprepo.py has been provided, that's based on statichttprepo.py.
- the repo class uses an opener to manage range reads using the provided
byterange module. This last already has a FTPRangeHandler, and is used
in the new ftprangereader.py module in a similar way to the
HTTPRangeHandler used for the static-http protocol used in
httprangereader.py.
I haven't been able to test this (working on win32 ATM), but I would
like to know if it works for anyone, and wouldn't mind others trying to
develop it further ;).
The attached diff has my changes so far.
Regards,
Rafael Villar Burke
www.rvburke.com
diff -r 82eb0fafb56d mercurial/ftprangereader.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/ftprangereader.py Tue Feb 06 02:32:54 2007 +0100
@@ -0,0 +1,29 @@
+# ftprangereader.py - just what it says
+#
+# Copyright 2005, 2006 Matt Mackall <mpm at selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+import byterange, urllib2
+from ftplib import FTP
+
+class ftprangereader(object):
+ def __init__(self, url):
+ self.url = url
+ self.pos = 0
+ def seek(self, pos):
+ self.pos = pos
+ def read(self, bytes=None):
+ opener = urllib2.build_opener(byterange.FTPRangeHandler())
+ urllib2.install_opener(opener)
+ req = urllib2.Request(self.url)
+ end = ''
+ if bytes:
+ end = self.pos + bytes - 1
+ req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
+ f = urllib2.urlopen(req)
+ data = f.read()
+ if bytes:
+ data = data[:bytes]
+ return data
diff -r 82eb0fafb56d mercurial/ftprepo.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/ftprepo.py Tue Feb 06 02:34:30 2007 +0100
@@ -0,0 +1,78 @@
+# statichttprepo.py - simple http repository class for mercurial
+#
+# This provides read-only repo access to repositories exported via
static http
+#
+# Copyright 2005, 2006 Matt Mackall <mpm at selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from i18n import _
+import changelog, filelog, httprangereader
+import repo, localrepo, manifest, os, urllib, urllib2, util
+
+class rangereader(httprangereader.httprangereader):
+ def read(self, size=None):
+ try:
+ return httprangereader.httprangereader.read(self, size)
+ except urllib2.URLError, inst:
+ raise IOError(None, inst.reason[1])
+
+def opener(base):
+ """return a function that opens files over http"""
+ p = base
+ def o(path, mode="r"):
+ f = "/".join((p, urllib.quote(path)))
+ return rangereader(f)
+ return o
+
+class ftprepository(localrepo.localrepository):
+ def __init__(self, ui, path):
+ self._url = path
+ self.ui = ui
+ self.revlogversion = 0
+
+ self.path = (path + "/.hg")
+ self.opener = opener(self.path)
+ # find requirements
+ try:
+ requirements = self.opener("requires").read().splitlines()
+ except IOError:
+ requirements = []
+ # check them
+ for r in requirements:
+ if r not in self.supported:
+ raise repo.RepoError(_("requirement '%s' not
supported") % r)
+
+ # setup store
+ if "store" in requirements:
+ self.encodefn = util.encodefilename
+ self.decodefn = util.decodefilename
+ self.spath = self.path + "/store"
+ else:
+ self.encodefn = lambda x: x
+ self.decodefn = lambda x: x
+ self.spath = self.path
+ self.sopener = util.encodedopener(opener(self.spath),
self.encodefn)
+
+ self.manifest = manifest.manifest(self.sopener)
+ self.changelog = changelog.changelog(self.sopener)
+ self.tagscache = None
+ self.nodetagscache = None
+ self.encodepats = None
+ self.decodepats = None
+
+ def url(self):
+ return self._url
+
+ def dev(self):
+ return -1
+
+ def local(self):
+ return False
+
+def instance(ui, path, create):
+ if create:
+ #TODO: should create repo here
+ raise util.Abort(_('cannot create new ftp repository'))
+ return ftprepository(ui, path)
diff -r 82eb0fafb56d mercurial/hg.py
--- a/mercurial/hg.py Tue Jan 30 21:11:10 2007 -0200
+++ b/mercurial/hg.py Tue Feb 06 02:35:04 2007 +0100
@@ -9,7 +9,7 @@ from node import *
from node import *
from repo import *
from i18n import _
-import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
+import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo, ftprepo
import errno, lock, os, shutil, util
import merge as _merge
import verify as _verify
@@ -27,6 +27,7 @@ schemes = {
'old-http': statichttprepo,
'ssh': sshrepo,
'static-http': statichttprepo,
+ 'ftp': ftprepo,
}
def _lookup(path):
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: ftp-read.diff
URL: <http://lists.mercurial-scm.org/pipermail/mercurial-devel/attachments/20070206/ab6560b0/attachment.diff>
More information about the Mercurial-devel
mailing list