From 027c3d0e5e89cff4b5f8038db4156f2eb232f712 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Fri, 13 Jun 2014 20:47:02 +0300 Subject: [PATCH] Implemented new commands: list, show, uninstall & update; minor improvements to code --- platformio/commands/install.py | 2 +- platformio/commands/list.py | 16 ++++++ platformio/commands/show.py | 29 +++++++++++ platformio/commands/uninstall.py | 21 ++++++++ platformio/commands/update.py | 17 +++++++ platformio/exception.py | 11 ++-- platformio/pkgmanager.py | 87 +++++++++++++++++++++++++++----- platformio/platforms/_base.py | 41 +++++++++------ platformio/projectconftpl.ini | 6 +-- 9 files changed, 192 insertions(+), 38 deletions(-) create mode 100644 platformio/commands/list.py create mode 100644 platformio/commands/show.py create mode 100644 platformio/commands/uninstall.py create mode 100644 platformio/commands/update.py diff --git a/platformio/commands/install.py b/platformio/commands/install.py index 5db7f031..e4501314 100644 --- a/platformio/commands/install.py +++ b/platformio/commands/install.py @@ -6,7 +6,7 @@ from click import argument, command, option, secho from platformio.platforms._base import PlatformFactory -@command("run", short_help="Install new platforms") +@command("install", short_help="Install new platforms") @argument("platform") @option('--with-package', multiple=True, metavar="") @option('--without-package', multiple=True, metavar="") diff --git a/platformio/commands/list.py b/platformio/commands/list.py new file mode 100644 index 00000000..699d2fb0 --- /dev/null +++ b/platformio/commands/list.py @@ -0,0 +1,16 @@ +# Copyright (C) Ivan Kravets +# See LICENSE for details. + +from click import command, echo, style + +from platformio.pkgmanager import PackageManager + + +@command("list", short_help="List installed platforms") +def cli(): + + for name, pkgs in PackageManager.get_installed().iteritems(): + echo("{name:<20} with packages: {pkgs}".format( + name=style(name, fg="cyan"), + pkgs=", ".join(pkgs.keys()) + )) diff --git a/platformio/commands/show.py b/platformio/commands/show.py new file mode 100644 index 00000000..9ae904c9 --- /dev/null +++ b/platformio/commands/show.py @@ -0,0 +1,29 @@ +# Copyright (C) Ivan Kravets +# See LICENSE for details. + +from os.path import join + +from click import argument, command, echo, style + +from platformio.exception import PlatformNotInstalledYet +from platformio.pkgmanager import PackageManager +from platformio.platforms._base import PlatformFactory + + +@command("show", short_help="Show details about an installed platforms") +@argument("platform") +def cli(platform): + p = PlatformFactory().newPlatform(platform) + if platform not in PackageManager.get_installed(): + raise PlatformNotInstalledYet(platform) + + # print info about platform + echo("{name:<20} - {info}".format(name=style(p.get_name(), fg="cyan"), + info=p.get_short_info())) + + pm = PackageManager(platform) + for name, data in pm.get_installed(platform).iteritems(): + echo("----------") + echo("Package: %s" % style(name, fg="yellow")) + echo("Location: %s" % join(pm.get_platform_dir(), data['path'])) + echo("Version: %d" % int(data['version'])) diff --git a/platformio/commands/uninstall.py b/platformio/commands/uninstall.py new file mode 100644 index 00000000..13f09e69 --- /dev/null +++ b/platformio/commands/uninstall.py @@ -0,0 +1,21 @@ +# Copyright (C) Ivan Kravets +# See LICENSE for details. + +from click import argument, command, secho + +from platformio.exception import PlatformNotInstalledYet +from platformio.pkgmanager import PackageManager +from platformio.platforms._base import PlatformFactory + + +@command("uninstall", short_help="Uninstall the platforms") +@argument("platform") +def cli(platform): + + if platform not in PackageManager.get_installed(): + raise PlatformNotInstalledYet(platform) + + p = PlatformFactory().newPlatform(platform) + if p.uninstall(): + secho("The platform '%s' has been successfully " + "uninstalled!" % platform, fg="green") diff --git a/platformio/commands/update.py b/platformio/commands/update.py new file mode 100644 index 00000000..6bd2432d --- /dev/null +++ b/platformio/commands/update.py @@ -0,0 +1,17 @@ +# Copyright (C) Ivan Kravets +# See LICENSE for details. + +from click import command, echo, style + +from platformio.pkgmanager import PackageManager +from platformio.platforms._base import PlatformFactory + + +@command("update", short_help="Update installed platforms") +def cli(): + + for platform in PackageManager.get_installed().keys(): + echo("\nPlatform %s" % style(platform, fg="cyan")) + echo("--------") + p = PlatformFactory().newPlatform(platform) + p.update() diff --git a/platformio/exception.py b/platformio/exception.py index 1be8a52e..7709870d 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -18,6 +18,12 @@ class UnknownPlatform(PlatformioException): MESSAGE = "Unknown platform '%s'" +class PlatformNotInstalledYet(PlatformioException): + + MESSAGE = ("The platform '%s' has not been installed yet. " + "Use `platformio install` command") + + class UnknownCLICommand(PlatformioException): MESSAGE = "Unknown command '%s'" @@ -33,11 +39,6 @@ class InvalidPackageVersion(PlatformioException): MESSAGE = "The package '%s' with version '%d' does not exist" -class PackageInstalled(PlatformioException): - - MESSAGE = "The package '%s' is installed already" - - class NonSystemPackage(PlatformioException): MESSAGE = "The package '%s' is not available for your system '%s'" diff --git a/platformio/pkgmanager.py b/platformio/pkgmanager.py index c281faf9..6822acbc 100644 --- a/platformio/pkgmanager.py +++ b/platformio/pkgmanager.py @@ -4,27 +4,33 @@ import json from os import makedirs, remove from os.path import isdir, isfile, join +from shutil import rmtree +from click import echo, secho, style from requests import get from platformio import __pkgmanifesturl__ from platformio.downloader import FileDownloader from platformio.exception import (InvalidPackageVersion, NonSystemPackage, - PackageInstalled, UnknownPackage) + UnknownPackage) from platformio.unpacker import FileUnpacker from platformio.util import get_home_dir, get_system class PackageManager(object): + DBFILE_PATH = join(get_home_dir(), "installed.json") + def __init__(self, platform_name): self._platform_name = platform_name - self._platforms_dir = get_home_dir() - self._dbfile = join(self._platforms_dir, "installed.json") @staticmethod def get_manifest(): - return get(__pkgmanifesturl__).json() + try: + return PackageManager._cached_manifest + except AttributeError: + PackageManager._cached_manifest = get(__pkgmanifesturl__).json() + return PackageManager._cached_manifest @staticmethod def download(url, dest_dir, sha1=None): @@ -38,12 +44,16 @@ class PackageManager(object): fu = FileUnpacker(pkgpath, dest_dir) return fu.start() - def get_installed(self): + @staticmethod + def get_installed(platform=None): data = {} - if isfile(self._dbfile): - with open(self._dbfile) as fp: + if isfile(PackageManager.DBFILE_PATH): + with open(PackageManager.DBFILE_PATH) as fp: data = json.load(fp) - return data + return data.get(platform, None) if platform else data + + def get_platform_dir(self): + return join(get_home_dir(), self._platform_name) def is_installed(self, name): installed = self.get_installed() @@ -51,9 +61,6 @@ class PackageManager(object): installed[self._platform_name]) def get_info(self, name, version=None): - if self.is_installed(name): - raise PackageInstalled(name) - manifest = self.get_manifest() if name not in manifest: raise UnknownPackage(name) @@ -74,8 +81,14 @@ class PackageManager(object): return sorted(builds, key=lambda s: s['version'])[-1] def install(self, name, path): + echo("Installing %s package:" % style(name, fg="cyan")) + + if self.is_installed(name): + secho("Already installed", fg="yellow") + return + info = self.get_info(name) - pkg_dir = join(self._platforms_dir, self._platform_name, path) + pkg_dir = join(self.get_platform_dir(), path) if not isdir(pkg_dir): makedirs(pkg_dir) @@ -85,13 +98,59 @@ class PackageManager(object): # remove archive remove(dlpath) + def uninstall(self, name, path): + echo("Uninstalling %s package: \t" % style(name, fg="cyan"), + nl=False) + rmtree(join(self.get_platform_dir(), path)) + self._unregister(name) + echo("[%s]" % style("OK", fg="green")) + + def update(self, name): + echo("Updating %s package:" % style(name, fg="yellow")) + + installed = self.get_installed(self._platform_name) + current_version = installed[name]['version'] + latest_version = self.get_info(name)['version'] + + echo("Versions: Current=%d, Latest=%d \t " % ( + current_version, latest_version), nl=False) + + if current_version == latest_version: + echo("[%s]" % (style("Up-to-date", fg="green"))) + return True + else: + echo("[%s]" % (style("Out-of-date", fg="red"))) + + self.uninstall(name, installed[name]['path']) + self.install(name, installed[name]['path']) + + def register_platform(self, name): + data = self.get_installed() + if name not in data: + data[name] = {} + self._update_db(data) + return data + + def unregister_platform(self, name): + data = self.get_installed() + del data[name] + self._update_db(data) + def _register(self, name, version, path): data = self.get_installed() if self._platform_name not in data: - data[self._platform_name] = {} + data = self.register_platform(self._platform_name) data[self._platform_name][name] = { "version": version, "path": path } - with open(self._dbfile, "w") as fp: + self._update_db(data) + + def _unregister(self, name): + data = self.get_installed() + del data[self._platform_name][name] + self._update_db(data) + + def _update_db(self, data): + with open(self.DBFILE_PATH, "w") as fp: json.dump(data, fp) diff --git a/platformio/platforms/_base.py b/platformio/platforms/_base.py index 26787edf..fc92a733 100644 --- a/platformio/platforms/_base.py +++ b/platformio/platforms/_base.py @@ -2,13 +2,11 @@ # See LICENSE for details. from os.path import join +from shutil import rmtree -from click import echo, secho, style - -from platformio.exception import (PackageInstalled, UnknownPackage, - UnknownPlatform) +from platformio.exception import UnknownPackage, UnknownPlatform from platformio.pkgmanager import PackageManager -from platformio.util import exec_command, get_source_dir +from platformio.util import exec_command, get_platforms, get_source_dir class PlatformFactory(object): @@ -17,9 +15,10 @@ class PlatformFactory(object): def newPlatform(name): clsname = "%sPlatform" % name.title() try: + assert name in get_platforms() mod = __import__("platformio.platforms." + name.lower(), None, None, [clsname]) - except ImportError: + except (AssertionError, ImportError): raise UnknownPlatform(name) obj = getattr(mod, clsname)() @@ -56,17 +55,26 @@ class BasePlatform(object): elif name in with_packages or opts["default"]: requirements.append((name, opts["path"])) - for (name, path) in requirements: - echo("Installing %s package:" % style(name, fg="cyan")) - try: - pm.install(name, path) - except PackageInstalled: - secho("Already installed", fg="yellow") - + for (package, path) in requirements: + pm.install(package, path) return True - def after_run(self, result): # pylint: disable=R0201 - return result + def uninstall(self): + platform = self.get_name() + pm = PackageManager(platform) + + for package, data in pm.get_installed(platform).iteritems(): + pm.uninstall(package, data['path']) + + pm.unregister_platform(platform) + rmtree(pm.get_platform_dir()) + return True + + def update(self): + platform = self.get_name() + pm = PackageManager(platform) + for package in pm.get_installed(platform).keys(): + pm.update(package) def run(self, variables, targets): assert isinstance(variables, list) @@ -83,3 +91,6 @@ class BasePlatform(object): ] + variables + targets) return self.after_run(result) + + def after_run(self, result): # pylint: disable=R0201 + return result diff --git a/platformio/projectconftpl.ini b/platformio/projectconftpl.ini index c4ffe2d4..2d436497 100644 --- a/platformio/projectconftpl.ini +++ b/platformio/projectconftpl.ini @@ -1,10 +1,10 @@ # Copyright (C) Ivan Kravets # See LICENSE for details. -# Please uncomment (remove "#" sign from the beginning of the line) any -# environments which are fit to your project +# Please uncomment (remove "#" sign from the beginning of the line) +# some of the environments which fit to your project. # -# And replace all values that match with "%..._HERE%" by real data +# And replace all values that match with "%..._HERE%" by real data. # Simple and base environment