composer-cli: Add a get_arg function

This is in preperation for adding more optional arguments. Adds a
generic get_arg function, tests for it, and converts get_size to use it.
This commit is contained in:
Brian C. Lane 2020-07-22 12:02:15 -07:00
parent f1c15c67e0
commit 4a4128af23
5 changed files with 72 additions and 21 deletions

View File

@ -24,7 +24,7 @@ import toml
from composer import http_client as client from composer import http_client as client
from composer.cli.help import compose_help from composer.cli.help import compose_help
from composer.cli.utilities import argify, handle_api_result, packageNEVRA from composer.cli.utilities import argify, handle_api_result, packageNEVRA, get_arg
def compose_cmd(opts): def compose_cmd(opts):
"""Process compose commands """Process compose commands
@ -74,8 +74,8 @@ def compose_cmd(opts):
def get_size(args): def get_size(args):
"""Return optional size argument, and remaining args """Return optional size argument, and remaining args
:param api: Details about the API server, "version" and "backend" :param args: list of arguments
:type api: dict :type args: list of strings
:returns: (args, size) :returns: (args, size)
:rtype: tuple :rtype: tuple
@ -86,20 +86,10 @@ def get_size(args):
- multiply by 1024**2 to make it easier on users to specify large sizes - multiply by 1024**2 to make it easier on users to specify large sizes
""" """
if len(args) == 0: args, value = get_arg(args, "--size", int)
return (args, 0) value = value * 1024**2 if value is not None else 0
return (args, value)
if args[0] != "--size" and "--size" in args[1:]:
raise RuntimeError("--size must be first argument after the command")
if args[0] != "--size":
return (args, 0)
if len(args) < 2:
raise RuntimeError("--size is missing the value, in MiB")
# Let this raise an error for non-digit input
size = int(args[1])
return (args[2:], size * 1024**2)
def compose_list(socket_path, api_version, args, show_json=False, testmode=0, api=None): def compose_list(socket_path, api_version, args, show_json=False, testmode=0, api=None):
"""Return a simple list of compose identifiers""" """Return a simple list of compose identifiers"""

View File

@ -20,9 +20,9 @@ compose start [--size XXXX] <BLUEPRINT> <TYPE> [<IMAGE-NAME> <PROVIDER> <PROFILE
Start a compose using the selected blueprint and output type. Optionally start an upload. Start a compose using the selected blueprint and output type. Optionally start an upload.
--size is supported by osbuild-composer, and is in MiB. --size is supported by osbuild-composer, and is in MiB.
compose start-ostree [--size XXXX] <BLUEPRINT> <TYPE> <REF> <PARENT> [<IMAGE-NAME> <PROVIDER> <PROFILE> | <IMAGE-NAME> <PROFILE.TOML>] compose start-ostree [--size XXXX] [--parent PARENT] [--ref REF] <BLUEPRINT> <TYPE> [<IMAGE-NAME> <PROFILE.TOML>]
Start an ostree compose using the selected blueprint and output type. Optionally start an upload. This command Start an ostree compose using the selected blueprint and output type. Optionally start an upload. This command
is only supported by osbuild-composer, and requires the ostree REF and PARENT. --size is in MiB. is only supported by osbuild-composer. --size is in MiB.
compose types compose types
List the supported output types. List the supported output types.

View File

@ -93,3 +93,31 @@ def packageNEVRA(pkg):
return "%s-%s:%s-%s.%s" % (pkg["name"], pkg["epoch"], pkg["version"], pkg["release"], pkg["arch"]) return "%s-%s:%s-%s.%s" % (pkg["name"], pkg["epoch"], pkg["version"], pkg["release"], pkg["arch"])
else: else:
return "%s-%s-%s.%s" % (pkg["name"], pkg["version"], pkg["release"], pkg["arch"]) return "%s-%s-%s.%s" % (pkg["name"], pkg["version"], pkg["release"], pkg["arch"])
def get_arg(args, name, argtype=None):
"""Return optional value from args, and remaining args
:param args: list of arguments
:type args: list of strings
:param name: The argument to remove from the args list
:type name: string
:param argtype: Type to use for checking the argument value
:type argtype: type
:returns (args, value)
:rtype: tuple
This removes the optional argument and value from the argument list, returns the new list,
and the value of the argument.
"""
try:
idx = args.index(name)
if len(args) < idx+2:
raise RuntimeError(f"{name} is missing the value")
value = args[idx+1]
except ValueError:
return (args, None)
if argtype:
value = argtype(value)
return (args[:idx]+args[idx+2:], value)

View File

@ -378,8 +378,7 @@ class SizeTest(unittest.TestCase):
(["blueprint", "type", "imagename", "profile"], 0)) (["blueprint", "type", "imagename", "profile"], 0))
def test_size_later(self): def test_size_later(self):
with self.assertRaises(RuntimeError): self.assertEqual(get_size(["start", "--size", "100", "type"]), (["start", "type"], 104857600))
get_size(["blueprint", "--size", "100", "type"])
def test_size_no_value(self): def test_size_no_value(self):
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):

View File

@ -18,7 +18,7 @@ import unittest
from pylorax.api.errors import INVALID_CHARS from pylorax.api.errors import INVALID_CHARS
from composer.cli.utilities import argify, toml_filename, frozen_toml_filename, packageNEVRA from composer.cli.utilities import argify, toml_filename, frozen_toml_filename, packageNEVRA
from composer.cli.utilities import handle_api_result from composer.cli.utilities import handle_api_result, get_arg
class CliUtilitiesTest(unittest.TestCase): class CliUtilitiesTest(unittest.TestCase):
def test_argify(self): def test_argify(self):
@ -94,3 +94,37 @@ class CliUtilitiesTest(unittest.TestCase):
"""Test a result with show_json=True, errors=[], and no status field""" """Test a result with show_json=True, errors=[], and no status field"""
result = {"foo": "bar", "errors": []} result = {"foo": "bar", "errors": []}
self.assertEqual(handle_api_result(result, show_json=True), (0, True)) self.assertEqual(handle_api_result(result, show_json=True), (0, True))
def test_get_arg_empty(self):
"""Test get_arg with no arguments"""
self.assertEqual(get_arg([], "--size"), ([], None))
def test_get_arg_no_arg(self):
"""Test get_arg with no argument in the list"""
self.assertEqual(get_arg(["first", "second"], "--size"), (["first", "second"], None))
def test_get_arg_notype(self):
"""Test get_arg with no argtype set"""
self.assertEqual(get_arg(["first", "--size", "100", "second"], "--size"), (["first", "second"], "100"))
def test_get_arg_string(self):
"""Test get_arg with a string argument"""
self.assertEqual(get_arg(["first", "--size", "100", "second"], "--size", str), (["first", "second"], "100"))
def test_get_arg_int(self):
"""Test get_arg with an int argument"""
self.assertEqual(get_arg(["first", "--size", "100", "second"], "--size", int), (["first", "second"], 100))
def test_get_arg_short(self):
"""Test get_arg error handling with a short list"""
with self.assertRaises(RuntimeError):
get_arg(["first", "--size", ], "--size", int)
def test_get_arg_start(self):
"""Test get_arg with the argument at the start of the list"""
self.assertEqual(get_arg(["--size", "100", "first", "second"], "--size", int), (["first", "second"], 100))
def test_get_arg_wrong_type(self):
"""Test get_arg with the wrong type"""
with self.assertRaises(ValueError):
get_arg(["first", "--size", "abc", "second"], "--size", int)