diff --git a/src/ahriman/application/ahriman.py b/src/ahriman/application/ahriman.py index df010057..280334ad 100644 --- a/src/ahriman/application/ahriman.py +++ b/src/ahriman/application/ahriman.py @@ -68,7 +68,7 @@ def sync(args: argparse.Namespace) -> None: def update(args: argparse.Namespace) -> None: app = _get_app(args) log_fn = lambda line: print(line) if args.dry_run else app.logger.info(line) - packages = app.get_updates(args.no_aur, args.no_manual, log_fn) + packages = app.get_updates(args.no_aur, args.no_manual, args.no_vcs, log_fn) if args.dry_run: return app.update(packages) @@ -88,7 +88,7 @@ if __name__ == '__main__': add_parser.set_defaults(fn=add) check_parser = subparsers.add_parser('check', description='check for updates') - check_parser.set_defaults(fn=update, no_aur=False, no_manual=True, dry_run=False) + check_parser.set_defaults(fn=update, no_aur=False, no_manual=True, no_vcs=False, dry_run=True) rebuild_parser = subparsers.add_parser('rebuild', description='rebuild whole repository') rebuild_parser.set_defaults(fn=rebuild) @@ -109,6 +109,7 @@ if __name__ == '__main__': update_parser.add_argument('--dry-run', help='just perform check for updates, same as check command', action='store_true') update_parser.add_argument('--no-aur', help='do not check for AUR updates', action='store_true') update_parser.add_argument('--no-manual', help='do not include manual updates', action='store_true') + update_parser.add_argument('--no-vcs', help='do not check VCS packages', action='store_true') update_parser.set_defaults(fn=update) args = parser.parse_args() diff --git a/src/ahriman/application/application.py b/src/ahriman/application/application.py index 668ecbf0..955e005a 100644 --- a/src/ahriman/application/application.py +++ b/src/ahriman/application/application.py @@ -41,12 +41,13 @@ class Application: self.report() self.sync() - def get_updates(self, no_aur: bool, no_manual: bool, log_fn: Callable[[str], None]) -> List[Package]: + def get_updates(self, no_aur: bool, no_manual: bool, no_vcs: bool, + log_fn: Callable[[str], None]) -> List[Package]: updates = [] checked: List[str] = [] if not no_aur: - updates.extend(self.repository.updates_aur(checked)) + updates.extend(self.repository.updates_aur(no_vcs, checked)) if not no_manual: updates.extend(self.repository.updates_manual(checked)) @@ -58,8 +59,7 @@ class Application: def add(self, names: List[str]) -> None: def add_manual(name: str) -> None: package = Package.load(name, self.config.get('aur', 'url')) - task = Task(package, self.architecture, self.config, self.repository.paths) - task.fetch(os.path.join(self.repository.paths.manual, package.name)) + Task.fetch(os.path.join(self.repository.paths.manual, package.name), package.url) def add_archive(src: str) -> None: dst = os.path.join(self.repository.paths.packages, os.path.basename(src)) diff --git a/src/ahriman/core/build_tools/task.py b/src/ahriman/core/build_tools/task.py index ade6bfa7..a5e9ee3f 100644 --- a/src/ahriman/core/build_tools/task.py +++ b/src/ahriman/core/build_tools/task.py @@ -48,6 +48,11 @@ class Task: def git_path(self) -> str: return os.path.join(self.paths.sources, self.package.name) + @staticmethod + def fetch(local: str, remote: str) -> None: + shutil.rmtree(local, ignore_errors=True) # remove in case if file exists + check_output('git', 'clone', remote, local, exception=None) + def build(self) -> List[str]: cmd = [self.build_command, '-r', self.paths.chroot] cmd.extend(self.archbuild_flags) @@ -66,7 +71,6 @@ class Task: exception=BuildFailed(self.package.name), cwd=self.git_path).splitlines() - def fetch(self, path: Optional[str] = None) -> None: + def clone(self, path: Optional[str] = None) -> None: git_path = path or self.git_path - shutil.rmtree(git_path, ignore_errors=True) # remote in case if file exists - check_output('git', 'clone', self.package.url, git_path, exception=None) + return Task.fetch(git_path, self.package.url) diff --git a/src/ahriman/core/repository.py b/src/ahriman/core/repository.py index 740c2567..46f4d7b2 100644 --- a/src/ahriman/core/repository.py +++ b/src/ahriman/core/repository.py @@ -80,7 +80,7 @@ class Repository: def process_build(self, updates: List[Package]) -> List[str]: def build_single(package: Package) -> None: task = Task(package, self.architecture, self.config, self.paths) - task.fetch() + task.clone() built = task.build() for src in built: dst = os.path.join(self.paths.packages, os.path.basename(src)) @@ -140,7 +140,7 @@ class Repository: return self.wrapper.repo_path - def updates_aur(self, checked: List[str]) -> List[Package]: + def updates_aur(self, no_vcs: bool, checked: List[str]) -> List[Package]: result: List[Package] = [] ignore_list = self.config.get_list( self.config.get_section_name('build', self.architecture), 'ignore_packages') @@ -159,6 +159,8 @@ class Repository: continue if local.name in ignore_list: continue + if local.is_vcs and no_vcs: + continue if local.is_outdated(remote): result.append(remote) diff --git a/src/ahriman/models/package.py b/src/ahriman/models/package.py index 50255669..2d59bc66 100644 --- a/src/ahriman/models/package.py +++ b/src/ahriman/models/package.py @@ -19,8 +19,11 @@ # from __future__ import annotations +import shutil + import aur import os +import tempfile from configparser import RawConfigParser from dataclasses import dataclass @@ -36,16 +39,48 @@ class Package: name: str version: str url: str + remote: bool + + @property + def is_vcs(self) -> bool: + return self.name.endswith('-bzr') \ + or self.name.endswith('-csv')\ + or self.name.endswith('-darcs')\ + or self.name.endswith('-git')\ + or self.name.endswith('-hg')\ + or self.name.endswith('-svn') + + # additional method to handle vcs versions + def actual_version(self) -> str: + if not self.is_vcs: + return self.version + + from ahriman.core.build_tools.task import Task + clone_dir = tempfile.mkdtemp() + try: + Task.fetch(clone_dir, self.url) + # update pkgver first + check_output('makepkg', '--nodeps', '--noprepare', '--nobuild', + exception=None, cwd=clone_dir) + # generate new .SRCINFO and put it to parser + src_info_source = check_output('makepkg', '--printsrcinfo', + exception=None, cwd=clone_dir) + src_info, errors = parse_srcinfo(src_info_source) + if errors: + raise InvalidPackageInfo(errors) + return f'{src_info["pkgver"]}-{src_info["pkgrel"]}' + finally: + shutil.rmtree(clone_dir, ignore_errors=True) @classmethod def from_archive(cls: Type[Package], path: str, aur_url: str) -> Package: name, version = check_output('expac', '-p', '%e %v', path, exception=None).split() - return cls(name, version, f'{aur_url}/{name}.git') + return cls(name, version, f'{aur_url}/{name}.git', False) @classmethod def from_aur(cls: Type[Package], name: str, aur_url: str)-> Package: package = aur.info(name) - return cls(package.package_base, package.version, f'{aur_url}/{package.package_base}.git') + return cls(package.package_base, package.version, f'{aur_url}/{package.package_base}.git', True) @classmethod def from_build(cls: Type[Package], path: str) -> Package: @@ -58,7 +93,7 @@ class Package: raise InvalidPackageInfo(errors) return cls(src_info['pkgbase'], f'{src_info["pkgver"]}-{src_info["pkgrel"]}', - git_config.get('remote "origin"', 'url')) + git_config.get('remote "origin"', 'url'), False) @classmethod def load(cls: Type[Package], path: str, aur_url: str) -> Package: @@ -76,5 +111,6 @@ class Package: raise InvalidPackageInfo(str(e)) def is_outdated(self, remote: Package) -> bool: - result = check_output('vercmp', self.version, remote.version, exception=None) + remote_version = remote.actual_version() # either normal version or updated VCS + result = check_output('vercmp', self.version, remote_version, exception=None) return True if int(result) < 0 else False \ No newline at end of file