Merge branch 'feature/library-manager' into develop

This commit is contained in:
Ivan Kravets
2014-09-05 21:39:41 +03:00
8 changed files with 264 additions and 6 deletions

View File

@ -1,7 +1,7 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
VERSION = (0, 7, "0-dev")
VERSION = (0, 7, "0.dev")
__version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio"
@ -14,4 +14,6 @@ __email__ = "me@ikravets.com"
__license__ = "MIT License"
__copyright__ = "Copyright (C) 2014 Ivan Kravets"
# __apiurl__ = "http://127.0.0.1:8080"
__apiurl__ = "http://api.platformio.ikravets.com"
__pkgmanifesturl__ = "http://platformio.ikravets.com/packages/manifest.json"

View File

@ -16,7 +16,8 @@ from os.path import isdir, join
from SCons.Script import (DefaultEnvironment, Exit, SConscript,
SConscriptChdir, Variables)
from platformio.util import get_pioenvs_dir, get_project_dir, get_source_dir
from platformio.util import (get_lib_dir, get_pioenvs_dir, get_project_dir,
get_source_dir)
# AllowSubstExceptions()
@ -57,6 +58,7 @@ DefaultEnvironment(
BUILD_DIR=join("$PIOENVS_DIR", "$PIOENV"),
LIBSOURCE_DIRS=[
join("$PROJECT_DIR", "lib"),
get_lib_dir(),
join("$PLATFORMFW_DIR", "libraries"),
]
)

View File

@ -165,8 +165,9 @@ def ConvertInotoCpp(env):
remove(f)
tmpcpp = []
for item in env.Glob(join("$PROJECT_DIR", "src", "*.ino")):
items = (env.Glob(join("$PROJECT_DIR", "src", "*.ino")) +
env.Glob(join("$PROJECT_DIR", "src", "*.pde")))
for item in items:
cppfile = item.get_path()[:-3] + "cpp"
if isfile(cppfile):
continue

124
platformio/commands/lib.py Normal file
View File

@ -0,0 +1,124 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
from urllib import quote
from click import argument, echo, group, option, secho, style
from platformio.exception import LibAlreadyInstalledError
from platformio.libmanager import LibraryManager
from platformio.util import get_api_result, get_lib_dir
@group(short_help="Library Manager")
def cli():
pass
@cli.command("search", short_help="Search for library")
@argument("query")
def lib_search(query):
result = get_api_result("/lib/search", dict(query=quote(query)))
secho("Found %d libraries:" % result['total'],
fg="green" if result['total'] else "yellow")
for item in result['items']:
echo("{name:<30} {description}".format(
name=style(item['name'], fg="cyan"),
description=item['description']
))
@cli.command("install", short_help="Install library")
@argument("names", nargs=-1)
@option("-v", "--version")
def lib_install_cli(names, version):
lib_install(names, version)
def lib_install(names, version=None):
lm = LibraryManager(get_lib_dir())
for name in names:
echo("Installing %s library:" % style(name, fg="cyan"))
try:
if lm.install(name, version):
secho("The library '%s' has been successfully installed!" %
name, fg="green")
except LibAlreadyInstalledError:
secho("Already installed", fg="yellow")
@cli.command("uninstall", short_help="Uninstall libraries")
@argument("names", nargs=-1)
def lib_uninstall_cli(names):
lib_uninstall(names)
def lib_uninstall(names):
lm = LibraryManager(get_lib_dir())
for name in names:
if lm.uninstall(name):
secho("The library '%s' has been successfully "
"uninstalled!" % 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)
echo("{name:<30} {description}".format(
name=style(info['name'], fg="cyan"),
description=info['description']
))
@cli.command("show", short_help="Show details about installed libraries")
@argument("name")
def lib_show(name):
lm = LibraryManager(get_lib_dir())
info = lm.get_info(name)
secho(info['name'], fg="cyan")
echo("-" * len(info['name']))
if "author" in info:
_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)
echo("Author: %s" % " ".join(_data))
echo("Keywords: %s" % info['keywords'])
echo("Version: %s" % info['version'])
echo()
echo(info['description'])
echo()
@cli.command("update", short_help="Update installed libraries")
def lib_update():
lm = LibraryManager(get_lib_dir())
lib_names = lm.get_installed()
versions = get_api_result("/lib/version/" + ",".join(lib_names))
for name in lib_names:
info = lm.get_info(name)
echo("Updating %s library:" % style(name, fg="yellow"))
current_version = info['version']
latest_version = versions[name]
echo("Versions: Current=%s, Latest=%s \t " % (
current_version, latest_version), nl=False)
if current_version == latest_version:
echo("[%s]" % (style("Up-to-date", fg="green")))
continue
else:
echo("[%s]" % (style("Out-of-date", fg="red")))
lib_uninstall([name])
lib_install([name])

View File

@ -10,7 +10,7 @@ from platformio.pkgmanager import PackageManager
from platformio.platforms.base import PlatformFactory
@command("show", short_help="Show details about an installed platforms")
@command("show", short_help="Show details about installed platforms")
@argument("platform")
def cli(platform):
p = PlatformFactory().newPlatform(platform)

View File

@ -105,3 +105,17 @@ class GetSerialPortsError(PlatformioException):
class GetLatestVersionError(PlatformioException):
MESSAGE = "Can't retrieve latest PlatformIO version"
class APIRequestError(PlatformioException):
MESSAGE = "[API] %s"
class LibAlreadyInstalledError(PlatformioException):
pass
class LibNotInstalledError(PlatformioException):
MESSAGE = "Library '%s' has not been installed yet"

75
platformio/libmanager.py Normal file
View File

@ -0,0 +1,75 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
import json
from os import listdir, makedirs, remove
from os.path import isdir, isfile, join
from shutil import rmtree
from tempfile import gettempdir
from platformio.downloader import FileDownloader
from platformio.exception import LibAlreadyInstalledError, LibNotInstalledError
from platformio.unpacker import FileUnpacker
from platformio.util import get_api_result
class LibraryManager(object):
CONFIG_NAME = "library.json"
def __init__(self, lib_dir):
self.lib_dir = lib_dir
@staticmethod
def download(url, dest_dir):
fd = FileDownloader(url, dest_dir)
fd.start()
return fd.get_filepath()
@staticmethod
def unpack(pkgpath, dest_dir):
fu = FileUnpacker(pkgpath, dest_dir)
return fu.start()
def get_installed(self):
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)
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 is_installed(self, name):
return isfile(join(self.lib_dir, name, self.CONFIG_NAME))
def install(self, name, version=None):
if self.is_installed(name):
raise LibAlreadyInstalledError()
_lib_dir = join(self.lib_dir, name)
if not isdir(_lib_dir):
makedirs(_lib_dir)
dlinfo = get_api_result("/lib/download/" + name, dict(version=version)
if version else None)
try:
dlpath = self.download(dlinfo['url'], gettempdir())
self.unpack(dlpath, _lib_dir)
finally:
remove(dlpath)
return self.is_installed(name)
def uninstall(self, name):
if self.is_installed(name):
rmtree(join(self.lib_dir, name))
return True
else:
raise LibNotInstalledError(name)

View File

@ -8,9 +8,14 @@ from platform import system, uname
from subprocess import PIPE, Popen
from time import sleep
from requests import get
from requests.exceptions import ConnectionError, HTTPError
from requests.utils import default_user_agent
from serial import Serial
from platformio.exception import GetSerialPortsError, NotPlatformProject
from platformio import __apiurl__, __version__
from platformio.exception import (APIRequestError, GetSerialPortsError,
NotPlatformProject)
try:
from configparser import ConfigParser
@ -36,6 +41,17 @@ def get_home_dir():
return expanduser("~/.platformio")
def get_lib_dir():
try:
config = get_project_config()
if (config.has_section("platformio") and
config.has_option("platformio", "lib_dir")):
return config.get("platformio", "lib_dir")
except NotPlatformProject:
pass
return join(get_home_dir(), "lib")
def get_source_dir():
return dirname(realpath(__file__))
@ -96,3 +112,27 @@ def get_serialports():
else:
raise GetSerialPortsError(os_name)
return[{"port": p, "description": d, "hwid": h} for p, d, h in comports()]
def get_api_result(path, params=None):
result = None
r = None
try:
headers = {"User-Agent": "PlatformIO/%s %s" % (
__version__, default_user_agent())}
r = get(__apiurl__ + path, params=params, headers=headers)
result = r.json()
r.raise_for_status()
except HTTPError as e:
if result and "errors" in result:
raise APIRequestError(result['errors'][0]['title'])
else:
raise APIRequestError(e)
except ConnectionError:
raise APIRequestError("Could not connect to PlatformIO API Service")
except ValueError:
raise APIRequestError("Invalid response: %s" % r.text)
finally:
if r:
r.close()
return result