diff --git a/docs b/docs index ea486d60..0efb6ee6 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit ea486d6022307c2e0bd152c5dd45b03fe4343c31 +Subproject commit 0efb6ee60ca89916b410d53dd36cef3a2f522ab0 diff --git a/platformio/commands/lib.py b/platformio/commands/lib.py index e18ba3e7..5a49369b 100644 --- a/platformio/commands/lib.py +++ b/platformio/commands/lib.py @@ -128,7 +128,7 @@ def lib_update(lm, libraries, only_check, json_output): requirements = None url = None 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) if not pkg_dir: continue @@ -314,7 +314,7 @@ def lib_builtin(storage, json_output): @click.option("--json-output", is_flag=True) def lib_show(library, json_output): lm = LibraryManager() - name, requirements, _ = lm.parse_pkg_input(library) + name, requirements, _ = lm.parse_pkg_uri(library) lib_id = lm.get_pkg_id_by_name( name, requirements, silent=json_output, interactive=not json_output) lib = get_api_result("/lib/info/%d" % lib_id, cache_valid="1d") diff --git a/platformio/commands/platform.py b/platformio/commands/platform.py index f67cccfc..61584691 100644 --- a/platformio/commands/platform.py +++ b/platformio/commands/platform.py @@ -351,7 +351,7 @@ def platform_update(platforms, only_packages, only_check, json_output): requirements = None url = None 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) if not pkg_dir: continue diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index ad3197a4..d13671ef 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -242,8 +242,7 @@ class LibraryManager(BasePkgManager): interactive=False): pkg_dir = None try: - _name, _requirements, _url = self.parse_pkg_input( - name, requirements) + _name, _requirements, _url = self.parse_pkg_uri(name, requirements) if not _url: name = "id=%d" % self.get_pkg_id_by_name( _name, diff --git a/platformio/managers/package.py b/platformio/managers/package.py index 6ee4b820..a7670109 100644 --- a/platformio/managers/package.py +++ b/platformio/managers/package.py @@ -490,51 +490,59 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): click.echo("%s: %s" % (self.__class__.__name__, message), nl=nl) @staticmethod - def parse_pkg_input( # pylint: disable=too-many-branches + def parse_pkg_uri( # pylint: disable=too-many-branches text, requirements=None): text = str(text) - # git@github.com:user/package.git - url_marker = text[:4] - if url_marker not in ("git@", "git+") or ":" not in text: - url_marker = "://" + name, url = None, None + # Parse requirements req_conditions = [ - "@" in text, - not requirements, - not url_marker.startswith("git") - ] # yapf: disable + "@" in text, not requirements, "://" not in text + or text.rfind("/") < text.rfind("@") + ] if all(req_conditions): text, requirements = text.rsplit("@", 1) + + # Handle PIO Library Registry ID if text.isdigit(): text = "id=" + text + # Parse custom name + elif "=" in text and not text.startswith("id="): + name, text = text.split("=", 1) - name, url = (None, text) - if "=" in text and not text.startswith("id="): - name, url = text.split("=", 1) + # Parse URL + # if valid URL with scheme vcs+protocol:// + 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 GitHub URL (https://github.com/user/package) - url.startswith("https://github.com/") and not url.endswith( - (".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 short version of GitHub URL + if text.count("/") == 1: + url = "git+https://github.com/" + text - # Handle Developer Mbed URL - # (https://developer.mbed.org/users/user/code/package/) - 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: + # Parse name from URL + if url and not name: _url = url.split("#", 1)[0] if "#" in url else url if _url.endswith(("\\", "/")): _url = _url[:-1] @@ -542,8 +550,6 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): if "." in name and not name.startswith("."): name = name.rsplit(".", 1)[0] - if url_marker not in url: - url = None return (name or text, requirements, url) def outdated(self, pkg_dir, requirements=None): @@ -607,7 +613,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): return 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) if not package_dir or not silent: @@ -653,8 +659,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): if isdir(package): pkg_dir = package else: - name, requirements, url = self.parse_pkg_input( - package, requirements) + name, requirements, url = self.parse_pkg_uri(package, requirements) pkg_dir = self.get_package_dir(name, requirements, url) if not pkg_dir: @@ -694,7 +699,7 @@ class BasePkgManager(PkgRepoMixin, PkgInstallerMixin): if isdir(package): pkg_dir = package 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: raise exception.UnknownPackage("%s @ %s" % (package, diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 9c26a1d7..dfd601fd 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -84,8 +84,7 @@ class PlatformManager(BasePkgManager): if isdir(package): pkg_dir = package else: - name, requirements, url = self.parse_pkg_input( - package, requirements) + name, requirements, url = self.parse_pkg_uri(package, requirements) pkg_dir = self.get_package_dir(name, requirements, url) p = PlatformFactory.newPlatform(pkg_dir) @@ -108,8 +107,7 @@ class PlatformManager(BasePkgManager): if isdir(package): pkg_dir = package else: - name, requirements, url = self.parse_pkg_input( - package, requirements) + name, requirements, url = self.parse_pkg_uri(package, requirements) pkg_dir = self.get_package_dir(name, requirements, url) p = PlatformFactory.newPlatform(pkg_dir) @@ -219,7 +217,7 @@ class PlatformFactory(object): platform_dir = dirname(name) name = util.load_json(name)['name'] 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) if platform_dir: name = pm.load_manifest(platform_dir)['name'] @@ -263,16 +261,10 @@ class PlatformPackagesMixin(object): continue elif (name in with_packages or not (skip_default_package or opts.get("optional", False))): - if self.is_valid_requirements(version): - self.pm.install(name, version, silent=silent) - elif version.startswith("git@"): - self.pm.install(version, silent=silent) + if "://" in version: + self.pm.install("%s=%s" % (name, version), silent=silent) else: - requirements = None - if "@" in version: - version, requirements = version.rsplit("@", 1) - self.pm.install( - "%s=%s" % (name, version), requirements, silent=silent) + self.pm.install(name, version, silent=silent) return True @@ -295,10 +287,10 @@ class PlatformPackagesMixin(object): def update_packages(self, only_check=False): for name, manifest in self.get_installed_packages().items(): - version = self.packages[name].get("version", "") - if "@" in version and not version.startswith("git@"): - _, version = version.rsplit("@", 1) - self.pm.update(manifest['__pkg_dir'], version, only_check) + requirements = self.packages[name].get("version", "") + if "://" in requirements: + _, requirements, __ = self.parse_pkg_uri(requirements) + self.pm.update(manifest['__pkg_dir'], requirements, only_check) def get_installed_packages(self): items = {} @@ -310,18 +302,19 @@ class PlatformPackagesMixin(object): def are_outdated_packages(self): for name, manifest in self.get_installed_packages().items(): - version = self.packages[name].get("version", "") - if "@" in version and not version.startswith("git@"): - _, version = version.rsplit("@", 1) - if self.pm.outdated(manifest['__pkg_dir'], version): + requirements = self.packages[name].get("version", "") + if "://" in requirements: + _, requirements, __ = self.parse_pkg_uri(requirements) + if self.pm.outdated(manifest['__pkg_dir'], requirements): return True return False def get_package_dir(self, name): version = self.packages[name].get("version", "") - if self.is_valid_requirements(version): - return self.pm.get_package_dir(name, version) - return self.pm.get_package_dir(*self._parse_pkg_input(name, version)) + if "://" in version: + return self.pm.get_package_dir(*self.pm.parse_pkg_uri( + "%s=%s" % (name, version))) + return self.pm.get_package_dir(name, version) def get_package_version(self, name): pkg_dir = self.get_package_dir(name) @@ -329,16 +322,6 @@ class PlatformPackagesMixin(object): return None 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): diff --git a/tests/test_managers.py b/tests/test_managers.py index a26742bc..b680b771 100644 --- a/tests/test_managers.py +++ b/tests/test_managers.py @@ -115,14 +115,14 @@ def test_pkg_input_parser(): "hg+https://example.com/user/package", ("package", None, "hg+https://example.com/user/package") ], - [ - "git@github.com:user/package.git", - ("package", None, "git@github.com:user/package.git") - ], - [ - "git@github.com:user/package.git#v1.2.0", - ("package", None, "git@github.com:user/package.git#v1.2.0") - ], + # [ + # "git@github.com:user/package.git", + # ("package", None, "git@github.com:user/package.git") + # ], + # [ + # "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", ("package", None, @@ -132,13 +132,19 @@ def test_pkg_input_parser(): "git+ssh://user@gitlab.private-server.com:1234/package#1.2.0", ("package", None, "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: if isinstance(params, tuple): - assert PackageManager.parse_pkg_input(*params) == result + assert PackageManager.parse_pkg_uri(*params) == result else: - assert PackageManager.parse_pkg_input(params) == result + assert PackageManager.parse_pkg_uri(params) == result def test_install_packages(isolated_pio_home, tmpdir):