Store filelists in generated repositories
This commit is contained in:
74
bpkg-repogen
74
bpkg-repogen
@@ -6,7 +6,6 @@ import zipfile
|
|||||||
import ast
|
import ast
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from utils import *
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -16,15 +15,15 @@ SCHEMA_VERSION = 1
|
|||||||
class BadAddon(Exception):
|
class BadAddon(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def iter_addons(path: Path) -> (Path, dict):
|
def iter_addons(path: Path) -> (Path, dict, list):
|
||||||
"""
|
"""
|
||||||
Generator, yields (path, bl_info) of blender addons in `path`.
|
Generator, yields (path, bl_info, filelist) of blender addons in `path`.
|
||||||
"""
|
"""
|
||||||
for item in path.iterdir():
|
for item in path.iterdir():
|
||||||
try:
|
try:
|
||||||
yield (item, extract_blinfo(item))
|
yield (item, extract_blinfo(item), get_filelist(item))
|
||||||
except BadAddon as err:
|
except BadAddon as err:
|
||||||
log.debug("Skipping '{}': {}".format(item.name, err))
|
log.info("Skipping '{}': {}".format(item.name, err))
|
||||||
|
|
||||||
def parse_blinfo(source: str) -> dict:
|
def parse_blinfo(source: str) -> dict:
|
||||||
"""Parse a python file and return its bl_info dict, if there is one (else return None)"""
|
"""Parse a python file and return its bl_info dict, if there is one (else return None)"""
|
||||||
@@ -46,6 +45,41 @@ def parse_blinfo(source: str) -> dict:
|
|||||||
|
|
||||||
raise BadAddon('No bl_info found')
|
raise BadAddon('No bl_info found')
|
||||||
|
|
||||||
|
def filelist_from_zip(zippath: Path) -> list:
|
||||||
|
"""Return list of files in the root of a zipfile"""
|
||||||
|
rootlist = []
|
||||||
|
with zipfile.ZipFile(str(zippath), 'r') as z:
|
||||||
|
for f in z.namelist():
|
||||||
|
# Get all names which have no path separators (root level files)
|
||||||
|
# or have a single path separator at the end (root level directories).
|
||||||
|
if len(f.rstrip('/').split('/')) == 1:
|
||||||
|
rootlist.append(f)
|
||||||
|
|
||||||
|
return rootlist
|
||||||
|
|
||||||
|
def get_filelist(addon_path: Path) -> list:
|
||||||
|
"""
|
||||||
|
Extract filelist from addon at path (can be single file, python package, or zip)
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not addon_path.exists():
|
||||||
|
raise FileNotFoundError("Cannot extract blinfo from '%s'; no such file or directory" % addon_path)
|
||||||
|
|
||||||
|
if addon_path.is_dir():
|
||||||
|
return [str(addon_path)]
|
||||||
|
|
||||||
|
if addon_path.is_file():
|
||||||
|
ext = addon_path.suffix.lower()
|
||||||
|
|
||||||
|
if ext == '.zip':
|
||||||
|
return filelist_from_zip(addon_path)
|
||||||
|
elif ext == '.py':
|
||||||
|
return [str(addon_path)]
|
||||||
|
else:
|
||||||
|
raise BadAddon("File '%s' doesn't have a .zip or .py extension; not an addon" % addon_path)
|
||||||
|
|
||||||
|
# This should not happen
|
||||||
|
raise RuntimeError("Could not read addon '%s'" % addon_path.name)
|
||||||
|
|
||||||
def blinfo_from_zip(item: Path) -> dict:
|
def blinfo_from_zip(item: Path) -> dict:
|
||||||
try:
|
try:
|
||||||
@@ -115,7 +149,8 @@ class Package:
|
|||||||
def __init__(self, path: Path, bl_info: dict):
|
def __init__(self, path: Path, bl_info: dict):
|
||||||
self.bl_info = bl_info
|
self.bl_info = bl_info
|
||||||
self.path = path
|
self.path = path
|
||||||
self.url = None
|
self.url = ""
|
||||||
|
self.files = []
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
"""
|
"""
|
||||||
@@ -124,8 +159,14 @@ class Package:
|
|||||||
return {
|
return {
|
||||||
'bl_info': self.bl_info,
|
'bl_info': self.bl_info,
|
||||||
'url': self.url,
|
'url': self.url,
|
||||||
|
'files': self.files,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# def raise_for_missing(self):
|
||||||
|
# """Ensure all fields are set"""
|
||||||
|
# if len(self.files) == 0:
|
||||||
|
# log.warning("Filelist for %s is empty", self.bl_info['name'])
|
||||||
|
|
||||||
class Repository:
|
class Repository:
|
||||||
"""
|
"""
|
||||||
Stores repository metadata (including a list of packages)
|
Stores repository metadata (including a list of packages)
|
||||||
@@ -171,17 +212,28 @@ def make_repo(path: Path, name: str, baseurl: str) -> Repository:
|
|||||||
if not path.is_dir():
|
if not path.is_dir():
|
||||||
raise FileNotFoundError(path)
|
raise FileNotFoundError(path)
|
||||||
|
|
||||||
for addon, bl_info in iter_addons(path):
|
for addon_path, bl_info, filelist in iter_addons(path):
|
||||||
|
|
||||||
# Check if we have all bl_info fields we want
|
# Check if we have all bl_info fields we want
|
||||||
if not REQUIRED_KEYS.issubset(set(bl_info)):
|
if not REQUIRED_KEYS.issubset(set(bl_info)):
|
||||||
log.warning(
|
log.warning(
|
||||||
"Required key(s) '{}' not found in bl_info of '{}'".format(
|
"Skipping '{}': Required key(s) '{}' not found in bl_info".format(
|
||||||
"', '".join(REQUIRED_KEYS.difference(set(bl_info))), addon)
|
addon_path,
|
||||||
|
"', '".join(REQUIRED_KEYS.difference(set(bl_info)))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
package = Package(addon, bl_info)
|
if addon_path.is_dir():
|
||||||
|
log.warning(
|
||||||
|
"Skipping '{}': Addon not zipped".format(addon_path)
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
package = Package(addon_path, bl_info)
|
||||||
package.url = baseurl + package.path.name
|
package.url = baseurl + package.path.name
|
||||||
|
package.files = filelist
|
||||||
|
|
||||||
repo.add_package(package)
|
repo.add_package(package)
|
||||||
|
|
||||||
log.info("Repository generation successful")
|
log.info("Repository generation successful")
|
||||||
@@ -210,7 +262,7 @@ def main():
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
logging.basicConfig(format='%(levelname)8s: %(message)s', level=logging.INFO)
|
logging.basicConfig(format='%(levelname)8s: %(message)s', level=logging.WARNING)
|
||||||
log.level += args.verbose
|
log.level += args.verbose
|
||||||
|
|
||||||
if args.name is None:
|
if args.name is None:
|
||||||
|
Reference in New Issue
Block a user