diff --git a/.travis.yml b/.travis.yml index 7182e95d..6bd4679c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,15 +5,15 @@ addons: apt: sources: - debian-sid - packages: - - shellcheck -install: "pip install flake8 pytest-cov python-coveralls" +install: + - sudo apt install shellcheck qemu-system-x86 + - pip install flake8 pytest-cov python-coveralls script: - test/static_code_analysis.sh - yes "" | ./pmbootstrap.py init - ./pmbootstrap.py kconfig_check + - test/check_checksums.py --build - test/testcases_fast.sh - - test/check_checksums.py after_success: - coveralls after_failure: diff --git a/aports/main/hello-world/APKBUILD b/aports/main/hello-world/APKBUILD index 2ed7a700..37ee6ca1 100644 --- a/aports/main/hello-world/APKBUILD +++ b/aports/main/hello-world/APKBUILD @@ -1,6 +1,6 @@ pkgname=hello-world pkgver=1 -pkgrel=3 +pkgrel=4 pkgdesc="hello world program to be built in the testsuite" url="https://en.wikipedia.org/wiki/%22Hello,_World!%22_program" arch="all" diff --git a/pmb/build/autodetect.py b/pmb/build/autodetect.py index 2d1c1fd1..51648efb 100644 --- a/pmb/build/autodetect.py +++ b/pmb/build/autodetect.py @@ -17,11 +17,37 @@ You should have received a copy of the GNU General Public License along with pmbootstrap. If not, see . """ import fnmatch +import logging +import os + import pmb.config import pmb.chroot.apk import pmb.parse.arch +def arch_from_deviceinfo(args, pkgname, aport): + """ + The device- packages are noarch packages. But it only makes sense to build + them for the device's architecture, which is specified in the deviceinfo + file. + + :returns: None (no deviceinfo file) + arch from the deviceinfo (e.g. "armhf") + """ + # Require a deviceinfo file in the aport + if not pkgname.startswith("device-"): + return + deviceinfo = aport + "/deviceinfo" + if not os.path.exists(deviceinfo): + return + + # Return its arch + device = pkgname.split("-", 1)[1] + arch = pmb.parse.deviceinfo(args, device)["arch"] + logging.verbose(pkgname + ": arch from deviceinfo: " + arch) + return arch + + def arch(args, pkgname): """ Find a good default in case the user did not specify for which architecture @@ -32,6 +58,10 @@ def arch(args, pkgname): APKBUILD. """ aport = pmb.build.find_aport(args, pkgname) + ret = arch_from_deviceinfo(args, pkgname, aport) + if ret: + return ret + apkbuild = pmb.parse.apkbuild(args, aport + "/APKBUILD") if "noarch" in apkbuild["arch"] or "all" in apkbuild["arch"]: return args.arch_native diff --git a/pmb/helpers/frontend.py b/pmb/helpers/frontend.py index d9958758..3aeb74ab 100644 --- a/pmb/helpers/frontend.py +++ b/pmb/helpers/frontend.py @@ -43,48 +43,28 @@ import pmb.parse import pmb.qemu -def _build_verify_usage_device_package(args, pkgname): +def _build_device_depends_note(args, pkgname): """ - Detect if the user is about to build a device- package for the wrong - architecture. The package is noarch, but the dependencies (kernel!) will get - pulled in with the same arch as dependency. + Previously 'pmbootstrap build device-...' built the device package in the + native chroot without installing its dependencies (e.g. armhf kernel!) and + created a symlink to all supported architectures. + + Not installing depends while building is incompatible with how Alpine's + abuild does it, so we changed the behavior. Now pmbootstrap reads the + device's architecture from the deviceinfo file and automatically builds + for that architecture, if you did not specify any architecture. And the + dependencies get installed correctly before the build. + + To make migration easier for the users, we show a hint if building a device + package was requested. """ - # Skip non-device-packages - if not pkgname.startswith("device-"): + # Only relevant for device packages when -i is not set + if not pkgname.startswith("device-") or getattr(args, "ignore_depends"): return - # Only continue when the --arch parameter is *not* the device architecture - deviceinfo = args.aports + "/device/" + pkgname + "/deviceinfo" - if not os.path.exists(deviceinfo): - return device = pkgname.split("-", 1)[1] - arch = pmb.parse.deviceinfo(args, device)["arch"] - if args.arch == arch: - return - - # Abort with a big note - logging.info("Dependency handling in 'pmbootstrap build' has been" - " changed.") - logging.info("Previously we only built and installed the 'makedepends'" - " from the APKBUILDs, now we use the 'depends', too.") - logging.info("") - logging.info("Your options:") - logging.info("* Ignore depends (fast, old behavior, may cause problems" - " with some packages):") - logging.info(" pmbootstrap build " + pkgname + " -i") - logging.info("* Build with depends (kernel!) and specify the right" - " architecture:") - logging.info(" pmbootstrap build " + pkgname + " --arch=" + arch) - logging.info("") - logging.info("This change was necessary to be more compatible with Alpine's" - " abuild.") - logging.info("The default architecture is the native one (" + - args.arch_native + " in your case), so you need to overwrite") - logging.info("it now to get the kernel dependency of your device package" - " for the right architecture.") - logging.info("Sorry for the inconvenience.") - logging.info("") - raise RuntimeError("Missing -i or --arch parameter") + logging.info("NOTE: " + device + "'s kernel will be installed as dependency" + " before building (old behavior: 'pmbootstrap build -i')") def _parse_flavor(args): @@ -135,10 +115,10 @@ def build(args): if args.strict: pmb.chroot.zap(args, False) - # Detect wrong usage for device- packages + # Detect old usage for device- packages if not args.ignore_depends: for package in args.packages: - _build_verify_usage_device_package(args, package) + _build_device_depends_note(args, package) # Build all packages for package in args.packages: diff --git a/pmb/qemu/run.py b/pmb/qemu/run.py index aca73a13..4645f0e7 100644 --- a/pmb/qemu/run.py +++ b/pmb/qemu/run.py @@ -18,8 +18,9 @@ along with pmbootstrap. If not, see . """ import logging import os -import shutil import re +import signal +import shutil import pmb.build import pmb.chroot @@ -218,6 +219,11 @@ def resize_image(args, img_size_new, img_path): raise RuntimeError("The system image size must be " + img_size_str + " or greater") +def sigterm_handler(number, frame): + raise RuntimeError("pmbootstrap was terminated by another process," + " and killed the Qemu VM it was running.") + + def run(args): """ Run a postmarketOS image in qemu @@ -253,13 +259,15 @@ def run(args): logging.info("* (ssh) ssh -p {port} {user}@localhost".format(**vars(args))) logging.info("* (telnet) telnet localhost " + str(args.port + 1)) - # Run Qemu (or Qemu + SPICE) + # Run Qemu (or Qemu + SPICE) and kill it together with pmbootstrap process = None try: + signal.signal(signal.SIGTERM, sigterm_handler) process = pmb.helpers.run.user(args, qemu, background=spice_enabled) if spice: pmb.helpers.run.user(args, spice) except KeyboardInterrupt: + # Don't show a trace when pressing ^C pass finally: if process: diff --git a/test/check_checksums.py b/test/check_checksums.py index 2ed067d8..c1999fa3 100755 --- a/test/check_checksums.py +++ b/test/check_checksums.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import os import subprocess +import sys def get_changed_files(): @@ -62,7 +63,27 @@ def check_checksums(package): exit(1) +def check_build(packages): + command = (["./pmbootstrap.py", "--details-to-stdout", "build", + "--strict"] + list(packages)) + try: + process = subprocess.Popen(command) + process.communicate() + except subprocess.CalledProcessError as e: + print("** Building failed") + exit(1) + + if __name__ == "__main__": + # Allow to specify "--build" to build instead of only verifying checksums + build = False + if len(sys.argv) > 1: + if sys.argv[1] == "--build": + build = True + else: + print("usage: {} [--build]".format(sys.argv[0])) + exit(1) + if 'TRAVIS_COMMIT_RANGE' in os.environ: print('Checking commit range: {}'.format(os.environ['TRAVIS_COMMIT_RANGE'])) if 'TRAVIS_PULL_REQUEST_BRANCH' in os.environ: @@ -74,6 +95,10 @@ if __name__ == "__main__": print("No aports packages changed in this commit") exit(0) - for package in packages: - print("Checking {} for correct checksums".format(package)) - check_checksums(package) + if build: + print("Building in strict mode: " + ", ".join(packages)) + check_build(packages) + else: + for package in packages: + print("Checking {} for correct checksums".format(package)) + check_checksums(package) diff --git a/test/test_qemu_running_processes.py b/test/test_qemu_running_processes.py new file mode 100644 index 00000000..741f1020 --- /dev/null +++ b/test/test_qemu_running_processes.py @@ -0,0 +1,169 @@ +""" +Copyright 2017 Oliver Smith + +This file is part of pmbootstrap. + +pmbootstrap is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +pmbootstrap is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pmbootstrap. If not, see . +""" + +""" +This file runs various installations and boots into them with Qemu, then checks +via SSH if expected processes are running. + +We use an extra config file (based on ~/.config/pmbootstrap.cfg), because we +need to change it a lot (e.g. UI, username, ...). +""" + +import os +import pytest +import sys +import shutil +import shlex +import time +import logging + +# Import from parent directory +pmb_src = os.path.realpath(os.path.join(os.path.dirname(__file__) + "/..")) +sys.path.append(pmb_src) +import pmb.chroot.apk_static +import pmb.parse.apkindex +import pmb.helpers.logging +import pmb.helpers.run +import pmb.parse.bootimg + + +@pytest.fixture +def args(request): + import pmb.parse + sys.argv = ["pmbootstrap.py", "chroot"] + args = pmb.parse.arguments() + args.log = args.work + "/log_testsuite.txt" + pmb.helpers.logging.init(args) + request.addfinalizer(args.logfd.close) + return args + + +def ssh_create_askpass_script(args): + """Create /tmp/y.sh, which we need to automatically login via SSH.""" + with open(args.work + "/chroot_native/tmp/y.sh", "w") as handle: + handle.write("#!/bin/sh\necho y\n") + pmb.chroot.root(args, ["chmod", "+x", "/tmp/y.sh"]) + + +def pmbootstrap_run(args, config, parameters, background=False): + """Execute pmbootstrap.py with a test pmbootstrap.conf.""" + return pmb.helpers.run.user(args, ["./pmbootstrap.py", "-c", config] + + parameters, working_dir=pmb_src, + background=background) + + +def pmbootstrap_yes(args, config, parameters): + """ + Execute pmbootstrap.py with a test pmbootstrap.conf, and pipe "yes" + into it (so we can do a fully automated installation, using "y" as + password everywhere). + """ + command = "yes | ./pmbootstrap.py -c " + shlex.quote(config) + for parameter in parameters: + command += " " + shlex.quote(parameter) + return pmb.helpers.run.user(args, ["/bin/sh", "-c", command], + working_dir=pmb_src) + + +class Qemu(object): + def __init__(self, request): + self.process = None + request.addfinalizer(self.terminate) + + def terminate(self): + if self.process: + self.process.terminate() + else: + print("WARNING: The Qemu process wasn't set, so it could not be" + " terminated.") + + def run(self, args, tmpdir, ui="none"): + # Copy and adjust user's pmbootstrap.cfg + config = str(tmpdir) + "/pmbootstrap.cfg" + shutil.copyfile(os.path.expanduser("~") + "/.config/pmbootstrap.cfg", + config) + pmbootstrap_run(args, config, ["config", "device", "qemu-amd64"]) + pmbootstrap_run(args, config, ["config", "extra_packages", "none"]) + pmbootstrap_run(args, config, ["config", "user", "testuser"]) + pmbootstrap_run(args, config, ["config", "ui", ui]) + pmbootstrap_run(args, config, ["config", "qemu_native_mesa_driver", "dri-swrast"]) + + # Prepare native chroot + pmbootstrap_run(args, config, ["-y", "zap"]) + pmb.chroot.apk.install(args, ["openssh-client"]) + ssh_create_askpass_script(args) + + # Create and run system image + pmbootstrap_yes(args, config, ["install", "--no-fde"]) + self.process = pmbootstrap_run(args, config, ["qemu", "--display", + "none"], background=True) + logging.info("(test) wait 90s until the VM booted up") + time.sleep(90) + + +@pytest.fixture +def qemu(request): + return Qemu(request) + + +def ssh_run(args, command): + """ + Run a command in the Qemu VM on localhost via SSH. + + :param command: flat string of the command to execute, e.g. "ps au" + :returns: the result from the SSH server + """ + ret = pmb.chroot.user(args, ["SSH_ASKPASS=/tmp/y.sh", "DISPLAY=", "ssh", + "-o", "UserKnownHostsFile=/dev/null", + "-o", "StrictHostKeyChecking=no", + "-p", "2222", "testuser@localhost", "--", + command], + return_stdout=True) + return ret + + +def is_running(args, programs): + """ + Simple check that looks for program names in the output of "ps ax". + This is error-prone, only use it with programs that have a unique name. + """ + all = ssh_run(args, "ps ax") + ret = True + for program in programs: + if program in all: + continue + print(program + ": not found in 'ps ax'!") + ret = False + return ret + + +def test_xfce4(args, tmpdir, qemu): + qemu.run(args, tmpdir, "xfce4") + assert is_running(args, ["xfce4-session", "xfdesktop", "xfce4-panel", + "Thunar", "dbus-daemon", "xfwm4"]) + + # self-test of is_running() + assert is_running(args, ["invalid-process"]) is False + + +def test_plasma_mobile(args, tmpdir, qemu): + # NOTE: Once we have plasma mobile running properly without GL, we can check + # for more processes + qemu.run(args, tmpdir, "plasma-mobile") + assert is_running(args, ["polkitd"]) diff --git a/test/test_version.py b/test/test_version.py index 5f5ea600..0f5e711c 100644 --- a/test/test_version.py +++ b/test/test_version.py @@ -21,8 +21,8 @@ import sys import pytest # Import from parent directory -sys.path.append(os.path.realpath( - os.path.join(os.path.dirname(__file__) + "/.."))) +pmb_src = os.path.realpath(os.path.join(os.path.dirname(__file__) + "/..")) +sys.path.append(pmb_src) import pmb.helpers.git import pmb.helpers.logging import pmb.parse.version @@ -43,11 +43,8 @@ def test_version(args): # Fail after the first error or print a grand total of failures keep_going = False - # Clone official test file from apk-tools - pmb.helpers.git.clone(args, "apk-tools") - path = args.work + "/cache_git/apk-tools/test/version.data" - - # Iterate over the cases from the list + # Iterate over the version tests from apk-tools + path = pmb_src + "/test/testdata/version/version.data" mapping = {-1: "<", 0: "=", 1: ">"} count = 0 errors = [] @@ -64,8 +61,7 @@ def test_version(args): count += 1 if real != expected: if keep_going: - errors.append(line.rstrip() + " (got: '" + real + - "')") + errors.append(line.rstrip() + " (got: '" + real + "')") else: assert real == expected diff --git a/test/testcases_fast.sh b/test/testcases_fast.sh index 1d993661..8e6f2064 100755 --- a/test/testcases_fast.sh +++ b/test/testcases_fast.sh @@ -3,11 +3,9 @@ # Disable slow testcases # aport_in_sync_with_git: clones Alpine's aports repo # aportgen: clones Alpine's aports repo -# version: clones Alpine's apk repo disabled=" aport_in_sync_with_git aportgen - version " # Make sure we have a valid device (#1128) diff --git a/test/testdata/version/README b/test/testdata/version/README new file mode 100644 index 00000000..86cf2e07 --- /dev/null +++ b/test/testdata/version/README @@ -0,0 +1,2 @@ +Source: +https://git.alpinelinux.org/cgit/apk-tools/tree/test/version.data diff --git a/test/testdata/version/version.data b/test/testdata/version/version.data new file mode 100644 index 00000000..59d93cf2 --- /dev/null +++ b/test/testdata/version/version.data @@ -0,0 +1,728 @@ +2.34 > 0.1.0_alpha +23_foo > 4_beta +1.0 < 1.0bc # invalid. do string sort +0.1.0_alpha = 0.1.0_alpha +0.1.0_alpha < 0.1.3_alpha +0.1.3_alpha > 0.1.0_alpha +0.1.0_alpha2 > 0.1.0_alpha +0.1.0_alpha < 2.2.39-r1 +2.2.39-r1 > 1.0.4-r3 +1.0.4-r3 < 1.0.4-r4 +1.0.4-r4 < 1.6 +1.6 > 1.0.2 +1.0.2 > 0.7-r1 +0.7-r1 < 1.0.0 +1.0.0 < 1.0.1 +1.0.1 < 1.1 +1.1 > 1.1_alpha1 +1.1_alpha1 < 1.2.1 +1.2.1 > 1.2 +1.2 < 1.3_alpha +1.3_alpha < 1.3_alpha2 +1.3_alpha2 < 1.3_alpha3 +1.3_alpha8 > 0.6.0 +0.6.0 < 0.6.1 +0.6.1 < 0.7.0 +0.7.0 < 0.8_beta1 +0.8_beta1 < 0.8_beta2 +0.8_beta4 < 4.8-r1 +4.8-r1 > 3.10.18-r1 +3.10.18-r1 > 2.3.0b-r1 +2.3.0b-r1 < 2.3.0b-r2 +2.3.0b-r2 < 2.3.0b-r3 +2.3.0b-r3 < 2.3.0b-r4 +2.3.0b-r4 > 0.12.1 +0.12.1 < 0.12.2 +0.12.2 < 0.12.3 +0.12.3 > 0.12 +0.12 < 0.13_beta1 +0.13_beta1 < 0.13_beta2 +0.13_beta2 < 0.13_beta3 +0.13_beta3 < 0.13_beta4 +0.13_beta4 < 0.13_beta5 +0.13_beta5 > 0.9.12 +0.9.12 < 0.9.13 +0.9.13 > 0.9.12 +0.9.12 < 0.9.13 +0.9.13 > 0.0.16 +0.0.16 < 0.6 +0.6 < 2.1.13-r3 +2.1.13-r3 < 2.1.15-r2 +2.1.15-r2 < 2.1.15-r3 +2.1.15-r3 > 1.2.11 +1.2.11 < 1.2.12.1 +1.2.12.1 < 1.2.13 +1.2.13 < 1.2.14-r1 +1.2.14-r1 > 0.7.1 +0.7.1 > 0.5.4 +0.5.4 < 0.7.0 +0.7.0 < 1.2.13 +1.2.13 > 1.0.8 +1.0.8 < 1.2.1 +1.2.1 > 0.7-r1 +0.7-r1 < 2.4.32 +2.4.32 < 2.8-r4 +2.8-r4 > 0.9.6 +0.9.6 > 0.2.0-r1 +0.2.0-r1 = 0.2.0-r1 +0.2.0-r1 < 3.1_p16 +3.1_p16 < 3.1_p17 +3.1_p17 > 1.06-r6 +1.06-r6 < 006 +006 > 1.0.0 +1.0.0 < 1.2.2-r1 +1.2.2-r1 > 1.2.2 +1.2.2 > 0.3-r1 +0.3-r1 < 9.3.2-r4 +9.3.2-r4 < 9.3.4-r2 +9.3.4-r2 > 9.3.4 +9.3.4 > 9.3.2 +9.3.2 < 9.3.4 +9.3.4 > 1.1.3 +1.1.3 < 2.16.1-r3 +2.16.1-r3 = 2.16.1-r3 +2.16.1-r3 > 2.1.0-r2 +2.1.0-r2 < 2.9.3-r1 +2.9.3-r1 > 0.9-r1 +0.9-r1 > 0.8-r1 +0.8-r1 < 1.0.6-r3 +1.0.6-r3 > 0.11 +0.11 < 0.12 +0.12 < 1.2.1-r1 +1.2.1-r1 < 1.2.2.1 +1.2.2.1 < 1.4.1-r1 +1.4.1-r1 < 1.4.1-r2 +1.4.1-r2 > 1.2.2 +1.2.2 < 1.3 +1.3 > 1.0.3-r6 +1.0.3-r6 < 1.0.4 +1.0.4 < 2.59 +2.59 < 20050718-r1 +20050718-r1 < 20050718-r2 +20050718-r2 > 3.9.8-r5 +3.9.8-r5 > 2.01.01_alpha10 +2.01.01_alpha10 > 0.94 +0.94 < 1.0 +1.0 > 0.99.3.20040818 +0.99.3.20040818 > 0.7 +0.7 < 1.21-r1 +1.21-r1 > 0.13 +0.13 < 0.90.1-r1 +0.90.1-r1 > 0.10.2 +0.10.2 < 0.10.3 +0.10.3 < 1.6 +1.6 < 1.39 +1.39 > 1.00_beta2 +1.00_beta2 > 0.9.2 +0.9.2 < 5.94-r1 +5.94-r1 < 6.4 +6.4 > 2.6-r5 +2.6-r5 > 1.4 +1.4 < 2.8.9-r1 +2.8.9-r1 > 2.8.9 +2.8.9 > 1.1 +1.1 > 1.0.3-r2 +1.0.3-r2 < 1.3.4-r3 +1.3.4-r3 < 2.2 +2.2 > 1.2.6 +1.2.6 < 7.15.1-r1 +7.15.1-r1 > 1.02 +1.02 < 1.03-r1 +1.03-r1 < 1.12.12-r2 +1.12.12-r2 < 2.8.0.6-r1 +2.8.0.6-r1 > 0.5.2.7 +0.5.2.7 < 4.2.52_p2-r1 +4.2.52_p2-r1 < 4.2.52_p4-r2 +4.2.52_p4-r2 > 1.02.07 +1.02.07 < 1.02.10-r1 +1.02.10-r1 < 3.0.3-r9 +3.0.3-r9 > 2.0.5-r1 +2.0.5-r1 < 4.5 +4.5 > 2.8.7-r1 +2.8.7-r1 > 1.0.5 +1.0.5 < 8 +8 < 9 +9 > 2.18.3-r10 +2.18.3-r10 > 1.05-r18 +1.05-r18 < 1.05-r19 +1.05-r19 < 2.2.5 +2.2.5 < 2.8 +2.8 < 2.20.1 +2.20.1 < 2.20.3 +2.20.3 < 2.31 +2.31 < 2.34 +2.34 < 2.38 +2.38 < 20050405 +20050405 > 1.8 +1.8 < 2.11-r1 +2.11-r1 > 2.11 +2.11 > 0.1.6-r3 +0.1.6-r3 < 0.47-r1 +0.47-r1 < 0.49 +0.49 < 3.6.8-r2 +3.6.8-r2 > 1.39 +1.39 < 2.43 +2.43 > 2.0.6-r1 +2.0.6-r1 > 0.2-r6 +0.2-r6 < 0.4 +0.4 < 1.0.0 +1.0.0 < 10-r1 +10-r1 > 4 +4 > 0.7.3-r2 +0.7.3-r2 > 0.7.3 +0.7.3 < 1.95.8 +1.95.8 > 1.1.19 +1.1.19 > 1.1.5 +1.1.5 < 6.3.2-r1 +6.3.2-r1 < 6.3.3 +6.3.3 > 4.17-r1 +4.17-r1 < 4.18 +4.18 < 4.19 +4.19 > 4.3.0 +4.3.0 < 4.3.2-r1 +4.3.2-r1 > 4.3.2 +4.3.2 > 0.68-r3 +0.68-r3 < 1.0.0 +1.0.0 < 1.0.1 +1.0.1 > 1.0.0 +1.0.0 = 1.0.0 +1.0.0 < 1.0.1 +1.0.1 < 2.3.2-r1 +2.3.2-r1 < 2.4.2 +2.4.2 < 20060720 +20060720 > 3.0.20060720 +3.0.20060720 < 20060720 +20060720 > 1.1 +1.1 = 1.1 +1.1 < 1.1.1-r1 +1.1.1-r1 < 1.1.3-r1 +1.1.3-r1 < 1.1.3-r2 +1.1.3-r2 < 2.1.10-r2 +2.1.10-r2 > 0.7.18-r2 +0.7.18-r2 < 0.17-r6 +0.17-r6 < 2.6.1 +2.6.1 < 2.6.3 +2.6.3 < 3.1.5-r2 +3.1.5-r2 < 3.4.6-r1 +3.4.6-r1 < 3.4.6-r2 +3.4.6-r2 = 3.4.6-r2 +3.4.6-r2 > 2.0.33 +2.0.33 < 2.0.34 +2.0.34 > 1.8.3-r2 +1.8.3-r2 < 1.8.3-r3 +1.8.3-r3 < 4.1 +4.1 < 8.54 +8.54 > 4.1.4 +4.1.4 > 1.2.10-r5 +1.2.10-r5 < 4.1.4-r3 +4.1.4-r3 = 4.1.4-r3 +4.1.4-r3 < 4.2.1 +4.2.1 > 4.1.0 +4.1.0 < 8.11 +8.11 > 1.4.4-r1 +1.4.4-r1 < 2.1.9.200602141850 +2.1.9.200602141850 > 1.6 +1.6 < 2.5.1-r8 +2.5.1-r8 < 2.5.1a-r1 +2.5.1a-r1 > 1.19.2-r1 +1.19.2-r1 > 0.97-r2 +0.97-r2 < 0.97-r3 +0.97-r3 < 1.3.5-r10 +1.3.5-r10 > 1.3.5-r8 +1.3.5-r8 < 1.3.5-r9 +1.3.5-r9 > 1.0 +1.0 < 1.1 +1.1 > 0.9.11 +0.9.11 < 0.9.12 +0.9.12 < 0.9.13 +0.9.13 < 0.9.14 +0.9.14 < 0.9.15 +0.9.15 < 0.9.16 +0.9.16 > 0.3-r2 +0.3-r2 < 6.3 +6.3 < 6.6 +6.6 < 6.9 +6.9 > 0.7.2-r3 +0.7.2-r3 < 1.2.10 +1.2.10 < 20040923-r2 +20040923-r2 > 20040401 +20040401 > 2.0.0_rc3-r1 +2.0.0_rc3-r1 > 1.5 +1.5 < 4.4 +4.4 > 1.0.1 +1.0.1 < 2.2.0 +2.2.0 > 1.1.0-r2 +1.1.0-r2 > 0.3 +0.3 < 20020207-r2 +20020207-r2 > 1.31-r2 +1.31-r2 < 3.7 +3.7 > 2.0.1 +2.0.1 < 2.0.2 +2.0.2 > 0.99.163 +0.99.163 < 2.6.15.20060110 +2.6.15.20060110 < 2.6.16.20060323 +2.6.16.20060323 < 2.6.19.20061214 +2.6.19.20061214 > 0.6.2-r1 +0.6.2-r1 < 0.6.3 +0.6.3 < 0.6.5 +0.6.5 < 1.3.5-r1 +1.3.5-r1 < 1.3.5-r4 +1.3.5-r4 < 3.0.0-r2 +3.0.0-r2 < 021109-r3 +021109-r3 < 20060512 +20060512 > 1.24 +1.24 > 0.9.16-r1 +0.9.16-r1 < 3.9_pre20060124 +3.9_pre20060124 > 0.01 +0.01 < 0.06 +0.06 < 1.1.7 +1.1.7 < 6b-r7 +6b-r7 > 1.12-r7 +1.12-r7 < 1.12-r8 +1.12-r8 > 1.1.12 +1.1.12 < 1.1.13 +1.1.13 > 0.3 +0.3 < 0.5 +0.5 < 3.96.1 +3.96.1 < 3.97 +3.97 > 0.10.0-r1 +0.10.0-r1 > 0.10.0 +0.10.0 < 0.10.1_rc1 +0.10.1_rc1 > 0.9.11 +0.9.11 < 394 +394 > 2.31 +2.31 > 1.0.1 +1.0.1 = 1.0.1 +1.0.1 < 1.0.3 +1.0.3 > 1.0.2 +1.0.2 = 1.0.2 +1.0.2 > 1.0.1 +1.0.1 = 1.0.1 +1.0.1 < 1.2.2 +1.2.2 < 2.1.10 +2.1.10 > 1.0.1 +1.0.1 < 1.0.2 +1.0.2 < 3.5.5 +3.5.5 > 1.1.1 +1.1.1 > 0.9.1 +0.9.1 < 1.0.2 +1.0.2 > 1.0.1 +1.0.1 < 1.0.2 +1.0.2 > 1.0.1 +1.0.1 = 1.0.1 +1.0.1 < 1.0.5 +1.0.5 > 0.8.5 +0.8.5 < 0.8.6-r3 +0.8.6-r3 < 2.3.17 +2.3.17 > 1.10-r5 +1.10-r5 < 1.10-r9 +1.10-r9 < 2.0.2 +2.0.2 > 1.1a +1.1a < 1.3a +1.3a > 1.0.2 +1.0.2 < 1.2.2-r1 +1.2.2-r1 > 1.0-r1 +1.0-r1 > 0.15.1b +0.15.1b < 1.0.1 +1.0.1 < 1.06-r1 +1.06-r1 < 1.06-r2 +1.06-r2 > 0.15.1b-r2 +0.15.1b-r2 > 0.15.1b +0.15.1b < 2.5.7 +2.5.7 > 1.1.2.1-r1 +1.1.2.1-r1 > 0.0.31 +0.0.31 < 0.0.50 +0.0.50 > 0.0.16 +0.0.16 < 0.0.25 +0.0.25 < 0.17 +0.17 > 0.5.0 +0.5.0 < 1.1.2 +1.1.2 < 1.1.3 +1.1.3 < 1.1.20 +1.1.20 > 0.9.4 +0.9.4 < 0.9.5 +0.9.5 < 6.3 +6.3 < 6.6 +6.6 > 6.3 +6.3 < 6.6 +6.6 > 1.2.12-r1 +1.2.12-r1 < 1.2.13 +1.2.13 < 1.2.14 +1.2.14 < 1.2.15 +1.2.15 < 8.0.12 +8.0.12 > 8.0.9 +8.0.9 > 1.2.3-r1 +1.2.3-r1 < 1.2.4-r1 +1.2.4-r1 > 0.1 +0.1 < 0.3.5 +0.3.5 < 1.5.22 +1.5.22 > 0.1.11 +0.1.11 < 0.1.12 +0.1.12 < 1.1.4.1 +1.1.4.1 > 1.1.0 +1.1.0 < 1.1.2 +1.1.2 > 1.0.3 +1.0.3 > 1.0.2 +1.0.2 < 2.6.26 +2.6.26 < 2.6.27 +2.6.27 > 1.1.17 +1.1.17 < 1.4.11 +1.4.11 < 22.7-r1 +22.7-r1 < 22.7.3-r1 +22.7.3-r1 > 22.7 +22.7 > 2.1_pre20 +2.1_pre20 < 2.1_pre26 +2.1_pre26 > 0.2.3-r2 +0.2.3-r2 > 0.2.2 +0.2.2 < 2.10.0 +2.10.0 < 2.10.1 +2.10.1 > 02.08.01b +02.08.01b < 4.77 +4.77 > 0.17 +0.17 < 5.1.1-r1 +5.1.1-r1 < 5.1.1-r2 +5.1.1-r2 > 5.1.1 +5.1.1 > 1.2 +1.2 < 5.1 +5.1 > 2.02.06 +2.02.06 < 2.02.10 +2.02.10 < 2.8.5-r3 +2.8.5-r3 < 2.8.6-r1 +2.8.6-r1 < 2.8.6-r2 +2.8.6-r2 > 2.02-r1 +2.02-r1 > 1.5.0-r1 +1.5.0-r1 > 1.5.0 +1.5.0 > 0.9.2 +0.9.2 < 8.1.2.20040524-r1 +8.1.2.20040524-r1 < 8.1.2.20050715-r1 +8.1.2.20050715-r1 < 20030215 +20030215 > 3.80-r4 +3.80-r4 < 3.81 +3.81 > 1.6d +1.6d > 1.2.07.8 +1.2.07.8 < 1.2.12.04 +1.2.12.04 < 1.2.12.05 +1.2.12.05 < 1.3.3 +1.3.3 < 2.6.4 +2.6.4 > 2.5.2 +2.5.2 < 2.6.1 +2.6.1 > 2.6 +2.6 < 6.5.1-r1 +6.5.1-r1 > 1.1.35-r1 +1.1.35-r1 < 1.1.35-r2 +1.1.35-r2 > 0.9.2 +0.9.2 < 1.07-r1 +1.07-r1 < 1.07.5 +1.07.5 > 1.07 +1.07 < 1.19 +1.19 < 2.1-r2 +2.1-r2 < 2.2 +2.2 > 1.0.4 +1.0.4 < 20060811 +20060811 < 20061003 +20061003 > 0.1_pre20060810 +0.1_pre20060810 < 0.1_pre20060817 +0.1_pre20060817 < 1.0.3 +1.0.3 > 1.0.2 +1.0.2 > 1.0.1 +1.0.1 < 3.2.2-r1 +3.2.2-r1 < 3.2.2-r2 +3.2.2-r2 < 3.3.17 +3.3.17 > 0.59s-r11 +0.59s-r11 < 0.65 +0.65 > 0.2.10-r2 +0.2.10-r2 < 2.01 +2.01 < 3.9.10 +3.9.10 > 1.2.18 +1.2.18 < 1.5.11-r2 +1.5.11-r2 < 1.5.13-r1 +1.5.13-r1 > 1.3.12-r1 +1.3.12-r1 < 2.0.1 +2.0.1 < 2.0.2 +2.0.2 < 2.0.3 +2.0.3 > 0.2.0 +0.2.0 < 5.5-r2 +5.5-r2 < 5.5-r3 +5.5-r3 > 0.25.3 +0.25.3 < 0.26.1-r1 +0.26.1-r1 < 5.2.1.2-r1 +5.2.1.2-r1 < 5.4 +5.4 > 1.60-r11 +1.60-r11 < 1.60-r12 +1.60-r12 < 110-r8 +110-r8 > 0.17-r2 +0.17-r2 < 1.05-r4 +1.05-r4 < 5.28.0 +5.28.0 > 0.51.6-r1 +0.51.6-r1 < 1.0.6-r6 +1.0.6-r6 > 0.8.3 +0.8.3 < 1.42 +1.42 < 20030719 +20030719 > 4.01 +4.01 < 4.20 +4.20 > 0.20070118 +0.20070118 < 0.20070207_rc1 +0.20070207_rc1 < 1.0 +1.0 < 1.13.0 +1.13.0 < 1.13.1 +1.13.1 > 0.21 +0.21 > 0.3.7-r3 +0.3.7-r3 < 0.4.10 +0.4.10 < 0.5.0 +0.5.0 < 0.5.5 +0.5.5 < 0.5.7 +0.5.7 < 0.6.11-r1 +0.6.11-r1 < 2.3.30-r2 +2.3.30-r2 < 3.7_p1 +3.7_p1 > 1.3 +1.3 > 0.10.1 +0.10.1 < 4.3_p2-r1 +4.3_p2-r1 < 4.3_p2-r5 +4.3_p2-r5 < 4.4_p1-r6 +4.4_p1-r6 < 4.5_p1-r1 +4.5_p1-r1 > 4.5_p1 +4.5_p1 < 4.5_p1-r1 +4.5_p1-r1 > 4.5_p1 +4.5_p1 > 0.9.8c-r1 +0.9.8c-r1 < 0.9.8d +0.9.8d < 2.4.4 +2.4.4 < 2.4.7 +2.4.7 > 2.0.6 +2.0.6 = 2.0.6 +2.0.6 > 0.78-r3 +0.78-r3 > 0.3.2 +0.3.2 < 1.7.1-r1 +1.7.1-r1 < 2.5.9 +2.5.9 > 0.1.13 +0.1.13 < 0.1.15 +0.1.15 < 0.4 +0.4 < 0.9.6 +0.9.6 < 2.2.0-r1 +2.2.0-r1 < 2.2.3-r2 +2.2.3-r2 < 013 +013 < 014-r1 +014-r1 > 1.3.1-r1 +1.3.1-r1 < 5.8.8-r2 +5.8.8-r2 > 5.1.6-r4 +5.1.6-r4 < 5.1.6-r6 +5.1.6-r6 < 5.2.1-r3 +5.2.1-r3 > 0.11.3 +0.11.3 = 0.11.3 +0.11.3 < 1.10.7 +1.10.7 > 1.7-r1 +1.7-r1 > 0.1.20 +0.1.20 < 0.1.23 +0.1.23 < 5b-r9 +5b-r9 > 2.2.10 +2.2.10 < 2.3.6 +2.3.6 < 8.0.12 +8.0.12 > 2.4.3-r16 +2.4.3-r16 < 2.4.4-r4 +2.4.4-r4 < 3.0.3-r5 +3.0.3-r5 < 3.0.6 +3.0.6 < 3.2.6 +3.2.6 < 3.2.7 +3.2.7 > 0.3.1_rc8 +0.3.1_rc8 < 22.2 +22.2 < 22.3 +22.3 > 1.2.2 +1.2.2 < 2.04 +2.04 < 2.4.3-r1 +2.4.3-r1 < 2.4.3-r4 +2.4.3-r4 > 0.98.6-r1 +0.98.6-r1 < 5.7-r2 +5.7-r2 < 5.7-r3 +5.7-r3 > 5.1_p4 +5.1_p4 > 1.0.5 +1.0.5 < 3.6.19-r1 +3.6.19-r1 > 3.6.19 +3.6.19 > 1.0.1 +1.0.1 < 3.8 +3.8 > 0.2.3 +0.2.3 < 1.2.15-r3 +1.2.15-r3 > 1.2.6-r1 +1.2.6-r1 < 2.6.8-r2 +2.6.8-r2 < 2.6.9-r1 +2.6.9-r1 > 1.7 +1.7 < 1.7b +1.7b < 1.8.4-r3 +1.8.4-r3 < 1.8.5 +1.8.5 < 1.8.5_p2 +1.8.5_p2 > 1.1.3 +1.1.3 < 3.0.22-r3 +3.0.22-r3 < 3.0.24 +3.0.24 = 3.0.24 +3.0.24 = 3.0.24 +3.0.24 < 4.0.2-r5 +4.0.2-r5 < 4.0.3 +4.0.3 > 0.98 +0.98 < 1.00 +1.00 < 4.1.4-r1 +4.1.4-r1 < 4.1.5 +4.1.5 > 2.3 +2.3 < 2.17-r3 +2.17-r3 > 0.1.7 +0.1.7 < 1.11 +1.11 < 4.2.1-r11 +4.2.1-r11 > 3.2.3 +3.2.3 < 3.2.4 +3.2.4 < 3.2.8 +3.2.8 < 3.2.9 +3.2.9 > 3.2.3 +3.2.3 < 3.2.4 +3.2.4 < 3.2.8 +3.2.8 < 3.2.9 +3.2.9 > 1.4.9-r2 +1.4.9-r2 < 2.9.11_pre20051101-r2 +2.9.11_pre20051101-r2 < 2.9.11_pre20051101-r3 +2.9.11_pre20051101-r3 > 2.9.11_pre20051101 +2.9.11_pre20051101 < 2.9.11_pre20061021-r1 +2.9.11_pre20061021-r1 < 2.9.11_pre20061021-r2 +2.9.11_pre20061021-r2 < 5.36-r1 +5.36-r1 > 1.0.1 +1.0.1 < 7.0-r2 +7.0-r2 > 2.4.5 +2.4.5 < 2.6.1.2 +2.6.1.2 < 2.6.1.3-r1 +2.6.1.3-r1 > 2.6.1.3 +2.6.1.3 < 2.6.1.3-r1 +2.6.1.3-r1 < 12.17.9 +12.17.9 > 1.1.12 +1.1.12 > 1.1.7 +1.1.7 < 2.5.14 +2.5.14 < 2.6.6-r1 +2.6.6-r1 < 2.6.7 +2.6.7 < 2.6.9-r1 +2.6.9-r1 > 2.6.9 +2.6.9 > 1.39 +1.39 > 0.9 +0.9 < 2.61-r2 +2.61-r2 < 4.5.14 +4.5.14 > 4.09-r1 +4.09-r1 > 1.3.1 +1.3.1 < 1.3.2-r3 +1.3.2-r3 < 1.6.8_p12-r1 +1.6.8_p12-r1 > 1.6.8_p9-r2 +1.6.8_p9-r2 > 1.3.0-r1 +1.3.0-r1 < 3.11 +3.11 < 3.20 +3.20 > 1.6.11-r1 +1.6.11-r1 > 1.6.9 +1.6.9 < 5.0.5-r2 +5.0.5-r2 > 2.86-r5 +2.86-r5 < 2.86-r6 +2.86-r6 > 1.15.1-r1 +1.15.1-r1 < 8.4.9 +8.4.9 > 7.6-r8 +7.6-r8 > 3.9.4-r2 +3.9.4-r2 < 3.9.4-r3 +3.9.4-r3 < 3.9.5-r2 +3.9.5-r2 > 1.1.9 +1.1.9 > 1.0.6 +1.0.6 < 5.9 +5.9 < 6.5 +6.5 > 0.40-r1 +0.40-r1 < 2.25b-r5 +2.25b-r5 < 2.25b-r6 +2.25b-r6 > 1.0.4 +1.0.4 < 1.0.5 +1.0.5 < 1.4_p12-r2 +1.4_p12-r2 < 1.4_p12-r5 +1.4_p12-r5 > 1.1 +1.1 > 0.2.0-r1 +0.2.0-r1 < 0.2.1 +0.2.1 < 0.9.28-r1 +0.9.28-r1 < 0.9.28-r2 +0.9.28-r2 < 0.9.28.1 +0.9.28.1 > 0.9.28 +0.9.28 < 0.9.28.1 +0.9.28.1 < 087-r1 +087-r1 < 103 +103 < 104-r11 +104-r11 > 104-r9 +104-r9 > 1.23-r1 +1.23-r1 > 1.23 +1.23 < 1.23-r1 +1.23-r1 > 1.0.2 +1.0.2 < 5.52-r1 +5.52-r1 > 1.2.5_rc2 +1.2.5_rc2 > 0.1 +0.1 < 0.71-r1 +0.71-r1 < 20040406-r1 +20040406-r1 > 2.12r-r4 +2.12r-r4 < 2.12r-r5 +2.12r-r5 > 0.0.7 +0.0.7 < 1.0.3 +1.0.3 < 1.8 +1.8 < 7.0.17 +7.0.17 < 7.0.174 +7.0.174 > 7.0.17 +7.0.17 < 7.0.174 +7.0.174 > 1.0.1 +1.0.1 < 1.1.1-r3 +1.1.1-r3 > 0.3.4_pre20061029 +0.3.4_pre20061029 < 0.4.0 +0.4.0 > 0.1.2 +0.1.2 < 1.10.2 +1.10.2 < 2.16 +2.16 < 28 +28 > 0.99.4 +0.99.4 < 1.13 +1.13 > 1.0.1 +1.0.1 < 1.1.2-r2 +1.1.2-r2 > 1.1.0 +1.1.0 < 1.1.1 +1.1.1 = 1.1.1 +1.1.1 > 0.6.0 +0.6.0 < 6.6.3 +6.6.3 > 1.1.1 +1.1.1 > 1.1.0 +1.1.0 = 1.1.0 +1.1.0 > 0.2.0 +0.2.0 < 0.3.0 +0.3.0 < 1.1.1 +1.1.1 < 1.2.0 +1.2.0 > 1.1.0 +1.1.0 < 1.6.5 +1.6.5 > 1.1.0 +1.1.0 < 1.4.2 +1.4.2 > 1.1.1 +1.1.1 < 2.8.1 +2.8.1 > 1.2.0 +1.2.0 < 4.1.0 +4.1.0 > 0.4.1 +0.4.1 < 1.9.1 +1.9.1 < 2.1.1 +2.1.1 > 1.4.1 +1.4.1 > 0.9.1-r1 +0.9.1-r1 > 0.8.1 +0.8.1 < 1.2.1-r1 +1.2.1-r1 > 1.1.0 +1.1.0 < 1.2.1 +1.2.1 > 1.1.0 +1.1.0 > 0.1.1 +0.1.1 < 1.2.1 +1.2.1 < 4.1.0 +4.1.0 > 0.2.1-r1 +0.2.1-r1 < 1.1.0 +1.1.0 < 2.7.11 +2.7.11 > 1.0.2-r6 +1.0.2-r6 > 1.0.2 +1.0.2 > 0.8 +0.8 < 1.1.1-r4 +1.1.1-r4 < 222 +222 > 1.0.1 +1.0.1 < 1.2.12-r1 +1.2.12-r1 > 1.2.8 +1.2.8 < 1.2.9.1-r1 +1.2.9.1-r1 > 1.2.9.1 +1.2.9.1 < 2.31-r1 +2.31-r1 > 2.31 +2.31 > 1.2.3-r1 +1.2.3-r1 > 1.2.3 +1.2.3 < 4.2.5 +4.2.5 < 4.3.2-r2 +1.3-r0 < 1.3.1-r0 +1.3_pre1-r1 < 1.3.2 +1.0_p10-r0 > 1.0_p9-r0 +0.1.0_alpha_pre2 < 0.1.0_alpha