Compare commits

...

49 Commits

Author SHA1 Message Date
Matthew Johnson a5b085e2cc Release v1.1.4
This release introduces safeguards to remove directories from the
package file list to protect against top-level directories being
included in packages (such as /usr). The build.log files are now saved
to the target directory for each failed build attempt. The urlban is now
respected when writing metadata to options.conf.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-11-07 16:44:11 -08:00
Matthew Johnson e34b4e9315 Respect urlban when writing metadata to options.conf
This also requires moving the read_config_opts() call to after
autospec.conf is read so the urlban is populated.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-11-07 14:27:12 -08:00
Matthew Johnson 7c4e0e9fd6 Do not clean any files with a directive
Use a regular expression in order to exclude all directives at the
beginning of the filename, including %doc.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-11-07 13:54:50 -08:00
Matthew Johnson a2b467e6b0 Do not attempt to clean "%dir" files
When cleaning directories from the package file lists do not attempt to
clean "%dir" prefixed files. Although autospec does not currently
support empty directories, it could in the future.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-11-07 13:54:50 -08:00
Matthew Johnson 7d7263d684 Remove directories from file list
Clean directories from package file lists. If directories are
encountered, print a warning, add the directory to the blacklist, and
re-run.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-11-07 13:54:50 -08:00
Matthew Johnson 7591bb9d25 Save build.log files from failed rounds
This is useful for debugging purposes. The file must be saved to the
target directory since the results directory is wiped on each round.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-11-07 11:32:21 -08:00
Matthew Johnson 9b8ef511d2 Add coverage statistics to unittest runs
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-11-07 11:04:46 -08:00
Matthew Johnson 52a48c0c69 Release v1.1.3
This release makes some small updates to our README documentation,
improves tarball.py and pkg_integrity.py testing, fixes a bug that
allowed an empty file to remain on failed downloads, and adds a regular
expression for build.log test scanning.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-11-02 11:20:40 -07:00
Matthew Johnson 5d722054e9 Add regular expression for vim tests
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-11-02 11:05:11 -07:00
Gabi Beyer e13d3edb03 Remove network dependencies for pkg_integrity test
Create a mock function that copies files from the testfiles
directory to a tmp directory, when attempting to download
files from the network.

Create a mock function for head_request that returns 404 for
a few specified urls, and 200 for the rest.

The mock calls will allow the functionality of the pkg_integrity
program to be tested and not dependent on networking. Tests will
no longer need to be skipped in travis with the removal of
network dependency.

Removed a few tests that were not specific to pkg_integrity, but
instead were testing the importing and exporting abilities
of the gpg key server.

Added mock as a requirement to the requirements.txt file.

Signed-off-by: Gabi Beyer <gabib@live.com>
2017-11-01 16:58:58 -07:00
Matthew Johnson 55feeec051 Remove empty download file on pycurl failure
Fixes #26

Remove empty file created when a download fails. The empty file caused
autospec to fail on consecutive runs due to autospec attempting to reuse
the file when it exists.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-27 15:20:16 -07:00
Brett T. Warden 7fa9e21b83 Add/enhance test cases for giturl
Add test cases for empty/null giturl. Add message to case when regex
fails to match.

Signed-off-by: Brett T. Warden <brett.t.warden@intel.com>
2017-10-26 14:34:08 -07:00
Brett T. Warden 3db36c3093 tarball: Use repo name only if more descriptive
For github URLs, only use the repo name as the package name if it's more
descriptive than what was extracted from the tarball name. Otherwise,
filter off prefix "release-" or a numeric suffix.

Signed-off-by: Brett T. Warden <brett.t.warden@intel.com>
2017-10-26 14:34:08 -07:00
Brett T. Warden 0eb744f788 tarball: de-conflate github repo and package name
For github URLs, capture and identify repo name separately from package
name. This is a building block for resolving cases where the package
name is actually different than the github repo name.

Signed-off-by: Brett T. Warden <brett.t.warden@intel.com>
2017-10-26 14:34:08 -07:00
Brett T. Warden 17fa67533f tarball: extend github URL match patterns
Extend the regular expressions used to match github URLs. Covers
additional cases found in the wild.

Signed-off-by: Brett T. Warden <brett.t.warden@intel.com>
2017-10-26 14:34:08 -07:00
Brett T. Warden 5132520108 Add test for giturl generation
For github URLs in tests/packageurls, check that we produce a giturl
that looks reasonably correct.

Signed-off-by: Brett T. Warden <brett.t.warden@intel.com>
2017-10-26 14:34:08 -07:00
William Douglas ff87f71be3 Add additional build_pattern options to README
Adds R, perl, ruby, and Java build pattern targets.
2017-10-24 10:38:14 -07:00
Brett T. Warden e9e9b5de2a Fix formatting --target option
Add missing comma to --target help text, fixing formatting to match previous command-line options.
2017-10-23 16:59:54 -07:00
Matthew Johnson 67924c9b17 Release v1.1.2
This release improves automated commit message guesses using the git
shortlog for the updated package. It also adds a --no-prep option that
downloads the sources, does the basic name and version detection, and
puts metadata in the <targetdir>/workingdir directory for human or tool
consumption before exiting without writing to the spec file.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-23 15:33:34 -07:00
Matthew Johnson 6017beb8f1 Honor the urlban during --prep-only
Also move the prep work into its own function to make it easier to
manage if it continues to grow.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-23 15:33:19 -07:00
Matthew Johnson 10090b8d2e Save name, version, url to workingdir for prep-only
Save the package metadata to the ./workingdir directory for --prep-only
runs.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-23 15:33:19 -07:00
Matthew Johnson d4e78abc6c Remove unused "output" directory
Since moving output to a temporary directory, the "output" directory has
fallen out of use. Remove the output directory from autospec.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-23 15:33:19 -07:00
Matthew Johnson a2967f2ea2 Add --prep-only option to run preparatory work only
For non-autospec enabled packages this option can be used to download
the upstream tarball, any specified archives, extract them and put the
archives at their destination, and update the upstream file, but not
actually attempt to build a specfile.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-23 15:33:19 -07:00
Matthew Johnson 32aa9c70ff Ignore bare excepts with flake8
The previous ignore, import not at top of file (E402) was unneeded. Bare
excepts are handy when we want to fail gracefully from any error. This
is a script, not an imported library.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-23 12:08:01 -07:00
Arjan van de Ven 9f049a5dcc add an empty line in order to make git happy 2017-10-23 08:19:25 -07:00
Arjan van de Ven 6d2bf1f784 improve guess heuristics to add exact matches for tags 2017-10-23 08:19:25 -07:00
Arjan van de Ven 557c0473a2 deal with git repos that do not match the package name 2017-10-23 08:19:25 -07:00
Arjan van de Ven 2f84e0eaa4 fix CI errors 2017-10-23 08:19:25 -07:00
Arjan van de Ven dc36372472 support git shortlog from upstream git for creating commit messages 2017-10-23 08:19:25 -07:00
Arjan van de Ven e378f9dfa9 add support for a giturl to autospec 2017-10-21 19:29:17 +00:00
Matthew Johnson 8bc25eebe3 Release v1.1.1
This release adds quoting ("") around filenames with whitespace in them.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-19 14:23:45 -07:00
Brett T. Warden 4004cffc23 specfiles: Quote filenames
In %files sections, double-quote any filenames containing a space or
tab. Uses a regex to detect and not quote rpm directive prefixes.

Fixes #32.

Signed-off-by: Brett T. Warden <brett.t.warden@intel.com>
2017-10-19 14:05:39 -07:00
Brett T. Warden a3589e1a70 tests: add leading slash to test filenames
Tests for the %files section use bare file names. Since rpmbuild
requires leading slashes anyway, adding slashes to some of the tests.

Adding new tests for filenames with white space and/or rpm directives.

Signed-off-by: Brett T. Warden <brett.t.warden@intel.com>
2017-10-19 14:05:39 -07:00
Matthew Johnson 1e1a8af5d3 Release v1.1.0
This release greatly improves version and package name detection and
adds over 1900 package URL tests for this feature. Package metadata is
now written to options.conf under the 'package' section. A Makefile is
still being written to, but this is deprecated and will be removed in
the future. The mock command is now detected in a manner compatible with
linux distributions other than Clear Linux.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-18 12:50:09 -07:00
Matthew Johnson 4c9004d398 Simplify URL version and name detection
Fix up several regular expressions and remove unused ones. Move as much
string replacing to string.replace() functions instead of slow regular
expressions.

Remove the pypi.python.org -> pypi.debian.net url conversion
(pypi.debian.net keeps going down).

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-18 12:39:12 -07:00
Matthew Johnson 7acd27bea2 Add the world to tests/packageurls
Test almost 2000 URLs for proper version and name detection. This list
is sorted by the second column (expected name).

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-18 12:39:12 -07:00
Caio Marcelo de Oliveira Filho cc57b39872 Remove use of global variable for mock_cmd
Rename set_mock to get_mock_cmd, and return the value instead of
setting a global variable.

This patch should not change any behavior.

Signed-off-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
2017-10-18 12:33:15 -07:00
Caio Marcelo de Oliveira Filho 1574477167 Change how to decide whether use sudo or not with mock
Use 'sudo' unless /usr/bin/mock points to consolehelper. This is a
simpler heuristic than checking for the group membership and will let
us use the group membership in Clear Linux to give sudo permissions.

Signed-off-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
2017-10-18 12:33:15 -07:00
Simental Magana, Marcos c61c9328ff keyring: add TingPing key for hexchat package sig.
Signed-off-by: Simental Magana, Marcos <marcos.simental.magana@intel.com>
2017-10-18 08:52:42 -07:00
Matthew Johnson a972ddf932 Read metadata from options.conf for local run
Instead of requiring the url argument and guessing where to put the
results from an autospec run, read metadata from options.conf. The
'package' section in options.conf defines the package name, url, and
archives when available.

If options.conf is present and there is at least one match between
detected metadata from the source tarball and the metadata in the
configuration, assume that the target directory is the current
directory. This is overridable with the -t/--target option. If nothing
matches the target directory is <current_dir>/<package_name>.

This functionality allows user to run autospec within the target
directory without passing any arguments, including the previously
required "url" argument if the metadata is present.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-16 16:07:14 -07:00
Matthew Johnson b9017aba4a Write package metadata to options.conf
Deprecate writing to a Makefile in the package directory and write to
the options.conf file instead. Any other infrastructure that needs a
Makefile should write it itself.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-16 16:07:14 -07:00
Matthew Johnson 1f0545ccaa Add regex to handle font packages
Adobe font packages have -nndpi as part of the name. Add tests and a
regular expression to capture these.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-16 15:26:34 -07:00
Matthew Johnson 673ba4fd4c Skip debian pkg_integrity tests in Travis
Debian is down again, and we've seen them go down in the past. We
shouldn't be running these tests in Travis.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-16 14:54:34 -07:00
Matthew Johnson 82f816a731 Release v1.0.3
This release adds the "-C/--cleanup" flag to clean up the mock chroots
after a build. It also ensures that mock will build unique chroots for
each build, useful for automation environments where autospec is run in
parallel.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-11 15:43:31 -07:00
Matthew Johnson 6576660c5e Enable sudo in travis and fix linter error
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-11 15:38:14 -07:00
Matthew Johnson 91df2fc823 Add argument to make mock clean up after itself
Add -C/--cleanup to tell mock to clean up the chroot after it completes
the build. This is useful for wrapping programs which run several
instances of autospec automatically. Use this flag to determine when we
actually need a unique uniqueext (automation environments) and when
those uniquexts can be reused (developer running one-offs).

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-11 15:38:14 -07:00
Matthew Johnson 8b56c225b1 Create mock chroot with a unique uniqueext
This prevents collisions when two instances are trying to build the same
package in parallel. Unit tests added as well.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-11 15:38:14 -07:00
Matthew Johnson e621984478 Release v1.0.2
Allow users to specify requires that are not dropped during existence
detection and os-packages list checking.

Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
2017-10-10 14:41:21 -07:00
William Douglas fa1e7951fe Allow manual override of requires
Allow developers to specify Requres that will not be dropped during
existence detection normally done for auto-detecting runtime
requirements.
2017-10-10 14:40:50 -07:00
33 changed files with 2662 additions and 398 deletions
+2
View File
@@ -3,3 +3,5 @@ __pycache__
*~
*.swp
tags
.coverage
htmlcov
+5
View File
@@ -1,6 +1,11 @@
language: python
sudo: enabled
python:
- "3.6"
install:
- pip install -r requirements.txt
# command to run tests
script:
- make check
+5 -2
View File
@@ -1,5 +1,5 @@
check: autospec/*.py
@flake8 --max-line-length=199 --ignore=E402 $^
@flake8 --max-line-length=199 --ignore=E722 $^
test_pkg_integrity:
PYTHONPATH=${CURDIR}/autospec python3 tests/test_pkg_integrity.py
@@ -47,4 +47,7 @@ test_autospec:
python3 tests/test_autospec.py -c ${CASES}
unittests:
PYTHONPATH=${CURDIR}/autospec python3 -m unittest discover -b -s tests -p 'test_*.py'
PYTHONPATH=${CURDIR}/autospec coverage run -m unittest discover -b -s tests -p 'test_*.py' && coverage report
coverage:
coverage report -m
+5 -1
View File
@@ -68,7 +68,7 @@ Usage: ``python3 autospec.py [options] URL``
-l, --license-only Only scan for license files
-b, --skip-bump Don't bump release number
-c CONFIG, --config CONFIG Set configuration file to use
-t DIRECTORY --target DIRECTORY Set location to create or use
-t DIRECTORY, --target DIRECTORY Set location to create or use
@@ -220,6 +220,10 @@ Controlling the build process
work for the given package. This one line file allows you to override the
build pattern that ``autospec`` will use. The supported build_pattern types are:
- R: R language package
- cpan: perl language package
- ruby: ruby language package
- maven: Java language package
- configure: Traditional ``%configure`` autotools route
- configure_ac: Like ``configure, but performs ``%reconfigure`` to regenerate ``./configure``
- autogen: Similar to ``configure_ac`` but uses the existing ``./autogen.sh`` instead of ``%reconfigure``
+102 -10
View File
@@ -19,8 +19,10 @@
import argparse
import sys
import os
import shutil
import re
import tempfile
import configparser
import build
import buildpattern
@@ -97,6 +99,57 @@ def load_specfile(specfile):
test.load_specfile(specfile)
def read_old_metadata():
if not os.path.exists(os.path.join(os.getcwd(), 'options.conf')):
return None, None, []
config_f = configparser.ConfigParser()
config_f.read('options.conf')
if "package" not in config_f.sections():
return None, None, []
archives = config_f["package"].get("archives")
archives = archives.split() if archives else []
print("ARCHIVES {}".format(archives))
return (config_f["package"].get("name"),
config_f["package"].get("url"),
archives)
def save_build_log(path, iteration):
"""
Save build log to <path>/build.log.round<iteration>
Must be saved outside of the results/ directory since it gets wiped away on
each round.
"""
buildlog = os.path.join(path, "results", "build.log")
shutil.copyfile(buildlog, "{}/build.log.round{}".format(path, iteration))
def write_prep(workingdir):
"""
Write metadata to the local workingdir when --prep-only is used
"""
if config.urlban:
used_url = re.sub(config.urlban, "localhost", tarball.url)
else:
used_url = tarball.url
print()
print("Exiting after prep due to --prep-only flag")
print()
print("Results under ./workingdir")
print("Source (./workingdir/{})".format(tarball.tarball_prefix))
print("Name (./workingdir/name) :", tarball.name)
print("Version (./workingdir/version) :", tarball.version)
print("URL (./workingdir/source0) :", used_url)
write_out(os.path.join(workingdir, "name"), tarball.name)
write_out(os.path.join(workingdir, "version"), tarball.version)
write_out(os.path.join(workingdir, "source0"), used_url)
def main():
"""
Main function for autospec
@@ -109,7 +162,7 @@ def main():
help="Override the package name")
parser.add_argument("-v", "--version", action="store", dest="version", default="",
help="Override the package version")
parser.add_argument("url",
parser.add_argument("url", default="", nargs="?",
help="tarball URL (e.g."
" http://example.com/downloads/mytar.tar.gz)")
parser.add_argument('-a', "--archives", action="store",
@@ -134,14 +187,39 @@ def main():
default=False,
help="Search for package signature from source URL and "
"attempt to verify package")
parser.add_argument("-p", "--prep-only", action="store_true",
default=False,
help="Only perform preparatory work on package")
parser.add_argument("--non_interactive", action="store_true",
default=False,
help="Disable interactive mode for package verification")
parser.add_argument("-C", "--cleanup", dest="cleanup", action="store_true",
default=False,
help="Clean up mock chroot after building the package")
args = parser.parse_args()
if len(args.archives) % 2 != 0:
parser.error(argparse.ArgumentTypeError(
"-a/--archives requires an even number of arguments"))
name, url, archives = read_old_metadata()
name = args.name or name
url = args.url or url
archives = args.archives or archives
if not url:
parser.error(argparse.ArgumentTypeError(
"the url argument or options.conf['package']['url'] is required"))
if len(archives) % 2 != 0:
parser.error(argparse.ArgumentTypeError(
"-a/--archives or options.conf['package']['archives'] requires an "
"even number of arguments"))
if args.prep_only:
package(args, url, name, archives, "./workingdir")
else:
with tempfile.TemporaryDirectory() as workingdir:
package(args, url, name, archives, workingdir)
def package(args, url, name, archives, workingdir):
check_requirements(args.git)
build.setup_workingdir(workingdir)
@@ -150,7 +228,7 @@ def main():
# of static analysis on the content of the tarball.
#
filemanager = files.FileManager()
tarball.process(args.url, args.name, args.version, args.target, args.archives, filemanager)
tarball.process(url, name, args.version, args.target, archives, filemanager)
_dir = tarball.path
if args.license_only:
@@ -170,12 +248,16 @@ def main():
config.parse_config_files(build.download_path, args.bump, filemanager)
config.parse_existing_spec(build.download_path, tarball.name)
if args.prep_only:
write_prep(workingdir)
exit(0)
buildreq.set_build_req()
buildreq.scan_for_configure(_dir)
specdescription.scan_for_description(tarball.name, _dir)
license.scan_for_licenses(_dir)
commitmessage.scan_for_changes(build.download_path, _dir)
add_sources(build.download_path, args.archives)
add_sources(build.download_path, archives)
test.scan_for_tests(_dir)
#
@@ -191,18 +273,29 @@ def main():
if args.integrity:
interactive_mode = not args.non_interactive
pkg_integrity.check(args.url, build.download_path, interactive=interactive_mode)
pkg_integrity.check(url, build.download_path, interactive=interactive_mode)
pkg_integrity.load_specfile(specfile)
specfile.write_spec(build.download_path)
while 1:
build.package(filemanager)
build.package(filemanager, args.cleanup)
filemanager.load_specfile(specfile)
specfile.write_spec(build.download_path)
filemanager.newfiles_printed = 0
mock_chroot = "/var/lib/mock/clear-{}/root/builddir/build/BUILDROOT/" \
"{}-{}-{}.x86_64".format(build.uniqueext,
tarball.name,
tarball.version,
tarball.release)
if filemanager.clean_directories(mock_chroot):
# directories added to the blacklist, need to re-run
build.must_restart += 1
if build.round > 20 or build.must_restart == 0:
break
save_build_log(build.download_path, build.round)
test.check_regression(build.download_path)
if build.success == 0:
@@ -235,5 +328,4 @@ def main():
if __name__ == '__main__':
with tempfile.TemporaryDirectory() as workingdir:
main()
main()
+60 -19
View File
@@ -23,8 +23,8 @@ import buildreq
import re
import tarball
import os
import grp
import shutil
import subprocess
import config
import util
@@ -33,18 +33,15 @@ success = 0
round = 0
must_restart = 0
base_path = None
output_path = None
download_path = None
mock_cmd = '/usr/bin/mock'
uniqueext = ''
def setup_workingdir(workingdir):
global base_path
global output_path
global download_path
base_path = workingdir
output_path = os.path.join(base_path, "output")
download_path = os.path.join(output_path, tarball.name)
download_path = os.path.join(base_path, tarball.name)
def simple_pattern_pkgconfig(line, pattern, pkgconfig):
@@ -164,29 +161,73 @@ def parse_build_results(filename, returncode, filemanager):
success = 1
def set_mock():
global mock_cmd
# get group list of current user
user_grps = [grp.getgrgid(g).gr_name for g in os.getgroups()]
if os.path.exists('/usr/bin/mock'):
if 'mock' not in user_grps:
mock_cmd = 'sudo /usr/bin/mock'
def reserve_path(path):
try:
subprocess.check_output(['sudo', 'mkdir', path], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as err:
out = err.output.decode('utf-8')
return "File exists" not in out
return True
def package(filemanager):
def get_uniqueext(dirn, dist, name):
"""
Find a unique name to create mock chroot without reusing an old one
"""
# Default to tarball name
resultsdir = os.path.join(dirn, "{}-{}".format(dist, name))
if reserve_path(resultsdir):
return name
# Find a unique extension by checking if it exists in /var/lib/mock
# Increment the pathname until an unused path is found
resultsdir += "-1"
seq = 1
while not reserve_path(resultsdir):
seq += 1
resultsdir = resultsdir.replace("-{}".format(seq - 1), "-{}".format(seq))
return "{}-{}".format(name, seq)
def get_mock_cmd():
# Some distributions (e.g. Fedora) use consolehelper to run mock,
# while others (e.g. Clear Linux) expect the user run it via sudo.
if os.path.basename(os.path.realpath('/usr/bin/mock')) == 'consolehelper':
return '/usr/bin/mock'
return 'sudo /usr/bin/mock'
def package(filemanager, cleanup=False):
global round
global uniqueext
round = round + 1
set_mock()
mock_cmd = get_mock_cmd()
print("Building package " + tarball.name + " round", round)
# call(mock_cmd + " -q -r clear --scrub=cache")
# call(mock_cmd + " -q -r clear --scrub=all")
# determine uniqueext only once
if cleanup:
uniqueext = uniqueext or get_uniqueext("/var/lib/mock", "clear", tarball.name)
cleanup_flag = "--cleanup-after"
else:
uniqueext = tarball.name
cleanup_flag = "--no-cleanup-after"
print("{} mock chroot at /var/lib/mock/clear-{}".format(tarball.name, uniqueext))
shutil.rmtree('{}/results'.format(download_path), ignore_errors=True)
os.makedirs('{}/results'.format(download_path))
util.call(mock_cmd + " -r clear --buildsrpm --sources=./ --spec={0}.spec --uniqueext={0} --result=results/ --no-cleanup-after".format(tarball.name),
util.call("{} -r clear --buildsrpm --sources=./ --spec={}.spec "
"--uniqueext={} --result=results/ {}"
.format(mock_cmd, tarball.name, uniqueext, cleanup_flag),
logfile="%s/mock_srpm.log" % download_path, cwd=download_path)
util.call("rm -f results/build.log", cwd=download_path)
srcrpm = "results/%s-%s-%s.src.rpm" % (tarball.name, tarball.version, tarball.release)
returncode = util.call(mock_cmd + " -r clear --result=results/ %s --enable-plugin=ccache --uniqueext=%s --no-cleanup-after" % (srcrpm, tarball.name),
returncode = util.call("{} -r clear --result=results/ {} "
"--enable-plugin=ccache --uniqueext={} {}"
.format(mock_cmd, srcrpm, uniqueext, cleanup_flag),
logfile="%s/mock_build.log" % download_path, check=False, cwd=download_path)
# sanity check the build log
if not os.path.exists(download_path + "/results/build.log"):
+2 -2
View File
@@ -72,7 +72,7 @@ def add_buildreq(req):
return new
def add_requires(req):
def add_requires(req, override=False):
"""
Add req to the global requires set if it is present in buildreqs and
os_packages and is not banned.
@@ -84,7 +84,7 @@ def add_requires(req):
new = False
if req in banned_requires:
return False
if req not in buildreqs and req not in config.os_packages:
if req not in buildreqs and req not in config.os_packages and not override:
if req:
print("requirement '{}' not found is buildreqs or os_packages, skipping".format(req))
return False
+55 -1
View File
@@ -32,6 +32,8 @@ import config
import tarball
import util
from subprocess import PIPE, run
def scan_for_changes(download_path, directory):
"""
@@ -168,6 +170,54 @@ def process_NEWS(newsfile):
return commitmessage, cves
def process_git(giturl, oldversion, newversion):
"""
process_git() checks out a git tree and tries to turn the
git history into a commit message
"""
oldtag = ""
guessed_oldtag = oldversion
newtag = ""
guessed_newtag = newversion
if len(giturl) < 1:
return ""
if oldversion == newversion:
return ""
run(["git", "-C", "results", "clone", giturl, tarball.name])
p = run(["git", "-C", "results/" + tarball.name, "tag"], stdout=PIPE)
tags = p.stdout.decode('utf-8').split('\n')
for t in tags:
i = t.find(oldversion)
if i != -1:
guessed_oldtag = t
if t == oldversion or t == "v" + oldversion:
oldtag = t
i = t.find(newversion)
if i != -1:
guessed_newtag = t
if t == newversion or t == "v" + newversion:
newtag = t
if oldtag == "":
oldtag = guessed_oldtag
if newtag == "":
newtag = guessed_newtag
p = run(["git", "-C", "results/" + tarball.name, "log", oldtag + ".." + newtag], stdout=PIPE)
fulllog = p.stdout.decode('utf-8').split('\n')
p = run(["git", "-C", "results/" + tarball.name, "shortlog", oldtag + ".." + newtag], stdout=PIPE)
shortlog = p.stdout.decode('utf-8').split('\n')
if len(fulllog) < 15:
return fulllog
else:
return shortlog
def guess_commit_message():
"""
guess_commit_message() parses newsfiles and determines a sane commit
@@ -199,6 +249,10 @@ def guess_commit_message():
if config.old_version is not None and config.old_version != tarball.version:
commitmessage.append("{}: Autospec creation for update from version {} to version {}"
.format(tarball.name, config.old_version, tarball.version))
if tarball.giturl != "":
gitmsg = process_git(tarball.giturl, config.old_version, tarball.version)
commitmessage.append("")
commitmessage.extend(gitmsg)
else:
if cves:
commitmessage.append("{}: Fix for {}"
@@ -224,7 +278,7 @@ def guess_commit_message():
commitmessage.append("")
util.write_out(os.path.join(build.download_path, "commitmsg"),
"\n".join(commitmessage) + "\n", encode="latin-1")
"\n".join(commitmessage) + "\n")
print("Guessed commit message:")
try:
+26 -3
View File
@@ -268,11 +268,32 @@ failed_pats = [
r"available", 0, 'maven')]
def get_metadata_conf():
"""
gather package metadata from the tarball module
"""
metadata = {}
metadata['name'] = tarball.name
if urlban:
metadata['url'] = re.sub(urlban, "localhost", tarball.url)
else:
metadata['url'] = tarball.url
metadata['archives'] = ' '.join(tarball.archives)
metadata['giturl'] = tarball.giturl
return metadata
def create_conf(path):
"""
Create options.conf file. Use deprecated configuration files or defaults to populate
"""
config_f = configparser.ConfigParser(allow_no_value=True)
# first the metadata
config_f['package'] = get_metadata_conf()
# next the options
config_f['autospec'] = {}
for fname, comment in sorted(config_options.items()):
config_f.set('autospec', '# {}'.format(comment))
@@ -326,6 +347,7 @@ def rewrite_config_opts(path):
Rewrite options.conf file when an option has changed (verify_required for example)
"""
config_f = configparser.ConfigParser(allow_no_value=True)
config_f['package'] = get_metadata_conf()
config_f['autospec'] = {}
# Populate missing configuration options
@@ -466,8 +488,6 @@ def parse_config_files(path, bump, filemanager):
packages_file = None
read_config_opts(path)
# Require autospec.conf for additional features
if os.path.exists(config_file):
config = configparser.ConfigParser(interpolation=None)
@@ -489,6 +509,9 @@ def parse_config_files(path, bump, filemanager):
urlban = config['autospec'].get('urlban', None)
# Read values from options.conf (and deprecated files) and rewrite as necessary
read_config_opts(path)
if not git_uri:
print("Warning: Set [autospec][git] upstream template for git support")
if not license_fetch:
@@ -577,7 +600,7 @@ def parse_config_files(path, bump, filemanager):
content = read_conf_file(os.path.join(path, "requires_add"))
for extra in content:
print("Adding additional runtime requirement: %s." % extra)
buildreq.add_requires(extra)
buildreq.add_requires(extra, override=True)
content = read_conf_file(os.path.join(path, "excludes"))
for exclude in content:
+7
View File
@@ -1104,6 +1104,13 @@ def parse_log(log, pkgname=''):
total_fail += convert_int(match.group(3))
continue
# vim
# Executed 9 tests
match = re.search(r"Executed ([0-9]+) tests$", line)
if match and incheck:
total_tests += convert_int(match.group(1))
continue
# rubygem-formatador
# 9 succeeded in 0.00375661 seconds
match = re.search(r"([0-9]+) succeeded in [0-9]+\.[0-9]+ seconds", line)
+42
View File
@@ -23,6 +23,8 @@ import build
import tarball
import config
import re
import os
import util
from collections import OrderedDict
# todo package splits
@@ -101,6 +103,46 @@ class FileManager(object):
else:
return False
def _clean_dirs(self, root, files):
"""
Do the work to remove the directories from the files list
"""
res = set()
removed = False
directive_re = re.compile("(%\w+(\([^\)]*\))?\s+)(.*)")
for f in files:
# skip the files with directives at the beginning, including %doc
# and %dir directives.
# autospec does not currently support adding empty directories to
# the file list by prefixing "%dir". Regardless, skip these entries
# because if they exist at this point it is intentional (i.e.
# support was added).
if directive_re.match(f):
res.add(f)
continue
if os.path.isdir(os.path.join(root, f.lstrip("/"))):
util.print_warning("Removing directory {} from file list".format(f))
self.files_blacklist.add(f)
removed = True
else:
res.add(f)
return (res, removed)
def clean_directories(self, root):
"""
Remove directories from file list
"""
removed = False
for pkg in self.packages:
self.packages[pkg], _rem = self._clean_dirs(root, self.packages[pkg])
if _rem:
removed = True
return removed
def push_file(self, filename):
"""
Perform a number of checks against the filename and push the filename
+86
View File
@@ -0,0 +1,86 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFL9JHIBEADDKL+vc3MHctXCWxG0IcuLPm4i+WO9jH6MdF8p2bokaL5lilcJ
o2i0RHImP83FpqCDj/hE7AeB3Ix3Oq3tIe6lpCz468OVbLivErX/yL8rYUhC+yba
zlSJcBipTIezD3pZI/vpFyCIC8mSEI4PJGiLotioNJWQBStQuuPqMKo4cd6cRWx6
WovQMKa85rQPvv+wYCseBqU6xBx1xSgpkjDJnAH7We5G6T8TYVM2gqXtii/JYyUC
8E7Z2BBdSGkq1Dma1W6paOw7VOtLu6YbAH9v/VUVx0UdzwiyXHQ8qLKbxeXkex9d
zoe+oy8wt3bvVHirxU42IlJJVLY4NcUYhr/xOq/YqT+3sWAqgdVM/WnzY3bPiMnQ
XqQ3UZ0LKXXsF2+9u2qM6FTiAHIMLtH95IlOQo1qXmDl1HRJTNq3B41UduLDRUhP
uGBaXbOtb6ql4nV3/BTxcHumisMh5ALhqXHRNOdn+mEjvT2HT6pp07ZfVhFwM4U0
K78f52S+NppiS0cWtn9ibq+UmqZyvw9HMOHYt51lSUOueg/sOvsxrG1gjvcUMlJw
nCgS3b+QUmZYo+pl/l13fiWPQpteVGZqKPMBBaQ4MCrwHgvikN8uppKDw8fFGs44
LgbCsDoQA8wKxNzMEMTvuhFFgCiOxMCzR0XKxlcKr8CiHZjYwovJLFfLvwARAQAB
tCVUaW5nUGluZyA8dGluZ3BpbmdAZmVkb3JhcHJvamVjdC5vcmc+iQIcBBABCAAG
BQJXCDvTAAoJEJl85gUEYfxXa6IP/jiLYg/YD73KOSs50K5TjdZq667SDtUEKo7d
n6RSewoVHCNqWlDoI5njVBmmzXNAQsf25SSJ7IGwxMDEoc/u+Ft/bxX3rZoOBGF+
CjH4Z76hlKHVUI9X4Zj+j6dZoImxFQLxFcGxNrN0hZedM4YFVBoJX/8D0foLRlnG
wBmOXRBO1P1EBQU/vKBnFeYsrL5jNOLqh6CNcUochPxHQSNfj4y02mVmA824Xcb/
d1IPCvshOw/hIyniMxpyE+2IgFFZHKDeqR6AidV/0y6BNOUoz4MOwzizn5QDuoBq
pW4plMdTwJ/CqcZ/Hu9IGNC+tRkhvG8NvvN21K5Vxy1915znIoRkF/zQmSqOYucq
/7uaAU+0ey4ESRU0BT0REYW1Q8BGFOtCKgUsZ0XupRo+ix9MkgbBaeYYDY72gLef
9DRW1+ARo+okvblYI9155SS3mSwu9N/G6QDJ+YHFtLICG5xqZ8+gm9qWMiKBLD/u
5n+28lsqf1SLjZH9fifmszKneJbO3iZWo79j7BWNFhemlZuam79y0AyNZzQRD+ya
YlP+t3w9FyBt2hkynr75KBDJZj1K4yLcxYR9cUuhfzTiBpzadDOUrMkC3+t7NMfm
dKB6esxIDtd7M0Xq6gYI3Go1kdIa6qY1mk2SNbfzp8JKLdzL+f15/PzjNXDhg2ia
Kan4G6bTiQI+BBMBAgAoBQJS/SRyAhsDBQkJZgGABgsJCAcDAgYVCAIJCgsEFgID
AQIeAQIXgAAKCRCzx84hDedt/GPYD/9fz6uJ1pEJKUKb2o8b1mQk9Qa+rXv7sPm9
x+KnBrjSkwdq3s17OGbEGA8kUSCvxN7+auesq4UfE8bCllB5FhiGwETtWCDUJFc1
bzJAmABAoXskCrUJgn/zDw/MDAtO0uGAhnz1aw1BU17hHORRDOVPqqApE0eSg5gx
N8jjdx3yVvTaanaU7aZzWCqQSkCTda6Hjks0cAljGuPwN7n3ZVzTXO1E1f5DQedG
eMxBTqtorhOW9bxBOUvbJnfHZsMOfvB3gcQKCuRFkxVj051Ua9+u+d70uZuXelFD
agfIAa7SVDy0BxjqSoUYfQJEtdzPvGHVowM6sDJZfM4NrXW4tfZ1opgMklER3Inh
uJSsSU5pJ/gpjWShUR6zn/zfNZ5A2N99TgNmkSfvweCJrQFT9iWGR/Y8k0hav2cg
OJVtu26gXnqNHBQSOXk2wKzl/EAa1BhToIQhdpXXFVwyEzQ57aDFNBzhAflw2k27
y6X61BqoycxIjjeWE8BGRAWHh3lndkkyTxXghhz37/cyjvjWs7vZovRp+w0nMVKb
TFH9MiVXXuOYnTGpnGD90GFAtuPWgIMEPVE9a1lNHTjwgIloUYVQEoZFCakJnihc
q5Sqay7sF8dlgyCgnthfzYAJHmSXNEWVvzCEFeuAffcibO9pEcmTH0PO3Nz0w79E
Ao2VvV/r9LQmUGF0cmljayBHcmlmZmlzIDx0aW5ncGluZ0B0aW5ncGluZy5zZT6J
AhwEEAEIAAYFAljFXSwACgkQmXzmBQRh/Fd9bw//eZs+FsIXDIRTMd1HP8tXd9WW
2rYhFPkdS9Gb4wdsG8hsj16OnOgbkaVxkIE/61YFy8VnnPSQvuqIC6pMD29Eb8m1
3b9hGO4TbP3sQSjqktyrSzBjIaF8Y2pL1B48uuwoglvPRIUbH5YFJfRFS3aGYRYU
hGgPDpZIDXJYLH8tV3vPGFACNqa6JJdWMSr55bV5MEy4TbTCIxXMjKF3OLpqgQYr
xOhIDmdSgJeaD31NnQDXvoK6RidJ1LK6Mw2ct9k0iMG6wZi8ENafL52WtT8SSHxl
15TUZVDyrnmrFe41nnOjKs8BkihcBEfsllnvtM/1qDqFDmBuBUzGeL/gojJ3g6P/
4VSvKkP5ntXY4BH4iCNyqtsBA5qw+UO9TrzNDyICmipJM/xoZ2lYmPmDPHdRY4gv
ObcHMg8TO2P0Z/3g/xriXD3dFgWibUHd41H7wHy7/GEqN0Kzt/yfH9xkxOXJhXrC
MxGf2Imp8BiXjaJ+28iUU1CpKPx3dYq3rIjB/7P85yo3DnYoJadwwQcrrm36Q2qn
WRbKbm5fKJsJQBe0hZ8zC3excKU3XhCAP1YvXsPa25MEVgrP4el13Ddh82h+Lm2z
d3rOzMZwJ/1uJtsYD+PXoQVpl+GotKjHfg9PLL7MOjde8pEZr+QdliJyyVUxyUZq
/IP2/nY/GOni4rspxw6JAjwEEwEIACcFAlfNKA4CGwMFCQlmAYAFCwkIBwIGFQgJ
CgsCBBYCAwECHgECF4AACgkQs8fOIQ3nbfwcQw/2Lhf3qFhgh3Y/9Anh/nkvWLbu
B7P2LeQ+KVyxA9NKWwKL33Cvn3ofG4H1axe0xCaTFNdYIeEDEAIGkZa3nszchWdr
uPwV6JKKVKNdq3X9wSvdoX+rdkmREsZzXREtH/jlzgQRkKy1L/zhDloP3gNLvQh/
7kPmWih7KFsWd1iLRbsUjBIgTjCzwQRML3lUfsz17qp20BRPMlgJIqxLN0ImjOKR
QZfzmwypmeTRYvgNrrhe1b/Lkciy9N3qFxo0FFAXfsxRmbUdu5h0hhTAkz2rC79G
xfK2txMJh9kUu8AR3p3nUPDtWn1W8vATuElZc+QyGlFBGUgrayeyQXtvZNo/6C6t
3YJFViRUmA/OaJD6wyF1/7T7niW9wUczlZiybMNhuXxTaqGGUE9hKaDN9dIFmbT+
1IO+pLh02pBp4W2fQy20mprUnsVQyqcPTTiTysuAWzzy3rdjT80/92y0MNBwILWx
nsNToCN+Lbr07UiOV5Tgu5/SemvgVDl4leofzB/qr3S3RUtTeQrRrEfB9BF51mSZ
epCrut2wHPvjVFr2UyMq2sspr+6wmcfq+bsdduAKt8prE046WPt2+YSMt3sVoT+p
Li61jN8SVFnaKm+q0xmyRc+A7eLQvvYI2+BoVvFOjjWHqINfXwUW3MVzzyo04ZZS
6F42zJpL5YTOCnCf3bkCDQRS/SRyARAAsdRSVgStUTkbvqx2udlHNPiZHK+/dQNd
CLcMr+n7ANEU+pqKG+rPEb3rfDUB+kmVUaohst3fIJcZ3nU99mcR1kaCwvD3Oj50
IVVwd0UmaBPVVZvc/u5xzhl1wo9GtDrIMhkhy3qxPezL5TJZH9hLDk4+oq2WQ7yR
+BG5W5NVswuCuRAua+xS/+LHRy2w1hFEd8Hpgu7NJ/SLrB8DQYk0ksaWoP3avfun
lcqAN6KbKklN8JUqn5t1P9BtzBuCZMA5kt5yuIZpqpwmpHV2WqimQxmY32s7U7ju
UT+9ynzR0jX7K3jl2N5XV+yctanR6f4QaeghV4R7pXeGcli/jurjEXDUHX3f2/FQ
Q3t89i2MNwB54YwJ5sCao354R96+4mzNvhwLa4/CeUMHv9vECTkd1H09frWFvCNG
6ZwXrH84JvVadrdyM5GhnV0DrAfSnXCkVeL4oquFT0tR3bb6SwMcazcRYLiJWAJC
zCcMLmmivF/iv5IAJt6ufrcbMUf4w5g2haqo9GJ30+7PnM20pJL1wxuvLE1a9XNr
u9YvENF10kqy99P4//v/wjfZj+qCOnWEQyucAhWmMHEHuU3f24iQ1l7F6JTgtAh5
8tU03zb2ivm9GJLGrO2i8qRznOcX1SSNXqL8JAaVwEEAxSaFpWbnV11L4zxbBMrf
Y3di1JeX2XEAEQEAAYkCJQQYAQIADwUCUv0kcgIbDAUJCWYBgAAKCRCzx84hDedt
/H30D/9q1BN2RI+f5K7aYA4rf7dEIpOu+A1CqoEw0tQp20B3S6oHsiHm1DRbScxL
byPO0RlWe11agPjTVkAKFuJeGBjxBq3QdrGtymB35UWxWycDjlU7goVcpDq8kph6
TKn7J4HMad+8SEVF1+mo3YeAv164VsCqCAPQetB0gaQ6KkRg5awwv3ch4C4d/k1f
KmxUIDoSYiCeFysSyajwSImYKo6HoNNGXQbv1HvPco2sXKkp6U6DU8VPTuRPb2UQ
eqqGRU0oQvdvp+38ICjmtBQ9BFsMJSYIxOrxtx8G94r9cpnWY5HJbqXSfNH3mbJn
mkvBL9NhBxWsXfzQMd0nUIa1Mn+KNXOhHiI4YDUNoxNeYUi6F9b2w+KahrajblW9
tyQ1ysXJV0C5ldOeIO0gI4zOR4ZuJq4s5PmdvV5bYGIvnHpJG6XTn76UR7ohm06E
ydBwlTnZ2vtfPUwp7CgUGImW2TQ6a7tL+JndQ2edX/9V1ovtZVTKloRkfgBUMMmK
ms+89YCcrnu2BqSRTfKdx6Jj0XMhn+pGdTIz5/E7CWrPP8nD3OpWikTDMXWfTPe7
/jWSDnbXqu+PKZbleBTH2ddJPKdWDUTCUGPbPhElpM5A8wUfpsrjalgTAVOQnNgK
AECYfQx9fE1jabBZ/y5XEcbsY37M/BiCPDGwf7tIXJK6u3l8eA==
=oA+6
-----END PGP PUBLIC KEY BLOCK-----
+30 -2
View File
@@ -315,7 +315,7 @@ class Specfile(object):
self._write("%defattr(-,root,root,-)\n")
if "main" in self.packages:
for filename in sorted(self.packages["main"]):
self._write("{}\n".format(filename))
self._write("{}\n".format(self.quote_filename(filename)))
for pkg in sorted(self.packages):
if pkg in ["ignore", "main", "locales"]:
@@ -324,7 +324,7 @@ class Specfile(object):
self._write("\n%files {}\n".format(pkg))
self._write("%defattr(-,root,root,-)\n")
for filename in sorted(self.packages[pkg]):
self._write("{}\n".format(filename))
self._write("{}\n".format(self.quote_filename(filename)))
def write_lang_files(self):
"""
@@ -1162,3 +1162,31 @@ class Specfile(object):
def _write_strip(self, string):
self.specfile.write_strip(string)
def quote_filename(self, filename):
"""
Quotes the filename, if necessary. Identifies and skips any RPM directive prefix.
"""
# Characters that require quoting -- only those with special
# meaning in specfiles
special_chars = set(" \t")
# Build up the output as a string
quoted = ''
# Capture any directive prefix separately from actual filename
# (1 )(3 )
directive_re = re.compile("(%\w+(\([^\)]*\))?\s+)(.*)")
parts = directive_re.match(filename)
if parts:
# Add prefix to the output
quoted += parts.group(1)
# Set the filename to the remaining portion
filename = parts.group(3)
# Now check for special characters
if any(c in filename for c in special_chars):
# Quote the filename
quoted += '"{}"'.format(filename)
else:
# Add the filename as-is
quoted += filename
return quoted
+160 -90
View File
@@ -24,6 +24,7 @@ import re
import shutil
import subprocess
import pycurl
import configparser
import build
import buildpattern
@@ -38,6 +39,8 @@ url = ""
path = ""
tarball_prefix = ""
gcov_file = ""
archives = []
giturl = ""
def get_sha1sum(filename):
@@ -63,6 +66,7 @@ def really_download(upstream_url, destination):
c.perform()
except pycurl.error:
print_fatal("unable to download {}".format(upstream_url))
os.remove(destination)
exit(1)
finally:
c.close()
@@ -172,13 +176,34 @@ def print_header():
def download_tarball(target_dir):
global giturl
"""
Download tarball at url (global) to target_dir
"""
global gcov_file
priority for target directory:
- target_dir set from args
- current directory if options.conf['package'] exists and
any of the options match what has been detected.
- curdir/name
"""
tarfile = os.path.basename(url)
build.download_path = target_dir if target_dir else os.path.join(os.getcwd(), name)
target = os.path.join(os.getcwd(), name)
if os.path.exists(os.path.join(os.getcwd(), 'options.conf')):
config_f = configparser.ConfigParser()
config_f.read('options.conf')
if "package" in config_f.sections():
if (config_f["package"].get("name") == name or
config_f["package"].get("url") == url or
config_f["package"].get("archives") == " ".join(archives)):
target = os.getcwd()
if "giturl" in config_f["package"]:
giturl = config_f["package"].get("giturl")
if target_dir:
target = target_dir
build.download_path = target
call("mkdir -p {}".format(build.download_path))
# locate the tarball locally or download
@@ -189,20 +214,66 @@ def convert_version(ver_str):
"""
Remove disallowed characters from the version
"""
suffix = ''
# remove architecture string
ver_str = ver_str.replace('x86_64', '')
ver_str = ver_str.replace(name, '')
# banned substrings. It is better to remove these here instead of filtering
# them out with expensive regular expressions
banned_subs = ["x86.64", "source", "src", "all", "bin", "release", "rh",
"ga", ".ce", "lcms", "onig", "linux", "gc", "sdk", "orig",
"jurko"]
# package names may be modified in the version string by adding "lib" for
# example. Remove these from the name before trying to remove the name from
# the version
name_mods = ["lib", "core", "pom", "opa-"]
# enforce lower-case strings to make them easier to standardize
ver_str = ver_str.lower()
# remove the package name from the version string
ver_str = ver_str.replace(name.lower(), '')
# handle modified name substrings in the version string
for mod in name_mods:
ver_str = ver_str.replace(name.replace(mod, ""), "")
# replace illegal characters
ver_str = ver_str.strip().replace('-', '.').replace('_', '.')
ver_str_pat = r'[0-9\.]+(beta|pre|b|alpha|sdist)([\.0-9]*)$'
match = re.search(ver_str_pat, ver_str)
# it is important the first group matches, not just the second
if match and match.group(1):
# match.group(2) is an empty string if it was not matched
suffix = match.group(1) + match.group(2)
ver_str = re.sub(r'{}$'.format(suffix), '', ver_str)
ver_str = ''.join(c for c in ver_str if c.isdigit() or c == '.')
return '{}.{}'.format(ver_str.strip('.'), suffix) if suffix else ver_str.strip('.')
# remove banned substrings
for sub in banned_subs:
ver_str = ver_str.replace(sub, "")
# remove consecutive '.' characters
while ".." in ver_str:
ver_str = ver_str.replace("..", ".")
return ver_str.strip(".")
def detect_build_from_url(url):
"""
Detect build patterns and build requirements from the patterns detected
in the url.
"""
# R package
if "cran.r-project.org" in url or "cran.rstudio.com" in url:
buildpattern.set_build_pattern("R", 10)
buildreq.add_buildreq("clr-R-helpers")
# python
if "pypi.python.org" in url or "pypi.debian.net" in url:
buildpattern.set_build_pattern("distutils23", 10)
buildreq.add_buildreq("python3-dev")
buildreq.add_buildreq("python-dev")
# cpan
if ".cpan.org/" in url or ".metacpan.org/" in url:
buildpattern.set_build_pattern("cpan", 10)
# ruby
if "rubygems.org/" in url:
buildpattern.set_build_pattern("ruby", 10)
# maven
if ".maven." in url:
buildpattern.set_build_pattern("maven", 10)
def name_and_version(name_arg, version_arg, filemanager):
@@ -213,6 +284,8 @@ def name_and_version(name_arg, version_arg, filemanager):
global rawname
global version
global url
global giturl
global repo
tarfile = os.path.basename(url)
@@ -230,14 +303,12 @@ def name_and_version(name_arg, version_arg, filemanager):
# it is important for the more specific patterns to come first
pattern_options = [
r"(.*?)[\-_](v*[0-9]+[a-zalpha\+_spbfourcesigedsvstableP0-9\.\-\~]*)\.orig\.tar",
r"(.*?)[\-_](v*[0-9]+[alpha\+_spbfourcesigedsvstableP0-9\.\-\~]*)\.src\.(tgz|tar|zip)",
r"(.*?)[\-_](v*[0-9]+[alpha\+_sbpfourcesigedsvstableP0-9\.\-\~]*)\.(tgz|tar|zip)",
r"(.*?)[\-_](v*[0-9]+[\+_spbfourcesigedsvstableP0-9\.\~]*)(-.*?)?\.tar",
# handle font packages with names ending in -nnndpi
r"(.*-[0-9]+dpi)[-_]([0-9]+[a-zA-Z0-9\+_\.\-\~]*)\.(tgz|tar|zip)",
r"(.*?)[-_][vs]?([0-9]+[a-zA-Z0-9\+_\.\-\~]*)\.(tgz|tar|zip)",
]
for pattern in pattern_options:
p = re.compile(pattern)
m = p.search(tarfile)
m = re.search(pattern, tarfile)
if m:
name = m.group(1).strip()
version = convert_version(m.group(2))
@@ -245,96 +316,88 @@ def name_and_version(name_arg, version_arg, filemanager):
rawname = name
# R package
if url.find("cran.r-project.org") > 0 or url.find("cran.rstudio.com") > 0:
buildpattern.set_build_pattern("R", 10)
if "cran.r-project.org" in url or "cran.rstudio.com" in url:
filemanager.want_dev_split = False
buildreq.add_buildreq("clr-R-helpers")
p = re.compile(r"([A-Za-z0-9.]+)_(v*[0-9]+[\+_spbfourcesigedsvstableP0-9\.\~\-]*)\.tar\.gz")
m = p.search(tarfile)
m = re.search(r"([A-Za-z0-9.]+)_(v*[0-9]+[a-zA-Z0-9\+_\.\~\-]*)\.tar\.gz",
tarfile)
if m:
name = "R-" + m.group(1).strip()
rawname = m.group(1).strip()
version = m.group(2).strip().replace('-', '.')
version = convert_version(m.group(2))
if url.find("pypi.python.org") > 0:
buildpattern.set_build_pattern("distutils23", 10)
url = "http://pypi.debian.net/" + name + "/" + tarfile
buildreq.add_buildreq("python3-dev")
buildreq.add_buildreq("python-dev")
if url.find("pypi.debian.net") > 0:
buildpattern.set_build_pattern("distutils23", 10)
buildreq.add_buildreq("python3-dev")
buildreq.add_buildreq("python-dev")
if url.find(".cpan.org/CPAN/") > 0:
buildpattern.set_build_pattern("cpan", 10)
if name:
name = "perl-" + name
if url.find(".metacpan.org/") > 0:
buildpattern.set_build_pattern("cpan", 10)
if name:
name = "perl-" + name
if ".cpan.org/" in url or ".metacpan.org/" in url and name:
name = "perl-" + name
if "github.com" in url:
# define regex accepted for valid packages, important for specific
# patterns to come before general ones
github_patterns = [r"https?://github.com/.*/(.*?)/archive/(.*)-final.tar",
r"https?://github.com/.*/.*/archive/[0-9a-fA-F]{1,40}\/(.*)\-(.*).tar",
r"https?://github.com/.*/(.*?)/archive/v?(.*).orig.tar",
r"https?://github.com/.*/(.*?)/archive/(.*).zip",
r"https?://github.com/.*/(.*?)/archive/v?(.*).tar",
r"https?://github.com/.*/(.*?)/releases/download/v.*/(.*).tar"]
github_patterns = [r"https?://github.com/(.*)/(.*?)/archive/[v|r]?.*/(.*).tar",
r"https?://github.com/(.*)/(.*?)/archive/[-a-zA-Z]*-(.*).tar",
r"https?://github.com/(.*)/(.*?)/archive/[vVrR]?(.*).tar",
r"https?://github.com/(.*)/(.*?)/releases/download/.*?/(.*).tar",
r"https?://github.com/(.*)/(.*?)/files/.*?/(.*).tar"]
for pattern in github_patterns:
p = re.compile(pattern)
m = p.search(url)
m = re.search(pattern, url)
if m:
name = m.group(1).strip()
repo = m.group(2).strip()
if repo not in name:
# Only take the repo name as the package name if it's more descriptive
name = repo
elif name != repo:
name = re.sub("release-", '', name)
name = re.sub("\d*$", '', name)
rawname = name
version = convert_version(m.group(2))
version = convert_version(m.group(3))
giturl = "https://github.com/" + m.group(1).strip() + "/" + repo + ".git"
break
if url.find("bitbucket.org") > 0:
p = re.compile(r"https?://bitbucket.org/.*/(.*?)/.*/([.0-9a-zA-Z_-]*?).tar")
m = p.search(url)
if "mirrors.kernel.org" in url:
m = re.search(r".*/sourceware/(.*?)/releases/(.*?).tgz", url)
if m:
name = m.group(1).strip()
version = convert_version(m.group(2))
else:
version = "1"
if "sourceforge.net" in url:
scf_pats = [r"projects/.*/files/(.*?)/(.*?)/[^-]*(-src)?.tar.gz",
r"downloads.sourceforge.net/.*/([a-zA-Z]+)([-0-9\.]*)(-src)?.tar.gz"]
for pat in scf_pats:
m = re.search(pat, url)
if m:
name = m.group(1).strip()
version = convert_version(m.group(2))
break
if "bitbucket.org" in url:
bitbucket_pats = [r"/.*/(.*?)/.*/.*v([-\.0-9a-zA-Z_]*?).(tar|zip)",
r"/.*/(.*?)/.*/([-\.0-9a-zA-Z_]*?).(tar|zip)"]
for pat in bitbucket_pats:
m = re.search(pat, url)
version = 1
if m:
name = m.group(1).strip()
version = convert_version(m.group(2))
break
# ruby
if url.find("rubygems.org/") > 0:
buildpattern.set_build_pattern("ruby", 10)
p = re.compile(r"(.*?)[\-_](v*[0-9]+[alpha\+_spbfourcesigedsvstableP0-9\.\-\~]*)\.gem")
m = p.search(tarfile)
if "rubygems.org/" in url:
m = re.search(r"(.*?)[\-_](v*[0-9]+[a-zA-Z0-9\+_\.\-\~]*)\.gem", tarfile)
if m:
name = "rubygem-" + m.group(1).strip()
# remove release candidate tag
# remove release candidate tag from the package name
# https://rubygems.org/downloads/ruby-rc4-0.1.5.gem
b = name.find("-rc")
if b > 0:
name = name[:b]
rawname = m.group(1).strip()
version = m.group(2).strip()
b = version.find("-")
if b >= 0:
version = version[:b]
version = convert_version(m.group(2))
# maven
if url.find("maven.org") > 0:
buildpattern.set_build_pattern("maven", 10)
if not name:
split = url.split('/')
if len(split) > 3 and split[-2] in ('archive', 'tarball'):
name = split[-3]
version = split[-1]
version = version.lstrip('v')
# remove extension
version = version.rsplit('.', 1)[0]
if version.endswith('.tar'):
version = version.replace('.tar', '')
if ".maven." in url:
m = re.search(r"/maven.*/org/.*/(.*?)/.*/.*[\-_]([0-9]+[a-zA-Z0-9\+_\.\-\~]*)\.jar", url)
if m:
name = m.group(1).strip()
version = convert_version(m.group(2))
# override name and version from commandline
name = name_arg if name_arg else name
@@ -400,7 +463,7 @@ def prepare_and_extract(extract_cmd):
"""
shutil.rmtree(os.path.join(build.base_path, name), ignore_errors=True)
shutil.rmtree(os.path.join(build.base_path, tarball_prefix), ignore_errors=True)
os.makedirs("{}".format(build.output_path), exist_ok=True)
os.makedirs("{}".format(build.base_path), exist_ok=True)
call("mkdir -p %s" % build.download_path)
call(extract_cmd)
@@ -435,7 +498,7 @@ def process_archives(archives):
write_upstream(sha1, os.path.basename(archive), mode="a")
def process(url_arg, name_arg, ver_arg, target, archives, filemanager):
def process(url_arg, name_arg, ver_arg, target, archives_arg, filemanager):
"""
Download and process the tarball at url_arg
"""
@@ -444,14 +507,20 @@ def process(url_arg, name_arg, ver_arg, target, archives, filemanager):
global version
global path
global tarball_prefix
global archives
url = url_arg
name = name_arg
version = ver_arg
archives = archives_arg
tarfile = os.path.basename(url_arg)
# set gcov file information
set_gcov()
# determine name and version of package
name_and_version(name_arg, ver_arg, filemanager)
# determine build pattern and build requirements from url
detect_build_from_url(url)
# set gcov file information, must be done after name is set since the gcov
# name is created by adding ".gcov" to the package name (if a gcov file
# exists)
set_gcov()
# download the tarball to tar_path
tar_path = download_tarball(target)
# write the sha of the upstream tarfile to the "upstream" file
@@ -463,11 +532,12 @@ def process(url_arg, name_arg, ver_arg, target, archives, filemanager):
# Now that the metadata has been collected print the header
print_header()
# write out the Makefile with the name, url, and archives we found
write_makefile(archives)
# DEPRECATED, this will be removed in a future version
write_makefile(archives_arg)
# prepare directory and extract tarball
prepare_and_extract(extract_cmd)
# locate or download archives and move them into the right spot
process_archives(archives)
process_archives(archives_arg)
def load_specfile(specfile):
+2
View File
@@ -1,3 +1,5 @@
flake8>=3.4.0
pycurl>=7.43.0
toml>=0.9.0
mock>=2.0.0
coverage>=4.4.1
+4
View File
@@ -2,3 +2,7 @@
tag_build =
[pycodestyle]
ignore = E501
[coverage:run]
# omit tests and travis site-packages
omit = tests/*,*site-packages*,*site.py
+1 -1
View File
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages
import sys, os
version = "1.0.1"
version = "1.1.4"
def readme():
with open("README.rst") as f:
+1869 -138
View File
File diff suppressed because it is too large Load Diff
+44 -47
View File
@@ -1,4 +1,6 @@
import unittest
import tempfile
import os
from unittest.mock import patch, mock_open
import build
import files
@@ -21,9 +23,7 @@ class TestBuildpattern(unittest.TestCase):
build.round = 0
build.must_restart = 0
build.base_path = None
build.output_path = None
build.download_path = None
build.mock_cmd = '/usr/bin/mock'
build.buildreq.buildreqs = set()
build.config.config_opts['32bit'] = False
@@ -34,9 +34,7 @@ class TestBuildpattern(unittest.TestCase):
build.tarball.name = "testtarball"
build.setup_workingdir("test_directory")
self.assertEqual(build.base_path, "test_directory")
self.assertEqual(build.output_path, "test_directory/output")
self.assertEqual(build.download_path,
"test_directory/output/testtarball")
self.assertEqual(build.download_path, "test_directory/testtarball")
def test_simple_pattern_pkgconfig(self):
"""
@@ -316,65 +314,64 @@ class TestBuildpattern(unittest.TestCase):
self.assertIn('testpkg-python', build.buildreq.buildreqs)
self.assertEqual(build.must_restart, 1)
def test_set_mock(self):
def test_get_mock_cmd_without_consolehelper(self):
"""
Test set_mock when user is not in the mock group
Test get_mock_cmd when /usr/bin/mock doesn't point to consolehelper
"""
class mock_getgrgid(object):
def __init__(self, g):
self.gr_name = 'not_mock'
def mock_realpath(path):
return path
def mock_getgroups():
return ['gr1', 'gr2', 'gr3']
realpath_backup = build.os.path.realpath
def mock_exists(path):
return True
build.os.path.realpath = mock_realpath
getgrgid_backup = build.grp.getgrgid
getgroups_backup = build.os.getgroups
exists_backup = build.os.path.exists
mock_cmd = build.get_mock_cmd()
build.grp.getgrgid = mock_getgrgid
build.os.getgroups = mock_getgroups
build.os.path.exists = mock_exists
build.os.path.realpath = realpath_backup
build.set_mock()
self.assertEqual(mock_cmd, 'sudo /usr/bin/mock')
build.grp.getgrgid = getgrgid_backup
build.os.getgroups = getgroups_backup
build.os.path.exists = exists_backup
self.assertEqual(build.mock_cmd, 'sudo /usr/bin/mock')
def test_set_mock_user_in_mock_group(self):
def test_get_mock_cmd_with_consolehelper(self):
"""
Test set_mock when user is in the mock group
Test get_mock_cmd when /usr/bin/mock points to consolehelper
"""
class mock_getgrgid(object):
def __init__(self, g):
self.gr_name = 'mock'
def mock_realpath(path):
return '/usr/bin/consolehelper'
def mock_getgroups():
return ['gr1', 'gr2', 'gr3']
realpath_backup = build.os.path.realpath
def mock_exists(path):
return True
build.os.path.realpath = mock_realpath
getgrgid_backup = build.grp.getgrgid
getgroups_backup = build.os.getgroups
exists_backup = build.os.path.exists
mock_cmd = build.get_mock_cmd()
build.grp.getgrgid = mock_getgrgid
build.os.getgroups = mock_getgroups
build.os.path.exists = mock_exists
build.os.path.realpath = realpath_backup
build.set_mock()
self.assertEqual(mock_cmd, '/usr/bin/mock')
build.grp.getgrgid = getgrgid_backup
build.os.getgroups = getgroups_backup
build.os.path.exists = exists_backup
def test_get_uniqueext_first(self):
"""
Test get_uniqueext() with no collisions
"""
with tempfile.TemporaryDirectory() as tmpd:
self.assertEqual(build.get_uniqueext(tmpd, "test", "pkg"), "pkg")
def test_get_uniqueext_second(self):
"""
Test get_uniqueext() with one collision
"""
with tempfile.TemporaryDirectory() as tmpd:
os.mkdir(os.path.join(tmpd, "test-pkg"))
self.assertEqual(build.get_uniqueext(tmpd, "test", "pkg"), "pkg-1")
def test_get_uniqueext_third(self):
"""
Test get_uniqueext() with two collisions
"""
with tempfile.TemporaryDirectory() as tmpd:
os.mkdir(os.path.join(tmpd, "test-pkg"))
os.mkdir(os.path.join(tmpd, "test-pkg-1"))
self.assertEqual(build.get_uniqueext(tmpd, "test", "pkg"), "pkg-2")
self.assertEqual(build.mock_cmd, '/usr/bin/mock')
if __name__ == '__main__':
+66
View File
@@ -1,5 +1,7 @@
import unittest
import files
import tempfile
import os
from unittest.mock import call, MagicMock
from files import FileManager
@@ -184,5 +186,69 @@ class TestFiles(unittest.TestCase):
self.assertNotIn('test', self.fm.files)
self.assertNotIn('test', self.fm.files_blacklist)
def test_clean_directories(self):
"""
Test clean_directories with a directory in the list
"""
with tempfile.TemporaryDirectory() as tmpd:
os.mkdir(os.path.join(tmpd, "directory"))
with open(os.path.join(tmpd, "file1"), "w") as f:
f.write(" ")
with open(os.path.join(tmpd, "file2"), "w") as f:
f.write(" ")
self.fm.packages["main"] = set()
self.fm.packages["main"].add("/directory")
self.fm.packages["main"].add("/file1")
self.fm.packages["main"].add("/file2")
self.fm.clean_directories(tmpd)
self.assertEqual(self.fm.packages["main"], set(["/file1", "/file2"]))
def test_clean_directories_with_dir(self):
"""
Test clean_directories with a %dir directory in the list. This should
remain.
"""
with tempfile.TemporaryDirectory() as tmpd:
os.mkdir(os.path.join(tmpd, "directory"))
with open(os.path.join(tmpd, "file1"), "w") as f:
f.write(" ")
with open(os.path.join(tmpd, "file2"), "w") as f:
f.write(" ")
self.fm.packages["main"] = set()
self.fm.packages["main"].add("%dir /directory")
self.fm.packages["main"].add("/file1")
self.fm.packages["main"].add("/file2")
self.fm.clean_directories(tmpd)
self.assertEqual(self.fm.packages["main"],
set(["%dir /directory", "/file1", "/file2"]))
def test_clean_directories_with_doc(self):
"""
Test clean_directories with a %doc directive in the list. This should
remain.
"""
with tempfile.TemporaryDirectory() as tmpd:
os.mkdir(os.path.join(tmpd, "directory"))
with open(os.path.join(tmpd, "file1"), "w") as f:
f.write(" ")
with open(os.path.join(tmpd, "file2"), "w") as f:
f.write(" ")
self.fm.packages["main"] = set()
self.fm.packages["main"].add("%doc /directory")
self.fm.packages["main"].add("/file1")
self.fm.packages["main"].add("/file2")
self.fm.clean_directories(tmpd)
self.assertEqual(self.fm.packages["main"],
set(["%doc /directory", "/file1", "/file2"]))
if __name__ == '__main__':
unittest.main(buffer=True)
+35 -77
View File
@@ -1,13 +1,18 @@
import os
import shutil
import mock
import unittest
import tempfile
import pkg_integrity
TESTDIR = os.path.join(os.getcwd(), "tests/testfiles/pkg_integrity")
PACKAGE_URL = "http://pkgconfig.freedesktop.org/releases/pkg-config-0.29.1.tar.gz"
XATTR_PKT_URL = "http://pypi.debian.net/xattr/xattr-0.9.1.tar.gz"
NO_SIGN_PKT_URL = "http://www.ferzkopp.net/Software/SDL_gfx-2.0/SDL_gfx-2.0.25.tar.gz"
GEM_PKT = "https://rubygems.org/downloads/hoe-debugging-1.2.1.gem"
NOSIGN_PKT_URL_BAD = "http://gnu.mirrors.pair.com/savannah/savannah/quagga/bad_quagga-1.1.0.tar.gz"
NOSIGN_PKT_URL = "http://download.savannah.gnu.org/releases/quagga/quagga-1.1.0.tar.gz"
NOSIGN_SIGN_URL = "http://download.savannah.gnu.org/releases/quagga/quagga-1.1.0.tar.gz.asc"
PYPI_MD5_ONLY_PKG = "http://pypi.debian.net/tappy/tappy-0.9.2.tar.gz"
@@ -15,36 +20,23 @@ GNOME_SHA256_PKG = "https://download.gnome.org/sources/pygobject/3.24/pygobject-
KEYID = "EC2392F2EDE74488680DA3CF5F2B4756ED873D23"
class TestGPGCli(unittest.TestCase):
def mock_attempt_to_download(path, dest=None):
if dest:
shutil.copyfile(os.path.join(TESTDIR, os.path.basename(path)), dest)
return 200
def test_import_export(self):
with pkg_integrity.cli_gpg_ctx() as ctx:
err, output = ctx.export_key(KEYID)
self.assertTrue(err is not None)
err, output = ctx.import_key(KEYID)
self.assertTrue(err is None)
err, output = ctx.export_key(KEYID)
self.assertTrue(err is None)
self.assertTrue('PGP PUBLIC KEY' in output)
def mock_head_request(url):
bad_sigs = ["http://pkgconfig.freedesktop.org/releases/pkg-config-0.29.1.tar.gz.sig",
"http://www.ferzkopp.net/Software/SDL_gfx-2.0/SDL_gfx-2.0.25.tar.gz.sig",
"http://www.ferzkopp.net/Software/SDL_gfx-2.0/SDL_gfx-2.0.25.tar.gz.asc"]
def test_import_non_existing_key(self):
with pkg_integrity.cli_gpg_ctx() as ctx:
keyid = '0' + KEYID[1:]
err, output = ctx.import_key(keyid)
self.assertTrue(err is not None)
def test_display_key_info(self):
with pkg_integrity.cli_gpg_ctx() as ctx:
err, output = ctx.import_key(KEYID)
self.assertTrue(err is None)
err, output = ctx.export_key(KEYID)
with open('key_test.pkey', 'w') as out_key:
out_key.write(output)
err, output = ctx.display_keyinfo('key_test.pkey')
os.remove('key_test.pkey')
self.assertTrue('keyid' in output)
if url in bad_sigs:
return 404
return 200
@mock.patch('pkg_integrity.attempt_to_download', mock_attempt_to_download)
@mock.patch('pkg_integrity.head_request', mock_head_request)
class TestCheckFn(unittest.TestCase):
def setUp(self):
@@ -53,8 +45,6 @@ class TestCheckFn(unittest.TestCase):
pkg_integrity.config.rewrite_config_opts = mock_rewrite
pkg_integrity.config.config_opts['verify_required'] = False
@unittest.skipIf("TRAVIS" in os.environ and os.environ["TRAVIS"] == "true",
"Skipping this test on Travis CI.")
def test_check_matching_sign_url(self):
with tempfile.TemporaryDirectory() as tmpd:
out_file = os.path.join(tmpd, os.path.basename(PACKAGE_URL))
@@ -73,6 +63,7 @@ class TestCheckFn(unittest.TestCase):
self.assertTrue(result)
@mock.patch('pkg_integrity.attempt_to_download', mock_attempt_to_download)
class TestDomainBasedVerifiers(unittest.TestCase):
def run_test_for_domain(self, Verifier, url):
@@ -94,6 +85,7 @@ class TestDomainBasedVerifiers(unittest.TestCase):
self.assertTrue(result)
@mock.patch('pkg_integrity.attempt_to_download', mock_attempt_to_download)
class TestGEMShaVerifier(unittest.TestCase):
def setUp(self):
@@ -120,6 +112,8 @@ class TestGEMShaVerifier(unittest.TestCase):
self.assertEqual(a.exception.code, 1)
@mock.patch('pkg_integrity.attempt_to_download', mock_attempt_to_download)
@mock.patch('pkg_integrity.head_request', mock_head_request)
class TestGPGVerifier(unittest.TestCase):
def setUp(self):
@@ -128,8 +122,6 @@ class TestGPGVerifier(unittest.TestCase):
pkg_integrity.config.rewrite_config_opts = mock_rewrite
pkg_integrity.config.config_opts['verify_required'] = False
@unittest.skipIf("TRAVIS" in os.environ and os.environ["TRAVIS"] == "true",
"Skipping this test on Travis CI.")
def test_from_url(self):
with tempfile.TemporaryDirectory() as tmpd:
out_file = os.path.join(tmpd, os.path.basename(PACKAGE_URL))
@@ -141,12 +133,14 @@ class TestGPGVerifier(unittest.TestCase):
def test_check_quit(self):
with tempfile.TemporaryDirectory() as tmpd:
#with self.assertRaises(SystemExit) as a:
pkg_integrity.check(NO_SIGN_PKT_URL, tmpd, interactive=False)
#self.assertEqual(a.exception.code, 1)
with self.assertRaises(SystemExit) as a:
out_file = os.path.join(tmpd, os.path.basename(NOSIGN_PKT_URL_BAD))
pkg_integrity.attempt_to_download(NOSIGN_PKT_URL_BAD, out_file)
key_file = os.path.join(tmpd, os.path.basename(NOSIGN_PKT_URL_BAD))
pkg_integrity.attempt_to_download(NOSIGN_SIGN_URL, key_file + '.asc')
result = pkg_integrity.check(NOSIGN_PKT_URL_BAD, tmpd)
self.assertEqual(a.exception.code, 1)
@unittest.skipIf("TRAVIS" in os.environ and os.environ["TRAVIS"] == "true",
"Skipping this test on Travis CI.")
def test_from_disk(self):
with tempfile.TemporaryDirectory() as tmpd:
out_file = os.path.join(tmpd, os.path.basename(PACKAGE_URL))
@@ -156,8 +150,6 @@ class TestGPGVerifier(unittest.TestCase):
result = pkg_integrity.from_disk(PACKAGE_URL, out_file, out_key)
self.assertTrue(result)
@unittest.skipIf("TRAVIS" in os.environ and os.environ["TRAVIS"] == "true",
"Skipping this test on Travis CI.")
def test_non_matchingsig(self):
with tempfile.TemporaryDirectory() as tmpd:
out_file = os.path.join(tmpd, os.path.basename(PACKAGE_URL))
@@ -172,35 +164,14 @@ class TestGPGVerifier(unittest.TestCase):
result = pkg_integrity.from_disk('http://nokey.com/package.tar.gz',
'NonExistentPKG.tar.gz',
'NonExistentKey.asc')
self.assertTrue(result is None)
self.assertIsNone(result)
def test_result_on_nosign_package(self):
with tempfile.TemporaryDirectory() as tmpd:
out_file = os.path.join(tmpd, os.path.basename(NO_SIGN_PKT_URL))
pkg_integrity.attempt_to_download(NO_SIGN_PKT_URL, out_file)
result = pkg_integrity.check(NO_SIGN_PKT_URL, tmpd)
self.assertTrue(result is None)
@unittest.skipIf("TRAVIS" in os.environ and os.environ["TRAVIS"] == "true",
"Skipping this test on Travis CI.")
def test_pubkey_import(self):
def say_yes(_):
return True
_ = pkg_integrity.InputGetter.get_answer
pkg_integrity.InputGetter.get_answer = say_yes
keyid = '0' + KEYID[1:]
result = pkg_integrity.attempt_key_import(keyid)
self.assertTrue(result is False)
result = pkg_integrity.attempt_key_import(KEYID)
self.assertTrue(result)
pkg_integrity.InputGetter.get_answer = _
self.removeKey()
def removeKey(self):
key_path = os.path.dirname(os.path.realpath(__file__))
key_path = os.path.dirname(key_path) + '/autospec/keyring/{}.pkey'.format(KEYID)
if os.path.exists(key_path):
os.unlink(key_path)
self.assertIsNone(result)
class TestInputGetter(unittest.TestCase):
@@ -210,12 +181,14 @@ class TestInputGetter(unittest.TestCase):
def test_timput(self):
ig = pkg_integrity.InputGetter(default='N', timeout=2)
answer = ig.get_answer()
self.assertTrue(answer is None)
self.assertIsNone(answer)
ig = pkg_integrity.InputGetter(default='Y', timeout=2)
answer = ig.get_answer()
self.assertTrue(answer is None)
self.assertIsNone(answer)
@mock.patch('pkg_integrity.attempt_to_download', mock_attempt_to_download)
@mock.patch('pkg_integrity.head_request', mock_head_request)
class TestUtils(unittest.TestCase):
def setUp(self):
@@ -250,21 +223,6 @@ class TestUtils(unittest.TestCase):
false_name = '/false/name'
self.assertTrue(pkg_integrity.get_keyid(false_name) is None)
def test_attempt_to_download(self):
fakeURL = "https://download.my.url.com/file.tar.gz"
realURLnoFile = "http://pypi.debian.net/alembic/alembic-0.8.8.non-existent.tar.gz"
realURL = "http://pypi.debian.net/alembic/alembic-0.8.8.tar.gz"
tmpf = tempfile.NamedTemporaryFile()
fname = tmpf.name
tmpf.close()
self.assertEqual(pkg_integrity.attempt_to_download(fakeURL, fname), None)
self.assertEqual(pkg_integrity.attempt_to_download(realURLnoFile, fname), 404)
self.assertEqual(pkg_integrity.attempt_to_download(realURL, fname), 200)
os.unlink(fname)
def test_get_signature_url(self):
url_from_gnu = "http://ftp.gnu.org/pub/gnu/gperf/gperf-3.0.4.tar.gz"
+9 -3
View File
@@ -343,15 +343,21 @@ class TestSpecfileWrite(unittest.TestCase):
"""
test write_files base test.
"""
self.specfile.packages["main"] = ["mainfile1", "mainfile2", "mainfile3"]
self.specfile.packages["main"] = ["mainfile1", "/mainfile2", "/mainfile3",
"/mainfile 4", "mainfile\t5", "%foo /mainfile6", "%bar /mainfile 7"]
self.specfile.packages["ignore"] = ["ignorepkg"]
self.specfile.packages["other"] = ["other2", "other1"]
self.specfile.write_files()
# Note the special sorting
expect = ["\n%files\n",
"%defattr(-,root,root,-)\n",
'%bar "/mainfile 7"\n',
"%foo /mainfile6\n",
'"/mainfile 4"\n',
"/mainfile2\n",
"/mainfile3\n",
'"mainfile\t5"\n',
"mainfile1\n",
"mainfile2\n",
"mainfile3\n",
"\n%files other\n",
"%defattr(-,root,root,-)\n",
"other1\n",
+10 -2
View File
@@ -3,6 +3,7 @@ import unittest
from unittest.mock import patch, Mock, mock_open, call
import build # needs to be imported before tarball due to dependencies
import tarball
import re
class FileManager():
@@ -27,10 +28,17 @@ def test_generator(url, name, version):
"""
tarball.name = ''
tarball.version = ''
tarball.giturl = ''
tarball.url = url
tarball.name_and_version('', '', FileManager())
self.assertEqual(tarball.name, name)
self.assertEqual(tarball.version, version)
self.assertEqual(name, tarball.name)
self.assertEqual(version, tarball.version)
if re.match("https?://github.com", url) != None:
self.assertIsNotNone(tarball.giturl)
self.assertNotEqual('', tarball.giturl, "giturl should not be empty")
self.assertIsNotNone(
re.match("https://github.com/[^/]+/"+tarball.repo+".git",
tarball.giturl), "%s looks incorrect" % tarball.giturl)
return test_packageurl
Binary file not shown.
@@ -0,0 +1,17 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQIcBAABCAAGBQJW2ZtDAAoJEAI6RCDH7GkUc0IP/1bH7KEJdUM+lrGM1SOuNHdq
4VEwDp1II8abbBzHeGEXZ8p4+MwwSOYHFiy+NM1yldZkDXtqAlAqvIuEzc+PtgGd
vFeNPb9infibNaEDK+zz4fcqJOSab1ZcQ/D3EIJXwKr5nIYP8RuCHu/zstf7o6R0
/wnGWaAIB1+p9PxvUhMPMbBEQCw/cBzyZ2d7nApHF3b0OH2wM7P8VG8ot4cuglPq
hzk27ZnrYeUDyUUhMRlL7sZZouJlSy/0OxsBK++tOjE6MiuAZhqtlSW+cFK4L7k/
q4eLodX7GtF0psSgTRjTk2ozdSIDkB2ccLBN6CzgCcbPrbcz4tVQqaQBcSd0mCl7
RWAKmSye7p+CY8mIIOjdYm+KaQRmJMKDXs49hMycti22jnu5T2BM6O7MZpiY+cb3
O2UKUXbVyX/cXKwTYwf4VMddxJKFaqYac+7n5qWbdwBjk9E5OC2ltz94taM1pxZ5
2jRtfyIb3s+Rj6M5cXI5UChrGqzMK6BmEbyZ0KbHAJ7Y0xvGqwydC6J+RwGIqRlp
LmW3k1ggpUajoMcgq9KqJgVqo/9f4+6anADHRMNJ93MxR7h5BRQ1/GWSXpOzYsYv
DnfQPrhc+z20m81qsvfUcBnN/k74yiDVqp3I/HrYGD+f8cXKPpBRESkPAXlUIcu2
ALHZXEdBGcWdUrAIpJT2
=SMbV
-----END PGP SIGNATURE-----
Binary file not shown.
@@ -0,0 +1,18 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQJMBAABCAA2BQJYBh/XLxpodHRwczovL3d3dy5qYWttYS5vcmcvfnBhdWwvcGdw
X3BvbGljeS0xLjEudHh0AAoJEG/lfKjBpK6mNOMP/irlUcU/4NQ6BQQbF7Vc90wo
hmTH/zGAodnndxSplIGV63BQqmQr5KiSOp6tNQ3OlCIwLFWlr/LiJz+MeThaMtZx
/mlrZptWIhbEcJzVa6efg8UGIYl2NC+QxFgEyezfCYSEmczd1qE3kiX+5WjcqVPH
pVjisPwaAYa0FTCsAwBMUKyJr2K3sq5hSJR7DFDVnvH1DJ1xZd9871ZdDpZBHz2z
GvR+IuZcWbYleH1ArFvT6cMokTpIUMvd33/+Gdpfu9fihzQQn199nN2LFZJzuEGV
vH6+IZVTmtXb5U/sdtbWGaDv8eFLAWl2NH9VNdlVw5FbWOYRC4YNN39/hBy7s0po
hvq33ZugC7JqPuje+4W1oF1T/dbRCIBmWUzKsoH8+3z4KJHdotSR0cU+TT+w6SJC
QhF9TAbjrfbeJs0D0NnZrllDLiLGFgLl5yULzMjRDqKcgqE5+nvYBPXHPUCCPU7+
59QOkPMsz/kZGV1lRzoUoxlM6V/phJRPU7jit10puiNij0c4peWbjVmTWDei3Xeu
kHpck5wIAUFzAIXBUpVhYdLl/kxq654Qqthoci869ATZIKH/SOId9Y0K1GE6xO6H
7vQFUGn3dcdnbgapM+tpmC77EmV4BtzkTjcu2pX6s0qnI4P+M+zXS+7G96xP3zHN
ZSFq45swEKd6SKbOYxcN
=mt1F
-----END PGP SIGNATURE-----
Binary file not shown.
Binary file not shown.