203 lines
6.1 KiB
Python
203 lines
6.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright 2016 Mirantis, Inc.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
import abc
|
|
|
|
from cliff import command
|
|
import six
|
|
|
|
from packetary.cli.commands.utils import make_display_attr_getter
|
|
from packetary.cli.commands.utils import read_from_file
|
|
|
|
from packetary import api
|
|
|
|
|
|
@six.add_metaclass(abc.ABCMeta)
|
|
class BaseRepoCommand(command.Command):
|
|
"""Super class for packetary commands."""
|
|
|
|
@property
|
|
def stdout(self):
|
|
"""Shortcut for self.app.stdout."""
|
|
return self.app.stdout
|
|
|
|
def get_parser(self, prog_name):
|
|
"""Specifies common options."""
|
|
parser = super(BaseRepoCommand, self).get_parser(prog_name)
|
|
parser.add_argument(
|
|
'-t',
|
|
'--type',
|
|
type=str,
|
|
choices=['deb', 'rpm'],
|
|
metavar='TYPE',
|
|
default='deb',
|
|
help='The type of repository.')
|
|
|
|
parser.add_argument(
|
|
'-a',
|
|
'--arch',
|
|
type=str,
|
|
choices=["x86_64", "i386"],
|
|
metavar='ARCHITECTURE',
|
|
default="x86_64",
|
|
help='The target architecture.')
|
|
|
|
return parser
|
|
|
|
def take_action(self, parsed_args):
|
|
"""See the Command.take_action.
|
|
|
|
:param parsed_args: the command-line arguments
|
|
:return: the result of take_repo_action
|
|
:rtype: object
|
|
"""
|
|
return self.take_repo_action(
|
|
api.RepositoryApi.create(
|
|
self.app_args, parsed_args.type, parsed_args.arch
|
|
),
|
|
parsed_args
|
|
)
|
|
|
|
@abc.abstractmethod
|
|
def take_repo_action(self, repo_api, parsed_args):
|
|
"""Takes action on repository.
|
|
|
|
:param repo_api: the RepositoryApi instance
|
|
:param parsed_args: the command-line arguments
|
|
:return: the action result
|
|
"""
|
|
|
|
|
|
class RepositoriesMixin(object):
|
|
def get_parser(self, prog_name):
|
|
"""Specifies common options."""
|
|
parser = super(RepositoriesMixin, self).get_parser(prog_name)
|
|
parser.add_argument(
|
|
'-r', '--repositories',
|
|
dest='repositories',
|
|
type=read_from_file,
|
|
metavar='FILENAME',
|
|
required=True,
|
|
help="The path to file with list of repositories."
|
|
"See documentation about format."
|
|
)
|
|
return parser
|
|
|
|
|
|
class PackagesMixin(object):
|
|
"""Added arguments to declare list of packages."""
|
|
|
|
def get_parser(self, prog_name):
|
|
parser = super(PackagesMixin, self).get_parser(prog_name)
|
|
parser.add_argument(
|
|
"-R", "--requirements",
|
|
dest='requirements',
|
|
type=read_from_file,
|
|
metavar='FILENAME',
|
|
help="The path to file with list of packages."
|
|
"See documentation about format."
|
|
)
|
|
return parser
|
|
|
|
|
|
class BaseProduceOutputCommand(BaseRepoCommand):
|
|
columns = None
|
|
|
|
def get_parser(self, prog_name):
|
|
parser = super(BaseProduceOutputCommand, self).get_parser(prog_name)
|
|
|
|
group = parser.add_argument_group(
|
|
title='output formatter',
|
|
description='output formatter options',
|
|
)
|
|
group.add_argument(
|
|
'-c', '--column',
|
|
nargs='+',
|
|
choices=self.columns,
|
|
dest='columns',
|
|
metavar='COLUMN',
|
|
default=[],
|
|
help='Space separated list of columns to include.',
|
|
)
|
|
group.add_argument(
|
|
'-s',
|
|
'--sort-columns',
|
|
type=str,
|
|
nargs='+',
|
|
choices=self.columns,
|
|
metavar='SORT_COLUMN',
|
|
default=[self.columns[0]],
|
|
help='Space separated list of keys for sorting '
|
|
'the data.'
|
|
)
|
|
group.add_argument(
|
|
'--sep',
|
|
type=six.text_type,
|
|
metavar='ROW SEPARATOR',
|
|
default=six.text_type('; '),
|
|
help='The row separator.'
|
|
)
|
|
|
|
return parser
|
|
|
|
def produce_output(self, parsed_args, data):
|
|
indexes = dict(
|
|
(c, i) for i, c in enumerate(self.columns)
|
|
)
|
|
sort_index = [indexes[c] for c in parsed_args.sort_columns]
|
|
if isinstance(data, list):
|
|
data.sort(key=lambda x: [x[i] for i in sort_index])
|
|
else:
|
|
data = sorted(data, key=lambda x: [x[i] for i in sort_index])
|
|
|
|
if parsed_args.columns:
|
|
include_index = [
|
|
indexes[c] for c in parsed_args.columns
|
|
]
|
|
data = ((row[i] for i in include_index) for row in data)
|
|
columns = parsed_args.columns
|
|
else:
|
|
columns = self.columns
|
|
|
|
stdout = self.stdout
|
|
sep = parsed_args.sep
|
|
|
|
# header
|
|
stdout.write("# ")
|
|
stdout.write(sep.join(columns))
|
|
stdout.write("\n")
|
|
|
|
for row in data:
|
|
stdout.write(sep.join(row))
|
|
stdout.write("\n")
|
|
|
|
def run(self, parsed_args):
|
|
# Use custom output producer.
|
|
# cliff.lister with default formatters does not work
|
|
# with large arrays of data, because it does not support streaming
|
|
# TODO(implement custom formatter)
|
|
|
|
formatter = make_display_attr_getter(self.columns)
|
|
data = six.moves.map(formatter, self.take_action(parsed_args))
|
|
self.produce_output(parsed_args, data)
|
|
return 0
|
|
|
|
@abc.abstractmethod
|
|
def take_repo_action(self, driver, parsed_args):
|
|
"""See Command.take_repo_action."""
|