Cleanup: Changes suggested by @sybren
This commit is contained in:
126
make_repo.py
126
make_repo.py
@@ -20,10 +20,9 @@ def iter_addons(path: Path) -> (Path, dict):
|
||||
"""
|
||||
Generator, yields (path, bl_info) of blender addons in `path`.
|
||||
"""
|
||||
pass
|
||||
for item in path.iterdir():
|
||||
try:
|
||||
yield(item, extract_blinfo(item))
|
||||
yield (item, extract_blinfo(item))
|
||||
except BadAddon as err:
|
||||
log.debug("Skipping '{}': {}".format(item.name, err))
|
||||
|
||||
@@ -48,104 +47,122 @@ def parse_blinfo(source: str) -> dict:
|
||||
raise BadAddon('No bl_info found')
|
||||
|
||||
|
||||
def blinfo_from_zip(item: Path) -> dict:
|
||||
try:
|
||||
with zipfile.ZipFile(str(item), 'r') as z:
|
||||
if len(z.namelist()) == 1:
|
||||
# zipfile with one item: just read that item
|
||||
return parse_blinfo(z.read(z.namelist()[0]))
|
||||
else:
|
||||
# zipfile with multiple items: try all __init__.py files
|
||||
for fname in z.namelist():
|
||||
# TODO: zips with multiple bl_infos might be a problem,
|
||||
# not sure how such cases should be handled (if at all)
|
||||
# for now we just break after the first one
|
||||
if fname.endswith('__init__.py'):
|
||||
try:
|
||||
return parse_blinfo(z.read(fname))
|
||||
except BadAddon:
|
||||
continue
|
||||
|
||||
raise BadAddon("Zipfile '%s' doesn't contain a readable bl_info dict" % item)
|
||||
|
||||
except zipfile.BadZipFile as err:
|
||||
raise BadAddon("Bad zipfile '%s'" % item) from err
|
||||
|
||||
|
||||
def blinfo_from_py(item: Path) -> dict:
|
||||
with item.open() as f:
|
||||
return parse_blinfo(f.read())
|
||||
|
||||
def blinfo_from_dir(item: Path) -> dict:
|
||||
try:
|
||||
f = (item / '__init__.py').open("r")
|
||||
except FileNotFoundError as err:
|
||||
raise BadAddon("Directory '%s' doesn't contain __init__.py; not a python package" % item) from err
|
||||
with f:
|
||||
return parse_blinfo(f.read())
|
||||
|
||||
def extract_blinfo(item: Path) -> dict:
|
||||
"""
|
||||
Extract bl_info dict from addon at path (can be single file, python package, or zip)
|
||||
"""
|
||||
|
||||
blinfo = None
|
||||
|
||||
if not item.exists():
|
||||
raise FileNotFoundError("Cannot extract blinfo from '%s'; no such file or directory" % item)
|
||||
|
||||
if item.is_dir():
|
||||
|
||||
try:
|
||||
f = (item / '__init__.py').open("r")
|
||||
except FileNotFoundError as err:
|
||||
raise BadAddon("Directory '%s' doesn't contain __init__.py; not a python package" % item) from err
|
||||
with f:
|
||||
blinfo = parse_blinfo(f.read())
|
||||
return blinfo_from_dir(item)
|
||||
|
||||
elif item.is_file():
|
||||
if item.is_file():
|
||||
ext = item.suffix.lower()
|
||||
|
||||
if ext == '.zip':
|
||||
try:
|
||||
with zipfile.ZipFile(str(item), 'r') as z:
|
||||
if len(z.namelist()) == 1:
|
||||
# zipfile with one item: just read that item
|
||||
blinfo = parse_blinfo(z.read(z.namelist()[0]))
|
||||
else:
|
||||
# zipfile with multiple items: try all __init__.py files
|
||||
for fname in z.namelist():
|
||||
# TODO: zips with multiple bl_infos might be a problem,
|
||||
# not sure how such cases should be handled (if at all)
|
||||
# for now we just break after the first one
|
||||
if fname.endswith('__init__.py'):
|
||||
try:
|
||||
blinfo = parse_blinfo(z.read(fname))
|
||||
break
|
||||
except BadAddon:
|
||||
continue
|
||||
if blinfo is None:
|
||||
raise BadAddon("Zipfile '%s' doesn't contain a readable bl_info dict" % item)
|
||||
except zipfile.BadZipFile as e:
|
||||
raise BadAddon("Bad zipfile '%s'" % item) from e
|
||||
|
||||
return blinfo_from_zip(item)
|
||||
elif ext == '.py':
|
||||
with item.open() as f:
|
||||
blinfo = parse_blinfo(f.read())
|
||||
|
||||
return blinfo_from_py(item)
|
||||
else:
|
||||
raise BadAddon("File '%s' doesn't have a .zip or .py extension; not an addon" % item)
|
||||
|
||||
# This should not happen
|
||||
if blinfo is None:
|
||||
raise RuntimeError("Could not read addon '%s'" % item.name)
|
||||
|
||||
return blinfo
|
||||
|
||||
raise RuntimeError("Could not read addon '%s'" % item.name)
|
||||
|
||||
class Package:
|
||||
def __init__(self, path: Path, bl_info: dict, baseurl=None):
|
||||
"""
|
||||
Stores package path and metadata
|
||||
"""
|
||||
|
||||
def __init__(self, path: Path, bl_info: dict):
|
||||
self.bl_info = bl_info
|
||||
self.path = path
|
||||
self.url = None
|
||||
|
||||
def dict(self) -> dict:
|
||||
def to_dict(self) -> dict:
|
||||
"""
|
||||
Return a dict representation of the package
|
||||
"""
|
||||
return {
|
||||
'bl_info': self.bl_info,
|
||||
'url': self.url,
|
||||
}
|
||||
|
||||
class Repository:
|
||||
"""
|
||||
Stores repository metadata (including a list of packages)
|
||||
"""
|
||||
|
||||
def __init__(self, name: str):
|
||||
self.name = name
|
||||
self.url = None
|
||||
self.packages = []
|
||||
|
||||
def add_package(self, pkg: Package):
|
||||
"""
|
||||
Add a package to the repository
|
||||
"""
|
||||
# if pkg.url is None:
|
||||
# pkg.url =
|
||||
self.packages.append(pkg)
|
||||
|
||||
def dict(self) -> dict:
|
||||
def to_dict(self) -> dict:
|
||||
"""
|
||||
Return a dict representation of the repository
|
||||
"""
|
||||
return {
|
||||
'name': self.name,
|
||||
'packages': [p.dict() for p in self.packages],
|
||||
'packages': [p.to_dict() for p in self.packages],
|
||||
'url': self.url,
|
||||
}
|
||||
|
||||
def dump(self, path: Path):
|
||||
"""
|
||||
Dump repository as a repo.json file in 'path'
|
||||
"""
|
||||
with (path / 'repo.json').open('w', encoding='utf-8') as repo_file:
|
||||
json.dump(self.dict(), repo_file, indent=4, sort_keys=True)
|
||||
json.dump(self.to_dict(), repo_file, indent=4, sort_keys=True)
|
||||
log.info("repo.json written to %s" % path)
|
||||
|
||||
|
||||
def json(self) -> str:
|
||||
return json.dumps(self.__dict__)
|
||||
|
||||
|
||||
def make_repo(path: Path, name: str) -> Repository:
|
||||
"""Make repo.json for files in directory 'path'"""
|
||||
|
||||
@@ -188,12 +205,15 @@ def main():
|
||||
help="Path to addon directory")
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.name is None:
|
||||
args.name = args.path.name
|
||||
|
||||
logging.basicConfig(format='%(levelname)8s: %(message)s', level=logging.INFO)
|
||||
log.level += args.verbose
|
||||
|
||||
if args.name is None:
|
||||
args.name = args.path.name
|
||||
|
||||
log.debug("Repository name: '%s'" % args.name)
|
||||
|
||||
repo = make_repo(args.path, args.name)
|
||||
repo.dump(args.output)
|
||||
|
||||
|
Reference in New Issue
Block a user