Skip to content

Instantly share code, notes, and snippets.

@ferdnyc
Created August 24, 2018 09:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ferdnyc/ebd44bb5ac7aa45020bcf0b7d6dc6d6f to your computer and use it in GitHub Desktop.
Save ferdnyc/ebd44bb5ac7aa45020bcf0b7d6dc6d6f to your computer and use it in GitHub Desktop.
Comparison (via unified diff) of the fedpkg and rfpkg __init__.py and cli.py source
--- fedpkg/fedpkg/cli.py 2018-08-23 12:21:22.627622258 -0400
+++ rfpkg/src/rfpkg/cli.py 2018-08-23 12:21:38.273925248 -0400
@@ -1,1136 +1,210 @@
-# -*- coding: utf-8 -*-
-# cli.py - a cli client class module for fedpkg
+# cli.py - a cli client class module for rfpkg
#
# Copyright (C) 2011 Red Hat Inc.
# Author(s): Jesse Keating <jkeating@redhat.com>
+# Nicolas Chauvet <kwizart@gmail.com> - 2015
#
# 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. See http://www.gnu.org/copyleft/gpl.html for
# the full text of the license.
-from __future__ import print_function
from pyrpkg.cli import cliClient
-import argparse
-import io
+import sys
import os
+import logging
import re
-import json
-import pkg_resources
-import six
-import shutil
+import subprocess
import textwrap
-import itertools
+import hashlib
-from datetime import datetime
+import pkgdb2client
-from six.moves import configparser
-from six.moves.configparser import NoSectionError
-from six.moves.configparser import NoOptionError
-from six.moves.urllib_parse import urlparse
-from pyrpkg import rpkgError
-from fedpkg.bugzilla import BugzillaClient
-from fedpkg.utils import (
- get_release_branches, sl_list_to_dict, verify_sls, new_pagure_issue,
- get_pagure_token, is_epel, assert_valid_epel_package,
- assert_new_tests_repo, get_dist_git_url, get_stream_branches,
- expand_release)
-RELEASE_BRANCH_REGEX = r'^(f\d+|el\d+|epel\d+)$'
-LOCAL_PACKAGE_CONFIG = 'package.cfg'
-
-BODHI_TEMPLATE = """\
-[ %(nvr)s ]
-
-# bugfix, security, enhancement, newpackage (required)
-type=%(type_)s
-
-# testing, stable
-request=%(request)s
-
-# Bug numbers: 1234,9876
-bugs=%(bugs)s
-
-%(changelog)s
-# Here is where you give an explanation of your update.
-# Content can span multiple lines, as long as they are indented deeper than
-# the first line. For example,
-# notes=first line
-# second line
-# and so on
-notes=%(descr)s
-
-# Enable request automation based on the stable/unstable karma thresholds
-autokarma=%(autokarma)s
-stable_karma=%(stable_karma)s
-unstable_karma=%(unstable_karma)s
-
-# Automatically close bugs when this marked as stable
-close_bugs=%(close_bugs)s
-
-# Suggest that users restart after update
-suggest_reboot=%(suggest_reboot)s
-"""
-
-
-def check_bodhi_version():
- try:
- dist = pkg_resources.get_distribution('bodhi_client')
- except pkg_resources.DistributionNotFound:
- raise rpkgError('bodhi-client < 2.0 is not supported.')
- major = int(dist.version.split('.', 1)[0])
- if major >= 4:
- raise rpkgError(
- 'This system has bodhi v{0}, which is unsupported.'.format(major))
-
-
-class fedpkgClient(cliClient):
+class rfpkgClient(cliClient):
def __init__(self, config, name=None):
- self.DEFAULT_CLI_NAME = 'fedpkg'
- super(fedpkgClient, self).__init__(config, name)
+ self.DEFAULT_CLI_NAME = 'rfpkg'
+ super(rfpkgClient, self).__init__(config, name)
self.setup_fed_subparsers()
- def setup_argparser(self):
- super(fedpkgClient, self).setup_argparser()
-
- # This line is added here so that it shows up with the "--help" option,
- # but it isn't used for anything else
- self.parser.add_argument(
- '--user-config', help='Specify a user config file to use')
- opt_release = self.parser._option_string_actions['--release']
- opt_release.help = 'Override the discovered release, e.g. f25, which has to match ' \
- 'the remote branch name created in package repository. ' \
- 'Particularly, use master to build RPMs for rawhide.'
-
def setup_fed_subparsers(self):
"""Register the fedora specific targets"""
- self.register_releases_info()
self.register_retire()
self.register_update()
- self.register_request_repo()
- self.register_request_tests_repo()
- self.register_request_branch()
- self.register_override()
# Target registry goes here
def register_retire(self):
"""Register the retire target"""
retire_parser = self.subparsers.add_parser(
'retire',
help='Retire a package',
description='This command will remove all files from the repo, '
- 'leave a dead.package file, and push the changes.'
+ 'leave a dead.package file, push the changes and '
+ 'retire the package in pkgdb.'
)
retire_parser.add_argument('reason',
help='Reason for retiring the package')
retire_parser.set_defaults(command=self.retire)
def register_update(self):
- description = '''
-This will create a bodhi update request for the current package n-v-r.
-
-There are two ways to specify update details. Without any argument from command
-line, either update type or notes is omitted, a template editor will be shown
-and let you edit the detail information interactively.
-
-Alternatively, you could specify argument from command line to create an update
-directly, for example:
-
- {0} update --type bugfix --notes 'Rebuilt' --bugs 1000 1002
-
-When all lines in template editor are commented out or deleted, the creation
-process is aborted. If the template keeps unchanged, {0} continues on creating
-update. That gives user a chance to confirm the auto-generated notes from
-change log if option --notes is omitted.
-'''.format(self.name)
-
update_parser = self.subparsers.add_parser(
'update',
- formatter_class=argparse.RawDescriptionHelpFormatter,
help='Submit last build as update',
- description=description,
+ description='This will create a bodhi update request for the '
+ 'current package n-v-r.'
)
-
- def validate_stable_karma(value):
- error = argparse.ArgumentTypeError(
- 'Stable karma must be an integer which is greater than zero.')
- try:
- karma = int(value)
- except ValueError:
- raise error
- if karma <= 0:
- raise error
-
- def validate_unstable_karma(value):
- error = argparse.ArgumentTypeError(
- 'Unstable karma must be an integer which is less than zero.')
- try:
- karma = int(value)
- except ValueError:
- raise error
- if karma >= 0:
- raise error
-
- def validate_bugs(value):
- if not value.isdigit():
- raise argparse.ArgumentTypeError(
- 'Invalid bug {0}. It should be an integer.'.format(value))
-
- update_parser.add_argument(
- '--type',
- choices=['bugfix', 'security', 'enhancement', 'newpackage'],
- dest='update_type',
- help='Update type. Template editor will be shown if type is '
- 'omitted.')
- update_parser.add_argument(
- '--request',
- choices=['testing', 'stable'],
- default='testing',
- help='Requested repository.')
- update_parser.add_argument(
- '--bugs',
- nargs='+',
- type=validate_bugs,
- help='Bug numbers. If omitted, bug numbers will be extracted from'
- ' change logs.')
- update_parser.add_argument(
- '--notes',
- help='Update description. Multiple lines of notes could be '
- 'specified. If omitted, template editor will be shown.')
- update_parser.add_argument(
- '--disable-autokarma',
- action='store_false',
- default=True,
- dest='autokarma',
- help='Karma automatism is enabled by default. Use this option to '
- 'disable that.')
- update_parser.add_argument(
- '--stable-karma',
- type=validate_stable_karma,
- metavar='KARMA',
- default=3,
- help='Stable karma. Default is 3.')
- update_parser.add_argument(
- '--unstable-karma',
- type=validate_unstable_karma,
- metavar='KARMA',
- default=-3,
- help='Unstable karma. Default is -3.')
- update_parser.add_argument(
- '--not-close-bugs',
- action='store_false',
- default=True,
- dest='close_bugs',
- help='By default, update will be created by enabling to close bugs'
- ' automatically. If this is what you do not want, use this '
- 'option to disable the default behavior.')
- update_parser.add_argument(
- '--suggest-reboot',
- action='store_true',
- default=False,
- dest='suggest_reboot',
- help='Suggest user to reboot after update. Default is False.')
update_parser.set_defaults(command=self.update)
- def get_distgit_namespaces(self):
- dg_namespaced = self._get_bool_opt('distgit_namespaced')
- if dg_namespaced and self.config.has_option(
- self.name, 'distgit_namespaces'):
- return self.config.get(self.name, 'distgit_namespaces').split()
- else:
- return None
-
- def register_request_repo(self):
- help_msg = 'Request a new dist-git repository'
- description = '''Request a new dist-git repository
-
-Before requesting a new dist-git repository for a new package, you need to
-generate a pagure.io API token at https://{1}/settings/token/new, select the
-"Create a new ticket" ACL and save it in your local user configuration located
-at ~/.config/rpkg/{0}.conf. For example:
-
- [{0}.pagure]
- token = <api_key_here>
-
-Below is a basic example of the command to request a dist-git repository for
-the package foo:
-
- fedpkg request-repo foo 1234
-
-Another example to request a module foo:
-
- fedpkg request-repo --namespace modules foo
-'''.format(self.name, urlparse(self.config.get(
- '{0}.pagure'.format(self.name), 'url')).netloc)
-
- request_repo_parser = self.subparsers.add_parser(
- 'request-repo',
- formatter_class=argparse.RawDescriptionHelpFormatter,
- help=help_msg,
- description=description)
- request_repo_parser.add_argument(
- 'name',
- help='Repository name to request.')
- request_repo_parser.add_argument(
- 'bug', nargs='?', type=int,
- help='Bugzilla bug ID of the package review request. '
- 'Not required for requesting a module repository')
- request_repo_parser.add_argument(
- '--namespace',
- required=False,
- default='rpms',
- choices=self.get_distgit_namespaces(),
- dest='new_repo_namespace',
- help='Namespace of repository. If omitted, default to rpms.')
- request_repo_parser.add_argument(
- '--description', '-d', help='The repo\'s description in dist-git')
- monitoring_choices = [
- 'no-monitoring', 'monitoring', 'monitoring-with-scratch']
- request_repo_parser.add_argument(
- '--monitor', '-m', help='The Anitya monitoring type for the repo',
- choices=monitoring_choices, default=monitoring_choices[1])
- request_repo_parser.add_argument(
- '--upstreamurl', '-u',
- help='The upstream URL of the project')
- request_repo_parser.add_argument(
- '--summary', '-s',
- help='Override the package\'s summary from the Bugzilla bug')
- request_repo_parser.add_argument(
- '--exception', action='store_true',
- help='The package is an exception to the regular package review '
- 'process (specifically, it does not require a Bugzilla bug)')
- request_repo_parser.add_argument(
- '--no-initial-commit',
- action='store_true',
- help='Do not include an initial commit in the repository.')
- request_repo_parser.set_defaults(command=self.request_repo)
-
- def register_request_tests_repo(self):
- help_msg = 'Request a new tests dist-git repository'
- pagure_url = urlparse(self.config.get(
- '{0}.pagure'.format(self.name), 'url')).netloc
- anongiturl = self.config.get(
- self.name, 'anongiturl', vars={'repo': 'any', 'module': 'any'}
- )
- description = '''Request a new dist-git repository in tests shared namespace
-
- {2}/projects/tests/*
-
-For more information about tests shared namespace see
-
- https://fedoraproject.org/wiki/CI/Share_Test_Code
-
-Please refer to the request-repo command to see what has to be done before
-requesting a repository in the tests namespace.
-
-Below is a basic example of the command to request a dist-git repository for
-the space tests/foo:
-
- fedpkg request-tests-repo foo "Description of the repository"
-
-Note that the space name needs to reflect the intent of the tests and will
-undergo a manual review.
-
-'''.format(self.name, pagure_url, get_dist_git_url(anongiturl))
-
- request_tests_repo_parser = self.subparsers.add_parser(
- 'request-tests-repo',
- formatter_class=argparse.RawDescriptionHelpFormatter,
- help=help_msg,
- description=description)
- request_tests_repo_parser.add_argument(
- 'name',
- help='Repository name to request.')
- request_tests_repo_parser.add_argument(
- 'description',
- help='Description of the tests repository')
- request_tests_repo_parser.set_defaults(command=self.request_tests_repo)
-
- def register_request_branch(self):
- help_msg = 'Request a new dist-git branch'
- description = '''Request a new dist-git branch
-
-Please refer to the request-repo command to see what has to be done before
-requesting a dist-git branch.
-
-Branch name could be one of current active Fedora and EPEL releases. Use
-command ``{0} releases-info`` to get release names that can be used to request
-a branch.
-
-Below are various examples of requesting a dist-git branch.
-
-Request a branch inside a cloned package repository:
-
- {0} request-branch f27
-
-Request a branch outside package repository, which could apply to cases of
-requested repository has not been approved and created, or just not change
-directory to package repository:
-
- {0} request-branch --repo foo f27
-'''.format(self.name)
-
- request_branch_parser = self.subparsers.add_parser(
- 'request-branch',
- formatter_class=argparse.RawDescriptionHelpFormatter,
- help=help_msg,
- description=description)
- request_branch_parser.add_argument(
- 'branch', nargs='?', help='The branch to request.')
- request_branch_parser.add_argument(
- '--repo',
- required=False,
- dest='repo_name_for_branch',
- metavar='NAME',
- help='Repository name the new branch is requested for.'
- )
- request_branch_parser.add_argument(
- '--namespace',
- required=False,
- dest='repo_ns_for_branch',
- choices=self.get_distgit_namespaces(),
- help='Repository name the new branch is requested for.'
- )
- request_branch_parser.add_argument(
- '--sl', nargs='*',
- help=('The service levels (SLs) tied to the branch. This must be '
- 'in the format of "sl_name:2020-12-01". This is only for '
- 'non-release branches. You may provide more than one by '
- 'separating each SL with a space.')
- )
- request_branch_parser.add_argument(
- '--no-git-branch', default=False, action='store_true',
- help='Don\'t create the branch in git but still create it in PDC'
- )
- request_branch_parser.add_argument(
- '--no-auto-module', default=False, action='store_true',
- help='If requesting an rpm arbitrary branch, do not '
- 'also request a new matching module. See '
- 'https://pagure.io/fedrepo_req/issue/129'
- )
- request_branch_parser.add_argument(
- '--all-releases', default=False, action='store_true',
- help='Make a new branch request for every active Fedora release'
- )
- request_branch_parser.set_defaults(command=self.request_branch)
-
- def register_releases_info(self):
- help_msg = 'Print Fedora or EPEL current active releases'
- parser = self.subparsers.add_parser(
- 'releases-info',
- help=help_msg,
- description=help_msg)
-
- group = parser.add_mutually_exclusive_group()
- group.add_argument(
- '-e', '--epel',
- action='store_true',
- dest='show_epel_only',
- help='Only show EPEL releases.')
- group.add_argument(
- '-f', '--fedora',
- action='store_true',
- dest='show_fedora_only',
- help='Only show Fedora active releases.')
- group.add_argument(
- '-j', '--join',
- action='store_true',
- help='Show all releases in one line separated by a space.')
-
- parser.set_defaults(command=self.show_releases_info)
-
- def register_override(self):
- """Register command line parser for subcommand override
-
- .. versionadded:: 1.34
- """
-
- def validate_duration(value):
- try:
- duration = int(value)
- except ValueError:
- raise argparse.ArgumentTypeError('duration must be an integer.')
- if duration > 0:
- return duration
- raise argparse.ArgumentTypeError(
- 'override should have 1 day to exist at least.')
-
- def validate_extend_duration(value):
- if value.isdigit():
- return validate_duration(value)
- match = re.match(r'(\d{4})-(\d{1,2})-(\d{1,2})', value)
- if not match:
- raise argparse.ArgumentTypeError(
- 'Invalid expiration date. Valid format: yyyy-mm-dd.')
- y, m, d = match.groups()
- return datetime(year=int(y), month=int(m), day=int(d))
-
- override_parser = self.subparsers.add_parser(
- 'override',
- help='Manage buildroot overrides')
- override_subparser = override_parser.add_subparsers(
- description='Commands on override')
-
- create_parser = override_subparser.add_parser(
- 'create',
- help='Create buildroot override from build',
- formatter_class=argparse.RawDescriptionHelpFormatter,
- description='''\
-Create a buildroot override from build guessed from current release branch or
-specified explicitly.
-
-Examples:
-
-Create a buildroot override from build guessed from release branch. Note that,
-command must run inside a package repository.
-
- {0} switch-branch f28
- {0} override create --duration 5
-
-Create for a specified build:
-
- {0} override create --duration 5 package-1.0-1.fc28
-'''.format(self.name))
- create_parser.add_argument(
- '--duration',
- type=validate_duration,
- default=7,
- help='Number of days the override should exist. If omitted, '
- 'default to 7 days.')
- create_parser.add_argument(
- '--notes',
- default='No explanation given...',
- help='Optional notes on why this override is in place.')
- create_parser.add_argument(
- 'NVR',
- nargs='?',
- help='Create override from this build. If omitted, build will be'
- ' guessed from current release branch.')
- create_parser.set_defaults(command=self.create_buildroot_override)
-
- extend_parser = override_subparser.add_parser(
- 'extend',
- help='Extend buildroot override expiration',
- formatter_class=argparse.RawDescriptionHelpFormatter,
- description='''\
-Extend buildroot override expiration.
-
-An override expiration date could be extended by number of days or a specific
-date. If override is expired, expiration date will be extended from the date
-of today, otherwise from the expiration date.
-
-Command extend accepts an optional build NVR to find out its override in
-advance. If there is no such an override created previously, please use
-`override create` to create one. If build NVR is omitted, command extend must
-run inside a package repository and build will be guessed from current release
-branch.
-
-Examples:
-
-1. To give 2 days to override for build somepkg-0.2-1.fc28
-
- {0} override extend 2 somepkg-0.2-1.fc28
-
-2. To extend expiration date to 2018-7-1
-
- cd /path/to/somepkg
- {0} switch-branch f28
- {0} override extend 2018-7-1
-'''.format(self.name))
- extend_parser.add_argument(
- 'duration',
- type=validate_extend_duration,
- help='Number of days to extend the expiration date, or set the '
- 'expiration date directly. Valid date format: yyyy-mm-dd.')
- extend_parser.add_argument(
- 'NVR',
- nargs='?',
- help='Buildroot override expiration for this build will be '
- 'extended. If omitted, build will be guessed from current '
- 'release branch.')
- extend_parser.set_defaults(command=self.extend_buildroot_override)
-
- def register_build(self):
- super(fedpkgClient, self).register_build()
-
- build_parser = self.subparsers.choices['build']
- build_parser.formatter_class = argparse.RawDescriptionHelpFormatter
- build_parser.description = '''{0}
-
-fedpkg is also able to submit multiple builds to Koji at once from stream
-branch based on a local config, which is inside the repository. The config file
-is named package.cfg in INI format. For example,
-
- [koji]
- targets = master fedora epel7
-
-You only need to put Fedora releases and EPEL in option targets and fedpkg will
-convert it to proper Koji build target for submitting builds. Beside regular
-release names, option targets accepts two shortcut names as well, fedora and
-epel, as you can see in the above example. Name fedora stands for current
-active Fedora releases, and epel stands for the active EPEL releases, which are
-el6 and epel7 currently.
-
-Note that the config file is a branch specific file. That means you could
-create package.cfg for each stream branch separately to indicate on which
-targets to build the package for a particular stream.
-'''.format('\n'.join(textwrap.wrap(build_parser.description)))
-
# Target functions go here
def retire(self):
- # Skip if package is already retired...
- if os.path.isfile(os.path.join(self.cmd.path, 'dead.package')):
- self.log.warn('dead.package found, package probably already '
- 'retired - will not remove files from git or '
- 'overwrite existing dead.package file')
- else:
- self.cmd.retire(self.args.reason)
- self.push()
+ try:
+ module_name = self.cmd.module_name
+ ns_module_name = self.cmd.ns_module_name
+ namespace = ns_module_name.split(module_name)[0].rstrip('/')
+ # Skip if package is already retired to allow to retire only in
+ # pkgdb
+ if os.path.isfile(os.path.join(self.cmd.path, 'dead.package')):
+ self.log.warn('dead.package found, package probably already '
+ 'retired - will not remove files from git or '
+ 'overwrite existing dead.package file')
+ else:
+ self.cmd.retire(self.args.reason)
+ self.push()
+
+ branch = self.cmd.branch_merge
+ pkgdb = pkgdb2client.PkgDB(
+ login_callback=pkgdb2client.ask_password, url="https://admin.rpmfusion.org/pkgdb")
+ pkgdb.retire_packages(module_name, branch, namespace=namespace)
+ except Exception as e:
+ self.log.error('Could not retire package: %s' % e)
+ sys.exit(1)
def _format_update_clog(self, clog):
''' Format clog for the update template. '''
lines = [l for l in clog.split('\n') if l]
if len(lines) == 0:
return "- Rebuilt.", ""
elif len(lines) == 1:
return lines[0], ""
log = ["# Changelog:"]
log.append('# - ' + lines[0])
for l in lines[1:]:
log.append('# ' + l)
log.append('#')
return lines[0], "\n".join(log)
- def _get_bodhi_config(self):
- try:
- section = '%s.bodhi' % self.name
- return {
- 'staging': self.config.getboolean(section, 'staging'),
- }
- except (ValueError, NoOptionError, NoSectionError) as e:
- self.log.error(str(e))
- raise rpkgError('Could not get bodhi options. It seems configuration is changed. '
- 'Please try to reinstall %s or consult developers to see what '
- 'is wrong with it.' % self.name)
-
- @staticmethod
- def is_update_aborted(template_file):
- """Check if the update is aborted
-
- As long as the template file cannot be loaded by configparse, abort
- immediately.
-
- From user's perspective, it is similar with aborting commit when option
- -m is omitted. If all lines are commented out, abort.
- """
- config = configparser.ConfigParser()
- try:
- loaded_files = config.read(template_file)
- except configparser.MissingSectionHeaderError:
- return True
- # Something wrong with the template, which causes it cannot be loaded.
- if not loaded_files:
- return True
- # template can be loaded even if it's empty.
- if not config.sections():
- return True
- return False
-
- def _prepare_bodhi_template(self, template_file):
- bodhi_args = {
- 'nvr': self.cmd.nvr,
- 'bugs': six.u(''),
- 'descr': six.u(
- 'Here is where you give an explanation of your update.'),
- 'request': self.args.request,
- 'autokarma': str(self.args.autokarma),
- 'stable_karma': self.args.stable_karma,
- 'unstable_karma': self.args.unstable_karma,
- 'close_bugs': str(self.args.close_bugs),
- 'suggest_reboot': str(self.args.suggest_reboot),
- }
-
- if self.args.update_type:
- bodhi_args['type_'] = self.args.update_type
- else:
- bodhi_args['type_'] = ''
-
- self.cmd.clog()
- clog_file = os.path.join(self.cmd.path, 'clog')
- with io.open(clog_file, encoding='utf-8') as f:
- clog = f.read()
-
- if self.args.bugs:
- bodhi_args['bugs'] = self.args.bugs
- else:
- # Extract bug numbers from the latest changelog entry
- bugs = re.findall(r'#([0-9]*)', clog)
- if bugs:
- bodhi_args['bugs'] = ','.join(bugs)
-
- if self.args.notes:
- bodhi_args['descr'] = self.args.notes.replace('\n', '\n ')
- bodhi_args['changelog'] = ''
- else:
- # Use clog as default message
- bodhi_args['descr'], bodhi_args['changelog'] = \
- self._format_update_clog(clog)
+ def update(self):
+ template = """\
+[ %(nvr)s ]
- template = textwrap.dedent(BODHI_TEMPLATE) % bodhi_args
+# bugfix, security, enhancement, newpackage (required)
+type=
- with io.open(template_file, 'w', encoding='utf-8') as f:
- f.write(template)
+# testing, stable
+request=testing
- if not self.args.update_type or not self.args.notes:
- # Open the template in a text editor
- editor = os.getenv('EDITOR', 'vi')
- self.cmd._run_command([editor, template_file], shell=True)
+# Bug numbers: 1234,9876
+bugs=%(bugs)s
- # Check to see if we got a template written out. Bail otherwise
- if not os.path.isfile(template_file):
- raise rpkgError('No bodhi update details saved!')
+%(changelog)s
+# Here is where you give an explanation of your update.
+notes=%(descr)s
- return not self.is_update_aborted(template_file)
+# Enable request automation based on the stable/unstable karma thresholds
+autokarma=True
+stable_karma=3
+unstable_karma=-3
- return True
+# Automatically close bugs when this marked as stable
+close_bugs=True
- def update(self):
- check_bodhi_version()
- bodhi_config = self._get_bodhi_config()
+# Suggest that users restart after update
+suggest_reboot=False
+"""
- bodhi_template_file = 'bodhi.template'
- ready = self._prepare_bodhi_template(bodhi_template_file)
+ bodhi_args = {'nvr': self.cmd.nvr,
+ 'bugs': '',
+ 'descr': 'Here is where you give an explanation'
+ ' of your update.'}
- if ready:
+ # Extract bug numbers from the latest changelog entry
+ self.cmd.clog()
+ clog = file('clog').read()
+ bugs = re.findall(r'#([0-9]*)', clog)
+ if bugs:
+ bodhi_args['bugs'] = ','.join(bugs)
+
+ # Use clog as default message
+ bodhi_args['descr'], bodhi_args['changelog'] = \
+ self._format_update_clog(clog)
+
+ template = textwrap.dedent(template) % bodhi_args
+
+ # Calculate the hash of the unaltered template
+ orig_hash = hashlib.new('sha1')
+ orig_hash.update(template)
+ orig_hash = orig_hash.hexdigest()
+
+ # Write out the template
+ out = file('bodhi.template', 'w')
+ out.write(template)
+ out.close()
+
+ # Open the template in a text editor
+ editor = os.getenv('EDITOR', 'vi')
+ self.cmd._run_command([editor, 'bodhi.template'], shell=True)
+
+ # Check to see if we got a template written out. Bail otherwise
+ if not os.path.isfile('bodhi.template'):
+ self.log.error('No bodhi update details saved!')
+ sys.exit(1)
+ # If the template was changed, submit it to bodhi
+ hash = self.cmd.lookasidecache.hash_file('bodhi.template', 'sha1')
+ if hash != orig_hash:
try:
- self.cmd.update(bodhi_config, template=bodhi_template_file)
+ self.cmd.update('bodhi.template')
except Exception as e:
- # Reserve original edited bodhi template so that packager could
- # have a chance to recover content on error for next try.
- shutil.copyfile(bodhi_template_file,
- '{0}.last'.format(bodhi_template_file))
- raise rpkgError('Could not generate update request: %s\n'
- 'A copy of the filled in template is saved '
- 'as bodhi.template.last' % e)
- finally:
- os.unlink(bodhi_template_file)
- os.unlink('clog')
+ self.log.error('Could not generate update request: %s' % e)
+ sys.exit(1)
else:
self.log.info('Bodhi update aborted!')
- def request_repo(self):
- self._request_repo(
- repo_name=self.args.name,
- ns=self.args.new_repo_namespace,
- branch='master',
- summary=self.args.summary,
- description=self.args.description,
- upstreamurl=self.args.upstreamurl,
- monitor=self.args.monitor,
- bug=self.args.bug,
- exception=self.args.exception,
- name=self.name,
- config=self.config,
- initial_commit=not self.args.no_initial_commit,
- )
-
- def request_tests_repo(self):
- self._request_repo(
- repo_name=self.args.name,
- ns='tests',
- description=self.args.description,
- name=self.name,
- config=self.config,
- anongiturl=self.cmd.anongiturl
- )
-
- @staticmethod
- def _request_repo(repo_name, ns, description, name, config, branch=None,
- summary=None, upstreamurl=None, monitor=None, bug=None,
- exception=None, anongiturl=None, initial_commit=True):
- """ Implementation of `request_repo`.
-
- Submits a request for a new dist-git repo.
-
- :param repo_name: The repository name string. Typically the
- value of `self.cmd.repo_name`.
- :param ns: The repository namespace string, i.e. 'rpms' or 'modules'.
- Typically takes the value of `self.cmd.ns`.
- :param description: A string, the description of the new repo.
- Typically takes the value of `self.args.description`.
- :param name: A string representing which section of the config should be
- used. Typically the value of `self.name`.
- :param config: A dict containing the configuration, loaded from file.
- Typically the value of `self.config`.
- :param branch: The git branch string when requesting a repo.
- Typically 'master'.
- :param summary: A string, the summary of the new repo. Typically
- takes the value of `self.args.summary`.
- :param upstreamurl: A string, the upstreamurl of the new repo.
- Typically takes the value of `self.args.upstreamurl`.
- :param monitor: A string, the monitoring flag of the new repo, i.e.
- `'no-monitoring'`, `'monitoring'`, or `'monitoring-with-scratch'`.
- Typically takes the value of `self.args.monitor`.
- :param bug: An integer representing the bugzilla ID of a "package
- review" associated with this new repo. Typically takes the
- value of `self.args.bug`.
- :param exception: An boolean specifying whether or not this request is
- an exception to the packaging policy. Exceptional requests may be
- granted the right to waive their package review at the discretion of
- Release Engineering. Typically takes the value of
- `self.args.exception`.
- :param anongiturl: A string with the name of the anonymous git url.
- Typically the value of `self.cmd.anongiturl`.
- :return: None
- """
-
- # bug is not a required parameter in the event the packager has an
- # exception, in which case, they may use the --exception flag
- # neither in case of modules, which don't require a formal review
- if not bug and not exception and ns not in ['tests', 'modules']:
- raise rpkgError(
- 'A Bugzilla bug is required on new repository requests')
- repo_regex = r'^[a-zA-Z0-9_][a-zA-Z0-9-_.+]*$'
- if not bool(re.match(repo_regex, repo_name)):
- raise rpkgError(
- 'The repository name "{0}" is invalid. It must be at least '
- 'two characters long with only letters, numbers, hyphens, '
- 'underscores, plus signs, and/or periods. Please note that '
- 'the project cannot start with a period or a plus sign.'
- .format(repo_name))
-
- summary_from_bug = ''
- if bug and ns not in ['tests', 'modules']:
- bz_url = config.get('{0}.bugzilla'.format(name), 'url')
- bz_client = BugzillaClient(bz_url)
- bug_obj = bz_client.get_review_bug(bug, ns, repo_name)
- summary_from_bug = bug_obj.summary.split(' - ', 1)[1].strip()
-
- if ns == 'tests':
- # check if tests repository does not exist already
- assert_new_tests_repo(repo_name, get_dist_git_url(anongiturl))
-
- ticket_body = {
- 'action': 'new_repo',
- 'namespace': 'tests',
- 'repo': repo_name,
- 'description': description,
- }
- else:
- ticket_body = {
- 'action': 'new_repo',
- 'branch': branch,
- 'bug_id': bug or '',
- 'description': description or '',
- 'exception': exception,
- 'monitor': monitor,
- 'namespace': ns,
- 'repo': repo_name,
- 'summary': summary or summary_from_bug,
- 'upstreamurl': upstreamurl or ''
- }
- if not initial_commit:
- ticket_body['initial_commit'] = False
-
- ticket_body = json.dumps(ticket_body, indent=True)
- ticket_body = '```\n{0}\n```'.format(ticket_body)
- ticket_title = 'New Repo for "{0}/{1}"'.format(ns, repo_name)
-
- pagure_url = config.get('{0}.pagure'.format(name), 'url')
- pagure_token = get_pagure_token(config, name)
- print(new_pagure_issue(
- pagure_url, pagure_token, ticket_title, ticket_body))
-
- def request_branch(self):
- if self.args.repo_name_for_branch:
- self.cmd.repo_name = self.args.repo_name_for_branch
- self.cmd.ns = self.args.repo_ns_for_branch or 'rpms'
+ # Clean up
+ os.unlink('bodhi.template')
+ os.unlink('clog')
+
+if __name__ == '__main__':
+ client = cliClient()
+ client._do_imports()
+ client.parse_cmdline()
+ if not client.args.path:
try:
- active_branch = self.cmd.repo.active_branch.name
- except rpkgError:
- active_branch = None
- self._request_branch(
- service_levels=self.args.sl,
- all_releases=self.args.all_releases,
- branch=self.args.branch,
- active_branch=active_branch,
- repo_name=self.cmd.repo_name,
- ns=self.cmd.ns,
- no_git_branch=self.args.no_git_branch,
- no_auto_module=self.args.no_auto_module,
- name=self.name,
- config=self.config,
- )
+ client.args.path = os.getcwd()
+ except:
+ print('Could not get current path, have you deleted it?')
+ sys.exit(1)
+
+ # setup the logger -- This logger will take things of INFO or DEBUG and
+ # log it to stdout. Anything above that (WARN, ERROR, CRITICAL) will go
+ # to stderr. Normal operation will show anything INFO and above.
+ # Quiet hides INFO, while Verbose exposes DEBUG. In all cases WARN or
+ # higher are exposed (via stderr).
+ log = client.site.log
+ client.setupLogging(log)
+
+ if client.args.v:
+ log.setLevel(logging.DEBUG)
+ elif client.args.q:
+ log.setLevel(logging.WARNING)
+ else:
+ log.setLevel(logging.INFO)
- @staticmethod
- def _request_branch(service_levels, all_releases, branch, active_branch,
- repo_name, ns, no_git_branch, no_auto_module,
- name, config):
- """ Implementation of `request_branch`.
-
- Submits a request for a new branch of a given dist-git repo.
-
- :param service_levels: A list of service level strings. Typically the
- value of `self.args.service_levels`.
- :param all_releases: A boolean indicating if this request should be made
- for all active Fedora branches.
- :param branch: A string specifying the specific branch to be requested.
- :param active_branch: A string (or None) specifying the active branch in
- the current git repo (the branch that is currently checked out).
- :param repo_name: The repository name string. Typically the
- value of `self.cmd.repo_name`.
- :param ns: The repository namespace string, i.e. 'rpms' or 'modules'.
- Typically takes the value of `self.cmd.ns`.
- :param no_git_branch: A boolean flag. If True, the SCM admins should
- create the git branch in PDC, but not in pagure.io.
- :param no_auto_module: A boolean flag. If True, requests for
- non-standard branches should not automatically result in additional
- requests for matching modules.
- :param name: A string representing which section of the config should be
- used. Typically the value of `self.name`.
- :param config: A dict containing the configuration, loaded from file.
- Typically the value of `self.config`.
- :return: None
- """
-
- if all_releases:
- if branch:
- raise rpkgError('You cannot specify a branch with the '
- '"--all-releases" option')
- elif service_levels:
- raise rpkgError('You cannot specify service levels with the '
- '"--all-releases" option')
- elif not branch:
- if active_branch:
- branch = active_branch
- else:
- raise rpkgError('You must specify a branch if you are not in '
- 'a git repository')
-
- pdc_url = config.get('{0}.pdc'.format(name), 'url')
- if branch:
- if is_epel(branch):
- assert_valid_epel_package(repo_name, branch)
-
- if ns in ['modules', 'test-modules']:
- branch_valid = bool(re.match(r'^[a-zA-Z0-9.\-_+]+$', branch))
- if not branch_valid:
- raise rpkgError(
- 'Only characters, numbers, periods, dashes, '
- 'underscores, and pluses are allowed in module branch '
- 'names')
- release_branches = list(itertools.chain(
- *list(get_release_branches(pdc_url).values())))
- if branch in release_branches:
- if service_levels:
- raise rpkgError(
- 'You can\'t provide SLs for release branches')
- else:
- if re.match(RELEASE_BRANCH_REGEX, branch):
- raise rpkgError('{0} is a current release branch'
- .format(branch))
- elif not service_levels:
- raise rpkgError(
- 'You must provide SLs for non-release branches (%s)' % branch)
-
- # If service levels were provided, verify them
- if service_levels:
- sl_dict = sl_list_to_dict(service_levels)
- verify_sls(pdc_url, sl_dict)
-
- pagure_url = config.get('{0}.pagure'.format(name), 'url')
- pagure_token = get_pagure_token(config, name)
- if all_releases:
- release_branches = list(itertools.chain(
- *list(get_release_branches(pdc_url).values())))
- branches = [b for b in release_branches
- if re.match(r'^(f\d+)$', b)]
- else:
- branches = [branch]
-
- for b in sorted(list(branches), reverse=True):
- ticket_body = {
- 'action': 'new_branch',
- 'branch': b,
- 'namespace': ns,
- 'repo': repo_name,
- 'create_git_branch': not no_git_branch
- }
- if service_levels:
- ticket_body['sls'] = sl_dict
-
- ticket_body = json.dumps(ticket_body, indent=True)
- ticket_body = '```\n{0}\n```'.format(ticket_body)
- ticket_title = 'New Branch "{0}" for "{1}/{2}"'.format(
- b, ns, repo_name)
-
- print(new_pagure_issue(
- pagure_url, pagure_token, ticket_title, ticket_body))
-
- # For non-standard rpm branch requests, also request a matching new
- # module repo with a matching branch.
- auto_module = (
- ns == 'rpms'
- and not re.match(RELEASE_BRANCH_REGEX, b)
- and not no_auto_module
- )
- if auto_module:
- summary = ('Automatically requested module for '
- 'rpms/%s:%s.' % (repo_name, b))
- fedpkgClient._request_repo(
- repo_name=repo_name,
- ns='modules',
- branch='master',
- summary=summary,
- description=summary,
- upstreamurl=None,
- monitor='no-monitoring',
- bug=None,
- exception=True,
- name=name,
- config=config,
- )
- fedpkgClient._request_branch(
- service_levels=service_levels,
- all_releases=all_releases,
- branch=b,
- active_branch=active_branch,
- repo_name=repo_name,
- ns='modules',
- no_git_branch=no_git_branch,
- no_auto_module=True, # Avoid infinite recursion.
- name=name,
- config=config,
- )
-
- def create_buildroot_override(self):
- """Create a buildroot override in Bodhi"""
- check_bodhi_version()
- if self.args.NVR:
- if not self.cmd.anon_kojisession.getBuild(self.args.NVR):
- raise rpkgError(
- 'Build {0} does not exist.'.format(self.args.NVR))
- bodhi_config = self._get_bodhi_config()
- self.cmd.create_buildroot_override(
- bodhi_config,
- build=self.args.NVR or self.cmd.nvr,
- duration=self.args.duration,
- notes=self.args.notes)
-
- def extend_buildroot_override(self):
- check_bodhi_version()
- if self.args.NVR:
- if not self.cmd.anon_kojisession.getBuild(self.args.NVR):
- raise rpkgError(
- 'Build {0} does not exist.'.format(self.args.NVR))
- bodhi_config = self._get_bodhi_config()
- self.cmd.extend_buildroot_override(
- bodhi_config,
- build=self.args.NVR or self.cmd.nvr,
- duration=self.args.duration)
-
- def read_releases_from_local_config(self, active_releases):
- """Read configured releases from build config from repo"""
- config_file = os.path.join(self.cmd.path, LOCAL_PACKAGE_CONFIG)
- if not os.path.exists(config_file):
- self.log.warning('No local config file exists.')
- self.log.warning(
- 'Create %s to specify build targets to build.',
- LOCAL_PACKAGE_CONFIG)
- return None
- config = configparser.ConfigParser()
- if not config.read([config_file]):
- raise rpkgError('Package config {0} is not accessible.'.format(
- LOCAL_PACKAGE_CONFIG))
- if not config.has_option('koji', 'targets'):
- self.log.warning(
- 'Build target is not configured. Continue to build as normal.')
- return None
- target_releases = config.get('koji', 'targets', raw=True).split()
- expanded_releases = []
- for rel in target_releases:
- expanded = expand_release(rel, active_releases)
- if expanded:
- expanded_releases += expanded
- else:
- self.log.error('Target %s is unknown. Skip.', rel)
- return sorted(set(expanded_releases))
-
- @staticmethod
- def is_stream_branch(stream_branches, name):
- """Determine if a branch is stream branch
-
- :param stream_branches: list of stream branches of a package. Each of
- them is a mapping containing name and active status, which are
- minimum set of properties to be included. For example, ``[{'name':
- '8', 'active': true}, {'name': '10', 'active': true}]``.
- :type stream_branches: list[dict]
- :param str name: branch name to check if it is a stream branch.
- :return: True if branch is a stream branch, False otherwise.
- :raises rpkgError: if branch is a stream branch but it is inactive.
- """
- for branch_info in stream_branches:
- if branch_info['name'] != name:
- continue
- if branch_info['active']:
- return True
- else:
- raise rpkgError('Cannot build from stream branch {0} as it is '
- 'inactive.'.format(name))
- return False
-
- def _build(self, sets=None):
- if hasattr(self.args, 'chain') or self.args.scratch:
- return super(fedpkgClient, self)._build(sets)
-
- server_url = self.config.get('{0}.pdc'.format(self.name), 'url')
-
- stream_branches = get_stream_branches(server_url, self.cmd.repo_name)
- self.log.debug(
- 'Package %s has stream branches: %r',
- self.cmd.repo_name, [item['name'] for item in stream_branches])
-
- if not self.is_stream_branch(stream_branches, self.cmd.branch_merge):
- return super(fedpkgClient, self)._build(sets)
-
- self.log.debug('Current branch %s is a stream branch.',
- self.cmd.branch_merge)
-
- releases = self.read_releases_from_local_config(
- get_release_branches(server_url))
-
- if not releases:
- # If local config file is not created yet, or no build targets
- # are not configured, let's build as normal.
- return super(fedpkgClient, self)._build(sets)
-
- self.log.debug('Build on release targets: %r', releases)
- task_ids = []
- for release in releases:
- self.cmd.branch_merge = release
- self.cmd.target = self.cmd.build_target(release)
- task_id = super(fedpkgClient, self)._build(sets)
- task_ids.append(task_id)
- return task_ids
-
- def show_releases_info(self):
- server_url = self.config.get('{0}.pdc'.format(self.name), 'url')
- releases = get_release_branches(server_url)
-
- def _join(l):
- return ' '.join(l)
-
- if self.args.show_epel_only:
- print(_join(releases['epel']))
- elif self.args.show_fedora_only:
- print(_join(releases['fedora']))
- elif self.args.join:
- print(' '.join(itertools.chain(releases['fedora'],
- releases['epel'])))
- else:
- print('Fedora: {0}'.format(_join(releases['fedora'])))
- print('EPEL: {0}'.format(_join(releases['epel'])))
+ # Run the necessary command
+ try:
+ client.args.command()
+ except KeyboardInterrupt:
+ pass
--- fedpkg/fedpkg/__init__.py 2018-08-23 12:21:22.626622238 -0400
+++ rfpkg/src/rfpkg/__init__.py 2018-08-23 12:21:38.273925248 -0400
@@ -1,396 +1,394 @@
-# fedpkg - a Python library for RPM Packagers
+# rfpkg - a Python library for RPM Packagers
#
# Copyright (C) 2011 Red Hat Inc.
# Author(s): Jesse Keating <jkeating@redhat.com>
+# Copyright (C) 2016 - Nicolas Chauvet <kwizart@gmail.com>
#
# 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. See http://www.gnu.org/copyleft/gpl.html for
# the full text of the license.
import pyrpkg
import os
+import cli
import git
import re
+import rpmfusion_cert
import platform
+import subprocess
+import urlparse
+import koji
-from datetime import datetime, timedelta
-from . import cli # noqa
-from .lookaside import FedoraLookasideCache
+from .lookaside import RPMFusionLookasideCache
from pyrpkg.utils import cached_property
-try:
- from bodhi.client.bindings import BodhiClient as _BodhiClient
-except ImportError:
- _BodhiClient = None
-
-
-if _BodhiClient is not None:
- from fedora.client import AuthError
-
- def clear_csrf_and_retry(func):
- """Clear csrf token and retry
-
- fedpkg uses Bodhi Python binding API list_overrides first before other
- save and extend APIs. That causes a readonly csrf token is received,
- which will be got again when next time to construct request data to
- modify updates. That is not expected and AuthError will be raised.
-
- So, the solution is to capture the AuthError error, clear the token and
- try to modify update again by requesting another token with user's
- credential.
- """
- def _decorator(self, *args, **kwargs):
- try:
- return func(self, *args, **kwargs)
- except AuthError:
- self._session.cookies.clear()
- self.csrf_token = None
- return func(self, *args, **kwargs)
- return _decorator
-
- class BodhiClient(_BodhiClient):
- """Customized BodhiClient for fedpkg"""
-
- UPDATE_TYPES = ['bugfix', 'security', 'enhancement', 'newpackage']
- REQUEST_TYPES = ['testing', 'stable']
-
- @clear_csrf_and_retry
- def save(self, *args, **kwargs):
- return super(BodhiClient, self).save(*args, **kwargs)
-
- @clear_csrf_and_retry
- def save_override(self, *args, **kwargs):
- return super(BodhiClient, self).save_override(*args, **kwargs)
-
- @clear_csrf_and_retry
- def extend_override(self, override, expiration_date):
- data = dict(
- nvr=override['nvr'],
- notes=override['notes'],
- expiration_date=expiration_date,
- edited=override['nvr'],
- csrf_token=self.csrf(),
- )
- return self.send_request(
- 'overrides/', verb='POST', auth=True, data=data)
-
class Commands(pyrpkg.Commands):
- def __init__(self, *args, **kwargs):
+ def __init__(self, path, lookaside, lookasidehash, lookaside_cgi,
+ gitbaseurl, anongiturl, branchre, kojiprofile,
+ build_client, **kwargs):
"""Init the object and some configuration details."""
- super(Commands, self).__init__(*args, **kwargs)
+ super(Commands, self).__init__(path, lookaside, lookasidehash,
+ lookaside_cgi, gitbaseurl, anongiturl,
+ branchre, kojiprofile, build_client,
+ **kwargs)
+
+ # New data
+ self.secondary_arch = {
+ 'ppc': [
+ 'apmud',
+ 'libbsr',
+ 'librtas',
+ 'libservicelog',
+ 'libvpd',
+ 'lsvpd',
+ 'powerpc-utils',
+ 'powerpc-utils-papr',
+ 'powerpc-utils-python',
+ 'ppc64-diag',
+ 'ppc64-utils',
+ 'servicelog',
+ 'yaboot',
+ ], 'arm': ['xorg-x11-drv-omapfb'],
+ 's390': ['s390utils', 'openssl-ibmca', 'libica', 'libzfcphbaapi']
+ }
+
+ # New properties
+ self._kojiprofile = None
+ self._cert_file = None
+ self._ca_cert = None
+ # Store this for later
+ self._orig_kojiprofile = kojiprofile
+
+ # RPM Fusion default namespace
+ self.default_namespace = 'free'
+ self.namespace = None
+ self.hashtype = 'md5'
+
+ # Add new properties
+ @property
+ def kojiprofile(self):
+ """This property ensures the kojiprofile attribute"""
+
+ if not self._kojiprofile:
+ self.load_kojiprofile()
+ return self._kojiprofile
+
+ @kojiprofile.setter
+ def kojiprofile(self, value):
+ self._kojiprofile = value
- self.source_entry_type = 'bsd'
+ def load_kojiprofile(self):
+ """This loads the kojiprofile attribute
- def load_user(self):
- """This sets the user attribute, based on the Fedora SSL cert."""
- fedora_upn = os.path.expanduser('~/.fedora.upn')
- if os.path.exists(fedora_upn):
- with open(fedora_upn, 'r') as f:
- self._user = f.read().strip()
- else:
- self.log.debug('Could not get user from .fedora.upn, falling back'
- ' to default method')
- super(Commands, self).load_user()
+ This will either use the one passed in via arguments or a
+ secondary arch config depending on the package
+ """
+
+ # We have to allow this to work, even if we don't have a package
+ # we're working on, for things like gitbuildhash.
+ try:
+ null = self.module_name
+ except:
+ self._kojiprofile = self._orig_kojiprofile
+ return
+ for arch in self.secondary_arch.keys():
+ if self.module_name in self.secondary_arch[arch]:
+ self._kojiprofile = arch
+ return
+ self._kojiprofile = self._orig_kojiprofile
+
+ @cached_property
+ def cert_file(self):
+ """A client-side certificate for SSL authentication
+
+ We override this from pyrpkg because we actually need a client-side
+ certificate.
+ """
+ return os.path.expanduser('~/.rpmfusion.cert')
+
+ @cached_property
+ def ca_cert(self):
+ """A CA certificate to authenticate the server in SSL connections
+
+ We override this from pyrpkg because we actually need a custom
+ CA certificate.
+ """
+ return os.path.expanduser('~/.rpmfusion-server-ca.cert')
+
+ def load_ns_module_name(self):
+ """Loads a RPM Fusion package module."""
+
+ if self.push_url:
+ parts = urlparse.urlparse(self.push_url)
+
+ if self.distgit_namespaced:
+ path_parts = [p for p in parts.path.split("/") if p]
+ ns_module_name = "/".join(path_parts[-2:])
+ _ns = path_parts[-2]
+
+ if ns_module_name.endswith('.git'):
+ ns_module_name = ns_module_name[:-len('.git')]
+ self._ns_module_name = ns_module_name
+ self.namespace = _ns
+ return
@cached_property
def lookasidecache(self):
"""A helper to interact with the lookaside cache
We override this because we need a different download path.
"""
- return FedoraLookasideCache(
- self.lookasidehash, self.lookaside, self.lookaside_cgi)
+ self.load_ns_module_name()
+ self._cert_file = os.path.expanduser('~/.rpmfusion.cert')
+
+ return RPMFusionLookasideCache(
+ self.lookasidehash, self.lookaside, self.lookaside_cgi,
+ client_cert=self._cert_file, ca_cert=self._ca_cert, namespace=self.namespace)
# Overloaded property loaders
def load_rpmdefines(self):
"""Populate rpmdefines based on branch data"""
# Determine runtime environment
self._runtime_disttag = self._determine_runtime_env()
+ self.load_ns_module_name()
# We only match the top level branch name exactly.
- # Anything else is too dangerous and --dist should be used
+ # Anything else is too dangerous and --release should be used
# This regex works until after Fedora 99.
if re.match(r'f\d\d$', self.branch_merge):
self._distval = self.branch_merge.split('f')[1]
self._distvar = 'fedora'
- self._disttag = 'fc%s' % self._distval
- self.mockconfig = 'fedora-%s-%s' % (self._distval, self.localarch)
- self.override = 'f%s-override' % self._distval
+ self.dist = 'fc%s' % self._distval
+ self.mockconfig = 'fedora-%s-%s-rpmfusion_%s' % (self._distval, self.localarch, self.namespace)
+ self.override = 'f%s-%s-override' % (self._distval, self.namespace)
self._distunset = 'rhel'
# Works until RHEL 10
- elif re.match(r'el\d$', self.branch_merge) or \
- re.match(r'epel\d$', self.branch_merge):
+ elif re.match(r'el\d$', self.branch_merge) or re.match(r'epel\d$', self.branch_merge):
self._distval = self.branch_merge.split('el')[1]
self._distvar = 'rhel'
- self._disttag = 'el%s' % self._distval
- self.mockconfig = 'epel-%s-%s' % (self._distval, self.localarch)
- self.override = 'epel%s-override' % self._distval
+ self.dist = 'el%s' % self._distval
+ self.mockconfig = 'epel-%s-%s-rpmfusion_%s' % (self._distval, self.localarch, self.namespace)
+ self.override = 'epel%s-%s-override' % (self._distval, self.namespace)
self._distunset = 'fedora'
- elif re.match(r'olpc\d$', self.branch_merge):
- self._distval = self.branch_merge.split('olpc')[1]
- self._distvar = 'olpc'
- self._disttag = 'olpc%s' % self._distval
- self.override = 'dist-olpc%s-override' % self._distval
- self._distunset = 'rhel'
# master
elif re.match(r'master$', self.branch_merge):
self._distval = self._findmasterbranch()
self._distvar = 'fedora'
- self._disttag = 'fc%s' % self._distval
- self.mockconfig = 'fedora-rawhide-%s' % self.localarch
+ self.dist = 'fc%s' % self._distval
+ self.mockconfig = 'fedora-rawhide-%s-rpmfusion_%s' % (self.localarch, self.namespace)
self.override = None
self._distunset = 'rhel'
# If we don't match one of the above, punt
else:
raise pyrpkg.rpkgError('Could not find the release/dist from branch name '
'%s\nPlease specify with --release' %
self.branch_merge)
self._rpmdefines = ["--define '_sourcedir %s'" % self.path,
"--define '_specdir %s'" % self.path,
"--define '_builddir %s'" % self.path,
"--define '_srcrpmdir %s'" % self.path,
"--define '_rpmdir %s'" % self.path,
- "--define 'dist .%s'" % self._disttag,
+ "--define 'dist .%s'" % self.dist,
"--define '%s %s'" % (self._distvar,
self._distval),
"--eval '%%undefine %s'" % self._distunset,
- "--define '%s 1'" % self._disttag]
+ "--define '%s 1'" % self.dist]
if self._runtime_disttag:
- if self._disttag != self._runtime_disttag:
+ if self.dist != self._runtime_disttag:
# This means that the runtime is known, and is different from
# the target, so we need to unset the _runtime_disttag
self._rpmdefines.append("--eval '%%undefine %s'" %
self._runtime_disttag)
- def build_target(self, release):
- if release == 'master':
- return 'rawhide'
- else:
- return '%s-candidate' % release
+ def load_target(self):
+ """This creates the target attribute based on branch merge"""
- def load_container_build_target(self):
+ self.load_ns_module_name()
if self.branch_merge == 'master':
- self._container_build_target = 'rawhide-%s-candidate' % self.ns
+ self._target = 'rawhide-%s' % self.namespace
else:
- super(Commands, self).load_container_build_target()
+ self._target = '%s-%s' % ( self.branch_merge , self.namespace)
- def _tag2version(self, dest_tag):
- """ get the '26' part of 'f26-foo' string """
- return dest_tag.split('-')[0].replace('f', '')
+ def load_user(self):
+ """This sets the user attribute, based on the RPM Fusion SSL cert."""
+ try:
+ self._user = rpmfusion_cert.read_user_cert()
+ except Exception as e:
+ self.log.debug('Could not read RPM Fusion cert, falling back to '
+ 'default method: %s' % e)
+ super(Commands, self).load_user()
# New functionality
def _findmasterbranch(self):
- """Find the right "fedora" for master"""
+ """Find the right "rpmfusion" for master"""
# If we already have a koji session, just get data from the source
if self._kojisession:
- rawhidetarget = self.kojisession.getBuildTarget('rawhide')
- return self._tag2version(rawhidetarget['dest_tag_name'])
-
- # Create a list of "fedoras"
- fedoras = []
-
- # Create a regex to find branches that exactly match f##. Should not
- # catch branches such as f14-foobar
- branchre = r'f\d\d$'
-
- # Find the repo refs
- for ref in self.repo.refs:
- # Only find the remote refs
- if type(ref) == git.RemoteReference:
- # Search for branch name by splitting off the remote
- # part of the ref name and returning the rest. This may
- # fail if somebody names a remote with / in the name...
- if re.match(branchre, ref.name.split('/', 1)[1]):
- # Add just the simple f## part to the list
- fedoras.append(ref.name.split('/')[1])
- if fedoras:
- # Sort the list
- fedoras.sort()
- # Start with the last item, strip the f, add 1, return it.
- return(int(fedoras[-1].strip('f')) + 1)
+ rawhidetarget = self.kojisession.getBuildTarget('rawhide-free')
+ desttag = rawhidetarget['dest_tag_name']
+ desttag=desttag.split('-')
+ desttag.remove('free')
+ desttag=''.join(desttag)
+ return desttag.replace('f', '')
else:
# We may not have Fedoras. Find out what rawhide target does.
try:
rawhidetarget = self.anon_kojisession.getBuildTarget(
- 'rawhide')
- except Exception:
+ 'rawhide-free')
+ except:
# We couldn't hit koji, bail.
- raise pyrpkg.rpkgError(
- 'Unable to query koji to find rawhide target')
- return self._tag2version(rawhidetarget['dest_tag_name'])
+ raise pyrpkg.rpkgError('Unable to query koji to find rawhide \
+ target')
+ desttag = rawhidetarget['dest_tag_name']
+ desttag=desttag.split('-')
+ desttag.remove('free')
+ desttag=''.join(desttag)
+ return desttag.replace('f', '')
def _determine_runtime_env(self):
"""Need to know what the runtime env is, so we can unset anything
conflicting
"""
+
try:
- runtime_os, runtime_version, _ = platform.linux_distribution()
- except Exception:
- return None
+ mydist = platform.linux_distribution()
+ except:
+ # This is marked as eventually being deprecated.
+ try:
+ mydist = platform.dist()
+ except:
+ runtime_os = 'unknown'
+ runtime_version = '0'
+
+ if mydist:
+ runtime_os = mydist[0]
+ runtime_version = mydist[1]
+ else:
+ runtime_os = 'unknown'
+ runtime_version = '0'
if runtime_os in ['redhat', 'centos']:
return 'el%s' % runtime_version
if runtime_os == 'Fedora':
return 'fc%s' % runtime_version
- if (runtime_os == 'Red Hat Enterprise Linux Server' or
- runtime_os.startswith('CentOS')):
- return 'el{0}'.format(runtime_version.split('.')[0])
-
- def check_inheritance(self, build_target, dest_tag):
- """Disable check inheritance
- Tag inheritance check is not required in Fedora when make chain build
- in Koji.
- """
+ # fall through, return None
+ return None
- def construct_build_url(self, *args, **kwargs):
- """Override build URL for Fedora Koji build
+ def construct_build_url(self):
+ """Override build URL for RPM Fusion Koji build
- In Fedora Koji, anonymous URL should have prefix "git+https://"
+ In RPM Fusion Koji, anonymous URL should have prefix "git+https://"
"""
- url = super(Commands, self).construct_build_url(*args, **kwargs)
- return 'git+{0}'.format(url)
+ url = super(Commands, self).construct_build_url()
+ if not url.startswith('git'):
+ url = 'git+{0}'.format(url)
+ return url
def retire(self, message):
"""Delete all tracked files and commit a new dead.package file
Use optional message in commit.
Runs the commands and returns nothing
"""
cmd = ['git']
if self.quiet:
cmd.append('--quiet')
cmd.extend(['rm', '-rf', '.'])
self._run_command(cmd, cwd=self.path)
fd = open(os.path.join(self.path, 'dead.package'), 'w')
fd.write(message + '\n')
fd.close()
cmd = ['git', 'add', os.path.join(self.path, 'dead.package')]
self._run_command(cmd, cwd=self.path)
self.commit(message=message)
- def update(self, bodhi_config, template='bodhi.template', bugs=[]):
+ def update(self, template='bodhi.template', bugs=[]):
"""Submit an update to bodhi using the provided template."""
- bodhi = BodhiClient(username=self.user,
- staging=bodhi_config['staging'])
-
- update_details = bodhi.parse_file(template)
- for detail in update_details:
- if not detail['type']:
- raise ValueError(
- 'Missing update type, which is required to create update.')
- if detail['type'] not in BodhiClient.UPDATE_TYPES:
- raise ValueError(
- 'Incorrect update type {0}'.format(detail['type']))
- if detail['request'] not in BodhiClient.REQUEST_TYPES:
- raise ValueError(
- 'Incorrect request type {0}'.format(detail['request']))
-
- bodhi.save(**detail)
-
- def create_buildroot_override(self, bodhi_config, build, duration,
- notes=''):
- bodhi = BodhiClient(username=self.user,
- staging=bodhi_config['staging'])
- result = bodhi.list_overrides(builds=build)
- if result['total'] == 0:
- try:
- self.log.debug(
- 'Create override in %s: nvr=%s, duration=%s, notes="%s"',
- 'staging Bodhi' if bodhi_config['staging'] else 'Bodhi',
- build, duration, notes)
- override = bodhi.save_override(
- nvr=build, duration=duration, notes=notes)
- except Exception as e:
- self.log.error(str(e))
- raise pyrpkg.rpkgError('Cannot create override.')
- else:
- self.log.info(bodhi.override_str(override, minimal=False))
+ # build up the bodhi arguments, based on which version of bodhi is
+ # installed
+ bodhi_major_version = _get_bodhi_version()[0]
+ if bodhi_major_version < 2:
+ cmd = ['bodhi', '--new', '--release', self.branch_merge,
+ '--file', 'bodhi.template', self.nvr, '--username',
+ self.user]
+ elif bodhi_major_version == 2:
+ cmd = ['bodhi', 'updates', 'new', '--file', 'bodhi.template',
+ '--user', self.user, self.nvr]
else:
- override = result['overrides'][0]
- expiration_date = datetime.strptime(override['expiration_date'],
- '%Y-%m-%d %H:%M:%S')
- if expiration_date < datetime.utcnow():
- self.log.info(
- 'Buildroot override for %s exists and is expired. Consider'
- ' using command `override extend` to extend duration.',
- build)
- else:
- self.log.info('Buildroot override for %s already exists and '
- 'not expired.', build)
+ msg = 'This system has bodhi v{0}, which is unsupported.'
+ msg = msg.format(bodhi_major_version)
+ raise Exception(msg)
+ self._run_command(cmd, shell=True)
- def extend_buildroot_override(self, bodhi_config, build, duration):
- bodhi = BodhiClient(username=self.user,
- staging=bodhi_config['staging'])
- result = bodhi.list_overrides(builds=build)
+ def load_kojisession(self, anon=False):
+ """Initiate a koji session.
- if result['total'] == 0:
- self.log.info('No buildroot override for build %s', build)
- return
+ The koji session can be logged in or anonymous
+ """
+ koji_config = self.read_koji_config()
- override = result['overrides'][0]
- expiration_date = datetime.strptime(override['expiration_date'],
- '%Y-%m-%d %H:%M:%S')
- utcnow = datetime.utcnow()
-
- # bodhi-client binding API save_override calculates expiration
- # date by adding duration to datetime.utcnow
- # This comparison should use utcnow as well.
- if expiration_date < utcnow:
- self.log.debug('Buildroot override is expired on %s',
- override['expiration_date'])
- self.log.debug('Extend expiration date from today in UTC.')
- base_date = utcnow
- else:
- self.log.debug(
- 'Extend expiration date from future expiration date.')
- base_date = expiration_date
-
- if isinstance(duration, datetime):
- if duration < utcnow:
- raise pyrpkg.rpkgError(
- 'At least, specified expiration date {0} should be '
- 'future date.'.format(duration.strftime('%Y-%m-%d')))
- if duration < base_date:
- self.log.warning(
- 'Expiration date %s to be set is before override current'
- ' expiration date %s',
- duration, base_date)
- # Keep time unchanged
- new_expiration_date = datetime(
- year=duration.year,
- month=duration.month,
- day=duration.day,
- hour=base_date.hour,
- minute=base_date.minute,
- second=base_date.second)
- else:
- new_expiration_date = base_date + timedelta(days=duration)
+ # Expand out the directory options
+ for name in ('cert', 'ca', 'serverca'):
+ path = koji_config[name]
+ if path:
+ koji_config[name] = os.path.expanduser(path)
+
+ # save the weburl and topurl for later use as well
+ self._kojiweburl = koji_config['weburl']
+ self._topurl = koji_config['topurl']
+
+ self.log.debug('Initiating a %s session to %s',
+ os.path.basename(self.build_client), koji_config['server'])
+
+ # Build session options used to create instance of ClientSession
+ session_opts = koji.grab_session_options(koji_config)
try:
- self.log.debug('Extend override expiration date to %s',
- new_expiration_date)
- override = bodhi.extend_override(override, new_expiration_date)
- except Exception as e:
- self.log.error('Cannot extend override expiration.')
- raise pyrpkg.rpkgError(str(e))
+ session = koji.ClientSession(koji_config['server'], session_opts)
+ except Exception:
+ raise rpkgError('Could not initiate %s session' % os.path.basename(self.build_client))
else:
- self.log.info(bodhi.override_str(override, minimal=False))
+ if anon:
+ self._anon_kojisession = session
+ else:
+ self._kojisession = session
+
+ if not anon:
+ try:
+ self.login_koji_session(koji_config, self._kojisession)
+ except pyrpkg.rpkgAuthError:
+ self.log.info("You might want to run rpmfusion-packager-setup to "
+ "regenerate SSL certificate. For more info see "
+ "https://fedoraproject.org/wiki/Using_the_Koji_build"
+ "_system#Fedora_Account_System_.28FAS2.29_Setup")
+ raise
+
+
+def _get_bodhi_version():
+ """
+ Use bodhi --version to determine the version of the Bodhi CLI that's
+ installed on the system, then return a list of the version components.
+ For example, if bodhi --version returns "2.1.9", this function will return
+ [2, 1, 9].
+ """
+ bodhi = subprocess.Popen(['bodhi', '--version'], stdout=subprocess.PIPE)
+ version = bodhi.communicate()[0].strip()
+ return [int(component) for component in version.split('.')]
if __name__ == "__main__":
- from fedpkg.__main__ import main
+ from rfpkg.__main__ import main
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment