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]
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
- 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
(`pull #858 <https://github.com/platformio/platformio-core/pull/858>`_)
* 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
VERSION = (3, 3, "0a1")
VERSION = (3, 3, "0a2")
__version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio"

View File

@ -12,12 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# pylint: disable=too-many-branches, too-many-locals
import json
from datetime import datetime
from os.path import join
from time import sleep
from urllib import quote
import arrow
import click
from platformio import exception, util
@ -46,7 +48,7 @@ from platformio.util import get_api_result
@click.pass_context
def cli(ctx, **options):
# 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")):
return
storage_dir = options['storage_dir']
@ -158,7 +160,7 @@ def echo_liblist_item(item):
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.option("--json-output", is_flag=True)
@click.option("--page", type=click.INT, default=1)
@ -247,8 +249,7 @@ def lib_list(lm, json_output):
items = lm.get_installed()
if json_output:
click.echo(json.dumps(items))
return
return click.echo(json.dumps(items))
if not items:
return
@ -260,28 +261,40 @@ def lib_list(lm, json_output):
echo_liblist_item(item)
@cli.command("show", short_help="Show details about installed library")
@click.pass_obj
@cli.command("show", short_help="Show detailed info about a library")
@click.argument("library", metavar="[LIBRARY]")
def lib_show(lm, library): # pylint: disable=too-many-branches
name, requirements, url = lm.parse_pkg_name(library)
package_dir = lm.get_package_dir(name, requirements, url)
if not package_dir:
click.secho(
"%s @ %s is not installed" % (name, requirements or "*"),
fg="yellow")
return
@click.option("--json-output", is_flag=True)
def lib_show(library, json_output):
lm = LibraryManager()
name, requirements, _ = lm.parse_pkg_name(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")
if json_output:
return click.echo(json.dumps(lib))
manifest = lm.load_manifest(package_dir)
click.secho(manifest['name'], fg="cyan")
click.echo("=" * len(manifest['name']))
if "description" in manifest:
click.echo(manifest['description'])
click.secho(lib['name'], fg="cyan")
click.echo("=" * len(lib['name']))
click.echo(lib['description'])
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 = []
for author in manifest.get("authors", []):
for author in lib.get("authors", []):
_data = []
for key in ("name", "email", "url", "maintainer"):
if not author[key]:
@ -294,19 +307,33 @@ def lib_show(lm, library): # pylint: disable=too-many-branches
_data.append(author[key])
_authors.append(" ".join(_data))
if _authors:
click.echo("Authors: %s" % ", ".join(_authors))
blocks.append(("Authors", _authors))
for key in ("keywords", "frameworks", "platforms", "license", "url",
"version"):
if key not in manifest:
continue
if isinstance(manifest[key], list):
click.echo("%s: %s" % (key.title(), ", ".join(manifest[key])))
else:
click.echo("%s: %s" % (key.title(), manifest[key]))
blocks.append(("Keywords", lib['keywords']))
if lib['frameworks']:
blocks.append(("Compatible Frameworks", lib['frameworks']))
if lib['platforms']:
blocks.append(("Compatible Platforms", lib['platforms']))
blocks.append(("Headers", lib['headers']))
blocks.append(("Examples", lib['examples']))
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")
def lib_register(config_url):
if (not config_url.startswith("http://") and
@ -353,8 +380,7 @@ def lib_stats(json_output):
name=click.style(
item['name'], fg="cyan"),
date=str(
datetime.strptime(item['date'].replace("Z", "UTC"),
"%Y-%m-%dT%H:%M:%S%Z")
arrow.get(item['date']).humanize()
if "date" in item else ""),
url=click.style(
"http://platformio.org/lib/show/%s/%s" % (item[

View File

@ -19,6 +19,7 @@ import os
from hashlib import md5
from os.path import dirname, join
import arrow
import click
import semantic_version
@ -129,13 +130,8 @@ class LibraryManager(BasePkgManager):
def max_satisfying_repo_version(versions, requirements=None):
def _cmp_dates(datestr1, datestr2):
from datetime import datetime
assert "T" in datestr1 and "T" in datestr2
dateformat = "%Y-%m-%d %H:%M:%S"
date1 = datetime.strptime(datestr1[:-1].replace("T", " "),
dateformat)
date2 = datetime.strptime(datestr2[:-1].replace("T", " "),
dateformat)
date1 = arrow.get(datestr1)
date2 = arrow.get(datestr2)
if date1 == date2:
return 0
return -1 if date1 < date2 else 1
@ -150,7 +146,7 @@ class LibraryManager(BasePkgManager):
for v in versions:
specver = None
try:
specver = semantic_version.Version(v['version'], partial=True)
specver = semantic_version.Version(v['name'], partial=True)
except ValueError:
pass
@ -158,30 +154,30 @@ class LibraryManager(BasePkgManager):
if not specver or specver not in reqspec:
continue
if not item or semantic_version.Version(
item['version'], partial=True) < specver:
item['name'], partial=True) < specver:
item = v
elif requirements:
if requirements == v['version']:
if requirements == v['name']:
return v
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
return item
def get_latest_repo_version(self, name, requirements):
item = self.max_satisfying_repo_version(
util.get_api_result(
"/lib/versions/%d" % self._get_pkg_id_by_name(name,
requirements),
cache_valid="1h"),
"/lib/info/%d" % self.get_pkg_id_by_name(name, requirements),
cache_valid="1d")['versions'],
requirements)
return item['version'] if item else None
return item['name'] if item else None
def _get_pkg_id_by_name(self,
name,
requirements,
silent=False,
interactive=False):
def get_pkg_id_by_name(self,
name,
requirements,
silent=False,
interactive=False):
if name.startswith("id="):
return int(name[3:])
# try to find ID from installed packages
@ -222,7 +218,7 @@ class LibraryManager(BasePkgManager):
try:
if not _url:
_name = "id=%d" % self._get_pkg_id_by_name(
_name = "id=%d" % self.get_pkg_id_by_name(
_name,
_requirements,
silent=silent,
@ -299,30 +295,34 @@ class LibraryManager(BasePkgManager):
if result['total'] == 1:
lib_info = result['items'][0]
elif result['total'] > 1:
click.secho(
"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)
if silent and not interactive:
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']]))
click.secho(
"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']:
if item['id'] == int(deplib_id):
lib_info = item
break
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]
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 filters.keys() == ["name"]:

View File

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