165 lines
6.5 KiB
Python
165 lines
6.5 KiB
Python
#!/usr/bin/env python
|
|
|
|
import re
|
|
import requests
|
|
import sys
|
|
import getpass
|
|
import pkgdb2client
|
|
import subprocess
|
|
|
|
#PAGE_URL = 'https://fedoraproject.org/w/api.php?format=json&action=query&rvprop=content&prop=revisions&titles=User:Codeblock/RequestsSANDBOX'
|
|
PAGE_URL = 'https://fedoraproject.org/w/api.php?format=json&action=query&rvprop=content&prop=revisions&titles=EPEL/epel7/Requests'
|
|
NEW_EPEL_VERSION = '7'
|
|
NEW_EPEL_SOURCE_BRANCH = 'f19'
|
|
RHEL_PKGS_PATH = '/var/lib/rhel/rhel' + NEW_EPEL_VERSION
|
|
|
|
# parse_page :: String -> IO (Map String String)
|
|
# This returns a dictionary of {"pkg_name": "branch"}
|
|
def parse_page(url):
|
|
r = requests.get(url).json()
|
|
text = r['query']['pages'][r['query']['pages'].keys()[0]]['revisions'][0]['*']
|
|
lines = text.split("\n")
|
|
pkgs = filter(lambda y: y.startswith('| '), lines)
|
|
__pkgs_list__ = map(lambda y: ''.join(y.split())[1:].split('||'), pkgs)
|
|
pkgs_list = filter(lambda y: y[0] != 'foo', __pkgs_list__)
|
|
pkgs_dict = dict(pkgs_list)
|
|
return pkgs_dict
|
|
|
|
# is_in_rhel :: String -> IO Bool
|
|
def is_in_rhel(pkg):
|
|
with open(RHEL_PKGS_PATH) as f:
|
|
pkgs = map(lambda x: x.strip(), f.readlines())
|
|
return (pkg in pkgs)
|
|
|
|
# These tuples will be used to substitute one pattern for another.
|
|
# Every transform will be run on every branch name so be sure the
|
|
# pattern cannot match if you don't want it to be triggered.
|
|
transforms = (
|
|
(re.compile(r'^devel$'), 'master'),
|
|
(re.compile(r'-'), ''),
|
|
(re.compile(r'^fc([0-9])'), r'f\1'),
|
|
(re.compile(r'^epel([456])$'), r'el\1'),
|
|
(re.compile(r'^el([789]|[1-9][0-9])'), r'epel\1'),
|
|
)
|
|
branch_replacements = {'devel': (re.compile(r'^devel$'), 'master'),}
|
|
|
|
# generate_collection_cache :: PkgDB -> IO [String]
|
|
def generate_collection_cache(pkgdb):
|
|
raw_collections = pkgdb.get_collections(clt_status=(
|
|
'Active',
|
|
'Under Development'))
|
|
collection_cache = frozenset(map(lambda y: y['branchname'],
|
|
raw_collections['collections']))
|
|
return collection_cache
|
|
|
|
# normalize_branch :: [String] -> String -> IO (Option String)
|
|
def normalize_branch(collection_cache, branch):
|
|
# I originally had this implemented as a foldRight (which it really is).
|
|
# But Python doesn't eliminate tail calls. It probably would have been fine
|
|
# because "transforms" above is only 5 elements, but instead I will deal
|
|
# with the local mutation and wish that I had a type system to reason with.
|
|
# -rbe
|
|
norm_branch = branch.lower()
|
|
for transform in transforms:
|
|
norm_branch = re.sub(transform[0], transform[1], norm_branch)
|
|
|
|
|
|
# Ugh, here we break purity. Where is the option type when you need it?
|
|
if not (norm_branch in collection_cache):
|
|
print('Unknown collection specified: {0}'.format(branch))
|
|
return None
|
|
|
|
return norm_branch
|
|
|
|
# process_package :: PkgDB -> String -> String -> IO Bool
|
|
def process_package(pkgdb, pkg, src, dest):
|
|
print "*** Processing package: " + pkg
|
|
|
|
data = pkgdb.get_package(pkg)
|
|
pkg_list = data['packages']
|
|
|
|
maybe_source = [branch for branch in pkg_list if branch['collection']['branchname'] == src]
|
|
maybe_dest = [branch for branch in pkg_list if branch['collection']['branchname'] == dest]
|
|
|
|
if len(maybe_source) == 0:
|
|
print "Source branch `" + src + "' not found. Please "\
|
|
"branch " + pkg + " manually."
|
|
return False
|
|
|
|
if len(maybe_dest) != 0:
|
|
print "Package `" + pkg + "' was already branched for `" + dest + "'."\
|
|
" Not overwriting branch."
|
|
return False
|
|
|
|
if 'acls' not in maybe_source[0].keys():
|
|
print "No 'acls' key given to us by pkgdb. Cloning ACLs from a "\
|
|
"branch that has no ACLs due to retirement/orphan?"
|
|
return False
|
|
|
|
acls = [
|
|
acl
|
|
for acl in maybe_source[0]['acls']
|
|
if acl['fas_name'] != 'group::provenpackager'
|
|
]
|
|
|
|
for acl in acls:
|
|
pkgdb.update_acl(pkg, dest, acl['acl'], acl['status'], acl['fas_name'])
|
|
|
|
pkgdb.update_package_poc(pkg, dest, maybe_source[0]['point_of_contact'])
|
|
|
|
return True
|
|
|
|
# main :: [String] -> IO Unit
|
|
def main(args):
|
|
new_epel_requests = "epel" + NEW_EPEL_VERSION + "-requests"
|
|
if len(args) < 1 or (len(args) < 3 and args[0] != new_epel_requests) or\
|
|
len(args) > 3 or (len(args) > 1 and args[0] == new_epel_requests):
|
|
print "Usage: pkgdb2-clone " + new_epel_requests
|
|
print " - OR -"
|
|
print " pkgdb2-clone <source branch> <dest branch> <pkgs ...>"
|
|
sys.exit(1)
|
|
|
|
pkgdb = pkgdb2client.PkgDB()
|
|
|
|
username = raw_input('Username: ')
|
|
password = getpass.getpass()
|
|
pkgdb.login(username, password, True)
|
|
|
|
collection_cache = generate_collection_cache(pkgdb)
|
|
|
|
if args[0] == new_epel_requests:
|
|
pkgs = parse_page(PAGE_URL)
|
|
for key in pkgs:
|
|
if is_in_rhel(key):
|
|
continue
|
|
src_branchname = normalize_branch(collection_cache, pkgs[key])
|
|
dest_branchname = normalize_branch(collection_cache,
|
|
'epel' + NEW_EPEL_VERSION)
|
|
if not src_branchname or not dest_branchname:
|
|
print "[" + key + "] Invalid source or destination branch "\
|
|
"name, " + src_branchname + " -> " + dest_branchname
|
|
else:
|
|
if process_package(pkgdb, key, src_branchname, dest_branchname):
|
|
subprocess.call(["mkbranch",
|
|
"-s",
|
|
NEW_EPEL_SOURCE_BRANCH,
|
|
"epel" + NEW_EPEL_VERSION,
|
|
key])
|
|
print "[" + key + "] \033[1m\033[32mSUCCESS\033[0m"
|
|
else:
|
|
print "[" + key + "] \033[1m\033[31mERROR\033[0m"
|
|
print "Done."
|
|
else:
|
|
src_branchname = normalize_branch(collection_cache, args[0])
|
|
dest_branchname = normalize_branch(collection_cache, args[1])
|
|
if not src_branchname or not dest_branchname:
|
|
print "[" + key + "] Invalid source or destination branch "\
|
|
"name, " + src_branchname + " -> " + dest_branchname
|
|
for pkg in args[2:]:
|
|
if process_package(pkgdb, key, src_branchname, dest_branchname):
|
|
print "[" + key + "] \033[1m\033[32mSUCCESS\033[0m"
|
|
else:
|
|
print "[" + key + "] \033[1m\033[31mERROR\033[0m"
|
|
|
|
if __name__ == '__main__':
|
|
main(sys.argv[1:])
|