mirror of
https://github.com/clearlinux/autospec.git
synced 2026-08-19 21:46:14 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 574198586b | |||
| 3dd679b459 | |||
| bbaade01c7 | |||
| ad2fa386a4 | |||
| 07622d5770 | |||
| 0c74c918c1 | |||
| 79246f925a | |||
| a0bae50f72 | |||
| 8281fb1b97 | |||
| a5b085e2cc | |||
| e34b4e9315 | |||
| 7c4e0e9fd6 | |||
| a2b467e6b0 | |||
| 7d7263d684 | |||
| 7591bb9d25 | |||
| 9b8ef511d2 | |||
| 52a48c0c69 | |||
| 5d722054e9 | |||
| e13d3edb03 | |||
| 55feeec051 | |||
| 7fa9e21b83 | |||
| 3db36c3093 | |||
| 0eb744f788 | |||
| 17fa67533f | |||
| 5132520108 | |||
| ff87f71be3 | |||
| e9e9b5de2a |
@@ -3,3 +3,5 @@ __pycache__
|
||||
*~
|
||||
*.swp
|
||||
tags
|
||||
.coverage
|
||||
htmlcov
|
||||
|
||||
@@ -2,6 +2,10 @@ language: python
|
||||
sudo: enabled
|
||||
python:
|
||||
- "3.6"
|
||||
|
||||
install:
|
||||
- pip install -r requirements.txt
|
||||
|
||||
# command to run tests
|
||||
script:
|
||||
- make check
|
||||
|
||||
@@ -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
@@ -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``
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
import re
|
||||
import tempfile
|
||||
import configparser
|
||||
@@ -116,6 +117,17 @@ def read_old_metadata():
|
||||
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
|
||||
@@ -270,9 +282,20 @@ def package(args, url, name, archives, workingdir):
|
||||
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:
|
||||
|
||||
+14
-5
@@ -107,7 +107,9 @@ config_options = {
|
||||
"nostrip": "disable stripping binaries",
|
||||
"verify_required": "require package verification for build",
|
||||
"security_sensitive": "set flags for security-sensitive builds",
|
||||
"so_to_lib": "add .so files to the lib package instead of dev"}
|
||||
"so_to_lib": "add .so files to the lib package instead of dev",
|
||||
"autoupdate": "this package is trusted enough to automatically update "
|
||||
"(used by other tools)"}
|
||||
|
||||
# simple_pattern_pkgconfig patterns
|
||||
# contains patterns for parsing build.log for missing dependencies
|
||||
@@ -158,7 +160,9 @@ simple_pats = [
|
||||
(r"Package systemd was not found in the pkg-config search path.", "systemd-dev"),
|
||||
(r"Unable to find the requested Boost libraries.", "boost-dev"),
|
||||
(r"libproc not found. Please configure without procps", "procps-ng-dev"),
|
||||
(r"configure: error: glib2", "glib-dev")]
|
||||
(r"configure: error: glib2", "glib-dev"),
|
||||
(r"C library 'efivar' not found", "efivar-dev"),
|
||||
(r"Has header \"efi.h\": NO", "gnu-efi-dev")]
|
||||
|
||||
# failed_pattern patterns
|
||||
# contains patterns for parsing build.log for missing dependencies
|
||||
@@ -274,7 +278,11 @@ def get_metadata_conf():
|
||||
"""
|
||||
metadata = {}
|
||||
metadata['name'] = tarball.name
|
||||
metadata['url'] = tarball.url
|
||||
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
|
||||
@@ -484,8 +492,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)
|
||||
@@ -507,6 +513,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:
|
||||
|
||||
+9
-31
@@ -211,7 +211,7 @@ def parse_log(log, pkgname=''):
|
||||
|
||||
# apr
|
||||
# testatomic : SUCCESS
|
||||
if re.search(r"\: SUCCESS$", line) and incheck:
|
||||
if re.search(r": SUCCESS$", line) and incheck:
|
||||
counted_pass += 1
|
||||
continue
|
||||
|
||||
@@ -283,7 +283,7 @@ def parse_log(log, pkgname=''):
|
||||
total_fail += convert_int(match.group(1))
|
||||
continue
|
||||
|
||||
match = re.search(r"/== ([0-9]+) failed, ([0-9]+) passed, ([0-9]+) xfailed in ", line)
|
||||
match = re.search(r"== ([0-9]+) failed, ([0-9]+) passed, ([0-9]+) xfailed in ", line)
|
||||
if match and incheck:
|
||||
total_pass += convert_int(match.group(2))
|
||||
total_fail += convert_int(match.group(1))
|
||||
@@ -967,13 +967,6 @@ def parse_log(log, pkgname=''):
|
||||
counted_pass += 1
|
||||
continue
|
||||
|
||||
# apr-util
|
||||
# : SUCCESS
|
||||
match = re.search(r": SUCCESS$", line)
|
||||
if match and incheck:
|
||||
counted_pass += 1
|
||||
continue
|
||||
|
||||
# bash
|
||||
# < Failed 126 of 1378 Unicode tests
|
||||
match = re.search(r"^[<,>] Failed ([0-9]+) of ([0-9]+)", line)
|
||||
@@ -1015,18 +1008,6 @@ def parse_log(log, pkgname=''):
|
||||
counted_pass += 1
|
||||
continue
|
||||
|
||||
# *** zlib test OK ***
|
||||
# *** zlib 64-bit test OK ***
|
||||
match = re.search(r"\*\*\* zlib .*test OK \*\*\*", line)
|
||||
if match and incheck:
|
||||
counted_pass += 1
|
||||
continue
|
||||
|
||||
match = re.search(r"\*\*\* zlib .*test [A-Z!O][A-Z!K] \*\*\*", line)
|
||||
if match and incheck:
|
||||
counted_fail += 1
|
||||
continue
|
||||
|
||||
# LVM2
|
||||
# valgrind pool awareness ... fail
|
||||
# dfa matching ... fail
|
||||
@@ -1104,6 +1085,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)
|
||||
@@ -1288,16 +1276,6 @@ def parse_log(log, pkgname=''):
|
||||
total_skip += 1
|
||||
continue
|
||||
|
||||
match = re.search(r"^Testing .+\ +\*FAILED\*$", line)
|
||||
if match and incheck:
|
||||
total_fail += 1
|
||||
continue
|
||||
|
||||
match = re.search(r"^Verifying .+\ +\*FAILED\*$", line)
|
||||
if match and incheck:
|
||||
total_fail += 1
|
||||
continue
|
||||
|
||||
# libconfig
|
||||
# 3 tests; 3 passed, 0 failed
|
||||
match = re.search(r"^([0-9]+) tests; ([0-9]+) passed\, ([0-9]+) failed", line)
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-2
@@ -75,8 +75,8 @@ def license_from_copying_hash(copying):
|
||||
try:
|
||||
c.perform()
|
||||
except Exception as excep:
|
||||
print_fatal("Failed to fetch license from " + config.license_fetch,
|
||||
excep)
|
||||
print_fatal("Failed to fetch license from {}: {}"
|
||||
.format(config.license_fetch, excep))
|
||||
c.close()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
+12
-21
@@ -66,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()
|
||||
@@ -284,6 +285,7 @@ def name_and_version(name_arg, version_arg, filemanager):
|
||||
global version
|
||||
global url
|
||||
global giturl
|
||||
global repo
|
||||
|
||||
tarfile = os.path.basename(url)
|
||||
|
||||
@@ -332,15 +334,22 @@ def name_and_version(name_arg, version_arg, filemanager):
|
||||
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/v.*/(.*).tar"]
|
||||
r"https?://github.com/(.*)/(.*?)/releases/download/.*?/(.*).tar",
|
||||
r"https?://github.com/(.*)/(.*?)/files/.*?/(.*).tar"]
|
||||
|
||||
for pattern in github_patterns:
|
||||
m = re.search(pattern, url)
|
||||
if m:
|
||||
name = m.group(2).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(3))
|
||||
giturl = "https://github.com/" + m.group(1).strip() + "/" + name + ".git"
|
||||
giturl = "https://github.com/" + m.group(1).strip() + "/" + repo + ".git"
|
||||
break
|
||||
|
||||
if "mirrors.kernel.org" in url:
|
||||
@@ -432,22 +441,6 @@ def find_extract(tar_path, tarfile):
|
||||
return extract_cmd, tar_prefix
|
||||
|
||||
|
||||
def write_makefile(archives):
|
||||
"""
|
||||
Write the new makefile with url, name, and archives
|
||||
"""
|
||||
with open(build.download_path + "/Makefile", "w") as f:
|
||||
f.write("PKG_NAME := " + name + "\n")
|
||||
f.write("URL := " + url + "\n")
|
||||
sep = "ARCHIVES := "
|
||||
for archive in archives:
|
||||
f.write("{}{}".format(sep, archive))
|
||||
sep = " " if sep != " " else " \\\n\t"
|
||||
f.write("\n")
|
||||
f.write("\n")
|
||||
f.write("include ../common/Makefile.common\n")
|
||||
|
||||
|
||||
def prepare_and_extract(extract_cmd):
|
||||
"""
|
||||
Prepare the directory and extract the tarball
|
||||
@@ -523,8 +516,6 @@ def process(url_arg, name_arg, ver_arg, target, archives_arg, 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
|
||||
# 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
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
flake8>=3.4.0
|
||||
pycurl>=7.43.0
|
||||
toml>=0.9.0
|
||||
mock>=2.0.0
|
||||
coverage>=4.4.1
|
||||
|
||||
@@ -2,3 +2,7 @@
|
||||
tag_build =
|
||||
[pycodestyle]
|
||||
ignore = E501
|
||||
|
||||
[coverage:run]
|
||||
# omit tests and travis site-packages
|
||||
omit = tests/*,*site-packages*,*site.py
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
import sys, os
|
||||
version = "1.1.2"
|
||||
version = "1.1.7"
|
||||
|
||||
def readme():
|
||||
with open("README.rst") as f:
|
||||
|
||||
+35
-1
@@ -236,7 +236,7 @@ class TestBuildpattern(unittest.TestCase):
|
||||
self.assertIn('jdk-apache-parent', build.buildreq.buildreqs)
|
||||
self.assertEqual(build.must_restart, 1)
|
||||
|
||||
def test_parse_build_resultsi_pkgconfig(self):
|
||||
def test_parse_build_results_pkgconfig(self):
|
||||
"""
|
||||
Test parse_build_results with a test log indicating failure due to a
|
||||
missing qmake package (pkgconfig error)
|
||||
@@ -314,6 +314,40 @@ class TestBuildpattern(unittest.TestCase):
|
||||
self.assertIn('testpkg-python', build.buildreq.buildreqs)
|
||||
self.assertEqual(build.must_restart, 1)
|
||||
|
||||
def test_parse_build_results_files(self):
|
||||
"""
|
||||
Test parse_build_results with a test log indicating files are missing
|
||||
"""
|
||||
def mock_util_call(cmd):
|
||||
del cmd
|
||||
|
||||
build.config.setup_patterns()
|
||||
call_backup = build.util.call
|
||||
build.util.call = mock_util_call
|
||||
fm = files.FileManager()
|
||||
|
||||
open_name = 'build.open'
|
||||
content = 'line 1\n' \
|
||||
'Installed (but unpackaged) file(s) found:\n' \
|
||||
'/usr/testdir/file\n' \
|
||||
'/usr/testdir/file1\n' \
|
||||
'/usr/testdir/file2\n' \
|
||||
'RPM build errors\n' \
|
||||
'errors here\n'
|
||||
m_open = mock_open(read_data=content)
|
||||
|
||||
with patch(open_name, m_open, create=True):
|
||||
build.parse_build_results('testname', 0, fm)
|
||||
|
||||
build.util.call = call_backup
|
||||
|
||||
self.assertEqual(fm.files,
|
||||
['/usr/testdir/file',
|
||||
'/usr/testdir/file1',
|
||||
'/usr/testdir/file2'])
|
||||
# one for each file added
|
||||
self.assertEqual(build.must_restart, 3)
|
||||
|
||||
def test_get_mock_cmd_without_consolehelper(self):
|
||||
"""
|
||||
Test get_mock_cmd when /usr/bin/mock doesn't point to consolehelper
|
||||
|
||||
+25
-2
@@ -36,6 +36,8 @@ pats = [
|
||||
[332, 281, 38, 0, 13, 0, 0, 0, 0, 0]),
|
||||
('===================== 5 failed, 318 passed in 1.06 seconds =====================',
|
||||
[323, 318, 5, 0, 0, 0, 0, 0, 0, 0]),
|
||||
('===================== 5 failed, 9 passed, 7 xfailed in 1.06 seconds ============',
|
||||
[21, 9, 5, 7, 0, 0, 0, 0, 0, 0]),
|
||||
('============= 1628 passed, 72 skipped, 4 xfailed in 146.26 seconds =============',
|
||||
[1704, 1628, 0, 4, 72, 0, 0, 0, 0, 0]),
|
||||
('=============== 119 passed, 2 skipped, 54 error in 2.19 seconds ================',
|
||||
@@ -87,8 +89,9 @@ pats = [
|
||||
('# of expected passes\t1144\n'
|
||||
'# of expected failures\t57\n'
|
||||
'# of untested testcases\t1\n'
|
||||
'# of unsupported tests\t12',
|
||||
[1213, 1144, 0, 57, 12, 0, 0, 0, 0, 0]),
|
||||
'# of unsupported tests\t12\n'
|
||||
'# of unexpected failures\t1\n',
|
||||
[1214, 1144, 1, 57, 12, 0, 0, 0, 0, 0]),
|
||||
# ccache
|
||||
('PASSED: 448 assertions, 88 tests, 10 suites',
|
||||
[88, 88, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
@@ -179,6 +182,13 @@ pats = [
|
||||
'Failed with core: 0\n'
|
||||
'Unknown status: 0',
|
||||
[13042, 13036, 6, 0, 0, 1, 1, 0, 0, 0]),
|
||||
# nss
|
||||
('cert.sh: #101: Import chain-2-serverCA-ec CA -t u,u,u for localhost.localdomain (ext.) - FAILED\n'
|
||||
'Passed: 13036\n'
|
||||
'Failed: 6\n'
|
||||
'Failed with core: 0\n'
|
||||
'Unknown status: 0',
|
||||
[13042, 13036, 6, 0, 0, 0, 0, 1, 0, 0]),
|
||||
# rsync
|
||||
(' 34 passed\n'
|
||||
' 5 skipped',
|
||||
@@ -191,6 +201,12 @@ pats = [
|
||||
[30, 0, 6, 6, 18, 0, 0, 0, 0, 0]),
|
||||
('FAILED (failures=1, errors=499, skipped=48)',
|
||||
[548, 0, 1, 499, 48, 0, 0, 0, 0, 0]),
|
||||
('FAILED (failures=1, errors=499)',
|
||||
[500, 0, 1, 499, 0, 0, 0, 0, 0, 0]),
|
||||
('FAILED (failures=1)',
|
||||
[1, 0, 1, 0, 0, 0, 0, 0, 0, 0]),
|
||||
('FAILED (errors=1)',
|
||||
[1, 0, 0, 1, 0, 0, 0, 0, 0, 0]),
|
||||
('OK (KNOWNFAIL=5, SKIP=15)',
|
||||
[20, 0, 0, 5, 15, 0, 0, 0, 0, 0]),
|
||||
# qpid-python
|
||||
@@ -304,6 +320,9 @@ pats = [
|
||||
# rubygem-ansi
|
||||
('Executed 12 tests with 7 passing, 5 errors.',
|
||||
[12, 7, 5, 0, 0, 0, 0, 0, 0, 0]),
|
||||
# vim
|
||||
('Executed 12 tests',
|
||||
[12, 12, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
# rubygem-formatador
|
||||
(' 9 succeeded in 0.00375661 seconds',
|
||||
[9, 9, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
@@ -372,8 +391,12 @@ pats = [
|
||||
# hdf5
|
||||
('Testing h5repack h5repack_szip.h5 -f dset_szip:GZIP=1 -SKIP-',
|
||||
[1, 0, 0, 0, 1, 0, 0, 0, 0, 0]),
|
||||
('Verifying h5repack h5repack_szip.h5 -f dset_szip:GZIP=1 -SKIP-',
|
||||
[1, 0, 0, 0, 1, 0, 0, 0, 0, 0]),
|
||||
('Verifying h5dump output -f GZIP=1 -m 1024 *FAILED*',
|
||||
[1, 0, 1, 0, 0, 0, 0, 0, 0, 0]),
|
||||
('Testing h5dump output -f GZIP=1 -m 1024 *FAILED*',
|
||||
[1, 0, 1, 0, 0, 0, 0, 0, 0, 0]),
|
||||
('Testing h5repack --metadata_block_size=8192 PASSED',
|
||||
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
('Verifying h5diff output h5repack_layout.h5 out-meta_long.h5repack_layo PASSED',
|
||||
|
||||
@@ -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)
|
||||
|
||||
+68
-2
@@ -65,6 +65,30 @@ class TestLicense(unittest.TestCase):
|
||||
|
||||
self.assertIn('GPL-3.0', license.licenses)
|
||||
|
||||
def test_license_from_copying_hash_no_license_show(self):
|
||||
"""
|
||||
Test license_from_copying_hash with invalid hash and no license_show
|
||||
set
|
||||
"""
|
||||
# Calls out to tarball.get_sha1sum to get the hash of the license
|
||||
# we might as well test that is returning what it should because it
|
||||
# doesn't call any external resources, it just calculates the hash.
|
||||
open_name = 'tarball.open'
|
||||
with open('tests/COPYING_TEST', 'rb') as copyingf:
|
||||
content = copyingf.read()
|
||||
|
||||
bkup_hash = license.config.license_hashes[license.tarball.get_sha1sum('tests/COPYING_TEST')]
|
||||
# remove the hash from license_hashes
|
||||
del(license.config.license_hashes[license.tarball.get_sha1sum('tests/COPYING_TEST')])
|
||||
license.config.license_show = "license.show.url"
|
||||
m_open = mock_open(read_data=content)
|
||||
with patch(open_name, m_open, create=True):
|
||||
license.license_from_copying_hash('copying.txt')
|
||||
|
||||
# restore the hash
|
||||
license.config.license_hashes[license.tarball.get_sha1sum('tests/COPYING_TEST')] = bkup_hash
|
||||
self.assertEquals(license.licenses, [])
|
||||
|
||||
def test_license_from_copying_hash_bad_license(self):
|
||||
"""
|
||||
Test license_from_copying_hash with invalid license file
|
||||
@@ -83,6 +107,50 @@ class TestLicense(unittest.TestCase):
|
||||
|
||||
self.assertEquals(license.licenses, [])
|
||||
|
||||
@patch('pycurl.Curl')
|
||||
def test_license_from_copying_hash_license_server_excep(self, mock_pycurl_curl):
|
||||
"""
|
||||
Test license_from_copying_hash with license server when pycurl raises
|
||||
an exception.
|
||||
"""
|
||||
class MockCurl():
|
||||
URL = None
|
||||
WRITEDATA = None
|
||||
POSTFIELDS = None
|
||||
def setopt(_, __, ___):
|
||||
pass
|
||||
|
||||
def perform(_):
|
||||
raise Exception('Test Exception')
|
||||
|
||||
def close(_):
|
||||
pass
|
||||
|
||||
# set the mock curl
|
||||
license.pycurl.Curl = MockCurl
|
||||
|
||||
license.config.license_fetch = 'license.server.url'
|
||||
with open('tests/COPYING_TEST', 'rb') as copyingf:
|
||||
content = copyingf.read()
|
||||
|
||||
# Calls out to tarball.get_sha1sum to get the hash of the license
|
||||
# we might as well test that is returning what it should because it
|
||||
# doesn't call any external resources, it just calculates the hash.
|
||||
# Also patch the open in license.py
|
||||
m_open = mock_open(read_data=content)
|
||||
with patch('tarball.open', m_open, create=True):
|
||||
with patch('license.open', m_open, create=True):
|
||||
# let's check that the proper thing is being printed as well
|
||||
out = StringIO()
|
||||
with redirect_stdout(out):
|
||||
with self.assertRaises(SystemExit):
|
||||
license.license_from_copying_hash('copying.txt')
|
||||
|
||||
self.assertIn('Failed to fetch license from ', out.getvalue())
|
||||
|
||||
# unset the manual mock
|
||||
license.pycurl.Curl = pycurl.Curl
|
||||
|
||||
@patch('pycurl.Curl')
|
||||
def test_license_from_copying_hash_license_server(self, mock_pycurl_curl):
|
||||
"""
|
||||
@@ -97,12 +165,10 @@ class TestLicense(unittest.TestCase):
|
||||
return 'GPL-3.0'.encode('utf-8')
|
||||
|
||||
# set the mocks
|
||||
mock_pycurl_curl.return_value = MagicMock()
|
||||
license.BytesIO = MockBytesIO
|
||||
|
||||
license.config.license_fetch = 'license.server.url'
|
||||
with open('tests/COPYING_TEST', 'rb') as copyingf:
|
||||
# note the replace corrupting the file contents
|
||||
content = copyingf.read()
|
||||
|
||||
# Calls out to tarball.get_sha1sum to get the hash of the license
|
||||
|
||||
+35
-81
@@ -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):
|
||||
@@ -85,8 +76,6 @@ class TestDomainBasedVerifiers(unittest.TestCase):
|
||||
return None
|
||||
|
||||
|
||||
@unittest.skipIf("TRAVIS" in os.environ and os.environ["TRAVIS"] == "true",
|
||||
"Skipping this test on Travis CI.")
|
||||
def test_pypi(self):
|
||||
result = self.run_test_for_domain(pkg_integrity.PyPiVerifier, PYPI_MD5_ONLY_PKG)
|
||||
self.assertTrue(result)
|
||||
@@ -96,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):
|
||||
@@ -122,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):
|
||||
@@ -130,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))
|
||||
@@ -143,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))
|
||||
@@ -158,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))
|
||||
@@ -174,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):
|
||||
@@ -212,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):
|
||||
@@ -252,23 +223,6 @@ class TestUtils(unittest.TestCase):
|
||||
false_name = '/false/name'
|
||||
self.assertTrue(pkg_integrity.get_keyid(false_name) is None)
|
||||
|
||||
@unittest.skipIf("TRAVIS" in os.environ and os.environ["TRAVIS"] == "true",
|
||||
"Skipping this test on Travis CI.")
|
||||
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"
|
||||
|
||||
+10
-26
@@ -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
|
||||
|
||||
@@ -160,30 +168,6 @@ class TestTarballVersionName(unittest.TestCase):
|
||||
tarball.build_gem_unpack = build_gem_unpack_backup
|
||||
tarball.build_untar = build_untar_backup
|
||||
|
||||
def test_write_makefile(self):
|
||||
"""
|
||||
Test write_makefile for correct archive format
|
||||
"""
|
||||
archives = ['archive1', 'dest1', 'archive2', 'dest2']
|
||||
build.download_path = '.'
|
||||
tarball.name = 'test'
|
||||
tarball.url = 'url'
|
||||
m_open = mock_open()
|
||||
with patch('tarball.open', m_open, create=True):
|
||||
tarball.write_makefile(archives)
|
||||
|
||||
exp_calls = [call().write('PKG_NAME := test\n'),
|
||||
call().write('URL := url\n'),
|
||||
call().write('ARCHIVES := archive1'),
|
||||
call().write(' dest1'),
|
||||
call().write(' \\\n\tarchive2'),
|
||||
call().write(' dest2'),
|
||||
call().write('\n'),
|
||||
call().write('\n'),
|
||||
call().write('include ../common/Makefile.common\n')]
|
||||
for m_call in exp_calls:
|
||||
self.assertIn(m_call, m_open.mock_calls)
|
||||
|
||||
|
||||
TAR_OUT = 'libjpeg-turbo-1.5.1/\n' \
|
||||
'libjpeg-turbo-1.5.1/md5/\n' \
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
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.
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.
Reference in New Issue
Block a user