Avoid trademark issues in library.json; switch to PlatformIO Library Registry ID logic

Resolve issue #17
This commit is contained in:
Ivan Kravets
2014-10-19 00:14:11 +03:00
parent 4f817a5b61
commit 2d6c0ef66d
11 changed files with 327 additions and 163 deletions
+136 -74
View File
@@ -3,11 +3,40 @@
import click
from platformio.exception import LibAlreadyInstalledError
from platformio.exception import (LibAlreadyInstalledError,
LibInstallDependencyError)
from platformio.libmanager import LibraryManager
from platformio.util import get_api_result, get_lib_dir
LIBLIST_TPL = ("[{id:^14}] {name:<25} {compatibility:<30} "
"\"{authornames}\": {description}")
def echo_liblist_header():
click.echo(LIBLIST_TPL.format(
id=click.style("ID", fg="green"),
name=click.style("Name", fg="cyan"),
compatibility=click.style("Compatibility", fg="yellow"),
authornames="Authors",
description="Description"
))
click.echo("-" * 85)
def echo_liblist_item(item):
click.echo(LIBLIST_TPL.format(
id=click.style(str(item['id']), fg="green"),
name=click.style(item['name'], fg="cyan"),
compatibility=click.style(
", ".join(item['frameworks'] + item['platforms']),
fg="yellow"
),
authornames=", ".join(item['authornames']),
description=item['description']
))
@click.group(short_help="Library Manager")
def cli():
pass
@@ -16,22 +45,24 @@ def cli():
@cli.command("search", short_help="Search for library")
@click.option("-a", "--author", multiple=True)
@click.option("-k", "--keyword", multiple=True)
@click.option("-f", "--framework", multiple=True)
@click.option("-p", "--platform", multiple=True)
@click.argument("query")
def lib_search(query, author, keyword):
for key, values in dict(author=author, keyword=keyword).iteritems():
def lib_search(query, **filters):
for key, values in filters.iteritems():
for value in values:
query += ' %s:"%s"' % (key, value)
result = get_api_result("/lib/search", dict(query=query))
click.secho("Found %d libraries:" % result['total'],
click.secho("Found %d libraries:\n" % result['total'],
fg="green" if result['total'] else "yellow")
if result['total']:
echo_liblist_header()
while True:
for item in result['items']:
click.echo("{name:<30} {description}".format(
name=click.style(item['name'], fg="cyan"),
description=item['description']
))
echo_liblist_item(item)
if int(result['page'])*int(result['perpage']) >= int(result['total']):
break
@@ -46,91 +77,115 @@ def lib_search(query, author, keyword):
@cli.command("install", short_help="Install library")
@click.argument("names", nargs=-1)
@click.argument("ids", type=click.INT, nargs=-1, metavar="[LIBRARY_ID]")
@click.option("-v", "--version")
def lib_install_cli(names, version):
lib_install(names, version)
def lib_install_cli(ids, version):
lib_install(ids, version)
def lib_install(names, version=None):
def lib_install(ids, version=None):
lm = LibraryManager(get_lib_dir())
for name in names:
click.echo("Installing %s library:" % click.style(name, fg="cyan"))
for id_ in ids:
click.echo(
"Installing library [ %s ]:" % click.style(str(id_), fg="green"))
try:
if lm.install(name, version):
click.secho(
"The library '%s' has been successfully installed!" %
name, fg="green")
info = lm.get_info(name)
if "dependencies" in info:
click.secho("Installing dependencies:", fg="yellow")
lib_install(info['dependencies'])
if not lm.install(id_, version):
continue
info = lm.get_info(id_)
click.secho(
"The library #%s '%s' has been successfully installed!"
% (str(id_), info['name']), fg="green")
if "dependencies" in info:
click.secho("Installing dependencies:", fg="yellow")
_dependencies = info['dependencies']
if not isinstance(_dependencies, list):
_dependencies = [_dependencies]
for item in _dependencies:
try:
lib_install_dependency(item)
except AssertionError:
raise LibInstallDependencyError(str(item))
except LibAlreadyInstalledError:
click.secho("Already installed", fg="yellow")
def lib_install_dependency(data):
assert isinstance(data, dict)
query = []
for key in data.keys():
if key in ("authors", "frameworks", "platforms", "keywords"):
values = data[key]
if not isinstance(values, list):
values = [v.strip() for v in values.split(",") if v]
for value in values:
query.append('%s:"%s"' % (key[:-1], value))
elif isinstance(data[key], basestring):
query.append('+"%s"' % data[key])
result = get_api_result("/lib/search", dict(query=" ".join(query)))
assert result['total'] == 1
lib_install([result['items'][0]['id']])
@cli.command("uninstall", short_help="Uninstall libraries")
@click.argument("names", nargs=-1)
def lib_uninstall_cli(names):
lib_uninstall(names)
@click.argument("ids", type=click.INT, nargs=-1)
def lib_uninstall_cli(ids):
lib_uninstall(ids)
def lib_uninstall_dependency(dependency):
def lib_uninstall(ids):
lm = LibraryManager(get_lib_dir())
for name in lm.get_installed():
info = lm.get_info(name)
if dependency in info.get("dependencies", []):
return
lib_uninstall([dependency])
def lib_uninstall(names):
lm = LibraryManager(get_lib_dir())
for name in names:
info = lm.get_info(name)
if lm.uninstall(name):
# find dependencies
if "dependencies" in info:
for d in info['dependencies']:
lib_uninstall_dependency(d)
click.secho("The library '%s' has been successfully "
"uninstalled!" % name, fg="green")
for id_ in ids:
info = lm.get_info(id_)
if lm.uninstall(id_):
click.secho("The library #%s '%s' has been successfully "
"uninstalled!" % (str(id_), info['name']), fg="green")
@cli.command("list", short_help="List installed libraries")
def lib_list():
lm = LibraryManager(get_lib_dir())
for name in lm.get_installed():
info = lm.get_info(name)
click.echo("{name:<30} {description}".format(
name=click.style(info['name'], fg="cyan"),
description=info['description']
))
items = lm.get_installed().values()
if not items:
return
echo_liblist_header()
for item in items:
item['authornames'] = [i['name'] for i in item['authors']]
echo_liblist_item(item)
@cli.command("show", short_help="Show details about installed libraries")
@click.argument("name")
def lib_show(name):
@click.argument("id", type=click.INT)
def lib_show(id):
lm = LibraryManager(get_lib_dir())
info = lm.get_info(name)
info = lm.get_info(id)
click.secho(info['name'], fg="cyan")
click.echo("-" * len(info['name']))
if "author" in info:
_authors = []
for author in info['authors']:
_data = []
for k in ("name", "email"):
if k in info['author'] and info['author'][k] is not None:
_value = info['author'][k]
if k == "email":
_value = "<%s>" % _value
_data.append(_value)
click.echo("Author: %s" % " ".join(_data))
for key in ("name", "email", "url", "maintainer"):
if not author[key]:
continue
if key == "email":
_data.append("<%s>" % author[key])
elif key == "maintainer":
_data.append("(maintainer)")
else:
_data.append(author[key])
_authors.append(" ".join(_data))
click.echo("Authors: %s" % ", ".join(_authors))
click.echo("Keywords: %s" % info['keywords'])
click.echo("Keywords: %s" % ", ".join(info['keywords']))
if "frameworks" in info:
click.echo("Frameworks: %s" % ", ".join(info['frameworks']))
if "platforms" in info:
click.echo("Platforms: %s" % ", ".join(info['platforms']))
click.echo("Version: %s" % info['version'])
click.echo()
click.echo(info['description'])
@@ -141,18 +196,25 @@ def lib_show(name):
def lib_update():
lm = LibraryManager(get_lib_dir())
lib_names = lm.get_installed()
if not lib_names:
lib_ids = [str(item['id']) for item in lm.get_installed().values()]
if not lib_ids:
return
versions = get_api_result("/lib/version/" + ",".join(lib_names))
for name in lib_names:
info = lm.get_info(name)
versions = get_api_result("/lib/version/" + str(",".join(lib_ids)))
for id_ in lib_ids:
info = lm.get_info(int(id_))
click.echo("Updating %s library:" % click.style(name, fg="yellow"))
click.echo("Updating [ %s ] %s library:" % (
click.style(id_, fg="yellow"),
click.style(info['name'], fg="cyan"))
)
current_version = info['version']
latest_version = versions[name]
latest_version = versions[id_]
if latest_version is None:
click.secho("Unknown library", fg="red")
continue
click.echo("Versions: Current=%s, Latest=%s \t " % (
current_version, latest_version), nl=False)
@@ -163,8 +225,8 @@ def lib_update():
else:
click.echo("[%s]" % (click.style("Out-of-date", fg="red")))
lib_uninstall([name])
lib_install([name])
lib_uninstall([int(id_)])
lib_install([int(id_)])
@cli.command("register", short_help="Register new library")
+6 -1
View File
@@ -118,4 +118,9 @@ class LibAlreadyInstalledError(PlatformioException):
class LibNotInstalledError(PlatformioException):
MESSAGE = "Library '%s' has not been installed yet"
MESSAGE = "Library #%d has not been installed yet"
class LibInstallDependencyError(PlatformioException):
MESSAGE = "Error has been occurred for library dependency '%s'"
+41 -31
View File
@@ -2,7 +2,8 @@
# See LICENSE for details.
import json
from os import listdir, makedirs, remove
import re
from os import listdir, makedirs, remove, rename
from os.path import isdir, isfile, join
from shutil import rmtree
from tempfile import gettempdir
@@ -15,7 +16,7 @@ from platformio.util import get_api_result
class LibraryManager(object):
CONFIG_NAME = "library.json"
CONFIG_NAME = ".library.json"
def __init__(self, lib_dir):
self.lib_dir = lib_dir
@@ -32,45 +33,54 @@ class LibraryManager(object):
return fu.start()
def get_installed(self):
items = []
items = {}
if not isdir(self.lib_dir):
return items
for item in listdir(self.lib_dir):
conf_path = join(self.lib_dir, item, self.CONFIG_NAME)
if isfile(conf_path):
items.append(item)
for dirname in listdir(self.lib_dir):
conf_path = join(self.lib_dir, dirname, self.CONFIG_NAME)
if not isfile(conf_path):
continue
with open(conf_path, "r") as f:
items[dirname] = json.load(f)
return items
def get_info(self, name):
conf_path = join(self.lib_dir, name, self.CONFIG_NAME)
if not isfile(conf_path):
raise LibNotInstalledError(name)
with open(conf_path, "r") as f:
return json.load(f)
def get_info(self, id_):
for item in self.get_installed().values():
if "id" in item and item['id'] == id_:
return item
raise LibNotInstalledError(id_)
def is_installed(self, name):
return isfile(join(self.lib_dir, name, self.CONFIG_NAME))
def is_installed(self, id_):
try:
return int(self.get_info(id_)['id']) == id_
except LibNotInstalledError:
return False
def install(self, name, version=None):
if self.is_installed(name):
def install(self, id_, version=None):
if self.is_installed(id_):
raise LibAlreadyInstalledError()
dlinfo = get_api_result("/lib/download/" + name, dict(version=version)
if version else None)
dlinfo = get_api_result("/lib/download/" + str(id_),
dict(version=version) if version else None)
dlpath = None
tmplib_dir = join(self.lib_dir, str(id_))
try:
dlpath = self.download(dlinfo['url'], gettempdir())
_lib_dir = join(self.lib_dir, name)
if not isdir(_lib_dir):
makedirs(_lib_dir)
self.unpack(dlpath, _lib_dir)
if not isdir(tmplib_dir):
makedirs(tmplib_dir)
self.unpack(dlpath, tmplib_dir)
finally:
remove(dlpath)
if dlpath:
remove(dlpath)
return self.is_installed(name)
info = self.get_info(id_)
rename(tmplib_dir, join(self.lib_dir, "%s_ID%d" % (
re.sub(r"[^\da-z]+", "_", info['name'], flags=re.I), id_)))
return True
def uninstall(self, name):
if self.is_installed(name):
rmtree(join(self.lib_dir, name))
return True
else:
raise LibNotInstalledError(name)
def uninstall(self, id_):
for libdir, item in self.get_installed().iteritems():
if "id" in item and item['id'] == id_:
rmtree(join(self.lib_dir, libdir))
return True
raise LibNotInstalledError(id_)
+2 -1
View File
@@ -137,7 +137,8 @@ def get_api_result(path, params=None, data=None):
else:
raise APIRequestError(e)
except ConnectionError:
raise APIRequestError("Could not connect to PlatformIO API Service")
raise APIRequestError(
"Could not connect to PlatformIO Registry Service")
except ValueError:
raise APIRequestError("Invalid response: %s" % r.text)
finally: