forked from platformio/platformio-core
		
	
		
			
				
	
	
		
			320 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			320 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Copyright 2014-present PlatformIO <contact@platformio.org>
 | 
						|
#
 | 
						|
# 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.
 | 
						|
 | 
						|
import json
 | 
						|
from os.path import join
 | 
						|
from time import sleep
 | 
						|
 | 
						|
import click
 | 
						|
 | 
						|
from platformio import exception, util
 | 
						|
from platformio.managers.lib import LibraryManager
 | 
						|
from platformio.util import get_api_result
 | 
						|
 | 
						|
 | 
						|
@click.group(short_help="Library Manager")
 | 
						|
@click.option(
 | 
						|
    "-g",
 | 
						|
    "--global",
 | 
						|
    is_flag=True,
 | 
						|
    help="Manage global PlatformIO"
 | 
						|
    " library storage `%s`" % join(util.get_home_dir(), "lib"))
 | 
						|
@click.option(
 | 
						|
    "-d",
 | 
						|
    "--storage-dir",
 | 
						|
    default=None,
 | 
						|
    type=click.Path(
 | 
						|
        exists=True,
 | 
						|
        file_okay=False,
 | 
						|
        dir_okay=True,
 | 
						|
        writable=True,
 | 
						|
        resolve_path=True),
 | 
						|
    help="Manage custom library storage")
 | 
						|
@click.pass_context
 | 
						|
def cli(ctx, **options):
 | 
						|
    # skip commands that don't need storage folder
 | 
						|
    if ctx.invoked_subcommand in ("search", "register") or \
 | 
						|
            (len(ctx.args) == 2 and ctx.args[1] in ("-h", "--help")):
 | 
						|
        return
 | 
						|
    storage_dir = options['storage_dir']
 | 
						|
    if not storage_dir:
 | 
						|
        if options['global']:
 | 
						|
            storage_dir = join(util.get_home_dir(), "lib")
 | 
						|
        elif util.is_platformio_project():
 | 
						|
            storage_dir = util.get_projectlibdeps_dir()
 | 
						|
        elif util.is_ci():
 | 
						|
            storage_dir = join(util.get_home_dir(), "lib")
 | 
						|
            click.secho(
 | 
						|
                "Warning! Global library storage is used automatically. "
 | 
						|
                "Please use `platformio lib --global %s` command to remove "
 | 
						|
                "this warning." % ctx.invoked_subcommand,
 | 
						|
                fg="yellow")
 | 
						|
 | 
						|
    if not storage_dir and not util.is_platformio_project():
 | 
						|
        raise exception.NotGlobalLibDir(util.get_project_dir(),
 | 
						|
                                        join(util.get_home_dir(), "lib"),
 | 
						|
                                        ctx.invoked_subcommand)
 | 
						|
 | 
						|
    ctx.obj = LibraryManager(storage_dir)
 | 
						|
    if "--json-output" not in ctx.args:
 | 
						|
        click.echo("Library Storage: " + storage_dir)
 | 
						|
 | 
						|
 | 
						|
@cli.command("install", short_help="Install library")
 | 
						|
@click.argument("libraries", required=False, nargs=-1, metavar="[LIBRARY...]")
 | 
						|
# @click.option(
 | 
						|
#     "--save",
 | 
						|
#     is_flag=True,
 | 
						|
#     help="Save installed libraries into the project's platformio.ini "
 | 
						|
#     "library dependencies")
 | 
						|
@click.option(
 | 
						|
    "-s", "--silent", is_flag=True, help="Suppress progress reporting")
 | 
						|
@click.option(
 | 
						|
    "--interactive",
 | 
						|
    is_flag=True,
 | 
						|
    help="Allow to make a choice for all prompts")
 | 
						|
@click.pass_obj
 | 
						|
def lib_install(lm, libraries, silent, interactive):
 | 
						|
    # @TODO "save" option
 | 
						|
    for library in libraries:
 | 
						|
        lm.install(library, silent=silent, interactive=interactive)
 | 
						|
 | 
						|
 | 
						|
@cli.command("uninstall", short_help="Uninstall libraries")
 | 
						|
@click.argument("libraries", nargs=-1, metavar="[LIBRARY...]")
 | 
						|
@click.pass_obj
 | 
						|
def lib_uninstall(lm, libraries):
 | 
						|
    for library in libraries:
 | 
						|
        lm.uninstall(library)
 | 
						|
 | 
						|
 | 
						|
@cli.command("update", short_help="Update installed libraries")
 | 
						|
@click.argument("libraries", required=False, nargs=-1, metavar="[LIBRARY...]")
 | 
						|
@click.option(
 | 
						|
    "-c",
 | 
						|
    "--only-check",
 | 
						|
    is_flag=True,
 | 
						|
    help="Do not update, only check for new version")
 | 
						|
@click.pass_obj
 | 
						|
def lib_update(lm, libraries, only_check):
 | 
						|
    if not libraries:
 | 
						|
        libraries = [str(m.get("id", m['name'])) for m in lm.get_installed()]
 | 
						|
    for library in libraries:
 | 
						|
        lm.update(library, only_check=only_check)
 | 
						|
 | 
						|
#######
 | 
						|
 | 
						|
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"))
 | 
						|
 | 
						|
    terminal_width, _ = click.get_terminal_size()
 | 
						|
    click.echo("-" * terminal_width)
 | 
						|
 | 
						|
 | 
						|
def echo_liblist_item(item):
 | 
						|
    description = item.get("description", item.get("url", "")).encode("utf-8")
 | 
						|
    if "version" in item:
 | 
						|
        description += " | @" + click.style(item['version'], fg="yellow")
 | 
						|
 | 
						|
    click.echo(
 | 
						|
        LIBLIST_TPL.format(
 | 
						|
            id=click.style(
 | 
						|
                str(item.get("id", "-")), fg="green"),
 | 
						|
            name=click.style(
 | 
						|
                item['name'], fg="cyan"),
 | 
						|
            compatibility=click.style(
 | 
						|
                ", ".join(
 | 
						|
                    item.get("frameworks", ["-"]) + item.get("platforms", [])),
 | 
						|
                fg="yellow"),
 | 
						|
            authornames=", ".join(item.get("authornames", ["Unknown"])).encode(
 | 
						|
                "utf-8"),
 | 
						|
            description=description))
 | 
						|
 | 
						|
 | 
						|
@cli.command("search", short_help="Search for library")
 | 
						|
@click.argument("query", required=False, nargs=-1)
 | 
						|
@click.option("--json-output", is_flag=True)
 | 
						|
@click.option("--page", type=click.INT, default=1)
 | 
						|
@click.option("-n", "--name", multiple=True)
 | 
						|
@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.option("-i", "--header", multiple=True)
 | 
						|
@click.option(
 | 
						|
    "--noninteractive",
 | 
						|
    is_flag=True,
 | 
						|
    help="Do not prompt, automatically paginate with delay")
 | 
						|
def lib_search(query, json_output, page, noninteractive, **filters):
 | 
						|
    if not query:
 | 
						|
        query = []
 | 
						|
    if not isinstance(query, list):
 | 
						|
        query = list(query)
 | 
						|
 | 
						|
    for key, values in filters.iteritems():
 | 
						|
        for value in values:
 | 
						|
            query.append('%s:"%s"' % (key, value))
 | 
						|
 | 
						|
    result = get_api_result(
 | 
						|
        "/lib/search",
 | 
						|
        dict(
 | 
						|
            query=" ".join(query), page=page),
 | 
						|
        cache_valid="3d")
 | 
						|
 | 
						|
    if json_output:
 | 
						|
        click.echo(json.dumps(result))
 | 
						|
        return
 | 
						|
 | 
						|
    if result['total'] == 0:
 | 
						|
        click.secho(
 | 
						|
            "Nothing has been found by your request\n"
 | 
						|
            "Try a less-specific search or use truncation (or wildcard) "
 | 
						|
            "operator",
 | 
						|
            fg="yellow",
 | 
						|
            nl=False)
 | 
						|
        click.secho(" *", fg="green")
 | 
						|
        click.secho("For example: DS*, PCA*, DHT* and etc.\n", fg="yellow")
 | 
						|
        click.echo("For more examples and advanced search syntax, "
 | 
						|
                   "please use documentation:")
 | 
						|
        click.secho(
 | 
						|
            "http://docs.platformio.org"
 | 
						|
            "/en/stable/userguide/lib/cmd_search.html\n",
 | 
						|
            fg="cyan")
 | 
						|
        return
 | 
						|
 | 
						|
    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']:
 | 
						|
            echo_liblist_item(item)
 | 
						|
 | 
						|
        if (int(result['page']) * int(result['perpage']) >=
 | 
						|
                int(result['total'])):
 | 
						|
            break
 | 
						|
 | 
						|
        if noninteractive:
 | 
						|
            click.echo()
 | 
						|
            click.secho(
 | 
						|
                "Loading next %d libraries... Press Ctrl+C to stop!" %
 | 
						|
                result['perpage'],
 | 
						|
                fg="yellow")
 | 
						|
            click.echo()
 | 
						|
            sleep(5)
 | 
						|
        elif not click.confirm("Show next libraries?"):
 | 
						|
            break
 | 
						|
        result = get_api_result(
 | 
						|
            "/lib/search",
 | 
						|
            dict(
 | 
						|
                query=" ".join(query), page=int(result['page']) + 1),
 | 
						|
            cache_valid="3d")
 | 
						|
 | 
						|
 | 
						|
@cli.command("list", short_help="List installed libraries")
 | 
						|
@click.option("--json-output", is_flag=True)
 | 
						|
@click.pass_obj
 | 
						|
def lib_list(lm, json_output):
 | 
						|
    items = lm.get_installed()
 | 
						|
 | 
						|
    if json_output:
 | 
						|
        click.echo(json.dumps(items))
 | 
						|
        return
 | 
						|
 | 
						|
    if not items:
 | 
						|
        return
 | 
						|
 | 
						|
    echo_liblist_header()
 | 
						|
    for item in sorted(items, key=lambda i: i['name']):
 | 
						|
        if "authors" in item:
 | 
						|
            item['authornames'] = [i['name'] for i in item['authors']]
 | 
						|
        echo_liblist_item(item)
 | 
						|
 | 
						|
 | 
						|
@cli.command("show", short_help="Show details about installed library")
 | 
						|
@click.pass_obj
 | 
						|
@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
 | 
						|
 | 
						|
    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.echo()
 | 
						|
 | 
						|
    _authors = []
 | 
						|
    for author in manifest.get("authors", []):
 | 
						|
        _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))
 | 
						|
    if _authors:
 | 
						|
        click.echo("Authors: %s" % ", ".join(_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]))
 | 
						|
 | 
						|
 | 
						|
@cli.command("register", short_help="Register new library")
 | 
						|
@click.argument("config_url")
 | 
						|
def lib_register(config_url):
 | 
						|
    if (not config_url.startswith("http://") and
 | 
						|
            not config_url.startswith("https://")):
 | 
						|
        raise exception.InvalidLibConfURL(config_url)
 | 
						|
 | 
						|
    result = get_api_result("/lib/register", data=dict(config_url=config_url))
 | 
						|
    if "message" in result and result['message']:
 | 
						|
        click.secho(
 | 
						|
            result['message'],
 | 
						|
            fg="green"
 | 
						|
            if "successed" in result and result['successed'] else "red")
 |