Improve support for VCS packages

This commit is contained in:
Ivan Kravets
2017-11-25 00:31:16 +02:00
parent d07833e010
commit 53b37216cc
7 changed files with 84 additions and 91 deletions

2
docs

Submodule docs updated: ea486d6022...0efb6ee60c

View File

@ -128,7 +128,7 @@ def lib_update(lm, libraries, only_check, json_output):
requirements = None requirements = None
url = None url = None
if not pkg_dir: if not pkg_dir:
name, requirements, url = lm.parse_pkg_input(library) name, requirements, url = lm.parse_pkg_uri(library)
pkg_dir = lm.get_package_dir(name, requirements, url) pkg_dir = lm.get_package_dir(name, requirements, url)
if not pkg_dir: if not pkg_dir:
continue continue
@ -314,7 +314,7 @@ def lib_builtin(storage, json_output):
@click.option("--json-output", is_flag=True) @click.option("--json-output", is_flag=True)
def lib_show(library, json_output): def lib_show(library, json_output):
lm = LibraryManager() lm = LibraryManager()
name, requirements, _ = lm.parse_pkg_input(library) name, requirements, _ = lm.parse_pkg_uri(library)
lib_id = lm.get_pkg_id_by_name( lib_id = lm.get_pkg_id_by_name(
name, requirements, silent=json_output, interactive=not json_output) name, requirements, silent=json_output, interactive=not json_output)
lib = get_api_result("/lib/info/%d" % lib_id, cache_valid="1d") lib = get_api_result("/lib/info/%d" % lib_id, cache_valid="1d")

View File

@ -351,7 +351,7 @@ def platform_update(platforms, only_packages, only_check, json_output):
requirements = None requirements = None
url = None url = None
if not pkg_dir: if not pkg_dir:
name, requirements, url = pm.parse_pkg_input(platform) name, requirements, url = pm.parse_pkg_uri(platform)
pkg_dir = pm.get_package_dir(name, requirements, url) pkg_dir = pm.get_package_dir(name, requirements, url)
if not pkg_dir: if not pkg_dir:
continue continue

View File

@ -242,8 +242,7 @@ class LibraryManager(BasePkgManager):
interactive=False): interactive=False):
pkg_dir = None pkg_dir = None
try: try:
_name, _requirements, _url = self.parse_pkg_input( _name, _requirements, _url = self.parse_pkg_uri(name, requirements)
name, requirements)
if not _url: if not _url:
name = "id=%d" % self.get_pkg_id_by_name( name = "id=%d" % self.get_pkg_id_by_name(
_name, _name,

View File

@ -490,51 +490,59 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
click.echo("%s: %s" % (self.__class__.__name__, message), nl=nl) click.echo("%s: %s" % (self.__class__.__name__, message), nl=nl)
@staticmethod @staticmethod
def parse_pkg_input( # pylint: disable=too-many-branches def parse_pkg_uri( # pylint: disable=too-many-branches
text, requirements=None): text, requirements=None):
text = str(text) text = str(text)
# git@github.com:user/package.git name, url = None, None
url_marker = text[:4]
if url_marker not in ("git@", "git+") or ":" not in text:
url_marker = "://"
# Parse requirements
req_conditions = [ req_conditions = [
"@" in text, "@" in text, not requirements, "://" not in text
not requirements, or text.rfind("/") < text.rfind("@")
not url_marker.startswith("git") ]
] # yapf: disable
if all(req_conditions): if all(req_conditions):
text, requirements = text.rsplit("@", 1) text, requirements = text.rsplit("@", 1)
# Handle PIO Library Registry ID
if text.isdigit(): if text.isdigit():
text = "id=" + text text = "id=" + text
# Parse custom name
elif "=" in text and not text.startswith("id="):
name, text = text.split("=", 1)
name, url = (None, text) # Parse URL
if "=" in text and not text.startswith("id="): # if valid URL with scheme vcs+protocol://
name, url = text.split("=", 1) if "+" in text and text.find("+") < text.find("://"):
url = text
elif "/" in text or "\\" in text:
git_conditions = [
# Handle GitHub URL (https://github.com/user/package)
text.startswith("https://github.com/") and not text.endswith(
(".zip", ".tar.gz")),
text.startswith("http")
and (text.split("#", 1)[0]
if "#" in text else text).endswith(".git")
]
hg_conditions = [
# Handle Developer Mbed URL
# (https://developer.mbed.org/users/user/code/package/)
text.startswith("https://developer.mbed.org")
]
if any(git_conditions):
url = "git+" + text
elif any(hg_conditions):
url = "hg+" + text
elif "://" not in text and (isfile(text) or isdir(text)):
url = "file://" + text
elif "://" in text:
url = text
git_conditions = [ # Handle short version of GitHub URL
# Handle GitHub URL (https://github.com/user/package) if text.count("/") == 1:
url.startswith("https://github.com/") and not url.endswith( url = "git+https://github.com/" + text
(".zip", ".tar.gz")),
url.startswith("http")
and (url.split("#", 1)[0] if "#" in url else url).endswith(".git")
]
if any(git_conditions):
url = "git+" + url
# Handle Developer Mbed URL # Parse name from URL
# (https://developer.mbed.org/users/user/code/package/) if url and not name:
if url.startswith("https://developer.mbed.org"):
url = "hg+" + url
if any([s in url for s in ("\\", "/")]) and url_marker not in url:
if isfile(url) or isdir(url):
url = "file://" + url
elif url.count("/") == 1 and "git" not in url_marker:
url = "git+https://github.com/" + url
# determine name
if url_marker in url and not name:
_url = url.split("#", 1)[0] if "#" in url else url _url = url.split("#", 1)[0] if "#" in url else url
if _url.endswith(("\\", "/")): if _url.endswith(("\\", "/")):
_url = _url[:-1] _url = _url[:-1]
@ -542,8 +550,6 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
if "." in name and not name.startswith("."): if "." in name and not name.startswith("."):
name = name.rsplit(".", 1)[0] name = name.rsplit(".", 1)[0]
if url_marker not in url:
url = None
return (name or text, requirements, url) return (name or text, requirements, url)
def outdated(self, pkg_dir, requirements=None): def outdated(self, pkg_dir, requirements=None):
@ -607,7 +613,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
return return
self.INSTALL_HISTORY.append(history_key) self.INSTALL_HISTORY.append(history_key)
name, requirements, url = self.parse_pkg_input(name, requirements) name, requirements, url = self.parse_pkg_uri(name, requirements)
package_dir = self.get_package_dir(name, requirements, url) package_dir = self.get_package_dir(name, requirements, url)
if not package_dir or not silent: if not package_dir or not silent:
@ -653,8 +659,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
if isdir(package): if isdir(package):
pkg_dir = package pkg_dir = package
else: else:
name, requirements, url = self.parse_pkg_input( name, requirements, url = self.parse_pkg_uri(package, requirements)
package, requirements)
pkg_dir = self.get_package_dir(name, requirements, url) pkg_dir = self.get_package_dir(name, requirements, url)
if not pkg_dir: if not pkg_dir:
@ -694,7 +699,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin):
if isdir(package): if isdir(package):
pkg_dir = package pkg_dir = package
else: else:
pkg_dir = self.get_package_dir(*self.parse_pkg_input(package)) pkg_dir = self.get_package_dir(*self.parse_pkg_uri(package))
if not pkg_dir: if not pkg_dir:
raise exception.UnknownPackage("%s @ %s" % (package, raise exception.UnknownPackage("%s @ %s" % (package,

View File

@ -84,8 +84,7 @@ class PlatformManager(BasePkgManager):
if isdir(package): if isdir(package):
pkg_dir = package pkg_dir = package
else: else:
name, requirements, url = self.parse_pkg_input( name, requirements, url = self.parse_pkg_uri(package, requirements)
package, requirements)
pkg_dir = self.get_package_dir(name, requirements, url) pkg_dir = self.get_package_dir(name, requirements, url)
p = PlatformFactory.newPlatform(pkg_dir) p = PlatformFactory.newPlatform(pkg_dir)
@ -108,8 +107,7 @@ class PlatformManager(BasePkgManager):
if isdir(package): if isdir(package):
pkg_dir = package pkg_dir = package
else: else:
name, requirements, url = self.parse_pkg_input( name, requirements, url = self.parse_pkg_uri(package, requirements)
package, requirements)
pkg_dir = self.get_package_dir(name, requirements, url) pkg_dir = self.get_package_dir(name, requirements, url)
p = PlatformFactory.newPlatform(pkg_dir) p = PlatformFactory.newPlatform(pkg_dir)
@ -219,7 +217,7 @@ class PlatformFactory(object):
platform_dir = dirname(name) platform_dir = dirname(name)
name = util.load_json(name)['name'] name = util.load_json(name)['name']
else: else:
name, requirements, url = pm.parse_pkg_input(name, requirements) name, requirements, url = pm.parse_pkg_uri(name, requirements)
platform_dir = pm.get_package_dir(name, requirements, url) platform_dir = pm.get_package_dir(name, requirements, url)
if platform_dir: if platform_dir:
name = pm.load_manifest(platform_dir)['name'] name = pm.load_manifest(platform_dir)['name']
@ -263,16 +261,10 @@ class PlatformPackagesMixin(object):
continue continue
elif (name in with_packages or elif (name in with_packages or
not (skip_default_package or opts.get("optional", False))): not (skip_default_package or opts.get("optional", False))):
if self.is_valid_requirements(version): if "://" in version:
self.pm.install(name, version, silent=silent) self.pm.install("%s=%s" % (name, version), silent=silent)
elif version.startswith("git@"):
self.pm.install(version, silent=silent)
else: else:
requirements = None self.pm.install(name, version, silent=silent)
if "@" in version:
version, requirements = version.rsplit("@", 1)
self.pm.install(
"%s=%s" % (name, version), requirements, silent=silent)
return True return True
@ -295,10 +287,10 @@ class PlatformPackagesMixin(object):
def update_packages(self, only_check=False): def update_packages(self, only_check=False):
for name, manifest in self.get_installed_packages().items(): for name, manifest in self.get_installed_packages().items():
version = self.packages[name].get("version", "") requirements = self.packages[name].get("version", "")
if "@" in version and not version.startswith("git@"): if "://" in requirements:
_, version = version.rsplit("@", 1) _, requirements, __ = self.parse_pkg_uri(requirements)
self.pm.update(manifest['__pkg_dir'], version, only_check) self.pm.update(manifest['__pkg_dir'], requirements, only_check)
def get_installed_packages(self): def get_installed_packages(self):
items = {} items = {}
@ -310,18 +302,19 @@ class PlatformPackagesMixin(object):
def are_outdated_packages(self): def are_outdated_packages(self):
for name, manifest in self.get_installed_packages().items(): for name, manifest in self.get_installed_packages().items():
version = self.packages[name].get("version", "") requirements = self.packages[name].get("version", "")
if "@" in version and not version.startswith("git@"): if "://" in requirements:
_, version = version.rsplit("@", 1) _, requirements, __ = self.parse_pkg_uri(requirements)
if self.pm.outdated(manifest['__pkg_dir'], version): if self.pm.outdated(manifest['__pkg_dir'], requirements):
return True return True
return False return False
def get_package_dir(self, name): def get_package_dir(self, name):
version = self.packages[name].get("version", "") version = self.packages[name].get("version", "")
if self.is_valid_requirements(version): if "://" in version:
return self.pm.get_package_dir(name, version) return self.pm.get_package_dir(*self.pm.parse_pkg_uri(
return self.pm.get_package_dir(*self._parse_pkg_input(name, version)) "%s=%s" % (name, version)))
return self.pm.get_package_dir(name, version)
def get_package_version(self, name): def get_package_version(self, name):
pkg_dir = self.get_package_dir(name) pkg_dir = self.get_package_dir(name)
@ -329,16 +322,6 @@ class PlatformPackagesMixin(object):
return None return None
return self.pm.load_manifest(pkg_dir).get("version") return self.pm.load_manifest(pkg_dir).get("version")
@staticmethod
def is_valid_requirements(requirements):
return requirements and ":" not in requirements
def _parse_pkg_input(self, name, version):
requirements = None
if "@" in version and not version.startswith("git@"):
version, requirements = version.rsplit("@", 1)
return self.pm.parse_pkg_input("%s=%s" % (name, version), requirements)
class PlatformRunMixin(object): class PlatformRunMixin(object):

View File

@ -115,14 +115,14 @@ def test_pkg_input_parser():
"hg+https://example.com/user/package", "hg+https://example.com/user/package",
("package", None, "hg+https://example.com/user/package") ("package", None, "hg+https://example.com/user/package")
], ],
[ # [
"git@github.com:user/package.git", # "git@github.com:user/package.git",
("package", None, "git@github.com:user/package.git") # ("package", None, "git@github.com:user/package.git")
], # ],
[ # [
"git@github.com:user/package.git#v1.2.0", # "git@github.com:user/package.git#v1.2.0",
("package", None, "git@github.com:user/package.git#v1.2.0") # ("package", None, "git@github.com:user/package.git#v1.2.0")
], # ],
[ [
"git+ssh://git@gitlab.private-server.com/user/package#1.2.0", "git+ssh://git@gitlab.private-server.com/user/package#1.2.0",
("package", None, ("package", None,
@ -132,13 +132,19 @@ def test_pkg_input_parser():
"git+ssh://user@gitlab.private-server.com:1234/package#1.2.0", "git+ssh://user@gitlab.private-server.com:1234/package#1.2.0",
("package", None, ("package", None,
"git+ssh://user@gitlab.private-server.com:1234/package#1.2.0") "git+ssh://user@gitlab.private-server.com:1234/package#1.2.0")
],
[
"LocalName=git+ssh://user@gitlab.private-server.com:1234"
"/package#1.2.0@!=13",
("LocalName", "!=13",
"git+ssh://user@gitlab.private-server.com:1234/package#1.2.0")
] ]
] ]
for params, result in items: for params, result in items:
if isinstance(params, tuple): if isinstance(params, tuple):
assert PackageManager.parse_pkg_input(*params) == result assert PackageManager.parse_pkg_uri(*params) == result
else: else:
assert PackageManager.parse_pkg_input(params) == result assert PackageManager.parse_pkg_uri(params) == result
def test_install_packages(isolated_pio_home, tmpdir): def test_install_packages(isolated_pio_home, tmpdir):