Skip to content

Commit

Permalink
Merge a28005d into 70eb459
Browse files Browse the repository at this point in the history
  • Loading branch information
lubomir committed Sep 23, 2015
2 parents 70eb459 + a28005d commit b368d0b
Show file tree
Hide file tree
Showing 37 changed files with 1,445 additions and 135 deletions.
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ install:
- pip install -r requirements/devel.txt
- sed -i -E '/import (koji|rpm)/d' $(python -vc 'import kobo.rpmlib' 2>&1 | grep 'import kobo.rpmlib' | awk '{print$NF}' | sed 's/pyc$/py/')
script:
- coverage run --source=contrib,pdc --omit='*tests.py,*/migrations/*,pdc/settings*' manage.py test --settings pdc.settings_test
- coverage run --parallel-mode --source=contrib,pdc --omit='*tests.py,*/migrations/*,pdc/settings*' manage.py test --settings pdc.settings_test contrib pdc
- make flake8
- make extra_test
- coverage run --parallel-mode --source=pdc_client client_test_run.py
after_success:
coveralls
- coverage combine
- coveralls
cache:
directories:
- $HOME/.cache/pip
Expand Down
12 changes: 9 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,23 @@ flake8:
run:
python manage.py runserver 0.0.0.0:8000

all_tests: test api_doc_test client_test

test:
python manage.py test --settings pdc.settings_test
python manage.py test --settings pdc.settings_test pdc contrib

cover_test:
coverage run --parallel-mode manage.py test --settings pdc.settings_test
coverage run --parallel-mode manage.py test --settings pdc.settings_test pdc contrib
coverage run --parallel-mode client_test_run.py
coverage combine
coverage html --rcfile=tox.ini

extra_test:
api_doc_test:
python manage.py test --settings pdc.settings_test tests.check_api_doc

client_test:
python client_test_run.py

models_svg: export DJANGO_SETTINGS_MODULE=pdc.settings_graph_models
models_svg:
python manage.py graph_models -aE -o docs/source/models_svg/all.svg
Expand Down
27 changes: 27 additions & 0 deletions client_test_run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2015 Red Hat
# Licensed under The MIT License (MIT)
# http://opensource.org/licenses/MIT
#
import unittest
import argparse

"""
Use this script either without arguments to run all tests:
python client_test_run.py
or with specific module/test to run only part of the test suite:
python client_test_run.py pdc_client.tests.release.tests.ReleaseTestCase.test_list_all
"""

if __name__ == '__main__':
parser = argparse.ArgumentParser('client_test_run.py')
parser.add_argument('tests', metavar='TEST', nargs='*')
options = parser.parse_args()
loader = unittest.TestLoader()
if options.tests:
suite = loader.loadTestsFromNames(options.tests)
else:
suite = loader.discover('pdc_client/tests', top_level_dir='.')
unittest.TextTestRunner().run(suite)
101 changes: 101 additions & 0 deletions create-plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2015 Red Hat
# Licensed under The MIT License (MIT)
# http://opensource.org/licenses/MIT
#


import argparse
import errno
import logging
import os


PLUGIN_TEMPLATE = '''
# -*- coding: utf-8 -*-
#
# Copyright (c) 2015 Red Hat
# Licensed under The MIT License (MIT)
# http://opensource.org/licenses/MIT
#
import json
from pdc_client import plugin_helpers
class {class_name}(plugin_helpers.PDCClientPlugin):
def register(self):
pass
PLUGIN_CLASSES = [{class_name}]
'''


TEST_TEMPLATE = '''
# -*- coding: utf-8 -*-
#
# Copyright (c) 2015 Red Hat
# Licensed under The MIT License (MIT)
# http://opensource.org/licenses/MIT
#
from pdc_client.test_helpers import CLITestCase
from pdc_client.runner import Runner
class {name}TestCase(CLITestCase):
def setUp(self):
self.runner = Runner()
self.runner.setup()
'''


def write_file(name, contents):
try:
with open(name, 'wx') as f:
f.write(contents)
except IOError as err:
if err.errno == errno.EEXIST:
logging.warning('Not overwriting %s', name)
else:
logging.error('Unhandled exception', exc_info=err)
else:
logging.info('Created %s (%d bytes)', name, len(contents))


def create_plugin(name):
filepath = os.path.join('pdc_client', 'plugins', name + '.py')
class_name = '{}Plugin'.format(name.capitalize())
data = PLUGIN_TEMPLATE.format(class_name=class_name).lstrip()
write_file(filepath, data)


def create_tests(name):
path = os.path.join('pdc_client', 'tests', name)
try:
os.makedirs(os.path.join(path, 'data'))
logging.info('Created %s/', os.path.join(path, 'data'))
except os.error:
pass
write_file(os.path.join(path, '__init__.py'), '')
data = TEST_TEMPLATE.format(name=name.capitalize()).lstrip()
write_file(os.path.join(path, 'tests.py'), data)


def main():
parser = argparse.ArgumentParser('create-plugin.py')
parser.add_argument('name', metavar='NAME')
parser.add_argument('--skip-tests', action='store_true')
parser.add_argument('--verbose', action='store_true')
options = parser.parse_args()
logging.basicConfig(level=logging.INFO if options.verbose else logging.WARNING,
format='%(levelname)s: %(message)s')
name = options.name
create_plugin(name)
if not options.skip_tests:
create_tests(name)


if __name__ == '__main__':
main()
117 changes: 1 addition & 116 deletions pdc_client/bin/pdc
Original file line number Diff line number Diff line change
Expand Up @@ -7,124 +7,9 @@
#

import sys
import argparse
import beanbag
import os
import os.path
import logging
import imp

# The client supports Bash completion if argcomplete Python package is
# installed. To enable it, run this in your terminal (assuming pdc is somewhere
# on path).
#
# eval "$(register-python-argcomplete pdc)"
#
# This is only a temporary solution, when the client is packaged, a completion
# file should be shipped with it and installed to /etc/bash_completion.d/.
try:
import argcomplete
except ImportError:
class argcomplete(object):
def autocomplete(*args):
pass

import pdc_client


# A list of paths to directories where plugins should be loaded from.
# The purpose of the plugins is to extend the default behaviour.
PLUGIN_DIRS = [
os.path.join(os.path.dirname(__file__), '..', 'plugins')
]


class Runner(object):
def __init__(self):
self.raw_plugins = []
self.plugins = []
self.logger = logging.getLogger('pdc')

def load_plugins(self):
for dir in PLUGIN_DIRS:
self.logger.debug('Loading plugins from {}'.format(dir))
for name in os.listdir(dir):
if not name.endswith('.py'):
continue
file, pathname, description = imp.find_module(name[:-3], [dir])
plugin = imp.load_module(name[:-3], file, pathname, description)
self.logger.debug('Loaded plugin {}'.format(name[:-3]))
self.raw_plugins.append(plugin)
if hasattr(plugin, 'PLUGIN_CLASSES'):
for p in plugin.PLUGIN_CLASSES:
self.logger.debug('Instantiating {}'.format(p.__name__))
self.plugins.append(p(self))

def run_hook(self, hook, *args, **kwargs):
"""
Loop over all plugins and invoke function `hook` with `args` and
`kwargs` in each of them. If the plugin does not have the function, it
is skipped.
"""
for plugin in self.raw_plugins:
if hasattr(plugin, hook):
self.logger.debug('Calling hook {} in plugin {}'.format(hook, plugin.__name__))
getattr(plugin, hook)(*args, **kwargs)

def setup(self):
self.load_plugins()

self.parser = argparse.ArgumentParser(description='PDC Client')
self.parser.add_argument('--help-all', action='help',
help='show help including all commands')
self.parser.add_argument('-s', '--server', default='stage',
help='API URL or shortcut from config file')
self.parser.add_argument('--debug', action='store_true', help=argparse.SUPPRESS)
self.parser.add_argument('--json', action='store_true',
help='display output as JSON')

subparsers = self.parser.add_subparsers(metavar='COMMAND')

for plugin in self.plugins:
plugin._before_register(subparsers)
plugin.register()

argcomplete.autocomplete(self.parser)

def run(self):
self.args = self.parser.parse_args()
self.client = pdc_client.PDCClient(self.args.server)
try:
self.args.func(self.args)
except beanbag.BeanBagException as exc:
self.print_error_header(exc)
try:
self.print_error_details(exc.response.json())
except ValueError:
pass
sys.exit(1)

def print_error_header(self, exc):
if exc.response.status_code > 500:
print 'Internal server error. Please consider reporting a bug.'
else:
headers = {
400: 'bad request data',
401: 'unauthorized',
404: 'not found',
409: 'conflict',
}
print 'Client error: {}.'.format(headers.get(exc.response.status_code, 'unknown'))

def print_error_details(self, body):
self.logger.debug(body)
for key, value in body.iteritems():
if isinstance(value, basestring):
print '{}: {}'.format(key, value)
else:
print '{}:'.format(key)
for error in value:
print ' * {}'.format(error)
from pdc_client.runner import Runner


if __name__ == '__main__':
Expand Down
File renamed without changes.
Empty file added pdc_client/plugins/__init__.py
Empty file.
9 changes: 5 additions & 4 deletions pdc_client/plugins/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import sys
from datetime import datetime

from pdc_client.plugins import PDCClientPlugin, get_paged, add_parser_arguments, extract_arguments
from pdc_client.plugin_helpers import PDCClientPlugin, get_paged, add_parser_arguments, extract_arguments


info_desc = """Generally there may be duplicate file names. If the file name
Expand Down Expand Up @@ -77,7 +77,7 @@ def image_info(self, args):
print 'Not found'
sys.exit(1)
elif image['count'] > 1:
print 'More that one image with that name, use --sha256 to specify.'
print 'More than one image with that name, use --sha256 to specify.'
self._print_image_list(image['results'], True)
sys.exit(1)
else:
Expand All @@ -86,18 +86,19 @@ def image_info(self, args):
print json.dumps(image)
return

mtime = datetime.fromtimestamp(image['mtime'])
mtime = datetime.utcfromtimestamp(image['mtime'])

fmt = '{:15} {}'
print fmt.format('File Name', image['file_name'])
print fmt.format('Image Type', image['image_type'])
print fmt.format('Image Format', image['image_format'])
print fmt.format('Arch', image['arch'])
print fmt.format('Disk', '{} / {}'.format(image['disc_number'], image['disc_count']))
print fmt.format('Disc', '{} / {}'.format(image['disc_number'], image['disc_count']))
print fmt.format('Modified', '{} ({})'.format(image['mtime'], mtime))
print fmt.format('Size', '{} ({})'.format(image['size'], size_format(image['size'])))
print fmt.format('Bootable', 'yes' if image['bootable'] else 'no')
print fmt.format('Volume ID', image['volume_id'])
print fmt.format('Implant MD5', image['implant_md5'])

print '\nChecksums:'
print ' {:7} {}'.format('MD5', image['md5'])
Expand Down
2 changes: 1 addition & 1 deletion pdc_client/plugins/permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#
import json

from pdc_client.plugins import PDCClientPlugin
from pdc_client.plugin_helpers import PDCClientPlugin


class PermissionPlugin(PDCClientPlugin):
Expand Down
2 changes: 1 addition & 1 deletion pdc_client/plugins/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#
import json

from pdc_client.plugins import PDCClientPlugin, get_paged, add_parser_arguments, extract_arguments
from pdc_client.plugin_helpers import PDCClientPlugin, get_paged, add_parser_arguments, extract_arguments


class ReleasePlugin(PDCClientPlugin):
Expand Down
7 changes: 2 additions & 5 deletions pdc_client/plugins/rpm.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import sys
import json

from pdc_client.plugins import PDCClientPlugin, get_paged, add_parser_arguments, extract_arguments
from pdc_client.plugin_helpers import PDCClientPlugin, get_paged, add_parser_arguments, extract_arguments


class RPMPlugin(PDCClientPlugin):
Expand Down Expand Up @@ -100,10 +100,7 @@ def rpm_info(self, args, rpm_id=None):
print dep

def rpm_create(self, args):
data = {}
for key, value in args.__dict__.iteritems():
if key.startswith('data_') and value is not None:
data[key[5:]] = value if value != '' else None
data = extract_arguments(args)
self.logger.debug('Creating rpm with data %r', data)
response = self.client.rpms._(data)
self.rpm_info(args, response['id'])
Expand Down
Loading

0 comments on commit b368d0b

Please sign in to comment.