Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Browse files

Added support for file:// urls

  • Loading branch information...
commit 17dd09cb69989210bc9d160a13df370587600e22 1 parent 4dc33cf
@dvarrazzo authored
13 docs/usage.rst
@@ -62,12 +62,15 @@ status accepted. The default is "stable".
A few commands also allow specifying a local archive or local directory
containing a distribution: in this case the specification should contain at
-least a path separator to disambiguate it from a distribution name, for
-instance ``pgxn install ./``. Currently the client supports ``.zip``
-and ``.tar`` archives (eventually with *gzip* and *bz2* compression).
+least a path separator to disambiguate it from a distribution name (for
+instance ``pgxn install ./``) or it should be specified as an URL with
+``file://`` schema.
-A few commands also allow specifying a package with an URL. Currently the
-schemas ``http://`` and ``https://`` are supported.
+A few commands also allow specifying a remote package with a URL. Currently
+the schemas ``http://`` and ``https://`` are supported.
+Currently the client supports ``.zip`` and ``.tar`` archives (eventually with
+*gzip* and *bz2* compression).
.. _install:
25 pgxnclient/
@@ -9,6 +9,7 @@
import os
import re
+import urllib
import operator as _op
from pgxnclient.i18n import _
@@ -71,18 +72,28 @@ def parse(self, spec):
Raise BadSpecError if couldn't parse.
- # TODO: handle file:// too
+ # check if it's a network resource
if spec.startswith('http://') or spec.startswith('https://'):
return Spec(url=spec)
- if os.sep in spec:
+ # check if it's a local resource
+ if spec.startswith('file://'):
+ try_file = urllib.unquote_plus(spec[len('file://'):])
+ elif os.sep in spec:
+ try_file = spec
+ else:
+ try_file = None
+ if try_file:
# This is a local thing, let's see what
- if os.path.isdir(spec):
- return Spec(dirname=spec)
- elif os.path.exists(spec):
- return Spec(filename=spec)
+ if os.path.isdir(try_file):
+ return Spec(dirname=try_file)
+ elif os.path.exists(try_file):
+ return Spec(filename=try_file)
- raise ResourceNotFound(_("cannot find '%s'") % spec)
+ raise ResourceNotFound(_("cannot find '%s'") % try_file)
+ # so we think it's a PGXN spec
# split operator/version and name
m = re.match(r'(.+?)(?:(==|=|>=|>|<=|<)(.*))?$', spec)
12 pgxnclient/tests/
@@ -478,6 +478,18 @@ def test_install_local_zip(self, mock_unpack):
tmpdir, = mock_unpack.call_args[0]
self.assertEqual(make_cwd, os.path.join(tmpdir, 'foobar-0.42.1'))
+ def test_install_url_file(self):
+ fn = get_test_filename('')
+ url = 'file://' + os.path.abspath(fn).replace("f", '%%%2x' % ord('f'))
+ from pgxnclient.cli import main
+ main(['install', '--sudo', '--', url])
+ self.assertEquals(self.mock_popen.call_count, 2)
+ self.assertCallArgs([self.make], self.mock_popen.call_args_list[0][0][0][:1])
+ self.assertCallArgs(['sudo', self.make],
+ self.mock_popen.call_args_list[1][0][0][:2])
def test_install_local_dir(self):
self.mock_get.side_effect = lambda *args:'network invoked')

0 comments on commit 17dd09c

Please sign in to comment.
Something went wrong with that request. Please try again.