Patchwork [1,of,3,V3] schemas: add schemas to repositories

login
register
mail settings
Submitter Durham Goode
Date Aug. 14, 2013, 9:02 p.m.
Message ID <84ac4b920802805474d2.1376514123@dev350.prn1.facebook.com>
Download mbox | patch
Permalink /patch/2176/
State Changes Requested
Headers show

Comments

Durham Goode - Aug. 14, 2013, 9:02 p.m.
# HG changeset patch
# User Durham Goode <durham@fb.com>
# Date 1375827328 25200
#      Tue Aug 06 15:15:28 2013 -0700
# Node ID 84ac4b920802805474d203b5b5dc1cd4aa861256
# Parent  3e34e7b223d10bbe8814f82d7a1f53575fe09096
schemas: add schemas to repositories

This adds the concept of schemas to repositories. A schema is a key/value pair
indicating alternative means of accessing the remote repository. For example,
the largefiles extension might provide a schema such as:

largefiles = http://some.cdn.com/myrepo

When a user interacts with the repository, if the client knows how to handle
the largefiles schema, it will read the url and obtain largefiles from the
url. Thus letting you serve large files from a CDN.

The next patch will allow querying schemas via the wire protocol.
Martin Geisler - Aug. 15, 2013, 7:58 a.m.
Durham Goode <durham@fb.com> writes:

> # HG changeset patch
> # User Durham Goode <durham@fb.com>
> # Date 1375827328 25200
> #      Tue Aug 06 15:15:28 2013 -0700
> # Node ID 84ac4b920802805474d203b5b5dc1cd4aa861256
> # Parent  3e34e7b223d10bbe8814f82d7a1f53575fe09096
> schemas: add schemas to repositories
>
> This adds the concept of schemas to repositories. A schema is a
> key/value pair indicating alternative means of accessing the remote
> repository.

When reading this I wonder how this differs from the pushkey system?
That's also a key/value store and as we've discussed, it could be used
for "schemas" too. Noting the advantage of a new key/value store would
probably be a good idea.

> For example, the largefiles extension might provide a schema such as:
>
> largefiles = http://some.cdn.com/myrepo
>
> When a user interacts with the repository, if the client knows how to
> handle the largefiles schema, it will read the url and obtain
> largefiles from the url. Thus letting you serve large files from a
> CDN.
>
> The next patch will allow querying schemas via the wire protocol.
>
> diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
> --- a/mercurial/localrepo.py
> +++ b/mercurial/localrepo.py
> @@ -661,6 +661,47 @@
>              bt[bn] = self._branchtip(heads)
>          return bt
>  
> +    @repofilecache('schemas')
> +    def schemas(self):
> +        try:
> +            file = self.opener('schemas')
> +        except IOError, inst:
> +            if inst.errno != errno.ENOENT:
> +                raise
> +            return {}

This pattern is also in abstractvfs.tryread. Maybe that could be used
instead somehow?

> +        try:
> +            schemas = {}
> +            lines = file.readlines()
> +            for line in lines:
> +                if line.find('=') > 0:
> +                    k, v = line.split('=', 1)
> +                    schemas[k.strip()] = v[:-1].strip()
> +
> +            return schemas
> +        finally:
> +            file.close()
> +
> +    def registerschema(self, name, url):
> +        existingschemas = self.schemas
> +        existingschemas[name] = url
> +        try:
> +            file = self.opener('schemas', 'w')
> +        except IOError, inst:
> +            if inst.errno != errno.ENOENT:
> +                raise
> +            return

Isn't this pattern only used when reading (not writing) a possibly
missing file?

Here you end up not serializing the schemes if a directory on the path
to <repo>/.hg/schemes doesn't exist -- which seems unlikely :)

> +        try:
> +            serialized = ""
> +            for k, v in existingschemas.iteritems():
> +                if len(k) > 0 and len(v) > 0:

I think 'if k and v:' is the usual style here.

Patch

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -661,6 +661,47 @@ 
             bt[bn] = self._branchtip(heads)
         return bt
 
+    @repofilecache('schemas')
+    def schemas(self):
+        try:
+            file = self.opener('schemas')
+        except IOError, inst:
+            if inst.errno != errno.ENOENT:
+                raise
+            return {}
+
+        try:
+            schemas = {}
+            lines = file.readlines()
+            for line in lines:
+                if line.find('=') > 0:
+                    k, v = line.split('=', 1)
+                    schemas[k.strip()] = v[:-1].strip()
+
+            return schemas
+        finally:
+            file.close()
+
+    def registerschema(self, name, url):
+        existingschemas = self.schemas
+        existingschemas[name] = url
+        try:
+            file = self.opener('schemas', 'w')
+        except IOError, inst:
+            if inst.errno != errno.ENOENT:
+                raise
+            return
+
+        try:
+            serialized = ""
+            for k, v in existingschemas.iteritems():
+                if len(k) > 0 and len(v) > 0:
+                    serialized += "%s = %s\n" % (k, v)
+
+            file.write(serialized)
+        finally:
+            file.close()
+
     def lookup(self, key):
         return self[key].node()