monitoring-plugins-cyconet/debian/packaging-helper.py
waja 52fd18c887 Merge pull request #6 from waja/github_ci
Adding initial version of packaging test
2020-11-06 00:19:26 +01:00

332 lines
12 KiB
Python
Executable file

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
import os
import re
from debian import deb822
ALLOWED_FIELDS = ('Suggests',
'Recommends',
'Depends',
'Uploaders',
'Version',
'Homepage',
'Watch',
'Description',
'Build-Depends')
ALLOWED_TESTS_FIELDS = ('Depends',
'Restrictions',
'Tests',
'Test-Command')
# find all plugins
__basedir__ = os.path.realpath(os.path.dirname(sys.argv[0]) + os.path.sep + '..')
__plugins__ = [p for p in os.listdir(__basedir__)
if (os.path.isdir(__basedir__ + os.path.sep + p) and p!='debian' and p!='.git' and p!='.github' and p!='.pc' and p!='redhat')]
__plugins__.sort()
__uploaders_re__ = re.compile(r', *')
__shlibs_re__ = re.compile(r'shlibs:Depends=(.+)')
def __get_control_data__():
# returns (plug, parsed control field data)
# We look at the first paragraph only!
for plugin in __plugins__:
data=(plugin, [x for x in deb822.Packages.iter_paragraphs(open(__basedir__ + os.path.sep+ plugin + os.path.sep + 'control'))][0])
for key in data[1].keys():
if key not in ALLOWED_FIELDS:
raise Exception("Unknown control field in plugin %s: %s" %(data[0],key))
yield data
def __get_tests_data__():
# returns (plug, parsed control field data)
# We look at the first paragraph only!
for plugin in __plugins__:
tests_file = __basedir__ + os.path.sep+ plugin + os.path.sep + 'tests'
if os.path.exists(tests_file):
data=(plugin, [x for x in deb822.Packages.iter_paragraphs(open(tests_file))][0])
for key in data[1].keys():
if key not in ALLOWED_TESTS_FIELDS:
raise Exception("Unknown tests/control field in plugin %s: %s" %(data[0],key))
yield data
def generate_debian_readme_plugins():
plugins_depends={}
for plugin, _control in __get_control_data__():
plugins_depends[plugin]={}
# look trough keys we might want to merge
for key in ['Suggests', 'Recommends']:
if key in _control:
plugins_depends[plugin][key]=deb822.PkgRelation.parse_relations(_control[key])
# check for generated substvars files
substvarsfile = __basedir__ + os.path.sep + 'debian' + os.path.sep + plugin + os.path.sep + 'substvars'
if os.path.exists(substvarsfile):
with open(substvarsfile, 'r') as fd:
substvars = fd.read()
try:
rel = deb822.PkgRelation.parse_relations(__shlibs_re__.findall(substvars)[0])
if 'Recommends' in plugins_depends[plugin]:
plugins_depends[plugin]['Recommends'].extend(rel)
else:
plugins_depends[plugin]['Recommends']=rel
except IndexError:
pass
# generate content
result=[]
for plugin in __plugins__:
if len(plugins_depends[plugin]) > 0:
rtext = '%s:' %(plugin,)
if 'Recommends' in plugins_depends[plugin]:
rtext = '%s\n Required Packages: %s' %(
rtext,
deb822.PkgRelation.str(plugins_depends[plugin]['Recommends'])
)
if 'Suggests' in plugins_depends[plugin]:
rtext = '%s\n Optional Packages: %s' %(
rtext,
deb822.PkgRelation.str(plugins_depends[plugin]['Suggests'])
)
result.append(rtext)
readmefile=__basedir__ + os.path.sep + 'debian' + os.path.sep + 'README.Debian.plugins'
with open(readmefile + '.in', 'r') as fd:
readme=fd.read()
readme=readme.replace('#AUTO_UPDATE_README#', '\n\n'.join(result))
with open(readmefile, 'w') as fd:
fd.write(readme)
def update_control():
control_data = {
'Suggests' : [],
'Recommends' : [],
'Build-Depends' : [],
'Description' : [],
'Uploaders' : []
}
for plugin, _control in __get_control_data__():
# look trough keys we might want to merge
if 'Depends' in _control:
print("Don't use 'Depends' in %s/control - use 'Recommends' instead" %(plugin,))
sys.exit(1)
for key in ['Build-Depends', 'Suggests', 'Recommends']:
if key in _control:
for rel in deb822.PkgRelation.parse_relations(_control[key]):
if not rel in control_data[key]:
control_data[key].append(rel)
# extract description
description = ' * %s' %(plugin,)
if 'Version' in _control:
description = '%s (%s)' %(description, _control['Version'])
try:
description = '%s: %s' %(description, _control['Description'].replace('\n','\n '))
except KeyError:
print('Description for plugin %s missing!' %(plugin,))
sys.exit(1)
try:
for uploader in __uploaders_re__.split(_control['Uploaders']):
if uploader not in control_data['Uploaders']:
control_data['Uploaders'].append(uploader)
except KeyError:
'Uploaders for plugin %s missing!' %(plugin,)
sys.exit(1)
# disables right now. do we want to have the homepage in the description?
# if _control.has_key('Homepage'):
# description = '%s\n Homepage: %s' %(description, _control['Homepage'])
control_data['Description'].append(description)
with open(__basedir__ + os.path.sep + 'debian' + os.path.sep + 'control.in', 'r') as f:
control_in = f.read()
for k, v in control_data.items():
if k == 'Description':
control_in = control_in.replace('#AUTO_UPDATE_Description#', '\n'.join(v))
elif k == 'Uploaders':
control_in = control_in.replace('#AUTO_UPDATE_Uploaders#', ', '.join(v))
else:
control_in = control_in.replace('#AUTO_UPDATE_%s#' %(k, ), deb822.PkgRelation.str(v))
with open(__basedir__ + os.path.sep + 'debian' + os.path.sep + 'control', 'w') as f:
f.write(control_in)
def update_tests():
with open(__basedir__ + os.path.sep + 'debian' + os.path.sep + 'tests' + os.path.sep + 'control', 'w') as f:
f.write("# DO NOT HAND HACK - MANAGED BY debian/packaging-helper.py\n#\n#\n")
for plugin, _control in __get_tests_data__():
if 'Depends' in _control and '@' not in _control['Depends']:
_control['Depends'] += ', @'
f.write(str(_control))
f.write("\n")
def update_copyright():
copyrights = []
for plugin, _control in __get_control_data__():
_p_copyright = '%s:\n\n' %(plugin,)
if 'Homepage' in _control:
_p_copyright = '%sThe plugin was downloaded from: \n%s\n\n' %(_p_copyright, _control['Homepage'])
try:
with open(__basedir__ + os.path.sep + plugin + os.path.sep + 'copyright', 'r') as f:
_p_copyright = '%s %s' %(_p_copyright, f.read().replace('\n','\n '))
except IOError:
print('copyright file for plugin %s missing!' %(plugin,))
sys.exit(1)
copyrights.append(_p_copyright)
with open(__basedir__ + os.path.sep + 'debian' + os.path.sep + 'copyright.in', 'r') as f:
copyright_in = f.read()
copyright_in = copyright_in.replace('#AUTO_UPDATE_Copyright#', '\n\n------------------------------------------------------------------------------\n\n'.join(copyrights))
with open(__basedir__ + os.path.sep + 'debian' + os.path.sep + 'copyright', 'w') as f:
f.write(copyright_in)
def watch():
import apt_pkg
apt_pkg.init_system()
import hashlib
import urllib.request, urllib.error, urllib.parse
url_opener = urllib.request.build_opener()
url_opener.addheaders = [('User-agent', 'Debian nagios-plugins-contrib 1.0')]
watch_re = re.compile(r'([^ ]+) (.+)')
whitespace_re = re.compile(r'\s')
for plugin, _control in __get_control_data__():
if 'Watch' not in _control:
print('WARNING: %s - missing watch information!' %(plugin,))
continue
try:
url, check = watch_re.findall(_control['Watch'])[0]
except IndexError:
print('WARNING: %s - failed to parse Watch line!' %(plugin,))
continue
try:
f=url_opener.open(url)
content = f.read().decode('utf-8')
f.close()
except IOError:
print('WARNING: %s - failed to retrieve %s !' %(plugin,url))
continue
check=check.strip()
if check.startswith('SHA1:'):
check=check.replace('SHA1:','')
new_sha=hashlib.sha1(content).hexdigest()
if check != new_sha:
print('UPDATE NECESSARY: %s - SHA1 checksum does not match! New checksum: %s' %(plugin,new_sha))
else:
print('OK: %s' %(plugin,))
else:
if 'Version' not in _control:
print('WARNING: %s - missing current version information!' %(plugin,))
continue
check_re=re.compile(check)
# check for simple matches
found_versions=check_re.findall(content)
# now also see if the regexp author added too many .* parts and the match is a bit buggy
# we replace all whitespaces with \n and try again.
for v in check_re.findall(whitespace_re.sub('\n',content)):
if not v in found_versions:
found_versions.append(v)
if not found_versions:
print("WARNING: %s - regex does not match!" %(plugin))
continue
new_version = found_versions[0]
for v in found_versions:
if (apt_pkg.version_compare(v, found_versions[0]) > 0):
new_version = v
if (apt_pkg.version_compare(new_version, _control['Version'].strip()) > 0):
print('UPDATE NECESSARY: %s - found new version %s' %(plugin, new_version))
elif (apt_pkg.version_compare(new_version, _control['Version'].strip()) < 0):
print('WARNING: %s - could not find the current version (found: %s, control says: %s)!' %(plugin, new_version, _control['Version']))
else:
print('OK: %s' %(plugin,))
if __name__ == '__main__':
from optparse import OptionParser
prog = os.path.basename(sys.argv[0])
usage = ('%s [--copyright] [--control] [--watch] [--generate-readme] [-h|--help]') %(prog,)
parser = OptionParser(usage=usage)
parser.add_option(
'--copyright',
dest='copyright',
action='store_true',
default=False,
help='Update debian/copyright'
)
parser.add_option(
'--control',
dest='control',
action='store_true',
default=False,
help='Update debian/control'
)
parser.add_option(
'--tests',
dest='tests',
action='store_true',
default=False,
help='Update debian/tests/control'
)
parser.add_option(
'--watch',
dest='watch',
action='store_true',
default=False,
help='Search for updates'
)
parser.add_option(
'--generate-readme',
dest='generate_readme',
action='store_true',
default=False,
help='Generate debian/README.Debian.plugins'
)
(options, args) = parser.parse_args()
if not (options.control or options.copyright or options.watch or options.tests or options.generate_readme):
parser.print_help()
sys.exit(1)
if options.control:
update_control()
if options.tests:
update_tests()
if options.copyright:
update_copyright()
if options.watch:
watch()
if options.generate_readme:
generate_debian_readme_plugins()