def apkinfo(apk): with tempfile.TemporaryDirectory('apk') as tempdir: try: run(["apktool", "d", "-f", "-s", apk, "-o", tempdir]) except CalledProcessError: raise ApktoolFailed with at_dir(tempdir): manifest = ET.parse('AndroidManifest.xml').getroot() package_id = manifest.get('package') package_ver = manifest.get(VER_ATTR) app = manifest.find('application') icon = app.get(ICON_ATTR) name = app.get(NAME_ATTR) if os.path.isdir('res'): with at_dir('res'): name = read_string(name) package_ver = read_string(package_ver) if icon and icon.startswith('@'): dirname, iconname = icon[1:].split('/', 1) iconfile = firstExistentPath( '%s/%s.png' % (d, iconname) for d in (dirname + x for x in ('-xxhdpi', '-xhdpi', '-hdpi', '', '-nodpi', '-xxhdpi-v4', '-xhdpi-v4', '-hdpi-v4', '-v4', '-nodpi-v4'))) with open(iconfile, 'rb') as f: icon = f.read() return ApkInfo(package_id, package_ver, name, icon)
def _update_aur_repo_real(pkgname: str) -> None: aurpath = const.AUR_REPO_DIR / pkgname if not os.path.isdir(aurpath): logger.info('cloning AUR repo: %s', aurpath) with at_dir(const.AUR_REPO_DIR): run_cmd(['git', 'clone', '[email protected]:%s.git' % pkgname]) else: with at_dir(aurpath): git_reset_hard() git_pull() logger.info('copying files to AUR repo: %s', aurpath) files = run_cmd(['git', 'ls-files']).splitlines() for f in files: if f in const.SPECIAL_FILES: continue logger.debug('copying file %s', f) shutil.copy(f, aurpath) with at_dir(aurpath): with open('.SRCINFO', 'wb') as srcinfo: subprocess.run( ['makepkg', '--printsrcinfo'], stdout=srcinfo, check=True, ) run_cmd(['git', 'add', '.']) run_cmd([ 'bash', '-c', 'git diff-index --quiet HEAD || git commit -m "update by lilac"' ]) run_cmd(['git', 'push'])
def _update_aur_repo_real(pkgname): aurpath = os.path.join(AUR_REPO_DIR, pkgname) if not os.path.isdir(aurpath): logger.info('cloning AUR repo: %s', aurpath) with at_dir(AUR_REPO_DIR): run_cmd(['git', 'clone', '[email protected]:%s.git' % pkgname]) else: with at_dir(aurpath): git_reset_hard() git_pull() logger.info('copying files to AUR repo: %s', aurpath) files = run_cmd(['git', 'ls-files']).splitlines() for f in files: if f in SPECIAL_FILES: continue logger.debug('copying file %s', f) shutil.copy(f, aurpath) with at_dir(aurpath): with open('.SRCINFO', 'wb') as srcinfo: subprocess.run( ['makepkg', '--printsrcinfo'], stdout=srcinfo, check=True, ) run_cmd(['git', 'add', '.']) run_cmd(['git', 'commit', '-m', 'update by lilac']) run_cmd(['git', 'push'])
def apkinfo(apk): with tempfile.TemporaryDirectory('apk') as tempdir: try: run(["apktool", "d", "-f", "-s", apk, tempdir]) except CalledProcessError: raise ApktoolFailed with at_dir(tempdir): manifest = ET.parse('AndroidManifest.xml').getroot() package_id = manifest.get('package') package_ver = manifest.get(VER_ATTR) app = manifest.find('application') icon = app.get(ICON_ATTR) name = app.get(NAME_ATTR) if os.path.isdir('res'): with at_dir('res'): name = read_string(name) package_ver = read_string(package_ver) if icon and icon.startswith('@'): dirname, iconname = icon[1:].split('/', 1) iconfile = firstExistentPath( '%s/%s.png' % (d, iconname) for d in (dirname + x for x in ('-xxhdpi', '-xhdpi', '-hdpi', '', '-nodpi')) ) with open(iconfile, 'rb') as f: icon = f.read() return ApkInfo(package_id, package_ver, name, icon)
def _update_aur_repo_real(pkgname: str) -> None: aurpath = const.AUR_REPO_DIR / pkgname if not os.path.isdir(aurpath): logger.info('cloning AUR repo: %s', aurpath) with at_dir(const.AUR_REPO_DIR): run_cmd(['git', 'clone', '[email protected]:%s.git' % pkgname]) else: with at_dir(aurpath): git_reset_hard() git_pull() logger.info('copying files to AUR repo: %s', aurpath) files = run_cmd(['git', 'ls-files']).splitlines() for f in files: if f in const.SPECIAL_FILES: continue logger.debug('copying file %s', f) shutil.copy(f, aurpath) with at_dir(aurpath): with open('.SRCINFO', 'wb') as srcinfo: subprocess.run( ['makepkg', '--printsrcinfo'], stdout = srcinfo, check = True, ) run_cmd(['git', 'add', '.']) run_cmd(['bash', '-c', 'git diff-index --quiet HEAD || git commit -m "update by lilac"']) run_cmd(['git', 'push'])
def _update_aur_repo_real(pkgname: str) -> None: aurpath = const.AUR_REPO_DIR / pkgname if not aurpath.is_dir(): logger.info('cloning AUR repo: %s', aurpath) with at_dir(const.AUR_REPO_DIR): run_cmd(['git', 'clone', f'[email protected]:{pkgname}.git']) else: with at_dir(aurpath): # reset everything, dropping local commits run_cmd(['git', 'reset', '--hard', 'origin/master']) git_pull() with at_dir(aurpath): oldfiles = set(run_cmd(['git', 'ls-files']).splitlines()) newfiles = set() logger.info('copying files to AUR repo: %s', aurpath) files = run_cmd(['git', 'ls-files']).splitlines() for f in files: if f in SPECIAL_FILES: continue logger.debug('copying file %s', f) shutil.copy(f, aurpath) newfiles.add(f) with at_dir(aurpath): for f in oldfiles - newfiles: if f in ['.SRCINFO', '.gitignore']: continue logger.debug('removing file %s', f) try: os.unlink(f) except OSError as e: logger.warning('failed to remove file %s: %s', f, e) if not _allow_update_aur_repo(pkgname, run_cmd(['git', 'diff'])): return with open('.SRCINFO', 'wb') as srcinfo: subprocess.run( ['makepkg', '--printsrcinfo'], stdout=srcinfo, check=True, ) run_cmd(['git', 'add', '.']) p = subprocess.run(['git', 'diff-index', '--quiet', 'HEAD']) if p.returncode != 0: built_version = _format_package_version(_G.epoch, _G.pkgver, _G.pkgrel) msg = f'[lilac] updated to {built_version}' run_cmd(['git', 'commit', '-m', msg]) run_cmd(['git', 'push'])
def test_update_pkgrel(tmpdir, pkgbuild, expected_pkgbuild, kwargs): with at_dir(tmpdir): with open('PKGBUILD', 'w') as f: f.write(pkgbuild) update_pkgrel(**kwargs) with open('PKGBUILD', 'r') as f: new_pkgbuild = f.read() assert new_pkgbuild == expected_pkgbuild
def apkinfo(apk): with tempfile.TemporaryDirectory("apk") as tempdir: try: run(["apktool", "d", "-f", "-s", apk, "-o", tempdir]) except CalledProcessError: raise ApktoolFailed with at_dir(tempdir): manifest = ET.parse("AndroidManifest.xml").getroot() package_id = manifest.get("package") package_ver = manifest.get(VER_ATTR) app = manifest.find("application") icon = app.get(ICON_ATTR) name = app.get(NAME_ATTR) if os.path.isdir("res"): with at_dir("res"): name = read_string(name) package_ver = read_string(package_ver) if icon and icon.startswith("@"): dirname, iconname = icon[1:].split("/", 1) iconfile = firstExistentPath( "%s/%s.png" % (d, iconname) for d in ( dirname + x for x in ( "-xxhdpi", "-xhdpi", "-hdpi", "", "-nodpi", "-xxhdpi-v4", "-xhdpi-v4", "-hdpi-v4", "-v4", "-nodpi-v4", ) ) ) with open(iconfile, "rb") as f: icon = f.read() return ApkInfo(package_id, package_ver, name, icon)
def find_maintainer_or_admin(self, package=None): if package is not None: path = os.path.join(self.repodir, package) else: path = '.' with at_dir(path): try: who = self.find_maintainer() more = '' except: who = self.mymaster more = traceback.format_exc() return who, more
def _find_local_package(self): with at_dir(self.directory): fnames = [x for x in os.listdir() if x.endswith('.pkg.tar.xz')] pkgs = [] for x in fnames: info = archpkg.PkgNameInfo.parseFilename(x) if info.name == self.pkgname: pkgs.append(x) if len(pkgs) == 1: return os.path.abspath(pkgs[0]) elif not pkgs: raise FileNotFoundError else: ret = sorted( pkgs, reverse=True, key=lambda n: os.stat(n).st_mtime)[0] return os.path.abspath(ret)
def load_all(repodir): repodir = pathlib.Path(repodir) mods = {} errors = {} for x in repodir.iterdir(): if not x.is_dir(): continue if x.name[0] == '.': continue with at_dir(x): try: with load_lilac() as mod: mods[x.name] = mod except FileNotFoundError: pass except Exception: errors[x.name] = sys.exc_info() return mods, errors
def load_all(repodir): mods = {} errors = {} for x in repodir.iterdir(): if not x.is_dir(): continue if x.name[0] == '.': continue with at_dir(x): try: with load_lilac() as mod: mods[x.name] = mod if hasattr(mod, 'time_limit_hours') and mod.time_limit_hours < 0: raise ValueError('time_limit_hours should be positive.') except FileNotFoundError: pass except Exception: errors[x.name] = sys.exc_info() return mods, errors
def packages_need_update(repo, U): full = configparser.ConfigParser(dict_type=dict, allow_no_value=True) nvchecker_full = repo.repodir / 'nvchecker.ini' try: full.read([nvchecker_full]) except Exception: tb = traceback.format_exc() try: who = repo.find_maintainer(file='nvchecker.ini') more = '' except Exception: who = repo.mymaster more = traceback.format_exc() subject = 'nvchecker 配置文件错误' msg = '调用栈如下:\n\n' + tb if more: msg += '\n获取维护者信息也失败了!调用栈如下:\n\n' + more repo.sendmail(who, subject, msg) raise all_known = set(full.sections()) unknown = U - all_known if unknown: logger.warn('unknown packages: %r', unknown) if not OLDVER_FILE.exists(): open(OLDVER_FILE, 'a').close() newconfig = {k: full[k] for k in U & all_known} newconfig['__config__'] = { 'oldver': OLDVER_FILE, 'newver': NEWVER_FILE, } new = configparser.ConfigParser(dict_type=dict, allow_no_value=True) new.read_dict(newconfig) with open(NVCHECKER_FILE, 'w') as f: new.write(f) # vcs source needs to be run in the repo, so cwd=... rfd, wfd = os.pipe() cmd = [ 'nvchecker', '--logger', 'both', '--json-log-fd', str(wfd), NVCHECKER_FILE ] process = subprocess.Popen(cmd, cwd=repo.repodir, pass_fds=(wfd, )) os.close(wfd) output = os.fdopen(rfd) nvdata = {} errors = defaultdict(list) for l in output: j = json.loads(l) pkg = j.get('name') event = j['event'] if event == 'updated': nvdata[pkg] = NvResult(j['old_version'], j['version']) elif event == 'up-to-date': nvdata[pkg] = NvResult(j['version'], j['version']) elif j['level'] in ['warn', 'error', 'exception', 'critical']: errors[pkg].append(j) ret = process.wait() if ret != 0: raise subprocess.CalledProcessError(ret, cmd) missing = [] error_owners = defaultdict(list) for pkg, pkgerrs in errors.items(): if pkg is None: continue dir = repo.repodir / pkg if not dir.is_dir(): missing.append(pkg) continue with at_dir(dir): who = repo.find_maintainer() error_owners[who].extend(pkgerrs) for who, errors in error_owners.items(): logger.info('send nvchecker report for %r packages to %s', {x['name'] for x in errors}, who) repo.sendmail(who, '[lilac] nvchecker 错误报告', '\n'.join(_format_error(e) for e in errors)) if unknown or None in errors or missing: subject = 'nvchecker 问题' msg = '' if unknown: msg += '以下软件包没有相应的更新配置信息:\n\n' + ''.join( x + '\n' for x in sorted(unknown)) + '\n' if None in errors: msg += '在更新检查时出现了一些错误:\n\n' + '\n'.join( _format_error(e) for e in errors[None]) + '\n' if missing: msg += '以下软件包没有所对应的目录:\n\n' + \ '\n'.join( missing) + '\n' repo.send_repo_mail(subject, msg) for name in U: if name not in nvdata: # we know nothing about these versions # maybe nvchecker has failed nvdata[name] = NvResult(None, None) return nvdata, unknown