Show detailed info about a library using pio lib show command // Resolve #430

This commit is contained in:
Ivan Kravets
2016-12-28 15:55:08 +02:00
parent b6e09c5da4
commit e7cc94c27e
7 changed files with 113 additions and 83 deletions

View File

@ -1,3 +1,3 @@
[settings] [settings]
line_length=79 line_length=79
known_third_party=bottle,click,lockfile,pytest,requests,semantic_version,serial,SCons known_third_party=arrow,bottle,click,lockfile,pytest,requests,SCons,semantic_version,serial

View File

@ -14,6 +14,9 @@ PlatformIO 3.0
- Recent and popular keywords - Recent and popular keywords
- Featured libraries (today, week, month) - Featured libraries (today, week, month)
* Show detailed info about a library using `pio lib show <http://docs.platformio.org/page/userguide/lib/cmd_show.html>`__
command
(`issue #430 <https://github.com/platformio/platformio-core/issues/430>`_)
* Added support for templated methods in ``*.ino to *.cpp`` convertor * Added support for templated methods in ``*.ino to *.cpp`` convertor
(`pull #858 <https://github.com/platformio/platformio-core/pull/858>`_) (`pull #858 <https://github.com/platformio/platformio-core/pull/858>`_)
* Produce less noisy output when ``-s/--silent`` options are used for * Produce less noisy output when ``-s/--silent`` options are used for

2
docs

Submodule docs updated: 308775747a...b709064430

View File

@ -14,7 +14,7 @@
import sys import sys
VERSION = (3, 3, "0a1") VERSION = (3, 3, "0a2")
__version__ = ".".join([str(s) for s in VERSION]) __version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio" __title__ = "platformio"

View File

@ -12,12 +12,14 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# pylint: disable=too-many-branches, too-many-locals
import json import json
from datetime import datetime
from os.path import join from os.path import join
from time import sleep from time import sleep
from urllib import quote from urllib import quote
import arrow
import click import click
from platformio import exception, util from platformio import exception, util
@ -46,7 +48,7 @@ from platformio.util import get_api_result
@click.pass_context @click.pass_context
def cli(ctx, **options): def cli(ctx, **options):
# skip commands that don't need storage folder # skip commands that don't need storage folder
if ctx.invoked_subcommand in ("search", "register", "stats") or \ if ctx.invoked_subcommand in ("search", "show", "register", "stats") or \
(len(ctx.args) == 2 and ctx.args[1] in ("-h", "--help")): (len(ctx.args) == 2 and ctx.args[1] in ("-h", "--help")):
return return
storage_dir = options['storage_dir'] storage_dir = options['storage_dir']
@ -158,7 +160,7 @@ def echo_liblist_item(item):
description=description)) description=description))
@cli.command("search", short_help="Search for library") @cli.command("search", short_help="Search for a library")
@click.argument("query", required=False, nargs=-1) @click.argument("query", required=False, nargs=-1)
@click.option("--json-output", is_flag=True) @click.option("--json-output", is_flag=True)
@click.option("--page", type=click.INT, default=1) @click.option("--page", type=click.INT, default=1)
@ -247,8 +249,7 @@ def lib_list(lm, json_output):
items = lm.get_installed() items = lm.get_installed()
if json_output: if json_output:
click.echo(json.dumps(items)) return click.echo(json.dumps(items))
return
if not items: if not items:
return return
@ -260,28 +261,40 @@ def lib_list(lm, json_output):
echo_liblist_item(item) echo_liblist_item(item)
@cli.command("show", short_help="Show details about installed library") @cli.command("show", short_help="Show detailed info about a library")
@click.pass_obj
@click.argument("library", metavar="[LIBRARY]") @click.argument("library", metavar="[LIBRARY]")
def lib_show(lm, library): # pylint: disable=too-many-branches @click.option("--json-output", is_flag=True)
name, requirements, url = lm.parse_pkg_name(library) def lib_show(library, json_output):
package_dir = lm.get_package_dir(name, requirements, url) lm = LibraryManager()
if not package_dir: name, requirements, _ = lm.parse_pkg_name(library)
click.secho( lib_id = lm.get_pkg_id_by_name(
"%s @ %s is not installed" % (name, requirements or "*"), name, requirements, silent=json_output, interactive=not json_output)
fg="yellow") lib = get_api_result("/lib/info/%d" % lib_id, cache_valid="1d")
return if json_output:
return click.echo(json.dumps(lib))
manifest = lm.load_manifest(package_dir) click.secho(lib['name'], fg="cyan")
click.echo("=" * len(lib['name']))
click.secho(manifest['name'], fg="cyan") click.echo(lib['description'])
click.echo("=" * len(manifest['name']))
if "description" in manifest:
click.echo(manifest['description'])
click.echo() click.echo()
click.echo("Version: %s, released %s" %
(lib['version']['name'],
arrow.get(lib['version']['released']).humanize()))
click.echo("Registry ID: %d" % lib['id'])
click.echo("Manifest: %s" % lib['confurl'])
for key in ("homepage", "repository", "license"):
if key not in lib or not lib[key]:
continue
if isinstance(lib[key], list):
click.echo("%s: %s" % (key.title(), ", ".join(lib[key])))
else:
click.echo("%s: %s" % (key.title(), lib[key]))
blocks = []
_authors = [] _authors = []
for author in manifest.get("authors", []): for author in lib.get("authors", []):
_data = [] _data = []
for key in ("name", "email", "url", "maintainer"): for key in ("name", "email", "url", "maintainer"):
if not author[key]: if not author[key]:
@ -294,19 +307,33 @@ def lib_show(lm, library): # pylint: disable=too-many-branches
_data.append(author[key]) _data.append(author[key])
_authors.append(" ".join(_data)) _authors.append(" ".join(_data))
if _authors: if _authors:
click.echo("Authors: %s" % ", ".join(_authors)) blocks.append(("Authors", _authors))
for key in ("keywords", "frameworks", "platforms", "license", "url", blocks.append(("Keywords", lib['keywords']))
"version"): if lib['frameworks']:
if key not in manifest: blocks.append(("Compatible Frameworks", lib['frameworks']))
continue if lib['platforms']:
if isinstance(manifest[key], list): blocks.append(("Compatible Platforms", lib['platforms']))
click.echo("%s: %s" % (key.title(), ", ".join(manifest[key]))) blocks.append(("Headers", lib['headers']))
else: blocks.append(("Examples", lib['examples']))
click.echo("%s: %s" % (key.title(), manifest[key])) blocks.append(("Versions", [
"%s, released %s" % (v['name'], arrow.get(v['released']).humanize())
for v in lib['versions']
]))
blocks.append(("Unique Downloads", [
"Today: %s" % lib['dlstats']['day'], "Week: %s" %
lib['dlstats']['week'], "Month: %s" % lib['dlstats']['month']
]))
for (title, rows) in blocks:
click.echo()
click.secho(title, bold=True)
click.echo("-" * len(title))
for row in rows:
click.echo(row)
@cli.command("register", short_help="Register new library") @cli.command("register", short_help="Register a new library")
@click.argument("config_url") @click.argument("config_url")
def lib_register(config_url): def lib_register(config_url):
if (not config_url.startswith("http://") and if (not config_url.startswith("http://") and
@ -353,8 +380,7 @@ def lib_stats(json_output):
name=click.style( name=click.style(
item['name'], fg="cyan"), item['name'], fg="cyan"),
date=str( date=str(
datetime.strptime(item['date'].replace("Z", "UTC"), arrow.get(item['date']).humanize()
"%Y-%m-%dT%H:%M:%S%Z")
if "date" in item else ""), if "date" in item else ""),
url=click.style( url=click.style(
"http://platformio.org/lib/show/%s/%s" % (item[ "http://platformio.org/lib/show/%s/%s" % (item[

View File

@ -19,6 +19,7 @@ import os
from hashlib import md5 from hashlib import md5
from os.path import dirname, join from os.path import dirname, join
import arrow
import click import click
import semantic_version import semantic_version
@ -129,13 +130,8 @@ class LibraryManager(BasePkgManager):
def max_satisfying_repo_version(versions, requirements=None): def max_satisfying_repo_version(versions, requirements=None):
def _cmp_dates(datestr1, datestr2): def _cmp_dates(datestr1, datestr2):
from datetime import datetime date1 = arrow.get(datestr1)
assert "T" in datestr1 and "T" in datestr2 date2 = arrow.get(datestr2)
dateformat = "%Y-%m-%d %H:%M:%S"
date1 = datetime.strptime(datestr1[:-1].replace("T", " "),
dateformat)
date2 = datetime.strptime(datestr2[:-1].replace("T", " "),
dateformat)
if date1 == date2: if date1 == date2:
return 0 return 0
return -1 if date1 < date2 else 1 return -1 if date1 < date2 else 1
@ -150,7 +146,7 @@ class LibraryManager(BasePkgManager):
for v in versions: for v in versions:
specver = None specver = None
try: try:
specver = semantic_version.Version(v['version'], partial=True) specver = semantic_version.Version(v['name'], partial=True)
except ValueError: except ValueError:
pass pass
@ -158,30 +154,30 @@ class LibraryManager(BasePkgManager):
if not specver or specver not in reqspec: if not specver or specver not in reqspec:
continue continue
if not item or semantic_version.Version( if not item or semantic_version.Version(
item['version'], partial=True) < specver: item['name'], partial=True) < specver:
item = v item = v
elif requirements: elif requirements:
if requirements == v['version']: if requirements == v['name']:
return v return v
else: else:
if not item or _cmp_dates(item['date'], v['date']) == -1: if not item or _cmp_dates(item['released'],
v['released']) == -1:
item = v item = v
return item return item
def get_latest_repo_version(self, name, requirements): def get_latest_repo_version(self, name, requirements):
item = self.max_satisfying_repo_version( item = self.max_satisfying_repo_version(
util.get_api_result( util.get_api_result(
"/lib/versions/%d" % self._get_pkg_id_by_name(name, "/lib/info/%d" % self.get_pkg_id_by_name(name, requirements),
requirements), cache_valid="1d")['versions'],
cache_valid="1h"),
requirements) requirements)
return item['version'] if item else None return item['name'] if item else None
def _get_pkg_id_by_name(self, def get_pkg_id_by_name(self,
name, name,
requirements, requirements,
silent=False, silent=False,
interactive=False): interactive=False):
if name.startswith("id="): if name.startswith("id="):
return int(name[3:]) return int(name[3:])
# try to find ID from installed packages # try to find ID from installed packages
@ -222,7 +218,7 @@ class LibraryManager(BasePkgManager):
try: try:
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,
_requirements, _requirements,
silent=silent, silent=silent,
@ -299,30 +295,34 @@ class LibraryManager(BasePkgManager):
if result['total'] == 1: if result['total'] == 1:
lib_info = result['items'][0] lib_info = result['items'][0]
elif result['total'] > 1: elif result['total'] > 1:
click.secho( if silent and not interactive:
"Conflict: More than one library has been found "
"by request %s:" % json.dumps(filters),
fg="red",
err=True)
commands.lib.echo_liblist_header()
for item in result['items']:
commands.lib.echo_liblist_item(item)
if not interactive:
click.secho(
"Automatically chose the first available library "
"(use `--interactive` option to make a choice)",
fg="yellow",
err=True)
lib_info = result['items'][0] lib_info = result['items'][0]
else: else:
deplib_id = click.prompt( click.secho(
"Please choose library ID", "Conflict: More than one library has been found "
type=click.Choice([str(i['id']) for i in result['items']])) "by request %s:" % json.dumps(filters),
fg="red",
err=True)
commands.lib.echo_liblist_header()
for item in result['items']: for item in result['items']:
if item['id'] == int(deplib_id): commands.lib.echo_liblist_item(item)
lib_info = item
break if not interactive:
click.secho(
"Automatically chose the first available library "
"(use `--interactive` option to make a choice)",
fg="yellow",
err=True)
lib_info = result['items'][0]
else:
deplib_id = click.prompt(
"Please choose library ID",
type=click.Choice(
[str(i['id']) for i in result['items']]))
for item in result['items']:
if item['id'] == int(deplib_id):
lib_info = item
break
if not lib_info: if not lib_info:
if filters.keys() == ["name"]: if filters.keys() == ["name"]:

View File

@ -18,13 +18,14 @@ from platformio import (__author__, __description__, __email__, __license__,
__title__, __url__, __version__) __title__, __url__, __version__)
install_requires = [ install_requires = [
"arrow<1",
"bottle<0.13", "bottle<0.13",
"click>=5,<6", "click>=5,<6",
"lockfile>=0.9.1,<0.13",
"requests>=2.4.0,<3",
"semantic_version>=2.5.0",
"colorama", "colorama",
"pyserial>=3,<4" "lockfile>=0.9.1,<0.13",
"pyserial>=3,<4",
"requests>=2.4.0,<3",
"semantic_version>=2.5.0"
] ]
setup( setup(