diff --git a/platformio/clients/registry.py b/platformio/clients/registry.py index 03e5b178..6e9ea3fa 100644 --- a/platformio/clients/registry.py +++ b/platformio/clients/registry.py @@ -41,3 +41,22 @@ class RegistryClient(RESTClient): data=fp, ) return response + + def unpublish_package(self, name, owner=None, version=None, undo=False): + account = AccountClient() + if not owner: + owner = ( + account.get_account_info(offline=True).get("profile").get("username") + ) + path = "/v3/package/%s/%s" % (owner, name) + if version: + path = path + "/version/" + version + response = self.send_request( + "delete", + path, + params={"undo": 1 if undo else 0}, + headers={ + "Authorization": "Bearer %s" % account.fetch_authentication_token() + }, + ) + return response diff --git a/platformio/commands/package.py b/platformio/commands/package.py index 261523e2..bf42b350 100644 --- a/platformio/commands/package.py +++ b/platformio/commands/package.py @@ -19,6 +19,7 @@ import click from platformio.clients.registry import RegistryClient from platformio.package.pack import PackagePacker +from platformio.package.spec import PackageSpec def validate_datetime(ctx, param, value): # pylint: disable=unused-argument @@ -38,17 +39,15 @@ def cli(): @click.argument("package", required=True, metavar="[source directory, tar.gz or zip]") def package_pack(package): p = PackagePacker(package) - tarball_path = p.pack() - click.secho('Wrote a tarball to "%s"' % tarball_path, fg="green") + archive_path = p.pack() + click.secho('Wrote a tarball to "%s"' % archive_path, fg="green") -@cli.command( - "publish", short_help="Publish a package to the PlatformIO Universal Registry" -) +@cli.command("publish", short_help="Publish a package to the registry") @click.argument("package", required=True, metavar="[source directory, tar.gz or zip]") @click.option( "--owner", - help="PIO Account username (could be organization username). " + help="PIO Account username (can be organization username). " "Default is set to a username of the authorized PIO Account", ) @click.option( @@ -65,3 +64,18 @@ def package_publish(package, owner, released_at, private): ) os.remove(archive_path) click.secho(response.get("message"), fg="green") + + +@cli.command("unpublish", short_help="Remove a pushed package from the registry") +@click.argument("package", required=True, metavar="[<@organization>/][@]") +@click.option( + "--undo", + is_flag=True, + help="Undo a remove, putting a version back into the registry", +) +def package_unpublish(package, undo): + spec = PackageSpec(package) + response = RegistryClient().unpublish_package( + owner=spec.organization, name=spec.name, version=spec.version, undo=undo + ) + click.secho(response.get("message"), fg="green") diff --git a/platformio/package/spec.py b/platformio/package/spec.py new file mode 100644 index 00000000..0de8227a --- /dev/null +++ b/platformio/package/spec.py @@ -0,0 +1,42 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class PackageSpec(object): + def __init__(self, raw=None, organization=None, name=None, version=None): + if raw is not None: + organization, name, version = self.parse(raw) + + self.organization = organization + self.name = name + self.version = version + + @staticmethod + def parse(raw): + organization = None + name = None + version = None + raw = raw.strip() + if raw.startswith("@") and "/" in raw: + tokens = raw[1:].split("/", 1) + organization = tokens[0].strip() + raw = tokens[1] + if "@" in raw: + name, version = raw.split("@", 1) + name = name.strip() + version = version.strip() + else: + name = raw.strip() + + return organization, name, version diff --git a/tests/package/test_spec.py b/tests/package/test_spec.py new file mode 100644 index 00000000..1886a836 --- /dev/null +++ b/tests/package/test_spec.py @@ -0,0 +1,27 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from platformio.package.spec import PackageSpec + + +def test_parser(): + inputs = [ + ("foo", (None, "foo", None)), + ("@org/foo", ("org", "foo", None)), + ("@org/foo @ 1.2.3", ("org", "foo", "1.2.3")), + ("bar @ 1.2.3", (None, "bar", "1.2.3")), + ("cat@^1.2", (None, "cat", "^1.2")), + ] + for raw, result in inputs: + assert PackageSpec.parse(raw) == result