From 2735d5a0d12c632d0d6dd09151d81edc377cd6fe Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Thu, 15 Dec 2022 16:23:11 +0100 Subject: [PATCH] commandline: Add methods for parsing repo, arch from the arguments --- osc/commandline.py | 82 ++++++++++++++++++++++++++++++++++++ tests/test_commandline.py | 89 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) diff --git a/osc/commandline.py b/osc/commandline.py index 360d5091..322bf25a 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -129,6 +129,88 @@ def pop_project_package_from_args(args, default_project=None, default_package=No return project, package +def pop_repository_arch_from_args(args): + """ + Get repository and arch from given `args`. + + :param args: List of command-line arguments. + WARNING: `args` gets modified in this function call! + :type args: list(str) + :returns: Repository name and arch name. + :rtype: tuple(str) + """ + assert isinstance(args, list) + + try: + repository = args.pop(0) + except IndexError: + raise oscerr.OscValueError("Please specify a repository") + + if not isinstance(repository, str): + raise TypeError(f"Repository should be 'str', found: {type(repository).__name__}") + + arch = None + + if "/" in repository: + # repository/arch + if repository.count("/") != 1: + raise oscerr.OscValueError(f"Argument doesn't match the '/' pattern: {repository}") + repository, arch = repository.split("/") + + if arch is None: + try: + arch = args.pop(0) + except IndexError: + raise oscerr.OscValueError("Please specify an arch") + + if not isinstance(arch, str): + raise TypeError(f"Arch should be 'str', found: {type(arch).__name__}") + + return repository, arch + + +def pop_project_package_repository_arch_from_args(args): + """ + Get project, package, repository and arch from given `args`. + + :param args: List of command-line arguments. + WARNING: `args` gets modified in this function call! + :type args: list(str) + :returns: Project name, package name, repository name and arch name. + :rtype: tuple(str) + """ + + args_backup = args.copy() + + try_working_copy = True + try: + # try this sequence first: project package repository arch + project, package = pop_project_package_from_args(args, package_is_optional=False) + if args: + # we got more than 2 arguments -> we shouldn't try to retrieve project and package from a working copy + try_working_copy = False + repository, arch = pop_repository_arch_from_args(args) + except oscerr.OscValueError as ex: + if not try_working_copy: + raise ex from None + + # then read project and package from working copy and try repository arch + args[:] = args_backup.copy() + project, package = pop_project_package_from_args( + [], default_project=".", default_package=".", package_is_optional=False + ) + repository, arch = pop_repository_arch_from_args(args) + + return project, package, repository, arch + + +def ensure_no_remaining_args(args): + if not args: + return + args_str = " ".join(args) + raise oscerr.WrongArgs(f"Unexpected args: {args_str}") + + class Osc(cmdln.Cmdln): """ openSUSE commander is a command-line interface to the Open Build Service. diff --git a/tests/test_commandline.py b/tests/test_commandline.py index fc65b2f7..26021ccc 100644 --- a/tests/test_commandline.py +++ b/tests/test_commandline.py @@ -4,6 +4,8 @@ import tempfile import unittest from osc.commandline import pop_project_package_from_args +from osc.commandline import pop_project_package_repository_arch_from_args +from osc.commandline import pop_repository_arch_from_args from osc.oscerr import NoWorkingCopy, OscValueError from osc.store import Store @@ -140,5 +142,92 @@ class TestPopProjectPackageFromArgs(unittest.TestCase): self.assertEqual(args, []) +class TestPopRepositoryArchFromArgs(unittest.TestCase): + def test_individial_args(self): + args = ["repo", "arch", "another-arg"] + repo, arch = pop_repository_arch_from_args(args) + self.assertEqual(repo, "repo") + self.assertEqual(arch, "arch") + self.assertEqual(args, ["another-arg"]) + + def test_slash_separator(self): + args = ["repo/arch", "another-arg"] + repo, arch = pop_repository_arch_from_args(args) + self.assertEqual(repo, "repo") + self.assertEqual(arch, "arch") + self.assertEqual(args, ["another-arg"]) + + def test_missing_repository(self): + args = [] + self.assertRaises(OscValueError, pop_repository_arch_from_args, args) + + def test_missing_arch(self): + args = ["repo"] + self.assertRaises(OscValueError, pop_repository_arch_from_args, args) + + +class TestPopProjectPackageRepositoryArchFromArgs(unittest.TestCase): + def _write_store(self, project=None, package=None): + store = Store(self.tmpdir, check=False) + if project: + store.project = project + store.is_project = True + if package: + store.package = package + store.is_project = False + store.is_package = True + + def setUp(self): + self.tmpdir = tempfile.mkdtemp(prefix="osc_test") + os.chdir(self.tmpdir) + + def tearDown(self): + try: + shutil.rmtree(self.tmpdir) + except OSError: + pass + + def test_individual_args(self): + args = ["project", "package", "repo", "arch", "another-arg"] + project, package, repo, arch = pop_project_package_repository_arch_from_args(args) + self.assertEqual(project, "project") + self.assertEqual(package, "package") + self.assertEqual(repo, "repo") + self.assertEqual(arch, "arch") + self.assertEqual(args, ["another-arg"]) + + def test_slash_separator(self): + args = ["project/package", "repo/arch", "another-arg"] + project, package, repo, arch = pop_project_package_repository_arch_from_args(args) + self.assertEqual(project, "project") + self.assertEqual(package, "package") + self.assertEqual(repo, "repo") + self.assertEqual(arch, "arch") + self.assertEqual(args, ["another-arg"]) + + def test_missing_arch(self): + args = ["project", "package", "repo"] + self.assertRaises(OscValueError, pop_project_package_repository_arch_from_args, args) + + def test_no_working_copy(self): + args = ["repo", "arch"] + self.assertRaises(NoWorkingCopy, pop_project_package_repository_arch_from_args, args) + + def test_working_copy(self): + self._write_store("store_project", "store_package") + args = ["repo", "arch"] + project, package, repo, arch = pop_project_package_repository_arch_from_args(args) + self.assertEqual(project, "store_project") + self.assertEqual(package, "store_package") + self.assertEqual(repo, "repo") + self.assertEqual(arch, "arch") + + def test_working_copy_extra_arg(self): + self._write_store("store_project", "store_package") + args = ["repo", "arch", "another-arg"] + # example of invalid usage, working copy is not used when there's 3+ args; [project, package, ...] are expected + self.assertRaises(OscValueError, pop_project_package_repository_arch_from_args, args) + + if __name__ == "__main__": unittest.main()