Improve cache logic for lookup operations

This commit is contained in:
Ivan Kravets
2015-04-23 14:11:30 +01:00
parent 31a2880c3c
commit 97044bf5a5
3 changed files with 106 additions and 71 deletions

View File

@ -8,28 +8,24 @@ from time import time
import click
from platformio import exception, telemetry
from platformio import exception, telemetry, util
from platformio.app import get_state_item, set_state_item
from platformio.downloader import FileDownloader
from platformio.unpacker import FileUnpacker
from platformio.util import get_api_result, get_home_dir, get_systype
class PackageManager(object):
def __init__(self):
self._package_dir = join(get_home_dir(), "packages")
self._package_dir = join(util.get_home_dir(), "packages")
if not isdir(self._package_dir):
makedirs(self._package_dir)
assert isdir(self._package_dir)
@classmethod
@util.memoized
def get_manifest(cls):
try:
return cls._cached_manifest
except AttributeError:
cls._cached_manifest = get_api_result("/packages/manifest")
return cls._cached_manifest
return util.get_api_result("/packages/manifest")
@staticmethod
def download(url, dest_dir, sha1=None):
@ -63,7 +59,7 @@ class PackageManager(object):
raise exception.UnknownPackage(name)
# check system platform
systype = get_systype()
systype = util.get_systype()
builds = ([b for b in manifest[name] if b['system'] == "all" or systype
in b['system']])
if not builds:

View File

@ -132,32 +132,33 @@ class PlatformFactory(object):
return module
@classmethod
def get_platforms(cls, installed=False):
@util.memoized
def _lookup_platforms(cls):
platforms = {}
try:
platforms = cls.get_platforms_cache
except AttributeError:
for d in (util.get_home_dir(), util.get_source_dir()):
pdir = join(d, "platforms")
if not isdir(pdir):
for d in (util.get_home_dir(), util.get_source_dir()):
pdir = join(d, "platforms")
if not isdir(pdir):
continue
for p in listdir(pdir):
if (p in ("__init__.py", "base.py") or not
p.endswith(".py")):
continue
for p in listdir(pdir):
if (p in ("__init__.py", "base.py") or not
p.endswith(".py")):
continue
type_ = p[:-3]
path = join(pdir, p)
try:
isplatform = hasattr(
cls.load_module(type_, path),
cls.get_clsname(type_)
)
if isplatform:
platforms[type_] = path
except exception.UnknownPlatform:
pass
cls.get_platforms_cache = platforms
type_ = p[:-3]
path = join(pdir, p)
try:
isplatform = hasattr(
cls.load_module(type_, path),
cls.get_clsname(type_)
)
if isplatform:
platforms[type_] = path
except exception.UnknownPlatform:
pass
return platforms
@classmethod
def get_platforms(cls, installed=False):
platforms = cls._lookup_platforms()
if not installed:
return platforms

View File

@ -1,6 +1,8 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details.
import collections
import functools
import json
import os
import re
@ -53,6 +55,39 @@ class AsyncPipe(Thread):
self.join()
class memoized(object):
'''
Decorator. Caches a function's return value each time it is called.
If called later with the same arguments, the cached value is returned
(not reevaluated).
https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
'''
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
if not isinstance(args, collections.Hashable):
# uncacheable. a list, for instance.
# better to not cache than blow up.
return self.func(*args)
if args in self.cache:
return self.cache[args]
else:
value = self.func(*args)
self.cache[args] = value
return value
def __repr__(self):
'''Return the function's docstring.'''
return self.func.__doc__
def __get__(self, obj, objtype):
'''Support instance methods.'''
return functools.partial(self.__call__, obj)
def get_systype():
data = uname()
return ("%s_%s" % (data[0], data[4])).lower()
@ -239,22 +274,24 @@ def get_api_result(path, params=None, data=None):
return result
def get_boards(type_=None):
@memoized
def _lookup_boards():
boards = {}
try:
boards = get_boards._cache # pylint: disable=W0212
except AttributeError:
bdirs = [join(get_source_dir(), "boards")]
if isdir(join(get_home_dir(), "boards")):
bdirs.append(join(get_home_dir(), "boards"))
bdirs = [join(get_source_dir(), "boards")]
if isdir(join(get_home_dir(), "boards")):
bdirs.append(join(get_home_dir(), "boards"))
for bdir in bdirs:
for json_file in os.listdir(bdir):
if not json_file.endswith(".json"):
continue
with open(join(bdir, json_file)) as f:
boards.update(json.load(f))
get_boards._cache = boards # pylint: disable=W0212
for bdir in bdirs:
for json_file in os.listdir(bdir):
if not json_file.endswith(".json"):
continue
with open(join(bdir, json_file)) as f:
boards.update(json.load(f))
return boards
def get_boards(type_=None):
boards = _lookup_boards()
if type_ is None:
return boards
@ -264,33 +301,34 @@ def get_boards(type_=None):
return boards[type_]
def get_frameworks(type_=None):
@memoized
def _lookup_frameworks():
frameworks = {}
frameworks_path = join(
get_source_dir(), "builder", "scripts", "frameworks")
try:
frameworks = get_frameworks._cache # pylint: disable=W0212
except AttributeError:
frameworks_path = join(
get_source_dir(), "builder", "scripts", "frameworks")
frameworks_list = [f[:-3] for f in os.listdir(frameworks_path)
if not f.startswith("__") and f.endswith(".py")]
for _type in frameworks_list:
script_path = join(frameworks_path, "%s.py" % _type)
with open(script_path) as f:
fcontent = f.read()
assert '"""' in fcontent
_doc_start = fcontent.index('"""') + 3
fdoc = fcontent[
_doc_start:fcontent.index('"""', _doc_start)].strip()
doclines = [l.strip() for l in fdoc.splitlines() if l.strip()]
frameworks[_type] = {
"name": doclines[0],
"description": " ".join(doclines[1:-1]),
"url": doclines[-1],
"script": script_path
}
return frameworks
frameworks_list = [f[:-3] for f in os.listdir(frameworks_path)
if not f.startswith("__") and f.endswith(".py")]
for _type in frameworks_list:
script_path = join(frameworks_path, "%s.py" % _type)
with open(script_path) as f:
fcontent = f.read()
assert '"""' in fcontent
_doc_start = fcontent.index('"""') + 3
fdoc = fcontent[
_doc_start:fcontent.index('"""', _doc_start)].strip()
doclines = [l.strip() for l in fdoc.splitlines() if l.strip()]
frameworks[_type] = {
"name": doclines[0],
"description": " ".join(doclines[1:-1]),
"url": doclines[-1],
"script": script_path
}
get_frameworks._cache = frameworks # pylint: disable=W0212
def get_frameworks(type_=None):
frameworks = _lookup_frameworks()
if type_ is None:
return frameworks