ubuntu-make-16.02.1/0000775000000000000000000000000012656574625011030 5ustar ubuntu-make-16.02.1/enable_completion0000664000000000000000000000015412656574623014430 0ustar # just source that file to enable shell completion on umake eval "$(register-python-argcomplete bin/umake)" ubuntu-make-16.02.1/runtests0000775000000000000000000003775612656574623012665 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import argparse import configparser import logging import logging.config import nose import os import yaml import shutil import subprocess import sys import tempfile root_dir = os.path.abspath(os.path.dirname(__file__)) config_dir = os.path.join(root_dir, 'confs') DEBUG_CONFIG_FILE = os.path.join(config_dir, "debug.nose") COVERAGE_CONFIG_FILE = os.path.join(config_dir, "prod.nose") TESTS_DIR = os.path.join(root_dir, 'tests') DEBUG_LOG_CONFIG = os.path.join(config_dir, "debug.logcfg") TESTING_LOG_CONFIG = os.path.join(config_dir, "testing.logcfg") # subprocess need to output on stdout the logs to be monitored # the profile is the testing one + console output in warning mode TESTING_SUBPROCESS_LOG_CONFIG = os.path.join(config_dir, "testing.subprocess.logcfg") def transform_nose_config_to_cmd(filename): """Manually transform a nose config file to a cmd parameters This is needed in case the same parameter is repeated multiple times This return the cmd line array parameters.""" cmd_line = [] config = configparser.ConfigParser() config.read(filename) for key in config["nosetests"]: value = config["nosetests"][key] if value == '1': cmd_line.append('--' + key) # multiple values (what the config parameter for nose doesn't support) elif ',' in value: for val in value.split(','): cmd_line.append('--{}={}'.format(key, val)) else: cmd_line.append('--{}={}'.format(key, value)) return cmd_line def set_logging_profile(log_config_file): """Set logging profile for current process and subprocesses""" with open(log_config_file, 'rt') as f: logging_config = yaml.load(f.read()) logging.config.dictConfig(logging_config) os.environ["LOG_CFG"] = log_config_file if log_config_file == TESTING_LOG_CONFIG: os.environ["LOG_CFG"] = TESTING_SUBPROCESS_LOG_CONFIG def local_run(args): """Run directly the tests on the host""" # setup the environment in plain english so that we standardize the test bed (if some people have some .mo # Ubuntu Make files installed while having a locale set to it) to avoid getting translated strings not # matching our expectations. os.environ["LANGUAGE"] = "C" nose_args = [] # nosetests captured logs format nose_args.extend(["--logging-format", "%(asctime)s [%(name)s] %(levelname)s: %(message)s"]) ## handle config first specified_config = False if args.config: nose_args.extend(["--config", args.config]) specified_config = True elif args.debug: nose_args.extend(["--config", DEBUG_CONFIG_FILE]) set_logging_profile(DEBUG_LOG_CONFIG) specified_config = True elif args.coverage: nose_args.extend(transform_nose_config_to_cmd(COVERAGE_CONFIG_FILE)) set_logging_profile(TESTING_LOG_CONFIG) specified_config = True elif args.no_config: specified_config = True ## output xunit and json if requested if args.publish: nose_args.append("--with-xunit") # FIXME: disable nose-json for now, incompatible with coverage reporting when an exception is raised. # we are going to switch to nose2 anyway. #nose_args.append("--with-json") ## check if we want to run those tests with the system code if args.system: nose_args.append("-P") # let remove it from there as well sys.path.remove(root_dir) else: import tests tests.tools.set_local_umake() if not "all" in args.tests and len(args.tests) > 0: for test_type in args.tests: for named_test_type in ("small", "medium", "large", "pep8"): if test_type == named_test_type: if test_type == "pep8": nose_args.append(os.path.join(TESTS_DIR, "__init__.py")) else: nose_args.append(os.path.join(TESTS_DIR, named_test_type)) break # Not a named test_type, but a list of tests to run else: nose_args.append(test_type) # If no config is given, choose debug by default for partial run if not specified_config: nose_args.extend(["--config", DEBUG_CONFIG_FILE]) set_logging_profile(DEBUG_LOG_CONFIG) specified_config = True else: # If no config is given, run with coverage if not specified_config: nose_args.extend(transform_nose_config_to_cmd(COVERAGE_CONFIG_FILE)) set_logging_profile(TESTING_LOG_CONFIG) specified_config = True ## need a fake $0 argument nose_args.insert(0, "") nose.main(argv=nose_args) def vm_run(args): """Run the tests on a qemu vm""" artefacts_dir = tempfile.mkdtemp(prefix="umake-test-artefacts-") cmds = ['adt-run', '-s', # add ubuntu-make and ubuntu-make-builddeps ppas with their gpg key '--setup-commands', """apt-key adv --keyserver keyserver.ubuntu.com --recv-key 399B698EEA9EF163B6F9A0F62CC98497A1231595; echo "deb http://ppa.launchpad.net/ubuntu-desktop/ubuntu-make-builddeps/ubuntu trusty main" > /etc/apt/sources.list.d/autopkgtest-ubuntu-desktop-ubuntu-make-builddeps.list; echo "deb-src http://ppa.launchpad.net/ubuntu-desktop/ubuntu-make-builddeps/ubuntu trusty main" >> /etc/apt/sources.list.d/autopkgtest-ubuntu-desktop-ubuntu-make-builddeps.list; echo "deb http://ppa.launchpad.net/ubuntu-desktop/ubuntu-make/ubuntu trusty main" > /etc/apt/sources.list.d/autopkgtest-ubuntu-desktop-ubuntu-make.list; echo "deb-src http://ppa.launchpad.net/ubuntu-desktop/ubuntu-make/ubuntu trusty main" >> /etc/apt/sources.list.d/autopkgtest-ubuntu-desktop-ubuntu-make.list; apt-get update""", # artefacts saving "--output-dir", artefacts_dir, # env variables setting up tests '--env', "TESTS={}".format(' '.join(args.tests))] # default target to test is current tree target = ['--built-tree', '.'] # test package from archive or ppa (the most recent) if args.test_package: target = ["--apt-source", "ubuntu-make"] # git checkout testing if args.test_git: target = ['--no-built-binaries', "--git-source", args.test_git] # local source package testing if args.test_source: target = ["--source", args.test_source] cmds.extend(target) # add emulator options cmds.extend(['---', 'qemu', '-o', '/var/tmp', args.image]) try: return_code = subprocess.call(cmds) print("Artefacts are available at {}".format(artefacts_dir)) except FileNotFoundError: print("adt-run isn't installed.") shutil.rmtree(artefacts_dir) return_code = 1 sys.exit(return_code) def remote_run(args): """Start a run on the official ubuntu instances""" # Note that we wrap arguments containing spaces with double quoting as they are passed through ssh # ssh connection to snakefruit cmds = ["ssh", "snakefruit.canonical.com", "sudo", "-i", "-u", "ubuntu-archive", # run-autopkgtest command "run-autopkgtest", "-s", args.series, # ensure we always add the ppa to be in correct swift container archive "--ppa", "ubuntu-desktop/ubuntu-make-builddeps", "--ppa", "ubuntu-desktop/ubuntu-make", # env variables setting up tests (with double quoting '--env', "'TESTS={}'".format(' '.join(args.tests))] # add architectures if any: for arch in args.architecture: cmds.extend(["-a", arch]) target = [] if args.test_package: target = ["ubuntu-make"] # git checkout testing, put results under ubuntu-make-git tag if args.test_git: target = ["--test-git", "'{}'".format(args.test_git), "ubuntu-make-git"] cmds.extend(target) sys.exit(subprocess.call(cmds)) def add_tests_arg(parser): """add the generic tests arguments to the parser""" parser.add_argument("tests", nargs='*', help="Action to perform: all (or omitted) to run all tests. " "small/medium/large/pep8 or nose syntax: " "tests.small.test_frameworks_loader:TestFrameworkLoaderSaveConfig.foo") class _GlobalHelp(argparse._HelpAction): def __call__(self, parser, namespace, values, option_string=None): parser.print_help() # retrieve local subparser from parser subparsers_actions = [ action for action in parser._actions if isinstance(action, argparse._SubParsersAction)] print(""" ------------------------------------------- Default mode is 'local' and can be omitted. -------------------------------------------""") subparsers_actions[0].choices['local'].print_help() parser.exit() if __name__ == '__main__': # ensure we have the right chmod on the ssh key to connect to docker containers (git by default reverts to x44) os.chmod(os.path.join(root_dir, "docker", "umake_docker"), 0o600) parser = argparse.ArgumentParser(description="Run umake tests. Specified list of test run in debug mode. " "Running a partial suite of tests is using a normal mode. " "Running all tests is using coverage by default.", add_help=False) parser.add_argument('--help', action=_GlobalHelp, help='Show this help') command_group = parser.add_subparsers(help='What mode to run tests with') local_mode = command_group.add_parser('local', help='run tests locally (default). Enable easy debugging but large ' 'tests requires sudo and impact your sessions.') vm_mode = command_group.add_parser('vm', help='run tests with vm_mode running on a qemu image.') remote_mode = command_group.add_parser('remote', help='run on official autopkgtests ubuntu instances (only for ' 'ubuntu archive admins or release team members)') ## local options local_mode.set_defaults(run=local_run) add_tests_arg(local_mode) local_mode.add_argument('-s', "--system", action="store_true", help="Use system umake instead of local one") local_mode.add_argument("--publish", action="store_true", help="Publish xunit results format") config_group = local_mode.add_argument_group('Run configuration options', description="The default configuration is to use the debug profile " "when running some manually specific list of tests. No profile is " "selected when running some suites of tests and coverage " "profile when selecting all tests.")\ .add_mutually_exclusive_group() config_group.add_argument("-c", "--config", help="Force using a particular nose profile, disable autoselection") config_group.add_argument("--coverage", action="store_true", help="Force using coverage profile even when some " "tests or tessuite") config_group.add_argument("--debug", action="store_true", help="Force using debug profile even when running " "all tests") config_group.add_argument("--no-config", action="store_true", help="Disable any automated or manual config " "selection") ## vm options vm_mode.set_defaults(run=vm_run) vm_mode.add_argument('image', metavar="image_path", help="Image against which running the tests. This is what " "determines as well the release and arch against which " "we are testing on. You can build one cloud image via: " "'buildvm-ubuntu-cloud -r trusty' for instance.") add_tests_arg(vm_mode) target_group = vm_mode.add_argument_group('Ubuntu Make test target', description="This defines which Ubuntu Make you want to test. Default " "is the local tree (what's your pwd). You can change it " "for a git tree/branch or package from archive.")\ .add_mutually_exclusive_group() target_group.add_argument("--test-git", metavar='GITURL [branchname]', help="A single URL or URL branchname. The test will be git cloned from " "that URL and ran from the checkout. This will not build binary " "packages from the branch and run tests against those, the test " "dependencies will be taken from the archive, or Ubuntu Make PPA.") target_group.add_argument("--test-package", action="store_true", help="Test the ubuntu-make package (system run) " "from the archive or Ubuntu Make PPA.") target_group.add_argument("--test-source", metavar='DSC or some/pkg.dsc', help='Build DSC and use its tests and/or generated binary packages') ## remote options remote_mode.set_defaults(run=remote_run) remote_mode.add_argument("series", help='Distro series name.') add_tests_arg(remote_mode) remote_mode.add_argument('-a', '--architecture', action='append', default=[], help='Only run test(s) on given architecture name(s). ' 'Can be specified multiple times (default: all).') target_group = remote_mode.add_argument_group('Ubuntu Make test target', description="This defines which Ubuntu Make you want to test. You " "can change between a git tree/branch of package from " "archive.")\ .add_mutually_exclusive_group(required=True) target_group.add_argument("--test-package", action="store_true", help="Test the ubuntu-make package (system run) " "from the archive or Ubuntu Make PPA.") target_group.add_argument("--test-git", metavar='GITURL [branchname]', help="A single URL or URL branchname. The test will be git cloned from " "that URL and ran from the checkout. This will not build binary " "packages from the branch and run tests against those, the test " "dependencies will be taken from the archive, or Ubuntu Make PPA.") # set local as default and parse cmd = sys.argv[1:] if "--help" not in cmd: if cmd[0] not in ["local", "vm", "remote"]: cmd.insert(0, "local") args = parser.parse_args(cmd) args.run(args) ubuntu-make-16.02.1/confs/0000775000000000000000000000000012656574623012136 5ustar ubuntu-make-16.02.1/confs/debug.nose0000664000000000000000000000005012656574623014105 0ustar [nosetests] nocapture=1 nologcapture=1 ubuntu-make-16.02.1/confs/debug_network.logcfg0000664000000000000000000000140212656574623016155 0ustar version: 1 disable_existing_loggers: False formatters: simple: format: "[%(name)s] %(levelname)s: %(message)s" with_time: format: "%(asctime)s [%(name)s] %(levelname)s: %(message)s" handlers: console: class: logging.StreamHandler level: DEBUG formatter: simple stream: ext://sys.stdout debug_network_file_handler: class: logging.handlers.RotatingFileHandler level: DEBUG formatter: with_time filename: debug_network.log maxBytes: 10485760 # 10MB backupCount: 20 encoding: utf8 loggers: umake.network: level: DEBUG handlers: [console, debug_network_file_handler] propagate: no root: level: INFO handlers: [console] ubuntu-make-16.02.1/confs/prod.nose0000664000000000000000000000014012656574623013763 0ustar [nosetests] with-cov=1 cov=umake cov-report=term-missing,html,xml cov-config=confs/coverage.cov ubuntu-make-16.02.1/confs/debug.logcfg0000664000000000000000000000121112656574623014402 0ustar version: 1 disable_existing_loggers: False formatters: simple: format: "[%(name)s] %(levelname)s: %(message)s" with_time: format: "%(asctime)s [%(name)s] %(levelname)s: %(message)s" handlers: console: class: logging.StreamHandler level: DEBUG formatter: simple stream: ext://sys.stdout debug_file_handler: class: logging.handlers.RotatingFileHandler level: DEBUG formatter: with_time filename: debug.log maxBytes: 10485760 # 10MB backupCount: 20 encoding: utf8 root: level: DEBUG handlers: [console, debug_file_handler] ubuntu-make-16.02.1/confs/githooks/0000775000000000000000000000000012656574623013765 5ustar ubuntu-make-16.02.1/confs/githooks/prepare-commit-msg0000775000000000000000000000264012656574623017425 0ustar #!/bin/sh # # We ensure we bump everything needed when doing a release. # We do not use debcommit, but just put "releasing" in the changelog, # we match "releas", ignoring the case and change+tag version # 0. Ensuring that we have some UNRELEASED content in debian/changelog # 1. Compute the new release number, based on older umake/version # 2. We update umake/version with the new release number # 3. Bumping debian/changelog version as well # 4. Then, modifying the commit message itself to match the correct version grep -qi "create release" $1 found=$? set -e # we are releasing a version, generate the version if [ $found -eq 0 ]; then scriptdir=$(dirname $(readlink -f $0)) rootdir="$scriptdir/../.." releasingfile="$rootdir/.git/releasing" # if we are already releasing (and so, amending the commit), don't redo anything (avoid loop) if [ -f $releasingfile ]; then exit 0 fi head -1 ${rootdir}/debian/changelog | grep -q UNRELEASED if [ $? -ne 0 ]; then echo "This commits says that it's releasing, but no UNRELEASED in debian/changelog, exiting" exit 1 fi # get a new valid version. This updates umake/version as well version=$(${scriptdir}/update_version git add ${rootdir}/umake/version) dch -v ${version} "" dch -r "" --distribution xenial git add ${rootdir}/debian/changelog echo "releasing package ubuntu-make ${version}" > $1 fi ubuntu-make-16.02.1/confs/githooks/update_version0000775000000000000000000000344712656574623016752 0ustar #!/usr/bin/python3 # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import datetime import os import sys if __name__ == '__main__': version_file_path = os.path.join(os.path.dirname(__file__), "..", "..", "umake", "version") version_tempfile_path = "{}.new".format(version_file_path) version = '{:%y.%m}'.format(datetime.datetime.now()) old_version = open(version_file_path, 'r', encoding='utf-8').read().strip() if old_version[0:5] == version: minor = old_version[6:] # need to bump to a minor version if minor: try: minor = int(minor) + 1 version += ".{}".format(minor) except ValueError: print("{} hasn't the expected format: YY.MM.".format(old_version)) sys.exit(1) # there was no minor version, so add first one else: version += ".1" # write new version file with open(version_tempfile_path, 'w', encoding="utf-8") as f: f.write(version) f.flush() os.fsync(f.fileno()) os.rename(version_tempfile_path, version_file_path) print(version) ubuntu-make-16.02.1/confs/githooks/post-commit0000775000000000000000000000124012656574623016163 0ustar #!/bin/sh # # Amend and tag releasing commit to take into account added autogenerated # or updated files in the pre commit hooks. git log -1 HEAD | grep -qi "releasing package" found=$? set -e # we are on a release commit, add missing files and tag if [ $found -eq 0 ]; then rootdir="$(dirname $(readlink -f $0))/../.." releasingfile="$rootdir/.git/releasing" # if we are already releasing (and so, amending the commit), don't redo anything (avoid loop) if [ -f $releasingfile ]; then rm $releasingfile exit 0 fi touch $releasingfile git commit --amend -C HEAD --no-verify git tag -f $(cat ${rootdir}/umake/version) fi ubuntu-make-16.02.1/confs/githooks/pre-commit0000775000000000000000000000316512656574623015774 0ustar #!/bin/sh # # only have this pre-commit check on master if [ "`git name-rev --name-only HEAD`" != "master" ]; then exit 0 fi if git rev-parse --verify HEAD >/dev/null 2>&1 then against=HEAD else # Initial commit: diff against an empty tree object against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 fi # If you want to allow non-ASCII filenames set this variable to true. allownonascii=$(git config --bool hooks.allownonascii) # Redirect output to stderr. exec 1>&2 # Cross platform projects tend to avoid non-ASCII filenames; prevent # them from being added to the repository. We exploit the fact that the # printable range starts at the space character and ends with tilde. if [ "$allownonascii" != "true" ] && # Note that the use of brackets around a tr range is ok here, (it's # even required, for portability to Solaris 10's /usr/bin/tr), since # the square bracket bytes happen to fall in the designated range. test $(git diff --cached --name-only --diff-filter=A -z $against | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 then cat <<\EOF Error: Attempt to add a non-ASCII file name. This can cause problems if you want to work with people on other platforms. To be portable it is advisable to rename the file. If you know what you are doing you can disable this check using: git config hooks.allownonascii true EOF exit 1 fi # If there are whitespace errors, print the offending file names and fail. ##We let download page being offending #git diff-index --check --cached $against -- # Run pep8 and small tests ##git stash -q --keep-index ./runtests pep8 small RESULT=$? ##git stash pop -q [ $RESULT -ne 0 ] && exit 1 exit 0 ubuntu-make-16.02.1/confs/info.logcfg0000664000000000000000000000046412656574623014260 0ustar version: 1 disable_existing_loggers: True formatters: simple: format: "[%(name)s] %(levelname)s: %(message)s" handlers: console: class: logging.StreamHandler level: INFO formatter: simple stream: ext://sys.stdout root: level: INFO handlers: [console] ubuntu-make-16.02.1/confs/completions/0000775000000000000000000000000012656574623014472 5ustar ubuntu-make-16.02.1/confs/completions/_umake0000664000000000000000000000017412656574623015660 0ustar #compdef umake # we use bash global completion autoload -Uz bashcompinit bashcompinit source /etc/bash_completion.d/umake ubuntu-make-16.02.1/confs/testing.logcfg0000664000000000000000000000200512656574623014773 0ustar version: 1 disable_existing_loggers: False formatters: simple: format: "[%(name)s] %(levelname)s: %(message)s" with_time: format: "%(asctime)s [%(name)s] %(levelname)s: %(message)s" handlers: debug_file_handler: class: logging.handlers.RotatingFileHandler level: DEBUG formatter: with_time filename: debug.log maxBytes: 10485760 # 10MB backupCount: 20 encoding: utf8 info_file_handler: class: logging.handlers.RotatingFileHandler level: INFO formatter: with_time filename: info.log maxBytes: 10485760 # 10MB backupCount: 20 encoding: utf8 warn_error_file_handler: class: logging.handlers.RotatingFileHandler level: WARNING formatter: with_time filename: errors.log maxBytes: 10485760 # 10MB backupCount: 20 encoding: utf8 root: level: DEBUG handlers: [debug_file_handler, info_file_handler, warn_error_file_handler] ubuntu-make-16.02.1/confs/coverage.cov0000664000000000000000000000011612656574623014440 0ustar # coverage should export html to coverage-html [html] directory=html-coverage ubuntu-make-16.02.1/confs/testingsubprocess.logcfg0000664000000000000000000000222212656574623017105 0ustar version: 1 disable_existing_loggers: False formatters: simple: format: "[%(name)s] %(levelname)s: %(message)s" with_time: format: "%(asctime)s [%(name)s] %(levelname)s: %(message)s" handlers: console: class: logging.StreamHandler level: WARNING formatter: simple stream: ext://sys.stdout debug_file_handler: class: logging.handlers.RotatingFileHandler level: DEBUG formatter: with_time filename: debug.log maxBytes: 10485760 # 10MB backupCount: 20 encoding: utf8 info_file_handler: class: logging.handlers.RotatingFileHandler level: INFO formatter: with_time filename: info.log maxBytes: 10485760 # 10MB backupCount: 20 encoding: utf8 warn_error_file_handler: class: logging.handlers.RotatingFileHandler level: WARNING formatter: with_time filename: errors.log maxBytes: 10485760 # 10MB backupCount: 20 encoding: utf8 root: level: DEBUG handlers: [console, debug_file_handler, info_file_handler, warn_error_file_handler] ubuntu-make-16.02.1/COPYING0000664000000000000000000010451312656574623012065 0ustar GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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. This program 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 this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ubuntu-make-16.02.1/setup.py0000775000000000000000000001242412656574623012546 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA from distutils import cmd from distutils.command.install_data import install_data as _install_data from distutils.command.build import build as _build import gettext from glob import glob import os from setuptools import setup, find_packages import subprocess import umake # that initializes the gettext domain from umake.settings import get_version I18N_DOMAIN = gettext.textdomain() PO_DIR = os.path.join(os.path.dirname(os.curdir), 'po') def get_requirements(tag_to_detect=""): """Gather a list of requirements line per line from tag_to_detect to next tag. if tag_to_detect is empty, it will gather every requirement""" requirements = [] tag_detected = False with open("requirements.txt") as f: for line in f.read().splitlines(): if line.startswith("#") or line == "": tag_detected = False if line.startswith(tag_to_detect): tag_detected = True continue if tag_detected: requirements.append(line) print(requirements) return requirements # # add translation support # class build(_build): sub_commands = _build.sub_commands + [('build_trans', None)] def run(self): _build.run(self) class build_trans(cmd.Command): description = 'Compile .po files into .mo files' user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): for filename in os.listdir(PO_DIR): if not filename.endswith('.po'): continue lang = filename[:-3] src = os.path.join(PO_DIR, filename) dest_path = os.path.join('build', 'locale', lang, 'LC_MESSAGES') dest = os.path.join(dest_path, I18N_DOMAIN + '.mo') if not os.path.exists(dest_path): os.makedirs(dest_path) if not os.path.exists(dest): print('Compiling {}'.format(src)) subprocess.call(["msgfmt", src, "--output-file", dest]) else: src_mtime = os.stat(src)[8] dest_mtime = os.stat(dest)[8] if src_mtime > dest_mtime: print('Compiling {}'.format(src)) subprocess.call(["msgfmt", src, "--output-file", dest]) class install_data(_install_data): def run(self): for filename in os.listdir(PO_DIR): if not filename.endswith('.po'): continue lang = filename[:-3] lang_dir = os.path.join('share', 'locale', lang, 'LC_MESSAGES') lang_file = os.path.join('build', 'locale', lang, 'LC_MESSAGES', I18N_DOMAIN + '.mo') self.data_files.append((lang_dir, [lang_file])) _install_data.run(self) class update_pot(cmd.Command): description = 'Update template for translators' user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): cmd = ['xgettext', '--language=Python', '--keyword=_', '--package-name', I18N_DOMAIN, '--output', 'po/{}.pot'.format(I18N_DOMAIN)] for path, names, filenames in os.walk(os.path.join(os.curdir, 'umake')): for f in filenames: if f.endswith('.py'): cmd.append(os.path.join(path, f)) subprocess.call(cmd) class update_po(cmd.Command): description = 'Update po from pot file' user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): source_pot = os.path.join(os.curdir, 'po', '{}.pot'.format(I18N_DOMAIN)) for po_file in glob(os.path.join(os.curdir, 'po', '*.po')): subprocess.check_call(["msgmerge", "-U", po_file, source_pot]) setup( name="Ubuntu Make", version=get_version(), packages=find_packages(exclude=["tests*"]), package_data={}, entry_points={ 'console_scripts': [ 'umake = umake:main', 'udtc = umake:main' ], }, data_files=[ ('lib/python3/dist-packages/umake', ['umake/version']), ("share/ubuntu-make/log-confs", glob('log-confs/*.yaml')), ('share/zsh/vendor-completions', ['confs/completions/_umake']), ], # In addition to run all nose tests, that will as well show python warnings test_suite="nose.collector", cmdclass={ 'build': build, 'build_trans': build_trans, 'install_data': install_data, 'update_pot': update_pot, 'update_po': update_po, } ) ubuntu-make-16.02.1/docker/0000775000000000000000000000000012656574623012275 5ustar ubuntu-make-16.02.1/docker/umake_docker.pub0000664000000000000000000000061412656574623015437 0ustar ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9iWeT1+JcYVzLUwqXJ4SnbpMmD2HhHBHAduFTLTFMHc5MZnwkHGzKiE3N9Usz7NRecnYzbmp5blx6bl0EabFmH8UrVwwiRJRhVyj67Xuyj07B0azOeIGpY561o8fsJX5D61IwFFqKao+J+ct3Nj2KJHHOKR9oJIkoPuEmdT81sBaKn9li137cUGbvPrppoNcWIIzEZ1q67SeeTsJrtOYharyGil2jwhjrXLUWm39ULZVHZSl0p06PcmgYLOTzxmOzPeVXmqxQhS7BimH8BOOACJuPeEGp0FYn41QOLiFIrcFtBOUbeYdU4x1arX0pWjaPj7LXC3tRQqdBcqJk38kX didrocks@tidus ubuntu-make-16.02.1/docker/create_packages.sh0000775000000000000000000001007712656574623015742 0ustar #!/bin/bash repo_root_dir=$1 generate_package (){ temp_dir="/tmp/package" package_name=$1 version=$2 arch=$3 multiarch=true if [ -z "$arch" ]; then arch=$(dpkg --print-architecture) multiarch=false fi mkdir -p $temp_dir/DEBIAN control_file=$temp_dir/DEBIAN/control echo "Package: $package_name Source: testpackage Version: $version Architecture: $arch Maintainer: Didier Roche Installed-Size: 26 Section: misc Priority: extra" > $control_file [[ $multiarch == true ]] && echo "Multi-Arch: same" >> $control_file echo "Description: Dummy package for testing Package used for testing debs installation" >> $control_file dpkg-deb -b $temp_dir ${package_name}_${version,}_${arch}.deb rm -rf $temp_dir } extract_version() { version=$(apt-cache policy $1 | grep Candidate | awk '{print $2}') [ -z "$version" ] && version=1.0 echo $version } create_package() { package_name=$1 arch=$2 version=$(extract_version $package_name) generate_package $package_name $version $arch } # android studio and adt deps mkdir -p $repo_root_dir/android cd $repo_root_dir/android create_package openjdk-7-jdk create_package jayatana create_package libncurses5 i386 create_package libstdc++6 i386 create_package zlib1g i386 dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz # eclipse deps mkdir -p $repo_root_dir/eclipse cd $repo_root_dir/eclipse create_package openjdk-7-jdk dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz # stencyl deps mkdir -p $repo_root_dir/stencyl cd $repo_root_dir/stencyl create_package libxtst6 i386 create_package libxext6 i386 create_package libxi6 i386 create_package libncurses5 i386 create_package libxt6 i386 create_package libxpm4 i386 create_package libxmu6 i386 create_package libxp6 i386 create_package libgtk2.0-0 i386 create_package libatk1.0-0 i386 create_package libc6 i386 create_package libcairo2 i386 create_package libexpat1 i386 create_package libfontconfig1 i386 create_package libfreetype6 i386 create_package libglib2.0-0 i386 create_package libice6 i386 create_package libpango1.0-0 i386 create_package libpng12-0 i386 create_package libsm6 i386 create_package libxau6 i386 create_package libxcursor1 i386 create_package libxdmcp6 i386 create_package libxfixes3 i386 create_package libx11-6 i386 create_package libxinerama1 i386 create_package libxrandr2 i386 create_package libxrender1 i386 create_package zlib1g i386 create_package libnss3-1d i386 create_package libnspr4-0d i386 create_package libcurl3 i386 create_package libasound2 i386 dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz # visual studio code deps mkdir -p $repo_root_dir/vscode cd $repo_root_dir/vscode create_package libgtk2.0-0 dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz # arduino deps mkdir -p $repo_root_dir/arduino cd $repo_root_dir/arduino create_package openjdk-7-jdk create_package jayatana create_package gcc-avr create_package avr-libc dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz # scala deps mkdir -p $repo_root_dir/scala cd $repo_root_dir/scala create_package default-jre dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz # swift deps mkdir -p $repo_root_dir/swift cd $repo_root_dir/swift create_package clang create_package libicu-dev dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz # unity3d deps mkdir -p $repo_root_dir/unity3d cd $repo_root_dir/unity3d create_package gconf-service create_package lib32gcc1 create_package lib32stdc++6 create_package libasound2 create_package libcairo2 create_package libcap2 create_package libcups2 create_package libfontconfig1 create_package libfreetype6 create_package libgconf-2-4 create_package libgdk-pixbuf2.0-0 create_package libgl1-mesa-glx create_package libglu1-mesa create_package libgtk2.0-0 create_package libnspr4 create_package libnss3 create_package libpango1.0-0 create_package libpq5 create_package libxcomposite1 create_package libxcursor1 create_package libxdamage1 create_package libxext6 create_package libxfixes3 create_package libxi6 create_package libxrandr2 create_package libxrender1 create_package libxtst6 create_package monodevelop dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz ubuntu-make-16.02.1/docker/umake_docker0000664000000000000000000000321312656574623014650 0ustar -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAvYlnk9fiXGFcy1MKlyeEp26TJg9h4RwRwHbhUy0xTB3OTGZ8 JBxsyohNzfVLM+zUXnJ2M25qeW5cem5dBGmxZh/FK1cMIkSUYVco+u17so9OwdGs zniBqWOetaPH7CV+Q+tSMBRaimqPifnLdzY9iiRxzikfaCSJKD7hJnU/NbAWip/Z Ytd+3FBm7z66aaDXFiCMxGdauu0nnk7Ca7TmIWq8hopdo8IY61y1Fpt/VC2VR2Up dKdOj3JoGCzk88Zjsz3lV5qsUIUuwYph/ATjgAibj3hBqdBWJ+NUDi4hSK3BbQTl G3mHVOMdWq19KVo2j4+y1wt7UUKnQXKiZN/JFwIDAQABAoIBABmN4Q0p2jciWWSA ebkPdu8sFWLYSBYVtr8ASDjyqubcTeg3GR21R2W3IuZV4CHMGIXzYMRmaqycmJNZ NelWZriiJ+9D+TrVjDvjiH7sbfURJUk0f9wGm1S/PbK3tki8dV2q6JXa6Koo29l6 eFhGU93ANCfbm4RrCKMId0q8HB2cuH2zJBiTv/GAjmXBOhIlNDEbydkt9kMGqmVV THh1pu9jGH+AnDfd0CBrW1IfRvjl49zkaEYq+FcWy/ksPFFMPKmiunPZWk+4jJUc aJ5goYtTmNGu4W/yEfFDGLPrGAkLNAhSs2s2ssnwSQynDs+9SGQFav5S7fI71oJG y67YL0ECgYEA8w7EeGCtn5UyqZmvAF0KD901INStHEfpzU5pD+y5xBh23kPDZw1a +Zn0AKwkcc4oI0w0EcjaUshJSQc82cncdSGQGTzlnE6t6Z/CEJd9HjZG5DmlHx17 AV5Z0PRXMqgalSQEfu1Pm22KFKqa6gXA970gn7CODp0kgO9S7K4UEu8CgYEAx6ER coQUiI5frwNKbgs4JQafxqZf+2+9xyHl4HQGn6EOhrBgaLmTC2+rz/RqCp8HRwV/ hBGwhJV4Eb1gEMxCTIBQJ+4YbuO+HPxv9cJdW3twtIROHoarRDwBhEnS4JnCbLvE 1uKoh99g0+5NWKZRvN8+xwS12uF+qgakWLkeDFkCgYB9ewA/TVoVawcuu+K3A1Fw gzksa9+7G/0+Ot7Ok94LuL2VXdKBX0m6Vpq7xiNChbX/ExZGoDTmS/RZuVzW6vnf lqY4AVJg8dWjKREdU7gKYucSaBgxCh04xacE00A5LMQcfu27QXS5v0FsDe/QJYxL 2d3/0zxjmwj/b46WFgDTDQKBgQCsD/kA0jT8inKQX268sLDgwPff+bELAAH77Ay9 zGOVHPVvRACk4yaJmePl5s2rf+x+249QHwsdC9OkvqxZbiTK2WG9OOwYT/Wh+Dbs BW4AFsJK5SqMBxkBRBMumY7IBd9dZu4/JLeL/Q3xPRmvihMzjtwGH9o64VcSZ40p 58ytaQKBgBd+1TYt0U2nk2P6nqQDtGi2IfaY0dllbhYzjrwIXyfcslFriXjdHRBh 1d0X7CoRLFIlGBbQL59JyHxBK06Fdeght37xXlfzv2QjMdexqL92jbEu2OpwKcZ3 1uso5EgxFZAamQ9DP+v4k8KL1hFUsYLi/xFlBIvzzmzIq40mvpnW -----END RSA PRIVATE KEY----- ubuntu-make-16.02.1/Dockerfile0000664000000000000000000000561612656574623013030 0ustar # Docker container for Ubuntu Make # this installs a full ubuntu desktop environment in an # unprivileged container, and adds a passwordless sudo user. # This enables running medium tests of umake. FROM ubuntu:14.04 MAINTAINER Didier Roche # Set the env variable DEBIAN_FRONTEND to noninteractive ENV DEBIAN_FRONTEND noninteractive ADD debian/control /tmp/ ADD docker/umake_docker.pub /tmp/ ADD tests/data/developer.android.com.crt /usr/local/share/ca-certificates/ ADD tests/data/www.eclipse.org.crt /usr/local/share/ca-certificates/ ADD tests/data/data.services.jetbrains.com.crt /usr/local/share/ca-certificates/ ADD tests/data/golang.org.crt /usr/local/share/ca-certificates/ ADD tests/data/www.mozilla.org.crt /usr/local/share/ca-certificates/ ADD tests/data/code.visualstudio.com.crt /usr/local/share/ca-certificates/ ADD tests/data/api.dartlang.org.crt /usr/local/share/ca-certificates/ ADD tests/data/storage.googleapis.com.crt /usr/local/share/ca-certificates/ ADD tests/data/netbeans.org.crt /usr/local/share/ca-certificates/ ADD tests/data/www.rust-lang.org.crt /usr/local/share/ca-certificates/ ADD tests/data/swift.org.crt /usr/local/share/ca-certificates/ ADD tests/data/nodejs.org.crt /usr/local/share/ca-certificates/ ADD tests/data/github.com.crt /usr/local/share/ca-certificates/ ADD tests/data/spring.io.crt /usr/local/share/ca-certificates/ ADD docker/create_packages.sh /tmp/ # Refresh the image RUN \ apt-get update && \ apt-get dist-upgrade -y && \ # install add-apt-repository and tools to create build-deps apt-get install -y software-properties-common devscripts equivs dpkg-dev && \ # add umake ppa add-apt-repository -y ppa:ubuntu-desktop/ubuntu-make && \ apt-get update && \ # install umake build-deps mk-build-deps /tmp/control -i --tool 'apt-get --yes' && \ # for running it as a daemon (and ssh requires the sshd directory) apt-get install openssh-server -y && \ mkdir /var/run/sshd && \ # disable DNS to not wait on host name resolution (delay when working offline) echo "UseDNS no" >> /etc/ssh/sshd_config && \ echo 'EXTRA_GROUPS="adm cdrom sudo dip plugdev fuse"' >> /etc/adduser.conf && \ echo 'ADD_EXTRA_GROUPS=1' >> /etc/adduser.conf && \ echo "user ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/bar && \ adduser --disabled-password --gecos "" user && \ echo user:user | chpasswd && \ # add the ubuntu make ssh key to the list of authorized ones mkdir -p /home/user/.ssh && \ cat /tmp/umake_docker.pub >> /home/user/.ssh/authorized_keys && \ chown -R user:user /home/user/ && \ # Twisted for a mock FTP server. apt-get install python-twisted-core -y && \ # add certificates update-ca-certificates && \ # finally remove all ppas and add local repository rm /etc/apt/sources.list.d/* && \ /tmp/create_packages.sh /apt-fake-repo && \ # clean up stuff apt-get clean -y && \ apt-get remove --purge -y software-properties-common devscripts equivs ubuntu-make-16.02.1/README.md0000664000000000000000000001614712656574623012316 0ustar # Ubuntu Make Ubuntu Make is a project designed to enable quick and easy setup of common needs for developers on Ubuntu. ## Current project health [![Build Status](https://api.travis-ci.org/ubuntu/ubuntu-make.svg?branch=master)](https://travis-ci.org/ubuntu/ubuntu-make) (pep8 and small tests) [All test results](https://jenkins.qa.ubuntu.com/job/udtc-trusty-tests/) and [Coverage report](https://jenkins.qa.ubuntu.com/job/udtc-trusty-tests-collect/label=ps-trusty-desktop-amd64-1/lastSuccessfulBuild/artifact/html-coverage/index.html) ## Installing We recommend to use the Ubuntu Make ppa to ensure you always have the latest and greatest version, even on older supported released. We are available on the currenctly supported Ubuntu version. ```sh $ sudo add-apt-repository ppa:ubuntu-desktop/ubuntu-make $ sudo apt update $ sudo apt install ubuntu-make ``` ## Running the command line tool To run the tool: ```sh $ ./umake ``` You can use `--help` to get more information and change the verbosity of the output with `-v`, `-vv`. ## Requirements > Note that this project uses python3 and requires at least python 3.3. All commands use the python 3 version. There are directions later on explaining how to install the corresponding virtualenv. ## Shell completion To enable shell completion on bash or zsh, just run: ```sh $ . enable_completion ``` ## Different level of logging Multiple logging profiles are available in *confs/* to be able to have different traces of your execution (particularly useful for debugging). For instance, you will find: * **debug.logcfg**: Similar to using -vv, but also puts logs in a *debug.log*. * **debug_network.logcfg**: The root logging level is INFO (-v), the network activities are in DEBUG mode and will be logged in *debug_network.log*. * **testing.logcfg**: Mostly for coverage tests, do not set any logging config on stdout, but: * DEBUG logs and above are available in *debug.log*. * INFO logs and above are available in *info.log*. * WARNING and ERROR logs are available in *error.log*. Under normal circumstances, we expect *error.log* to remain empty../ To load one of those logging profiles: ```sh $ LOG_CFG=confs/debug.logcfg bin/umake ``` ## Development ### Providing user's framework It's possible for anyone to have local frameworks for either development purposes or for special local or team use-cases. * Any files in a directory set with the "UMAKE_FRAMEWORKS" environment variable will be loaded first. * Any files inside ~/.umake/frameworks will be loaded next. Any file should eventually contain a category or frameworks like the ones in umake/frameworks/*. If category names are duplicated only one will be loaded. Ubuntu Make will first load the one controlled by the environment variable, then the one located in the home based directory, and finally, the system one. Note that duplicate filenames are supported but not encouraged. ### Style guide and checking We are running pep8, but the max line length has been relaxed to 120. env/ is excluded from the pep8 check as well. Running this test, in particular: ```sh $ ./runtests pep8 ``` This will run those pep8 checks on the code. You can also run the pep8 tool directly from the project directory: ```sh $ pep8 . ``` ### Tests #### Types of tests There are four types of tests that can be combined in runtests: * **pep8**: Run the pep8 tests on all the umake and test code. * **small**: Tests modules and components with mock content around them. Note that this uses a local webserver (http and https) to serve mock content. * **medium**: Tests the whole workflow. It directly calls end user tools from the command line, but without effecting the local system. Requirements like installing packages are mocked, as well as the usage of a local webserver serving (smaller) content similar to what will be fetched in a real use case. The assets have the same formats and layout. * **large**: Runs the same tests as the medium test, but with real server downloads and installation of dpkg packages. Most of these tests need root privileges. Be aware that these tests only run on a graphical environment. It will interfere with it and it is likely to install or remove packages on your system. To run all the tests, with coverage report, like in our jenkins infra: ```sh $ ./runtests ``` Use `--no-config` to disable the coverage report selection. #### Running some tests with all debug infos By default, **runtests** will not display any debug output if the tests are successful, similar to Nose. However, if only some tests are selected, runtests will a display full debug log, ```sh $ ./runtests tests/small/test_tools.py:TestConfigHandler ``` Use `--no-config` to disable the debug output selection. #### More information on runtests **runtests** is a small nose wrapper used to simplify the testing process. By default, if no arguments are supplied or if "all" is supplied, runtests will run all available tests on the project using the production nose configuration. It is possible to run only some types of tests: ```sh $ ./runtests small medium ``` This will only run small and medium tests, with all nose defaults (no profile is selected). Finally, you can run a selection of one or more tests: ```sh $ ./runtests tests/small/test_tools.py:TestConfigHandler ``` This enables the debug profile by default, to display all outputs and logging information (in debug level). You can activate/disable/change any of those default selected configurations with **--config/--coverage/--debug/--no-config** (see `runtests --help` for more information) #### Nose configurations Some nose configurations are available in **confs/**. You will find: * **debug.nose**: this profile shows all outputs and logging information while turning debug logging on. * **prod.nose**: this profile keep all outputs captured, but display tests coverage results. #### Check for python warnings: **runtests** is compatible with showing the python warnings: ```sh $ PYTHONWARNINGS=d ./runtests ``` ### Create your own environment and run from it For an easier development workflow, we encourage the use of virtualenv to test and iterate on the project rather than installing all the requirements on your machine. In the project root directory run (env/ is already in .gitignore and excluded from pep8 checking): ```sh $ virtualenv --python=python3 --system-site-packages env $ sudo apt-get install -qq apt apt-utils libapt-pkg-dev # those are the requirements to compile python-apt $ sudo apt-get install -qq python3-gi # not installable with pypi $ sudo apt-get install -qq bzr python3-dev # requires for pip install -r $ env/bin/pip install -r requirements.txt $ source env/bin/activate $ bin/umake ``` ### Developing using system package Instead of using a virtual environment, you can install system packages to be able to run the Ubuntu Make tests. The build dependencies are listed in *debian/control* and should be available in latest development ubuntu version. If you are using the latest LTS, you should find them in a dedicated [Ubuntu Make Build-dep ppa](https://launchpad.net/~ubuntu-desktop/+archive/ubuntu/ubuntu-make-builddeps). ## Release management Refresh .pot files: ```sh $ ./setup.py update_pot ``` ubuntu-make-16.02.1/tests/0000775000000000000000000000000012656574623012170 5ustar ubuntu-make-16.02.1/tests/medium/0000775000000000000000000000000012656574623013450 5ustar ubuntu-make-16.02.1/tests/medium/test_ide.py0000664000000000000000000004676712656574623015646 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # Tin Tvrtković # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for ides""" from . import ContainerTests import os import pexpect from ..large import test_ide from ..tools import get_data_dir, swap_file_and_restore, UMAKE, spawn_process class EclipseJavaIDEInContainer(ContainerTests, test_ide.EclipseJavaIDETests): """This will test the eclipse IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["www.eclipse.org"]} # we reuse the android-studio repo self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'eclipse') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "eclipse") self.bad_download_page_file_path = os.path.join(get_data_dir(), "server-content", "www.eclipse.org", "technology", "epp", "downloads", "release", "version", "point_release", "eclipse-java-linux-gtk-x86_64.tar.gz.sha512") def test_install_with_changed_download_page(self): """Installing eclipse ide should fail if download page has significantly changed""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "www.eclipse.org", "downloads", "index.html") self.bad_download_page_test(self.command(self.command_args), download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) def test_install_with_changed_checksum_page(self): """Installing eclipse ide should fail if checksum link is unparseable""" self.bad_download_page_test(self.command(self.command_args), self.bad_download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) class EclipsePHPIDEInContainer(ContainerTests, test_ide.EclipsePHPIDETests): """This will test the eclipse IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["www.eclipse.org"]} # we reuse the android-studio repo self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'eclipse') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "eclipse-php") self.bad_download_page_file_path = os.path.join(get_data_dir(), "server-content", "www.eclipse.org", "technology", "epp", "downloads", "release", "version", "point_release", "eclipse-php-linux-gtk-x86_64.tar.gz.sha512") class EclipseCPPIDEInContainer(ContainerTests, test_ide.EclipseCPPIDETests): """This will test the eclipse IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["www.eclipse.org"]} # we reuse the android-studio repo self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'eclipse') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "eclipse-cpp") self.bad_download_page_file_path = os.path.join(get_data_dir(), "server-content", "www.eclipse.org", "technology", "epp", "downloads", "release", "version", "point_release", "eclipse-cpp-linux-gtk-x86_64.tar.gz.sha512") class IdeaIDEInContainer(ContainerTests, test_ide.IdeaIDETests): """This will test the Idea IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["data.services.jetbrains.com"]} # Reuse the Android Studio environment. self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "idea") # This actually tests the code in BaseJetBrains def test_install_with_changed_download_page(self): """Installing IntelliJ Idea should fail if download page has changed""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "data.services.jetbrains.com", "products", "releases?code=IIC") umake_command = self.command('{} ide idea'.format(UMAKE)) self.bad_download_page_test(umake_command, download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) class IdeaUltimateIDEInContainer(ContainerTests, test_ide.IdeaUltimateIDETests): """This will test the Idea Ultimate IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["data.services.jetbrains.com"]} # Reuse the Android Studio environment. self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "idea-ultimate") class PyCharmIDEInContainer(ContainerTests, test_ide.PyCharmIDETests): """This will test the PyCharm IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["data.services.jetbrains.com"]} # Reuse the Android Studio environment. self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "pycharm") class PyCharmEducationalIDEInContainer(ContainerTests, test_ide.PyCharmEducationalIDETests): """This will test the PyCharm Educational IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["data.services.jetbrains.com"]} # Reuse the Android Studio environment. self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "pycharm-educational") class PyCharmProfessionalIDEInContainer(ContainerTests, test_ide.PyCharmProfessionalIDETests): """This will test the PyCharm Professional IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["data.services.jetbrains.com"]} # Reuse the Android Studio environment. self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "pycharm-professional") class RubyMineIDEInContainer(ContainerTests, test_ide.RubyMineIDETests): """This will test the RubyMine IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["data.services.jetbrains.com"]} # Reuse the Android Studio environment. self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "rubymine") class WebStormIDEInContainer(ContainerTests, test_ide.WebStormIDETests): """This will test the WebStorm IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["data.services.jetbrains.com"]} # Reuse the Android Studio environment. self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "webstorm") class CLionIDEInContainer(ContainerTests, test_ide.CLionIDETests): """This will test the CLion IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["data.services.jetbrains.com"]} # Reuse the Android Studio environment. self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "clion") class DataGripIDEInContainer(ContainerTests, test_ide.DataGripIDETests): """This will test the DataGrip IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["data.services.jetbrains.com"]} # Reuse the Android Studio environment. self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "datagrip") class PhpStormIDEInContainer(ContainerTests, test_ide.PhpStormIDETests): """This will test the PhpStorm IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["data.services.jetbrains.com"]} # Reuse the Android Studio environment. self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "phpstorm") class ArduinoIDEInContainer(ContainerTests, test_ide.ArduinoIDETests): """This will test the Arduino IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {80: ["www.arduino.cc"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'arduino') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "arduino") def test_install_with_changed_download_page(self): """Installing arduino ide should fail if download page has significantly changed""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "www.arduino.cc", "en", "Main", "Software") umake_command = self.command('{} ide arduino'.format(UMAKE)) self.bad_download_page_test(umake_command, download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) def test_install_with_changed_checksum_page(self): """Installing arduino ide should fail if checksum link is unparseable""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "www.arduino.cc", "checksums.md5sum.txt") umake_command = self.command('{} ide arduino'.format(UMAKE)) self.bad_download_page_test(umake_command, download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) class BaseNetBeansInContainer(ContainerTests, test_ide.BaseNetBeansTests): """This will test the NetBeans IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 TEST_CHECKSUM_NETBEANS_DATA = "1e07ec8775939ba6d35731831bdb7bf0" def setUp(self): self.hosts = {80: ["download.netbeans.org"], 443: ["netbeans.org"]} # Reuse the Android Studio environment. self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "netbeans") def test_install_with_changed_download_page(self): """Installing NetBeans ide should fail if download page has significantly changed""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "netbeans.org", "downloads", "zip.html") umake_command = self.command('{} ide netbeans'.format(UMAKE)) self.bad_download_page_test(umake_command, download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) def test_install_with_changed_download_reference_page(self): """Installing NetBeans ide should fail if download reference page has significantly changed""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "netbeans.org", "images_www", "v6", "download", "8.0.42", "js", "files.js") umake_command = self.command('{} ide netbeans'.format(UMAKE)) self.bad_download_page_test(umake_command, download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) def test_install_with_changed_checksum_page(self): """Installing NetBeans ide should fail if checksum link is wrong""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "netbeans.org", "images_www", "v6", "download", "8.0.42", "js", "files.js") with swap_file_and_restore(download_page_file_path) as content: with open(download_page_file_path, "w") as newfile: newfile.write(content.replace(self.TEST_CHECKSUM_NETBEANS_DATA, "abcdef")) self.child = spawn_process(self.command('{} ide netbeans'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn([pexpect.EOF, "Corrupted download? Aborting."], timeout=self.TIMEOUT_INSTALL_PROGRESS, expect_warn=True) self.wait_and_close(exit_status=1) # we have nothing installed self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) class VisualStudioCodeInContainer(ContainerTests, test_ide.VisualStudioCodeTest): """This will test the Visual Studio Code integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["code.visualstudio.com"], 80: ["go.microsoft.com"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'vscode') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "visual-studio-code") class LightTableInContainer(ContainerTests, test_ide.LightTableTest): """This will test the LightTable integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["github.com"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'LightTable') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "lighttable") def test_install_with_changed_download_page(self): """Installing LightTable should fail if download page has significantly changed""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "github.com", "LightTable", "LightTable", "releases", "index.html") umake_command = self.command('{} ide lighttable'.format(UMAKE)) self.bad_download_page_test(umake_command, download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) class SpringToolsSuiteInContainer(ContainerTests, test_ide.SpringToolsSuiteTest): """This will test Spring Tools Suite IDE integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ['spring.io'], 80: ['dist.springsource.com']} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'eclipse') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "ide", "spring-tools-suite") def test_install_with_changed_download_page(self): """Installing STS should fail if download page has significantly changed""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "spring.io", "tools", "sts", "all") umake_command = self.command('{} ide spring-tools-suite'.format(UMAKE)) self.bad_download_page_test(self.command(self.command_args), download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) def test_install_with_changed_checksum_page(self): """Installing STS should fail if checksum link is unparseable""" download_page_file_path = os.path.join(get_data_dir(), 'server-content', 'dist.springsource.com', 'release', 'STS', '3.7.2.RELEASE', 'dist', 'e4.5', 'spring-tool-suite-3.7.2.RELEASE-e4.5.1-linux-gtk-x86_64.tar.gz.sha1') self.bad_download_page_test(self.command(self.command_args), download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) ubuntu-make-16.02.1/tests/medium/test_web.py0000664000000000000000000000472412656574623015645 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for web category""" from . import ContainerTests import os from ..large import test_web from ..tools import get_data_dir, UMAKE class FirefoxDevContainer(ContainerTests, test_web.FirefoxDevTests): """This will test the Firefox dev integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["www.mozilla.org"]} super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "web", "firefox-dev") def test_install_with_changed_download_page(self): """Installing firefox developer should fail if download page has significantly changed""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "www.mozilla.org", "en-US", "firefox", "developer", "all") umake_command = self.command('{} web firefox-dev'.format(UMAKE)) self.bad_download_page_test(umake_command, download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) class VisualStudioCodeInContainer(ContainerTests, test_web.VisualStudioCodeTest): """This will test the Visual Studio Code integration inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["code.visualstudio.com"], 80: ["go.microsoft.com"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'vscode') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "web", "visual-studio-code") ubuntu-make-16.02.1/tests/medium/test_games.py0000664000000000000000000000417712656574623016166 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for games framework""" from . import ContainerTests import os from ..large import test_games class StencylInContainer(ContainerTests, test_games.StencylTests): """This will test the Stencyl editor inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {80: ["www.stencyl.com"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'stencyl') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "games", "stencyl") class Unity3DInContainer(ContainerTests, test_games.Unity3DTests): """This will test the Unity 3D editor inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {80: ["forum.unity3d.com"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'unity3d') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "games", "unity3d") class TwineInContainer(ContainerTests, test_games.TwineTests): """This will test Twine inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {80: ["twinery.org"]} super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "games", "twine") ubuntu-make-16.02.1/tests/medium/test_basics_cli.py0000664000000000000000000000223312656574623017154 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for basic CLI commands""" import os from ..large import test_basics_cli from . import ContainerTests class BasicCLIInContainer(ContainerTests, test_basics_cli.BasicCLI): """This will test the basic cli command class inside a container""" def setUp(self): # Reuse the Android Studio environment.(used in --help) self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() ubuntu-make-16.02.1/tests/medium/test_android.py0000664000000000000000000000433312656574623016504 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for android frameworks in container""" from . import ContainerTests import os from ..large import test_android class AndroidStudioInContainer(ContainerTests, test_android.AndroidStudioTests): """This will install Android Studio inside a container""" TIMEOUT_START = 20 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {443: ["developer.android.com"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "android", "android-studio") class AndroidSDKContainer(ContainerTests, test_android.AndroidSDKTests): """This will install Android SDK inside a container""" def setUp(self): self.hosts = {443: ["developer.android.com"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "android", "android-sdk") class AndroidNDKContainer(ContainerTests, test_android.AndroidNDKTests): """This will install Android NDK inside a container""" def setUp(self): self.hosts = {443: ["developer.android.com"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "android", "android-ndk") ubuntu-make-16.02.1/tests/medium/test_dart.py0000664000000000000000000000327512656574623016022 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for dart""" from . import ContainerTests import os from ..large import test_dart from ..tools import get_data_dir, UMAKE class DartInContainer(ContainerTests, test_dart.DartEditorTests): """This will test the eclipse IDE integration inside a container""" def setUp(self): self.hosts = {443: ["api.dartlang.org", "storage.googleapis.com"]} super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "dart", "dart-sdk") def test_install_with_changed_version_page(self): """Installing dart sdk should fail if version page has significantly changed""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "api.dartlang.org", "index.html") umake_command = self.command('{} dart'.format(UMAKE)) self.bad_download_page_test(umake_command, download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) ubuntu-make-16.02.1/tests/medium/test_scala.py0000664000000000000000000000237112656574623016147 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # Igor Vuk # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for scala""" from . import ContainerTests import os from ..large import test_scala class ScalaInContainer(ContainerTests, test_scala.ScalaTests): """This will test the Scala integration inside a container""" def setUp(self): self.hosts = {80: ["www.scala-lang.org"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'scala') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "scala", "scala-lang") ubuntu-make-16.02.1/tests/medium/test_rust.py0000664000000000000000000000566112656574623016066 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014-2015 Canonical # # Authors: # Didier Roche # Jared Ravetch # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for rust""" from . import ContainerTests import os import pexpect from ..large import test_rust from ..tools import get_data_dir, UMAKE, swap_file_and_restore, spawn_process class RustInContainer(ContainerTests, test_rust.RustTests): """This will test the Rust integration inside a container""" TEST_CHECKSUM_RUST_DATA = "2a0db6efe370a900491d9e9db13e53ffd00b01dcd8458486f9f3fc3177f96af3" def setUp(self): self.hosts = {443: ["www.rust-lang.org"]} super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "rust", "rust-lang") def test_install_with_changed_download_reference_page(self): """Installing Rust should fail if download reference page has significantly changed""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "www.rust-lang.org", "downloads.html") umake_command = self.command('{} rust'.format(UMAKE)) self.bad_download_page_test(umake_command, download_page_file_path) self.assertFalse(self.path_exists(self.exec_path)) def test_install_with_wrong_sha(self): """Installing Rust should fail if checksum is wrong""" # we only modify the amd64 sha as docker only run on it download_page_file_path = os.path.join(get_data_dir(), "server-content", "www.rust-lang.org", "rust-fake-x86_64-unknown-linux-gnu.tar.gz.sha256") with swap_file_and_restore(download_page_file_path) as content: with open(download_page_file_path, "w") as newfile: newfile.write(content.replace(self.TEST_CHECKSUM_RUST_DATA, "abcdef")) self.child = spawn_process(self.command('{} rust'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn([pexpect.EOF, "Corrupted download? Aborting."], timeout=self.TIMEOUT_INSTALL_PROGRESS, expect_warn=True) self.wait_and_close(exit_status=1) # we have nothing installed self.assertFalse(self.path_exists(self.exec_path)) ubuntu-make-16.02.1/tests/medium/test_nodejs.py0000664000000000000000000000223112656574623016341 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for nodejs""" from . import ContainerTests import os from ..large import test_nodejs class NodejsInContainer(ContainerTests, test_nodejs.NodejsTests): """This will test the Nodejs integration inside a container""" def setUp(self): self.hosts = {443: ["nodejs.org"]} super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "nodejs", "nodejs-lang") ubuntu-make-16.02.1/tests/medium/test_baseinstaller.py0000664000000000000000000000271612656574623017717 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for base installer framework in container""" from . import ContainerTests import os from ..large import test_baseinstaller class BaseInstallerInContainer(ContainerTests, test_baseinstaller.BaseInstallerTests): """This will install the Base Framework inside a container""" TIMEOUT_START = 10 TIMEOUT_STOP = 10 def setUp(self): self.hosts = {8765: ["localhost"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'android') self.additional_local_frameworks = [os.path.join("tests", "data", "testframeworks", "baseinstallerfake.py")] super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "base", "base-framework") ubuntu-make-16.02.1/tests/medium/__init__.py0000664000000000000000000002631212656574623015565 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for basic CLI commands""" import os import pwd import subprocess from ..tools import get_root_dir, get_tools_helper_dir, LoggedTestCase, get_docker_path, get_data_dir, INSTALL_DIR, \ BRANCH_TESTS, SYSTEM_UMAKE_DIR, BINARY_DIR from time import sleep class ContainerTests(LoggedTestCase): """Container-based tests utilities""" DOCKER_USER = "user" DOCKER_TESTIMAGE = "didrocks/docker-umake-manual" UMAKE_TOOLS_IN_CONTAINER = "/umake" APT_FAKE_REPO_PATH = "/apt-fake-repo" in_container = True def setUp(self): super().setUp() # this will call other parents of ContainerTests ancestors, like LargeFrameworkTests self.umake_path = get_root_dir() self.install_base_path = os.path.expanduser("/home/{}/{}".format(self.DOCKER_USER, INSTALL_DIR)) self.binary_dir = os.path.join(self.install_base_path, BINARY_DIR) self.image_name = self.DOCKER_TESTIMAGE if not hasattr(self, "hosts"): self.hosts = {} if not hasattr(self, "additional_local_frameworks"): self.additional_local_frameworks = [] command = [get_docker_path(), "run"] # bind master used for testing tools code inside the container runner_cmd = "mkdir -p {}; ln -s {}/ {};".format(os.path.dirname(get_root_dir()), self.UMAKE_TOOLS_IN_CONTAINER, get_root_dir()) local_framework_dir = "/home/{}/.umake/frameworks/".format(self.DOCKER_USER) runner_cmd += "mkdir -p {};".format(local_framework_dir) for additional_framework in self.additional_local_frameworks: runner_cmd += "cp {} {};".format( os.path.join(self.UMAKE_TOOLS_IN_CONTAINER, additional_framework), local_framework_dir) if not BRANCH_TESTS: # create a system binary which will use system umake version (without having the package installed) bin_umake = "/usr/bin/umake" runner_cmd += "echo '#!/usr/bin/env python3\nfrom umake import main\nif __name__ == \"__main__\":" \ "\n main()'>{bin_umake}; chmod +x {bin_umake};".format(bin_umake=bin_umake) # start the local server at container startup for port, hostnames in self.hosts.items(): ftp_redir = hasattr(self, 'ftp') for hostname in hostnames: if "-h" not in command: command.extend(["-h", hostname]) runner_cmd += ' echo "127.0.0.1 {}" >> /etc/hosts;'.format(hostname) runner_cmd += "{} {} 'sudo -E env PATH={} VIRTUAL_ENV={} {} {} {} {}';".format( os.path.join(get_tools_helper_dir(), "run_in_umake_dir_async"), self.UMAKE_TOOLS_IN_CONTAINER, os.getenv("PATH"), os.getenv("VIRTUAL_ENV"), os.path.join(get_tools_helper_dir(), "run_local_server"), str(port), str(ftp_redir), " ".join(hostnames) if port == 443 else "") if ftp_redir: runner_cmd += "/usr/bin/twistd ftp -p 21 -r {};".format(os.path.join(get_data_dir(), 'server-content', hostnames[0])) if hasattr(self, "apt_repo_override_path"): runner_cmd += "sh -c 'echo deb file:{} / > /etc/apt/sources.list'; apt-get update;".format( self.apt_repo_override_path) runner_cmd += "/usr/sbin/sshd -D" # we bindmount system umake directory if not BRANCH_TESTS: command.extend(["-v", "{system_umake}:{system_umake}".format(system_umake=SYSTEM_UMAKE_DIR)]) command.extend(["-d", "-v", "{}:{}".format(self.umake_path, self.UMAKE_TOOLS_IN_CONTAINER), "--dns=8.8.8.8", "--dns=8.8.4.4", # suppress local DNS warning self.image_name, 'sh', '-c', runner_cmd]) self.container_id = subprocess.check_output(command).decode("utf-8").strip() self.container_ip = subprocess.check_output([get_docker_path(), "inspect", "-f", "{{ .NetworkSettings.IPAddress }}", self.container_id]).decode("utf-8").strip() # override with container paths self.conf_path = os.path.expanduser("/home/{}/.config/umake".format(self.DOCKER_USER)) sleep(5) # let the container and service starts def tearDown(self): subprocess.check_call([get_docker_path(), "stop", "-t", "0", self.container_id], stdout=subprocess.DEVNULL) subprocess.check_call([get_docker_path(), "rm", self.container_id], stdout=subprocess.DEVNULL) super().tearDown() # this will call other parents of ContainerTests ancestors, like LargeFrameworkTests def command(self, commands_to_run): """Return a string for a command line ready to run in docker""" return " ".join(self.command_as_list(commands_to_run)) def command_as_list(self, commands_to_run): """Return a list for a command line ready to run in docker""" if isinstance(commands_to_run, list): commands_to_run = " ".join(commands_to_run) return ["ssh", "-i", os.path.join(get_root_dir(), "docker", "umake_docker"), "-o", "UserKnownHostsFile=/dev/null", "-o", "StrictHostKeyChecking=no", "-t", "-q", "{}@{}".format(self.DOCKER_USER, self.container_ip), "{} {} '{}'".format(os.path.join(get_tools_helper_dir(), "run_in_umake_dir"), self.UMAKE_TOOLS_IN_CONTAINER, commands_to_run)] def check_and_kill_process(self, process_grep, wait_before=0, send_sigkill=False): """Check a process matching process_grep exists and kill it""" sleep(wait_before) if not self._exec_command(self.command_as_list("{} {} {}".format(os.path.join(get_tools_helper_dir(), "check_and_kill_process"), send_sigkill, " ".join(process_grep))))[0]: raise BaseException("The process we try to find and kill can't be found".format(process_grep)) def _get_path_from_desktop_file(self, key, abspath_transform=None): """get the path referred as key in the desktop filename exists""" command = self.command_as_list([os.path.join(get_tools_helper_dir(), "get_path_from_desktop_file"), self.desktop_filename, key]) success, stdout, stderr = self._exec_command(command) if success: path = stdout if not path.startswith("/") and abspath_transform: path = abspath_transform(path) else: raise BaseException("Unknown failure from {}".format(command)) return path def _exec_command(self, command): """Exec the required command inside the container, returns if it exited with 0 or 1 + stdout/stderr""" proc = subprocess.Popen(command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) (stdout, stderr) = proc.communicate() # convert in strings and remove remaining \n if stdout: stdout = stdout.decode("utf-8").strip() if stderr: stderr = stderr.decode("utf-8").strip() return_code = proc.returncode if return_code == 0: return (True, stdout, stderr) elif return_code == 1: return (False, stdout, stderr) raise BaseException("Unknown return code from {}".format(command)) def get_launcher_path(self, desktop_filename): """Return launcher path inside container""" command = self.command_as_list([os.path.join(get_tools_helper_dir(), "get_launcher_path"), desktop_filename]) return self._exec_command(command)[1] def launcher_exists_and_is_pinned(self, desktop_filename): """Check if launcher exists and is pinned inside the container""" command = self.command_as_list([os.path.join(get_tools_helper_dir(), "check_launcher_exists_and_is_pinned"), desktop_filename]) return self._exec_command(command)[0] def path_exists(self, path): """Check if a path exists inside the container""" # replace current user home dir with container one. path = path.replace(os.environ['HOME'], "/home/{}".format(self.DOCKER_USER)) command = self.command_as_list([os.path.join(get_tools_helper_dir(), "path_exists"), path]) return self._exec_command(command)[0] def remove_path(self, path): """Remove targeted path""" path = path.replace(os.environ['HOME'], "/home/{}".format(self.DOCKER_USER)) command = self.command_as_list([os.path.join(get_tools_helper_dir(), "remove_path"), path]) self._exec_command(command) def is_in_path(self, filename): """Check inside the container if filename is in PATH thanks to which""" return self._exec_command(self.command_as_list(["bash", "-l", "which", filename]))[0] def is_in_group(self, group): """Check inside the container if the user is in a group""" command = self.command_as_list([os.path.join(get_tools_helper_dir(), "check_user_in_group"), group]) return self._exec_command(command)[0] def get_file_perms(self, path): """return unix file perms string for path from the container""" command = self.command_as_list([os.path.join(get_tools_helper_dir(), "get_file_perms"), path]) success, stdout, stderr = self._exec_command(command) if success: return stdout else: raise BaseException("Unknown failure from {}".format(command)) def create_file(self, path, content): """Create file inside the container.replace in path current user with the docker user""" try: src_user = os.getlogin() except FileNotFoundError: # fallback for container issues when trying to get login src_user = pwd.getpwuid(os.getuid())[0] path = path.replace(src_user, self.DOCKER_USER) dir_path = os.path.dirname(path) command = self.command_as_list(["mkdir", "-p", dir_path, path]) if not self._exec_command(command)[0]: raise BaseException("Couldn't create {} in container".format(path)) ubuntu-make-16.02.1/tests/medium/test_swift.py0000664000000000000000000000341312656574623016216 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for swift""" from . import ContainerTests import os from ..large import test_swift from ..tools import get_data_dir, UMAKE class SwiftInContainer(ContainerTests, test_swift.SwiftTests): """This will test the Swift integration inside a container""" def setUp(self): self.hosts = {443: ["swift.org"]} self.apt_repo_override_path = os.path.join(self.APT_FAKE_REPO_PATH, 'swift') super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "swift", "swift-lang") def test_install_with_changed_download_page(self): """Installing swift ide should fail if download page has significantly changed""" download_page_file_path = os.path.join(get_data_dir(), "server-content", "swift.org", "download", "index.html") umake_command = self.command('{} swift'.format(UMAKE)) self.bad_download_page_test(umake_command, download_page_file_path) self.assertFalse(self.is_in_path(self.exec_path)) ubuntu-make-16.02.1/tests/medium/test_go.py0000664000000000000000000000217112656574623015467 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for go""" from . import ContainerTests import os from ..large import test_go class GoInContainer(ContainerTests, test_go.GoTests): """This will test the Go integration inside a container""" def setUp(self): self.hosts = {443: ["golang.org"]} super().setUp() # override with container path self.installed_path = os.path.join(self.install_base_path, "go", "go-lang") ubuntu-make-16.02.1/tests/large/0000775000000000000000000000000012656574623013262 5ustar ubuntu-make-16.02.1/tests/large/test_ide.py0000664000000000000000000007433212656574623015445 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # Tin Tvrtković # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the IDE category""" import logging import platform import subprocess import os from tests.large import LargeFrameworkTests from tests.tools import UMAKE, spawn_process logger = logging.getLogger(__name__) class EclipseJavaIDETests(LargeFrameworkTests): """The Eclipse distribution from the IDE collection.""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "eclipse") self.desktop_filename = "eclipse-java.desktop" self.command_args = '{} ide eclipse'.format(UMAKE) self.name = "Eclipse" @property def arch_option(self): """we return the expected arch call on command line""" return platform.machine() def test_default_eclipse_ide_install(self): """Install eclipse from scratch test case""" self.child = spawn_process(self.command(self.command_args)) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # on 64 bits, there is a java subprocess, we kill that one with SIGKILL (eclipse isn't reliable on SIGTERM) if self.arch_option == "x86_64": self.check_and_kill_process(["java", self.arch_option, self.installed_path], wait_before=self.TIMEOUT_START, send_sigkill=True) else: self.check_and_kill_process([self.exec_path], wait_before=self.TIMEOUT_START, send_sigkill=True) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command(self.command_args)) self.expect_and_no_warn("{} is already installed.*\[.*\] ".format(self.name)) self.child.sendline() self.wait_and_close() class EclipsePHPIDETests(EclipseJavaIDETests): """The Eclipse distribution from the IDE collection.""" def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "eclipse-php") self.desktop_filename = "eclipse-php.desktop" self.command_args = '{} ide eclipse-php'.format(UMAKE) self.name = "Eclipse PHP" class EclipseCPPIDETests(EclipseJavaIDETests): """The Eclipse distribution from the IDE collection.""" def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "eclipse-cpp") self.desktop_filename = "eclipse-cpp.desktop" self.command_args = '{} ide eclipse-cpp'.format(UMAKE) self.name = "Eclipse CPP" class IdeaIDETests(LargeFrameworkTests): """IntelliJ Idea from the IDE collection.""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "idea") self.desktop_filename = 'jetbrains-idea.desktop' def test_default_install(self): """Install from scratch test case""" self.child = spawn_process(self.command('{} ide idea'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide idea'.format(UMAKE))) self.expect_and_no_warn("Idea is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class IdeaUltimateIDETests(LargeFrameworkTests): """IntelliJ Idea Ultimate from the IDE collection.""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "idea-ultimate") self.desktop_filename = 'jetbrains-idea.desktop' def test_default_install(self): """Install from scratch test case""" self.child = spawn_process(self.command('{} ide idea-ultimate'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() logger.info("Installed, running...") # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide idea-ultimate'.format(UMAKE))) self.expect_and_no_warn("Idea Ultimate is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class PyCharmIDETests(LargeFrameworkTests): """PyCharm from the IDE collection.""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "pycharm") self.desktop_filename = 'jetbrains-pycharm.desktop' def test_default_install(self): """Install from scratch test case""" self.child = spawn_process(self.command('{} ide pycharm'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() logger.info("Installed, running...") # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide pycharm'.format(UMAKE))) self.expect_and_no_warn("PyCharm is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class PyCharmEducationalIDETests(LargeFrameworkTests): """PyCharm Educational from the IDE collection.""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "pycharm-educational") self.desktop_filename = 'jetbrains-pycharm.desktop' def test_default_install(self): """Install from scratch test case""" self.child = spawn_process(self.command('{} ide pycharm-educational'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() logger.info("Installed, running...") # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide pycharm-educational'.format(UMAKE))) self.expect_and_no_warn("PyCharm Educational is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class PyCharmProfessionalIDETests(LargeFrameworkTests): """PyCharm Professional from the IDE collection.""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "pycharm-professional") self.desktop_filename = 'jetbrains-pycharm.desktop' def test_default_install(self): """Install from scratch test case""" self.child = spawn_process(self.command('{} ide pycharm-professional'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() logger.info("Installed, running...") # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide pycharm-professional'.format(UMAKE))) self.expect_and_no_warn("PyCharm Professional is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class RubyMineIDETests(LargeFrameworkTests): """RubyMine from the IDE collection.""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "rubymine") self.desktop_filename = 'jetbrains-rubymine.desktop' def test_default_install(self): """Install from scratch test case""" self.child = spawn_process(self.command('{} ide rubymine'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() logger.info("Installed, running...") # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide rubymine'.format(UMAKE))) self.expect_and_no_warn("RubyMine is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class WebStormIDETests(LargeFrameworkTests): """WebStorm from the IDE collection.""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "webstorm") self.desktop_filename = 'jetbrains-webstorm.desktop' def test_default_install(self): """Install from scratch test case""" self.child = spawn_process(self.command('{} ide webstorm'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() logger.info("Installed, running...") # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide webstorm'.format(UMAKE))) self.expect_and_no_warn("WebStorm is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class PhpStormIDETests(LargeFrameworkTests): """PhpStorm from the IDE collection.""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "phpstorm") self.desktop_filename = 'jetbrains-phpstorm.desktop' def test_default_install(self): """Install from scratch test case""" self.child = spawn_process(self.command('{} ide phpstorm'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() logger.info("Installed, running...") # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide phpstorm'.format(UMAKE))) self.expect_and_no_warn("PhpStorm is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class CLionIDETests(LargeFrameworkTests): """CLion test from the IDE collection""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "clion") self.desktop_filename = 'jetbrains-clion.desktop' def test_default_install(self): """Install from scratch test case""" # only an amd64 framework if platform.machine() != "x86_64": return self.child = spawn_process(self.command('{} ide clion'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() logger.info("Installed, running...") # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide clion'.format(UMAKE))) self.expect_and_no_warn("CLion is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class DataGripIDETests(LargeFrameworkTests): """Datagrip test from the IDE collection""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "datagrip") self.desktop_filename = 'jetbrains-datagrip.desktop' def test_default_install(self): """Install from scratch test case""" self.child = spawn_process(self.command('{} ide datagrip'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() logger.info("Installed, running...") # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide datagrip'.format(UMAKE))) self.expect_and_no_warn("DataGrip is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class ArduinoIDETests(LargeFrameworkTests): """The Arduino Software distribution from the IDE collection.""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "arduino") self.desktop_filename = "arduino.desktop" @property def arch_option(self): """we return the expected arch call on command line""" return platform.machine() def test_default_install(self): """Install the distribution from scratch test case""" self.child = spawn_process(self.command('{} ide arduino'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assertTrue(self.is_in_group("dialout")) self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", "processing.app.Base"], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide arduino'.format(UMAKE))) self.expect_and_no_warn("Arduino is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class BaseNetBeansTests(LargeFrameworkTests): """Tests for the Netbeans installer.""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "netbeans") self.desktop_filename = "netbeans.desktop" def test_default_install(self): """Install from scratch test case""" self.child = spawn_process(self.command('{} ide netbeans'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() logger.info("Installed, running...") # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide netbeans'.format(UMAKE))) self.expect_and_no_warn("Netbeans is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class VisualStudioCodeTest(LargeFrameworkTests): """Tests for Visual Studio Code""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 20 TIMEOUT_STOP = 20 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "visual-studio-code") self.desktop_filename = "visual-studio-code.desktop" def test_default_install(self): """Install visual studio from scratch test case""" self.child = spawn_process(self.command('{} ide visual-studio-code'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license question self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["Code", self.installed_path], wait_before=self.TIMEOUT_START, send_sigkill=True) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide visual-studio-code'.format(UMAKE))) self.expect_and_no_warn("Visual Studio Code is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class LightTableTest(LargeFrameworkTests): """Tests for LightTable""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 20 TIMEOUT_STOP = 20 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "lighttable") self.desktop_filename = "lighttable.desktop" def test_default_install(self): """Install LightTable from scratch test case""" self.child = spawn_process(self.command('{} ide lighttable'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["LightTable", self.installed_path], wait_before=self.TIMEOUT_START, send_sigkill=True) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} ide lighttable'.format(UMAKE))) self.expect_and_no_warn("LightTable is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class SpringToolsSuiteTest(LargeFrameworkTests): """Tests for Spring Tools Suite""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "ide", "spring-tools-suite") self.desktop_filename = "STS.desktop" self.command_args = '{} ide spring-tools-suite'.format(UMAKE) self.name = 'Spring Tools Suite' @property def arch_option(self): """we return the expected arch call on command line""" return platform.machine() def test_default_install(self): """Install STS from scratch test case""" self.child = spawn_process(self.command(self.command_args)) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # on 64 bits, there is a java subprocess, we kill that one with SIGKILL (eclipse isn't reliable on SIGTERM) if self.arch_option == "x86_64": self.check_and_kill_process(["java", self.arch_option, self.installed_path], wait_before=self.TIMEOUT_START, send_sigkill=True) else: self.check_and_kill_process([self.exec_path], wait_before=self.TIMEOUT_START, send_sigkill=True) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command(self.command_args)) self.expect_and_no_warn("{} is already installed.*\[.*\] ".format(self.name)) self.child.sendline() self.wait_and_close() ubuntu-make-16.02.1/tests/large/test_general.py0000664000000000000000000000261512656574623016314 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """General frameworks tests""" from . import LargeFrameworkTests import subprocess from ..tools import UMAKE class GeneralTests(LargeFrameworkTests): """This will test the General frameworks functionality""" def test_run_category_without_default_framework(self): """Trying to run a category without a default framework exits in error""" exception_raised = False try: subprocess.check_output(self.command_as_list([UMAKE, 'ide']), stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: self.assertIn("ERROR:", e.output.decode("utf-8")) exception_raised = True self.assertTrue(exception_raised) ubuntu-make-16.02.1/tests/large/test_web.py0000664000000000000000000001544112656574623015455 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the Web category""" import logging import platform import subprocess import os from tests.large import LargeFrameworkTests from tests.tools import UMAKE, spawn_process logger = logging.getLogger(__name__) class FirefoxDevTests(LargeFrameworkTests): """Tests for Firefox Developer Edition""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 20 TIMEOUT_STOP = 20 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "web", "firefox-dev") self.desktop_filename = "firefox-developer.desktop" @property def arch_option(self): """we return the expected arch call on command line""" return platform.machine() def verify_install(self, installed_language): # we have an installed launcher, added to the launcher, a dictionary file and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertTrue(self.language_file_exists(installed_language)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["firefox-dev", self.installed_path], wait_before=self.TIMEOUT_START, send_sigkill=True) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} web firefox-dev'.format(UMAKE))) self.expect_and_no_warn("Firefox Dev is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() def test_default_install(self): """Install firefox dev from scratch test case""" install_language = "en-US" self.child = spawn_process(self.command('{} web firefox-dev'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Choose language:") self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() self.verify_install(install_language) def test_arg_language_select_install(self): """Install firefox dev with language selected by --lang""" install_language = "bg" self.child = spawn_process(self.command('{} web firefox-dev --lang={}'.format(UMAKE, install_language))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() self.verify_install(install_language) def test_interactive_language_select_install(self): """Install firefox dev with language selected interactively""" install_language = "bg" self.child = spawn_process(self.command('{} web firefox-dev'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Choose language:") self.child.sendline(install_language) self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() self.verify_install(install_language) def test_unavailable_language_select_install(self): """Installing Firefox-dev in unavailable language should be rejected""" install_language = "ABCdwXYZ" self.child = spawn_process(self.command('{} web firefox-dev --lang={}'.format(UMAKE, install_language))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.wait_and_close(expect_warn=True, exit_status=1) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) def language_file_exists(self, language): return self.path_exists(os.path.join(self.installed_path, "dictionaries", "{}.aff".format(language))) class VisualStudioCodeTest(LargeFrameworkTests): """Tests for Visual Studio Code""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 20 TIMEOUT_STOP = 20 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "web", "visual-studio-code") self.desktop_filename = "visual-studio-code.desktop" def test_default_install(self): """Install visual studio from scratch test case""" self.child = spawn_process(self.command('{} web visual-studio-code'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path), expect_warn=True) self.child.sendline("") self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license question self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher and an icon file self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["Code", self.installed_path], wait_before=self.TIMEOUT_START, send_sigkill=True) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} web visual-studio-code'.format(UMAKE))) self.expect_and_no_warn("Visual Studio Code is already installed.*\[.*\] ", expect_warn=True) self.child.sendline() self.wait_and_close() ubuntu-make-16.02.1/tests/large/test_games.py0000664000000000000000000001411212656574623015766 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for android""" from . import LargeFrameworkTests import os import platform import subprocess from ..tools import UMAKE, spawn_process class StencylTests(LargeFrameworkTests): """This will test the Stencyl installation""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 20 TIMEOUT_STOP = 20 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "games", "stencyl") self.desktop_filename = "stencyl.desktop" def test_default_stencyl_install(self): """Install stencyl from scratch test case""" self.child = spawn_process(self.command('{} games stencyl'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine use_cwd = self.installed_path if self.in_container: use_cwd = None proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=use_cwd) self.check_and_kill_process(["./runtimes/jre-linux/bin/java"], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} games stencyl'.format(UMAKE))) self.expect_and_no_warn("Stencyl is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class Unity3DTests(LargeFrameworkTests): """This will test the Unity 3D editor installation""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 20 TIMEOUT_STOP = 20 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "games", "unity3d") self.desktop_filename = "unity3d-editor.desktop" def test_default_unity3D_install(self): """Install unity3D editor from scratch test case""" # only an amd64 test if platform.machine() != "x86_64": return self.child = spawn_process(self.command('{} games unity3d'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # ensure setuid self.assertEqual(self.get_file_perms(os.path.join(self.installed_path, "Editor", "chrome-sandbox")), '-rwsr-xr-x') # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process([self.exec_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} games unity3d'.format(UMAKE))) self.expect_and_no_warn("Unity3d is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class TwineTests(LargeFrameworkTests): """This will test the Twine installation""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 20 TIMEOUT_STOP = 20 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "games", "twine") self.desktop_filename = "twine.desktop" def test_default_twine_install(self): """Install twine editor from scratch test case""" self.child = spawn_process(self.command('{} games twine'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process([self.exec_path], wait_before=self.TIMEOUT_START) proc.wait(self.TIMEOUT_STOP) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} games twine'.format(UMAKE))) self.expect_and_no_warn("Twine is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() ubuntu-make-16.02.1/tests/large/test_basics_cli.py0000664000000000000000000001257712656574623017002 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for basic CLI commands""" from contextlib import suppress import os import subprocess from . import LargeFrameworkTests from ..tools import LoggedTestCase, UMAKE, get_root_dir class BasicCLI(LargeFrameworkTests): """This will test the basic cli command class""" @classmethod def setUpClass(cls): super().setUpClass() cls.log_cfg = None with suppress(KeyError): cls.log_cfg = os.environ.pop("LOG_CFG") @classmethod def tearDownClass(cls): super().tearDownClass() if (cls.log_cfg): os.environ["LOG_CFG"] = cls.log_cfg def command_as_list(self, commands_input): """passthrough, return args""" return commands_input def return_without_first_output(self, stdout): """We return ignoring the first line which is INFO: set logging level to""" return "\n".join(stdout.split('\n')[1:]) def test_global_help(self): """We display a global help message""" result = subprocess.check_output(self.command_as_list([UMAKE, '--help'])) self.assertNotEqual(result, "") def test_setup_info_logging(self): """We display info logs""" result = subprocess.check_output(self.command_as_list([UMAKE, '-v', '--help']), stderr=subprocess.STDOUT) self.assertIn("INFO:", self.return_without_first_output(result.decode("utf-8"))) def test_setup_debug_logging(self): """We display debug logs""" result = subprocess.check_output(self.command_as_list([UMAKE, '-vv', '--help']), stderr=subprocess.STDOUT) self.assertIn("DEBUG:", self.return_without_first_output(result.decode("utf-8"))) def test_setup_with_option_logging(self): """We don't mix info or debug logs with a -v option""" exception_raised = False try: subprocess.check_output(self.command_as_list([UMAKE, '-vouep', '--help']), stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: self.assertNotIn("INFO:", self.return_without_first_output(e.output.decode("utf-8"))) self.assertNotIn("DEBUG:", self.return_without_first_output(e.output.decode("utf-8"))) exception_raised = True self.assertTrue(exception_raised) def test_setup_logging_level_with_env(self): """Set logging option to debug via env var""" env = {"LOG_CFG": os.path.join(get_root_dir(), "confs", "info.logcfg")} env.update(os.environ) commands = [UMAKE] if self.in_container: commands.insert(0, "LOG_CFG={}".format(env["LOG_CFG"])) result = subprocess.check_output(self.command_as_list(commands), env=env, stderr=subprocess.STDOUT) self.assertIn("Logging level set to INFO", result.decode("utf-8")) def test_version(self): """We display a version""" result = subprocess.check_output(self.command_as_list([UMAKE, '--version'])) self.assertNotEqual(result, "") def test_category_help(self): """We display a category help""" result = subprocess.check_output(self.command_as_list([UMAKE, 'ide', '--help'])) self.assertNotEqual(result, "") def test_framework_help(self): """We display a framework help""" result = subprocess.check_output(self.command_as_list([UMAKE, 'ide', 'pycharm', '--help'])) self.assertNotEqual(result, "") def test_help_position_matters(self): """The help option position matters""" result1 = subprocess.check_output(self.command_as_list([UMAKE, 'ide', 'pycharm', '--help'])) result2 = subprocess.check_output(self.command_as_list([UMAKE, 'ide', '--help', 'pycharm'])) result3 = subprocess.check_output(self.command_as_list([UMAKE, '--help', 'ide', 'pycharm'])) self.assertNotEquals(result1, result2) self.assertNotEquals(result2, result3) self.assertNotEquals(result1, result3) def test_category_with_default_framework_help(self): """We display a help when there is a default framework""" result = subprocess.check_output(self.command_as_list([UMAKE, 'android', '--help'])) self.assertNotEqual(result, "") def test_only_category_help_with_default_framework(self): """We display a category help which is different from the default framework one""" result1 = subprocess.check_output(self.command_as_list([UMAKE, 'android', '--help'])) result2 = subprocess.check_output(self.command_as_list([UMAKE, 'android', 'android-studio', '--help'])) self.assertNotEquals(result1, result2) ubuntu-make-16.02.1/tests/large/test_android.py0000664000000000000000000001437712656574623016327 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for android""" from . import LargeFrameworkTests import os import subprocess from ..tools import UMAKE, spawn_process class AndroidStudioTests(LargeFrameworkTests): """This will test the Android Studio base""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 60 TIMEOUT_STOP = 60 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "android", "android-studio") self.desktop_filename = "android-studio.desktop" def test_default_android_studio_install(self): """Install android studio from scratch test case""" self.child = spawn_process(self.command('{} android android-studio'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license question self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() self.assert_exec_link_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process(["java", self.installed_path], wait_before=self.TIMEOUT_START) self.assertEqual(proc.wait(self.TIMEOUT_STOP), 143) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} android android-studio'.format(UMAKE))) self.expect_and_no_warn("Android Studio is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class AndroidSDKTests(LargeFrameworkTests): """This will test the Android SDK installation""" TIMEOUT_INSTALL_PROGRESS = 120 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "android", "android-sdk") @property def exec_path(self): return os.path.join(self.installed_path, "tools", "android") def test_default_android_sdk_install(self): """Install android sdk from scratch test case""" self.child = spawn_process(self.command('{} android android-sdk'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license question self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed sdk exec self.assert_exec_exists() self.assertTrue(self.is_in_path(self.exec_path)) # launch it, send SIGTERM and check that it exits fine self.assertEqual(subprocess.check_call(self.command_as_list([self.exec_path, "list"]), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL), 0) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} android android-sdk'.format(UMAKE))) self.expect_and_no_warn("Android SDK is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() class AndroidNDKTests(LargeFrameworkTests): """This will test the Android NDK installation""" TIMEOUT_INSTALL_PROGRESS = 120 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "android", "android-ndk") @property def exec_path(self): return os.path.join(self.installed_path, "ndk-which") def test_default_android_ndk_install(self): """Install android ndk from scratch test case""" self.child = spawn_process(self.command('{} android android-ndk'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license question self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed ndk exec self.assert_exec_exists() cmd_list = ["echo $NDK_ROOT"] if not self.in_container: relogging_command = ["bash", "-l", "-c"] relogging_command.extend(cmd_list) cmd_list = relogging_command self.assertEqual(subprocess.check_output(self.command_as_list(cmd_list)).decode("utf-8").strip(), self.installed_path) # launch it, send SIGTERM and check that it exits fine self.assertEqual(subprocess.check_call(self.command_as_list([self.exec_path, "gcc"]), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL), 0) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} android android-ndk'.format(UMAKE))) self.expect_and_no_warn("Android NDK is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() ubuntu-make-16.02.1/tests/large/test_dart.py0000664000000000000000000000411312656574623015624 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the Dart category""" import logging import os from tests.large import LargeFrameworkTests from tests.tools import UMAKE, spawn_process logger = logging.getLogger(__name__) class DartEditorTests(LargeFrameworkTests): """Tests for Dart Editor with SDK""" TIMEOUT_INSTALL_PROGRESS = 120 def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "dart", "dart-sdk") @property def exec_path(self): return os.path.join(self.installed_path, "bin", "dart") def test_default_dart_install(self): """Install dart editor from scratch test case""" self.child = spawn_process(self.command('{} dart'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher and an icon file self.assert_exec_exists() self.assertTrue(self.is_in_path(self.exec_path)) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} dart'.format(UMAKE))) self.expect_and_no_warn("Dart SDK is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() ubuntu-make-16.02.1/tests/large/test_scala.py0000664000000000000000000000524612656574623015765 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # Tin Tvrtković # Igor Vuk # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the Scala category""" import subprocess import os import tempfile from tests.large import LargeFrameworkTests from tests.tools import UMAKE, spawn_process class ScalaTests(LargeFrameworkTests): """The default Scala compiler.""" TIMEOUT_INSTALL_PROGRESS = 300 EXAMPLE_PROJECT = """object HelloWorld { def main(args: Array[String]) { println("hello, world") } }""" def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "scala", "scala-lang") self.framework_name_for_profile = "Scala Lang" @property def exec_path(self): return os.path.join(self.installed_path, "bin", "scala") def test_default_scala_install(self): """Install Scala from scratch test case""" if not self.in_container: self.example_prog_dir = tempfile.mkdtemp() self.additional_dirs.append(self.example_prog_dir) example_file = os.path.join(self.example_prog_dir, "hello.scala") open(example_file, "w").write(self.EXAMPLE_PROJECT) compile_command = ["bash", "-l", "-c", "scala {}".format(example_file)] else: # our mock expects getting that path compile_command = ["bash", "-l", "scala /tmp/hello.scala"] self.child = spawn_process(self.command('{} scala'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() self.assert_exec_exists() self.assertTrue(self.is_in_path(self.exec_path)) # compile a small project output = subprocess.check_output(self.command_as_list(compile_command)).decode()\ .replace('\r', '').replace('\n', '') self.assertEqual(output, "hello, world") ubuntu-make-16.02.1/tests/large/test_rust.py0000664000000000000000000000715612656574623015701 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014-2015 Canonical # # Authors: # Didier Roche # Tin Tvrtković # Jared Ravetch # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the Rust category""" import subprocess import os import tempfile from tests.large import LargeFrameworkTests from tests.tools import UMAKE, spawn_process class RustTests(LargeFrameworkTests): """The official Rust distribution""" TIMEOUT_INSTALL_PROGRESS = 300 EXAMPLE_PROJECT = """fn main() {println!("hello, world");}""" def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "rust", "rust-lang") self.framework_name_for_profile = "Rust" @property def exec_path(self): return os.path.join(self.installed_path, "rustc", "bin", "rustc") def test_default_rust_install(self): """Install Rust from scratch test case""" if not self.in_container: self.example_prog_dir = tempfile.mkdtemp() self.additional_dirs.append(self.example_prog_dir) example_file = os.path.join(self.example_prog_dir, "hello.rs") open(example_file, "w").write(self.EXAMPLE_PROJECT) # rust compile in pwd by default, do not pollute ubuntu make source code compile_command = ["bash", "-l", "-c", "rustc --out-dir {} {}".format(self.example_prog_dir, example_file)] else: # our mock expects getting that path self.example_prog_dir = "/tmp" example_file = os.path.join(self.example_prog_dir, "hello.rs") # rust compile in pwd by default, do not pollute ubuntu make source code compile_command = ["bash", "-l", "rustc --out-dir {} {}".format(self.example_prog_dir, example_file)] resulting_binary = os.path.join(self.example_prog_dir, "hello") self.child = spawn_process(self.command('{} rust'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() self.assert_exec_exists() self.assertTrue(self.is_in_path(self.exec_path)) self.assertTrue(self.is_in_path(os.path.join(self.installed_path, "cargo", "bin", "cargo"))) cmd_list = ["echo $LD_LIBRARY_PATH"] if not self.in_container: relogging_command = ["bash", "-l", "-c"] relogging_command.extend(cmd_list) cmd_list = relogging_command self.assertIn(os.path.join(self.installed_path, "rustc", "lib"), subprocess.check_output(self.command_as_list(cmd_list)).decode("utf-8").strip().split(":")) # compile a small project subprocess.check_call(self.command_as_list(compile_command)) # run the compiled result output = subprocess.check_output(self.command_as_list(resulting_binary)).decode()\ .replace('\r', '').replace('\n', '') self.assertEqual(output, "hello, world") ubuntu-make-16.02.1/tests/large/test_nodejs.py0000664000000000000000000000644012656574623016161 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the Nodejs category""" import subprocess import os import tempfile from tests.large import LargeFrameworkTests from tests.tools import UMAKE, spawn_process class NodejsTests(LargeFrameworkTests): """Nodejs stable.""" TIMEOUT_INSTALL_PROGRESS = 300 EXAMPLE_PROJECT = """console.log("Hello World");""" def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "nodejs", "nodejs-lang") self.framework_name_for_profile = "Nodejs Lang" @property def exec_path(self): return os.path.join(self.installed_path, "bin", "node") def test_default_nodejs_install(self): """Install Nodejs from scratch test case""" if not self.in_container: self.example_prog_dir = tempfile.mkdtemp() self.additional_dirs.append(self.example_prog_dir) example_file = os.path.join(self.example_prog_dir, "hello.js") open(example_file, "w").write(self.EXAMPLE_PROJECT) compile_command = ["bash", "-l", "-c", "node {}".format(example_file)] npm_command = ["bash", "-l", "-c", "npm config get prefix"] else: # our mock expects getting that path compile_command = ["bash", "-l", "node /tmp/hello.js"] npm_command = ["bash", "-l", "npm config get prefix"] self.child = spawn_process(self.command('{} nodejs'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() self.assert_exec_exists() self.assertTrue(self.is_in_path(self.exec_path)) npm_path = os.path.join(self.installed_path, "bin", "npm") self.assertTrue(self.path_exists(npm_path)) self.assertTrue(self.is_in_path(npm_path)) # compile a small project output = subprocess.check_output(self.command_as_list(compile_command)).decode()\ .replace('\r', '').replace('\n', '') # set npm prefix npm_output = subprocess.check_output(self.command_as_list(npm_command)).decode()\ .replace('\r', '').replace('\n', '') self.assertEqual(output, "Hello World") self.assertEqual(npm_output, "{}/.node_modules".format(os.path.join("/", self.installed_path.split('/')[1], self.installed_path.split('/')[2]))) ubuntu-make-16.02.1/tests/large/test_baseinstaller.py0000664000000000000000000006740012656574623017532 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for large base installer framework""" from . import LargeFrameworkTests import os import pexpect import platform import shutil import subprocess import tempfile from ..tools import UMAKE, spawn_process, get_data_dir, swap_file_and_restore from ..tools.local_server import LocalHttp class BaseInstallerTests(LargeFrameworkTests): """This will test the base installer framework via a fake one""" TIMEOUT_INSTALL_PROGRESS = 120 TIMEOUT_START = 1 TIMEOUT_STOP = 1 server = None TEST_URL_FAKE_DATA = "http://localhost:8765/base-framework-fake64.tgz" TEST_CHECKSUM_FAKE_DATA = "4a582c6e35700f00332783b0b83783f73499aa60" JAVAEXEC = "java-fake64" @classmethod def setUpClass(cls): super().setUpClass() cls.proxy_env = {"http_proxy": None, "https_proxy": None} for key in cls.proxy_env: cls.proxy_env[key] = os.environ.pop(key, None) cls.download_page_file_path = os.path.join(get_data_dir(), "server-content", "localhost", "index.html") if not cls.in_container: server_dir = os.path.join(get_data_dir(), "server-content", "localhost") cls.server = LocalHttp(server_dir, port=8765) framework_dir = os.path.expanduser(os.path.join('~', '.umake', 'frameworks')) cls.testframework = (os.path.join(framework_dir, 'baseinstallerfake.py')) os.makedirs(framework_dir, exist_ok=True) shutil.copy(os.path.join(get_data_dir(), "testframeworks", "baseinstallerfake.py"), cls.testframework) if platform.machine() != "x86_64": cls.TEST_URL_FAKE_DATA = "http://localhost:8765/base-framework-fake32.tgz" cls.TEST_CHECKSUM_FAKE_DATA = "4f64664ebe496cc6d54f417f25a1707f156d74d2" cls.JAVAEXEC = "java-fake32" @classmethod def tearDownClass(cls): super().tearDownClass() for key, value in cls.proxy_env.items(): if value: os.environ[key] = value if not cls.in_container: os.remove(cls.testframework) cls.server.stop() def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "base", "base-framework") self.desktop_filename = "base-framework.desktop" @property def arch_option(self): """we return the expected arch call on command line""" return platform.machine() def test_default_install(self): """Install base installer from scratch test case""" self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license question self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process([self.JAVAEXEC, self.installed_path], wait_before=self.TIMEOUT_START) self.assertEqual(proc.wait(self.TIMEOUT_STOP), 143) # ensure that it's detected as installed: self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Base Framework is already installed.*\[.*\] ") self.child.sendline() self.wait_and_close() def test_no_license_accept(self): """We don't accept the license (default)""" self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license question self.accept_default_and_wait() self.close_and_check_status() self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) def test_doesnt_accept_wrong_path(self): """We don't accept a wrong path""" self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline(chr(127) * 100) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline(chr(127) * 100 + "/") self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path), expect_warn=True) self.child.sendcontrol('C') self.wait_and_no_warn() self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) def test_reinstall(self): """Reinstall once installed""" for loop in ("install", "reinstall"): self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) if loop == "reinstall": # we only have one question, not the one about existing dir. self.expect_and_no_warn("Base Framework is already installed.*\[.*\] ") self.child.sendline("y") self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[.*\] ") self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process([self.JAVAEXEC, self.installed_path], wait_before=self.TIMEOUT_START) def test_reinstall_other_path(self): """Reinstall Base Framework on another path once installed should remove the first version""" original_install_path = self.installed_path for loop in ("install", "reinstall"): if loop == "reinstall": self.installed_path = "/tmp/foo" self.child = spawn_process(self.command('{} base base-framework {}'.format(UMAKE, self.installed_path))) self.expect_and_no_warn("Base Framework is already installed.*\[.*\] ") self.child.sendline("y") else: self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[.*\] ") self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() # ensure that version first isn't installed anymore self.assertFalse(self.path_exists(original_install_path)) def test_reinstall_other_non_empty_path(self): """Reinstall Base Framework on another path (non empty) once installed should remove the first version""" original_install_path = self.installed_path if not self.in_container: self.reinstalled_path = tempfile.mkdtemp() else: # we still give a path for the container self.reinstalled_path = os.path.join(tempfile.gettempdir(), "tmptests") self.create_file(os.path.join(self.reinstalled_path, "bar"), "foo") for loop in ("install", "reinstall"): if loop == "reinstall": self.installed_path = self.reinstalled_path self.child = spawn_process(self.command('{} base base-framework {}'.format(UMAKE, self.installed_path))) self.expect_and_no_warn("Base Framework is already installed.*\[.*\] ") self.child.sendline("y") self.expect_and_no_warn("{} isn't an empty directory.*there\? \[.*\] ".format(self.installed_path)) self.child.sendline("y") else: self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[.*\] ") self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() # ensure that version first isn't installed anymore self.assertFalse(self.path_exists(original_install_path)) def test_reinstall_previous_install_removed(self): """Detect that removing Base Framework content, but still having a launcher, doesn't trigger a reinstall question""" for loop in ("install", "reinstall"): if loop == "reinstall": # remove code (but not laucher) self.remove_path(self.installed_path) self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[.*\] ") self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() def test_reinstall_previous_launcher_removed(self): """Detect that removing Base Framework launcher, but still having the code, doesn't trigger a reinstall question. However, we do have a dir isn't empty one.""" for loop in ("install", "reinstall"): if loop == "reinstall": # remove launcher, but not code self.remove_path(self.get_launcher_path(self.desktop_filename)) self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") if loop == "reinstall": self.expect_and_no_warn("{} isn't an empty directory.*there\? \[.*\] ".format(self.installed_path)) self.child.sendline("y") self.expect_and_no_warn("\[.*\] ") self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() def test_xdg_data_install_path(self): """Install in path specified by XDG_DATA_HOME""" xdg_data_path = "/tmp/foo" self.installed_path = "{}/umake/base/base-framework".format(xdg_data_path) cmd = "XDG_DATA_HOME={} {} base base-framework".format(xdg_data_path, UMAKE) if not self.in_container: cmd = 'bash -c "{}"'.format(cmd) self.child = spawn_process(self.command(cmd)) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[I Accept.*\]") self.accept_default_and_wait() self.close_and_check_status() self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) def test_custom_install_path(self): """We install Base Framework in a custom path""" # We skip the existing directory prompt self.installed_path = "/tmp/foo" self.child = spawn_process(self.command('{} base base-framework {}'.format(UMAKE, self.installed_path))) self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license as the first question self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process([self.JAVAEXEC, self.installed_path], wait_before=self.TIMEOUT_START) self.assertEqual(proc.wait(self.TIMEOUT_STOP), 143) def test_start_install_on_empty_dir(self): """We try to install on an existing empty dir""" if not self.in_container: self.installed_path = tempfile.mkdtemp() else: # we still give a path for the container self.installed_path = os.path.join(tempfile.gettempdir(), "tmptests") self.child = spawn_process(self.command('{} base base-framework {}'.format(UMAKE, self.installed_path))) self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license as the first question self.accept_default_and_wait() self.close_and_check_status() self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) def test_start_install_on_existing_dir_refuse(self): """We prompt if we try to install on an existing directory which isn't empty. Refusing doesn't install""" if not self.in_container: self.installed_path = tempfile.mkdtemp() else: # we still give a path for the container self.installed_path = os.path.join(tempfile.gettempdir(), "tmptests") self.create_file(os.path.join(self.installed_path, "bar"), "foo") self.child = spawn_process(self.command('{} base base-framework {}'.format(UMAKE, self.installed_path))) self.expect_and_no_warn("{} isn't an empty directory.*there\? \[.*\] ".format(self.installed_path)) self.accept_default_and_wait() self.close_and_check_status() self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) def test_start_install_on_existing_dir_accept(self): """We prompt if we try to install on an existing directory which isn't empty. Accepting install""" if not self.in_container: self.installed_path = tempfile.mkdtemp() else: # we still give a path for the container self.installed_path = os.path.join(tempfile.gettempdir(), "tmptests") self.create_file(os.path.join(self.installed_path, "bar"), "foo") self.child = spawn_process(self.command('{} base base-framework {}'.format(UMAKE, self.installed_path))) self.expect_and_no_warn("{} isn't an empty directory.*there\? \[.*\] ".format(self.installed_path)) self.child.sendline("y") self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license question self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process([self.JAVAEXEC, self.installed_path], wait_before=self.TIMEOUT_START) self.assertEqual(proc.wait(self.TIMEOUT_STOP), 143) def test_is_default_framework(self): """Base Framework is chosen as the default framework""" self.child = spawn_process(self.command('{} base'.format(UMAKE))) # we ensure it thanks to installed_path being the base framework one self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendcontrol('C') self.wait_and_no_warn() def test_is_default_framework_with_options(self): """Base Framework options are sucked in as the default framework""" self.child = spawn_process(self.command('{} base /tmp/foo'.format(UMAKE))) self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license as the first question self.accept_default_and_wait() self.close_and_check_status() def test_not_default_framework_with_path_without_path_separator(self): """Base Framework isn't selected for default framework with path without separator""" self.child = spawn_process(self.command('{} base foo'.format(UMAKE))) self.expect_and_no_warn("error: argument framework: invalid choice") self.accept_default_and_wait() self.close_and_check_status(exit_status=2) def test_is_default_framework_with_user_path(self): """Base Framework isn't selected for default framework with path without separator""" self.installed_path = "/tmp/foo" self.child = spawn_process(self.command('{} base {}'.format(UMAKE, self.installed_path))) self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license as the first question self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() self.assert_icon_exists() # launch it, send SIGTERM and check that it exits fine proc = subprocess.Popen(self.command_as_list(self.exec_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) self.check_and_kill_process([self.JAVAEXEC, self.installed_path], wait_before=self.TIMEOUT_START) self.assertEqual(proc.wait(self.TIMEOUT_STOP), 143) def test_removal(self): """Remove Base Framework with default path""" self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[.*\] ") self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertTrue(self.path_exists(self.installed_path)) # now, remove it self.child = spawn_process(self.command('{} base base-framework --remove'.format(UMAKE))) self.wait_and_close() self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.path_exists(self.installed_path)) def test_removal_non_default_path(self): """Remove Base Framework with non default path""" self.installed_path = "/tmp/foo" self.child = spawn_process(self.command('{} base base-framework {}'.format(UMAKE, self.installed_path))) self.expect_and_no_warn("\[.*\] ") self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertTrue(self.path_exists(self.installed_path)) # now, remove it self.child = spawn_process(self.command('{} base base-framework --remove'.format(UMAKE))) self.wait_and_close() self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.path_exists(self.installed_path)) def test_removal_global_option(self): """Remove Base Framework via global option (before category) should delete it""" self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[.*\] ") self.child.sendline("a") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertTrue(self.path_exists(self.installed_path)) # now, remove it self.child = spawn_process(self.command('{} --remove base base-framework'.format(UMAKE))) self.wait_and_close() self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assertFalse(self.path_exists(self.installed_path)) def test_automated_install(self): """Install Base Framework automatically with no interactive options""" self.child = spawn_process(self.command('{} base base-framework {} --accept-license'.format(UMAKE, self.installed_path))) self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() # we have an installed launcher, added to the launcher self.assertTrue(self.launcher_exists_and_is_pinned(self.desktop_filename)) self.assert_exec_exists() def test_try_removing_uninstalled_framework(self): """Trying to remove an uninstalled framework will fail""" self.child = spawn_process(self.command('{} base base-framework --remove'.format(UMAKE))) self.wait_and_close(expect_warn=True, exit_status=1) # additional test with fake md5sum def test_install_with_wrong_md5sum(self): """Install requires a md5sum, and a wrong one is rejected""" with swap_file_and_restore(self.download_page_file_path) as content: with open(self.download_page_file_path, "w") as newfile: newfile.write(content.replace(self.TEST_CHECKSUM_FAKE_DATA, "c8362a0c2ffc07b1b19c4b9001c8532de5a4b8c3")) self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license question self.child.sendline("a") self.expect_and_no_warn([pexpect.EOF, "Corrupted download? Aborting."], timeout=self.TIMEOUT_INSTALL_PROGRESS, expect_warn=True) self.wait_and_close(exit_status=1) # we have nothing installed self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) def test_install_with_no_license_in_download_page(self): """Installing should fail if not even license i dowload page""" umake_command = self.command("{} base base-framework".format(UMAKE)) self.bad_download_page_test(umake_command, self.download_page_file_path) self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) def test_install_with_no_download_links(self): """Installing should fail if no valid download links are found""" with swap_file_and_restore(self.download_page_file_path) as content: with open(self.download_page_file_path, "w") as newfile: newfile.write(content.replace('id="linux-bundle', "")) self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn([pexpect.EOF], timeout=self.TIMEOUT_INSTALL_PROGRESS, expect_warn=True) self.wait_and_close(exit_status=1) # we have nothing installed self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) def test_install_with_404(self): """Installing should fail with a 404 download asset reported correctly""" with swap_file_and_restore(self.download_page_file_path) as content: with open(self.download_page_file_path, "w") as newfile: newfile.write(content.replace(self.TEST_URL_FAKE_DATA, "https://localhost:8765/android-studio-unexisting.tgz")) self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("\[I Accept.*\]") # ensure we have a license question self.child.sendline("a") self.expect_and_no_warn([pexpect.EOF, "ERROR: 404 Client Error: File not found"], timeout=self.TIMEOUT_INSTALL_PROGRESS, expect_warn=True) self.wait_and_close(exit_status=1) # we have nothing installed self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) def test_download_page_404(self): """Download page changed address or is just 404 should be reported correctly""" with swap_file_and_restore(self.download_page_file_path): os.remove(self.download_page_file_path) self.child = spawn_process(self.command('{} base base-framework'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn([pexpect.EOF, "ERROR: 404 Client Error: File not found"], timeout=self.TIMEOUT_INSTALL_PROGRESS, expect_warn=True) self.wait_and_close(exit_status=1) # we have nothing installed self.assertFalse(self.launcher_exists_and_is_pinned(self.desktop_filename)) ubuntu-make-16.02.1/tests/large/__init__.py0000664000000000000000000002272112656574623015377 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Basic large tests class""" from contextlib import suppress from nose.tools import nottest import os import pexpect import shutil import signal import stat import subprocess from time import sleep from umake.tools import get_icon_path, get_launcher_path, launcher_exists_and_is_pinned, remove_framework_envs_from_user from ..tools import LoggedTestCase, get_path_from_desktop_file, is_in_group, INSTALL_DIR, swap_file_and_restore, \ spawn_process from umake.settings import DEFAULT_BINARY_LINK_PATH class LargeFrameworkTests(LoggedTestCase): """Large framework base utilities""" in_container = False def setUp(self): super().setUp() self.installed_path = "" self.framework_name_for_profile = "" self.conf_path = os.path.expanduser("~/.config/umake") self.install_base_path = os.path.expanduser("~/{}".format(INSTALL_DIR)) self.binary_dir = DEFAULT_BINARY_LINK_PATH self.desktop_filename = "" self.child = None self.additional_dirs = [] self.original_env = os.environ.copy() # we want to standardize on bash environment for running large tests os.environ["SHELL"] = "/bin/bash" def tearDown(self): # don't remove on machine paths if running within a container if not self.in_container: with suppress(FileNotFoundError): shutil.rmtree(self.installed_path) # TODO: need to be finer grain in the future with suppress(FileNotFoundError): os.remove(self.conf_path) if self.desktop_filename: with suppress(FileNotFoundError): os.remove(get_launcher_path(self.desktop_filename)) remove_framework_envs_from_user(self.framework_name_for_profile) for dir in self.additional_dirs: with suppress(OSError): shutil.rmtree(dir) # restore original environment. Do not use the dict copy which erases the object and doesn't have the magical # _Environ which setenv() for subprocess os.environ.clear() os.environ.update(self.original_env) super().tearDown() def _pid_for(self, process_grep): """Return pid matching the process_grep elements""" for pid in os.listdir('/proc'): if not pid.isdigit(): continue # ignore processes that are closed in between with suppress(IOError): cmdline = open(os.path.join('/proc', pid, 'cmdline'), 'r').read() for process_elem in process_grep: if process_elem not in cmdline: break # we found it else: return int(pid) raise BaseException("The process that we can find with {} isn't started".format(process_grep)) def check_and_kill_process(self, process_grep, wait_before=0, send_sigkill=False): """Check a process matching process_grep exists and kill it""" sleep(wait_before) pid = self._pid_for(process_grep) if send_sigkill: os.kill(pid, signal.SIGKILL) else: os.kill(pid, signal.SIGTERM) @property def exec_path(self): return self._get_path_from_desktop_file("Exec") def _get_path_from_desktop_file(self, key, abspath_transform=None): """get the path referred as key in the desktop filename exists""" path = get_path_from_desktop_file(self.desktop_filename, key) if not path.startswith("/") and abspath_transform: path = abspath_transform(path) return path def assert_exec_exists(self): """Assert that the exec path exists""" self.assertTrue(self.path_exists(self.exec_path)) def assert_icon_exists(self): """Assert that the icon path exists""" self.assertTrue(self.path_exists(self._get_path_from_desktop_file('Icon', get_icon_path))) def assert_exec_link_exists(self): """Assert that the link to the binary exists""" self.assertTrue(self.is_in_path(os.path.join(self.binary_dir, self.desktop_filename.split('.')[0]))) def assert_for_warn(self, content, expect_warn=False): """assert if there is any warn""" if not expect_warn: # We need to remove the first expected message, which is "Logging level set to " # (can be WARNING or ERROR) content = content.replace("Logging level set to WARNING", "").replace("Logging level set to ERROR", "") self.assertNotIn("WARNING", content) self.assertNotIn("ERROR", content) else: for warn_tag in ("WARNING", "ERROR"): if warn_tag in content: break else: # nothing found: raise BaseException("We didn't find an expected WARNING or ERROR in {}".format(content)) def expect_and_no_warn(self, expect_query, timeout=-1, expect_warn=False): """run the expect query and check that there is no warning or error It doesn't fail on the given timeout if stdout is progressing""" output = "" continue_expect = True while continue_expect: try: self.child.expect(expect_query, timeout=timeout) continue_expect = False except pexpect.TIMEOUT: # stalled during timeout period if output == self.child.before: print(self.child.before) raise output = self.child.before # print the whole process output before getting the pexpect exception except: print(self.child.before) raise self.assert_for_warn(self.child.before, expect_warn) def wait_and_no_warn(self, expect_warn=False): """run wait and check that there is no warning or error""" self.expect_and_no_warn(pexpect.EOF, expect_warn=expect_warn) def accept_default_and_wait(self, expect_warn=False): """accept default and wait for exiting""" self.child.sendline("") self.wait_and_no_warn(expect_warn) def close_and_check_status(self, exit_status=0): """exit child process and check its exit status""" self.child.close() self.assertEqual(exit_status, self.child.exitstatus) def wait_and_close(self, expect_warn=False, exit_status=0): """wait for exiting and check exit status""" self.wait_and_no_warn(expect_warn) self.close_and_check_status(exit_status) def command(self, commands_to_run): """passthrough, return args""" return commands_to_run def command_as_list(self, commands_input): """passthrough, return args""" return commands_input def get_launcher_path(self, desktop_filename): """passthrough getting the launcher path from umake tools""" return get_launcher_path(desktop_filename) def launcher_exists_and_is_pinned(self, desktop_filename): """passthrough to in process method""" return launcher_exists_and_is_pinned(desktop_filename) def path_exists(self, path): """passthrough to os.path.exists""" return os.path.exists(path) def remove_path(self, path): """Remove targeted path""" try: os.remove(path) except OSError: shutil.rmtree(path) def is_in_path(self, filename): """check that we have a directory in path""" return_code = subprocess.call(["bash", "-l", "which", filename], stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if return_code == 0: return True elif return_code == 1: return False raise BaseException("Unknown return code for looking if {} is in path".format(filename)) def is_in_group(self, group): """return if current user is in a group""" return is_in_group(group) def get_file_perms(self, path): """return unix file perms string for path""" return stat.filemode(os.stat(path).st_mode) def create_file(self, path, content): """passthrough to create a file on the disk""" open(path, 'w').write(content) @nottest def bad_download_page_test(self, command, content_file_path): """Helper for running a test to confirm failure on a significantly changed download page.""" with swap_file_and_restore(content_file_path): with open(content_file_path, "w") as newfile: newfile.write("foo") self.child = spawn_process(command) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.wait_and_close(expect_warn=True, exit_status=1) ubuntu-make-16.02.1/tests/large/test_swift.py0000664000000000000000000000612312656574623016031 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the Swift category""" import subprocess import os import tempfile from tests.large import LargeFrameworkTests from tests.tools import UMAKE, spawn_process class SwiftTests(LargeFrameworkTests): """The default Swift compiler.""" TIMEOUT_INSTALL_PROGRESS = 300 EXAMPLE_PROJECT = """print("Hello, world!")""" def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "swift", "swift-lang") self.framework_name_for_profile = "Swift Lang" @property def exec_path(self): return os.path.join(self.installed_path, "usr", "bin", "swift") def test_default_swift_install(self): """Install Swift from scratch test case""" if not self.in_container: self.example_prog_dir = tempfile.mkdtemp() self.additional_dirs.append(self.example_prog_dir) example_file = os.path.join(self.example_prog_dir, "Package.swift") open(example_file, "w").write("") os.mkdir(os.path.join(self.example_prog_dir, "Sources")) example_file = os.path.join(self.example_prog_dir, "Sources", "main.swift") open(example_file, "w").write(self.EXAMPLE_PROJECT) compile_command = ["bash", "-l", "-c", "swift build"] else: # our mock expects getting that command parameter self.example_prog_dir = "/tmp" compile_command = ["bash", "-l", "swift build"] self.child = spawn_process(self.command('{} swift'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() self.assert_exec_exists() self.assertTrue(self.is_in_path(self.exec_path)) resulting_binary = os.path.join(self.example_prog_dir, ".build", "debug", self.example_prog_dir.split('/')[-1]) # compile a small project subprocess.check_call(self.command_as_list(compile_command), cwd=self.example_prog_dir) # run the compiled result output = subprocess.check_output(self.command(resulting_binary), cwd=self.example_prog_dir, shell=True).decode()\ .replace('\r', '').replace('\n', '') self.assertEqual(output, "Hello, world!") ubuntu-make-16.02.1/tests/large/test_go.py0000664000000000000000000000516412656574623015306 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # Tin Tvrtković # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the Go category""" import subprocess import os import tempfile from tests.large import LargeFrameworkTests from tests.tools import UMAKE, spawn_process class GoTests(LargeFrameworkTests): """The default Go google compiler.""" TIMEOUT_INSTALL_PROGRESS = 300 EXAMPLE_PROJECT = """package main import "fmt" func main() { fmt.Printf("hello, world") }""" def setUp(self): super().setUp() self.installed_path = os.path.join(self.install_base_path, "go", "go-lang") self.framework_name_for_profile = "Go Lang" @property def exec_path(self): return os.path.join(self.installed_path, "bin", "go") def test_default_go_install(self): """Install Go from scratch test case""" if not self.in_container: self.example_prog_dir = tempfile.mkdtemp() self.additional_dirs.append(self.example_prog_dir) example_file = os.path.join(self.example_prog_dir, "hello.go") open(example_file, "w").write(self.EXAMPLE_PROJECT) compile_command = ["bash", "-l", "-c", "go run {}".format(example_file)] else: # our mock expects getting that path compile_command = ["bash", "-l", "go run /tmp/hello.go"] self.child = spawn_process(self.command('{} go'.format(UMAKE))) self.expect_and_no_warn("Choose installation path: {}".format(self.installed_path)) self.child.sendline("") self.expect_and_no_warn("Installation done", timeout=self.TIMEOUT_INSTALL_PROGRESS) self.wait_and_close() self.assert_exec_exists() self.assertTrue(self.is_in_path(self.exec_path)) # compile a small project output = subprocess.check_output(self.command_as_list(compile_command)).decode()\ .replace('\r', '').replace('\n', '') self.assertEqual(output, "hello, world") ubuntu-make-16.02.1/tests/jenkins/0000775000000000000000000000000012656574623013631 5ustar ubuntu-make-16.02.1/tests/jenkins/ps-trusty-desktop-revert-snapshot-daily.xml0000664000000000000000000001021412656574623024254 0ustar false 100 true false false false false #!/bin/bash set -ex ssh ubuntu@10.100.0.103 /usr/bin/virsh snapshot-revert ps-trusty-desktop-amd64-1 24022015 ssh ubuntu@10.100.0.103 /usr/bin/virsh snapshot-revert ps-trusty-desktop-i386-1 24022015-i386 both_started=false # start the domain until it's started and kept running (virsh will return in error if domain already started) while [ "$both_started" == false ]; do echo "trying to start both vms" both_started=true # virsh returns false is domain is already started, and so, true if just started it ssh ubuntu@10.100.0.103 /usr/bin/virsh start ps-trusty-desktop-amd64-1 && both_started=false ssh ubuntu@10.100.0.103 /usr/bin/virsh start ps-trusty-desktop-i386-1 && both_started=false sleep 60 done # trying to start the jenkins slave, and ensure they are kept running for at least one loop both_were_started=false while true; do amd64_started=true i386_started=true ssh ubuntu@ps-trusty-desktop-amd64-1 /usr/bin/sudo status jenkins-slave | grep running || amd64_started=false ssh ubuntu@ps-trusty-desktop-i386-1 /usr/bin/sudo status jenkins-slave | grep running || i386_started=false if [ "$amd64_started" = true ] && [ "$i386_started" = true ]; then if [ "$both_were_started" = true ]; then break; fi both_were_started=true fi if [ "$both_were_started" = false ]; then ssh ubuntu@ps-trusty-desktop-amd64-1 /usr/bin/sudo start jenkins-slave || true ssh ubuntu@ps-trusty-desktop-i386-1 /usr/bin/sudo start jenkins-slave || true both_were_started=false fi # Let the service restarts if they do. sleep 60 done ps-trusty-desktop-update-daily ALWAYS false false #!/bin/bash set -ex # reboot the slaves and wait for them to boot up ssh ubuntu@ps-trusty-desktop-amd64-1 /usr/bin/sudo reboot ssh ubuntu@ps-trusty-desktop-i386-1 /usr/bin/sudo reboot sleep 150 # trying to start the jenkins slave, and ensure they are kept running for at least one loop both_were_started=false while true; do amd64_started=true i386_started=true ssh ubuntu@ps-trusty-desktop-amd64-1 /usr/bin/sudo status jenkins-slave | grep running || amd64_started=false ssh ubuntu@ps-trusty-desktop-i386-1 /usr/bin/sudo status jenkins-slave | grep running || i386_started=false if [ "$amd64_started" = true ] && [ "$i386_started" = true ]; then if [ "$both_were_started" = true ]; then break; fi both_were_started=true fi if [ "$both_were_started" = false ]; then ssh ubuntu@ps-trusty-desktop-amd64-1 /usr/bin/sudo start jenkins-slave || true ssh ubuntu@ps-trusty-desktop-i386-1 /usr/bin/sudo start jenkins-slave || true both_were_started=false fi # Let the service restarts if they do. sleep 60 done ubuntu-make-16.02.1/tests/jenkins/tests-collect.xml0000664000000000000000000000572412656574623017150 0ustar Collect ubuntu make trusty tests coverage report false 100 true false false false false label ps-trusty-desktop-amd64-1 ps-trusty-desktop-i386-1 #!/bin/bash -eu # remove old artefacts. rm -rf * .* 2>/dev/null || true TESTS_RESULT_DIR=~/jenkins/workspace/tests/label/*/type for test_type in `ls $TESTS_RESULT_DIR`; do coverage_file=${TESTS_RESULT_DIR}/${test_type}/.coverage config_dir=${TESTS_RESULT_DIR}/${test_type}/config if [ -f ${coverage_file} ]; then cp ${coverage_file} .coverage.${test_type} fi # all configs are identicals if [ ! -d config ] && [ -d ${config_dir} ]; then cp -a ${config_dir} . fi done python3-coverage combine python3-coverage html -d html-coverage python3-coverage xml # print on stdout as well python3-coverage report echo Stats: cd ~/ubuntu-make mv umakelocal umake 2>/dev/null || true # for the stats in case of system tests sloccount umake/ tests/ | head -n -17 | tail -n 9 ** false true true ps-trusty-desktop-revert-snapshot-daily ALWAYS true false ubuntu-make-16.02.1/tests/jenkins/tests.xml0000664000000000000000000001136212656574623015520 0ustar Tests execution for ubuntu make on trusty using latest available ubuntu make test. false 100 target Test target (system or trunk). This depends on which setup job previously executed and is just a tag here. true false false false false type pep8 small medium large label ps-trusty-desktop-amd64-1 ps-trusty-desktop-i386-1 #!/bin/bash -eu RESULT_DIR=$PWD # remove old artefacts. rm -rf * .* 2>/dev/null || true echo "Testing $type tests on ubuntu make $target" ADDITIONAL_OPTS="" if [ "$target" == "system" ]; then ADDITIONAL_OPTS="--system " fi TEST_ENV="DISPLAY=:0" # set proxy for all tests but small ones (proxy doesn't know about localhost and try to interfere) if [ "$type" != small ]; then TEST_ENV="http_proxy=http://squid.internal:3128 https_proxy=http://squid.internal:3128 $TEST_ENV" fi # we skip medium on non amd64, containers are 64 bits if [ "$type" == medium ] && [ "$(arch)" != x86_64 ]; then echo '<?xml version="1.0" encoding="UTF-8"?><testsuite name="nosetests" tests="1" errors="0" failures="0" skip="0"><testcase classname="ignore" name="medium._test_not_supported" time="0.0">{}</testcase></testsuite>' > ${RESULT_DIR}/nosetests.xml exit 0 fi # We need a pseudo tty (even if we have no input) for medium tests to pass. That's why we "ssh -t -t" # sudo su is used because tests: # 1. are better run as non root (hence su whoami) # 2. need to be able to gain sudo priviledge when installing packages ssh -o StrictHostKeyChecking=no -t -t 127.0.0.1 "sudo su $(whoami) -c 'cd ~/ubuntu-make && $TEST_ENV dbus-launch eatmydata ./runtests --coverage --publish ${ADDITIONAL_OPTS} $type'" || true # copy artefacts cd ~/ubuntu-make cp nosetests.* ${RESULT_DIR} cp .coverage ${RESULT_DIR} cp -a *coverage* ${RESULT_DIR} cp *.log ${RESULT_DIR} cp -a /tmp/config ${RESULT_DIR} ** false **/nosetests.xml false true true tests-collect, ALWAYS true false ubuntu-make-16.02.1/tests/jenkins/branch-setup.xml0000664000000000000000000001221612656574623016750 0ustar Setup ubuntu make trusty job using an ubuntu make branch false 100 branch git branch to test if not master, name the branch can take github url like: "https://github.com/ubuntu/ubuntu-make/tree/test_set_c", or "<repo> <branch>" like "https://github.com/ubuntu/ubuntu-make.git test_set_c" rebaseontrunk Rebase on trunk true true false false false false label ps-trusty-desktop-amd64-1 ps-trusty-desktop-i386-1 #!/bin/bash -eu CONFIG_PATH=/tmp/config # cleanup rm -rf ~/ubuntu-make* rm -rf ${CONFIG_PATH} # enable localhost ssh connection without pass ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys # add ppa for external content assets like jayatana sudo add-apt-repository -y ppa:ubuntu-desktop/ubuntu-make # add test packages sudo add-apt-repository -y ppa:ubuntu-desktop/ubuntu-make-builddeps sudo apt update sudo apt upgrade -y # install VCS and stats tools sudo apt install -y git sloccount # split branch name if github url given instead of "<repo> <branch>" repo=${branch%/tree/*} if [ "$repo" != "$branch" ]; then branch="${repo}.git ${branch##*/tree/}" fi # merge with trunk or clone from given branch cd ~ if [ "$rebaseontrunk" = true ]; then git config --global user.email "test@ubuntu.com" git config --global user.name "Ubuntu desktop" git clone https://github.com/ubuntu/ubuntu-make cd ubuntu-make git pull --no-edit $branch else git clone $branch ubuntu-make cd ubuntu-make fi UBUNTU_MAKE_VERSION=$(git rev-parse HEAD) # install deps from debian/control sudo apt install -y $(tests/daily_runs/get_binary_depends ubuntu-make) # install test packages sudo tests/daily_runs/install_build_tests_depends sudo addgroup $(whoami) docker # ensure docker is using the CI proxy sudo bash -c 'echo export http_proxy="http://squid.internal:3128" >> /etc/default/docker.io' sudo restart docker # config save mkdir ${CONFIG_PATH} cd ${CONFIG_PATH} echo -e "{\n 'target': 'trunk',\n 'version': '${UBUNTU_MAKE_VERSION}',\n 'date': {\n 'timestamp': '$(date +%s)',\n 'utc': '$(date -u)' },\n 'arch': '$(arch)'\n}" > ubuntu-make-version dpkg -l > packages_list target=branch tests, UNSTABLE_OR_BETTER false ps-trusty-desktop-revert-snapshot-daily FAILED true false ubuntu-make-16.02.1/tests/jenkins/system-setup.xml0000664000000000000000000001007712656574623017042 0ustar Setup udtc trusty job using system ubuntu make false 100 true false false false 02 3,9,15,21 * * * false label ps-trusty-desktop-amd64-1 ps-trusty-desktop-i386-1 #!/bin/bash -eu CONFIG_PATH=/tmp/config # cleanup rm -rf ~/ubuntu-make* rm -rf ${CONFIG_PATH} # enable localhost ssh connection without pass ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys # add ppa for external content assets like jayatana and Ubuntu Make source package sudo add-apt-repository -y ppa:ubuntu-desktop/ubuntu-make sudo sed -i 's/# deb-src/deb-src/' /etc/apt/sources.list.d/ubuntu-desktop-ubuntu-make-trusty.list # add test packages sudo add-apt-repository -y ppa:ubuntu-desktop/ubuntu-make-builddeps sudo apt update sudo apt upgrade -y # install source and stats tools sudo apt install -y dpkg-dev sloccount # install latest system version sudo apt install -y ubuntu-make cd ~ apt-get source ubuntu-make mv ubuntu-make-* ubuntu-make cd ubuntu-make mv umake umakelocal # get umake dir out of the way for coverage report UBUNTU_MAKE_VERSION=$(dpkg-parsechangelog --show-field Version) # install test packages sudo tests/daily_runs/install_build_tests_depends sudo addgroup $(whoami) docker # ensure docker is using the CI proxy sudo bash -c 'echo export http_proxy="http://squid.internal:3128" >> /etc/default/docker.io' sudo restart docker # config save mkdir ${CONFIG_PATH} cd ${CONFIG_PATH} echo -e "{\n 'version': '${UBUNTU_MAKE_VERSION}',\n 'date': {\n 'timestamp': '$(date +%s)',\n 'utc': '$(date -u)' },\n 'arch': '$(arch)'\n}" > ubuntu-make-version dpkg -l > packages_list target=system tests, UNSTABLE_OR_BETTER false ps-trusty-desktop-revert-snapshot-daily FAILED true false ubuntu-make-16.02.1/tests/jenkins/trunk-setup.xml0000664000000000000000000000744612656574623016667 0ustar Setup ubuntu make trusty job using ubuntu make trunk false 100 true false false false 2 */6 * * * false label ps-trusty-desktop-amd64-1 ps-trusty-desktop-i386-1 #!/bin/bash -eu CONFIG_PATH=/tmp/config # cleanup rm -rf ~/ubuntu-make* rm -rf ${CONFIG_PATH} # add ppa for external content assets like jayatana sudo add-apt-repository -y ppa:ubuntu-desktop/ubuntu-make # add test packages sudo add-apt-repository -y ppa:ubuntu-desktop/ubuntu-make-builddeps sudo apt update sudo apt upgrade -y # install VCS and stats tools sudo apt install -y git sloccount # clone from trunk cd ~ git clone https://github.com/ubuntu/ubuntu-make cd ubuntu-make UBUNTU_MAKE_VERSION=$(git rev-parse HEAD) # install deps from debian/control sudo apt install -y $(tests/daily_runs/get_binary_depends ubuntu-make) # install test packages sudo tests/daily_runs/install_build_tests_depends sudo addgroup $(whoami) docker # ensure docker is using the CI proxy sudo bash -c 'echo export http_proxy="http://squid.internal:3128" >> /etc/default/docker.io' sudo restart docker # config save mkdir ${CONFIG_PATH} cd ${CONFIG_PATH} echo -e "{\n 'target': 'trunk',\n 'version': '${UBUNTU_MAKE_VERSION}',\n 'date': {\n 'timestamp': '$(date +%s)',\n 'utc': '$(date -u)' },\n 'arch': &apoapos;$(arch)'\n}" > ubuntu-make-version dpkg -l > packages_list target=trunk tests, UNSTABLE_OR_BETTER false ps-trusty-desktop-revert-snapshot-daily FAILED true false ubuntu-make-16.02.1/tests/jenkins/ps-trusty-desktop-update-daily.xml0000664000000000000000000000313712656574623022400 0ustar false 100 true false false false false label ps-trusty-desktop-amd64-1 ps-trusty-desktop-i386-1 #!/bin/bash set -ex sudo apt-get update || sudo apt-get update || sudo apt-get update sudo apt-get dist-upgrade -y --force-yes || sudo apt-get dist-upgrade -y --force-yes || sudo apt-get dist-upgrade -y --force-yes sudo apt-get install -f -y --force-yes || sudo apt-get install -f -y --force-yes || sudo apt-get install -f -y --force-yes sudo apt-get dist-upgrade -y --force-yes || sudo apt-get dist-upgrade -y --force-yes || sudo apt-get dist-upgrade -y --force-yes false ubuntu-make-16.02.1/tests/data/0000775000000000000000000000000012656574623013101 5ustar ubuntu-make-16.02.1/tests/data/developer.android.com.pem0000664000000000000000000000574212656574623017775 0ustar -----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDTn09HkbU3LVMU JozYQigCHsv3FtjhiPrxx3JPchc+A7suLL+hXJdHInIAh2mrAxRHKculeR526zvT r3Gqmh0ckC3RbaUDCrT92l4GCEoBipBwA5mdD92IM9UVgIPLem4WlE/XAMhq6Hxp Wt3Wllojo0zt9PAgaQcxp6dHvZqAzBhLvkxzC6no2U8rp450KkxnOE5D7dpHNKHp 8CgBWlvwkryL4zMuz+ZSdckWxYs+ykQHQwnuDHnFyKI/VMvdUydvmxWCzuU7s68V ESJC7BystgpMGkMsaGEYFkMO6nEztc0k8gqIi5Z2LwOXrT3hRdPSVHHuqp/saCMP ITiItBRZAgMBAAECggEBAKxd4jElGTksDbMoAyhSGkw/0VocneJ1tBAip5TWFOBK Ibfmct93jzA9eiW8JfFIvMeJ33mUQaAS0dQF3staY8PUG72tVO45Vlo99r9rGPxQ ZH0YMZKgTYyWy0SMPM0Ll4eEndM9rACIBG27uV0Dcb/9Trey/bMoWNe0+qeQY7vr BMLZz90zcFgLuRL5errPIvYCpiz22HQxXFo1+KlkXtCtwAyKpJ2Lu5ey9u04Ugng gCzsDPix1u5yYbcSEMfbKCeyMQEEiXahaLbk2I/U8CuHrZxkBTArl8xunRcAqqNk kO/MhNTTQO1c/dKB6KQJ/TqCz6AjhzT6D47HT2G3wJECgYEA+3J8K+I+4o6kuVDi jgHlApSuUyaDjCIdrwE26ujOOisjTDqB/p/vyJcZXOzYlxe1d0dNcxvkLwqk3jH8 f/jCCMy3d+xvmf8pME7be3N7TpBAluA4/5GaByVly0igkNUREVQrEugimgpn3BX6 kOhvX0tbzO/pvyhX62NyKPhUSTsCgYEA13Q6JzUvKXobVbs4V50POLmEL8s6vkZ/ g5JeaVrINncC+S3b0aEd9RXa7FhaQ2NS1BcWoftjSDd1tzsUKIxTCvDM0pNB1fRN a0NzBXUA94tvNfosVvDDJgTYIadCyjtjeIThpes5Zzrto8ckeX5+Ze0o+dj3cC1a m37+DAKYX3sCgYEAw+JBR7KeSMLVIqUXiYeCT8tiLtbPHikptL8eeExa9EfM3MKr qKASHdNQZ+r/JF3M+ZorhOQSlG8XVx3b1hoFlvNcbmlb271C6iZUp8ykH+US3Dbb UIWuV6jTr1Tp+UpzXGuUjssWwagflv3sUF0y/irn3jR8hXW5YF/9fFtQ1icCgYEA zRyKLD9Wib8EfOaCae5MymzaqgFpCDHnPSPAG75gMnG0c/IzfetLsMJAq5YlQFgz R1Q/qK/BQcQCnhBxTXThrd22sJWeLIiql34b50sPQ5sLobBsO8xzjCM6ezdXv10w glDG3QUFngAcsjlowP0qafCQfOMQFUwoITaRtm9WDjcCgYBAzawqKntYEavAYnMW 12O4f2Ms3g0xcyLqj3OcCUlhe9tqT20EDe/FGmTZYDhDqTQYjqHOCxhI5cNq49/n GO6MU4Gd3gfL27NjqIfiMEWwqWcLeeUEBQGmNN5XMLZ5+Ro2koyLrO7SJpmB5VRn 0v6kiANcQGQ6wXdH9XfSXq5jQg== -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDqzCCApOgAwIBAgIJANM5Fcvms7E/MA0GCSqGSIb3DQEBCwUAMGwxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSgwJgYDVQQKDB9BbmRyb2lkIGRl dmVsb3BlciBrZXkgZm9yIHRlc3RzMR4wHAYDVQQDDBVkZXZlbG9wZXIuYW5kcm9p ZC5jb20wHhcNMTQwODI4MDgyMzQyWhcNMjQwNzA2MDgyMzQyWjBsMQswCQYDVQQG EwJGUjETMBEGA1UECAwKU29tZS1TdGF0ZTEoMCYGA1UECgwfQW5kcm9pZCBkZXZl bG9wZXIga2V5IGZvciB0ZXN0czEeMBwGA1UEAwwVZGV2ZWxvcGVyLmFuZHJvaWQu Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA059PR5G1Ny1TFCaM 2EIoAh7L9xbY4Yj68cdyT3IXPgO7Liy/oVyXRyJyAIdpqwMURynLpXkedus7069x qpodHJAt0W2lAwq0/dpeBghKAYqQcAOZnQ/diDPVFYCDy3puFpRP1wDIauh8aVrd 1pZaI6NM7fTwIGkHMaenR72agMwYS75Mcwup6NlPK6eOdCpMZzhOQ+3aRzSh6fAo AVpb8JK8i+MzLs/mUnXJFsWLPspEB0MJ7gx5xciiP1TL3VMnb5sVgs7lO7OvFREi QuwcrLYKTBpDLGhhGBZDDupxM7XNJPIKiIuWdi8Dl6094UXT0lRx7qqf7GgjDyE4 iLQUWQIDAQABo1AwTjAdBgNVHQ4EFgQUs7PCZ/tV4Cfh1/UD9uiuJLnOIS8wHwYD VR0jBBgwFoAUs7PCZ/tV4Cfh1/UD9uiuJLnOIS8wDAYDVR0TBAUwAwEB/zANBgkq hkiG9w0BAQsFAAOCAQEAGgmIDe7aBeSsqr92Sh/hh1aEKxXbPSVpcKc7u8PS0/Y6 SA/2NbduLod/rY3YYMQFmbuzACFFPngdyrT4vnQp7NuMv0BEGJeAWs8jLf31x7zT pCaE7aRr+v3m5PVE1T9r7xrpeUkuKUZdKpLb/zwQGHzTQh8hOwpHWkOeaPhbeyM3 9D3v1huHumwTevKlz8DstGT+cUtSzG8xFG/eCCJYts3NgCYAunwuMbt3hO4BoANf 4sdR/MUPXxL4gSL/W8cVqwoukx2TmjvBYLyChSGNK4PZ6nfCNLrtSkXE0oKxyaLp FB8jsk738QvcVJALvN5gHW6gVY6O5o66tcCc/CPN/A== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/localhost.pem0000664000000000000000000000513412656574623015577 0ustar -----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEA+5Z43eFs0XxUlrTV2Zr/TJRp+OmxWQnLWgYgMDKvcgEVacvS ntZTsCijWiGt2cgTxcYvV1zaQKQ+pzSOKV7EvO+s++Px4qwiINotZ9T1+ciWsTGe ToCONDCDtmdzWMazva3WTfltfxx4dnX8HIyNxR8CT3ZLDgfqcfIeaFzHoUrRGHga 56sWjxAbqLb9ZcBnabb7bdh6M/OJm0E5/A4IPZ9+Y1/fd0lBH/EdZ6e1VqSf2gPz luSqlUPRpwJNP7nMfImtYpqZyqE0dJit/SwcyvHi9e5Vyt+2aqmy9cNa4VpaKp5Q WnLzvHRbvIWu1z6BdxaM9DvjqNKuCvA5q5BSlwIDAQABAoIBABvRAUAXAn8O7hNT nylWF9ARwL3CqNcdXBxx/PEXSYqjUAjIflsNe2dItvbqLlyb4IPHa8iO/ZqUDlFS YD12uu3g2hFnnIDhY0yaktaeFyws32xr/gLT9+URUB7ExV4Vah4YsE8iutaJAVCn rt5BNBONYCYFADtm6Kb8jBwh1fihIup1RFMGXvB29Xfhp/7nHOGa7C7xxOcn4MEL uTrF6o1udVPcpvHYEZIu5X6XHkY1+ZpNKrsglGrkfT9Z2QUd7oDi1iIXCC73ZIkg QkLSokgDM+hIQBehTfEGsR7WhPDlDcRtMSXf2GeNSqnHakmGhD0uTKwgDnSP/XXK Xk1iSdECgYEA/zFBrKBLw2m7B1dAb2G39X/gxVGaKG98jEYfQflagOVpcyt3fvSc GzNtFoB8syiydiCjXjvlUUJUF6oxIDhz08hmWxMfed5e5uSAUy1iqAVhs98Xg5jF L/vVvDnQKVnPlP8pEm8B2uwR8ZRiAQYn3wrp6YTuu7ckXpW6D3FQuvMCgYEA/GJL md2R/TGzjcCkRqE2K16k5fypBVoGFB98MQPuw+xHL/M6LCJU2B5ii7DPHtICR6yP iR72CbWLmMh9gHGDCO0vA9hy6yPiFQRNXwNWPeq/mXNBpTCSBpkPYidLdIkYxdL1 StAPt9HO8LnEJQ6axsCX+cQRN1N1SYe7AHn2as0CgYA6xCkPi8pmsc50Hk+kVqh6 THyCdAxAC4xu8Sb5lmaVED98WiImhkX8rZcNe4E78L9IHLQCW2CvmcqruHGfreBe gOOxTXIOKntISI6UmPsDHlolhdZwY5nlNuU9d0LMgvYepbPbntyagYqQS09WVQiR gH3lXMttRvuFHI3ASKQCqQKBgHsc8+YFqG5LLVxLiZcOkt8LFwM9gbGjnW15glpi obke7Abe7hSTVrHp+IZN5GsTZJtT+NyZpslLruIDgv0B4jqbgKCumDhN074O0DM1 7H7doUMYbwBGtiTTyyZFJtCdA+GUK6Wn4tL3XKwe4ih1fFjRoBDtbLyBUKhitnzg Aa1NAoGAZn0OXRBnnFZuPy1Yic4c6H1gNUG8Kv5KTTuU6A6Cm/cPUqSUEB2Tcyka h/sB2fgyZsqHvp3rP4JJPyoJ42FFRJ7VpysfGFs7L1xzv2pCKbMe2DpUrX2ZHe8R Fhqr7W6RmX2YahR73rK3f5zqpzvMtkgyicAAs2lMjUowxvGcpMc= -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIICozCCAYugAwIBAgIBATANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDEwlsb2Nh bGhvc3QwIBcNMTQwOTE2MTk1NTAwWhgPOTk5OTEyMzEyMzU5NTlaMBQxEjAQBgNV BAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPuW eN3hbNF8VJa01dma/0yUafjpsVkJy1oGIDAyr3IBFWnL0p7WU7Aoo1ohrdnIE8XG L1dc2kCkPqc0jilexLzvrPvj8eKsIiDaLWfU9fnIlrExnk6AjjQwg7Znc1jGs72t 1k35bX8ceHZ1/ByMjcUfAk92Sw4H6nHyHmhcx6FK0Rh4GuerFo8QG6i2/WXAZ2m2 +23YejPziZtBOfwOCD2ffmNf33dJQR/xHWentVakn9oD85bkqpVD0acCTT+5zHyJ rWKamcqhNHSYrf0sHMrx4vXuVcrftmqpsvXDWuFaWiqeUFpy87x0W7yFrtc+gXcW jPQ746jSrgrwOauQUpcCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAa920hzrFFEBu yoqYxVjbQDw1iVECcCLiwoBPHspUlCWww3TFo04i1v5oa66ooOhupz8ClpzRyskp C69jZrQn8RnWBBRvkqsqpUK3lSv3ZDZtAZZT8BeoOc8GLF9FtLXdXcVdNiwGCFf/ A7cx+UKM0+7s61FcyC/+zwhAXTBpLP9V3KyhZsARWNr8GRxb9l8PincFo8F/Zop7 eu9HmUBY4XE9HhOZXKfiMJJG11BZaMu8iF3QcJJ4OEUfKOJzb1vEYZpBJbdxfd6e 0DrQMAwuOrFxGLE9+DeRJ8qtiip3r9aMKKNGr+oX6pDGX2teVUcetgkjuXS9Lw8s X8G2zxyT9A== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/github.com.crt0000664000000000000000000000240512656574623015653 0ustar -----BEGIN CERTIFICATE----- MIIDhzCCAm+gAwIBAgIJAPN26r3EAAhsMA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCmdpdGh1Yi5jb20wHhcNMTYwMTMxMTQx OTQxWhcNMjUxMjA5MTQxOTQxWjBaMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29t ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYD VQQDDApnaXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA r9oq9Rj3SYzmBCjZz7JwJnTwQbt9SXEwn3oL+RpqXQa3TXDbHPDorzf8vvco1ns8 A6+JmnMOiYvLBoTvI4fngjoI2fP+GpQOoQfsTaBuDQyzOsJv2E5cbOZQzSkcykro lx1Dwkqdy/2Bz25YtPX+PBi6xpVCLSBkad5iZW5+yd6mloG76610KoBRB0S+GCD6 aCVOHpeleZ5nJYHO6owAoGCndHoMR4MM60eHvB2qGgnoqd4WuEQZsrh2mqSfX0dH 9JJUHvBPLfz3Ex0uh69qoKRra2y/Nro6vdDzy50F2VCMs6Fru8un6y0RWBUXj2iP +uMY+bj3D1Jp+IdMTH6jAQIDAQABo1AwTjAdBgNVHQ4EFgQU6p1ApP9amffHE/US lXsqax3qhFIwHwYDVR0jBBgwFoAU6p1ApP9amffHE/USlXsqax3qhFIwDAYDVR0T BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAoPMNVOSchGgKjTjnQcBspTKN3jI6 We3k2DCBV8i2J03v9wy8QtslOfAwY7Mm8wJJDLjtZwmxNAGEWiabvbEs2aehL98O zWnXOxL4ZxIH4Mgld4L+ihml6n2yFpF8z66wx+x8NqG5tfpeVztgJMns4jmfE8Kg g1aZhPYjkvMRqcom/Lg+lSNh/7g4DUyx9gNikQUySDDKnrRu1qtrI+c+TsGBq45K uQnbCefDQdEc340P/GAqkBHbOdVOwGjnhlk8LyAjqse0YicLs7qnFojp55Cwn8Nd KI6aj9+JN/EYOnv0Q9ywUDCrRPs87QHudv81v2vscBnTzJu+ox8iUPorDQ== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/data.services.jetbrains.com.pem0000664000000000000000000000573212656574623021103 0ustar -----BEGIN PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDKSnFhK9DSmdtM 2TjG5KNmW0GWdrKAJsLx2/TZ2uQhzt5Mzj9gPus0Gb4XcBHPFty7ToGYCuulyoby 00NZVqfXxAW5ibSRFALraDQ4eZoqe+UlS5JS9ABKtzNSlWSj8dtChq8HJ2Z3yxSU h90Qua9GW/z7bvbETIw274OIjCHIflazWtT9+BFHTB1lEAG5f5oDZtfbyduGbzlI +M1/TOpw0yRpooJlwbW4ZKgGsrnkPnVC1MfGzPm7SgkVNQoWnamXY2gefaxKtBDA 67i1uUgPA0pDNisK0Wzbcb6nzyrFwymWGFj05iuBs5RYG9lmW4nzMLNnNEwKjdNS l/0Q8gVNAgMBAAECggEAS8/EWAdktlik4FMUPS3YsvaGSQ5o7TAZpSyqwa6QCr+N fjlZdQd/fEIdhIkik3rc9HGCjemh0LtrAbv9JJEeS/WRs6wQ+MIIKhMeZv/jsAJI qUZ+Kwp4xYeM+2kzk2GDq5XwKH0yoLiCGPwl9CuyrWqyD8TRRFXvwnLW16i0zH8p 25NlzyQFFiXTldifAWoAeCgUZWyePQj7lhTUth1UWldbEaziKx0HEz2znqa8SWkq SWEHW8rE+ohawr+JtRP93emIJlGd7kbstdyukVz2UBgdvOiDceyL7grg59nRcppg OtOCeWXVgoal1tzDkb4PFqUoOOOAjmXa/yOfTT7BPQKBgQDuam5c5ZeG9NPj87MX 9K9S6asZufuA5Qy3T9VvaTFNWOchJ9Cjpyyh85EYGVw/fMg2p73NCt0QE8hPQWYq WF45nTpcWpMcgdvW8j3M3psAir/8U+mu+XSAigeF5rbxX7dL70cm7GVWJWJ9OTmo mrSP7kchz7LAMWAgev0BRlynOwKBgQDZNe4nVP0iLxWYE7BkipHS/IBgtzL969Lh 3/OnLwIP2rs6imAACSAzq8LoXOGgT6lSD1hNpAkri6nR+flf1fPxqViwYLOui0RS uyR9OGFliM2JUIMA+kwCEJNEo6xdFSpdh5etlA3Q+AD+9xUHloeq6VdFwN4TyVog u3TvVlMNFwKBgFHmS80rrXbVyagnwiD7k/KmhHlM80Ge7VRXX1lrSF1qqdMw6zIc rm9fzTr7Ez5X7isgSkoSbkgkk43uSFtJiey+vxqUnq6PSWa4RlSHL7Xq8/KJHOBX nxa808LCs5uNJtk19DpBwLnsE74yl0T9CAPddZ/+ykfNblkaBqmWcyObAoGAOJ8y YdZp1ktn2ajoRo1IzjM8U/nttPuQkYkLvv0mEHP4cp43wEqgtleEC4aK2ntprBaL 8lFcgpl5v17mfvELEmgO0ouiy1FKkjZuoKXd3dX3nl/6hnq47aDcgvwXpnwp+w+p nnoFz/+WYuCN/thirU7+jRRlz8qhT/8N0IY0SCkCgYBNkU6BUAaWXID6RcgRjxFy /8vm+oUYJCJiaSFC8Jlr8oA6nFmtkCEhuNt3jUBCLe69qlCdjqji9gOe7oFtDVEd p0X70uqhfVNV3s9F/mOxoT2Xaga79vu+RRbxCG2VOHzAveQZAKZ/hbo/LJDJd/Mr ygAqsTq4unvzpkiliYFZyw== -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDqTCCApGgAwIBAgIJAPoNW2O3W47oMA0GCSqGSIb3DQEBCwUAMGsxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxJDAiBgNVBAMMG2RhdGEuc2VydmljZXMuamV0YnJhaW5z LmNvbTAeFw0xNTEyMTEwODUyNTFaFw0yNTEwMTkwODUyNTFaMGsxCzAJBgNVBAYT AkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn aXRzIFB0eSBMdGQxJDAiBgNVBAMMG2RhdGEuc2VydmljZXMuamV0YnJhaW5zLmNv bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMpKcWEr0NKZ20zZOMbk o2ZbQZZ2soAmwvHb9Nna5CHO3kzOP2A+6zQZvhdwEc8W3LtOgZgK66XKhvLTQ1lW p9fEBbmJtJEUAutoNDh5mip75SVLklL0AEq3M1KVZKPx20KGrwcnZnfLFJSH3RC5 r0Zb/Ptu9sRMjDbvg4iMIch+VrNa1P34EUdMHWUQAbl/mgNm19vJ24ZvOUj4zX9M 6nDTJGmigmXBtbhkqAayueQ+dULUx8bM+btKCRU1ChadqZdjaB59rEq0EMDruLW5 SA8DSkM2KwrRbNtxvqfPKsXDKZYYWPTmK4GzlFgb2WZbifMws2c0TAqN01KX/RDy BU0CAwEAAaNQME4wHQYDVR0OBBYEFMlFjpvuzTPurQ5jYRlAQbQdmkEBMB8GA1Ud IwQYMBaAFMlFjpvuzTPurQ5jYRlAQbQdmkEBMAwGA1UdEwQFMAMBAf8wDQYJKoZI hvcNAQELBQADggEBACqrK0PtcYKLppXmaAqv5xFghcvyH4OKSb3g+OS35CEwofNP +8dlFoCLcVCgLRcOzY3E49ky02dVmpjOg6GnK6A69gwzsw0WRRx8LzZB/hoT2fvi SDe+Z5cQ71xB9MyfUu44UQ4q8babtHwgPqcBgqT9ofp0qW0ofE2tnVzRMcc79gQE NpYnEBRn1R9k4kfRgJKk+9WuY0woNG9W+z2+ERcDit2hQeXsyLvgx58RF3tGEar9 m3sy2pBSjBaO/W5wq3P+bIIEyjqG1gWhAePG2j18hvu7/njP70oFhis2zOJRnkos oGBEZhjNDMRiW5qj1kjUgfxRqH/4U7taSYVzenA= -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/testframeworks/0000775000000000000000000000000012656574623016161 5ustar ubuntu-make-16.02.1/tests/data/testframeworks/category_f.py0000664000000000000000000000437612656574623020667 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with package requirements""" import umake.frameworks class CategoryF(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category F", description="Category F to test installed state") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A (impossible path)", category=category, install_path_dir="/foo/bar/baz") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework B", description="Description for framework B (good install dir, " "no package req)", category=category, install_path_dir="/") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkC(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework C", description="Description for framework C (good install dir, package req.)", category=category, install_path_dir="/", packages_requirements=["foo", "bar"]) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/testframeworks/othercategory.py0000664000000000000000000000343512656574623021417 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with another category module without any framework""" import umake.frameworks class BCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category/B", description="Category B description") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() @property def is_installed(self): return True class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework/B", description="Description for framework B", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() @property def is_installed(self): return True ubuntu-make-16.02.1/tests/data/testframeworks/baseinstallerfake.py0000664000000000000000000001165712656574623022224 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Base category module""" from contextlib import suppress from gettext import gettext as _ import logging import os import platform import re import umake.frameworks.baseinstaller from umake.tools import create_launcher, get_application_desktop_file, ChecksumType logger = logging.getLogger(__name__) _supported_archs = ['i386', 'amd64'] class BaseCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Base", description=_("Base category"), logo_path=None) def parse_license(self, tag, line, license_txt, in_license): """Parse Android download page for license""" if line.startswith(tag): in_license = True if in_license: if line.startswith(''): in_license = False else: license_txt.write(line) return in_license def parse_download_link(self, tag, line, in_download): """Parse Android download links, expect to find a md5sum and a url""" url, md5sum = (None, None) if tag in line: in_download = True if in_download: p = re.search(r'href="(.*)"', line) with suppress(AttributeError): url = p.group(1) p = re.search(r'(\w+)', line) with suppress(AttributeError): # ensure the size can match a md5 or sha1 checksum if len(p.group(1)) > 15: md5sum = p.group(1) if "" in line: in_download = False if url is None and md5sum is None: return (None, in_download) return ((url, md5sum), in_download) class BaseFramework(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Base Framework", description=_("Base Framework (default)"), is_category_default=True, category=category, only_on_archs=_supported_archs, expect_license=True, packages_requirements=["jayatana"], download_page="http://localhost:8765/index.html", checksum_type=ChecksumType.sha1, dir_to_decompress_in_tarball="base-framework-*", desktop_filename="base-framework.desktop", required_files_path=[os.path.join("bin", "studio.sh")]) arch = platform.machine() self.tag = 'id="linux-bundle64"' if arch == 'i686': self.tag = 'id="linux-bundle32"' def parse_license(self, line, license_txt, in_license): """Parse download page for license""" if line.startswith('

'): in_license = True if in_license: if line.startswith(''): in_license = False else: license_txt.write(line) return in_license def parse_download_link(self, line, in_download): """Parse download links, expect to find a md5sum and a url""" url, md5sum = (None, None) if self.tag in line: in_download = True if in_download: p = re.search(r'href="(.*)"', line) with suppress(AttributeError): url = p.group(1) p = re.search(r'(\w+)', line) with suppress(AttributeError): # ensure the size can match a md5 or sha1 checksum if len(p.group(1)) > 15: md5sum = p.group(1) if "" in line: in_download = False if url is None and md5sum is None: return (None, in_download) return ((url, md5sum), in_download) def post_install(self): """Create the launcher""" create_launcher(self.desktop_filename, get_application_desktop_file(name=_("Base Framework"), icon_path=os.path.join(self.install_path, "bin", "studio.png"), exec='"{}" %f'.format(os.path.join(self.install_path, "bin", "studio.sh")), comment=_("Base Framework developer environment"), categories="Development;IDE;", extra="StartupWMClass=jetbrains-base-framework")) ubuntu-make-16.02.1/tests/data/testframeworks/framework_for_removal.py0000664000000000000000000000450612656574623023130 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework only marked for removal""" import umake.frameworks class RCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category R", description="Only containing one framework for removal") class FrameworkRuninstalled(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework R uninstalled", description="For removal", only_for_removal=True, category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkRinstalled(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework R installed", description="For removal", only_for_removal=True, category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() @property def is_installed(self): return True class FrameworkRinstallednotinstallable(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework R installed not installable", description="For removal without only for removal", category=category) def setup(self, install_path=None, auto_accept_license=False): print("here") super().setup() def remove(self): super().remove() @property def is_installed(self): return True @property def is_installable(self): return False ubuntu-make-16.02.1/tests/data/testframeworks/restrictions.py0000664000000000000000000000443612656574623021272 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with another category module without any framework""" import umake.frameworks class DCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category D", description="Category D description (with restricted frameworks)") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A (restricted arch)", category=category, only_on_archs=["foo", "baz"]) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework B", description="Description for framework B (restricted version)", category=category, only_ubuntu_version=["9.10", "10.04"]) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkC(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework C", description="Description for framework C (restricted version and arch)", category=category, only_on_archs=["foo", "bar", "baz"], only_ubuntu_version=["9.10", "10.04", "10.10.10"]) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/testframeworks/category_g.py0000664000000000000000000000350712656574623020663 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with package requirements on Category""" import umake.frameworks class CategoryG(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category G", description="Category G to test installed state", packages_requirements=["baz"]) class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A (with add req.)", category=category, install_path_dir="/", packages_requirements=["buz", "biz"]) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework B", description="Description for framework B (with no req.)", category=category, install_path_dir="/") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/testframeworks/uninstantiableframework.py0000664000000000000000000000302712656574623023473 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with another category module without any framework""" import umake.frameworks class Uninstantiable(umake.frameworks.BaseFramework): def __new__(cls, *args, **kwargs): "This class is not meant to be instantiated, so __new__ returns None." if cls == Uninstantiable: return None return super().__new__(cls) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class InheritedFromUninstantiable(Uninstantiable): def __init__(self, category): super().__init__(name="Inherited From Uninstantiable", description="Framework Inheriting Uninstantiable", category=category) ubuntu-make-16.02.1/tests/data/testframeworks/is_installable.py0000664000000000000000000000523612656574623021526 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with another category module without any framework""" import umake.frameworks class ECategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category E", description="Category E description") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A (installable chained to parent)", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() @property def is_installable(self): return super().is_installable class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework B", description="Description for framework B (installable forced to True even " "with archs restrictions)", category=category, only_on_archs=["archswhichdontexist"], only_ubuntu_version=["versionwhichdontexist"]) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() @property def is_installable(self): """overridden to say True""" return True class FrameworkC(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework C", description="Description for framework C (installable forced to False " "even with no restriction", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() @property def is_installable(self): """overridden to say False""" return False ubuntu-make-16.02.1/tests/data/testframeworks/withcategory.py0000664000000000000000000000332612656574623021250 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with category module""" import umake.frameworks class ACategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category A", description="Category A description") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A", is_category_default=True, category=category, install_path_dir="custom/frameworka") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework/B", description="Description for framework B", category=category, expect_license=True) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/testframeworks/oneframeworkcategory.py0000664000000000000000000000254012656574623022771 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """One framework with category module""" import umake.frameworks class OneFrameworkCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="One framework category", description="Category with one framework") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A", category=category, install_path_dir="custom/frameworka") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/testframeworks/emptycategory.py0000664000000000000000000000170712656574623021434 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with an empty category""" import umake.frameworks class EmptyCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Empty category", description="Category which has no frameworks") ubuntu-make-16.02.1/tests/data/testframeworks/__init__.py0000664000000000000000000000000012656574623020260 0ustar ubuntu-make-16.02.1/tests/data/testframeworks/anotherothercategory.py0000664000000000000000000000347212656574623023001 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with another category module without any framework""" import umake.frameworks class CCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category/C", description="Category C description") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A (not installed)", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() @property def is_installed(self): return False class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework/B", description="Description for framework B (installed)", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() @property def is_installed(self): return True ubuntu-make-16.02.1/tests/data/testframeworks/withoutcategory.py0000664000000000000000000000307412656574623022000 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with category module""" import umake.frameworks class FrameworkFreeA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework Free A", description="Description for framework A in no category", category=category, install_path_dir="custom/frameworka") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkFreeB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework Free / B", description="Description for framework B in no category", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/code.visualstudio.com.pem0000664000000000000000000000602712656574623020032 0ustar -----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDSiDmIjpkJEwAH Kq8DsV2wX13D5ld745XZ3pT/o3Jonge7EuJHYzTwATNYkERRhJ6QTR+1VP6Gq+gV 1g0tdB0pCtXGzj6McYDoQi8y/h1PaldxL5xb9vpCHUfKO0GjyPCpZe7p/lMGJnC0 yJJ6EM5AhLfj6gnQFhaei0pVgeLuA7CmI5aOmNY8mzqdj5mbktrlJhJG0jLUuh0y XW8IxgYOQAECeke5pis9sXhF0qYmEsyABrRHi9NKj/LPMuKzLiRWkO4/znmmzc3D NRwGD69iEokasXoohe9jaUcMdwY+/oHGJXonSxQ5P05MocGbmTYicD+R2Ft/Lyag eZlzrBj5AgMBAAECggEBAML2+mi2vYwEt2rroUXHNB8IQdoP7wZA3V303YDbyTCO 4FPjCf/YJIb6ZaVnfI0NRpYVhf60Jj1q5zOJlYx5UiPW79/60TvYROtRl0oev9/y d+XOlHsp/dnKKdhjBcd6ZzxItHanWhWA9bDFabh25boj7fO3oby9J9dM4NrMvO1y eMW2XHYjm8l+s8mqYyv0PD2milBCH7ofii/wSf2iH9sKf0Mix7BUsVSEueVIc0dV WvQ9x+GJuFl8Czdk14r20LQRQP/JcAFTymPwp0r0ZeKjlPQk71p+DK+eho8QpDXv 680LmBXTTX7wf2SqVetydsIPaUkoAG122y+XdsOwoR0CgYEA9NQea2eKPwKz7W3w d4Fe//yUDdEI0tc/muUHylg/UUvCjvZ86sU9E/qGzqBU2j1ioRf/hIP0pp1zIcZ9 HjXlS4r6unIwuqmH3hQSFxnXCZsMHLqPTNaB383rzBPlNMXrrv/QLr6ZzLkEd66h PzkmeeKgJMSDcB4fH+2mXf06hP8CgYEA3CN7ywqTf7BWQdM9kuAvbOA7bbxqqpGy Y5AXm7JpRBgJG/2uiDCN+9O4ZaruZ4paJzCiDrFf0RnE1BcdU3qsC4fqhqAL3UWh kjqzU9YdltY5oOEUuB+KX1uavHvcaOZeLBJiNsoHCBxGGWfdLRdtiJi4l3Pfj7OF VBX+bZ+figcCgYBTX8EUNmhf2N3JJz1SlR3y8uLAacUld+PTLdefUroNR010PgCA Orb4DMLHrtX2lBz4WyHK0N0JuGiywdNt7FCvjx6fS6/IgV8hg5g9gbE3NjPDvMx8 EDieLJP2JXhSpmwCZl9Q69uYWhFpaHDFBQNTUpfSrZFNJxTWXKnhLBE3pQKBgEaQ 2U3sxftYe03+eO5sDsfH2UUD8O1cZuKjfe3a8wNw8PqYByqA5gKji6iLcoCeSOfn Hwu2sBBHQmD6R9xKpnvLxdIB28vCVliZmIJ3UGTZpv97JzkeYyzOIHvq+Gxn7CgU fIczm61t4sqiELQznlj7G7Dw4+kcktCxfC2HzYxhAoGAcVdRQyuuJEXt8H7Mrzim ZZB2JRF+pfvOMZM77iYWmqmYHQKS01a5aogIBlyzuWpG4M9AHmtZkxrnnUjd1aW/ 5etGiuPPwX7G1wEm94WPFU9RSbjh5KyQVa4Pi6u649JgFYCWLDbI3yEw6JQ0aH0w nG2V4ze93qjRrzUA0zwzkH8= -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIID1zCCAr+gAwIBAgIJALcOyQpcVt+2MA0GCSqGSIb3DQEBCwUAMIGBMQswCQYD VQQGEwJGUjETMBEGA1UECAwKU29tZS1TdGF0ZTE9MDsGA1UECgw0TW9jayBjZXJ0 aWZpY2F0ZSBmb3IgVmlzdWFsIFN0dWRpbyBDb2RlIG1lZGl1bSB0ZXN0czEeMBwG A1UEAwwVY29kZS52aXN1YWxzdHVkaW8uY29tMB4XDTE1MDQzMDA3NDUxMloXDTI1 MDMwODA3NDUxMlowgYExCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRl MT0wOwYDVQQKDDRNb2NrIGNlcnRpZmljYXRlIGZvciBWaXN1YWwgU3R1ZGlvIENv ZGUgbWVkaXVtIHRlc3RzMR4wHAYDVQQDDBVjb2RlLnZpc3VhbHN0dWRpby5jb20w ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSiDmIjpkJEwAHKq8DsV2w X13D5ld745XZ3pT/o3Jonge7EuJHYzTwATNYkERRhJ6QTR+1VP6Gq+gV1g0tdB0p CtXGzj6McYDoQi8y/h1PaldxL5xb9vpCHUfKO0GjyPCpZe7p/lMGJnC0yJJ6EM5A hLfj6gnQFhaei0pVgeLuA7CmI5aOmNY8mzqdj5mbktrlJhJG0jLUuh0yXW8IxgYO QAECeke5pis9sXhF0qYmEsyABrRHi9NKj/LPMuKzLiRWkO4/znmmzc3DNRwGD69i EokasXoohe9jaUcMdwY+/oHGJXonSxQ5P05MocGbmTYicD+R2Ft/LyageZlzrBj5 AgMBAAGjUDBOMB0GA1UdDgQWBBQmVWhkaDF6PHbXnDGNICP8aACkNzAfBgNVHSME GDAWgBQmVWhkaDF6PHbXnDGNICP8aACkNzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 DQEBCwUAA4IBAQAHmQQXMs09tDQjvPdO9i82JZ/BduBFI0FuZV/GQs2zcfF3EmLC USwXttKT7pUtL0HuO40wfwHuTl9P+bNsacpeAMG80ND437b7+o34BfAd4EqzP6mO JSZ0wCqsNvRI7H7BpsXjdO5H3DZgv6Sqcr6ibwWpRyspl70NnTzM/sjvARMrzX21 2feKEhS/MsuE0phNh9WKipGymqALFgwuVw5a+E5TSs8X/9is+YW7fpQ1y2Hrf/3T NQF4FQ41730cHEiaO/5WK6wypi55p62hyEdjlgvfdOLdxw20mu76BtX6m4S5+a5C bGBvmiSFeRyk0EXCTDYc/LYOe3WW/qWdQsnb -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/overlayframeworks/0000775000000000000000000000000012656574623016663 5ustar ubuntu-make-16.02.1/tests/data/overlayframeworks/duplicatedcategory.py0000664000000000000000000000340412656574623023112 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with category module""" import umake.frameworks class ACategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category A", description="Category A description, same prog_name") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A from overlay", description="Description for framework A from overlay", is_category_default=True, category=category, install_path_dir="custom/frameworka") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework/B", description="Description for framework B", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/overlayframeworks/withcategory.py0000664000000000000000000000331112656574623021744 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with category module""" import umake.frameworks class ACategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category A overlay", description="Category A description") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A", is_category_default=True, category=category, install_path_dir="custom/frameworka") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework/B", description="Description for framework B", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/overlayframeworks/overlayframeworks.py0000664000000000000000000000331112656574623023015 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with category module""" import umake.frameworks class ACategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category A overlay", description="Category A description") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A", is_category_default=True, category=category, install_path_dir="custom/frameworka") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework/B", description="Description for framework B", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/overlayframeworks/duplicatedcategory2.py0000664000000000000000000000341012656574623023171 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with category module""" import umake.frameworks class ACategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category A", description="Category A description, same prog_name") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A from overlay 2", description="Description for framework A from overlay 2", is_category_default=True, category=category, install_path_dir="custom/frameworka") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework/B", description="Description for framework B", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/overlayframeworks/withcategory2.py0000664000000000000000000000331312656574623022030 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with category module""" import umake.frameworks class ACategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category A2 overlay", description="Category A2 description") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A", is_category_default=True, category=category, install_path_dir="custom/frameworka") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework/B", description="Description for framework B", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/multipledefaultsframeworks/0000775000000000000000000000000012656574623020565 5ustar ubuntu-make-16.02.1/tests/data/multipledefaultsframeworks/defaultframeworkformain.py0000664000000000000000000000234212656574623026056 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Try to get a reject to set a framework as default for main category""" import umake.frameworks class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A", is_category_default=True, category=category, install_path_dir="custom/frameworka") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/multipledefaultsframeworks/__init__.py0000664000000000000000000000000012656574623022664 0ustar ubuntu-make-16.02.1/tests/data/multipledefaultsframeworks/twodefaultscategory.py0000664000000000000000000000334312656574623025241 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with two defaults frameworks""" import umake.frameworks class ACategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category A", description="Category A description") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A", is_category_default=True, category=category, install_path_dir="custom/frameworka") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework B", description="Description for framework B", is_category_default=True, category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/duplicatedframeworks/0000775000000000000000000000000012656574623017320 5ustar ubuntu-make-16.02.1/tests/data/duplicatedframeworks/samecategory.py0000664000000000000000000000324512656574623022361 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with another category module without any framework""" import umake.frameworks class ACategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category A", description="Other category A description") class FrameworkC(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework C", description="Description for framework C", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkD(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework D", description="Description for framework D", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/duplicatedframeworks/category.py0000664000000000000000000000326212656574623021512 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with category module""" import umake.frameworks class ACategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category A", description="Category A description") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A", category=category, install_path_dir="custom/frameworka") def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() class FrameworkB(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for duplicated framework A", category=category) def setup(self, install_path=None, auto_accept_license=False): super().setup() def remove(self): super().remove() ubuntu-make-16.02.1/tests/data/duplicatedframeworks/__init__.py0000664000000000000000000000000012656574623021417 0ustar ubuntu-make-16.02.1/tests/data/www.eclipse.org.pem0000664000000000000000000000563512656574623016652 0ustar -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCgEa3kHNJD/cha wLdb0a8neaxMJpapWgY5O/CkevkT3b9W6/PWk+mQhpbvpxFDl5FfCLJ1Mh98HHI2 48HuHl4xYiOjfFhrnGopa8XmH+K7Va8zccDtgcpzYoj/YuV7y+x9m1vz0aJu8k1J LgV31s/zT+5MCpHoqheiwDSOAMV9WphAQzlN9uyo1h7bm3+37M+0vb4HRS9AoRMZ OIallN0Br2o4y1ab4K0k5rCqbHdkNMJ+yzzpcsB5tuQSd2xIkhQKxWSRSnGv1GBL h6E63tX9/nzwWlusQnm51f7Dt6OGT8ajs2HIlPVWKG/fI+cYru90oAClG50vgKDR m1SyjEwnAgMBAAECggEBAJhN+h1w5wjWswrXECCHtZdkCHM0zGo7RGy1AdYfRFyI xATa4dqsRrLDvV4uoxijYSkBx3wHwzl+f5aGxAHkV0+5x5tJN4C9Ba5/43+Bm2UQ tHHIrP/QXWfIu/30hdJzSISDjMzEDUBvwOX+qilK9fbXeTBVZlvxbCfpppfvV/pa 9bZb2Bter3J/FezNjSYnZyj7GqfG5kwHD+inAc8EtxGLA6qEAatTZeIKzB/Wvtxj Mlh8gMENx4tiNb2AUZ6gXcy1pT/FNdMYTsG/eY8PZln8oqC1lK5V39Y1a942e9jc 8GSpZbR9vrh+Fo4mrmYcKpLnM1rnoB1XZQ5omcuXbCECgYEA0rGSfb/sGn0vVaiu Lc4Fz6UJbBt5iaC0W9zPP2r+2JNowjXWcdeMqX6CQjUjJ1J8uU9eD7SDawivnWj3 TNnrFU1JlhIrviAbySOUb6ypOOQwVgZUeA962nl2N1hpmTnlsYQE6pK8bnsRp0i0 YduNX7eCWWAGpXtQQgkVL3zUTCkCgYEAwn1JHL1IesmyOtfS4cHhoAUN156ogUwF ypb0X3/bbgj/SuNjU3+gEIjnscygtEA/mVdNWNTxIzye7i9utBDals4nTYBZgf4Q QZe0SVCgJjq+DGNiQvA/O/OTIMsrxuRGgkDSEMhqnS36/pBBkkYpFnzTzCjuh4Jv NGrIzHGT388CgYAFE4gvBW+/16JLUwwXSG51aUmH1EWiXj/aMsC/i2lmeG6+tyNa jNHzx3uF8tfM+7zLjjD6+eNsscHhbgT/UgTK95i9R+TL6OQifXv3ENbm6wCLIg3o 8p6IIwMJJFUu/ukc1Mx1hmGJ2+c5+5N1BCAs3TQDyT9/vy/Y13UuNri6uQKBgQCU bck+hbaq/wNmpQ/r+2uWFEVcKVmwU7SXyFz4BTwR3gv3u1Iyh1RBSjqJFwIOjnn7 LQV6pgjiO4GPheOWyMYKEYstOqcU7jC53m1ZBo8yneIs0ixLqc6YkmvWuzfNsqmc /ptS86FqE41aef2RBLqWzu1VAmgIQyNbfaOBY6zXQQKBgF0/wNhHqPHIlycK5zh7 j2vwc0oRyQ+Ok+csAW7RW14RxpOz3M3so85fvnhkLrKGeun72VOSexMgGIGYzYBj Ego23PQzhK1KdDnDVx3M1Z75dYeOaera89pZG9Mu+/ehgSRZ8kYzQ2rkHfKhBg0W jH16B82QvFjSzLT4y6GsNL/G -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDfTCCAmWgAwIBAgIJAM20ZMP9aWmfMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMRcwFQYDVQQKDA5FY2xpcHNlIHNl cnZlcjEYMBYGA1UEAwwPd3d3LmVjbGlwc2Uub3JnMB4XDTE0MTAyMzEzNDA1N1oX DTI0MDgzMTEzNDA1N1owVTELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3Rh dGUxFzAVBgNVBAoMDkVjbGlwc2Ugc2VydmVyMRgwFgYDVQQDDA93d3cuZWNsaXBz ZS5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgEa3kHNJD/cha wLdb0a8neaxMJpapWgY5O/CkevkT3b9W6/PWk+mQhpbvpxFDl5FfCLJ1Mh98HHI2 48HuHl4xYiOjfFhrnGopa8XmH+K7Va8zccDtgcpzYoj/YuV7y+x9m1vz0aJu8k1J LgV31s/zT+5MCpHoqheiwDSOAMV9WphAQzlN9uyo1h7bm3+37M+0vb4HRS9AoRMZ OIallN0Br2o4y1ab4K0k5rCqbHdkNMJ+yzzpcsB5tuQSd2xIkhQKxWSRSnGv1GBL h6E63tX9/nzwWlusQnm51f7Dt6OGT8ajs2HIlPVWKG/fI+cYru90oAClG50vgKDR m1SyjEwnAgMBAAGjUDBOMB0GA1UdDgQWBBTmUq4DtfLPIe9T8TwZoLM8waKw7jAf BgNVHSMEGDAWgBTmUq4DtfLPIe9T8TwZoLM8waKw7jAMBgNVHRMEBTADAQH/MA0G CSqGSIb3DQEBCwUAA4IBAQA+rB/ZJ3qNVGK9TgTZ7HoJbyavy0swtX61w3zeoKPt 303xXLW+VopIJPvWgIokVRgkTRV3TELZf4zd9HL1dOndDXhOFJSvyn5ZDZ3H3r2+ Lll+wnHlSEP4XYGoVbjcFx4BwYSIx0Q5KwClkSET/iRr++KOISEbqJ99grv6mPl5 ZcT7wybh/+sRK1JTuvMAeBWRdTIrHbEAbAK6PzghAxQG8fTSYBc5rZ5utP9naXaa rNQT6Wgr+KAW9NQP3LD0fwhzZWa7NZHT6k4v65QVSP53C/JAUoAzA7TwG8VzrU5G gthhvU3VeSKRGCa8DrFkK7JkOvK37NitkOPfVoBUd5Vw -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/storage.googleapis.com.pem0000664000000000000000000000572212656574623020163 0ustar -----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDZBLCOahdyUiWF ZfStskHKEKymvGZa7ynWyJxlreM/ldEyuMcLIrBkOyMyY1VAJK6EkKlRSJkpLsmM oYN59uH6BCgKbZvbDMJoHR8C9pUvnuaHM8Mg3AP53+tz1yTGIKyKbm/rrrtlVAWU cTj0VjobYu+dQE6EmGJvPXRx+24dDpYZ1Ox8XrdzzM18gjrUDmwqO7c9bZoNPhQE igTbIapf+iW3MkrA5ue3J29Cs46kGOnX+YNU1p2Exh6w//vUDB38RUJRxVakVpJf S2SRv7PJYjbodN80cwFw/6DeRqptsV9AHin/OrBlbzn/kq+qWXOPjia2QZkUOiL2 C/zPV8WJAgMBAAECggEBAJ2Fy+nzlAVFHzsO4GVb6GkVZVy5j8odo07l2q/rYfH7 exfIC6JHkaWPT2L5ux2OAqbyohQAEDxWW7GaYuaajzh839uB6Ak937bWvHXYKj2g p1AoAFDPooszP6Kb3XN6sALjWpXGBPvt2wb+kAq6s/7A95A650NToM+B2g4KJMkt QH4yr5kQ2uDr0mNSNMmr3hKRuVjk87N6jA/8oERRwj3hzoB5qIr0D2hcF636NJxd rU/F7cX3tNMdp9OHfyqG9ZveGPI/npB/27GsPg1/ZdIvhH/lsvDEGkmx5qdduXQa 3aMjfXN30vJv7St1oxC36I4X3XYPs9nPz+Fu08IiVAECgYEA+fPep18WLMXWNGHo QC/aecJ1qshc8DK12zRtSSS9daEFGLRlTx01hOf+hhTLwfxKhpxwt06MJPUfmkK9 vJOx+4avbmuMgos/w14MC6jPiZ5BIbaZzhzm5/Vo7QAjPFSM7L5xDV372ZQrmC84 5kBA9LMkVvOSmXRb1IdjQJFTAkkCgYEA3kTVvrpTOtGTFhboE0+iQlcoEYt+ZpUA UaP4GCbKSne/lqiVax7D+46CNkOgQQieXU4YER0GfK3RGg2AlUfU7g9m8HkzG+Mc JWRVL+SoSuE2QAYzF/IQiJzbOrNq7MJWHAvxilU1SkAIfbT/VLrbTPEZA/Y7hZhh DBe4zFayqUECgYEAz4TcR6NXWsbKB+V9mMTiI5MCdE8zciz39U16qm55ac7M12z2 a4+5nmWqWJGtdZnMGiSKJHZvPkPRABcHRihtbYGt5wQdvUh1IPPVFl0KKZydQKtE 2O3/+3cxrQsfNfiQpAGdBNcRwNwWsZwLJocUJtUQh6xj+0my8CmTisjc3RkCgYAJ XSsIGv9wpe2la5ehYKR8WQGmI5NSrQpTZi4IjnHNS1g196o71hL5oRpZQOYad0t8 sNKQvgFM9WGu0EzPfTQ6R0nV7bU6gonoBV8VYnO4m95WOiyi4J7TspAF3BMwIEvS aKpnYomZNDNnYF21ax3cEvgz04bUbQQBp2owqaJjQQKBgQDRgvhjtknvb43SoVBg snEZ27iVuMV5rtLca4rY9sSMaziiAx+xk4OWWyrtgq10GC0BgjjbxuRrpiFPf5X0 CVgqEHyiBcPEM/uTJFanL14vV+Ve5NXXF89AZsw2h3rd4jp1btOKoJfqZFkKQ6nb YCxWJ3ue//bLmESPTval4xPCSQ== -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDnzCCAoegAwIBAgIJANR5WAxHskyBMA0GCSqGSIb3DQEBCwUAMGYxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxHzAdBgNVBAMMFnN0b3JhZ2UuZ29vZ2xlYXBpcy5jb20w HhcNMTUwOTMwMTQyMzA2WhcNMjUwODA4MTQyMzA2WjBmMQswCQYDVQQGEwJGUjET MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ dHkgTHRkMR8wHQYDVQQDDBZzdG9yYWdlLmdvb2dsZWFwaXMuY29tMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2QSwjmoXclIlhWX0rbJByhCsprxmWu8p 1sicZa3jP5XRMrjHCyKwZDsjMmNVQCSuhJCpUUiZKS7JjKGDefbh+gQoCm2b2wzC aB0fAvaVL57mhzPDINwD+d/rc9ckxiCsim5v6667ZVQFlHE49FY6G2LvnUBOhJhi bz10cftuHQ6WGdTsfF63c8zNfII61A5sKju3PW2aDT4UBIoE2yGqX/oltzJKwObn tydvQrOOpBjp1/mDVNadhMYesP/71Awd/EVCUcVWpFaSX0tkkb+zyWI26HTfNHMB cP+g3kaqbbFfQB4p/zqwZW85/5Kvqllzj44mtkGZFDoi9gv8z1fFiQIDAQABo1Aw TjAdBgNVHQ4EFgQU20v78UMwwLEe2B7OnXlWjeYeBKkwHwYDVR0jBBgwFoAU20v7 8UMwwLEe2B7OnXlWjeYeBKkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC AQEAiIA9TlycwXcIPGSw72QMmlZesazTKPCImLWNWWh/WPU4y0lXcPXB4aKo1G3N jksK4wBITBpXuFU4aZolqxS6NoZEdyjHd4V9oPDGl4ZtwVas35P6ehnhHzhu1Tld QKynp+4e2V3tv4tcc4nnxDN4SXBNlMKIfJ6CaTbo0GlzJHNHBWlIIDdG2TjM3axP o996KFvAQkdq3WqWzmoNXOGS1Bkd52fJgtqr+mWNNGc2Yiox3teidQ98hKg6Wubs fkUS8A+H0d+ViAVY30IThuiS5MEiGQxNoZH/XVdn+SzSs9eyOZFScGSBaBruJynR kj7ar0lcF+c/ksbVXVA5LkqMKQ== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/www.rust-lang.org.pem0000664000000000000000000000567612656574623017147 0ustar -----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDVplHGBWABxRoi zmlVbeSPoF7ma8lTzwGZ4Rd5beOzSEhh5MdTNJa/eCEsH9lxHUKfR42FltzZg9Ag gx9Bo+GaT3Alrt3BYasw8rc23Yt12QfgbjBB6qVfndW9acaJU6DWRErDTLocgW+d 77uXPKJySqWLlXCZ5XuxTvWYeiqqI7afmr90cQ89yEoYosluKRAiYcE+WFPq8YWD pg8LbgOSRmj06+P6ap0Jh+yB1//awOGdLIj7HzJ1mJBKcJWapItwhI7TQmrI4vuF FsQVofawW2rj2Cp38Cj1JJnaksFzW9+VBOoqLfV8VvgEPRrdrbpSVtYGAyppaIXa NketwQeXAgMBAAECggEAD4OnVoDXaul8L2Dbx0dWnJNhsMvM79gNXrY4tSmkqkUq dGlfjAw6kibQCds6N/uO9fAFN9kvql/nAiVjZKnY3RK9qw7arYtBGinV4hcOZH1h FAwMVw0J+zqD5eBDeX9oI4cMAsiUjzNa/pYFAkN17GS9RriQV6yRYdvA+9SLOpWB U3skYIDC9R+N1pmijjtfbMKAepSCS2u5p9XxcApFSnEhNyAwdND9dI4HJQGeuh43 ATluonmGojCHzRGqjbn7KKqoRkzF6ndBfUxEkns9hCaEPiLKvSgVUmkwmEQkBsSo 9gS64bN2hQ36M9cZTak+h/uxmoEAycwPC1+kFabhIQKBgQDz/iBV/1WcreVHYsrP /XR9od6ysJ/0XwcHCymRdCxXuWq0FWyCfRciyp85Hk7DyJrqwC2T4NDqyUG2Qitk SBqeBt4f9y3zME9ZKIR1Tw9tHTxpNuFHzr+lvU1+BPdESIZZcM/LnnXDsH49fn4b f7UtZWl+jEQKAVE2PHPLq/3KUQKBgQDgKezkBD4QuBik4ypgaCf58D5ZwGTJMwyY NQ07evoprxemcVynNGmt6Uxy467nakOY+J82vCjjXWqYGpanwMkIU/tEeScDmxiB P84vpKOkxdiSEwHrbpCdVbi3Kdx0dTFPIPFYguEC6jZ5xAWeqRcKaXIEWuQDQvt0 cOnWClFRZwKBgQCDIXMThPToDfWJlijV+6vd0V80vgRZe7D1MiSXDc6/HuGgA1uc DcqfYjKMqiM+ydOokrxsG4lshdmRMKLNdIsJnztGBrxlVPNwQXxe56ysweezzFDr HMyXMNQzBEw4IJpD+4NSNcmo8HQIbLEt6kbfLP+ziYMPtYGGGptJPRha4QKBgDNX JtxqZFSr9Wj+ZlxCPrWt4nnn6K10NbQ+olM3LUiSw5XpbNEW3gVo44uEvjBeVDEa 8Ew2+B5q7Nj9bffp3aE8qtXZ8aePxCMGHBEpYhmA/sMl+1CSuChw06ePvOAnXy3C W8Rr5WEnh2aIEMlv7MkDsYtxzbs5giH/Im9VWZ6NAoGAMj2B9J0qfSMHhxraB4cP 1F1KFhfjdatV+33e9ZO3FPqBMwQf/rVpGQ9aR26vEMSDDL7JCbDYyWgty2y+vSK6 7guTleSeiKFtQwIauWfzTaNoVSGjgt4tXJ4TxTWrC3CLjNTOXDme3FaQUwH9I2WJ 2A5fT/pWPxJHnCBxLhwrCug= -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDlTCCAn2gAwIBAgIJAO2Bl4dLamtDMA0GCSqGSIb3DQEBCwUAMGExCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxGjAYBgNVBAMMEXd3dy5ydXN0LWxhbmcub3JnMB4XDTE1 MTEwNjA4NTAxMFoXDTI1MDkxNDA4NTAxMFowYTELMAkGA1UEBhMCRlIxEzARBgNV BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 ZDEaMBgGA1UEAwwRd3d3LnJ1c3QtbGFuZy5vcmcwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDVplHGBWABxRoizmlVbeSPoF7ma8lTzwGZ4Rd5beOzSEhh 5MdTNJa/eCEsH9lxHUKfR42FltzZg9Aggx9Bo+GaT3Alrt3BYasw8rc23Yt12Qfg bjBB6qVfndW9acaJU6DWRErDTLocgW+d77uXPKJySqWLlXCZ5XuxTvWYeiqqI7af mr90cQ89yEoYosluKRAiYcE+WFPq8YWDpg8LbgOSRmj06+P6ap0Jh+yB1//awOGd LIj7HzJ1mJBKcJWapItwhI7TQmrI4vuFFsQVofawW2rj2Cp38Cj1JJnaksFzW9+V BOoqLfV8VvgEPRrdrbpSVtYGAyppaIXaNketwQeXAgMBAAGjUDBOMB0GA1UdDgQW BBSZ0A9gOD5XYyFFBey1+vZt+QNg/TAfBgNVHSMEGDAWgBSZ0A9gOD5XYyFFBey1 +vZt+QNg/TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDFlTnebTgQ 12xZuGDBs1akL6IIopJBfAtAZ4VKb4Hs096WRW4FRoTITZekvttj5PpC60rwCktO wzyvBAaTyyAEFTdJwYDkjQyOn1f/s09dwSJGGRE7m+32gWhJ5wHyYioaq2g/6HZK LEw/URV/ZbC3b6WGajNjKeze9WzR9j7lPwMY1bTyD7PrATI0X/0/Kpb0vB7thoUj FPSmCdOhAvtbwHk14ZYR+cuZF3eKjuwOPQvBgImKSshUa+xny5iypcrGoRSz8TR0 L8JtHyryhBvAOlE1ZxsQ1KGNLkWhSq+IXu62Sn3ypWvzcK12oJleCVVfs4SeyNPa g08xyaMtt/iS -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/swift.org.crt0000664000000000000000000000240512656574623015536 0ustar -----BEGIN CERTIFICATE----- MIIDiTCCAnGgAwIBAgIJALgNuEPn0NBYMA0GCSqGSIb3DQEBCwUAMFsxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSMwIQYDVQQKDBpNb2NrIGNlcnRp ZmljYXRlIGZvciBzd2lmdDESMBAGA1UEAwwJc3dpZnQub3JnMB4XDTE2MDExMTA5 MTMzM1oXDTI1MTExOTA5MTMzM1owWzELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNv bWUtU3RhdGUxIzAhBgNVBAoMGk1vY2sgY2VydGlmaWNhdGUgZm9yIHN3aWZ0MRIw EAYDVQQDDAlzd2lmdC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDFuYqdj9M/XqfKFKKIHmevbzHpdMVXpRy07FwaDdIlaJ18jepDZlbpYtmp7twV ab74IQelt4YrzuspXXoYif4JCfo1IJHM6eL0vVOyh9Agv6Op+7xu1ZKUDahkbbJe l6QwyGgl+v30vYyraDXOFbxWVNcVlkHRCLUfPo98aVKlcbzTQn3vlu4NHrR6SaQI hxgZlZtE27sVSZHnYuBAXnWVRvu+A9MT2pXV6TcJbhpnn0sKuQCEv77iOo28rr0r BoBG+mxxsCH3htI1M3qe0f9qSQke9xy6b13Rhh4VqtvdS/8JkM0o4cwcVkr8twE2 jOTaASa16ZT4YhzNPv/YV531AgMBAAGjUDBOMB0GA1UdDgQWBBRzuTe5u+FcqtKb HqQNRdS13sKQuDAfBgNVHSMEGDAWgBRzuTe5u+FcqtKbHqQNRdS13sKQuDAMBgNV HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDDhkOjx++RxFFQn1ogPj53uw30 y23SvFwB2LPL+KiPNmDnZh25EhExrlI/3V6C3yFLMhs/y/DzXoWVjDHanSrBeHs/ kTKTVPOfSDjp1n8fnBHOZcpMVsFzUeU7e424OiJR8VmzxNtPNqnSx5l3Z4MPGaer ejO08r3qgrUBbj4SJk0+iIRaHCyOlYZQzXJ5uO0HlqIA+XvcBNOI0VHle/owYZPv yFg3wjb8sq8XdJ6OR57gSP8R7JFMxQtvJhmJJ5UgzUS2F/kVVDSQVBgmEqef3pva z4HZqBpg+rwZppywQtH7WTQ0iA57BbB2pCTV2FZM1KPmtIr60mfFN98KM0zO -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/api.dartlang.org.pem0000664000000000000000000000567612656574623016754 0ustar -----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/qO1tNmZv7FBr WNsW5c9001bqTdLRYNUQWW7hEEYzVFgnW75e0L28QokwLNCpQOcQ5tMH+FhOWXv3 H35k6dTPCIcVMzwyFAyjiHRKFeedw4Fp7hfXNWLp35JGsY+NcI4mLeCF2eyegUzP 9Bbq/QJ+wOCKrT+yJDaxdihrE0hFu2VabIcKvYt9heb//4v19BI68Jex+Ae/XRdL KwdL27b5+riF7jreGanEgo+1nV/3iyrbKDm9rbFh9x5oXuN6fS7EFxAzAmo76Ug3 1YKyumZYtMRHNXO438fQMrzGMJ+BKWGvPnACEhnRkbRJcyv5ecwwL1Q3SWy2P4XS 0TkwpIxvAgMBAAECggEAfNMNhzKF9uEG41Mkpb4YpjK6ibET26/gNFy63TQXNHj7 TO7whpoW6JTA+rJFV+ZgV16uFKPHB4g6N5G4ZQrxwcEBEWqkCs2KCbvmWRX5GoPp Nk+OEWjAuicVApvELc8flXgNob9z3yvBFjMX9gXAaUM/OrJpKKFzSZL18f7F9Dtd x0zpf2BDefqy9eaNJOL6OVyUh4Ay38SbL1LnXsoIKwnt8Mfq/gRR5JCJvUlD/Pof ZQlLOEp2Q1FcgWWKfAlQEohnMxeeXBH1D03dx2l9vhr68YOr5y0S4IHyAR4JZMTq DGhZE3CTX9/tQ86CNEhfsCirRU2rkrg3JFrweNd8QQKBgQDxZsgBt8o0l4QyiXAJ j75MHt4Tsuxj/HTpnODX/diCTSrA/DNZcg1MuME0Y8WEpux3VVWaG4Cshuh1MEEp J53qPmxSjbgl/l8x/VBzZ+xCUxGDv6WfVehz4yUDIQ6/HA6fTlnh0MxcaJSF1gpd tqu8z4nXlb6dsyAEctg3m1zPDwKBgQDLQBRKCn5kHze7jH9C5iDb9Q71qg27C22l SA1pcTwQctBhg1+PlXLVs9IEOmRjIzFRo6a086snQoUZRpgkRQrrFdY/79MdDBky gA01Baf1Wa3fq24vnlsD7l5A1sNZg4RcqVe5+JJ81IOW0w/oXT1FCSlqbyTUlnU7 O/xobVRsoQKBgQClUuG5I3itCfN0dOGw+qu2EBHBZfE1DMm40ELASc4EdvrHzjEQ meZ327QdwBKepX8evudwMlOuVHpQ/6owmDwzF2syInKyOoJRhw2Y69xHFALTuuWf uMMI0tAfU3147qso+QzfdRLwWoMVIaBZy+fT2EKrzZcNA4by5QAlHRaziwKBgG1x 8fr0r56GWOJ7A0Qo22TWDtomWgJwYvhvVhmDSg6pZKA9t8V/ejis/dgdAVWI69PE Rc6Gr5ESds1ngCF3tCtmtNn08D9h9meFIJd+ljS9t60LiOfHY8c4IjTT8JlRAoNL BNw1h9wEK1+aA6TiIE3+YvjXJIP9CN9+q6onxSBBAoGAQCQB+kDXWA5qnegDTgPq 7v0o1ToWnGXySFNFS+EDCsPmRD+tx4ArVegocaH8kyo2eDM1y1EBWmMT+wbbAmbT /26MTkQhJrFh6Tgh7RBRIYwkk6CgjCQHqhSSGcgMpevcFSchDZ3Mu0JEStHEFqr/ iJCaY82855sNTKV91XvaNHU= -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDkzCCAnugAwIBAgIJALSb3qXZ19zRMA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxGTAXBgNVBAMMEGFwaS5kYXJ0bGFuZy5vcmcwHhcNMTUw OTMwMTQyMTE4WhcNMjUwODA4MTQyMTE4WjBgMQswCQYDVQQGEwJGUjETMBEGA1UE CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk MRkwFwYDVQQDDBBhcGkuZGFydGxhbmcub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAv6jtbTZmb+xQa1jbFuXPdNNW6k3S0WDVEFlu4RBGM1RYJ1u+ XtC9vEKJMCzQqUDnEObTB/hYTll79x9+ZOnUzwiHFTM8MhQMo4h0ShXnncOBae4X 1zVi6d+SRrGPjXCOJi3ghdnsnoFMz/QW6v0CfsDgiq0/siQ2sXYoaxNIRbtlWmyH Cr2LfYXm//+L9fQSOvCXsfgHv10XSysHS9u2+fq4he463hmpxIKPtZ1f94sq2yg5 va2xYfceaF7jen0uxBcQMwJqO+lIN9WCsrpmWLTERzVzuN/H0DK8xjCfgSlhrz5w AhIZ0ZG0SXMr+XnMMC9UN0lstj+F0tE5MKSMbwIDAQABo1AwTjAdBgNVHQ4EFgQU INl38sv3/6yjLDjbyjR5slQNa0IwHwYDVR0jBBgwFoAUINl38sv3/6yjLDjbyjR5 slQNa0IwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAYvDi9QURcC6i 4zHdnYSklEQSrIrbiqfVUKokol5fa8ohdwI53mYRviwrAMJT5NOVWW0ZGLI+o2H7 4HtGV+BX4++2UmvoK2DgPSg70hGJRsHJhDwhkjo27Gtkdn4xE6Fr9JfVIWQ2NCoW lJ2a6ZN6gzEtTMz2CT8M1AoXteI0tCwDS9azrcIjmNPMeKB3TxHU3D1Hdaos6Ahy LUUhNt5ETwA5ua4nZnkmeBCFk9S4lexnrH2J+qBi9YJLsPvbGiGcH+nJCXCKAHou D12o6JFY+Oxm2ccH3obX+yr2VMbN9vNU6s0/EzXTBYUkh6a116XAvJIp4sURAB42 8NvYomFOig== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/compress-files/0000775000000000000000000000000012656574623016034 5ustar ubuntu-make-16.02.1/tests/data/compress-files/script_with_archive.sh0000664000000000000000000000070712656574623022434 0ustar This is a script with a self-contained archive It contains multiple lines before the real archive itself == ARCHIVE TAG == Sj0Ux$zښ2# vӎM k> $r8'qBLuՆ ;GBzʌL^d7]$yz}ߌnj>ǿ)˰)ʐ>.PZj~F`x9YBjgOozZyY\{/0?wI.ds{Q?mn'7_V*@7)Y,p>Kp3?MfQN_́Oxg<P ubuntu-make-16.02.1/tests/data/compress-files/valid.zip0000664000000000000000000000256412656574623017666 0ustar PK +Eserver-content/UT TTux PK zGDserver-content/subdir/UT hSvTux PK zGD > server-content/subdir/otherfileUT hSqTux foo bar baz PKaD)8'(#server-content/biggerfileUT SvTux   _(7PKaD)8'(#server-content/executablefileUT STux   _(7PK oSD > server-content/simplefileUT r؎SvTux foo bar baz PK D > 0server-content/simplefile-with-no-content-lengthUT ?պSvTux foo bar baz PK +EAserver-content/UTTux PK zGDAIserver-content/subdir/UThSux PK zGD > server-content/subdir/otherfileUThSux PKaD)8'(#server-content/biggerfileUTSux PKaD)8'(#kserver-content/executablefileUTSux PK oSD > server-content/simplefileUTr؎Sux PK D > 0;server-content/simplefile-with-no-content-lengthUT?պSux PKubuntu-make-16.02.1/tests/data/compress-files/valid.tgz0000664000000000000000000000051312656574623017660 0ustar Sj0Ux$zښ2# vӎM k> $r8'qBLuՆ ;GBzʌL^d7]$yz}ߌnj>ǿ)˰)ʐ>.PZj~F`x9YBjgOozZyY\{/0?wI.ds{Q?mn'7_V*@7)Y,p>Kp3?MfQN_́Oxg<Pubuntu-make-16.02.1/tests/data/compress-files/simple.bin0000775000000000000000000000036512656574623020026 0ustar #!/bin/bash dest=android-ndk-foo while getopts "o:" opt; do case $opt in o) dest=$OPTARG/$dest ;; esac done mkdir -p $dest for bin in ndk-which ndk-build; do echo "#!/bin/sh" > $dest/$bin chmod +x $dest/$bin done ubuntu-make-16.02.1/tests/data/compress-files/invalid.tgz0000664000000000000000000000026112656574623020207 0ustar This is not a tarfile Sj0BLuՆ ;GBzʌL^d7]$yz}ߌnj>ǿ)˰)ʐ>.PZj~F`x9YBjgOozZyY\{/0? ubuntu-make-16.02.1/tests/data/compress-files/valid2.tgz0000664000000000000000000005000012656574623017736 0ustar server-content2/0000775000175000017500000000000012614620657014317 5ustar didrocksdidrocksserver-content2/subdir2/0000775000175000017500000000000012357164150015664 5ustar didrocksdidrocksserver-content2/subdir2/otherfile0000664000175000017500000000001412357164150017563 0ustar didrocksdidrocksfoo bar baz server-content2/simplefile-with-no-content-length20000664000175000017500000000001412356552477022771 0ustar didrocksdidrocksfoo bar baz server-content2/biggerfile20000664000175000017500000002145012343570667016431 0ustar didrocksdidrocksaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaserver-content2/simplefile20000664000175000017500000000001412343554162016444 0ustar didrocksdidrocksfoo bar baz ubuntu-make-16.02.1/tests/data/developer.android.com.crt0000664000000000000000000000246612656574623020004 0ustar -----BEGIN CERTIFICATE----- MIIDqzCCApOgAwIBAgIJANM5Fcvms7E/MA0GCSqGSIb3DQEBCwUAMGwxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSgwJgYDVQQKDB9BbmRyb2lkIGRl dmVsb3BlciBrZXkgZm9yIHRlc3RzMR4wHAYDVQQDDBVkZXZlbG9wZXIuYW5kcm9p ZC5jb20wHhcNMTQwODI4MDgyMzQyWhcNMjQwNzA2MDgyMzQyWjBsMQswCQYDVQQG EwJGUjETMBEGA1UECAwKU29tZS1TdGF0ZTEoMCYGA1UECgwfQW5kcm9pZCBkZXZl bG9wZXIga2V5IGZvciB0ZXN0czEeMBwGA1UEAwwVZGV2ZWxvcGVyLmFuZHJvaWQu Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA059PR5G1Ny1TFCaM 2EIoAh7L9xbY4Yj68cdyT3IXPgO7Liy/oVyXRyJyAIdpqwMURynLpXkedus7069x qpodHJAt0W2lAwq0/dpeBghKAYqQcAOZnQ/diDPVFYCDy3puFpRP1wDIauh8aVrd 1pZaI6NM7fTwIGkHMaenR72agMwYS75Mcwup6NlPK6eOdCpMZzhOQ+3aRzSh6fAo AVpb8JK8i+MzLs/mUnXJFsWLPspEB0MJ7gx5xciiP1TL3VMnb5sVgs7lO7OvFREi QuwcrLYKTBpDLGhhGBZDDupxM7XNJPIKiIuWdi8Dl6094UXT0lRx7qqf7GgjDyE4 iLQUWQIDAQABo1AwTjAdBgNVHQ4EFgQUs7PCZ/tV4Cfh1/UD9uiuJLnOIS8wHwYD VR0jBBgwFoAUs7PCZ/tV4Cfh1/UD9uiuJLnOIS8wDAYDVR0TBAUwAwEB/zANBgkq hkiG9w0BAQsFAAOCAQEAGgmIDe7aBeSsqr92Sh/hh1aEKxXbPSVpcKc7u8PS0/Y6 SA/2NbduLod/rY3YYMQFmbuzACFFPngdyrT4vnQp7NuMv0BEGJeAWs8jLf31x7zT pCaE7aRr+v3m5PVE1T9r7xrpeUkuKUZdKpLb/zwQGHzTQh8hOwpHWkOeaPhbeyM3 9D3v1huHumwTevKlz8DstGT+cUtSzG8xFG/eCCJYts3NgCYAunwuMbt3hO4BoANf 4sdR/MUPXxL4gSL/W8cVqwoukx2TmjvBYLyChSGNK4PZ6nfCNLrtSkXE0oKxyaLp FB8jsk738QvcVJALvN5gHW6gVY6O5o66tcCc/CPN/A== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/www.mozilla.org.crt0000664000000000000000000000212712656574623016675 0ustar -----BEGIN CERTIFICATE----- MIIDBzCCAe+gAwIBAgIJAKTsk2YD8MVzMA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV BAMMD3d3dy5tb3ppbGxhLm9yZzAeFw0xNTA3MjYwNzQ1MzdaFw0yNTA2MDMwNzQ1 MzdaMBoxGDAWBgNVBAMMD3d3dy5tb3ppbGxhLm9yZzCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAPj7Pu2WuyNGp2x8pWT7ZOIx8dHNvFvAhjjsj7RTRN9M HWTWCWRM10WSeylFZKd/tiS5rY2X0cpwC7KsLDFw0bDeOtChKsxY8jTR1bjo/Eb4 pIpkPALdjCH1bbuJ1cvf+G01Tf21UeNCEpT2bKMxhWSNj5kT3NAKoxhDFyGwLHYR PGOkAaK0s+aggD7w1kK1rD8g44IpslW2j4HMts3j5LGwYGS+kodRMvj/zmvUugAI /2I5SNPEvYIObEUeAftuU0RXgUWZENprWWp8yX4gL8bwM00cH5w4pxZX/Xtiys5e CFQDQGzwKPvw4sWr43pu/NnFVM0j9vzKYTc7DzBckjMCAwEAAaNQME4wHQYDVR0O BBYEFLKyZ+S5wc3fVfutG+Qqr1KqJpQ7MB8GA1UdIwQYMBaAFLKyZ+S5wc3fVfut G+Qqr1KqJpQ7MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANz9HVL/ 3LMVMNMUGefSEjO75bIcnp/cfv6CfX6bbuRavOmqPR5D21ZPAlWX1zYXOGPJ+rId INYlvM3d+xL3O9FBDedUx3ps6cYyaTpGSptJZ+4VUVI2jdGOASqI3W3StrQQQ2bD 6QDWvMNIe2yelNL5/JMZSVRl7WQEWStqTv9TvysAJzLvo3Sq3rgRyGI0M0e+wPzq /cTinJLPRR7uQim3+3oUv82nQzSL8swkt8zUd2wdGUxs8Tm6DgjnqhTVAWGUOheZ m+szCY3Wz6YBTF3LtPKdOctrvJ1OWoAkeMxROyzG27YURpTY2iCXvey0dGjlBOWd o/RqkNtalg7bO9c= -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/abstractframeworks/0000775000000000000000000000000012656574623017005 5ustar ubuntu-make-16.02.1/tests/data/abstractframeworks/category.py0000664000000000000000000000235312656574623021177 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Abstract framework with category module""" import umake.frameworks class ACategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category A", description="Category A description") class FrameworkA(umake.frameworks.BaseFramework): def __init__(self, category): super().__init__(name="Framework A", description="Description for framework A", category=category, install_path_dir="custom/frameworka") # No setup() or other virtual interfaces ubuntu-make-16.02.1/tests/data/abstractframeworks/__init__.py0000664000000000000000000000000012656574623021104 0ustar ubuntu-make-16.02.1/tests/data/golang.org.pem0000664000000000000000000000565512656574623015654 0ustar -----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCW9cmYh84IpnWI JE2oTpuEFnPRQzXDHcPIbR5vb+/npSA3zSNNKDJmd5MJvoO6sfBVDh1W0IJz+8uv kZ8zopxrsAZY9Qey3eLeUdPq8g7Pl1gbJ/zoQC0J2F509wq3G/wRG3LmgA/MJz8i oJ31/Nz+4AuOzC0FEIV8Kq6T3MlHvnhCK/p0s+Yy9MQ/iMjsZ4ltlITOFB96twMX 7+Hda3upeitNp/Jb2Du56Db7LiMpzXmWT3G6m6ZeMWJHdFFTM1NuNerekYpBIw/y p8y9aKwSuhtt56Xw+oVXy5w5nXAAhzmAS/Y6wpz+o6zWYuJakluVR1Br5MkUpj0R F0Zf2v/XAgMBAAECggEASgQnHQ9xGNKtC9xo6x3nqGLt1Gu0v38nkGzYIGFs6lIP Muz04w7Tb2QvhvaPVgmKwdlSz08at018+A9ZVJLlSPOcmR9C8BNU+hZ65lZaprQY 8e+wVBurOYmJ/qVl7pPdCnI/6v5dQIb5sLu513Ns09b8M76uUC5ilJfE0yDM28yq FRLVztblpiOv1LRsHyYOWTkxNBFsHoe/JjVaYwgLGKly2apYdwI/CPrMZBrJox2H 94sRW8Daa6xICaJtRy7Zb/Nv9qoBT4uQC5tPaVUu0DWi/1YwHiKcbgTrAQ2y4mmV e0qZhgLQqhsX6x5Ycsv0FPibKwdvTNMZ2oUNloPBsQKBgQDHPrlzYq+1hcA73cUk BY6lC150AydCXRKRNqsNSEAzd6xCqCJR7y00xXGDfUfP0qdspRy/mRak/CqELAwF b+PwDpY6mJg51d6p6ihoZz33UkJ/twKKABvm/XOpt0IjpoJ7ANuZQ5k5DZnLgxvv 6GCAxDr07f1HgmAUlCgZmUFUiQKBgQDB9gw3wS/J/bdFBMvuXCBZ5JvhB3Piks/8 hy7qrgW3lPrSbxk+fBYYBKlkONdfrpFlT3AlLJmM9WaTfWeGO4jO/ekxFtFwqBhq qR1+o1x5WwVw7KuDTPwjrHq4+wR7yycO8MJgMfZru9qET2k9b+/ZnTvvPZtS+pz5 1DhhvDFZXwKBgDvo9mZllCPm1ciqhG6yZRPneT00/YcM6VpUr9ZMlVFkeJ2KZNdy LYuimuFIuGEbHFCkzSInbBGr6TTY8bxoyocSO8XewFcToeJBkGjkMlO9nlU8uDy6 j6lDKJYtjmud07ocpetN0jK/jjENeUcH/ox5dKjVLsVjxHQroGsiE+zRAoGBAIq1 fz9QNPDrNOly6LRpxekDiEaBoepiu8MImhDSqtwC+u0K7q605sf+bXVzAPM4UFp3 WOf84ULhLJ5FjId+g/QjuWSVwOokDHIaxzENetB+u4Fqf63CnH6Wlp07RpWRTzls DFXm5SdejIMal1SMfKbPv1D0aeQJvcEcd8XNZC1ZAoGAKEFnSl9Ux0VV+eiO4kCY O9WnwxrnOSm3HCVgZTkBqc1m3+vM6zi6jCOtTcVGWdpf1cISTgcwl52ss+TaHFYe IypgFfhg8y1yl5P2NqzSfUMplEvLSsmcQ/q+2KnhfFRNLqvDws09lG3Imojm9cOE nzLEXjtAIm6ip318KcEK4zs= -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDhzCCAm+gAwIBAgIJAMXZAeV6XoKqMA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCmdvbGFuZy5vcmcwHhcNMTQxMTA0MTA0 NTQ1WhcNMjQwOTEyMTA0NTQ1WjBaMQswCQYDVQQGEwJGUjETMBEGA1UECAwKU29t ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYD VQQDDApnb2xhbmcub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA lvXJmIfOCKZ1iCRNqE6bhBZz0UM1wx3DyG0eb2/v56UgN80jTSgyZneTCb6DurHw VQ4dVtCCc/vLr5GfM6Kca7AGWPUHst3i3lHT6vIOz5dYGyf86EAtCdhedPcKtxv8 ERty5oAPzCc/IqCd9fzc/uALjswtBRCFfCquk9zJR754Qiv6dLPmMvTEP4jI7GeJ bZSEzhQfercDF+/h3Wt7qXorTafyW9g7ueg2+y4jKc15lk9xupumXjFiR3RRUzNT bjXq3pGKQSMP8qfMvWisErobbeel8PqFV8ucOZ1wAIc5gEv2OsKc/qOs1mLiWpJb lUdQa+TJFKY9ERdGX9r/1wIDAQABo1AwTjAdBgNVHQ4EFgQU4pdBPfs5FhCf5pAB xjyXIGdyfZswHwYDVR0jBBgwFoAU4pdBPfs5FhCf5pABxjyXIGdyfZswDAYDVR0T BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAbcCgfKm9R9k7UrOK739uh0XsZnX7 zGwYpB7ruDultkZwrFinLf5mzZY1458NIozuiL/unBR4k7z9S5EUiWRSO9hce+Cb SCLW/XfX3LlthgcndtNTFuHTkPmjzYNnN03vIZQcg9PEljjpN1oQ0571MJ07GtVd CwVyUmunOK/rnyP8S9kOcpEYI2SQesZu7Ld/vO4nQIoy5eTgOdWbj3qCf1oXImcR 8nNZu7/vIrluaQS91AT7sbz/ii4vMNOKlTrlpAVFCcjVyk8kx44g8g0+PKoSmpUd Juoopd+AWgef39ASUmidHCWyoGTSPB3fVauC4TC6OOdkpx6r91oDpd3ZpA== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/www.eclipse.org.crt0000664000000000000000000000236512656574623016656 0ustar -----BEGIN CERTIFICATE----- MIIDfTCCAmWgAwIBAgIJAM20ZMP9aWmfMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMRcwFQYDVQQKDA5FY2xpcHNlIHNl cnZlcjEYMBYGA1UEAwwPd3d3LmVjbGlwc2Uub3JnMB4XDTE0MTAyMzEzNDA1N1oX DTI0MDgzMTEzNDA1N1owVTELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3Rh dGUxFzAVBgNVBAoMDkVjbGlwc2Ugc2VydmVyMRgwFgYDVQQDDA93d3cuZWNsaXBz ZS5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgEa3kHNJD/cha wLdb0a8neaxMJpapWgY5O/CkevkT3b9W6/PWk+mQhpbvpxFDl5FfCLJ1Mh98HHI2 48HuHl4xYiOjfFhrnGopa8XmH+K7Va8zccDtgcpzYoj/YuV7y+x9m1vz0aJu8k1J LgV31s/zT+5MCpHoqheiwDSOAMV9WphAQzlN9uyo1h7bm3+37M+0vb4HRS9AoRMZ OIallN0Br2o4y1ab4K0k5rCqbHdkNMJ+yzzpcsB5tuQSd2xIkhQKxWSRSnGv1GBL h6E63tX9/nzwWlusQnm51f7Dt6OGT8ajs2HIlPVWKG/fI+cYru90oAClG50vgKDR m1SyjEwnAgMBAAGjUDBOMB0GA1UdDgQWBBTmUq4DtfLPIe9T8TwZoLM8waKw7jAf BgNVHSMEGDAWgBTmUq4DtfLPIe9T8TwZoLM8waKw7jAMBgNVHRMEBTADAQH/MA0G CSqGSIb3DQEBCwUAA4IBAQA+rB/ZJ3qNVGK9TgTZ7HoJbyavy0swtX61w3zeoKPt 303xXLW+VopIJPvWgIokVRgkTRV3TELZf4zd9HL1dOndDXhOFJSvyn5ZDZ3H3r2+ Lll+wnHlSEP4XYGoVbjcFx4BwYSIx0Q5KwClkSET/iRr++KOISEbqJ99grv6mPl5 ZcT7wybh/+sRK1JTuvMAeBWRdTIrHbEAbAK6PzghAxQG8fTSYBc5rZ5utP9naXaa rNQT6Wgr+KAW9NQP3LD0fwhzZWa7NZHT6k4v65QVSP53C/JAUoAzA7TwG8VzrU5G gthhvU3VeSKRGCa8DrFkK7JkOvK37NitkOPfVoBUd5Vw -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/invalidframeworks/0000775000000000000000000000000012656574623016630 5ustar ubuntu-make-16.02.1/tests/data/invalidframeworks/invalid_type.py0000664000000000000000000000176612656574623021703 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Framework with an invalid type""" import umake.frameworks class ACategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Category/A", description="Category A description") class InvalidFramework(umake.frameworks.BaseFramework): pass ubuntu-make-16.02.1/tests/data/invalidframeworks/__init_.py0000664000000000000000000000000012656574623020570 0ustar ubuntu-make-16.02.1/tests/data/netbeans.org.crt0000664000000000000000000000241112656574623016176 0ustar -----BEGIN CERTIFICATE----- MIIDizCCAnOgAwIBAgIJAKV0wmMGmeB5MA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxFTATBgNVBAMMDG5ldGJlYW5zLm9yZzAeFw0xNTExMDIx NjAzMjFaFw0yNTA5MTAxNjAzMjFaMFwxCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApT b21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFTAT BgNVBAMMDG5ldGJlYW5zLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALnF19MaByOa44WkHygDR3TtyIiusMI0JFGC/u049MczUU9TWAul3CEePRit h4UmlzIP9JeBEfhsAkqLNH6t+70fa8qwDMOPdfZKaO1q3ZlR3jPhPKRhEHl9fNo7 5miLC3XYVUNiJZV2VZxKRT2ID8KndNhSD5uogGAaHiTU8jGAw5BkYMWLQqkZpbuk vvloZOLIgWhrBzw2bBVw5PNuoC+0WtMqf/uImeSsD7xf580eOwPHZp1R8dTdlqfx uOFVkpu6cX9G1d9JZeisaH1w57jh6uW0oRStHuXz1/2c4vjU2PaJM+zRN9sFrvr2 Oa02yQ2iawV6DSzVV3XwBuTdDHsCAwEAAaNQME4wHQYDVR0OBBYEFKBhmoDTcTWo KOIpL/UXSM6XE/pMMB8GA1UdIwQYMBaAFKBhmoDTcTWoKOIpL/UXSM6XE/pMMAwG A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAAzj+bVvCKYm19ig8uqDW5g p4Eq/R06LpV0J35iwKRN/YN5lyuIIdAFUtKLDgYxXaqUeh68zDcMyBpOU1o66Ei5 h8OT6quVA8IFmPHGWCt2KCMt58a2GFC92RHtHUFD91xuu2zFakXhZYxJvVPt1xpV QBOixTsW9O/pCO8KQ4Id9RXAgcMHMb9Ngho63cb7+FvSCcHd9/BJ/drO6PbcxqcG fLvHvdlTDV5aL38N0b2N1Ufpnu+btviQnuIiBCB1WWU/7nxE7phl6xVwVmLUCGze U2frDvRtahVe89R+GBz9QiNK+5i7wiz559vBPDFYneG0LVa+FA1scBpFEXwZ/4o= -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/storage.googleapis.com.crt0000664000000000000000000000244612656574623020172 0ustar -----BEGIN CERTIFICATE----- MIIDnzCCAoegAwIBAgIJANR5WAxHskyBMA0GCSqGSIb3DQEBCwUAMGYxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxHzAdBgNVBAMMFnN0b3JhZ2UuZ29vZ2xlYXBpcy5jb20w HhcNMTUwOTMwMTQyMzA2WhcNMjUwODA4MTQyMzA2WjBmMQswCQYDVQQGEwJGUjET MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ dHkgTHRkMR8wHQYDVQQDDBZzdG9yYWdlLmdvb2dsZWFwaXMuY29tMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2QSwjmoXclIlhWX0rbJByhCsprxmWu8p 1sicZa3jP5XRMrjHCyKwZDsjMmNVQCSuhJCpUUiZKS7JjKGDefbh+gQoCm2b2wzC aB0fAvaVL57mhzPDINwD+d/rc9ckxiCsim5v6667ZVQFlHE49FY6G2LvnUBOhJhi bz10cftuHQ6WGdTsfF63c8zNfII61A5sKju3PW2aDT4UBIoE2yGqX/oltzJKwObn tydvQrOOpBjp1/mDVNadhMYesP/71Awd/EVCUcVWpFaSX0tkkb+zyWI26HTfNHMB cP+g3kaqbbFfQB4p/zqwZW85/5Kvqllzj44mtkGZFDoi9gv8z1fFiQIDAQABo1Aw TjAdBgNVHQ4EFgQU20v78UMwwLEe2B7OnXlWjeYeBKkwHwYDVR0jBBgwFoAU20v7 8UMwwLEe2B7OnXlWjeYeBKkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC AQEAiIA9TlycwXcIPGSw72QMmlZesazTKPCImLWNWWh/WPU4y0lXcPXB4aKo1G3N jksK4wBITBpXuFU4aZolqxS6NoZEdyjHd4V9oPDGl4ZtwVas35P6ehnhHzhu1Tld QKynp+4e2V3tv4tcc4nnxDN4SXBNlMKIfJ6CaTbo0GlzJHNHBWlIIDdG2TjM3axP o996KFvAQkdq3WqWzmoNXOGS1Bkd52fJgtqr+mWNNGc2Yiox3teidQ98hKg6Wubs fkUS8A+H0d+ViAVY30IThuiS5MEiGQxNoZH/XVdn+SzSs9eyOZFScGSBaBruJynR kj7ar0lcF+c/ksbVXVA5LkqMKQ== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/api.dartlang.org.crt0000664000000000000000000000242612656574623016751 0ustar -----BEGIN CERTIFICATE----- MIIDkzCCAnugAwIBAgIJALSb3qXZ19zRMA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxGTAXBgNVBAMMEGFwaS5kYXJ0bGFuZy5vcmcwHhcNMTUw OTMwMTQyMTE4WhcNMjUwODA4MTQyMTE4WjBgMQswCQYDVQQGEwJGUjETMBEGA1UE CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk MRkwFwYDVQQDDBBhcGkuZGFydGxhbmcub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAv6jtbTZmb+xQa1jbFuXPdNNW6k3S0WDVEFlu4RBGM1RYJ1u+ XtC9vEKJMCzQqUDnEObTB/hYTll79x9+ZOnUzwiHFTM8MhQMo4h0ShXnncOBae4X 1zVi6d+SRrGPjXCOJi3ghdnsnoFMz/QW6v0CfsDgiq0/siQ2sXYoaxNIRbtlWmyH Cr2LfYXm//+L9fQSOvCXsfgHv10XSysHS9u2+fq4he463hmpxIKPtZ1f94sq2yg5 va2xYfceaF7jen0uxBcQMwJqO+lIN9WCsrpmWLTERzVzuN/H0DK8xjCfgSlhrz5w AhIZ0ZG0SXMr+XnMMC9UN0lstj+F0tE5MKSMbwIDAQABo1AwTjAdBgNVHQ4EFgQU INl38sv3/6yjLDjbyjR5slQNa0IwHwYDVR0jBBgwFoAUINl38sv3/6yjLDjbyjR5 slQNa0IwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAYvDi9QURcC6i 4zHdnYSklEQSrIrbiqfVUKokol5fa8ohdwI53mYRviwrAMJT5NOVWW0ZGLI+o2H7 4HtGV+BX4++2UmvoK2DgPSg70hGJRsHJhDwhkjo27Gtkdn4xE6Fr9JfVIWQ2NCoW lJ2a6ZN6gzEtTMz2CT8M1AoXteI0tCwDS9azrcIjmNPMeKB3TxHU3D1Hdaos6Ahy LUUhNt5ETwA5ua4nZnkmeBCFk9S4lexnrH2J+qBi9YJLsPvbGiGcH+nJCXCKAHou D12o6JFY+Oxm2ccH3obX+yr2VMbN9vNU6s0/EzXTBYUkh6a116XAvJIp4sURAB42 8NvYomFOig== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/code.visualstudio.com.crt0000664000000000000000000000255712656574623020045 0ustar -----BEGIN CERTIFICATE----- MIID1zCCAr+gAwIBAgIJALcOyQpcVt+2MA0GCSqGSIb3DQEBCwUAMIGBMQswCQYD VQQGEwJGUjETMBEGA1UECAwKU29tZS1TdGF0ZTE9MDsGA1UECgw0TW9jayBjZXJ0 aWZpY2F0ZSBmb3IgVmlzdWFsIFN0dWRpbyBDb2RlIG1lZGl1bSB0ZXN0czEeMBwG A1UEAwwVY29kZS52aXN1YWxzdHVkaW8uY29tMB4XDTE1MDQzMDA3NDUxMloXDTI1 MDMwODA3NDUxMlowgYExCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRl MT0wOwYDVQQKDDRNb2NrIGNlcnRpZmljYXRlIGZvciBWaXN1YWwgU3R1ZGlvIENv ZGUgbWVkaXVtIHRlc3RzMR4wHAYDVQQDDBVjb2RlLnZpc3VhbHN0dWRpby5jb20w ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSiDmIjpkJEwAHKq8DsV2w X13D5ld745XZ3pT/o3Jonge7EuJHYzTwATNYkERRhJ6QTR+1VP6Gq+gV1g0tdB0p CtXGzj6McYDoQi8y/h1PaldxL5xb9vpCHUfKO0GjyPCpZe7p/lMGJnC0yJJ6EM5A hLfj6gnQFhaei0pVgeLuA7CmI5aOmNY8mzqdj5mbktrlJhJG0jLUuh0yXW8IxgYO QAECeke5pis9sXhF0qYmEsyABrRHi9NKj/LPMuKzLiRWkO4/znmmzc3DNRwGD69i EokasXoohe9jaUcMdwY+/oHGJXonSxQ5P05MocGbmTYicD+R2Ft/LyageZlzrBj5 AgMBAAGjUDBOMB0GA1UdDgQWBBQmVWhkaDF6PHbXnDGNICP8aACkNzAfBgNVHSME GDAWgBQmVWhkaDF6PHbXnDGNICP8aACkNzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 DQEBCwUAA4IBAQAHmQQXMs09tDQjvPdO9i82JZ/BduBFI0FuZV/GQs2zcfF3EmLC USwXttKT7pUtL0HuO40wfwHuTl9P+bNsacpeAMG80ND437b7+o34BfAd4EqzP6mO JSZ0wCqsNvRI7H7BpsXjdO5H3DZgv6Sqcr6ibwWpRyspl70NnTzM/sjvARMrzX21 2feKEhS/MsuE0phNh9WKipGymqALFgwuVw5a+E5TSs8X/9is+YW7fpQ1y2Hrf/3T NQF4FQ41730cHEiaO/5WK6wypi55p62hyEdjlgvfdOLdxw20mu76BtX6m4S5+a5C bGBvmiSFeRyk0EXCTDYc/LYOe3WW/qWdQsnb -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/configs/0000775000000000000000000000000012656574623014531 5ustar ubuntu-make-16.02.1/tests/data/configs/valid/0000775000000000000000000000000012656574623015630 5ustar ubuntu-make-16.02.1/tests/data/configs/valid/umake0000664000000000000000000000025112656574623016653 0ustar frameworks: category-a: framework-a: path: /home/didrocks/quickly/ubuntu-make/adt-eclipse framework-b: path: /home/didrocks/foo/bar/android-studio ubuntu-make-16.02.1/tests/data/configs/invalid/0000775000000000000000000000000012656574623016157 5ustar ubuntu-make-16.02.1/tests/data/configs/invalid/umake0000664000000000000000000000000212656574623017174 0ustar : ubuntu-make-16.02.1/tests/data/configs/old/0000775000000000000000000000000012656574623015307 5ustar ubuntu-make-16.02.1/tests/data/configs/old/udtc0000664000000000000000000000025112656574623016167 0ustar frameworks: category-a: framework-a: path: /home/didrocks/quickly/ubuntu-make/adt-eclipse framework-b: path: /home/didrocks/foo/bar/android-studio ubuntu-make-16.02.1/tests/data/__init__.py0000664000000000000000000000000012656574623015200 0ustar ubuntu-make-16.02.1/tests/data/golang.org.crt0000664000000000000000000000240512656574623015651 0ustar -----BEGIN CERTIFICATE----- MIIDhzCCAm+gAwIBAgIJAMXZAeV6XoKqMA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCmdvbGFuZy5vcmcwHhcNMTQxMTA0MTA0 NTQ1WhcNMjQwOTEyMTA0NTQ1WjBaMQswCQYDVQQGEwJGUjETMBEGA1UECAwKU29t ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYD VQQDDApnb2xhbmcub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA lvXJmIfOCKZ1iCRNqE6bhBZz0UM1wx3DyG0eb2/v56UgN80jTSgyZneTCb6DurHw VQ4dVtCCc/vLr5GfM6Kca7AGWPUHst3i3lHT6vIOz5dYGyf86EAtCdhedPcKtxv8 ERty5oAPzCc/IqCd9fzc/uALjswtBRCFfCquk9zJR754Qiv6dLPmMvTEP4jI7GeJ bZSEzhQfercDF+/h3Wt7qXorTafyW9g7ueg2+y4jKc15lk9xupumXjFiR3RRUzNT bjXq3pGKQSMP8qfMvWisErobbeel8PqFV8ucOZ1wAIc5gEv2OsKc/qOs1mLiWpJb lUdQa+TJFKY9ERdGX9r/1wIDAQABo1AwTjAdBgNVHQ4EFgQU4pdBPfs5FhCf5pAB xjyXIGdyfZswHwYDVR0jBBgwFoAU4pdBPfs5FhCf5pABxjyXIGdyfZswDAYDVR0T BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAbcCgfKm9R9k7UrOK739uh0XsZnX7 zGwYpB7ruDultkZwrFinLf5mzZY1458NIozuiL/unBR4k7z9S5EUiWRSO9hce+Cb SCLW/XfX3LlthgcndtNTFuHTkPmjzYNnN03vIZQcg9PEljjpN1oQ0571MJ07GtVd CwVyUmunOK/rnyP8S9kOcpEYI2SQesZu7Ld/vO4nQIoy5eTgOdWbj3qCf1oXImcR 8nNZu7/vIrluaQS91AT7sbz/ii4vMNOKlTrlpAVFCcjVyk8kx44g8g0+PKoSmpUd Juoopd+AWgef39ASUmidHCWyoGTSPB3fVauC4TC6OOdkpx6r91oDpd3ZpA== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/spring.io.pem0000664000000000000000000000565112656574623015523 0ustar -----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCtBpvpZ46sKnU2 kxMwBeDB2fEwnn/OK0d4wL7ZSNM6BiqD6RNzO2PBkayhrLq+B3R9kFNPFtqZtVXv jB4PdCvjPN6d++QcqLv75dXS78cgTauZltrOo8HOkvrILdAPYxpuw5yRcHXrA3st IUVC4L2Z91ps4bSPApo2fA8BvKJqVsN+SrqR6qXjqwqGJIWc4BRDbqXnxGmfe0xj sHv71o0S8m+e+jdEaWy5zR9nj0J2zITydXkQYUTy/TTZvRiJB1DeSzJCaZLgovy2 J8KKSaMDYhA+/V9OrwSEstUjUKTWUhDdf/dugiNqHh93bKUNLNUSk7SEpc1qdA2X Y510isMjAgMBAAECggEBAJlq6MfWON1TcEcJtdO5AocgNgoEIBKwsVjSnuaO+ivS 19PK0KI2IMe74TQhshtZBONpG1VfUElGToJu3SCaw2djy4iNlsAKpVQ/gI7eaNOt yuAOsMjUzr3Z+V+Rr5BVMVTRQXx8GTJfDdMAUydvmu5wMs+kebLsfcydx7ikh+Z8 vrBurG0wM5Uiup3htqQmNB/sETBLpzrdOGQTjTXwTWnJRDG5yjaJP75AKcbTitAS oj0htsW03nKhmm7jBwzV44KGhesaggF9k5OPy8C8OZ5CGu1P80o6r9MRWdd50TTR x/y56DhHG7AL+E7DX5OzrMr6XHPd/qCDQOVCF2eN6cECgYEA2oUrg7ahHO20eQoy kyoesOAUJPAKjBuRLdU5JbOqN4WzWlp/Ttx6L07/AWnMCFS1k2XkfurqqOZojOuh 8Gj8XRQ29VIHy3oGyo+Dysv+7RkUE7JWaUKeeBgRgxGXQMbBjTl3+nciHYBr+aA8 /FMD/JvZVWR6HI9X/MWT48uySfMCgYEAyrPcyQnXVXbSIuwvdlkBnknK1mn5E5ye RRJrCAjniGzjz7FEn9IQW9fm3eWG4gsxTefdZO/MQCdmmMp1q9AoxEwDTTSciuWD 2MS121ozTG3ntGQTAZju2wJ2deG93SDUWHlaDqqipGycAShct2bAEsDv2yoHL2m/ 2orV4ZDJPhECgYB1yMQcucr76dCWUX3TPyfN1OpmwpAc1xsY5k5oWQBN7x4ufIsU edjOOTlQjLMyZl589bYFByC3K4J9OuFN0Xj9vtCkyLN05PBWLKcwH2boa9UbjMvw 7ry2JNsDl+68NqXLNofKFH7qAfexVMKqiyCh/2tVENSVIlqd3+2IIpqWKwKBgE2i DVFB36Lv2xNc+eCNvjztbi4ocCi+ty8lGrD9GA/8BFQrRGkhfvpt+hHKMpqoRr3b q8NYxBVeAcFK6T5gfvyPUERlff8EYDbJQA0+wp7nCPLh0RWviOuASfZj+t+SD0HD WGZ9m8T1g9o9pyTmyXFlS3fY5N+X1M7SlY/KcAjBAoGAQNixliS1YPOw2CYN2cv1 XP4lGPdVeFYU+4DZvFU+kWbFxr/4W+pCPZviiwLDh75wWn8Zq/PNx1BYM/532VSE kciBOUqSgDTX2UCH5VBzf0pOAc+CEco6hI1Nteq0/y1NdrSs1jhNc34Zmb1l28m9 IWsQTbxlnNDpg82xNXnXHVc= -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDhTCCAm2gAwIBAgIJANd9J6BAtBP4MA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCXNwcmluZy5pbzAeFw0xNjAxMzEyMTMz MTBaFw0yNTEyMDkyMTMzMTBaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV BAMMCXNwcmluZy5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK0G m+lnjqwqdTaTEzAF4MHZ8TCef84rR3jAvtlI0zoGKoPpE3M7Y8GRrKGsur4HdH2Q U08W2pm1Ve+MHg90K+M83p375Byou/vl1dLvxyBNq5mW2s6jwc6S+sgt0A9jGm7D nJFwdesDey0hRULgvZn3WmzhtI8CmjZ8DwG8ompWw35KupHqpeOrCoYkhZzgFENu pefEaZ97TGOwe/vWjRLyb576N0RpbLnNH2ePQnbMhPJ1eRBhRPL9NNm9GIkHUN5L MkJpkuCi/LYnwopJowNiED79X06vBISy1SNQpNZSEN1/926CI2oeH3dspQ0s1RKT tISlzWp0DZdjnXSKwyMCAwEAAaNQME4wHQYDVR0OBBYEFKiq4jCdiGRESUkCrCzQ PcjDLikeMB8GA1UdIwQYMBaAFKiq4jCdiGRESUkCrCzQPcjDLikeMAwGA1UdEwQF MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJG0neIXxTai+LWapryH8EpUai/rzuY3 qAhgyKOaylwmDQtKRkOmK3jEHRe8f3IIRG9chO7v+sQhTQIE+wTcqo4b+U7WL3dN 0MzhB1+xrLdf+mL6igAV+91MQzN4HG7/vzYoN86BRzQvPSaQF3TPJRAbrMdLwldM r19VLvjVKxVtSMrlj8tat04yPBQnnR+WFWpY6UDdNPCIXWvkUL9BW4GaNQkyXlbo 7nTGSmOQxEthAUiFZ2CZr4WLsbW+1+zkeg7lfutbnmM9hL5cC1TH2QZ2pGblpOcx KlGv2hyLzTjwPa05IAVJ51LK9u/6OGLG8Mt2NXnqBVLIfhyTWbBESak= -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/nodejs.org.crt0000664000000000000000000000240512656574623015664 0ustar -----BEGIN CERTIFICATE----- MIIDhzCCAm+gAwIBAgIJAM0RuxL089KdMA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCm5vZGVqcy5vcmcwHhcNMTYwMTE3MjM1 MzQ2WhcNMjUxMTI1MjM1MzQ2WjBaMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29t ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYD VQQDDApub2RlanMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA 2BMk7kFXmVV6KDiAIK/KXB1K03JUKqziyr1VbqZE++i/qJ7u/psK5+tbeksktBvP HeJZOqXdcICNo+kZwM9/gvH4WQ8u4LMg+ZWCvPzLcnkDd1r1hg2eND5m+E3VkVES /KL3AcaBNadfk/oAXIT1nVjvl2ZUlsRaYzb09Whr5995XTVw+ZntDoHrgjAHoYNq Erqc0/Cbv2Da0LHtUYRgUFFUQmBKOtbB+r2f7KYP8lCKxkISDxrq/je3tYJcUPfm aBFKcTmHgQa+WHK+AznZCtvpMicm/odh0K/mg8o0tADx7A56lTsedNI5DB8D90Es 2X4LzHuhhXPLxP8jUQbgLQIDAQABo1AwTjAdBgNVHQ4EFgQU44gu/w7Juo2HIvWV pGfZbgnY15MwHwYDVR0jBBgwFoAU44gu/w7Juo2HIvWVpGfZbgnY15MwDAYDVR0T BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVZItQ973u+yzHF1zQXGmhDIRQrcZ 5r4zmnT0VJhcZiPh3kDJfX9YnSLY2zYWB34UHhrO8Zp+55dv8e99y0RYgtQQgt+b K8D4U2NP1qBDAiFkOhKdVgXLL7r+MjZpGFTr75GDvFZQDyP+T1GUw++XSVVYQhFP x4RwSwMmUNv80uHMRrcPYe6a8XKCa1li/OlBJQq/JpFyhITDuo4aMVRcPK0HAfJE M+ZMM9mmHrrCqazFo0qThbJCz0hRqKZGMphjJ4kdPt3Y8536fZsEzTcR6PhLCOvd 4AovC7EmDmY9o2FXpPDmt8GpxenMdRRZkV+DkBv8OGcpsSLJ2vhflVm2MA== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/www.rust-lang.org.crt0000664000000000000000000000242612656574623017144 0ustar -----BEGIN CERTIFICATE----- MIIDlTCCAn2gAwIBAgIJAO2Bl4dLamtDMA0GCSqGSIb3DQEBCwUAMGExCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxGjAYBgNVBAMMEXd3dy5ydXN0LWxhbmcub3JnMB4XDTE1 MTEwNjA4NTAxMFoXDTI1MDkxNDA4NTAxMFowYTELMAkGA1UEBhMCRlIxEzARBgNV BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 ZDEaMBgGA1UEAwwRd3d3LnJ1c3QtbGFuZy5vcmcwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDVplHGBWABxRoizmlVbeSPoF7ma8lTzwGZ4Rd5beOzSEhh 5MdTNJa/eCEsH9lxHUKfR42FltzZg9Aggx9Bo+GaT3Alrt3BYasw8rc23Yt12Qfg bjBB6qVfndW9acaJU6DWRErDTLocgW+d77uXPKJySqWLlXCZ5XuxTvWYeiqqI7af mr90cQ89yEoYosluKRAiYcE+WFPq8YWDpg8LbgOSRmj06+P6ap0Jh+yB1//awOGd LIj7HzJ1mJBKcJWapItwhI7TQmrI4vuFFsQVofawW2rj2Cp38Cj1JJnaksFzW9+V BOoqLfV8VvgEPRrdrbpSVtYGAyppaIXaNketwQeXAgMBAAGjUDBOMB0GA1UdDgQW BBSZ0A9gOD5XYyFFBey1+vZt+QNg/TAfBgNVHSMEGDAWgBSZ0A9gOD5XYyFFBey1 +vZt+QNg/TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDFlTnebTgQ 12xZuGDBs1akL6IIopJBfAtAZ4VKb4Hs096WRW4FRoTITZekvttj5PpC60rwCktO wzyvBAaTyyAEFTdJwYDkjQyOn1f/s09dwSJGGRE7m+32gWhJ5wHyYioaq2g/6HZK LEw/URV/ZbC3b6WGajNjKeze9WzR9j7lPwMY1bTyD7PrATI0X/0/Kpb0vB7thoUj FPSmCdOhAvtbwHk14ZYR+cuZF3eKjuwOPQvBgImKSshUa+xny5iypcrGoRSz8TR0 L8JtHyryhBvAOlE1ZxsQ1KGNLkWhSq+IXu62Sn3ypWvzcK12oJleCVVfs4SeyNPa g08xyaMtt/iS -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/data.services.jetbrains.com.crt0000664000000000000000000000246212656574623021107 0ustar -----BEGIN CERTIFICATE----- MIIDqTCCApGgAwIBAgIJAPoNW2O3W47oMA0GCSqGSIb3DQEBCwUAMGsxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxJDAiBgNVBAMMG2RhdGEuc2VydmljZXMuamV0YnJhaW5z LmNvbTAeFw0xNTEyMTEwODUyNTFaFw0yNTEwMTkwODUyNTFaMGsxCzAJBgNVBAYT AkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn aXRzIFB0eSBMdGQxJDAiBgNVBAMMG2RhdGEuc2VydmljZXMuamV0YnJhaW5zLmNv bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMpKcWEr0NKZ20zZOMbk o2ZbQZZ2soAmwvHb9Nna5CHO3kzOP2A+6zQZvhdwEc8W3LtOgZgK66XKhvLTQ1lW p9fEBbmJtJEUAutoNDh5mip75SVLklL0AEq3M1KVZKPx20KGrwcnZnfLFJSH3RC5 r0Zb/Ptu9sRMjDbvg4iMIch+VrNa1P34EUdMHWUQAbl/mgNm19vJ24ZvOUj4zX9M 6nDTJGmigmXBtbhkqAayueQ+dULUx8bM+btKCRU1ChadqZdjaB59rEq0EMDruLW5 SA8DSkM2KwrRbNtxvqfPKsXDKZYYWPTmK4GzlFgb2WZbifMws2c0TAqN01KX/RDy BU0CAwEAAaNQME4wHQYDVR0OBBYEFMlFjpvuzTPurQ5jYRlAQbQdmkEBMB8GA1Ud IwQYMBaAFMlFjpvuzTPurQ5jYRlAQbQdmkEBMAwGA1UdEwQFMAMBAf8wDQYJKoZI hvcNAQELBQADggEBACqrK0PtcYKLppXmaAqv5xFghcvyH4OKSb3g+OS35CEwofNP +8dlFoCLcVCgLRcOzY3E49ky02dVmpjOg6GnK6A69gwzsw0WRRx8LzZB/hoT2fvi SDe+Z5cQ71xB9MyfUu44UQ4q8babtHwgPqcBgqT9ofp0qW0ofE2tnVzRMcc79gQE NpYnEBRn1R9k4kfRgJKk+9WuY0woNG9W+z2+ERcDit2hQeXsyLvgx58RF3tGEar9 m3sy2pBSjBaO/W5wq3P+bIIEyjqG1gWhAePG2j18hvu7/njP70oFhis2zOJRnkos oGBEZhjNDMRiW5qj1kjUgfxRqH/4U7taSYVzenA= -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/github.com.pem0000664000000000000000000000565512656574623015656 0ustar -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCv2ir1GPdJjOYE KNnPsnAmdPBBu31JcTCfegv5GmpdBrdNcNsc8OivN/y+9yjWezwDr4macw6Ji8sG hO8jh+eCOgjZ8/4alA6hB+xNoG4NDLM6wm/YTlxs5lDNKRzKSuiXHUPCSp3L/YHP bli09f48GLrGlUItIGRp3mJlbn7J3qaWgbvrrXQqgFEHRL4YIPpoJU4el6V5nmcl gc7qjACgYKd0egxHgwzrR4e8HaoaCeip3ha4RBmyuHaapJ9fR0f0klQe8E8t/PcT HS6Hr2qgpGtrbL82ujq90PPLnQXZUIyzoWu7y6frLRFYFRePaI/64xj5uPcPUmn4 h0xMfqMBAgMBAAECggEACGHp8k0CXKsuu7wGxfPHjM2+NiPt0PZoTvHOaE1uDIkp a7OZfkOtk8yja6b0d2Tgc3yGnqolY0EaqHDlxVfRHVAO4/TRhArSt7Jc/UZMeKrG UGK8Wh9CIJ7J8z2mda4kcC+g7z4HT5YB/hVQfS/MsqirHpQ211fX8YP8RMGDobO7 Bmc9A7XGQWo+aFYuqcctpK05WrWOK8GCgfCyLLaOklEkCgxJmgoRS9tdQ9HI4RHY EnnyJQJbUeE9QpMshR5fRE2RvnFSsDVrsVwMdSvqDHi1rPGQDozF5mv3V0Cy/P/T QM+jC0hQs9GuuOXatfpxtizyBcJmjBLJPs3VDXwlEQKBgQDn2Ii72pJqK6QlAug1 ordK3t+97/xiKPkT/G6fWOKR/22da7CW+1TyD+CXcjWPA4LCEnM7OeepEYKew3HU EvrCBg3wO7kXOUFyjNNL7LfKx73jItBq9JPuhwlbUZnirzzIJrwumcSp6cl3IE4y t77tf3MX8ktH0bUt282wPPM5QwKBgQDCLEAtYyatoGrF3U6FLx2v4DpAiSoa49jt 64RDHuCPAf9NS/TBJyrhqi4j0VwVnAp/uQON5Oqr8H0K/YOA3e0bLrHI2CXA2DTO YElokcJCZZ86IqZokmOOfhV2x13ACL2KJwuZ/A6IUdQm9DS74g6eK5Fr/jc/Q2ey o9kWtU48awKBgQDfNBH/eJ/44ub2UuQnru1zgTo6a+64ueWCHkaJ1lLaZ+Sp52Ft Ga5gFHUOmH+Dncem+4hAfrDOjfMI0fSmTVdor9d/bp/1AcRGedl6gP04li/zmjK4 pZo9y3dwmRDjsf18W/5ThupVAqRYsZtXLJr9nvO5HCTpkbUx3ykZALTQbQKBgQCN o7XU5eTK9p+sYfjrEil3p/sWJHhAUUBmnUxHofhwmSZgfi210BpprrgljIy9fqvx 60X6dafxcGXmZHNOx5Q0JeWt+m3ftFcgzAAAdYLc6EA0Kh51XYOd579Ee72ZXUbV xhGia8k2C2rUV4M4InhDTMixnCk0zriQCRFMjUjarQKBgCVNex03rtGulS4TNt1R ggsUa1xRoNnAfbXAE4W97akEuljL6jZiiF6IT3kM8Sckkt02bloy/+DlBjixroqp zr3gRzDmE85lDYnOYm8z42fJ8JkVgbyGUdFlolqzROAP9PaBTMs2lT4trS/UMSm4 N6DD3fKNNZRv6ZhkrvlbS+2D -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDhzCCAm+gAwIBAgIJAPN26r3EAAhsMA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCmdpdGh1Yi5jb20wHhcNMTYwMTMxMTQx OTQxWhcNMjUxMjA5MTQxOTQxWjBaMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29t ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYD VQQDDApnaXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA r9oq9Rj3SYzmBCjZz7JwJnTwQbt9SXEwn3oL+RpqXQa3TXDbHPDorzf8vvco1ns8 A6+JmnMOiYvLBoTvI4fngjoI2fP+GpQOoQfsTaBuDQyzOsJv2E5cbOZQzSkcykro lx1Dwkqdy/2Bz25YtPX+PBi6xpVCLSBkad5iZW5+yd6mloG76610KoBRB0S+GCD6 aCVOHpeleZ5nJYHO6owAoGCndHoMR4MM60eHvB2qGgnoqd4WuEQZsrh2mqSfX0dH 9JJUHvBPLfz3Ex0uh69qoKRra2y/Nro6vdDzy50F2VCMs6Fru8un6y0RWBUXj2iP +uMY+bj3D1Jp+IdMTH6jAQIDAQABo1AwTjAdBgNVHQ4EFgQU6p1ApP9amffHE/US lXsqax3qhFIwHwYDVR0jBBgwFoAU6p1ApP9amffHE/USlXsqax3qhFIwDAYDVR0T BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAoPMNVOSchGgKjTjnQcBspTKN3jI6 We3k2DCBV8i2J03v9wy8QtslOfAwY7Mm8wJJDLjtZwmxNAGEWiabvbEs2aehL98O zWnXOxL4ZxIH4Mgld4L+ihml6n2yFpF8z66wx+x8NqG5tfpeVztgJMns4jmfE8Kg g1aZhPYjkvMRqcom/Lg+lSNh/7g4DUyx9gNikQUySDDKnrRu1qtrI+c+TsGBq45K uQnbCefDQdEc340P/GAqkBHbOdVOwGjnhlk8LyAjqse0YicLs7qnFojp55Cwn8Nd KI6aj9+JN/EYOnv0Q9ywUDCrRPs87QHudv81v2vscBnTzJu+ox8iUPorDQ== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/netbeans.org.pem0000664000000000000000000000566112656574623016201 0ustar -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5xdfTGgcjmuOF pB8oA0d07ciIrrDCNCRRgv7tOPTHM1FPU1gLpdwhHj0YrYeFJpcyD/SXgRH4bAJK izR+rfu9H2vKsAzDj3X2Smjtat2ZUd4z4TykYRB5fXzaO+Zoiwt12FVDYiWVdlWc SkU9iA/Cp3TYUg+bqIBgGh4k1PIxgMOQZGDFi0KpGaW7pL75aGTiyIFoawc8NmwV cOTzbqAvtFrTKn/7iJnkrA+8X+fNHjsDx2adUfHU3Zan8bjhVZKbunF/RtXfSWXo rGh9cOe44erltKEUrR7l89f9nOL41Nj2iTPs0TfbBa769jmtNskNomsFeg0s1Vd1 8Abk3Qx7AgMBAAECggEBAKSm66FZAlbWYy4BxvOJ5H2IeyJZ4qRd3oq4VgYfYyRj IX/zWKgKO07HJFOJCgJDr+JZLepSJYFPCcDUHJTi06pN/RXKb6Wss1q1nMZA32OS oiTNTxhKR3XGeTBbwt2Jz4CFWxy8Ep+kIEDDuxbMT1uxW+iW4uqNsCp9O5ZdfsPL 36M4C6o+tJoLyelAqBMgRwYBAR7U9g3vfYq6bUNzPD4/gZ7YaO6JvtieDTbPwpjc p3iCBgSPRA6ED2yR48LwC/u0piXlsNcBHUFVk872KpGOPHGXnqWIvj7kq9sMCpyU Wo90B+XJ8wuwGMPMjmKwHte2WYYlQCbjLYFVA2VBnzECgYEA4zO33WDgLz001EmP PGW6SoFVo5UD1N9p6AwgYToLqvMiTgi3c6dlRkrEYWaM1bcJnaBYU5OdzkCQGpxC JJA+YaJVTjMZiqo02X+XfANQaPBFVhHBCXwTWIKiJuspLy+0gwYyEwMV1GczQbkE mPUufsDaVt3TwejSMqS2nTQ90EcCgYEA0VHTGWyAs2SO9MUGr+Apfy6miEFUHkLu J33nfVfOwsaZHqpEeSYEeDuTsC64EMmruHhlo/jxDarZhWLhz9QnjAd8mA1fzDaq xexYBgusHofEvYQ5VOH79fhnX0HJT3TCIUOeBs4iaKwWvL9TFI3DuWPYCU+TcD3x KRTNiZ+tEC0CgYEAw6oulkBv0T7s2EXhTSpunOt1TUNv4UvmcSjAWfsbQUXSLVHk a32mAjsxlJA0iXjwlwcYCiH+rTl84O3hKIvwrTSYMphfTsP2b7kqRGq2PSlvDQiN LhXksz0NWGb9ON3kn1IenbDyg9G8msUz6GZ+fDqpzlWLoFtZarPfcNMkyNECgYBU sj0url6tN+U4WXjJNXTVB3VO8NAupnpi9Gj0qND6sw1GATNPqfhpBgJOabkE4fVf 4SePX616EEWP2WDxjTCrUmQxykeXBA+5olZDq/lrKRiMbrIcDIy9DFQXkTD5u47J kuigbEwz+l4A5ZGiYXJu012Y9t/7rLSmIMrCAyAtyQKBgCNxkCNw3mcErowwoiHd fhh4IEsRyd6erVid4jTNb7G7N1lEujlUNY2OsAfhROBy5P/ohJgMKre1nyc1xeiu cZxnQwZetmja4xAnNlcqxsloZlyOrP3APeFQYG3norKirZ4YFeFaU9w/L0kUUFSK N189dwTgx9yqDEP0SEgYJBF8 -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDizCCAnOgAwIBAgIJAKV0wmMGmeB5MA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxFTATBgNVBAMMDG5ldGJlYW5zLm9yZzAeFw0xNTExMDIx NjAzMjFaFw0yNTA5MTAxNjAzMjFaMFwxCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApT b21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFTAT BgNVBAMMDG5ldGJlYW5zLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALnF19MaByOa44WkHygDR3TtyIiusMI0JFGC/u049MczUU9TWAul3CEePRit h4UmlzIP9JeBEfhsAkqLNH6t+70fa8qwDMOPdfZKaO1q3ZlR3jPhPKRhEHl9fNo7 5miLC3XYVUNiJZV2VZxKRT2ID8KndNhSD5uogGAaHiTU8jGAw5BkYMWLQqkZpbuk vvloZOLIgWhrBzw2bBVw5PNuoC+0WtMqf/uImeSsD7xf580eOwPHZp1R8dTdlqfx uOFVkpu6cX9G1d9JZeisaH1w57jh6uW0oRStHuXz1/2c4vjU2PaJM+zRN9sFrvr2 Oa02yQ2iawV6DSzVV3XwBuTdDHsCAwEAAaNQME4wHQYDVR0OBBYEFKBhmoDTcTWo KOIpL/UXSM6XE/pMMB8GA1UdIwQYMBaAFKBhmoDTcTWoKOIpL/UXSM6XE/pMMAwG A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAAzj+bVvCKYm19ig8uqDW5g p4Eq/R06LpV0J35iwKRN/YN5lyuIIdAFUtKLDgYxXaqUeh68zDcMyBpOU1o66Ei5 h8OT6quVA8IFmPHGWCt2KCMt58a2GFC92RHtHUFD91xuu2zFakXhZYxJvVPt1xpV QBOixTsW9O/pCO8KQ4Id9RXAgcMHMb9Ngho63cb7+FvSCcHd9/BJ/drO6PbcxqcG fLvHvdlTDV5aL38N0b2N1Ufpnu+btviQnuIiBCB1WWU/7nxE7phl6xVwVmLUCGze U2frDvRtahVe89R+GBz9QiNK+5i7wiz559vBPDFYneG0LVa+FA1scBpFEXwZ/4o= -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/swift.org.pem0000664000000000000000000000565512656574623015541 0ustar -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFuYqdj9M/XqfK FKKIHmevbzHpdMVXpRy07FwaDdIlaJ18jepDZlbpYtmp7twVab74IQelt4Yrzusp XXoYif4JCfo1IJHM6eL0vVOyh9Agv6Op+7xu1ZKUDahkbbJel6QwyGgl+v30vYyr aDXOFbxWVNcVlkHRCLUfPo98aVKlcbzTQn3vlu4NHrR6SaQIhxgZlZtE27sVSZHn YuBAXnWVRvu+A9MT2pXV6TcJbhpnn0sKuQCEv77iOo28rr0rBoBG+mxxsCH3htI1 M3qe0f9qSQke9xy6b13Rhh4VqtvdS/8JkM0o4cwcVkr8twE2jOTaASa16ZT4YhzN Pv/YV531AgMBAAECggEADAgiWzwpSq3j3/Qpf8b54D8P9njYmWC+wnOvlxZIN2aK Ts4D913+4+zT+fdDBTqOGGNKJ9dnHrtUrAu4Jk4fW0V0KE93D9UbrnDm6vJAw/1l ZC6hZM0yQjgiixnxxLfNkfpf/A+t7HqsWLHatFO2RjqbbADcuG+jNeeEq7ltAgwy PSaZIS08WQm6i6wXANWZ9BwYEgbaIELnrLjTl6fDy2tLmlaNDLC603u7iVF4/puG G+0r9SVGqXctKKAy19dwl/4lBuMcXpEap7mzDXMEIzQL30Czby/69prGtBxU9oS8 lMUnJDuq5m0vlf315Srvi52RSKir6bfiktmZ+vy/gQKBgQD52c6lZBrjdV2D8EhW HSFbpSzoESodF0ByUAvM+guoE1G5wuYldxfZ0mfYEgisFGScj5CHs1a2uaZteWQ4 TnBo7fWn/V8DWcimLArAvY419ap7QH7iwkt/WeRrLQBylaNt9yAUHe3kFnIEOjJC mYsCaQ8Lqeb2drRdm/gaMYAFiQKBgQDKl1ACJ/ZsRr0bppgdEua2cG0NtKlkBOb6 IGxd9sQS41UYiTp5yx8z6WhFOM7QqbpAGupXSgNc+TcBuEqNltrgsSv84KpEQPRF qNjy8AZRJQI9i378m72JT3a7957JpIAOBb9M2n/m3IvRd/S0JEWgSZajP8CXrVe1 xe+Kt50mDQKBgQC7yhNhiC4VjB8vjagw4VAzO6DXBB+tIc7UnIliFQYx2+NvRagJ vMt2coiOhG90Nxev/M/aztZ8HGmUmsrS71HZ7BDZpLyHHjKLg0rJty9uKylp3f4A nZx1KbFfRMGzXfkqK7Y2qJAnAR/NQZiJKjKrKx+d2qO311yVhychONdKUQKBgFST lvNPe7D4VzqT8i0xFuBTTzPJmG4JHeSOZK9VtcWs4nm70I3IHt6tMrqzXKQAN6FL m0mVvJGz+SLerUEvGXF0hcisgmi8NT5fnzLMwdZefPD0q68J1bbdVdRjLAdChbNU 8uhCz+KxcC2ixqXt/qNMFXdRxjWMSHG6kKZ4wUKBAoGBAME/bHER0mXGA+51F7XG bod4IoZZXMwry5Sg7Q7TvGlC5HC2omzISo+3MpYozzDsgddjxb80+8zAGo0ffE6s tKN7Jv2gDO7YsTA+52a2B2WgvbiFQ0QNdf663GkojV84tZ2dSqtYq9sutFTLCkPR xwgHSfN5eF6ViFf3YMAHZaV2 -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDiTCCAnGgAwIBAgIJALgNuEPn0NBYMA0GCSqGSIb3DQEBCwUAMFsxCzAJBgNV BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMSMwIQYDVQQKDBpNb2NrIGNlcnRp ZmljYXRlIGZvciBzd2lmdDESMBAGA1UEAwwJc3dpZnQub3JnMB4XDTE2MDExMTA5 MTMzM1oXDTI1MTExOTA5MTMzM1owWzELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNv bWUtU3RhdGUxIzAhBgNVBAoMGk1vY2sgY2VydGlmaWNhdGUgZm9yIHN3aWZ0MRIw EAYDVQQDDAlzd2lmdC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDFuYqdj9M/XqfKFKKIHmevbzHpdMVXpRy07FwaDdIlaJ18jepDZlbpYtmp7twV ab74IQelt4YrzuspXXoYif4JCfo1IJHM6eL0vVOyh9Agv6Op+7xu1ZKUDahkbbJe l6QwyGgl+v30vYyraDXOFbxWVNcVlkHRCLUfPo98aVKlcbzTQn3vlu4NHrR6SaQI hxgZlZtE27sVSZHnYuBAXnWVRvu+A9MT2pXV6TcJbhpnn0sKuQCEv77iOo28rr0r BoBG+mxxsCH3htI1M3qe0f9qSQke9xy6b13Rhh4VqtvdS/8JkM0o4cwcVkr8twE2 jOTaASa16ZT4YhzNPv/YV531AgMBAAGjUDBOMB0GA1UdDgQWBBRzuTe5u+FcqtKb HqQNRdS13sKQuDAfBgNVHSMEGDAWgBRzuTe5u+FcqtKbHqQNRdS13sKQuDAMBgNV HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDDhkOjx++RxFFQn1ogPj53uw30 y23SvFwB2LPL+KiPNmDnZh25EhExrlI/3V6C3yFLMhs/y/DzXoWVjDHanSrBeHs/ kTKTVPOfSDjp1n8fnBHOZcpMVsFzUeU7e424OiJR8VmzxNtPNqnSx5l3Z4MPGaer ejO08r3qgrUBbj4SJk0+iIRaHCyOlYZQzXJ5uO0HlqIA+XvcBNOI0VHle/owYZPv yFg3wjb8sq8XdJ6OR57gSP8R7JFMxQtvJhmJJ5UgzUS2F/kVVDSQVBgmEqef3pva z4HZqBpg+rwZppywQtH7WTQ0iA57BbB2pCTV2FZM1KPmtIr60mfFN98KM0zO -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/spring.io.crt0000664000000000000000000000240112656574623015520 0ustar -----BEGIN CERTIFICATE----- MIIDhTCCAm2gAwIBAgIJANd9J6BAtBP4MA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCXNwcmluZy5pbzAeFw0xNjAxMzEyMTMz MTBaFw0yNTEyMDkyMTMzMTBaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV BAMMCXNwcmluZy5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK0G m+lnjqwqdTaTEzAF4MHZ8TCef84rR3jAvtlI0zoGKoPpE3M7Y8GRrKGsur4HdH2Q U08W2pm1Ve+MHg90K+M83p375Byou/vl1dLvxyBNq5mW2s6jwc6S+sgt0A9jGm7D nJFwdesDey0hRULgvZn3WmzhtI8CmjZ8DwG8ompWw35KupHqpeOrCoYkhZzgFENu pefEaZ97TGOwe/vWjRLyb576N0RpbLnNH2ePQnbMhPJ1eRBhRPL9NNm9GIkHUN5L MkJpkuCi/LYnwopJowNiED79X06vBISy1SNQpNZSEN1/926CI2oeH3dspQ0s1RKT tISlzWp0DZdjnXSKwyMCAwEAAaNQME4wHQYDVR0OBBYEFKiq4jCdiGRESUkCrCzQ PcjDLikeMB8GA1UdIwQYMBaAFKiq4jCdiGRESUkCrCzQPcjDLikeMAwGA1UdEwQF MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJG0neIXxTai+LWapryH8EpUai/rzuY3 qAhgyKOaylwmDQtKRkOmK3jEHRe8f3IIRG9chO7v+sQhTQIE+wTcqo4b+U7WL3dN 0MzhB1+xrLdf+mL6igAV+91MQzN4HG7/vzYoN86BRzQvPSaQF3TPJRAbrMdLwldM r19VLvjVKxVtSMrlj8tat04yPBQnnR+WFWpY6UDdNPCIXWvkUL9BW4GaNQkyXlbo 7nTGSmOQxEthAUiFZ2CZr4WLsbW+1+zkeg7lfutbnmM9hL5cC1TH2QZ2pGblpOcx KlGv2hyLzTjwPa05IAVJ51LK9u/6OGLG8Mt2NXnqBVLIfhyTWbBESak= -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/lsb_releases/0000775000000000000000000000000012656574623015544 5ustar ubuntu-make-16.02.1/tests/data/lsb_releases/valid0000664000000000000000000000014712656574623016570 0ustar DISTRIB_ID=Ubuntu DISTRIB_RELEASE=14.04 DISTRIB_CODENAME=trusty DISTRIB_DESCRIPTION="Ubuntu 14.04 LTS" ubuntu-make-16.02.1/tests/data/lsb_releases/invalid0000664000000000000000000000000012656574623017103 0ustar ubuntu-make-16.02.1/tests/data/www.mozilla.org.pem0000664000000000000000000000537712656574623016700 0ustar -----BEGIN PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQD4+z7tlrsjRqds fKVk+2TiMfHRzbxbwIY47I+0U0TfTB1k1glkTNdFknspRWSnf7Ykua2Nl9HKcAuy rCwxcNGw3jrQoSrMWPI00dW46PxG+KSKZDwC3Ywh9W27idXL3/htNU39tVHjQhKU 9myjMYVkjY+ZE9zQCqMYQxchsCx2ETxjpAGitLPmoIA+8NZCtaw/IOOCKbJVto+B zLbN4+SxsGBkvpKHUTL4/85r1LoACP9iOUjTxL2CDmxFHgH7blNEV4FFmRDaa1lq fMl+IC/G8DNNHB+cOKcWV/17YsrOXghUA0Bs8Cj78OLFq+N6bvzZxVTNI/b8ymE3 Ow8wXJIzAgMBAAECggEARoLgz2hglxzrTU3/iRmo+GYslb4uGc3sNTLJf8gVOSfV Kzlyb3VTgeB6ALYmS0lfzAbJn8/fGfWhWnhoC5hnyi8lePArrrOB5HOIk1VoHLFN 5+N7G1Si2vsmmHXwlkxXjpYKAE/ZYQLVQFqJaa4cmN1+TVvSrRhWGAjoBCJgdQ7d i4tLx/MNjrDNahOGQW/HPhEGY1llkBGhwesh9/tUoZ869RK4bEtqc84IRvWe1ft5 A3KNgDEpolq+8T0fatgaVFhTGcwbSFUBaApgm+rlPi2vaCNAUE0fMsaN3CaXZg1V 7IjU9ObJycUyDsh608wzRZoekWZG2BDwWzvseqKwAQKBgQD9SOTJWYQpJC02YAHr RPpvf0+WL1SrRc9g2xk8ws/UlPF1UR3i5n9eMUc9RTkHQpLO3Scerr1H18actqF5 wvuBw6vTM+jD8tVaRp8doUDV06KQako+9hA58Hu+MP9BkDZH8ywykaQLwWOj2Ont lCZdW19WkHGMnHhcXi1HiKCzIwKBgQD7porQvNjaLw1iN6M3gIRi9VTFigHs4+L2 xIl9+QThzzr+N6HS8776v+E6WdZSW/7Pbmas+cra6cdZ/AC3VpRKtdH6LYGqMfRR RwOCuklEMpnOuRKkywxn2k4dRF5pSgHZLhk9jo5W0i33JVRdrM60bzTxRzkkqULl V49wZG9dsQKBgCIfONs7WQel3QVvR7LnVwnAT/t+otx0Ci0VN0AtSoxsCF9yryEL RmttHhjOA5HL0TVXK9cBWXSdSB+CpxxdPT7NGo/YdWo4g6+mxfba634jBcqI1znG Modrs2/679hoUje9Nd4WKtB+nCrNpS4hgE2haqWhzfpQdhKTiWwSpvubAoGAJmnh vsNVBtkv3dJIY+yGSOTSL+VFLfgLaUfPBR/CEwYjJzMuzJjQik5H/zQ/dwr79oYP vk/TG1+cQqwpH9Njh5QBnYLczDIb7Vw9uPLexD5FJD00D1u/ZQr56ZXKI6Bcb96N k8vzBmXHBnb4TeRXGUvwdPQ+UM5Vm9Sl3K44IcECgYASkhydtcdZ4tNgVcQule6t MFyWGhhsNH98AuDyqMiylMcbS4E73d7gMD3jdgy2QyMLcZ3pyjO8ZdYU/1VuhjmB hQrUlMwn97c8O/AmtMeKpBc/3WUt5JGAWo/8CIR5J+RY0bzUnSGLxi3zanFjKe57 A35F5r+3kUWLH89Gr6nqsA== -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDBzCCAe+gAwIBAgIJAKTsk2YD8MVzMA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV BAMMD3d3dy5tb3ppbGxhLm9yZzAeFw0xNTA3MjYwNzQ1MzdaFw0yNTA2MDMwNzQ1 MzdaMBoxGDAWBgNVBAMMD3d3dy5tb3ppbGxhLm9yZzCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAPj7Pu2WuyNGp2x8pWT7ZOIx8dHNvFvAhjjsj7RTRN9M HWTWCWRM10WSeylFZKd/tiS5rY2X0cpwC7KsLDFw0bDeOtChKsxY8jTR1bjo/Eb4 pIpkPALdjCH1bbuJ1cvf+G01Tf21UeNCEpT2bKMxhWSNj5kT3NAKoxhDFyGwLHYR PGOkAaK0s+aggD7w1kK1rD8g44IpslW2j4HMts3j5LGwYGS+kodRMvj/zmvUugAI /2I5SNPEvYIObEUeAftuU0RXgUWZENprWWp8yX4gL8bwM00cH5w4pxZX/Xtiys5e CFQDQGzwKPvw4sWr43pu/NnFVM0j9vzKYTc7DzBckjMCAwEAAaNQME4wHQYDVR0O BBYEFLKyZ+S5wc3fVfutG+Qqr1KqJpQ7MB8GA1UdIwQYMBaAFLKyZ+S5wc3fVfut G+Qqr1KqJpQ7MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANz9HVL/ 3LMVMNMUGefSEjO75bIcnp/cfv6CfX6bbuRavOmqPR5D21ZPAlWX1zYXOGPJ+rId INYlvM3d+xL3O9FBDedUx3ps6cYyaTpGSptJZ+4VUVI2jdGOASqI3W3StrQQQ2bD 6QDWvMNIe2yelNL5/JMZSVRl7WQEWStqTv9TvysAJzLvo3Sq3rgRyGI0M0e+wPzq /cTinJLPRR7uQim3+3oUv82nQzSL8swkt8zUd2wdGUxs8Tm6DgjnqhTVAWGUOheZ m+szCY3Wz6YBTF3LtPKdOctrvJ1OWoAkeMxROyzG27YURpTY2iCXvey0dGjlBOWd o/RqkNtalg7bO9c= -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/nodejs.org.pem0000664000000000000000000000565512656574623015667 0ustar -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDYEyTuQVeZVXoo OIAgr8pcHUrTclQqrOLKvVVupkT76L+onu7+mwrn61t6SyS0G88d4lk6pd1wgI2j 6RnAz3+C8fhZDy7gsyD5lYK8/MtyeQN3WvWGDZ40Pmb4TdWRURL8ovcBxoE1p1+T +gBchPWdWO+XZlSWxFpjNvT1aGvn33ldNXD5me0OgeuCMAehg2oSupzT8Ju/YNrQ se1RhGBQUVRCYEo61sH6vZ/spg/yUIrGQhIPGur+N7e1glxQ9+ZoEUpxOYeBBr5Y cr4DOdkK2+kyJyb+h2HQr+aDyjS0APHsDnqVOx500jkMHwP3QSzZfgvMe6GFc8vE /yNRBuAtAgMBAAECggEAfpq5COFAcpei++4fJQfbih2fukVDC75BJInLhQnnYbL+ mc6GOqidu0YsU3u0BdRFhz0ZC0Qke8bXNzNd45uxGwise4Jp9T8AEz2HXTTCAFDn tweU1Pclu3bU3qi8emkGtwDFukSVcNqhJhNWIt/FCm0R9aP/7FcgnwGUhjapAzLa S5dY3Flo6sY9GFiBQ/LGs0/mYxegKr1LRfUlobcP7UafrPmBqArqbe70IcegY2dl z6qKxAF25/osB8ACFquDymZBS7ZIgwdUV3AIahVn5gz8x90yk9toehxS5foBDngS nWiDCEe71HeLFPIhYAMF918WWohYb1A9/qkI7JwAAQKBgQDsNRrV1liFlTFdPYCC W2/okye7yFfZLUuL3RuCO9NtIH+mo4Dk9YY9ob19hpzkpm18Og+iYkLKHYxYquCB qepgmh5sqlNAox/Jkehf+rbTCFlj3TnATHSPmRMTSqKKeIm6v3d//d8FemrwfqgT e8KHpPdh4zVZh7r0Gbq/EQF1DQKBgQDqLixIckfE4tBKOXLDYJv325VEi5wm0lBB RsjmqmgV7mODCV8Vr+W6J8O/TOQI4FCmEuonQhiWybqZDi28NUFmTGNtqDxUI1fd 9QSbuc5scKn391BsxMDs9CrRgFJ/glaRe/t0uCQtRSd/753UoMx43oTdlJcCEsjA 9NH+jyKPoQKBgQDEBVIO0YHG4cgEm8xw4dbeCHj54kndBjTijgyNKH7N2iF1Ncz6 tTLBJN9vM24yZlcHt9tPpAHPX3QgBTapBExn/J5xCWxrgLQZgEd6l0JvoUclk+qg RhKZNKxa3x5CkcOiwdA23ITfM/dZO5LaEGOgU+ukRXz5nqUse8m5VDCEZQKBgHST 0cWq5mF0C/63RJNQl7Q2osNBwNVuozcrtr1lnXU1fGJyGtyf+PvH6eFktKxahqt2 BQzQEY+XEwY4kbn8xPbZFjIzqvyzr302CTpAsCs5ltNzUZ0kAWq0TlCG0grZ5qB8 GPzM4m2K3JQKxAZimgedtoTcAKSulzO/bH6N4MWhAoGBAIyN+JHAwX3qhGVPBEe+ nML36BHlTbkTQseTWu58cAW5NHVEiKT4GK6+oc6LB5mJXksKDmSyTVnleLUNwniK 5YTYuhU/Uqr4PrkSna/OCJZ7vFW1qOmkKJZAZKaApb6SMuExtHEMcqtIKKGzPQAu 26+W0MZLftCuGuGh4UfX7q3I -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIIDhzCCAm+gAwIBAgIJAM0RuxL089KdMA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCm5vZGVqcy5vcmcwHhcNMTYwMTE3MjM1 MzQ2WhcNMjUxMTI1MjM1MzQ2WjBaMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29t ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYD VQQDDApub2RlanMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA 2BMk7kFXmVV6KDiAIK/KXB1K03JUKqziyr1VbqZE++i/qJ7u/psK5+tbeksktBvP HeJZOqXdcICNo+kZwM9/gvH4WQ8u4LMg+ZWCvPzLcnkDd1r1hg2eND5m+E3VkVES /KL3AcaBNadfk/oAXIT1nVjvl2ZUlsRaYzb09Whr5995XTVw+ZntDoHrgjAHoYNq Erqc0/Cbv2Da0LHtUYRgUFFUQmBKOtbB+r2f7KYP8lCKxkISDxrq/je3tYJcUPfm aBFKcTmHgQa+WHK+AznZCtvpMicm/odh0K/mg8o0tADx7A56lTsedNI5DB8D90Es 2X4LzHuhhXPLxP8jUQbgLQIDAQABo1AwTjAdBgNVHQ4EFgQU44gu/w7Juo2HIvWV pGfZbgnY15MwHwYDVR0jBBgwFoAU44gu/w7Juo2HIvWVpGfZbgnY15MwDAYDVR0T BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVZItQ973u+yzHF1zQXGmhDIRQrcZ 5r4zmnT0VJhcZiPh3kDJfX9YnSLY2zYWB34UHhrO8Zp+55dv8e99y0RYgtQQgt+b K8D4U2NP1qBDAiFkOhKdVgXLL7r+MjZpGFTr75GDvFZQDyP+T1GUw++XSVVYQhFP x4RwSwMmUNv80uHMRrcPYe6a8XKCa1li/OlBJQq/JpFyhITDuo4aMVRcPK0HAfJE M+ZMM9mmHrrCqazFo0qThbJCz0hRqKZGMphjJ4kdPt3Y8536fZsEzTcR6PhLCOvd 4AovC7EmDmY9o2FXpPDmt8GpxenMdRRZkV+DkBv8OGcpsSLJ2vhflVm2MA== -----END CERTIFICATE----- ubuntu-make-16.02.1/tests/data/mocks/0000775000000000000000000000000012656574623014215 5ustar ubuntu-make-16.02.1/tests/data/mocks/fails/0000775000000000000000000000000012656574623015313 5ustar ubuntu-make-16.02.1/tests/data/mocks/fails/git0000775000000000000000000000012712656574623016024 0ustar #!/bin/sh params=$@ if [ "$params" = "describe --tags --dirty" ]; then exit 1 fi ubuntu-make-16.02.1/tests/data/mocks/git0000775000000000000000000000015112656574623014723 0ustar #!/bin/sh params=$@ if [ "$params" = "describe --tags --dirty" ]; then echo "42.03-25-g1fd9507" fi ubuntu-make-16.02.1/tests/data/apt/0000775000000000000000000000000012656574623013665 5ustar ubuntu-make-16.02.1/tests/data/apt/testpackagefoo_0.0.1_foo.deb0000664000000000000000000000327612656574623020727 0ustar ! debian-binary 1404741350 0 0 100644 4 ` 2.0 control.tar.gz 1404741350 0 0 100644 442 ` ͊0`zObRv!z-ֶ~JO_K=%|`lheyrsEel}GwYQYEicv[U a%$*'\܍ϟϿeU )orZox)yUY!-B\{p$hL.10>_VrZZYS EŋBb˛(9&~/?kVJ {xߎ\cz0Xͼ#EVdeh=HlLzz#{4X5=.>dL_osq9![jHfYwYςtNZ}ڇi:|!kzɆy<SQt#2yۀx5sD_RKxB!B!B!B~2(data.tar.xz 1404741350 0 0 100644 1092 ` 7zXZi"6!t/'] }J>y&Tao4=&T!}^"C2*A}a s`2|#L]<)Wh4n(Ʀ @"_RZV{2W I%8Hhű8Pp%d6cڣs^ׂ B  k4Ɉ)HLIuLsrT|]tg2}ߡ%{_FSV0Q%cBNZKql`]ŵLY#%~8PX. NStmQASh]n\@T(ˋ/繉KT_8@x>h7˚Xn$>)&8rgCRy]v?g> JgNl!'6c<+-D4+iMlTg#^D& 4xCrJLtGaQtyn*#Ps0P[i: 7*J aV[I <$` rxmgRPr< W>,A[~x(-!%גDWg"DQbndO#Gih dg @vEڀYo 7 rMRsn"tɴU$UnM1I7oHC΁çr0c.iԭ8,!0=H e}ɞPyk>0 YZubuntu-make-16.02.1/tests/data/apt/Packages.gz0000664000000000000000000000173512656574623015753 0ustar 릺S͖Mo6 >>().az]P"OחLf7@6mۃ[E[ϫzKrϲ_d7wSfn҉Zuizt_ <<yivewu\&|r5KX~V>~It)KԽZ?)Ws9#RIw;8k>H̡!KG@ߒ)-m@Zk2! /k;)5Vbݕn~öv0N|D݅l4≠ح6N6]ym?}vla#iY.agq7 P<H O,5Zա':M Ԛ5 U[J5!TGߊG,;8! Ьf}ƈFKj * M QOq/Bdۧy_/PHSB; ORsr縠K0v9MRLznEAi@I!P\2"1/)Md@Е!M+tלa=K~)ߏ{&_$G4.&HUK7SZf'xEɦ*fIu.XML Q8$й 5AрlP%GD -V(=7(a,~#)Fl JD#l"+.'~ k%.Bp%'Z7po FF ZioZETϘQ,`s|T\ ~eK~2\o 꾧_iXQY>hBJX>t Q.+mm4|l(7pЀXmbr%!*Qjb&hPD5-& 8 P,iup"X6AJUeޠ?XBR4埧 ubuntu-make-16.02.1/tests/data/apt/testpackage1_0.0.1_all.deb0000664000000000000000000000327212656574623020265 0ustar ! debian-binary 1404741350 0 0 100644 4 ` 2.0 control.tar.gz 1404741350 0 0 100644 433 ` j0`zGRJ {,"e$vzsv|`ll4K.6}}.XgeYؿ0Pt&Ѽl/rEU1/N+MـhD[á.cKcŻA0K$;(2˩viL%\rݨ,!okEBnD]Gљ$Ae_UMSsnr${8uIyc-<-wz@ʼnrOi/p[3ڀV@hUO.SXReǯ0ۛ &/=}Gw:[ qWeu!=X2SG暴ׯ'q F2_B!B!B!B( data.tar.xz 1404741350 0 0 100644 1096 ` 7zXZi"6!t/' ] }J>y&Tao4=&T!}^"C2*A}a s`2|#L]<)Wh4n(Ʀ @"_RZV{2W I$+ vy+ J#אaרzQ>T?VP&񇺣1%<3Xni58BxvAla뤤REpaL+RY0aEs9v:Pu!cm{cN:TM-P|Щ ,?HGm #pXna M*TË=ՉH/R_L$j Չd_PLH< z#[ DmVlh<[WwnqRIe5!4ǯ'k]l=50 \roP =>1DUuHnFxv$oH+XzJ;PIy=>~Od$q+Vj|an)!A\7N.J0KJT[l[Hw7f{["̅#Y 5*E**ls[VɦcI"aJPoTM>0 YZubuntu-make-16.02.1/tests/data/apt/testpackage2_0.0.1_all.deb0000664000000000000000000000330412656574623020262 0ustar ! debian-binary 1404741350 0 0 100644 4 ` 2.0 control.tar.gz 1404741350 0 0 100644 443 ` Ao0`>n1` MeI"n8M6i'!cx6Xi\:t/Rx90>HDd[UZ0sYi^dGg!ݶR_#ũA7v^Q4'L8!^VtcGY5]kU{q9,e~AmCLlhT3wu'8i ;c I9#64 ;N;9{Oo >0a8B!B!B!BW~( data.tar.xz 1404741350 0 0 100644 1096 ` 7zXZi"6!t/' ] }J>y&Tao4=&T!}^"C2*A}a s`2|#L]<)Wh4n(Ʀ @"_RZV{2W I$c׾ xtVZ&k:X}3,\8Wp,:;:_X5a!qp\۵*<f/a͏^ew[ f71A$[ q<ƢU\dqӚ h f&\7qPu{C%q?ZP̢uW"OI$'8A5f2R4zu[Y)*cKO˥IɈ03z8*XI D:@`4hYI'xk9\ҀH,"eK~mg.I#!<*W8]ֵa_q0q).@#2 )0~eh"2U  6= Xg v׌ $SF̏=oU/$9xDߧ#175}NIc>2~x0&O'4?}-E1odA|G IGk3FȡqAiz~59j( bY%~р|99*kfed u\,O C#j6u^chL"#p0{My']㔵j.B+Kzǔ1ƫ%RIfK -EuYѵN /"ys~!cKkUyqLڲ8<\ki+{"嘯^wVьRRt s#ƳU2:L^)crz1[3g_Ƀu&]d2G4q,9-E-[%}ByAM:E#82x(֐FGK٬iu0PdH>0 YZubuntu-make-16.02.1/tests/data/apt/testpackage/0000775000000000000000000000000012656574623016160 5ustar ubuntu-make-16.02.1/tests/data/apt/testpackage/debian/0000775000000000000000000000000012656574623017402 5ustar ubuntu-make-16.02.1/tests/data/apt/testpackage/debian/changelog0000664000000000000000000000042112656574623021251 0ustar testpackage (0.0.1) trusty; urgency=low * Initial release * Note: to add foo architecture, add it to: /usr/share/dpkg/cputable (copying your current arch line). And then: $ debuild -afoo -- Didier Roche Wed, 11 Jun 2014 14:00:13 +0200 ubuntu-make-16.02.1/tests/data/apt/testpackage/debian/rules0000775000000000000000000000006212656574623020460 0ustar #!/usr/bin/make -f # -*- makefile -*- %: dh $@ ubuntu-make-16.02.1/tests/data/apt/testpackage/debian/control0000664000000000000000000000262412656574623021011 0ustar Source: testpackage Section: misc Priority: extra Maintainer: Didier Roche Build-Depends: debhelper (>= 9.0.0) Standards-Version: 3.9.5 Package: testpackage Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, Description: Dummy package for testing Package used for testing debs installation Package: testpackage0 Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, Description: Dummy package for testinga - other Package used for other testing debs installation Package: testpackage1 Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, testpackage, Description: Dummy package for testing - dep Package used for testing debs installation with dep Package: testpackage2 Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, Conflicts: testpackage (<< 0.2), Description: Dummy package for testing - breaks Package used for testing debs installation with break Package: testpackagefoo Architecture: foo Multi-Arch: foreign Depends: ${shlibs:Depends}, ${misc:Depends}, Description: Dummy package for testing - only available on foo Package used for testing debs installation Package: testpackagearmhf Architecture: armhf Multi-Arch: foreign Depends: ${shlibs:Depends}, ${misc:Depends}, Description: Dummy package for testing - only available on armhf Package used for testing debs installation ubuntu-make-16.02.1/tests/data/apt/testpackage/debian/copyright0000664000000000000000000000170412656574623021337 0ustar Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: testpackage Source: www.example.com Files: * Copyright: 2014 Didier Roche License: GPL-2+ This package 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 2 of the License, or (at your option) any later version. . This package 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 this program. If not, see . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". ubuntu-make-16.02.1/tests/data/apt/testpackage/debian/compat0000664000000000000000000000000212656574623020600 0ustar 9 ubuntu-make-16.02.1/tests/data/apt/testpackage/debian/source/0000775000000000000000000000000012656574623020702 5ustar ubuntu-make-16.02.1/tests/data/apt/testpackage/debian/source/format0000664000000000000000000000001512656574623022111 0ustar 3.0 (native) ubuntu-make-16.02.1/tests/data/apt/states/0000775000000000000000000000000012656574623015170 5ustar ubuntu-make-16.02.1/tests/data/apt/states/testpackage_installed_dpkg_status0000664000000000000000000000040712656574623024056 0ustar Package: testpackage Status: install ok installed Priority: extra Section: misc Installed-Size: 26 Maintainer: Didier Roche Architecture: all Version: 0.0.0 Description: Dummy package for testing Package used for testing debs installation ubuntu-make-16.02.1/tests/data/apt/testpackage0_0.0.1_all.deb0000664000000000000000000000326212656574623020263 0ustar ! debian-binary 1404741350 0 0 100644 4 ` 2.0 control.tar.gz 1404741350 0 0 100644 426 ` Qk0`?WԖeK-eebVdX8uOI)F|eȮ%!1{\K^ )xU2o6gTd7X7o)Y^Aŧ@5仲sL-YcN@kO~9.vWmN~sJ%٧t+&4yyO[ WdA{{Di:їу^+zG]m.P{م:gų!B!B!B!g1(data.tar.xz 1404741350 0 0 100644 1096 ` 7zXZi"6!t/' ] }J>y&Tao4=&T!}^"C2*A}a s`2|#L]<)Wh4n(Ʀ @"_RZV{2W I$ v i|e~?2ϐG5Ń_o̭ٙI/fv-7; W "*/ jhMw_5}2ZlȴGǭ.Ûb'7iH~n~K AF}A 5/o1w6Lqw<{g.t8R^j v*N!׼NL 6Q^:^H_L53҇jF`.jpG܆l%!eK T)c,ur̖Dw([%e TKϿG7Ej@f1۝Ȁl}^L=jEXa=>B#!$8=$@0 YZubuntu-make-16.02.1/tests/data/apt/create_package_list.sh0000775000000000000000000000137712656574623020205 0ustar #/bin/sh # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz ubuntu-make-16.02.1/tests/data/apt/testpackage_0.0.1_all.deb0000664000000000000000000000324212656574623020201 0ustar ! debian-binary 1404741350 0 0 100644 4 ` 2.0 control.tar.gz 1404741350 0 0 100644 410 ` A ~&FIRZK }&qPug0-t{)-$ScY+y~5RI.D张-&(-uGbeܖxmyM?ߜPFCW+i[ UtzS%͓2^GXϤ7J0-lo! 1[Vu]f!<7N7~M1BW/\`#!:(+YYOL.I[ k ݣ{%"yECӎ4C4/+۲Y:zk{=C- ˶ YB!B!B!B~j}(data.tar.xz 1404741350 0 0 100644 1096 ` 7zXZi"6!t/' ] }J>y&Tao4=&T!}^"C2*A}a s`2|#L]<)Wh4n(Ʀ @"_RZV{2W I|#@_f;:g\C1zSøv1L2Hˆ[ gI%b d>)̺ EOqVaӷ8kT6p1Udگ-ӟ,faTײZ'{Iu KoGp5s';K3 n-N_}>"K)S*֖ uw+5w*7_w-J] 6mWg=A_S)2S557p}c砡vboRhe<̼$حGIާ+ˬ\&D\j&}C0ĉPc߁HQ?Ŗ7^/_̌9{'Rr.>f \d LY8 bv7Y jX37xp(Pfd2(υN>Pw}귝yʋuة@H)-%$*P a,.^0n7h]oDžD\L2\[oA uցRUb,bRyZnF ?sw4&U`A\Š{~GS0M]ʓ:0p'; CõGT%Q~DdW# HT]<~0E[D{ɽrDEQ x02f߽,Ʒ3{Up]ϯjDy}Um3ѭoq Ji'!tnZ{֩˧#On4 <=k nzY #i {.-tRNh.ä@d&lfQ_=rus'K0T&ZTO]wKZmEPr&>0 YZubuntu-make-16.02.1/tests/data/server-content/0000775000000000000000000000000012656574623016057 5ustar ubuntu-make-16.02.1/tests/data/server-content/spring.io/0000775000000000000000000000000012656574623017767 5ustar ubuntu-make-16.02.1/tests/data/server-content/spring.io/tools/0000775000000000000000000000000012656574623021127 5ustar ubuntu-make-16.02.1/tests/data/server-content/spring.io/tools/sts/0000775000000000000000000000000012656574623021740 5ustar ubuntu-make-16.02.1/tests/data/server-content/spring.io/tools/sts/all0000664000000000000000000003232112656574623022434 0ustar Download STS

Tools

Spring Tool Suite™ Downloads

Use one of the links below to download an all-in-one distribution for your platform.
Or check the list of previous Spring Tool Suite™ versions.

STS 3.7.2.RELEASE

New & Noteworthy

Windows

WIN, 32BIT

WIN, 64BIT

Mac

COCOA, 64BIT

Linux

GTK, 32BIT

GTK, 64BIT

Update Site Archives

You can download archived versions of the update sites, if you want to install STS into an existing Eclipse installation or if you want to update an existing STS installation without accessing the hosted version of the update repository.

Eclipse Archive Size
4.5.1 springsource-tool-suite-3.7.2.RELEASE-e4.5.1-updatesite.zip 120MB
4.4.2 springsource-tool-suite-3.7.2.RELEASE-e4.4.2-updatesite.zip 109MB

Update Sites

If you want to install STS in an existing Eclipse installation, you can use one of the following update sites. Please choose the one that matches the Eclipse version you're running:

Eclipse Update Sites
4.5 http://dist.springsource.com/release/TOOLS/update/e4.5/
4.4 http://dist.springsource.com/release/TOOLS/update/e4.4/

As an alternative, you can also install STS directly from the Eclipse Marketplace.

ubuntu-make-16.02.1/tests/data/server-content/github.com/0000775000000000000000000000000012656574623020116 5ustar ubuntu-make-16.02.1/tests/data/server-content/github.com/LightTable/0000775000000000000000000000000012656574623022135 5ustar ubuntu-make-16.02.1/tests/data/server-content/github.com/LightTable/LightTable/0000775000000000000000000000000012656574623024154 5ustar ubuntu-make-16.02.1/tests/data/server-content/github.com/LightTable/LightTable/releases/0000775000000000000000000000000012656574623025757 5ustar ubuntu-make-16.02.1/tests/data/server-content/github.com/LightTable/LightTable/releases/index.html0000664000000000000000000024607612656574623027773 0ustar Releases · LightTable/LightTable Skip to content
  • Watch

/LightTable

0.8.1

@kenny-evitt kenny-evitt released this

Changes

  • CHANGED: [:app :lt.objs.settings/pair-keymap-diffs] behavior is being deprecated. Use [:editor :lt.objs.editor/autoclose-brackets] in your user.behaviors instead. lt.objs.editor/autoclose-brackets should fix autoclosing characters e.g. '[{" for international users.
  • CHANGED: Backspace key uses the same CodeMirror plugin that lt.objs.editor/autoclose-brackets does
  • CHANGED: lt.util.cljs/js->clj is being deprecated. Plugin authors can use the js->clj that comes with ClojureScript
  • CHANGED: Removed unused lt.objs.titlebar ns and lt.objs.titlebar/add-titlebar behavior
  • CHANGED: Removed unused styling in structure.css
  • CHANGED: Removed harbor and jshint node packages that belong to other LightTable plugins
  • CHANGED: Removed :hide-connect command which is the same as :show-connect
  • CHANGED: Removed light skin which was just a confusing pointer to dark skin
  • CHANGED: files/open-sync logs an error when trying to open a nonexistent file. Previously the error was ignored
  • CHANGED: Check for updates every hour instead of every 5 minutes
  • FIX: Git (vcs) friendly! Changing branches and doing rebases doesn't cause buggy dialogs. If a file is removed, the tab is closed. If a file has a local modification, the user decides whether to overwrite the current file or not
  • FIX: LightTable documentation supports navigation as it is now in a browser tab
  • FIX: Save and remove trailing whitespace behavior refreshes tab
  • FIX: Navigator no longer cuts off end of files i.e. can scroll horizontally
  • FIX: Case sensitive renaming of files e.g. readme -> README
  • FIX: Faster detection of binaries in build scripts
  • FIX: In linux, middle click to close tab doesn't paste clipboard contents
  • FIX: :open-path command resolves relative paths before opening them
  • FIX: Clearer description of font-settings behavior
  • FIX: Clear console error when github endpoints returns invalid JSON
  • FIX: All errors are consistently caught and logged to console
  • ADDED: Light Table builds without warnings on ClojureScript 1.7.x
  • ADDED: Add build target for generating cljsdeps.js (need for ClojureScript upgrade)
  • ADDED: Linux and Windows users have access keys on menus
  • ADDED: Linux and Windows users have additional menu items under File: Quit Light Table and About Light Table
  • ADDED: Added file type definitions for html templates: ERB, ASPX, EJS, JSP
  • ADDED: Command-0/Ctrl-0 to reset zoom and Command-=/Ctrl-= to zoom in
  • ADDED: Disply notification to user after installing/updating/uninstalling a plugin

Checksums

The MD5 checksums are reproducible on OSX and Linux with openssl md5 FILE and on Windows with certUtil -hashfile FILE MD5.

  • Windows – 9cdda77518e86243a52bdb88e9ddebb8
  • Ubuntu (14.04) - 087dc9fb7be184c6549173c94be85254
  • OSX 10.10 - 4f9fb2dd330d589a109c582a6472a4a5

Downloads

0.8.0

@cldwalker cldwalker released this · 98 commits to master since this release

CHANGELOG

  • CHANGED: We have switched to Electron from NW.js
  • CHANGED: LT's releases and self-updating processes are completely in the open on Github
  • CHANGED: We no longer ship with a node binary as we're able to use Electon's node binary for background processes
  • CHANGED: Proxy support has been disabled. There is an issue for re-enabling it at #1984. We are looking for help on how to QA this.
  • CHANGED: :lt.objs.app/set-default-zoom-level behavior takes a value from 0 to 1. With NW.js, it could take negative numbers which no longer work and will freeze LT on startup
  • CHANGED: When opening a file from the commandline, each invocation opens a new LightTable app regardless of whether LightTable is already open. To optionally bring back the old behavior, see #2014.
  • CHANGED: Provide constant port number 5678 for external browser connection
  • CHANGED: Beginner friendly explanations to user.keymap and user.behaviors
  • CHANGED: 32-bit linux is no longer an official download. Building from source will still be supported
  • FIX: Major usability issues on >= OSX 10.10
  • FIX: Bug in :editor.force.wrap command
  • FIX: Invalid behaviors warning when installing plugin
  • FIX: Uninstalling plugin causes misleading missing dialog to popup
  • FIX: Installing plugins, loads new behaviors immediately
  • FIX: Open files from commandline that have whitespace
  • FIX: Styling for folding
  • FIX: Creating files under folders with '.' in name
  • FIX: Quote and link styling for default theme
  • FIX: Fat cursor not showing up when searching in default theme
  • FIX: Uncomment command respects line-comment-options behavior
  • FIX: Opening file from OSX file manager opens correct file
  • FIX: Width of inputs for renaming files in workspace tree
  • FIX: Detect latest plugin versions in plugin manager
  • ADDED: LT can be built from source with provided scripts across supported platforms
  • ADDED: Improved documentation - most core fns have docstrings, all namespaces have docstrings, API docs and developer docs
  • ADDED: Most of LT's node libraries are installed as npm dependencies instead of as forked libraries
  • ADDED: Vector format support for workspace behaviors
  • ADDED: Open to line number from commandline e.g. light FILE:LINE
  • ADDED: commandline comes with improved --help
  • ADDED: :lt.objs.editor/load-addon behavior loads CodeMirror addons that ship with LT
  • ADDED: :lt.objs.editor/set-rulers behavior to set CodeMirror rulers - screenshot
  • ADDED: Add file-type definitions for .feature, .rst and many more
  • ADDED: Add F-11 keybinding for fullscreen
  • ADDED: Add pmeta-/ for toggle-comment
  • ADDED: Better error handling for download errors
  • ADDED: Block comment command
  • ADDED: Max length for autocompletion is configurable
  • ADDED: Plugins and settings menu items

Builds

  • OSX built on OSX 10.10.4
  • Linux built on Ununtu 14.04
  • Windows built on Windows 7

Checksums

The MD5 checksum is reproducible on OSX with openssl md5 FILE or certUtil -hashfile FILE MD5 on Windows.

  • osx download - eeb03b4b8e55639b670e96f6d8a69397
  • windows download - 84fbb93779b1197f0c4b87d573be0818
  • linux download - ac8484d589b8b1ff4de11a0954ef49f7

Downloads

0.8.0-alpha

@cldwalker cldwalker released this · 146 commits to master since this release

CHANGELOG

  • CHANGED: We have switched to Electron from NW.js
  • CHANGED: LT's releases and self-updating processes are completely in the open on Github
  • CHANGED: We no longer ship with a node binary as we're able to use Electon's node binary for background processes
  • CHANGED: Proxy support has been disabled. There is an issue for re-enabling it at #1984. We are looking for help on how to QA this.
  • CHANGED: :lt.objs.app/set-default-zoom-level behavior takes a value from 0 to 1. With nw.js, it could take negative numbers which no longer work and will freeze LT on startup
  • CHANGED: When opening a file from the commandline, each invocation opens a new LightTable app regardless of whether LightTable is already open. To optionally bring back the old behavior, see #2014.
  • FIX: Major usability issues on >= OSX 10.10
  • FIX: Bug in :editor.force.wrap command
  • FIX: Invalid behaviors warning when installing plugin
  • FIX: Uninstalling plugin causes misleading missing dialog to popup
  • FIX: Installing plugins, loads new behaviors immediately
  • FIX: Open files from commandline that have whitespace
  • FIX: Styling for folding
  • FIX: Creating files under folders with '.' in name
  • FIX: Quote and link styling for default theme
  • FIX: Fat cursor not showing up when searching in default theme
  • ADDED: LT can be built from source with provided scripts across supported platforms
  • ADDED: Improved documentation - most core fns have docstrings, all namespaces have docstrings and developer docs
  • ADDED: Most of LT's node libraries are installed as npm dependencies instead of as forked libraries
  • ADDED: Vector format support for workspace behaviors
  • ADDED: Open to line number from commandline e.g. light FILE:LINE
  • ADDED: commandline comes with improved --help
  • ADDED: :lt.objs.editor/load-addon behavior loads CodeMirror addons that ship with LT
  • ADDED: :lt.objs.editor/set-rulers behavior to set CodeMirror rulers - screenshot
  • ADDED: Add file-type definitions for .feature, .rst and many more
  • ADDED: Add F-11 keybinding for fullscreen
  • ADDED: Add pmeta-/ for toggle-comment
  • ADDED: Better error handling for download errors

Builds

  • OSX built on OSX 10.9.5
  • Linux built on Ubuntu 14.04 VirtualBox
  • Windows built on Windows 7

Downloads

Something went wrong with that request. Please try again.
ubuntu-make-16.02.1/tests/data/server-content/github.com/LightTable/LightTable/releases/download/0000775000000000000000000000000012656574623027566 5ustar ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/github.com/LightTable/LightTable/releases/download/mock/ubuntu-make-16.02.1/tests/data/server-content/github.com/LightTable/LightTable/releases/download/moc0000775000000000000000000000000012656574623030265 5ustar ././@LongLink0000644000000000000000000000020300000000000011576 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/github.com/LightTable/LightTable/releases/download/mock/lighttable-mock-linux.tar.gzubuntu-make-16.02.1/tests/data/server-content/github.com/LightTable/LightTable/releases/download/moc0000664000000000000000000000045412656574623030272 0ustar *VKj0)N5z.e/*rڡ]8J\R}K|FV/Ͼ|;[ښmi:Z4 -}k=W4{ Z2{AG%$+#hǭT-}<ǭܬô6n_/rKs/;z5Ny9c 俽Dz[/Q1X44ca1Œ,"#?Uyf bH$?Wubuntu-make-16.02.1/tests/data/server-content/dist.springsource.com/0000775000000000000000000000000012656574623022321 5ustar ubuntu-make-16.02.1/tests/data/server-content/dist.springsource.com/release/0000775000000000000000000000000012656574623023741 5ustar ubuntu-make-16.02.1/tests/data/server-content/dist.springsource.com/release/STS/0000775000000000000000000000000012656574623024412 5ustar ubuntu-make-16.02.1/tests/data/server-content/dist.springsource.com/release/STS/3.7.2.RELEASE/0000775000000000000000000000000012656574623026140 5ustar ubuntu-make-16.02.1/tests/data/server-content/dist.springsource.com/release/STS/3.7.2.RELEASE/dist/0000775000000000000000000000000012656574623027103 5ustar ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/dist.springsource.com/release/STS/3.7.2.RELEASE/dist/e4.5/ubuntu-make-16.02.1/tests/data/server-content/dist.springsource.com/release/STS/3.7.2.RELEASE/dist/e0000775000000000000000000000000012656574623027250 5ustar ././@LongLink0000644000000000000000000000024000000000000011577 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/dist.springsource.com/release/STS/3.7.2.RELEASE/dist/e4.5/spring-tool-suite-3.7.2.RELEASE-e4.5.1-linux-gtk.tar.gzubuntu-make-16.02.1/tests/data/server-content/dist.springsource.com/release/STS/3.7.2.RELEASE/dist/e0000664000000000000000000000046412656574623027256 0ustar VAO0`wЖW<jnHf^cFLƲlès) $OztYt.c0/s9co5}+ OU[ەc~,l*!L?gNߚՑ{SRr#œ8|ӫ(././@LongLink0000644000000000000000000000024700000000000011606 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/dist.springsource.com/release/STS/3.7.2.RELEASE/dist/e4.5/spring-tool-suite-3.7.2.RELEASE-e4.5.1-linux-gtk-x86_64.tar.gzubuntu-make-16.02.1/tests/data/server-content/dist.springsource.com/release/STS/3.7.2.RELEASE/dist/e0000664000000000000000000000047012656574623027253 0ustar ÉVAO0p|wЖիnĻ鶚4:.,c,w)W=U0󥋼S5ct y{ I:֜=.VvԲֶd+ W]]aP]r&C/BsÑ:o6x/_KUVB( Download Stencyl

Download Stencyl 3.1

Build 7305 - May 23rd, 2014



Mac (10.8 and above)



Download

Windows



Download


Having trouble with the newly released 3.1? Let us know.




What's New in Stencyl 3.1?

Summary
Full Changelist

New to Stencyl? Start Here.

Follow our crash course for beginners. You'll be creating games in no time.


Want to publish to iPhone, iPad, Android & Desktop?

Stencyl is free to use for Flash publishing. Publish to iOS, Android, Windows, Mac & Linux by upgrading today.





Are you upgrading from 3.0 or later?

Uninstall your prior copy and install the new version to the same location. There is no upgrade process for games, but as always, you should back them up.


Are you upgrading an existing game from 2.0-2.2?

Read our upgrade guide and be sure to back your games up before opening them in 3.0 (or above).


Can't even run a blank game? (The game shows "Compiling" forever)

See this, then post a question on the forums.


Minimum Requirements

  • Mac OS X 10.8 (Mountain Lion) or later. Stencyl does not work on 10.7 and below.
  • Windows XP or later. Preferably not Vista.
  • Ubuntu 10 or later.

Recommended Requirements

  • Mac OS X 10.9 (Mavericks) or later. You will not be able to publish iPhone or Mac apps with 10.8 or below, starting with Stencyl 3.2.
  • Windows 7 or later. Preferably not Vista.
  • Ubuntu 12 or later.

Where did the sample games go?

They're now available on our Developer Center, so we can update them separately from a release.


Major Known Issues

  • On Mac, you must install Stencyl to a path with *no* spaces or () in it, or games will fail to run.
  • On Mac, project names must contain no spaces or () in it, or they'll fail to run.
  • Games may not auto-start on an iOS Device. You must tap the icon to launch the app when directed.





ubuntu-make-16.02.1/tests/data/server-content/www.stencyl.com/lin0000664000000000000000000000052612656574623021650 0ustar -Un0 @9zhq'}AJGC`~P:D]|&'klLDi#UPƥ@ )hDǚz֮-%3Wխƞ_wwfS9%oo+QEh+*_Ϟc%xM 9F+g RDVu??jiFV/Y>uMn{K/g1 EXEUs$Bc?uR;cRa7a_9&#0<-ÉhgѮ82@ oDϼrubuntu-make-16.02.1/tests/data/server-content/developer.android.com/0000775000000000000000000000000012656574623022240 5ustar ubuntu-make-16.02.1/tests/data/server-content/developer.android.com/android-ndk-r10d-linux-x86.bin0000775000000000000000000000041512656574623027453 0ustar #!/bin/bash echo "Version 32 bits" dest=android-ndk-foo while getopts "o:" opt; do case $opt in o) dest=$OPTARG/$dest ;; esac done mkdir -p $dest for bin in ndk-which ndk-build; do echo "#!/bin/sh" > $dest/$bin chmod +x $dest/$bin done ubuntu-make-16.02.1/tests/data/server-content/developer.android.com/ndk/0000775000000000000000000000000012656574623023014 5ustar ubuntu-make-16.02.1/tests/data/server-content/developer.android.com/ndk/downloads/0000775000000000000000000000000012656574623025006 5ustar ubuntu-make-16.02.1/tests/data/server-content/developer.android.com/ndk/downloads/index.html0000664000000000000000000075625212656574623027024 0ustar Android NDK | Android Developers

Android NDK

Platform Package Size (Bytes) MD5 Checksum
Windows 32-bit android-ndk-r10d-windows-x86.exe 455427281 c0930abfae0c990c4d191cc4ebd46b68
Windows 64-bit android-ndk-r10d-windows-x86_64.exe 472613732 9a33f96da58a7e0b70e47d27b4a880b4
Mac OS X 32-bit android-ndk-r10d-darwin-x86.bin 441545213 0aeb3dc062dc457a4cd01e72eadb2379
Mac OS X 64-bit android-ndk-r10d-darwin-x86_64.bin 442691567 cb101e1e62d56ea75b215f6bc6c27fae
Linux 32-bit (x86) android-ndk-r10d-linux-x86.bin 449997190 47dead9b10b647099f423b9b5dbb5d5f
Linux 64-bit (x86) android-ndk-r10d-linux-x86_64.bin 459151600 3ebcd92b48ebf9b59037836e2cb9b028

The NDK is a toolset that allows you to implement parts of your app using native-code languages such as C and C++. For certain types of apps, this can be helpful so you can reuse existing code libraries written in these languages, but most apps do not need the Android NDK.

Before downloading the NDK, you should understand that the NDK will not benefit most apps. As a developer, you need to balance its benefits against its drawbacks. Notably, using native code on Android generally does not result in a noticable performance improvement, but it always increases your app complexity. In general, you should only use the NDK if it is essential to your app—never because you simply prefer to program in C/C++.

Typical good candidates for the NDK are CPU-intensive workloads such as game engines, signal processing, physics simulation, and so on. When examining whether or not you should develop in native code, think about your requirements and see if the Android framework APIs provide the functionality that you need.

Downloads

Revisions

The following sections provide information about releases of the NDK.

Android NDK, Revision 10d (December 2014)

Important changes:
  • Made GCC 4.8 the default for all 32-bit ABIs. Deprecated GCC 4.6, and will remove it next release. To restore previous behavior, either add NDK_TOOLCHAIN_VERSION=4.6 to ndk-build, or add --toolchain=arm-linux-androideabi-4.6 when executing make-standalone-toolchain.sh on the command line. GCC 4.9 remains the default for 64-bit ABIs.
  • Stopped all x86[_64] toolchains from adding -mstackrealign by default. The NDK toolchain assumes a 16-byte stack alignment. The tools and options used by default enforce this rule. A user writing assembly code must make sure to preserve stack alignment, and ensure that other compilers also comply with this rule. (GCC bug 38496)
  • Added Address Sanitizer functionality to Clang 3.5 support to the ARM and x86 ABIs. For more information on this change, see the Address Sanitizer project.
  • Introduced the requirement, starting from API level 21, to use -fPIE -pie when building. In API levels 16 and higher, ndk-build uses PIE when building. This change has a number of implications, which are discussed in Developer Preview Issue 888. These implications do not apply to shared libraries.
Important bug fixes:
  • Made more fixes related to A53 Errata #835769 in the aarch64-linux-android-4.9 linker. As part of this, GCC passes a new option, --fix-cortex-a53-835769, when -mfix-cortex-a53-835769 (enabled by default) is specified. For more information, see this binutils message and this binutils message.
  • Documented a fix to a libc++ sscanf/vsscanf hang that occurred in API level 21. The fix itself had been implemented in r10c. (Issue 77988)
  • Fixed an AutoFDO (-fauto-profile) crash that occurred with GCC 4.9 when -Os was specified. (Issue 77571)
Other bug fixes:
  • Made the following header and library fixes:
    • Added posix_memalign to API level 16. Also, added a prototype in stdlib.h to API levels 16 to 19. (Issue 77861)
    • Fixed stdatomic.h so that it includes <atomic> only for C++11.
    • Modified the following headers for standalone use: sys/user.h, and gl2ext.h, dlext.h, fts.h, sgidefs.h for API level 21.
    • Modified sys/user.h to rename mxcsr_mask as mxcr_mask, and to change the data type for u_ar0
    • from unsigned long to struct user_regs_struct*.
    • Changed sysconf() return value type from int to long.
  • Fixed ndk-build's handling of thumb for LOCAL_ARM_MODE: In r10d, ndk-build adds LOCAL_LDFLAGS+=-mthumb by default, unless one of the following conditions applies:
    • You have set LOCAL_ARM_MODE equal to arm.
    • You are doing a debug build (with settings such as APP_OPTIM=debug and AndroidManifest.xml containing android:debuggable="true"), where ARM mode is the default in order to retain compatibility with earlier toolchains. (Issue 74040)
  • Fixed LOCAL_SRC_FILES in ndk-build to use Windows absolute paths. (Issue 74333)
  • Removed bash-specific code from ndk-gdb. (Issue 73338)
  • Removed bash-specific code from make-standalone-toolchain.sh. (Issue 74145)
  • Revised documentation concerning a fix for System.loadLibrary() transitive dependencies. (Issue 41790)
  • Fixed a problem that was preventing 64-bit packages from extracting on Ubuntu 14.04 and OS X 10.10 (Yosemite). (Issue 78148)
  • Fixed an issue with LOCAL_PCH to improve Clang support. (Issue 77575)
  • Clarified "requires executable stack" warning from ld.gold. (Issue 79115)

Android NDK, Revision 10c (October 2014)

Important changes:
  • Made the following changes to download structure:
    • Each package now contains both the 32- and the 64-bit headers, libraries, and tools for its respective platform.
    • STL libraries with debugging info no longer need be downloaded separately.
  • Changed everything previously called Android-L to the official release designation: android-21.
  • Updated GCC 4.9 by rebasing to the google branch of the GCC repository. Major differences from the upstream version of GCC 4.9 include:
    • The -O2 option now turns on vectorization, without loop peeling but with more aggressive unrolling.
    • Enhancements to FDO and LIPO
    • For more detailed information, see Important bug fixes below.

  • Added Clang 3.5 support to all hosts: NDK_TOOLCHAIN_VERSION=clang now picks Clang 3.5. Note that:
    • ARM and x86 default to using the integrated assembler. If this causes issues, use -fno-integrated-as as a workaround.
    • Clang 3.5 issues more warnings for unused flags, such as the -finline-functions option that GCC supports.
    • When migrating from projects using GCC, you can use -Wno-invalid-command-line-argument and -Wno-unused-command-line-argument to ignore the unused flags until you're able decide on what to do with them longer-term.

  • Made it possible to enter ART debugging mode, when debugging on an Android 5.0 device using ART as its virtual machine, by specifying the art-on option. For more information, see prebuilt/common/gdb/common.setup in the directory containing the NDK.
  • Removed support for Clang 3.3.
  • Deprecated GCC 4.6, and may remove it from future releases.
  • Updated mclinker to 2.8 with Identical Code Folding ("ICF") support. Specify ICF using the --icf option.
  • Broadened arm_neon.h support in x86 and x86_64, attaining coverage of ~93% of NEON intrinsics. For more information about NEON support:
    • Navigate to the NDK Programmer's Guide (docs/Programmers_Guide/html/), and see Architectures and CPUs > Neon.
    • Examine the updated hello-neon sample in samples/.
    • See Intel's guide to porting from ARM NEON to Intel SSE.
  • Documented support for _FORTIFY_SOURCE in headers/libs/android-21, which appeared in r10 (when android-21 was still called Android-L), but had no documentation.
Important bug fixes:
Other bug fixes:
  • Made the following header and library fixes to android-21:
    • Added more TV keycodes: android/keycodes.h
    • Added more constants and six new sensor functions to android/sensor.h: ASensorManager_getDefaultSensorEx, ASensor_getFifoMaxEventCount, ASensor_getFifoReservedEventCount, ASensor_getStringType, ASensor_getReportingMode, and ASensor_isWakeUpSensor.
    • Fixed stdatomic.h to improve compatibility with GCC 4.6, and provide support for the <atomic> header.
    • Added sys/ucontext.h and sys/user.h to all API levels. The signal.h header now includes <sys/ucontext.h>. You may remove any existing definition of struct ucontext.
    • Added posix_memalign to API levels 17, 18, and 19.
    • Added the following functions to all architectures: android_set_abort_message, posix_fadvise, posix_fadvise64, pthread_gettid_np.
    • Added the required permissions to the native-media/AndroidManifest.xml sample. (Issue 106640)
    • Added clock_nanosleep and clock_settime to API level 21. (Issue 77372)
    • Removed the following symbols from all architectures: get_malloc_leak_info, free_malloc_leak_info, __srget, __swbuf, __srefill, __swsetup, __sdidinit, __sflags, __sfp, __sinit, __smakebuf, __sflush, __sread, __swrite, __sseek, __sclose, _fwalk, __sglue, __get_thread, __wait4, __futex_wake, __open, __get_tls, __getdents64, and dlmalloc.
    • Removed the following functions from the 64-bit architectures: basename_r, dirname_r, __isthreaded, _flush_cache (mips64).
    • Removed the following function from the 32-bit architectures: __signalfd4.
    • Changed the type of the third argument from size_t to int in the following functions: strtoll_l, strtoull_l, wcstoll_l, and wcstoull_l.
    • Restored the following functions to the 64-bit architecture: arc4random, arc4random_buf, and arc4random_uniform.
    • Moved cxa_* and the new and delete operators back to libstdc++.so. This change restores r9d behavior; previous versions of r10 contained dummy files.
  • Restored MXU support in GCC 4.8 and 4.9 for mips. This support had been absent from r10 and r10b because those versions of GCC had been compiled with binutils-2.24, which did not support MXU. It now does.
  • Fixed --toolchain= in make-standalone-toolchain.sh so that it now properly supports use of a suffix specifying a version of Clang.
  • Fixed the libc++/armeabi strtod() functions.
  • Made fixes to NDK documentation in docs/.
Other changes:
  • Enhanced cpu-features to detect ARMv8 support for the following instruction sets: AES, CRC32, SHA2, SHA1, and 64-bit PMULL/PMULL2. (Issue 106360)
  • Modified ndk-build to use *-gcc-ar, which is available in GCC 4.8, GCC 4.9, and Clang. Clang specifies it, instead of *-ar. This setting brings improved LTO support.
  • Removed the include-fixed/linux/a.out.h and include-fixed/linux/compiler.h headers from the GCC compiler. (Issue 73728)
  • Fixed an issue related to -flto with GCC 4.8 on Mac OS X. The error message read:
  • .../ld: error: .../libexec/gcc/arm-linux-androideabi/4.9/liblto_plugin.so
    Symbol not found: _environ
    
  • Fixed a typo in build-binary.mk. (Issue 76992)
Important known issues:
  • Specifying -Os (-fauto-profile) in GCC4.9 may cause crashing. (Issue 77571)

Android NDK, Revision 10b (September 2014)

Important notes:
  • Because of the 512MB size restriction on downloadable packages, the following 32-bit items are not in the 32-bit NDK download packages. Instead, they reside in the 64-bit ones:
    • Android-L headers
    • GCC 4.9
  • Currently, the only Renderscript support provided by the NDK is for 32-bit Renderscript with Android 4.4 (API level 19). You cannot build HelloComputeNDK (the only Renderscript sample) with any other combination of Renderscript (32- or 64-bit) and Android version.
  • To compile native-codec, you must use a 64-bit NDK package, which is where all the Android-L headers are located.
Important bug fixes:
  • Fixed gdb 7.6 in GCC 4.8/4.9. (Issues 74112 and 74371.)
  • Fixed GCC 4.8/4.9 for x86, so that they no longer enable -msse4.2 and -mpopcnt by default. (Issue 73843.)
Other bug fixes:
  • Removed stdio.h from the include-fixed/ directories of all versions of GCC. (Issue 73728.)
  • Removed duplicate header files from the Windows packages in the platforms/android-L/arch-*/usr/include/linux/netfilter*/ directories. (Issue 73704.)
  • Fixed a problem that prevented Clang from building HelloComputeNDK.
  • Fixed atexit. (Issue 66595.)
  • Made various fixes to the docs in docs/ and sources/third_party/googletest/README.NDK. (Issue 74069.)
  • Made the following fixes to the Android-L headers:
    1. Added the following functions to ctype.h and wchar.h: dn_expand(), grantpt(), inet_nsap_addr(), inet_nsap_ntoa(), insque(), nsdispatch(), posix_openpt(), __pthread_cleanup_pop(), __pthread_cleanup_push(), remque(), setfsgid(), setfsuid(), splice(), tee(), twalk() (Issue 73719), and 42 *_l() functions.
    2. Renamed cmsg_nxthdr to __cmsg_nxthdr.
    3. Removed __libc_malloc_dispatch.
    4. Changed the ptrace() prototype to long ptrace(int, ...);.
    5. Removed sha1.h.
    6. Extended android_dlextinfo in android/dlext.h.
    7. Annotated __NDK_FPABI__ for functions receiving or returning float- or double-type values in stdlib.h, time.h, wchar.h, and complex.h.
Other changes:
  • Updated mipsel-linux-android-4.9 and mips64el-linux-android-4.9, implementing a new multilib directory layout, and providing support for gdb-7.7
  • Enhanced cpu-features to detect more arm64 features. (Change list 100339.)

Android NDK, Revision 10 (July 2014)

Important changes:
  • Added 3 new ABIs, all 64-bit: arm64-v8a, x86_64, mips64.
  • Note that:
    • GCC 4.9 is the default compiler for 64-bit ABIs. Clang is currently version 3.4. NDK_TOOLCHAIN_VERSION=clang may not work for arm64-v8a and mips64.
    • Android-L is the first level with 64-bit support. Note that this API level is a temporary one, and only for L-preview. An actual API level number will replace it at L-release.
    • This release includes now includes all32 and all64 settings for APP_ABI.
      • APP_ABI=all32 is equivalent to APP_ABI=armeabi,armeabi-v7a,x86,mips.
      • APP_ABI=all64 is equivalent to APP_ABI=arm64-v8a,x86_64,mips64.
      • APP_ABI=all selects all ABIs.
    • The new GNU libstdc++ in Android-L contains all <tr1/cmath> Before defining your own math function, check _GLIBCXX_USE_C99_MATH_TR1 to see a function with that name already exists, in order to avoid "multiple definition" errors from the linker.
    • The cpu-features library has been updated for the ARMv8 kernel. The existing cpu-features library may fail to detect the presence of NEON on the ARMv8 platform. Recompile your code with the new version.
  • Added a new platforms/android-L/ API directory. It includes:
    • Updated Bionic headers, which had not changed from Android API levels 3 (Cupcake) to 19 (KitKat). This new version, for level L, is to be synchronized with AOSP.
    • New media APIs and a native-codec sample.
    • An updated Android.h header for SLES/OpenSLES, enabling support for single-precision, floating-point audio format in AudioPlayer.
    • GLES 3.1 and AEP extensions to libGLESv3.so.
    • GLES2 and GLES3 headers updated to the latest official Khronos versions.
  • Added GCC 4.9 compilers to the 32-/64-bit ABIs. GCC 4.9 is the default (only) compiler for 64-bit ABIs, as previously mentioned. For 32-bit ABIs, you must explcitly enable GCC 4.9, as GCC 4.6 is still the default.
    • For ndk-build, enable 32-bit, GCC 4.9 building either by adding NDK_TOOLCHAIN_VERSION=4.9 to Application.mk, or exporting it as an environment variable from the command line.
    • For a standalone toolchain, use the --toolchain= option in the make-standalone-toolchain.sh script. For example: --toolchain=arm-linux-androideabi-4.9.
  • Upgraded GDB to version 7.6 in GCC 4.8/4.9 and x86*. Since GDB is still at version GDB-7.3.x in GCC 4.6 (the default for ARM and MIPS), you must set NDK_TOOLCHAIN_VERSION=4.8 or 4.9 to enable ndk-gdb to select GDB 7.6.
  • Added the -mssse3 build option to provide SSSE3 support, and made it the default for ABI x86 (upgrading from SSE3). The image released by Google does not contain SSSE3 instructions.
  • Updated GCC 4.8 to 4.8.3.
  • Improved ARM libc++ EH support by switching from gabi++ to libc++abi. For details, see the "C++ Support" section of the documentation. Note that:
    • All tests except for locale now pass for Clang 3.4 and GCC 4.8. For more information, see the "C++ Support" section of the documentation.
    • The libc++ libraries for X86 and MIPS libc++ still use gabi++.
    • GCC 4.7 and later can now use <atomic>.
    • You must add -fno-strict-aliasing if you use <list>, because __list_imp::_end_ breaks TBAA rules. (Issue 61571.)
    • As of GCC 4.6, LIBCXX_FORCE_REBUILD:=true no longer rebuilds libc++. Rebuilding it requires the use of a different compiler. Note that Clang 3.3 is untested.
  • mclinker is now version 2.7, and has aarch64 Linux support.
  • Added precompiled header support for headers specified by LOCAL_PCH. (Issue 25412).
Important bug fixes:
  • Fixed libc++ so that it now compiles std::feof, etc. (Issue 66668).
  • Fixed a Clang 3.3/3.4 atomic library call that caused crashes in some of the libc++ tests for ABI armeabi.
  • Fixed Clang 3.4 crashes that were occurring on reading precompiled headers. (Issue 66657).
  • Fixed the Clang 3.3/3.4 -O3 assert on:
  • llvm-3.2/llvm/include/llvm/MDBuilder.h:64: llvm::MDNode* llvm::MDBuilder::createBranchWeights(llvm::ArrayRef): Assertion Weights.size() >= 2 && "Need at least two branch weights!" (Issue 57381).
  • Fixed the following Clang 3.3/3.4 crash:
  • Assertion failed: (!Fn && "cast failed but able to resolve overload expression!!"), function CheckCXXCStyleCast, file Volumes/data/ndk-toolchain/src/llvm-3.3/llvm/tools/clang/lib/Sema/SemaCast.cpp, line 2018. (Issue 66950).
Other bug fixes:
  • Fixed headers:
    • Fixed 32-bit ssize_t to be int instead of long int.
    • Fixed WCHAR_MIN and WCHAR_MAX so that they they take appropriate signs according to the architecture they're running on:
      • X86/MIPS: signed.
      • ARM: unsigned.
      • To force X86/MIPS to default to unsigned, use -D__WCHAR_UNSIGNED__.
      • To force wchar_t to be 16 bits, use -fshort-wchar.
    • Removed non-existent symbols from 32-bit libc.so, and added pread64, pwrite64, ftruncate64 for Android API level 12 and higher. (Issue 69319). For more information, see the commit message accompanying AOSP change list 94137.
  • Fixed GCC warning about redefinition of putchar. Warning message reads:
  • include/stdio.h:236:5: warning: conflicts with previous declaration here [-Wattributes] int putchar(int); (Change list 91185).
  • Fixed make-standalone-toolchain.sh --stl=libc++ so that it:
    • Copies cxxabi.h. (Issue 68001).
    • Runs in directories other than the NDK install directory. (Issues 67690 and 68647).
  • Fixed GCC/Windows to quote arguments only when necessary for spawning processes in external programs. This change decreases the likelihood of exceeding the 32K length limit.
  • Fixed an issue that made it impossible to adjust the APP_PLATFORM environment variable.
  • Fixed the implementation of IsSystemLibrary() in crazy_linker so that it uses strrchr() instead of strchr() to find the library path's true basename.
  • Fixed native-audio's inability to build in debug mode.
  • Fixed gdb's inability to print extreme floating-point numbers. (Issue 69203).
  • Fixed Clang 3.4 inability to compile with -Wl,-shared (as opposed to -shared, which had no compilation issues). The problem was that Clang added -pie for Android targets if neither -shared nor -static existed. This behavior, which was incorrect, caused the linker to complain that -shared and -pie could not co-exist.
Other changes:
  • Added arm_neon.h to the x86 toolchain so that it now emulates ~47% of Neon. There is currently no support for 64-bit types. For more information, see the section on ARM Neon intrinsics support in the x86 documentation.
  • Ported ARM/GOT_PREL optimization (present in GCC 4.6 built from the GCC google branch) to ARM GCC 4.8/4.9. This optimization sometimes reduces instruction count when accessing global variables. As an example, see the build.sh script in $NDK/tests/build/b14811006-GOT_PREL-optimization/.
  • Added ARM version for STL gabi++, stlport, and libc++. They now have both it and Thumb mode.
  • It is now possible to call the make-standalone-toolchain.sh script with --toolchain=x86_64-linux-android-4.9, which is equivalent to --toolchain=x86_64-4.9.

Android NDK, Revision 9d (March 2014)

Important changes:
  • Added support for the Clang 3.4 compiler. The NDK_TOOLCHAIN_VERSION=clang option now picks Clang 3.4. GCC 4.6 is still the default compiler.
  • Added APP_ABI=armeabi-v7a-hard, with additional multilib option -mfloat-abi=hard. These options are for use with ARM GCC 4.6/4.8 and Clang 3.3/3.4 (which use 4.8's assembler, linker, and libs). When using these options, note the following changes:
    • When executing the ndk-build script, add the following options for armeabi-v7a target:
      TARGET_CFLAGS += -mhard-float -D_NDK_MATH_NO_SOFTFP=1
      TARGET_LDFLAGS += -Wl,--no-warn-mismatch -lm_hard
      The built library is copied to libs/armeabi-v7a. For make to behave as expected, you cannot specify both armeabi-v7a and armeabi-v7a-hard as make targets (i.e., on the APP_ABI= line). Doing so causes one of them to be ignored. Note that APP_ABI=all is still equivalent to armeabi armeabi-v7a x86 mips.
    • The make-standalone-toolchain.sh script copies additional libaries under /hard directories. Add the above CFLAGS and LFLAGS to your makefile to enable GCC or Clang to link with libraries in /hard.
  • Added the yasm assembler, as well as LOCAL_ASMFLAGS and EXPORT_ASMFLAGS flags for x86 targets. The ndk-build script uses prebuilts/*/bin/yasm* to build LOCAL_SRC_FILES that have the .asm extension.
  • Updated MClinker to 2.6.0, which adds -gc-sections support.
  • Added experimental libc++ support (upstream r201101). Use this new feature by following these steps:
    • Add APP_STL := c++_static or APP_STL := c++_shared in Application.mk. You may rebuild from source via LIBCXX_FORCE_REBUILD := true
    • Execute make-standalone-toolchain.sh --stl=libc++ to create a standalone toolchain with libc++ headers/lib.
    For more information, see CPLUSPLUS-SUPPORT.html. (Issue 36496)
Important bug fixes:
  • Fixed an uncaught throw from an unexpected exception handler for GCC 4.6/4.8 ARM EABI. (GCC Issue 59392)
  • Fixed GCC 4.8 so that it now correctly resolves partial specialization of a template with a dependent, non-type template argument. (GCC Issue 59052)
  • Added more modules to prebuilt python (Issue 59902):
    • Mac OS X: zlib, bz2, _curses, _curses_panel, _hashlib, _ssl
    • Linux: zlib, nis, crypt, _curses, and _curses_panel
  • Fixed the x86 and MIPS gdbserver event_getmsg_helper.
  • Fixed numerous issues in the RenderScript NDK toolchain, including issues with compatibility across older devices and C++ reflection.

Other bug fixes:
  • Header fixes:
    • Fixed a missing #include <sys/types.h> in android/asset_manager.h for Android API level 13 and higher. (Issue 64988)
    • Fixed a missing #include in android/rect_manager.h for Android API level 14 and higher.
    • Added JNICALL to JNI_OnLoad and JNI_OnUnload in jni.h. Note that JNICALL is defined as __NDK_FPABI__ For more information, see sys/cdefs.h.
    • Updated the following headers so that they can be included without the need to manually include their dependencies (Issue 64679):
    • android/tts.h
      EGL/eglext.h
      fts.h
      GLES/glext.h
      GLES2/gl2ext.h
      OMXAL/OpenMAXSL_Android.h
      SLES/OpenSLES_Android.h
      sys/prctl.h
      sys/utime.h
      
    • Added sys/cachectl.h for all architectures. MIPS developers can now include this header instead of writing #ifdef __mips__.
    • Fixed platforms/android-18/include/android/input.h by adding __NDK_FPABI__ to functions taking or returning float or double values.
    • Fixed MIPS struct stat, which was incorrectly set to its 64-bit counterpart for Android API level 12 and later. This wrong setting was a regression introduced in release r9c.
    • Defined __PTHREAD_MUTEX_INIT_VALUE, __PTHREAD_RECURSIVE_MUTEX_INIT_VALUE, and __PTHREAD_ERRORCHECK_MUTEX_INIT_VALUE for Android API level 9 and lower.
    • Added scalbln, scalblnf, and scalblnl to x86 libm.so for APIs 18 and later.
    • Fixed a typo in sources/android/support/include/iconv.h. (Issue 63806)
  • Fixed gabi++ std::unexpected() to call std::terminate() so that a user-defined std::terminate() handler has a chance to run.
  • Fixed gabi++ to catch std::nullptr.
  • Fixed samples Teapot and MoreTeapots:
    • Solved a problem with Tegra 2 and 3 chips by changing specular variables to use medium precision. Values for specular power can now be less than 1.0.
    • Changed the samples so that pressing the volume button restores immersive mode and invalidates SYSTEM_UI_FLAG_IMMERSIVE_STICKY. Screen rotation does not trigger onSystemUiVisibilityChange, and so does not restore immersive mode.
  • Fixed the ndk-build script to add -rpath-link=$SYSROOT/usr/lib and -rpath-link=$TARGET_OUT in order to use ld.bfd to link executables. (Issue 64266)
  • Removed -Bsymbolic from all STL builds.
  • Fixed ndk-gdb-py.cmd by setting SHELL as an environment variable instead of passing it to python.exe, which ignores the setting. (Issue 63054)
  • Fixed the make-standalone-toolchain.sh script so that the --stl=stlport option copies the gabi++ headers instead of symlinking them; the cmd.exe and MinGW shells do not understand symlinks created by cygwin.
Other changes:
  • Applied execution permissions to all *cmd scripts previously intended for use only in the cmd.exe shell, in case developers prefer to use ndk-build.cmd in cygwin instead of the recommended ndk-build script.
  • Improved the speed of the make-standalone-toolchain.sh script by moving instead of copying if the specified destination directory does not exist.

Android NDK, Revision 9c (December 2013)

This is a bug-fix-only release.

Important bug fixes:
  • Fixed a problem with GCC 4.8 ARM, in which the stack pointer is restored too early. This problem prevented the frame pointer from reliably accessing a variable in the stack frame. (GCC Issue 58854)
  • Fixed a problem with GCC 4.8 libstdc++, in which a bug in std::nth_element was causing generation of code that produced a random segfault. (Issue 62910)
  • Fixed GCC 4.8 ICE in cc1/cc1plus with -fuse-ld=mcld, so that the following error no longer occurs:
    cc1: internal compiler error: in common_handle_option, at
    opts.c:1774
  • Fixed -mhard-float support for __builtin math functions. For ongoing information on fixes for -mhard-float with STL, please follow Issue 61784.
Other bug fixes:
  • Header fixes:
    • Changed prototype of poll to poll(struct pollfd *, nfds_t, int); in poll.h.
    • Added utimensat to libc.so for Android API levels 12 and 19. These libraries are now included for all Android API levels 12 through 19.
    • Introduced futimens into libc.so, for Android API level 19.
    • Added missing clock_settime() and clock_nanosleep() to time.h for Android API level 8 and higher.
    • Added CLOCK_MONOTONIC_RAW, CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC_COARSE, CLOCK_BOOTTIME, CLOCK_REALTIME_ALARM, and CLOCK_BOOTTIME_ALARM in time.h.
    • Removed obsolete CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR.
  • In samples Teapot, MoreTeapots, and source/android/ndk_helper:
    • Changed them so that they now use a hard-float abi for armeabi-v7a.
    • Updated them to use immersive mode on Android API level 19 and higher.
    • Fixed a problem with Check_ReleaseStringUTFChars in /system/lib/libdvm.so that was causing crashes on x86 devices.
  • Fixed ndk-build fails that happen in cygwin when the NDK package is referenced via symlink.
  • Fixed ndk-build.cmd fails that happen in windows cmd.exe when LOCAL_SRC_FILES contains absolute paths. (Issue 69992)
  • Fixed the ndk-stack script to proceed even when it can't parse a frame due to inability to find a routine, filename, or line number. In any of these cases, it prints ??.
  • Fixed the ndk-stack stack for windows-x64_64 targets so that it no longer erroneously matches a frame line with a line in the stack: section that doesn't contain pc, eip, or ip. For example:
    I/DEBUG   ( 1151):     #00  5f09db68  401f01c4
    /system/lib/libc.so
  • Fixed gabi++ so that it:
    • Does not use malloc() to allocate C++ thread-local objects.
    • Avoids deadlocks in gabi++ in cases where libc.debug.malloc is non-zero in userdebug/eng Android platform builds.
Other changes:
  • Added LOCAL_EXPORT_LDFLAGS.
  • Introduced the NDK_PROJECT_PATH=null setting for use in an integrated build system where options are explicitly passed to ndk-build. With this setting, ndk-build makes no attempt to look for NDK_PROJECT_PATH. This setting also prevents variables from deriving default settings from NDK_PROJECT_PATH. As a result, the following variables must now be explicitly specified (with their default values if such exist): NDK_OUT, NDK_LIBS_OUT, APP_BUILD_SCRIPT, NDK_DEBUG (optional, default to 0), and other APP_*'s contained in Application.mk.
  • APP_ABI can now be enumerated in a comma-delimited list. For example:
    APP_ABI := "armeabi,armeabi-v7a"
  • Provided the ability to rebuild all of STL with debugging info in an optional, separate package called android-ndk-r9c-cxx-stl-libs-with-debugging-info.zip, using the -g option. This option helps the ndk-stack script provide better a stack dump across STL. This change should not affect the code/size of the final, stripped file.
  • Enhanced hello-jni samples to report APP_ABI at compilation.
  • Used the ar tool in Deterministic mode (option -D) to build static libraries. (Issue 60705)

Android NDK, Revision 9b (October 2013)

Important changes:
  • Updated include/android/*h and math.h for all Android API levels up to 18, including the addition of levels 13, 15, 16 and 17. For information on added APIs, see commit messages for Changes 68012 and 68014. (Issues 47150, 58528, and 38423)
  • Added support for Android API level 19, including Renderscript binding.
  • Added support for -mhard-float in the existing armeabi-v7a ABI. For more information and current restrictions on Clang, see tests/device/hard-float/jni/Android.mk.
  • Migrated from GNU Compiler Collection (GCC) 4.8 to 4.8.2, and added diagnostic color support. To enable diagnostic colors, set -fdiagnostics-color=auto, -fdiagnostics-color=always, or export GCC_COLORS as shown below:
    GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
    
    For more information, see GCC Language Independent Options.
  • Added two new samples to demonstrate OpenGL ES 3.0 features: Teapot and MoreTeapots. These samples run on devices with Android 4.1 (API level 16) and higher.
  • Deprecated GCC 4.7 and Clang 3.2 support, which will be removed in the next release.
Important bug fixes:
  • Fixed problem with ARM GCC 4.6 thumb2 failing to generate 16-bit relative jump tables. (GCC Issue)
  • Fixed GCC 4.8 internal compiler error (ICE) on g++.dg/cpp0x/lambda/lambda-defarg3.C. (Change 62770, GCC Issue)
  • Fixed a problem with Windows 32-bit *-gdb.exe executables failing to launch. (Issue 58975)
  • Fixed GCC 4.8 ICE when building bullet library. The error message is as follows:
    internal compiler error: verify_flow_info failed
    (Issue 58916, GCC Issue)
  • Modified GDB/ARM build to skip ARM.exidx data for unwinding in prologue code and added a command (set arm exidx-unwinding) to control exidx-based stack unwinding. (Issue 55826)
  • Fixed Clang 3.3 MIPS compiler problem where HI and LO registers are incorrectly reused.
  • Fixed issue with MIPS 4.7 ICE in dbx_reg_number. The error message is as follows:
    external/icu4c/i18n/decimfmt.cpp:1322:1:
    internal compiler error: in dbx_reg_number, at dwarf2out.c:10185
    
    (GCC Patch)
Other bug fixes:
  • Header fixes
    • Fixed the ARM WCHAR_MIN and WCHAR_MAX to be unsigned according to spec (the X86/MIPS versions are signed). Define _WCHAR_IS_ALWAYS_SIGNED to restore old behavior. (Issue 57749)
    • Fixed include/netinet/tcp.h to contain TCP_INFO state enum. (Issue 38881)
    • Fixed the cdefs_elh.h macro _C_LABEL_STRING to stop generating warnings in the GCC 4.8 toolchain when using c++11 mode. (Issue 58135, Issue 58652)
    • Removed non-existent functions imaxabs and imaxdiv from header inttypes.h.
    • Fixed issue with pthread_exit() return values and pthread_self(). (Issue 60686)
    • Added missing mkdtemp() function, which already exists in bionic header stdlib.h.
  • Fixed problem building samples/gles3jni with Clang on Android API level 11.
  • Fixed MCLinker to allow multiple occurrences of the following options: -gc-sections and --eh-frame-hdr.
  • Fixed MCLinker to accept the --no-warn-mismatch option.
  • Modified cpu-features option to not assume all VFPv4 devices support IDIV. Now this option only adds IDIV to white-listed devices, including Nexus 4. (Issue 57637)
  • Fixed problem with android_native_app_glue.c erroneously logging errors on event predispatch operations.
  • Fixed all operations on gabi++ terminate and unexpected_handler to be thread-safe.
  • Fixed several issues with Clang -integrated-as option so it can pass tests for ssax-instructions and fenv.
  • Fixed GCC 4.6/4.7/4.8 compiler to pass the linker option --eh-frame-hdr even for static executables. For more information, see the GCC patch.
  • Fixed extra apostrophe in CPU-ARCH-ABIS.html. For more information, see NDK-DEPENDS.html. (Issue 60142)
  • Fixed extra quotes in ndk-build output on Windows. (Issue 60649)
  • Fixed Clang 3.3 to compile ARM's built-in, atomic operations such as __atomic_fetch_add, __atomic_fetch_sub, and __atomic_fetch_or.
  • Fixed Clang 3.3 ICE with customized vfprintf. (Clang issue)
Other changes:
  • Enabled OpenMP for all GCC builds. To use this feature, add the following flags to your build settings:
    LOCAL_CFLAGS += -fopenmp
    LOCAL_LDFLAGS += -fopenmp
    
    For code examples, see tests/device/test-openmp
  • Reduced the size of ld.mcld significantly (1.5MB vs. ld.bfd 3.5MB and ld.gold 7.5MB), resulting in a speed improvement of approximately 20%.
  • Added LOCAL_CONLYFLAGS and APP_CONLYFLAGS to specify options applicable to C only but not C++. The existing LOCAL_CFLAGS and APP_CFLAGS are also used for C++ compilation (to save trouble of specifying most options twice), so options such as -std=gnu99 may fail in g++ builds with a warning and clang++ builds with an error.
  • Added gabi++ array helper functions.
  • Modified GCC builds so that all libgcc.a files are built with -funwind-tables to allow the stack to be unwound past previously blocked points, such as __aeabi_idiv0.
  • Added Ingenic MXU support in MIPS GCC4.6/4.7/4.8 with new -mmxu option.
  • Extended MIPS GCC4.6/4.7/4.8 -mldc1-sdc1 to control ldxc1/sdxc1 too
  • Added crazy linker. For more information, see sources/android/crazy_linker/README.TXT.
  • Fixed bitmap-plasma to draw to full screen rather than a 200x200 pixel area.
  • Reduced linux and darwin toolchain sizes by 25% by creating symlinks to identical files.

Android NDK, Revision 9 (July 2013)

Important changes:
  • Added support for Android 4.3 (API level 18). For more information, see STABLE-APIS.html and new code examples in samples/gles3jni/README.
  • Added headers and libraries for OpenGL ES 3.0, which is supported by Android 4.3 (API level 18) and higher.
  • Added GNU Compiler Collection (GCC) 4.8 compiler to the NDK. Since GCC 4.6 is still the default, you must explicitly enable this option:
    • For ndk-build builds, export NDK_TOOLCHAIN_VERSION=4.8 or add it in Application.mk.
    • For standalone builds, use the --toolchain= option in make-standalone-toolchain.sh, for example:
      --toolchain=arm-linux-androideabi-4.8

    Note: The -Wunused-local-typedefs option is enabled by -Wall. Be sure to add __attribute__((unused)) if you use compile-time asserts like sources/cxx-stl/stlport/stlport/stl/config/features.h, line #311. For more information, see Change 55460

    Note: In the GCC 4.7 release and later, ARM compilers generate unaligned access code by default for ARMv6 and higher build targets. You may need to add the -mno-unaligned-access build option when building for kernels that do not support this feature.

  • Added Clang 3.3 support. The NDK_TOOLCHAIN_VERSION=clang build option now picks Clang 3.3 by default.

    Note: Both GCC 4.4.3 and Clang 3.1 are deprecated, and will be removed from the next NDK release.

  • Updated GNU Project Debugger (GDB) to support python 2.7.5.
  • Added MCLinker to support Windows hosts. Since ld.gold is the default where available, you must add -fuse-ld=mcld in LOCAL_LDFLAGS or APP_LDFLAGS to enable MCLinker.
  • Added ndk-depends tool which prints ELF library dependencies. For more information, see NDK-DEPENDS.html. (Issue 53486)
Important bug fixes:
  • Fixed potential event handling issue in android_native_app_glue. (Issue 41755)
  • Fixed ARM/GCC-4.7 build to generate sufficient alignment for NEON load and store instructions VST and VLD. (GCC Issue 57271)
  • Fixed a GCC 4.4.3/4.6/4.7 internal compiler error (ICE) for a constant negative index value on a string literal. (Issue 54623)
  • Fixed GCC 4.7 segmentation fault for constant initialization with an object address. (Issue 56508)
  • Fixed GCC 4.6 ARM segmentation fault for -O values when using Boost 1.52.0. (Issue 42891)
  • Fixed libc.so and libc.a to support the wait4() function. (Issue 19854)
  • Updated the x86 libc.so and libc.a files to include the clone() function.
  • Fixed LOCAL_SHORT_COMMANDS bug where the linker.list file is empty or not used.
  • Fixed GCC MIPS build on Mac OS to use CFI directives, without which ld.mcld --eh-frame-hdr fails frequently.
  • Fixed Clang 3.2 X86/MIPS internal compiler error in llvm/lib/VMCore/Value.cpp. (Change 59021)
  • Fixed GCC 4.7 64-bit Windows assembler crash. (Error: out of memory allocating 4294967280 bytes).
  • Updated ndk-gdb script so that the --start or --launch actions now wait for the GNU Debug Server, so that it can more reliably hit breakpoints set early in the execution path (such as breakpoints in JNI code). (Issue 41278)

    Note: This feature requires jdb and produces warning about pending breakpoints. Specify the --nowait option to restore previous behavior.

  • Fixed GDB crash when library list is empty.
  • Fixed GDB crash when using a stepi command past a bx pc or blx pc Thumb instruction. (Issue 56962, Issue 36149)
  • Fixed MIPS gdbserver to look for DT_MIPS_RLD_MAP instead of DT_DEBUG. (Issue 56586)
  • Fixed a circular dependency in the ndk-build script, for example: If A->B and B->B, then B was dropped from build. (Issue 56690)
Other bug fixes:
  • Fixed the ndk-build script to enable you to specify a version of Clang as a command line option (e.g., NDK_TOOLCHAIN_VERSION=clang3.2). Previously, only specifying the version as an environment variable worked.
  • Fixed gabi++ size of _Unwind_Exception to be 24 for MIPS build targets when using the Clang compiler. (Change 54141)
  • Fixed the ndk-build script to ensure that built libraries are actually removed from projects that include prebuilt static libraries when using the ndk-build clean command. (Change 54461, Change 54480)
  • Modified the NDK_ANALYZE=1 option to be less verbose.
  • Fixed gnu-libstdc++/Android.mk to include a backward/ path for builds that use backward compability. (Issue 53404)
  • Fixed a problem where stlport new sometimes returned random values.
  • Fixed ndk-gdb to match the order of CPU_ABIS, not APP_ABIS. (Issue 54033)
  • Fixed a problem where the NDK 64-bit build on MacOSX choses the wrong path for compiler. (Issue 53769)
  • Fixed build scripts to detect 64-bit Windows Vista. (Issue 54485)
  • Fixed x86 ntonl/swap32 error: invalid 'asm': operand number out of range. (Issue 54465, Change 57242)
  • Fixed ld.gold to merge string literals.
  • Fixed ld.gold to handle large symbol alignment.
  • Updated ld.gold to enable the --sort-section=name option.
  • Fixed GCC 4.4.3/4.6/4.7 to suppress the -export-dynamic option for statically linked programs. GCC no longer adds an .interp section for statically linked programs.
  • Fixed GCC 4.4.3 stlport compilation error about inconsistent typedef of _Unwind_Control_Block. (Issue 54426)
  • Fixed awk scripts to handle AndroidManifest.xml files created on Windows which may contain trailing \r characters and cause build errors. (Issue 42548)
  • Fixed make-standalone-toolchain.sh to probe the prebuilts/ directory to detect if the host is 32 bit or 64 bit.
  • Fixed the Clang 3.2 -integrated-as option.
  • Fixed the Clang 3.2 ARM EHABI compact model pr1 and pr2 handler data.
  • Added Clang -mllvm -arm-enable-ehabi option to fix the following Clang error:
    clang: for the -arm-enable-ehabi option: may only occur zero or one times!
  • Fixed build failure when there is no uses-sdk element in application manifest. (Issue 57015)
Other changes:
  • Header Fixes
    • Modified headers to make __set_errno an inlined function, since __set_errno in errno.h is deprecated, and libc.so no longer exports it.
    • Modified elf.h to include stdint.h. (Issue 55443)
    • Fixed sys/un.h to be included independently of other headers. (Issue 53646)
    • Fixed all of the MotionEvent_getHistorical API family to take the const AInputEvent* motion_event. (Issue 55873)
    • Fixed malloc_usable_size to take const void*. (Issue 55725)
    • Fixed stdint.h to be more compatible with C99. (Change 46821)
    • Modified wchar.h to not redefine WCHAR_MAX and WCHAR_MIN
    • Fixed <inttypes.h> declaration for pointer-related PRI and SCN macros. (Issue 57218)
    • Changed the sys/cdefs.h header so that __WCHAR_TYPE__ is 32-bit for API levels less than 9, which means that wchat_t is 32-bit for all API levels. To restore the previous behavior, define the _WCHAR_IS_8BIT boolean variable. (Issue 57267)
  • Added more formatting in NDK docs/ and miscellaneous documentation fixes.
  • Added support for a thin archive technique when building static libraries. (Issue 40303)
  • Updated script make-standalone-toolchain.sh to support the stlport library in addition to gnustl, when you specify the option --stl=stlport. For more information, see STANDALONE-TOOLCHAIN.html.
  • Updated the make-standalone-toolchain.sh script so that the --llvm-version= option creates the $TOOLCHAIN_PREFIX-clang and $TOOLCHAIN_PREFIX-clang++ scripts in addition to clang and clang++, to avoid using the host's clang and clang++ definitions by accident.
  • Added two flags to re-enable two optimizations in upstream Clang but disabled in NDK for better compatibility with code compiled by GCC:
    • Added a -fcxx-missing-return-semantics flag to re-enable missing return semantics in Clang 3.2+. Normally, all paths should terminate with a return statement for a value-returning function. If this is not the case, clang inserts an undefined instruction (or trap in debug mode) at the path without a return statement. If you are sure your code is correct, use this flag to allow the optimizer to take advantage of the undefined behavior. If you are not sure, do not use this flag. The caller may still receive a random incorrect value, but the optimizer will not exploit it and make your code harder to debug.
    • Added a -fglobal-ctor-const-promotion flag to re-enable promoting global variables with static constructor to be constants. With this flag, the global variable optimization pass of LLVM tries to evaluate the global variables with static constructors and promote them to global constants. Although this optimization is correct, it may cause some incompatability with code compiled by GCC. For example, code may do const_cast to cast the constant to mutable and modify it. In GCC, the variable is in read-write and the code is run by accident. In Clang, the const variable is in read-only memory and may cause your application to crash.
  • Added -mldc1-sdc1 to the MIPS GCC and Clang compilers. By default, compilers align 8-byte objects properly and emit the ldc1 and sdc1 instructions to move them around. If your app uses a custom allocator that does not always align with a new object's 8-byte boundary in the same way as the default allocator, your app may crash due to ldc1 and sdc1 operations on unaligned memory. In this case, use the -mno-ldc1-sdc1 flag to workaround the problem.
  • Downgraded the event severity from warning to info if APP_PLATFORM_LEVEL is larger than APP_MIN_PLATFORM_LEVEL. The APP_PLATFORM_LEVEL may be lower than APP_PLATFORM in jni/Application.mk because the NDK does not have headers for all levels. In this case, the actual level is shifted downwards. The APP_MIN_PLATFORM_LEVEL is specified by the android:minSdkVersion in your application's manifest. (Issue 39752)
  • Added the android_getCpuIdArm() and android_setCpuArm() methods to cpu-features.c. This addition enables easier retrieval of the ARM CPUID information. (Issue 53689)
  • Modified ndk-build to use GCC 4.7's as/ld for Clang compiling.

    Note: In GCC 4.7, monotonic_clock and is_monotonic have been renamed to steady_clock and is_steady, respectively.

  • Added the following new warnings to the ndk-build script:
    • Added warnings if LOCAL_LDLIBS/LDFLAGS are used in static library modules.
    • Added a warning if a configuration has no module to build.
    • Added a warning for non-system libraries being used in LOCAL_LDLIBS/LDFLAGS of a shared library or executable modules.
  • Updated build scripts, so that if APP_MODULES is not defined and only static libraries are listed in Android.mk, the script force-builds all of them. (Issue 53502)
  • Updated ndk-build to support absolute paths in LOCAL_SRC_FILES.
  • Removed the *-gdbtui executables, which are duplicates of the *-gdb executables with the -tui option enabled.
  • Updated the build scripts to warn you when the Edison Design Group (EDG) compiler front-end turns _STLP_HAS_INCLUDE_NEXT back on. (Issue 53646)
  • Added the environment variable NDK_LIBS_OUT to allow overriding of the path for libraries/gdbserver from the default $PROJECT/libs. For more information, see OVERVIEW.html.
  • Changed ndk-build script defaults to compile code with format string protection -Wformat -Werror=format-security. You may set LOCAL_DISABLE_FORMAT_STRING_CHECKS=true to disable it. For more information, see ANDROID-MK.html
  • Added STL pretty-print support in ndk-gdb-py. For more information, see NDK-GDB.html.
  • Added tests based on the googletest frameworks.
  • Added a notification to the toolchain build script that warns you if the current shell is not bash.

Android NDK, Revision 8e (March 2013)

Important changes:
  • Added 64-bit host toolchain set (package name suffix *-x86_64.*). For more information, see CHANGES.HTML and NDK-BUILD.html.
  • Added Clang 3.2 compiler. GCC 4.6 is still the default. For information on using the Clang compiler, see CHANGES.HTML.
  • Added static code analyzer for Linux/MacOSX hosts. For information on using the analyzer, see CHANGES.HTML.
  • Added MCLinker for Linux/MacOSX hosts as an experimental feature. The ld.gold linker is the default where available, so you must explicitly enable it. For more information, see CHANGES.HTML.
  • Updated ndk-build to use topological sort for module dependencies, which means the build automatically sorts out the order of libraries specified in LOCAL_STATIC_LIBRARIES, LOCAL_WHOLE_STATIC_LIBRARIES and LOCAL_SHARED_LIBRARIES. For more information, see CHANGES.HTML. (Issue 39378)
Important bug fixes:
  • Fixed build script to build all toolchains in -O2. Toolchains in previous releases were incorrectly built without optimization.
  • Fixed build script which unconditionally builds Clang/llvm for MacOSX in 64-bit.
  • Fixed GCC 4.6/4.7 internal compiler error: gen_thumb_movhi_clobber at config/arm/arm.md:5832. (Issue 52732)
  • Fixed build problem where GCC/ARM 4.6/4.7 fails to link code using 64-bit atomic built-in functions. (Issue 41297)
  • Fixed GCC 4.7 linker DIV usage mismatch errors. (Sourceware Issue)
  • Fixed GCC 4.7 internal compiler error build_data_member_initialization, at cp/semantics.c:5790.
  • Fixed GCC 4.7 internal compiler error redirect_eh_edge_1, at tree-eh.c:2214. (Issue 52909)
  • Fixed a GCC 4.7 segfault. (GCC Issue)
  • Fixed <chrono> clock resolution and enabled steady_clock. (Issue 39680)
  • Fixed toolchain to enable _GLIBCXX_HAS_GTHREADS for GCC 4.7 libstdc++. (Issue 41770, Issue 41859)
  • Fixed problem with the X86 MXX/SSE code failing to link due to missing posix_memalign. (Change 51872)
  • Fixed GCC4.7/X86 segmentation fault in i386.c, function distance_non_agu_define_in_bb(). (Change 50383)
  • Fixed GCC4.7/X86 to restore earlier cmov behavior. (GCC Issue)
  • Fixed handling NULL return value of setlocale() in libstdc++/GCC4.7. (Issue 46718)
  • Fixed ld.gold runtime undefined reference to __exidx_start and __exidx_start_end. (Change 52134)
  • Fixed Clang 3.1 internal compiler error when using Eigen library. (Issue 41246)
  • Fixed Clang 3.1 internal compiler error including <chrono> in C++11 mode. (Issue 39600)
  • Fixed Clang 3.1 internal compiler error when generating object code for a method call to a uniform initialized rvalue. (Issue 41387)
  • Fixed Clang 3.1/X86 stack realignment. (Change 52154)
  • Fixed problem with GNU Debugger (GDB) SIGILL when debugging on Android 4.1.2. (Issue 40941)
  • Fixed problem where GDB cannot set source:line breakpoints when symbols contain long, indirect file paths. (Issue 42448)
  • Fixed GDB read_program_header for MIPS PIE executables. (Change 49592)
  • Fixed STLport segmentation fault in uncaught_exception(). (Change 50236)
  • Fixed STLport bus error in exception handling due to unaligned access of DW_EH_PE_udata2, DW_EH_PE_udata4, and DW_EH_PE_udata8.
  • Fixed Gabi++ infinite recursion problem with nothrow new[] operator. (Issue 52833)
  • Fixed Gabi++ wrong offset to exception handler pointer. (Change 53446)
  • Removed Gabi++ redundant free on exception object (Change 53447)
Other bug fixes:
  • Fixed NDK headers:
    • Removed redundant definitions of size_t, ssize_t, and ptrdiff_t.
    • Fixed MIPS and ARM fenv.h header.
    • Fixed stddef.h to not redefine offsetof since it already exists in the toolchain.
    • Fixed elf.h to contain Elf32_auxv_t and Elf64_auxv_t. (Issue 38441)
    • Fixed the #ifdef C++ definitions in the OpenSLES_AndroidConfiguration.h header file. (Issue 53163)
  • Fixed STLport to abort after out of memory error instead of silently exiting.
  • Fixed system and Gabi++ headers to be able to compile with API level 8 and lower.
  • Fixed cpufeatures to not parse /proc/self/auxv. (Issue 43055)
  • Fixed ld.gold to not depend on host libstdc++ and on Windows platforms, to not depend on the libgcc_sjlj_1.dll library.
  • Fixed Clang 3.1 which emits inconsistent register list in .vsave and fails assembler. (Change 49930)
  • Fixed Clang 3.1 to be able to compile libgabi++ and pass the test-stlport tests for MIPS build targets. (Change 51961)
  • Fixed Clang 3.1 to only enable exception by default for C++, not for C.
  • Fixed several issues in Clang 3.1 to pass most GNU exception tests.
  • Fixed scripts clang and clang++ in standalone NDK compiler to detect -cc1 and to not specify -target when found.
  • Fixed ndk-build to observe NDK_APP_OUT set in Application.mk.
  • Fixed X86 libc.so and lib.a which were missing the sigsetjmp and siglongjmp functions already declared in setjmp.h. (Issue 19851)
  • Patched GCC 4.4.3/4.6/4.7 libstdc++ to work with Clang in C++ 11. (Clang Issue)
  • Fixed cygwin path in argument passed to HOST_AWK.
  • Fixed ndk-build script warning in windows when running from project's JNI directory. (Issue 40192)
  • Fixed problem where the ndk-build script does not build if makefile has trailing whitespace in the LOCAL_PATH definition. (Issue 42841)
Other changes:
  • Enabled threading support in GCC/MIPS toolchain.
  • Updated GCC exception handling helpers __cxa_begin_cleanup and __cxa_type_match to have default visibility from the previous hidden visibility in GNU libstdc++. For more information, see CHANGES.HTML.
  • Updated build scripts so that Gabi++ and STLport static libraries are now built with hidden visibility except for exception handling helpers.
  • Updated build so that STLport is built for ARM in Thumb mode.
  • Added support for std::set_new_handler in Gabi++. (Issue 52805)
  • Enabled FUTEX system call in GNU libstdc++.
  • Updated ndk-build so that it no longer copies prebuilt static library to a project's obj/local/<abi>/ directory. (Issue 40302)
  • Removed __ARM_ARCH_5*__ from ARM toolchains/*/setup.mk script. (Issue 21132)
  • Built additional GNU libstdc++ libraries in thumb for ARM.
  • Enabled MIPS floating-point madd/msub/nmadd/nmsub/recip/rsqrt instructions with 32-bit FPU.
  • Enabled graphite loop optimizer in GCC 4.6 and 4.7 to allow more optimizations: -fgraphite, -fgraphite-identity, -floop-block, -floop-flatten, -floop-interchange, -floop-strip-mine, -floop-parallelize-all, and -ftree-loop-linear. (info)
  • Enabled polly for Clang 3.1 on Linux and Max OS X 32-bit hosts which analyzes and optimizes memory access. (info)
  • Enabled -flto in GCC 4.7, 4.6, Clang 3.2 and Clang 3.1 on linux (Clang LTO via LLVMgold.so). MIPS compiler targets are not supported because ld.gold is not available.
  • Enabled --plugin and --plugin-opt for ld.gold in GCC 4.6/4.7.
  • Enabled --text-reorder for ld.gold in GCC 4.7.
  • Configured GNU libstdc++ with _GLIBCXX_USE_C99_MATH which undefines the isinf script in the bionic header. For more information, see CHANGES.html.
  • Added APP_LDFLAGS to the build scripts. For more information, see ANDROID-MK.html.
  • Updated build scripts to allow NDK_LOG=0 to disable the NDK_LOG.
  • Updated build scripts to allow NDK_HOST_32BIT=0 to disable the host developer environment 32-bit toolchain.
  • Changed the default GCC/X86 flags -march= and -mtune= from pentiumpro and generic to i686 and atom.
  • Enhanced toolchain build scripts:
    • Fixed a race condition in build-gcc.sh for the mingw build type which was preventing a significant amount of parallel build processing.
    • Updated build-gabi++.sh and build-stlport.sh so they can now run from the NDK package. (Issue 52835)
    • Fixed run-tests.sh in the MSys utilities collection.
    • Improved 64-bit host toolchain and Canadian Cross build support.
    • Updated build-mingw64-toolchain.sh script to more recent version.
    • Added option to build libgnustl_static.a and stlport_static.a without hidden visibility.

Android NDK, Revision 8d (December 2012)

Important changes:
  • Added the GNU Compiler Collection (GCC) 4.7 compiler to the NDK. The GCC 4.6 compiler is still the default, so you must to explicitly enable the new version as follows:
    • For ndk-build, export the NDK_TOOLCHAIN_VERSION=4.7 variable or add it to Application.mk.
    • For standalone builds, add the --toolchain= option to make-standalone-toolchain.sh, for example:
      --toolchain=arm-linux-androideabi-4.7

    Note: This feature is experimental. Please try it and report any issues.

  • Added stlport exception support via gabi++. Note that the new gabi++ depends on dlopen and related code, meaning that:
    • You can no longer build a static executable using the -static option or include libstlport_static.a using APP_STL := stlport_static. (You can still use the -static option with a standalone toolchain.) Compiling a dynamic executable using include $(BUILD_EXECUTABLE) continues to work because the compiler automatically adds the -ldl option.
    • If your project links using -nostdlib and {-Wl,--no-undefined}, you must manually include the -ldl option.
    For more information, see CPLUSPLUS-SUPPORT.html.

    Note: This feature is experimental and works better with the GCC 4.6/4.7 compilers than with GCC 4.4.3 or Clang 3.1. Please try it and report any issues.

  • Added a -mstack-protector-guard= option for x86 to choose between a global default path which is compatible with older Android C library (bionic) and a new tls path (%gs:20) for -fstack-protector, -fstack-protector-all and -fstack-protector-strong using the GCC 4.6 and higher compilers.

    Note: The -mstack-protector-guard setting itself does not enable any -fstack-protector* options.

  • Added android_setCpu() function to sources/android/cpufeatures/cpu-features.c for use when auto-detection via /proc is not possible in Android 4.1 and higher. (Chromium Issue 164154)
Important bug fixes:
  • Fixed unnecessary rebuild of object files when using the ndk-build script. (Issue 39810)
  • Fixed a linker failure with the NDK 8c release for Mac OS X 10.6.x that produced the following error:
    dyld: lazy symbol binding failed: Symbol not found: _memmem
    Referenced from: ...../arm-linux-androideabi/bin/ld
    Expected in: /usr/lib/libSystem.B.dylib
    This problem was caused by building on Mac OS X 10.7, which produced binaries that were not compatible with Mac OS 10.6.x and the NDK.
  • Removed the -x c++ options from the Clang++ standalone build script. (Issue 39089)
  • Fixed issues using the NDK_TOOLCHAIN_VERSION=clang3.1 option in Cygwin. (Issue 39585)
  • Fixed the make-standalone-toolchain.sh script to allow generation of a standalone toolchain using the Cygwin or MinGW environments. The resulting toolchain can be used in Cygwin, MingGW or CMD.exe environments. (Issue 39915, Issue 39585)
  • Added missing SL_IID_ANDROIDBUFFERQUEUESOURCE option in android-14 builds for ARM and X86. (Issue 40625)
  • Fixed x86 CPU detection for the ANDROID_CPU_X86_FEATURE_MOVBE feature. (Issue 39317)
  • Fixed an issue preventing the Standard Template Library (STL) from using C++ sources that do not have a .cpp file extension.
  • Fixed GCC 4.6 ARM internal compiler error at reload1.c:1061. (Issue 20862)
  • Fixed GCC 4.4.3 ARM internal compiler error at emit-rtl.c:1954. (Issue 22336)
  • Fixed GCC 4.4.3 ARM internal compiler error at postreload.c:396. (Issue 22345)
  • Fixed problem with GCC 4.6/4.7 skipping lambda functions. (Issue 35933)
Other bug fixes:
  • NDK header file fixes:
    • Fixed __WINT_TYPE__ and wint_t to be the same type.
    • Corrected typo in android/bitmap.h. (Issue 15134)
    • Corrected typo in errno.h.
    • Added check for the presence of __STDC_VERSION__ in sys/cdefs.h. (Issue 14627)
    • Reorganized headers in byteswap.h and dirent.h.
    • Fixed limits.h to include page.h which provides PAGE_SIZE settings. (Issue 39983)
    • Fixed return type of glGetAttribLocation() and glGetUniformLocation() from int to GLint.
    • Fixed __BYTE_ORDER constant for x86 builds. (Issue 39824)
  • Fixed ndk-build script to not overwrite -Os with -O2 for ARM builds.
  • Fixed build scripts to allow overwriting of HOST_AWK, HOST_SED, and HOST_MAKE settings.
  • Fixed issue for ld.gold on fsck_msdos builds linking objects built by the Intel C/C++ compiler (ICC).
  • Fixed ARM EHABI support in Clang to conform to specifications.
  • Fixed GNU Debugger (GDB) to shorten the time spent on walking the target's link map during solib events. (Issue 38402)
  • Fixed missing libgcc.a file when linking shared libraries.
Other changes:
  • Backported 64-bit built-in atomic functions for ARM to GCC 4.6.
  • Added documentation for audio output latency, along with other documentation and fixes.
  • Fixed debug builds with Clang so that non-void functions now raise a SIGILL signal for paths without a return statement.
  • Updated make-standalone-toolchain.sh to accept the suffix -clang3.1 which is equivalent to adding --llvm-version=3.1 to the GCC 4.6 toolchain.
  • Updated GCC and Clang bug report URL to: http://source.android.com/source/report-bug s.html
  • Added ARM ELF support to llvm-objdump.
  • Suppressed treating c input as c++ warning for Clang builds.
  • Updated build so that only the 32-bit version of libiberty.a is built and placed in lib32/.

Android NDK, Revision 8c (November 2012)

Important changes:
  • Added the Clang 3.1 compiler to the NDK. The GNU Compiler Collection (GCC) 4.6 is still the default, so you must explicitly enable the Clang compiler option as follows:
    • For ndk-build, export NDK_TOOLCHAIN_VERSION=clang3.1 or add this environment variable setting to Application.mk.
    • For standalone builds, add --llvm-version=3.1 to make-standalone-toolchain.sh and replace CC and CXX in your makefile with <tool-path>/bin/clang and <tool-path>/bin/clang++. See STANDALONE-TOOLCHAIN.html for details.

    Note: This feature is experimental. Please try it and report any issues.

  • Added Gold linker ld.gold for the Windows toolchain. Gold linker is also the default for ARM and X86 on all hosts. You may override it to use the ld.bfd linker by adding LOCAL_LDFLAGS += -fuse-ld=bfd to Android.mk, or by passing -fuse-ld=bfd to the g++/clang++ command line that does the linking.
  • Added checks for spaces in the NDK path to the ndk-build[.cmd] and ndk-gdb scripts, to prevent build errors that are difficult to diagnose.
  • Made the following changes to API level handling:
    • Modified build logic so that projects that specify android-10 through android-13 in APP_PLATFORM, project.properties or default.properties link against android-9 instead of android-14.
    • Updated build so that executables using android-16 (Jelly Bean) or higher are compiled with the -fPIE option for position-independent executables (PIE). A new APP_PIE option allows you to control this behavior. See APPLICATION-MK.html for details.

      Note: All API levels above 14 still link against platforms/android-14 and no new platforms/android-N have been added.

    • Modified ndk-build to provide warnings if the adjusted API level is larger than android:minSdkVersion in the project's AndroidManifest.xml.
  • Updated the cpu-features helper library to include more ARM-specific features. See sources/android/cpufeatures/cpu-features.h for details.
  • Modified the long double on the X86 platform to be 8 bytes. This data type is now the same size as a double, but is still treated as a distinct type.
  • Updated build for APP_ABI=armeabi-v7a:
    • Modified this build type to pass the -march=armv7-a parameter to the linker. This change ensures that v7-specific libraries and crt*.o are linked correctly.
    • Added -mfpu=vfpv3-d16 to ndk-build instead of the -mfpu=vfp option used in previous releases.
Important bug fixes:
  • Fixed an issue where running make-standalone-toolchain.sh with root privileges resulted in the stand alone tool chain being inaccessible to some users. (Issue 35279)
    • All files and executables in the NDK release package are set to have read and execute permissions for all.
    • The ownership/group of libstdc++.a is now preserved when copied.
  • Removed redundant \r from Windows prebuilt echo.exe. The redundant \r caused gdb.setup to fail in the GNU Debugger (GDB) because it incorrectly became part of the path. (Issue 36054)
  • Fixed Windows parallel builds that sometimes failed due to timing issues in the host-mkdir implementation. (Issue 25875)
  • Fixed GCC 4.4.3 GNU libstdc++ to not merge typeinfo names by default. For more details, see toolchain repo gcc/gcc-4.4.3/libstdc++-v3/libsupc++/typeinfo. (Issue 22165)
  • Fixed problem on null context in GCC 4.6 cp/mangle.c::write_unscoped_name, where GCC may crash when the context is null and dereferenced in TREE_CODE.
  • Fixed GCC 4.4.3 crashes on ARM NEON-specific type definitions for floats. (Issue 34613)
  • Fixed the STLport internal _IteWrapper::operator*() implementation where a stale stack location holding the dereferenced value was returned and caused runtime crashes. (Issue 38630)
  • ARM-specific fixes:
    • Fixed ARM GCC 4.4.3/4.6 g++ to not warn that the mangling of <va_list> was changed in GCC 4.4. The workaround using the -Wno-psabi switch to avoid this warning is no longer required.
    • Fixed an issue when a project with .arm or .neon suffixes in LOCAL_SRC_FILES also used APP_STL. With APP_STL, the ndk-build script searches for C++ files in LOCAL_SRC_FILES before adding STL header/lib paths to compilation. Modified ndk-build to filter out .arm and .neon suffixes before the search, otherwise items in LOCAL_SRC_FILES like myfile.cpp.arm.neon won't be compiled as C++ code.
    • Fixed binutils-2.21/ld.bfd to be capable of linking object from older binutils without tag_FP_arch, which was producing assertion fail error messages in GNU Binutils. (Issue 35209)
    • Removed Unknown EABI object attribute 44 warning when binutils-2.19/ld links prebuilt object by newer binutils-2.21
    • Fixed an issue in GNU stdc++ compilation with both -mthumb and -march=armv7-a, by modifying make-standalone-toolchain.sh to populate headers/libs in sub-directory armv7-a/thumb. (Issue 35616)
    • Fixed unresolvable R_ARM_THM_CALL relocation error. (Issue 35342)
    • Fixed internal compiler error at reload1.c:3633, caused by the ARM back-end expecting the wrong operand type when sign-extend from char. (GCC Issue 50099)
    • Fixed internal compiler error with negative shift amount. (GCC Issue)
  • Fixed -fstack-protector for X86, which is also the default for the ndk-build x86 ABI target.
  • MIPS-specific fixes:
    • Fixed STLport endian-ness by setting _STLP_LITTLE_ENDIAN to 1 when compiling MIPS libstlport_*.
    • Fixed GCC __builtin_unreachable issue when compiling LLVM. (GCC Issue 54369)
    • Backported fix for cc1 compile process consuming 100% CPU. (GCC Issue 50380)
  • GNU Debugger-specific fixes:
    • Disabled Python support in gdb-7.x at build, otherwise the gdb-7.x configure function may pick up whatever Python version is available on the host and build gdb with a hard-wired dependency on a specific version of Python. (Issue 36120)
    • Fixed ndk-gdb when APP_ABI contains all and matchs none of the known architectures. (Issue 35392)
    • Fixed Windows pathname support, by keeping the : character if it looks like it could be part of a Windows path starting with a drive letter. (GDB Issue 12843)
    • Fixed adding of hardware breakpoint support for ARM in gdbserver. (GDB Issue)
    • Added fix to only read the current solibs when the linker is consistent. This change speeds up solib event handling. (Issue 37677)
    • Added fix to make repeated attempts to find solib breakpoints. GDB now retries enable_break() during every call to svr4_current_sos() until it succeeds. (Change 43563)
    • Fixed an issue where gdb would not stop on breakpoints placed in dlopen-ed libraries. (Issue 34856)
    • Fixed SIGILL in dynamic linker when calling dlopen(), on system where /system/bin/linker is stripped of symbols and rtld_db_dlactivity() is implemented as Thumb, due to not preserving LSB of sym_addr. (Issue 37147)
Other bug fixes:
  • Fixed NDK headers:
    • Fixed arch-mips/include/asm/* code that was incorrectly removed from original kernel. (Change 43335)
    • Replaced struct member data __unused with __linux_unused in linux/sysctl.h and linux/icmp.h to avoid conflict with #define __unused in sys/cdefs.h.
    • Fixed fenv.h for enclosed C functions with __BEGIN_DECLS and __END_DECLS.
    • Removed unimplemented functions in malloc.h.
    • Fixed stdint.h defintion of uint64_t for ANSI compilers. (Issue 1952)
    • Fixed preprocessor macros in <arch>/include/machine/*.
    • Replaced link.h for MIPS with new version supporting all platforms.
    • Removed linux-unistd.h
    • Move GLibc-specific macros LONG_LONG_MIN, LONG_LONG_MAX and ULONG_LONG_MAX from <pthread.h> to <limits.h>.
  • Fixed a buffer overflow in ndk-stack-parser.
  • Fixed _STLP_USE_EXCEPTIONS, when not defined, to omit all declarations and uses of __Named_exception. Compiling and use of __Named_exception settings only occurs when STLport is allowed to use exceptions.
  • Fixed building of Linux-only NDK packages without also building Windows code. Use the following settings to perform this type of build:
    ./build/tools/make-release.sh --force --systems=linux-x86
  • Fixed libc.so so it does not export atexit() and __do_handler. These symbols are exported for ARM builds by the system version of the C library to support legacy native libraries. NDK-generated should never reference them directly. Instead, each shared library or executable should embed its own version of these symbols, provided by crtbegin_*.o.

    If your project is linked with the -nostdlib -Wl,--no-undefined options, you must provide your own __dso_handle because crtbegin_so.o is not linked in this case. The content of __dso_handle does not matter, as shown in the following example code:

    extern "C" {
      extern void *__dso_handle __attribute__((__visibility__ ("hidden")));
      void *__dso_handle;
    }
    
  • Fixed symbol decoder for ARM used in objdump for plt entries to generate a more readable form function@plt.
  • Removed the following symbols, introduced in GCC 4.6 libgcc.a, from the X86 platform libc.so library: __aeabi_idiv0, __aeabi_ldiv0, __aeabi_unwind_cpp_pr1, and __aeabi_unwind_cpp_pr2.
  • Removed unused .ctors, .dtors, and .eh_frame in MIPS crt*_so.S.
  • Updated ndk-gdb so that it only takes the last line of output for ndk-build DUMP_XXXX. This change ensures that if Application.mk or Android.mk print something with $(info ...) syntax, it does not get injected into the result of DUMP_XXXX. (More info)
Other changes:
  • Removed arch-x86 and arch-mips headers from platforms/android-[3,4,5,8]. Those headers were incomplete, since both X86 and MIPS ABIs are only supported at API 9 or higher.
  • Simplified c++ include path in standalone packages, as shown below. (Issue 35279)
    <path>/arm-linux-androideabi/include/c++/4.6.x-google
      to:
    <path>/include/c++/4.6/
    
  • Fixed ndk-build to recognize more C++ file extensions by default: .cc .cp .cxx .cpp .CPP .c++ .C. You may still use LOCAL_CPP_EXTENSION to overwrite these extension settings.
  • Fixed an issue in samples/san-angeles that caused a black screen or freeze frame on re-launch.
  • Replaced deprecated APIs in NDK samples. (Issue 20017)
    • hello-gl2 from android-5 to android-7
    • native-activity from android-9 to android-10
    • native-audio from android-9 to android-10
    • native-plasma from android-9 to android-10
  • Added new branding for Android executables with a simpler scheme in section .note.android.ident (defined in crtbegin_static/dynamic.o) so that debugging tools can act accordingly. The structure member and values are defined as follows:
    static const struct {
      int32_t namesz;  /* = 8,  sizeof ("Android") */
      int32_t descsz;  /* = 1 * sizeof(int32_t) */
      int32_t type;    /* = 1, ABI_NOTETYPE */
      char name[sizeof "Android"];  /* = "Android" */
      int32_t android_api; /* = 3, 4, 5, 8, 9, 14 */
    }
    

    The previous branding options in section .note.ABI-tag are deprecated.

  • Added a new script run-tests-all.sh which calls run-tests.sh and standalone/run.sh with various conditions. The script run-tests.sh runs without the --abi option, and is enhanced to compile most of the tests for all supported ABIs and run on all attached devices

Android NDK, Revision 8b (July 2012)

The main features of this release are a new GNU Compiler Collection (GCC) 4.6 toolchain and GNU Debugger (GDB) 7.3.x which adds debugging support for the Android 4.1 (API Level 16) system image.

Important bug fixes:
  • Fixed LOCAL_SHORT_COMMANDS issues on Mac OS, Windows Cygwin environments for static libraries. List file generation is faster, and it is not regenerated to avoid repeated project rebuilds.
  • Fixed several issues in ndk-gdb:
    • Updated tool to pass flags -e, -d and -s to adb more consistently.
    • Updated tool to accept device serial names containing spaces.
    • Updated tool to retrieve /system/bin/link information, so gdb on the host can set a breakpoint in __dl_rtld_db_dlactivity and be aware of linker activity (e.g., rescan solib symbols when dlopen() is called).
  • Fixed ndk-build clean on Windows, which was failing to remove ./libs/*/lib*.so.
  • Fixed ndk-build.cmd to return a non-zero ERRORLEVEL when make fails.
  • Fixed libc.so to stop incorrectly exporting the __exidx_start and __exidx_end symbols.
  • Fixed SEGV when unwinding the stack past __libc_init for ARM and MIPS.
Important changes:
  • Added GCC 4.6 toolchain (binutils 2.21 with gold and GDB 7.3.x) to co-exist with the original GCC 4.4.3 toolchain (binutils 2.19 and GDB 6.6).
    • GCC 4.6 is now the default toolchain. You may set NDK_TOOLCHAIN_VERSION=4.4.3 in Application.mk to select the original one.
    • Support for the gold linker is only available for ARM and x86 architectures on Linux and Mac OS hosts. This support is disabled by default. Add LOCAL_LDLIBS += -fuse-ld=gold in Android.mk to enable it.
    • Programs compiled with -fPIE require the new GDB for debugging, including binaries in Android 4.1 (API Level 16) system images.
    • The binutils 2.21 ld tool contains back-ported fixes from version 2.22:
      • Fixed ld --gc-sections, which incorrectly retains zombie references to external libraries. (more info).
      • Fixed ARM strip command to preserve the original p_align and p_flags in GNU_RELRO section if they are valid. Without this fix, programs built with -fPIE could not be debugged. (mor e info)
    • Disabled sincos() optimization for compatibility with older platforms.
  • Updated build options to enable the Never eXecute (NX) bit and relro/bind_now protections by default:
    • Added --noexecstack to assembler and -z noexecstack to linker that provides NX protection against buffer overflow attacks by enabling NX bit on stack and heap.
    • Added -z relro and -z now to linker for hardening of internal data sections after linking to guard against security vulnerabilities caused by memory corruption. (more info: 1, 2)
    • These features can be disabled using the following options:
      1. Disable NX protection by setting the --execstack option for the assembler and -z execstack for the linker.
      2. Disable hardening of internal data by setting the -z norelro and -z lazy options for the linker.
      3. Disable these protections in the NDK jni/Android.mk by setting the following options:
        LOCAL_DISABLE_NO_EXECUTE=true  # disable "--noexecstack" and "-z noexecstack"
        DISABLE_RELRO=true             # disable "-z relro" and "-z now"
        

      See docs/ANDROID-MK.html for more details.

  • Added branding for Android executables with the .note.ABI-tag section (in crtbegin_static/dynamic.o) so that debugging tools can act accordingly. The structure member and values are defined as follows:
    static const struct {
      int32_t namesz;  /* = 4,  sizeof ("GNU") */
      int32_t descsz;  /* = 6 * sizeof(int32_t) */
      int32_t type;    /* = 1 */
      char  name[sizeof "GNU"];  /* = "GNU" */
      int32_t os;      /* = 0 */
      int32_t major;   /* = 2 */
      int32_t minor;   /* = 6 */
      int32_t teeny;   /* = 15 */
      int32_t os_variant;  /* = 1 */
      int32_t android_api; /* = 3, 4, 5, 8, 9, 14 */
    }
Other bug fixes:
  • Fixed mips-linux-gnu relocation truncated to fit R_MIPS_TLS_LDM issue. (more info)
  • Fixed ld tool segfaults when using --gc-sections. (more info)
  • Fixed MIPS GOT_PAGE counting issue. (more info)
  • Fixed follow warning symbol link for mips_elf_count_got_symbols.
  • Fixed follow warning symbol link for mips_elf_allocate_lazy_stub.
  • Moved MIPS .dynamic to the data segment, so that it is writable.
  • Replaced hard-coded values for symbols with correct segment sizes for MIPS.
  • Removed the -mno-shared option from the defaults in the MIPS toolchain. The default for Android toolchain is -fPIC (or -fpic if supported). If you do not explicitly specify -mshared, -fpic, -fPIC, -fpie, or -fPIE, the MIPS compiler adds -mno-shared that turns off PIC. Fixed compiler not to add -mno-shared in this case.
  • Fixed wrong package names in samples hello-jni and two-libs so that the tests project underneath it can compile.
Other Changes:
  • Changed locations of binaries:
    • Moved gdbserver from toolchain/<arch-os-ver>/prebuilt/gdbserver to prebuilt/android-<arch>/gdbserver/gdbserver.
    • Renamed x86 toolchain prefix from i686-android-linux- to i686-linux-android-.
    • Moved sources/cxx-stl/gnu-libstdc++/include and lib to sources/cxx-stl/gnu-libstdc++/4.6 when compiled with GCC 4.6, or sources/cxx-stl/gnu-libstdc++/4.4.3 when compiled with GCC 4.4.3.
    • Moved libbfd.a and libintl.a from lib/ to lib32/.
  • Added and improved various scripts in the rebuild and test NDK toolchain:
    • Added build-mingw64-toolchain.sh to generate a new Linux-hosted toolchain that generates Win32 and Win64 executables.
    • Improved speed of download-toolchain-sources.sh by using the clone command and only using checkout for the directories that are needed to build the NDK toolchain binaries.
    • Added build-host-gcc.sh and build-host-gdb.sh scripts.
    • Added tests/check-release.sh to check the content of a given NDK installation directory, or an existing NDK package.
    • Rewrote the tests/standalone/run.sh standalone tests .
  • Removed if_dl.h header from all platforms and architectures. The AF_LINK and sockaddr_dl elements it describes are specific to BSD (i.e., they don't exist in Linux).

Android NDK, Revision 8 (May 2012)

This release of the NDK includes support for MIPS ABI and a few additional fixes.

New features:
  • Added support for the MIPS ABI, which allows you to generate machine code that runs on compatible MIPS-based Android devices. Major features for MIPS include MIPS-specific toolchains, system headers, libraries and debugging support. For more details regarding MIPS support, see docs/CPU-MIPS.html in the NDK package.

    By default, code is generated for ARM-based devices. You can add mips to your APP_ABI definition in your Application.mk file to build for MIPS platforms. For example, the following line instructs ndk-build to build your code for three distinct ABIs:

    APP_ABI := armeabi armeabi-v7a mips

    Unless you rely on architecture-specific assembly sources, such as ARM assembly code, you should not need to touch your Android.mk files to build MIPS machine code.

  • You can build a standalone MIPS toolchain using the --arch=mips option when calling make-standalone-toolchain.sh. See docs/STANDALONE-TOOLCHAIN.html for more details.

Note: To ensure that your applications are available to users only if their devices are capable of running them, Google Play filters applications based on the instruction set information included in your application ? no action is needed on your part to enable the filtering. Additionally, the Android system itself also checks your application at install time and allows the installation to continue only if the application provides a library that is compiled for the device's CPU architecture.

Important bug fixes:
  • Fixed a typo in GAbi++ implementation where the result of dynamic_cast<D>(b) of base class object b to derived class D is incorrectly adjusted in the opposite direction from the base class. (Issue 28721)
  • Fixed an issue in which make-standalone-toolchain.sh fails to copy libsupc++.*.
Other bug fixes:
  • Fixed ndk-build.cmd to ensure that ndk-build.cmd works correctly even if the user has redefined the SHELL environment variable, which may be changed when installing a variety of development tools in Windows environments.

Android NDK, Revision 7c (April 2012)

This release of the NDK includes an important fix for Tegra2-based devices, and a few additional fixes and improvements:

Important bug fixes:
  • Fixed GNU STL armeabi-v7a binaries to not crash on non-NEON devices. The files provided with NDK r7b were not configured properly, resulting in crashes on Tegra2-based devices and others when trying to use certain floating-point functions (e.g., cosf, sinf, expf).
Important changes:
  • Added support for custom output directories through the NDK_OUT environment variable. When defined, this variable is used to store all intermediate generated files, instead of $PROJECT_PATH/obj. The variable is also recognized by ndk-gdb.
  • Added support for building modules with hundreds or even thousands of source files by defining LOCAL_SHORT_COMMANDS to true in your Android.mk.

    This change forces the NDK build system to put most linker or archiver options into list files, as a work-around for command-line length limitations. See docs/ANDROID-MK.html for details.

Other bug fixes:
  • Fixed android_getCpuCount() implementation in the cpufeatures helper library. On certain devices, where cores are enabled dynamically by the system, the previous implementation would report the total number of active cores the first time the function was called, rather than the total number of physically available cores.

Android NDK, Revision 7b (February 2012)

This release of the NDK includes fixes for native Windows builds, Cygwin and many other improvements:

Important bug fixes:
  • Updated sys/atomics.h to avoid correctness issues on some multi-core ARM-based devices. Rebuild your unmodified sources with this version of the NDK and this problem should be completely eliminated. For more details, read docs/ANDROID-ATOMICS.html.
  • Reverted to binutils 2.19 to fix debugging issues that appeared in NDK r7 (which switched to binutils 2.20.1).
  • Fixed ndk-build on 32-bit Linux. A packaging error put a 64-bit version of the awk executable under prebuilt/linux-x86/bin in NDK r7.
  • Fixed native Windows build (ndk-build.cmd). Other build modes were not affected. The fixes include:
    • Removed an infinite loop / stack overflow bug that happened when trying to call ndk-build.cmd from a directory that was not the top of your project path (e.g., in any sub-directory of it).
    • Fixed a problem where the auto-generated dependency files were ignored. This meant that updating a header didn't trigger recompilation of sources that included it.
    • Fixed a problem where special characters in files or paths, other than spaces and quotes, were not correctly handled.
  • Fixed the standalone toolchain to generate proper binaries when using -lstdc++ (i.e., linking against the GNU libstdc++ C++ runtime). You should use -lgnustl_shared if you want to link against the shared library version or -lstdc++ for the static version.

    See docs/STANDALONE-TOOLCHAIN.html for more details about this fix.

  • Fixed gnustl_shared on Cygwin. The linker complained that it couldn't find libsupc++.a even though the file was at the right location.
  • Fixed Cygwin C++ link when not using any specific C++ runtime through APP_STL.
Other changes:
  • When your application uses the GNU libstdc++ runtime, the compiler will no longer forcibly enable exceptions and RTTI. This change results in smaller code.

    If you need these features, you must do one of the following:

    • Enable exceptions and/or RTTI explicitly in your modules or Application.mk. (recommended)
    • Define APP_GNUSTL_FORCE_CPP_FEATURES to 'exceptions', 'rtti' or both in your Application.mk. See docs/APPLICATION-MK.html for more details.
  • ndk-gdb now works properly when your application has private services running in independent processes. It debugs the main application process, instead of the first process listed by ps, which is usually a service process.
  • Fixed a rare bug where NDK r7 would fail to honor the LOCAL_ARM_MODE value and always compile certain source files (but not all) to 32-bit instructions.
  • STLport: Refresh the sources to match the Android platform version. This update fixes a few minor bugs:
    • Fixed instantiation of an incomplete type
    • Fixed minor "==" versus "=" typo
    • Used memmove instead of memcpy in string::assign
    • Added better handling of IsNANorINF, IsINF, IsNegNAN, etc.

    For complete details, see the commit log.

  • STLport: Removed 5 unnecessary static initializers from the library.
  • The GNU libstdc++ libraries for armeabi-v7a were mistakenly compiled for armeabi instead. This change had no impact on correctness, but using the right ABI should provide slightly better performance.
  • The cpu-features helper library was updated to report three optional x86 CPU features (SSSE3, MOVBE and POPCNT). See docs/CPU-FEATURES.html for more details.
  • docs/NDK-BUILD.html was updated to mention NDK_APPLICATION_MK instead of NDK_APP_APPLICATION_MK to select a custom Application.mk file.
  • Cygwin: ndk-build no longer creates an empty "NUL" file in the current directory when invoked.
  • Cygwin: Added better automatic dependency detection. In the previous version, it didn't work properly in the following cases:
    • When the Cygwin drive prefix was not /cygdrive.
    • When using drive-less mounts, for example, when Cygwin would translate /home to \\server\subdir instead of C:\Some\Dir.
  • Cygwin: ndk-build does not try to use the native Windows tools under $NDK/prebuilt/windows/bin with certain versions of Cygwin and/or GNU Make.

Android NDK, Revision 7 (November 2011)

This release of the NDK includes new features to support the Android 4.0 platform as well as many other additions and improvements:

New features
  • Added official NDK APIs for Android 4.0 (API level 14), which adds the following native features to the platform:
    • Added native multimedia API based on the Khronos Group OpenMAX AL? 1.0.1 standard. The new <OMXAL/OpenMAXAL.h> and <OMXAL/OpenMAXAL_Android.h> headers allow applications targeting API level 14 to perform multimedia output directly from native code by using a new Android-specific buffer queue interface. For more details, see docs/openmaxal/index.html and http://www.khronos.org/openmax/.
    • Updated the native audio API based on the Khronos Group OpenSL ES 1.0.1? standard. With API Level 14, you can now decode compressed audio (e.g. MP3, AAC, Vorbis) to PCM. For more details, see docs/opensles/index.html and http://www.khronos.org/opensles/.
  • Added CCache support. To speed up large rebuilds, define the NDK_CCACHE environment variable to ccache (or the path to your ccache binary). When declared, the NDK build system automatically uses CCache when compiling any source file. For example:
    export NDK_CCACHE=ccache
    

    Note: CCache is not included in the NDK release so you must have it installed prior to using it. For more information about CCache, see http://ccache.samba.org.

  • Added support for setting APP_ABI to all to indicate that you want to build your NDK modules for all the ABIs supported by your given NDK release. This means that either one of the following two lines in your Application.mk are equivalent with this release:
    APP_ABI := all
    APP_ABI := armeabi armeabi-v7a x86
    

    This also works if you define APP_ABI when calling ndk-build from the command-line, which is a quick way to check that your project builds for all supported ABIs without changing the project's Application.mk file. For example:

    ndk-build APP_ABI=all
    
  • Added a LOCAL_CPP_FEATURES variable in Android.mk that allows you to declare which C++ features (RTTI or Exceptions) your module uses. This ensures that the final linking works correctly if you have prebuilt modules that depend on these features. See docs/ANDROID-MK.html and docs/CPLUSPLUS-SUPPORT.html for more details.
  • Shortened paths to source and object files that are used in build commands. When invoking $NDK/ndk-build from your project path, the paths to the source, object, and binary files that are passed to the build commands are significantly shorter now, because they are passed relative to the current directory. This is useful when building projects with a lot of source files, to avoid limits on the maximum command line length supported by your host operating system. The behavior is unchanged if you invoke ndk-build from a sub-directory of your project tree, or if you define NDK_PROJECT_PATH to point to a specific directory.
Experimental features
You can now build your NDK source files on Windows without Cygwin by calling the ndk-build.cmd script from the command line from your project path. The script takes exactly the same arguments as the original ndk-build script. The Windows NDK package comes with its own prebuilt binaries for GNU Make, Awk and other tools required by the build. You should not need to install anything else to get a working build system.

Important: ndk-gdb does not work on Windows, so you still need Cygwin to debug.

This feature is still experimental, so feel free to try it and report issues on the public bug database or public forum. All samples and unit tests shipped with the NDK succesfully compile with this feature.

Important bug fixes
  • Imported shared libraries are now installed by default to the target installation location (libs/<abi>) if APP_MODULES is not defined in your Application.mk. For example, if a top-level module foo imports a module bar, then both libfoo.so and libbar.so are copied to the install location. Previously, only libfoo.so was copied, unless you listed bar in your APP_MODULES too. If you define APP_MODULES explicitly, the behavior is unchanged.
  • ndk-gdb now works correctly for activities with multiple categories in their MAIN intent filters.
  • Static library imports are now properly transitive. For example, if a top-level module foo imports static library bar that imports static library zoo, the libfoo.so will now be linked against both libbar.a and libzoo.a.
Other changes
  • docs/NATIVE-ACTIVITY.HTML: Fixed typo. The minimum API level should be 9, not 8 for native activities.
  • docs/STABLE-APIS.html: Added missing documentation listing EGL as a supported stable API, starting from API level 9.
  • download-toolchain-sources.sh: Updated to download the toolchain sources from android.googlesource.com, which is the new location for the AOSP servers.
  • Added a new C++ support runtime named gabi++. More details about it are available in the updated docs/CPLUSPLUS-SUPPORT.html.
  • Added a new C++ support runtime named gnustl_shared that corresponds to the shared library version of GNU libstdc++ v3 (GPLv3 license). See more info at docs/CPLUSPLUS-SUPPORT.html
  • Added support for RTTI in the STLport C++ runtimes (no support for exceptions).
  • Added support for multiple file extensions in LOCAL_CPP_EXTENSION. For example, to compile both foo.cpp and bar.cxx as C++ sources, declare the following:
    LOCAL_CPP_EXTENSION := .cpp .cxx
    
  • Removed many unwanted exported symbols from the link-time shared system libraries provided by the NDK. This ensures that code generated with the standalone toolchain doesn't risk to accidentally depend on a non-stable ABI symbol (e.g. any libgcc.a symbol that changes each time the toolchain used to build the platform is changed)
  • Refreshed the EGL and OpenGLES Khronos headers to support more extensions. Note that this does not change the NDK ABIs for the corresponding libraries, because each extension must be probed at runtime by the client application.

    The extensions that are available depend on your actual device and GPU drivers, not the platform version the device runs on. The header changes simply add new constants and types to make it easier to use the extensions when they have been probed with eglGetProcAddress() or glGetProcAddress(). The following list describes the newly supported extensions:

    GLES 1.x
    • GL_OES_vertex_array_object
    • GL_OES_EGL_image_external
    • GL_APPLE_texture_2D_limited_npot
    • GL_EXT_blend_minmax
    • GL_EXT_discard_framebuffer
    • GL_EXT_multi_draw_arrays
    • GL_EXT_read_format_bgra
    • GL_EXT_texture_filter_anisotropic
    • GL_EXT_texture_format_BGRA8888
    • GL_EXT_texture_lod_bias
    • GL_IMG_read_format
    • GL_IMG_texture_compression_pvrtc
    • GL_IMG_texture_env_enhanced_fixed_function
    • GL_IMG_user_clip_plane
    • GL_IMG_multisampled_render_to_texture
    • GL_NV_fence
    • GL_QCOM_driver_control
    • GL_QCOM_extended_get
    • GL_QCOM_extended_get2
    • GL_QCOM_perfmon_global_mode
    • GL_QCOM_writeonly_rendering
    • GL_QCOM_tiled_rendering
    GLES 2.0
    • GL_OES_element_index_uint
    • GL_OES_get_program_binary
    • GL_OES_mapbuffer
    • GL_OES_packed_depth_stencil
    • GL_OES_texture_3D
    • GL_OES_texture_float
    • GL_OES_texture_float_linear
    • GL_OES_texture_half_float_linear
    • GL_OES_texture_npot
    • GL_OES_vertex_array_object
    • GL_OES_EGL_image_external
    • GL_AMD_program_binary_Z400
    • GL_EXT_blend_minmax
    • GL_EXT_discard_framebuffer
    • GL_EXT_multi_draw_arrays
    • GL_EXT_read_format_bgra
    • GL_EXT_texture_format_BGRA8888
    • GL_EXT_texture_compression_dxt1
    • GL_IMG_program_binary
    • GL_IMG_read_format
    • GL_IMG_shader_binary
    • GL_IMG_texture_compression_pvrtc
    • GL_IMG_multisampled_render_to_texture
    • GL_NV_coverage_sample
    • GL_NV_depth_nonlinear
    • GL_QCOM_extended_get
    • GL_QCOM_extended_get2
    • GL_QCOM_writeonly_rendering
    • GL_QCOM_tiled_rendering
    EGL
    • EGL_ANDROID_recordable
    • EGL_NV_system_time

Android NDK, Revision 6b (August 2011)

This release of the NDK does not include any new features compared to r6. The r6b release addresses the following issues in the r6 release:

Important bug fixes
  • Fixed the build when APP_ABI="armeabi x86" is used for multi-architecture builds.
  • Fixed the location of prebuilt STLport binaries in the NDK release package. A bug in the packaging script placed them in the wrong location.
  • Fixed atexit() usage in shared libraries with the x86standalone toolchain.
  • Fixed make-standalone-toolchain.sh --arch=x86. It used to fail to copy the proper GNU libstdc++ binaries to the right location.
  • Fixed the standalone toolchain linker warnings about missing the definition and size for the __dso_handle symbol (ARM only).
  • Fixed the inclusion order of $(SYSROOT)/usr/include for x86 builds. See the bug for more information.
  • Fixed the definitions of ptrdiff_t and size_t in x86-specific systems when they are used with the x86 standalone toolchain.

Android NDK, Revision 6 (July 2011)

This release of the NDK includes support for the x86 ABI and other minor changes. For detailed information describing the changes in this release, read the CHANGES.HTML document included in the NDK package.

General notes:
  • Adds support for the x86 ABI, which allows you to generate machine code that runs on compatible x86-based Android devices. Major features for x86 include x86-specific toolchains, system headers, libraries and debugging support. For all of the details regarding x86 support, see docs/CPU-X86.html in the NDK package.

    By default, code is generated for ARM-based devices, but you can add x86 to your APP_ABI definition in your Application.mk file to build for x86 platforms. For example, the following line instructs ndk-build to build your code for three distinct ABIs:

    APP_ABI := armeabi armeabi-v7a x86

    Unless you rely on ARM-based assembly sources, you shouldn't need to touch your Android.mk files to build x86 machine code.

  • You can build a standalone x86 toolchain using the --toolchain=x86-4.4.3 option when calling make-standalone-toolchain.sh. See docs/STANDALONE-TOOLCHAIN.html for more details.
  • The new ndk-stack tool lets you translate stack traces in logcat that are generated by native code. The tool translates instruction addresses into a readable format that contains things such as the function, source file, and line number corresponding to each stack frame. For more information and a usage example, see docs/NDK-STACK.html.
Other changes:
arm-eabi-4.4.0, which had been deprecated since NDK r5, has been removed from the NDK distribution.

Android NDK, Revision 5c (June 2011)

This release of the NDK does not include any new features compared to r5b. The r5c release addresses the following problems in the r5b release:

Important bug fixes:
  • ndk-build: Fixed a rare bug that appeared when trying to perform parallel builds of debuggable projects.
  • Fixed a typo that prevented LOCAL_WHOLE_STATIC_LIBRARIES to work correctly with the new toolchain and added documentation for this in docs/ANDROID-MK.html.
  • Fixed a bug where code linked against gnustl_static crashed when run on platform releases older than API level 8 (Android 2.2).
  • ndk-gdb: Fixed a bug that caused a segmentation fault when debugging Android 3.0 or newer devices.
  • <android/input.h>: Two functions that were introduced in API level 9 (Android 2.3) were incorrect and are fixed. While this breaks the source API, the binary interface to the system is unchanged. The incorrect functions were missing a history_index parameter, and the correct definitions are shown below:
    float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event,
                                               size_t pointer_index,
                                               size_t history_index);
    
    float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event,
                                               size_t pointer_index,
                                               size_t history_index);
    
  • Updated the C library ARM binary for API level 9 (Android 2.3) to correctly expose at link time new functions that were added in that API level (for example, pthread_rwlock_init).
Minor improvements and fixes:
  • Object files are now always linked in the order they appear in LOCAL_SRC_FILES. This was not the case previously because the files were grouped by source extensions instead.
  • When import-module fails, it now prints the list of directories that were searched. This is useful to check that the NDK_MODULE_PATH definition used by the build system is correct.
  • When import-module succeeds, it now prints the directory where the module was found to the log (visible with NDK_LOG=1).
  • Increased the build speed of debuggable applications when there is a very large number of include directories in the project.
  • ndk-gdb: Better detection of adb shell failures and improved error messages.
  • <pthread.h>: Fixed the definition of PTHREAD_RWLOCK_INITIALIZER for API level 9 (Android 2.3) and higher.
  • Fixed an issue where a module could import itself, resulting in an infinite loop in GNU Make.
  • Fixed a bug that caused the build to fail if LOCAL_ARM_NEON was set to true (typo in build/core/build-binary.mk).
  • Fixed a bug that prevented the compilation of .s assembly files (.S files were okay).

Android NDK, Revision 5b (January 2011)

This release of the NDK does not include any new features compared to r5. The r5b release addresses the following problems in the r5 release:

  • The r5 binaries required glibc 2.11, but the r5b binaries are generated with a special toolchain that targets glibc 2.7 or higher instead. The Linux toolchain binaries now run on Ubuntu 8.04 or higher.
  • Fixes a compiler bug in the arm-linux-androideabi-4.4.3 toolchain. The previous binary generated invalid thumb instruction sequences when dealing with signed chars.
  • Adds missing documentation for the "gnustl_static" value for APP_STL, that allows you to link against a static library version of GNU libstdc++.
  • the
  • Fixed the following ndk-build issues:
    • A bug that created inconsistent dependency files when a compilation error occured on Windows. This prevented a proper build after the error was fixed in the source code.
    • A Cygwin-specific bug where using very short paths for the Android NDK installation or the project path led to the generation of invalid dependency files. This made incremental builds impossible.
    • A typo that prevented the cpufeatures library from working correctly with the new NDK toolchain.
    • Builds in Cygwin are faster by avoiding calls to cygpath -m from GNU Make for every source or object file, which caused problems with very large source trees. In case this doesn't work properly, define NDK_USE_CYGPATH=1 in your environment to use cygpath -m again.
    • The Cygwin installation now notifies the user of invalid installation paths that contain spaces. Previously, an invalid path would output an error that complained about an incorrect version of GNU Make, even if the right one was installed.
  • Fixed a typo that prevented the NDK_MODULE_PATH environment variable from working properly when it contained multiple directories separated with a colon.
  • The prebuilt-common.sh script contains fixes to check the compiler for 64-bit generated machine code, instead of relying on the host tag, which allows the 32-bit toolchain to rebuild properly on Snow Leopard. The toolchain rebuild scripts now also support using a 32-bit host toolchain.
  • A missing declaration for INET_ADDRSTRLEN was added to <netinet/in.h>.
  • Missing declarations for IN6_IS_ADDR_MC_NODELOCAL and IN6_IS_ADDR_MC_GLOBAL were added to <netinet/in6.h>.
  • 'asm' was replaced with '__asm__' in <asm/byteorder.h> to allow compilation with -std=c99.

Android NDK, Revision 5 (December 2010)

This release of the NDK includes many new APIs, most of which are introduced to support the development of games and similar applications that make extensive use of native code. Using the APIs, developers have direct native access to events, audio, graphics and window management, assets, and storage. Developers can also implement the Android application lifecycle in native code with help from the new NativeActivity class. For detailed information describing the changes in this release, read the CHANGES.HTML document included in the downloaded NDK package.

General notes:
  • Adds support for native activities, which allows you to implement the Android application lifecycle in native code.
  • Adds native support for the following:
    • Input subsystem (such as the keyboard and touch screen)
    • Access to sensor data (accelerometer, compass, gyroscope, etc).
    • Event loop APIs to wait for things such as input and sensor events.
    • Window and surface subsystem
    • Audio APIs based on the OpenSL ES standard that support playback and recording as well as control over platform audio effects
    • Access to assets packaged in an .apk file.
  • Includes a new toolchain (based on GCC 4.4.3), which generates better code, and can also now be used as a standalone cross-compiler, for people who want to build their stuff with ./configure && make. See docs/STANDALONE-TOOLCHAIN.html for the details. The binaries for GCC 4.4.0 are still provided, but the 4.2.1 binaries were removed.
  • Adds support for prebuilt static and shared libraries (docs/PREBUILTS.html) and module exports and imports to make sharing and reuse of third-party modules much easier (docs/IMPORT-MODULE.html explains why).
  • Provides a default C++ STL implementation (based on STLport) as a helper module. It can be used either as a static or shared library (details and usage examples are in sources/android/stlport/README). Prebuilt binaries for STLport (static or shared) and GNU libstdc++ (static only) are also provided if you choose to compile against those libraries instead of the default C++ STL implementation. C++ Exceptions and RTTI are not supported in the default STL implementation. For more information, see docs/CPLUSPLUS-SUPPORT.HTML.
  • Includes improvements to the cpufeatures helper library that improves reporting of the CPU type (some devices previously reported ARMv7 CPU when the device really was an ARMv6). We recommend developers that use this library to rebuild their applications then upload to Google Play to benefit from the improvements.
  • Adds an EGL library that lets you create and manage OpenGL ES textures and services.
  • Adds new sample applications, native-plasma and native-activity, to demonstrate how to write a native activity.
  • Includes many bugfixes and other small improvements; see docs/CHANGES.html for a more detailed list of changes.

Android NDK, Revision 4b (June 2010)

NDK r4b notes:

Includes fixes for several issues in the NDK build and debugging scripts — if you are using NDK r4, we recommend downloading the NDK r4b build. For detailed information describing the changes in this release, read the CHANGES.TXT document included in the downloaded NDK package.

General notes:
  • Provides a simplified build system through the new ndk-build build command.
  • Adds support for easy native debugging of generated machine code on production devices through the new ndk-gdb command.
  • Adds a new Android-specific ABI for ARM-based CPU architectures, armeabi-v7a. The new ABI extends the existing armeabi ABI to include these CPU instruction set extensions:
    • Thumb-2 instructions
    • VFP hardware FPU instructions (VFPv3-D16)
    • Optional support for ARM Advanced SIMD (NEON) GCC intrinsics and VFPv3-D32. Supported by devices such as Verizon Droid by Motorola, Google Nexus One, and others.
  • Adds a new cpufeatures static library (with sources) that lets your app detect the host device's CPU features at runtime. Specifically, applications can check for ARMv7-A support, as well as VFPv3-D32 and NEON support, then provide separate code paths as needed.
  • Adds a sample application, hello-neon, that illustrates how to use the cpufeatures library to check CPU features and then provide an optimized code path using NEON instrinsics, if supported by the CPU.
  • Lets you generate machine code for either or both of the instruction sets supported by the NDK. For example, you can build for both ARMv5 and ARMv7-A architectures at the same time and have everything stored to your application's final .apk.
  • To ensure that your applications are available to users only if their devices are capable of running them, Google Play now filters applications based on the instruction set information included in your application — no action is needed on your part to enable the filtering. Additionally, the Android system itself also checks your application at install time and allows the installation to continue only if the application provides a library that is compiled for the device's CPU architecture.
  • Adds support for Android 2.2, including a new stable API for accessing the pixel buffers of Bitmap objects from native code.

Android NDK, Revision 3 (March 2010)

General notes:
  • Adds OpenGL ES 2.0 native library support.
  • Adds a sample application,hello-gl2, that illustrates the use of OpenGL ES 2.0 vertex and fragment shaders.
  • The toolchain binaries have been refreshed for this release with GCC 4.4.0, which should generate slightly more compact and efficient machine code than the previous one (4.2.1). The NDK also still provides the 4.2.1 binaries, which you can optionally use to build your machine code.

Android NDK, Revision 2 (September 2009)

Originally released as "Android 1.6 NDK, Release 1".

General notes:
  • Adds OpenGL ES 1.1 native library support.
  • Adds a sample application, san-angeles, that renders 3D graphics through the native OpenGL ES APIs, while managing activity lifecycle with a GLSurfaceView object.

Android NDK, Revision 1 (June 2009)

Originally released as "Android 1.5 NDK, Release 1".

General notes:
  • Includes compiler support (GCC) for ARMv5TE instructions, including Thumb-1 instructions.
  • Includes system headers for stable native APIs, documentation, and sample applications.

System and Software Requirements

The sections below describe the system and software requirements for using the Android NDK, as well as platform compatibility considerations that affect appplications using libraries produced with the NDK.

The Android SDK

  • A complete Android SDK installation (including all dependencies) is required.
  • Android 1.5 SDK or later version is required.

Supported operating systems

  • Windows XP (32-bit) or Vista (32- or 64-bit)
  • Mac OS X 10.4.8 or later (x86 only)
  • Linux (32 or 64-bit; Ubuntu 8.04, or other Linux distributions using GLibc 2.7 or later)

Required development tools

  • For all development platforms, GNU Make 3.81 or later is required. Earlier versions of GNU Make might work but have not been tested.
  • A recent version of awk (either GNU Awk or Nawk) is also required.
  • For Windows, Cygwin 1.7 or higher is required. The NDK will not work with Cygwin 1.5 installations.

Android platform compatibility

  • The native libraries created by the Android NDK can only be used on devices running specific minimum Android platform versions. The minimum required platform version depends on the CPU architecture of the devices you are targeting. The following table details which Android platform versions are compatible with native code developed for specific CPU architectures.
    Native Code CPU Architecture Used Compatible Android Platform(s)
    ARM, ARM-NEON Android 1.5 (API Level 3) and higher
    x86 Android 2.3 (API Level 9) and higher
    MIPS Android 2.3 (API Level 9) and higher

    These requirements mean you can use native libraries produced with the NDK in applications that are deployable to ARM-based devices running Android 1.5 or later. If you are deploying native libraries to x86 and MIPS-based devices, your application must target Android 2.3 or later.

  • To ensure compatibility, an application using a native library produced with the NDK must declare a <uses-sdk> element in its manifest file, with an android:minSdkVersion attribute value of "3" or higher. For example:
    <manifest>
      <uses-sdk android:minSdkVersion="3" />
      ...
    </manifest>
    
  • If you use this NDK to create a native library that uses the OpenGL ES APIs, the application containing the library can be deployed only to devices running the minimum platform versions described in the table below. To ensure compatibility, make sure that your application declares the proper android:minSdkVersion attribute value, as shown in the following table.
  • OpenGL ES Version Used Compatible Android Platform(s) Required uses-sdk Attribute
    OpenGL ES 1.1 Android 1.6 (API Level 4) and higher android:minSdkVersion="4"
    OpenGL ES 2.0 Android 2.0 (API Level 5) and higher android:minSdkVersion="5"

    For more information about API Level and its relationship to Android platform versions, see Android API Levels.

  • Additionally, an application using the OpenGL ES APIs should declare a <uses-feature> element in its manifest, with an android:glEsVersion attribute that specifies the minimum OpenGl ES version required by the application. This ensures that Google Play will show your application only to users whose devices are capable of supporting your application. For example:
    <manifest>
    
      <uses-feature android:glEsVersion="0x00020000" />
      ...
    </manifest>
    

    For more information, see the <uses-feature> documentation.

  • If you use this NDK to create a native library that uses the API to access Android Bitmap pixel buffers or utilizes native activities, the application containing the library can be deployed only to devices running Android 2.2 (API level 8) or higher. To ensure compatibility, make sure that your application declares <uses-sdk android:minSdkVersion="8" /> attribute value in its manifest.

Installing the NDK

Installing the NDK on your development computer is straightforward and involves extracting the NDK from its download package.

Before you get started make sure that you have downloaded the latest Android SDK and upgraded your applications and environment as needed. The NDK is compatible with older platform versions but not older versions of the SDK tools. Also, take a moment to review the System and Software Requirements for the NDK, if you haven't already.

To install the NDK, first download the appropriate package from the table at the top of this page. Then, follow the procedure for your development platform:

  • On Linux and Mac OS X (Darwin):
      1. Download the appropriate package from this page.
      2. Open a terminal window.
      3. Go to the directory to which you downloaded the package.
      4. Run chmod a+x on the downloaded package.
      5. Execute the package. For example:
      6. ndk$ chmod a+x android-ndk-r10c-darwin-x86_64.bin
        ndk$ ./android-ndk-r10c-darwin-x86_64.bin
                  

        The folder containing the NDK extracts itself.

        Note that you can also use a program like 7z to extract the package.

  • On Windows:
      1. Download the appropriate package from this page.
      2. Navigate to the folder to which you downloaded the package.
      3. Double-click the downloaded file. The folder containing the NDK extracts itself.
When uncompressed, the NDK files are contained in a directory called android-ndk-<version>. You can rename the NDK directory if necessary and you can move it to any location on your computer. This documentation refers to the NDK directory as <ndk>.

You are now ready to start working with the NDK.

Getting Started with the NDK

Once you've installed the NDK successfully, take a few minutes to read the documentation included in the NDK. You can find the documentation in the <ndk>/docs/ directory. In particular, please read the OVERVIEW.HTML document completely, so that you understand the intent of the NDK and how to use it.

If you used a previous version of the NDK, take a moment to review the list of NDK changes in the CHANGES.HTML document.

Here's the general outline of how you work with the NDK tools:

  1. Place your native sources under <project>/jni/...
  2. Create <project>/jni/Android.mk to describe your native sources to the NDK build system
  3. Optional: Create <project>/jni/Application.mk.
  4. Build your native code by running the 'ndk-build' script from your project's directory. It is located in the top-level NDK directory:
    cd <project>
    <ndk>/ndk-build
    

    The build tools copy the stripped, shared libraries needed by your application to the proper location in the application's project directory.

  5. Finally, compile your application using the SDK tools in the usual way. The SDK build tools will package the shared libraries in the application's deployable .apk file.

For complete information on all of the steps listed above, please see the documentation included with the NDK package.

Using the NDK

The Android framework provides two ways to use native code:

  • Write your application using the Android framework and use JNI to access the APIs provided by the Android NDK. This technique allows you to take advantage of the convenience of the Android framework, but still allows you to write native code when necessary. If you use this approach, your application must target specific, minimum Android platform levels, see Android platform compatibility for more information.
  • Write a native activity, which allows you to implement the lifecycle callbacks in native code. The Android SDK provides the NativeActivity class, which is a convenience class that notifies your native code of any activity lifecycle callbacks (onCreate(), onPause(), onResume(), etc). You can implement the callbacks in your native code to handle these events when they occur. Applications that use native activities must be run on Android 2.3 (API Level 9) or later.

    You cannot access features such as Services and Content Providers natively, so if you want to use them or any other framework API, you can still write JNI code to do so.

Contents of the NDK

The NDK contains the APIs, documentation, and sample applications that help you write your native code. Specifically:

  • A set of tools and build files used to generate native code libraries from C and C++ sources
  • A way to embed the corresponding native libraries into an application package file (.apk) that can be deployed on Android devices
  • A set of native system headers and libraries that will be supported in all future versions of the Android platform, starting from Android 1.5. Applications that use native activities must be run on Android 2.3 or later.
  • Documentation, samples, and tutorials

The latest release of the NDK supports the following instruction sets:

  • ARMv5TE, including Thumb-1 instructions (see docs/CPU-ARCH-ABIS.html for more information)
  • ARMv7-A, including Thumb-2 and VFPv3-D16 instructions, with optional support for NEON/VFPv3-D32 instructions (see docs/CPU-ARM-NEON.html for more information)
  • x86 instructions (see docs/CPU-X86.html for more information)
  • MIPS instructions (see docs/CPU-MIPS.html for more information)

ARMv5TE machine code will run on all ARM-based Android devices. ARMv7-A will run only on devices such as the Verizon Droid or Google Nexus One that have a compatible CPU. The main difference between the two instruction sets is that ARMv7-A supports hardware FPU, Thumb-2, and NEON instructions. You can target either or both of the instruction sets — ARMv5TE is the default, but switching to ARMv7-A is as easy as adding a single line to the application's Application.mk file, without needing to change anything else in the file. You can also build for both architectures at the same time and have everything stored in the final .apk. Complete information is provided in the CPU-ARCH-ABIS.HTML in the NDK package.

The NDK provides stable headers for libc (the C library), libm (the Math library), OpenGL ES (3D graphics library), the JNI interface, and other libraries, as listed in the Development tools section.

Development tools

The NDK includes a set of cross-toolchains (compilers, linkers, etc.) that can generate native ARM binaries on Linux, OS X, and Windows (with Cygwin) platforms.

It provides a set of system headers for stable native APIs that are guaranteed to be supported in all later releases of the platform:

  • libc (C library) headers
  • libm (math library) headers
  • JNI interface headers
  • libz (Zlib compression) headers
  • liblog (Android logging) header
  • OpenGL ES 1.1 and OpenGL ES 2.0 (3D graphics libraries) headers
  • libjnigraphics (Pixel buffer access) header (for Android 2.2 and above).
  • A Minimal set of headers for C++ support
  • OpenSL ES native audio libraries
  • Android native application APIS

The NDK also provides a build system that lets you work efficiently with your sources, without having to handle the toolchain/platform/CPU/ABI details. You create very short build files to describe which sources to compile and which Android application will use them — the build system compiles the sources and places the shared libraries directly in your application project.

Important: With the exception of the libraries listed above, native system libraries in the Android platform are not stable and may change in future platform versions. Your applications should only make use of the stable native system libraries provided in this NDK.

Documentation

The NDK package includes a set of documentation that describes the capabilities of the NDK and how to use it to create shared libraries for your Android applications. In this release, the documentation is provided only in the downloadable NDK package. You can find the documentation in the <ndk>/docs/ directory. Included are these files (partial listing):

  • INSTALL.HTML — describes how to install the NDK and configure it for your host system
  • OVERVIEW.HTML — provides an overview of the NDK capabilities and usage
  • ANDROID-MK.HTML — describes the use of the Android.mk file, which defines the native sources you want to compile
  • APPLICATION-MK.HTML — describes the use of the Application.mk file, which describes the native sources required by your Android application
  • CPLUSPLUS-SUPPORT.HTML — describes the C++ support provided in the Android NDK
  • CPU-ARCH-ABIS.HTML — a description of supported CPU architectures and how to target them.
  • CPU-FEATURES.HTML — a description of the cpufeatures static library that lets your application code detect the target device's CPU family and the optional features at runtime.
  • CHANGES.HTML — a complete list of changes to the NDK across all releases.
  • DEVELOPMENT.HTML — describes how to modify the NDK and generate release packages for it
  • HOWTO.HTML — information about common tasks associated with NDK development
  • IMPORT-MODULE.HTML — describes how to share and reuse modules
  • LICENSES.HTML — information about the various open source licenses that govern the Android NDK
  • NATIVE-ACTIVITY.HTML — describes how to implement native activities
  • NDK-BUILD.HTML — describes the usage of the ndk-build script
  • NDK-GDB.HTML — describes how to use the native code debugger
  • PREBUILTS.HTML — information about how shared and static prebuilt libraries work
  • STANDALONE-TOOLCHAIN.HTML — describes how to use Android NDK toolchain as a standalone compiler (still in beta).
  • SYSTEM-ISSUES.HTML — known issues in the Android system images that you should be aware of, if you are developing using the NDK.
  • STABLE-APIS.HTML — a complete list of the stable APIs exposed by headers in the NDK.

Additionally, the package includes detailed information about the "bionic" C library provided with the Android platform that you should be aware of, if you are developing using the NDK. You can find the documentation in the <ndk>/docs/system/libc/ directory:

  • OVERVIEW.HTML — provides an overview of the "bionic" C library and the features it offers.

Sample apps

The NDK includes sample applications that illustrate how to use native code in your Android applications:

  • hello-jni — a simple application that loads a string from a native method implemented in a shared library and then displays it in the application UI.
  • two-libs — a simple application that loads a shared library dynamically and calls a native method provided by the library. In this case, the method is implemented in a static library imported by the shared library.
  • san-angeles — a simple application that renders 3D graphics through the native OpenGL ES APIs, while managing activity lifecycle with a GLSurfaceView object.
  • hello-gl2 — a simple application that renders a triangle using OpenGL ES 2.0 vertex and fragment shaders.
  • hello-neon — a simple application that shows how to use the cpufeatures library to check CPU capabilities at runtime, then use NEON intrinsics if supported by the CPU. Specifically, the application implements two versions of a tiny benchmark for a FIR filter loop, a C version and a NEON-optimized version for devices that support it.
  • bitmap-plasma — a simple application that demonstrates how to access the pixel buffers of Android Bitmap objects from native code, and uses this to generate an old-school "plasma" effect.
  • native-activity — a simple application that demonstrates how to use the native-app-glue static library to create a native activity
  • native-plasma — a version of bitmap-plasma implemented with a native activity.

For each sample, the NDK includes the corresponding C source code and the necessary Android.mk and Application.mk files. There are located under <ndk>/samples/<name>/ and their source code can be found under <ndk>/samples/<name>/jni/.

You can build the shared libraries for the sample apps by going into <ndk>/samples/<name>/ then calling the ndk-build command. The generated shared libraries will be located under <ndk>/samples/<name>/libs/armeabi/ for (ARMv5TE machine code) and/or <ndk>/samples/<name>/libs/armeabi-v7a/ for (ARMv7 machine code).

Next, build the sample Android applications that use the shared libraries:

  • If you are developing in Eclipse with ADT, use the New Project Wizard to create a new Android project for each sample, using the "Import from Existing Source" option and importing the source from <ndk>/samples/<name>/. Then, set up an AVD, if necessary, and build/run the application in the emulator.
  • If you are developing with Ant, use the android tool to create the build file for each of the sample projects at <ndk>/samples/<name>/. Then set up an AVD, if necessary, build your project in the usual way, and run it in the emulator.

For more information about developing with the Android SDK tools and what you need to do to create, build, and run your applications, see the Overview section for developing on Android.

Exploring the hello-jni Sample

The hello-jni sample is a simple demonstration on how to use JNI from an Android application. The HelloJni activity receives a string from a simple C function and displays it in a TextView.

The main components of the sample include:

  • The familiar basic structure of an Android application (an AndroidManifest.xml file, a src/ and res directories, and a main activity)
  • A jni/ directory that includes the implemented source file for the native code as well as the Android.mk file
  • A tests/ directory that contains unit test code.
  1. Create a new project in Eclipse from the existing sample source or use the android tool to update the project so it generates a build.xml file that you can use to build the sample.
    • In Eclipse:
      1. Click File > New Android Project...
      2. Select the Create project from existing source radio button.
      3. Select any API level above Android 1.5.
      4. In the Location field, click Browse... and select the <ndk-root>/samples/hello-jni directory.
      5. Click Finish.
    • On the command line:
      1. Change to the <ndk-root>/samples/hello-jni directory.
      2. Run the following command to generate a build.xml file:
        android update project -p . -s
  2. Compile the native code using the ndk-build command.
    cd <ndk-root>/samples/hello-jni
    <ndk_root>/ndk-build
    
  3. Build and install the application as you would a normal Android application. If you are using Eclipse, run the application to build and install it on a device. If you are using Ant, run the following commands from the project directory:
    ant debug
    adb install bin/HelloJni-debug.apk
    

When you run the application on the device, the string Hello JNI should appear on your device. You can explore the rest of the samples that are located in the <ndk-root>/samples directory for more examples on how to use the JNI.

Exploring the native-activity Sample Application

The native-activity sample provided with the Android NDK demonstrates how to use the android_native_app_glue static library. This static library makes creating a native activity easier by providing you with an implementation that handles your callbacks in another thread, so you do not have to worry about them blocking your main UI thread. The main parts of the sample are described below:

  • The familiar basic structure of an Android application (an AndroidManifest.xml file, a src/ and res directories). The AndroidManifest.xml declares that the application is native and specifies the .so file of the native activity. See NativeActivity for the source or see the <ndk_root>/platforms/samples/native-activity/AndroidManifest.xml file.
  • A jni/ directory contains the native activity, main.c, which uses the android_native_app_glue.h interface to implement the activity. The Android.mk that describes the native module to the build system also exists here.

To build this sample application:

  1. Create a new project in Eclipse from the existing sample source or use the android tool to update the project so it generates a build.xml file that you can use to build the sample.
    • In Eclipse:
      1. Click File > New Android Project...
      2. Select the Create project from existing source radio button.
      3. Select any API level above Android 2.3.
      4. In the Location field, click Browse... and select the <ndk-root>/samples/native-activity directory.
      5. Click Finish.
    • On the command line:
      1. Change to the <ndk-root>/samples/native-activity directory.
      2. Run the following command to generate a build.xml file:
        android update project -p . -s
        
  2. Compile the native code using the ndk-build command.
    cd <ndk-root>/platforms/samples/android-9/samples/native-activity
    <ndk_root>/ndk-build
    
  3. Build and install the application as you would a normal Android application. If you are using Eclipse, run the application to build and install it on a device. If you are using Ant, run the following commands in the project directory, then run the application on the device:
    ant debug
    adb install bin/NativeActivity-debug.apk
    
ubuntu-make-16.02.1/tests/data/server-content/developer.android.com/android-sdk_r24.0.1-linuz.tgz0000664000000000000000000000037212656574623027312 0ustar 9Uandroid-sdk_r24.0.1-linuz.tar 0]FqϣMP2gP$PKk6 UYHxGcJ4^_TZFXlbQzץmsgܹ_*5M+=F' s[{uX_wy8'ycuޓrǺ[@~ғ(ubuntu-make-16.02.1/tests/data/server-content/developer.android.com/android-studio-fake.tgz0000664000000000000000000000063012656574623026616 0ustar ;Un@)uy.Vaw)ZEuM|7k 0Uٙw6+KZKO%{e\IAA2MJ`BE9ajSTlo}"+¿/ר :o>UKKNԄ@~k5_%fUaLqjliig5'ɵEb o mtKo;o7^U>r~gT:?e[٭{u$Sv_6Xcpc[(o0ƨTspAc_/o%P hֹbHvfgA. ubuntu-make-16.02.1/tests/data/server-content/developer.android.com/sdk/0000775000000000000000000000000012656574623023021 5ustar ubuntu-make-16.02.1/tests/data/server-content/developer.android.com/sdk/index.html0000664000000000000000000017340512656574623025030 0ustar Download Android Studio and SDK Tools | Android Developers
 

Android Studio

The official Android IDE

  • Android Studio IDE
  • Android SDK tools
  • Android 5.0 (Lollipop) Platform
  • Android 5.0 emulator system image with Google APIs
Download Android Studio

To get Android Studio or stand-alone SDK tools, visit developer.android.com/sdk/

Intelligent code editor

At the core of Android Studio is an intelligent code editor capable of advanced code completion, refactoring, and code analysis.

The powerful code editor helps you be a more productive Android app developer.

Code templates and GitHub integration

New project wizards make it easier than ever to start a new project.

Start projects using template code for patterns such as navigation drawer and view pagers, and even import Google code samples from GitHub.

Multi-screen app development

Build apps for Android phones, tablets, Android Wear, Android TV, Android Auto and Google Glass.

With the new Android Project View and module support in Android Studio, it's easier to manage app projects and resources.

Virtual devices for all shapes and sizes

Android Studio comes pre-configured with an optimized emulator image.

The updated and streamlined Virtual Device Manager provides pre-defined device profiles for common Android devices.

Android builds evolved, with Gradle

Create multiple APKs for your Android app with different features using the same project.

Manage app dependencies with Maven.

Build APKs from Android Studio or the command line.

More about Android Studio

Download Android Studio
  • Built on IntelliJ IDEA Community Edition, the popular Java IDE by JetBrains.
  • Flexible Gradle-based build system.
  • Build variants and multiple APK generation.
  • Expanded template support for Google Services and various device types.
  • Rich layout editor with support for theme editing.
  • Lint tools to catch performance, usability, version compatibility, and other problems.
  • ProGuard and app-signing capabilities.
  • Built-in support for Google Cloud Platform, making it easy to integrate Google Cloud Messaging and App Engine.

For more details about features available in Android Studio, read the guide to Android Studio Basics.

If you have been using Eclipse with ADT, be aware that Android Studio is now the official IDE for Android, so you should migrate to Android Studio to receive all the latest IDE updates. For help moving projects, see Migrating to Android Studio.

System Requirements

Windows

  • Microsoft® Windows® 8/7/Vista/2003 (32 or 64-bit)
  • 2 GB RAM minimum, 4 GB RAM recommended
  • 400 MB hard disk space + at least 1 G for Android SDK, emulator system images, and caches
  • 1280 x 800 minimum screen resolution
  • Java Development Kit (JDK) 7
  • Optional for accelerated emulator: Intel® processor with support for Intel® VT-x, Intel® EM64T (Intel® 64), and Execute Disable (XD) Bit functionality

Mac OS X

  • Mac® OS X® 10.8.5 or higher, up to 10.9 (Mavericks)
  • 2 GB RAM minimum, 4 GB RAM recommended
  • 400 MB hard disk space
  • At least 1 GB for Android SDK, emulator system images, and caches
  • 1280 x 800 minimum screen resolution
  • Java Runtime Environment (JRE) 6
  • Java Development Kit (JDK) 7
  • Optional for accelerated emulator: Intel® processor with support for Intel® VT-x, Intel® EM64T (Intel® 64), and Execute Disable (XD) Bit functionality

On Mac OS, run Android Studio with Java Runtime Environment (JRE) 6 for optimized font rendering. You can then configure your project to use Java Development Kit (JDK) 6 or JDK 7.

Linux

  • GNOME or KDE desktop
  • GNU C Library (glibc) 2.11 or later
  • 2 GB RAM minimum, 4 GB RAM recommended
  • 400 MB hard disk space
  • At least 1 GB for Android SDK, emulator system images, and caches
  • 1280 x 800 minimum screen resolution
  • Oracle® Java Development Kit (JDK) 7

Tested on Ubuntu® 12.04, Precise Pangolin (64-bit distribution capable of running 32-bit applications.

Other Download Options

SDK Tools Only

If you prefer to use a different IDE or run the tools from the command line or with build scripts, you can instead download the stand-alone Android SDK Tools. These packages provide the basic SDK tools for app development, without an IDE. Also see the SDK tools release notes.

Platform Package Size SHA-1 Checksum
Windows installer_r24.0.1-windows.exe (Recommended) 92180986 bytes 505d7a95647bccc194b7aa707854422d9c7288d5
android-sdk_r24.0.1-windows.zip 140743633 bytes cc49974e8bfcc865ffe0d887e9a74cf52085c632
Mac OS X android-sdk_r24.0.1-macosx.zip 88535741 bytes 7097c09c72645d7ad33c81a37b1a1363a9df2a54
Linux android-sdk_r24.0.1-linux.tgz 141304203 bytes bc1ccd6b05beb06f59a2011c5a7f2bbab8e87f02

All Android Studio Packages

Select a specific Android Studio package for your platform. Also see the Android Studio release notes.

Platform Package Size SHA-1 Checksum
Windows android-studio-bundle-135.1641136.exe
(Recommended)
868344232 bytes 1931dbaeadb52f5e0a8ba6e2ae60d9df20b2076b
android-studio-ide-135.1641136.exe
(No SDK tools included)
260272840 bytes 464d1c5497ab3d1bdef441365791ab36c89cd5ae
android-studio-ide-135.1641136-windows.zip 246249059 bytes 6d6856aca83f6ff747ca40b10f70edfbbcccd91c
Mac OS X android-studio-ide-1641136.dmg 245729073 bytes 49506ba2cf6b56be4f7d07e6a00c4ec3ba2249d5
Linux android-studio-ide-135.1641136-linux.zip 243917559 bytes d8362a0c2ffc07b1b19c4b9001c8532de5a4b8c3
././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/developer.android.com/android-ndk-r10d-linux-x86_64.binubuntu-make-16.02.1/tests/data/server-content/developer.android.com/android-ndk-r10d-linux-x86_64.bi0000775000000000000000000000041512656574623027606 0ustar #!/bin/bash echo "Version 64 bits" dest=android-ndk-foo while getopts "o:" opt; do case $opt in o) dest=$OPTARG/$dest ;; esac done mkdir -p $dest for bin in ndk-which ndk-build; do echo "#!/bin/sh" > $dest/$bin chmod +x $dest/$bin done ubuntu-make-16.02.1/tests/data/server-content/www.mozilla.org/0000775000000000000000000000000012656574623021137 5ustar ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.mozilla.org/?product=firefox-aurora-latest-l10n&os=linux&lang=bgubuntu-make-16.02.1/tests/data/server-content/www.mozilla.org/?product=firefox-aurora-latest-l10n&os0000664000000000000000000000044212656574623030262 0ustar V Un0 @{+v/N;.JӪ~DjZ$A 0xbQYxT @*O`(qʢμCs}q Cmc c,GEJMvY{?Z~DfXkOZ;/}$׆"wy X?OU*E~sn_]0oR.M}_vGW֊9O݁6ǰڿ`d L'UO;ubuntu-make-16.02.1/tests/data/server-content/www.mozilla.org/en-US/0000775000000000000000000000000012656574623022066 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.mozilla.org/en-US/firefox/0000775000000000000000000000000012656574623023530 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.mozilla.org/en-US/firefox/developer/0000775000000000000000000000000012656574623025515 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.mozilla.org/en-US/firefox/developer/all0000664000000000000000000042023612656574623026217 0ustar Mozilla Firefox Web Browser — Download Developer Edition in your language — Mozilla
Mozilla

Firefox Developer Edition

Download Developer Edition in your language

Download Firefox Developer Edition in your language to experience the newest features and innovations in an unstable environment even before they go to Beta. Give us feedback that will determine what makes it to Final Release and help shape the future of Firefox.

Check the system requirements
Release notes

Fully localized versions

Language Windows Windows 64-bit Mac OS X Linux Linux 64-bit
Acholi Acholi Download Download Download Download Download
Afrikaans Afrikaans Download Download Download Download Download
Albanian Shqip Download Download Download Download Download
Arabic عربي Download Download Download Download Download
Aragonese aragonés Download Download Download Download Download
Armenian Հայերեն Download Download Download Download Download
Assamese অসমীয়া Download Download Download Download Download
Asturian Asturianu Download Download Download Download Download
Azerbaijani Azərbaycanca Download Download Download Download Download
Basque Euskara Download Download Download Download Download
Belarusian Беларуская Download Download Download Download Download
Bengali (Bangladesh) বাংলা (বাংলাদেশ) Download Download Download Download Download
Bengali (India) বাংলা (ভারত) Download Download Download Download Download
Bodo बर' Download Download Download Download Download
Bosnian Bosanski Download Download Download Download Download
Breton Brezhoneg Download Download Download Download Download
Bulgarian Български Download Download Download Download Download
Burmese မြန်မာဘာသာ Download Download Download Download Download
Catalan Català Download Download Download Download Download
Chinese (Simplified) 中文 (简体) Download Download Download Download Download
Chinese (Traditional) 正體中文 (繁體) Download Download Download Download Download
Croatian Hrvatski Download Download Download Download Download
Czech Čeština Download Download Download Download Download
Danish Dansk Download Download Download Download Download
Dutch Nederlands Download Download Download Download Download
English (British) English (British) Download Download Download Download Download
English (South African) English (South African) Download Download Download Download Download
English (US) English (US) Download Download Download Download Download
Esperanto Esperanto Download Download Download Download Download
Estonian Eesti keel Download Download Download Download Download
Finnish suomi Download Download Download Download Download
French Français Download Download Download Download Download
Frisian Frysk Download Download Download Download Download
Fulah Pulaar-Fulfulde Download Download Download Download Download
Gaelic (Scotland) Gàidhlig Download Download Download Download Download
Galician Galego Download Download Download Download Download
German Deutsch Download Download Download Download Download
Greek Ελληνικά Download Download Download Download Download
Gujarati (India) ગુજરાતી (ભારત) Download Download Download Download Download
Hebrew עברית Download Download Download Download Download
Hindi (India) हिन्दी (भारत) Download Download Download Download Download
Hungarian magyar Download Download Download Download Download
Icelandic íslenska Download Download Download Download Download
Indonesian Bahasa Indonesia Download Download Download Download Download
Irish Gaeilge Download Download Download Download Download
Italian Italiano Download Download Download Download Download
Japanese 日本語 Download Download Download Download Download
Kannada ಕನ್ನಡ Download Download Download Download Download
Kashmiri كشمیری Download Download Download Download Download
Kazakh Қазақ Download Download Download Download Download
Khmer ខ្មែរ Download Download Download Download Download
Konkani कोंकनी Download Download Download Download Download
Korean 한국어 Download Download Download Download Download
Latvian Latviešu Download Download Download Download Download
Ligurian Ligure Download Download Download Download Download
Lithuanian lietuvių kalba Download Download Download Download Download
Lower Sorbian Dolnoserbšćina Download Download Download Download Download
Macedonian Македонски Download Download Download Download Download
Maithili मैथिली মৈথিলী Download Download Download Download Download
Malay Melayu Download Download Download Download Download
Malayalam മലയാളം Download Download Download Download Download
Marathi मराठी Download Download Download Download Download
Norwegian (Bokmål) Norsk bokmål Download Download Download Download Download
Norwegian (Nynorsk) Norsk nynorsk Download Download Download Download Download
Occitan (Lengadocian) occitan (lengadocian) Download Download Download Download Download
Oriya ଓଡ଼ିଆ Download Download Download Download Download
Persian فارسی Download Download Download Download Download
Polish Polski Download Download Download Download Download
Portuguese (Brazilian) Português (do Brasil) Download Download Download Download Download
Portuguese (Portugal) Português (Europeu) Download Download Download Download Download
Punjabi (India) ਪੰਜਾਬੀ (ਭਾਰਤ) Download Download Download Download Download
Romanian română Download Download Download Download Download
Romansh rumantsch Download Download Download Download Download
Russian Русский Download Download Download Download Download
Santali संताली Download Download Download Download Download
Serbian Српски Download Download Download Download Download
Sinhala සිංහල Download Download Download Download Download
Slovak slovenčina Download Download Download Download Download
Slovenian Slovenščina Download Download Download Download Download
Songhai Soŋay Download Download Download Download Download
Spanish (Argentina) Español (de Argentina) Download Download Download Download Download
Spanish (Chile) Español (de Chile) Download Download Download Download Download
Spanish (Mexico) Español (de México) Download Download Download Download Download
Spanish (Spain) Español (de España) Download Download Download Download Download
Swedish Svenska Download Download Download Download Download
Tamil தமிழ் Download Download Download Download Download
Telugu తెలుగు Download Download Download Download Download
Thai ไทย Download Download Download Download Download
Turkish Türkçe Download Download Download Download Download
Ukrainian Українська Download Download Download Download Download
Upper Sorbian Hornjoserbsce Download Download Download Download Download
Uzbek Oʻzbek tili Download Download Download Download Download
Vietnamese Tiếng Việt Download Download Download Download Download
Welsh Cymraeg Download Download Download Download Download
Xhosa isiXhosa Download Download Download Download Download

No matching languages found.

././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.mozilla.org/?product=firefox-aurora-latest-ssl&os=linux64&lang=en-USubuntu-make-16.02.1/tests/data/server-content/www.mozilla.org/?product=firefox-aurora-latest-ssl&os=0000777000000000000000000000000012656574623042605 2?product=firefox-aurora-latest-ssl&os=linux&lang=en-USustar ././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.mozilla.org/?product=firefox-aurora-latest-ssl&os=linux&lang=en-USubuntu-make-16.02.1/tests/data/server-content/www.mozilla.org/?product=firefox-aurora-latest-ssl&os=0000664000000000000000000000045012656574623030405 0ustar _~UQN0 @Sd{ Ѝ"fJ@uӄ&ǭZn_]sv2ƠHQxDH5 H',kܷ!6\9Ѝf|gt%_mphn}iBJ Eclipse Downloads Skip to main content
Eclipse Mars.1 (4.5.1) Release for

Try the Eclipse Installer NEW

The easiest way to install and update your Eclipse Development Environment.

Mac OS X

Windows

Linux

5 Steps to Install Eclipse

For the Mars release, we are introducing a new Eclipse installer. This is a new and more efficient way to install Eclipse. It is a proper installer, so no more zip files, with a self extracting download that will lead you through the installation experience. For those not into installers, we still have the packages and zip files available on our download pages.


1. Download the Eclipse Installer

Eclipse is hosted on many mirrors around the world. Please select the one closest to you and start to download the Installer


2. Start the Eclipse Installer executable

For Windows users, after the Eclipse Installer executable has finished downloading it should be available in your download directory. Start the Eclipse Installer executable. You may get a security warning to run this file. If the Eclipse Foundation is the Publisher, you are good to select Run.

For Mac and Linux users, you will still need to unzip the download to create the Installer. Start the Installer once it is available.

Screenshot of the Eclipse Installer executable.

3. Select the package to install

The new Eclipse Installer shows the packages available to Eclipse users. You can search for the package you want to install or scroll through the list.

Select and click on the package you want to install.

Screenshot of the Eclipse packages.

4. Select your installation folder

Specify the folder where you want Eclipse to be installed. The default folder will be in your User directory.

Select the ‘Install’ button to begin the installation.

Screenshot of the Install window.

5. Launch Eclipse

Once the installation is complete you can now launch Eclipse. The Eclipse Installer has done it's work. Happy coding.

Screenshot of the Launch window.

...or download an Eclipse Package

Eclipse IDE for Java EE Developers

Eclipse IDE for Java EE Developers

  • 273 MB
  • 1,850,647 DOWNLOADS

Tools for Java developers creating Java EE and Web applications, including a Java IDE, tools for Java EE, JPA, JSF, Mylyn...

Run your Apps on the Cloud

Want Eclipse in the cloud? IBM Bluemix makes it easy. Sign up to begin building today!

Eclipse IDE for Java Developers

Eclipse IDE for Java Developers

  • 165 MB
  • 908,477 DOWNLOADS

The essential tools for any Java developer, including a Java IDE, a Git client, XML Editor, Mylyn, Maven integration and WindowBuilder...

Eclipse IDE for C/C++ Developers

Eclipse IDE for C/C++ Developers

  • 182 MB
  • 373,036 DOWNLOADS

An IDE for C/C++ developers with Mylyn integration.

Eclipse IDE for Eclipse Committers 4.5.1

Eclipse IDE for Eclipse Committers 4.5.1

  • 243 MB
  • 264,159 DOWNLOADS

Package suited for development of Eclipse itself at Eclipse.

Eclipse for PHP Developers

Eclipse for PHP Developers

  • 152 MB
  • 244,573 DOWNLOADS

The essential tools for any PHP developer, including PHP language support, Git client, Mylyn and editors for JavaScript, HTML, CSS and...

Eclipse IDE for Java and DSL Developers

Eclipse IDE for Java and DSL Developers

  • 295 MB
  • 157,313 DOWNLOADS

The essential tools for Java and DSL developers, including a Java & Xtend IDE, a DSL Framework (Xtext), a Git client.

Eclipse IDE for Automotive Software Developers

Eclipse IDE for Automotive Software Developers

  • 235 MB
  • 137,029 DOWNLOADS

This package contains frameworks and tools used for the development of embedded automotive software: In addition to Eclipse Platform, Java Development...

Eclipse for RCP and RAP Developers

Eclipse for RCP and RAP Developers

  • 257 MB
  • 132,249 DOWNLOADS

A complete set of tools for developers who want to create Eclipse plug-ins, Rich Client Applications or Remote Application Platform (RCP+RAP).

Eclipse Modeling Tools

Eclipse Modeling Tools

  • 363 MB
  • 129,097 DOWNLOADS

The Modeling package provides tools and runtimes for building model-based applications.

Eclipse IDE for Java and Report Developers

Eclipse IDE for Java and Report Developers

  • 298 MB
  • 127,157 DOWNLOADS

Java EE tools and BIRT reporting tool for Java developers to create Java EE and Web applications that also have reporting...

Eclipse for Parallel Application Developers

Eclipse for Parallel Application Developers

  • 225 MB
  • 118,544 DOWNLOADS

Tools for C, C++, Fortran, and UPC, including MPI, OpenMP, OpenACC, a parallel debugger, and remotely building, running and monitoring applications...

Eclipse for Testers

Eclipse for Testers

  • 116 MB
  • 116,335 DOWNLOADS

This package contains Eclipse features that support the software development quality assurance process, such as Jubula and Mylyn.

Eclipse for Scout Developers

Eclipse for Scout Developers

  • 312 MB
  • 110,889 DOWNLOADS

Eclipse Scout is a framework to develop Java/Eclipse based business applications that run on the desktop, in browsers, and on mobile.

Hint

You will need a Java runtime environment (JRE) to use Eclipse (Java SE 7 or greater is recommended). All downloads are provided under the terms and conditions of the Eclipse Foundation Software User Agreement unless otherwise specified.

Back to the top

ubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/downloads/images/0000775000000000000000000000000012656574623024353 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/downloads/images/cdt.png0000664000000000000000000000000012656574623025621 0ustar ubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/downloads/images/php.png0000664000000000000000000000000012656574623025636 0ustar ubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/downloads/images/java.png0000664000000000000000000000000012656574623025770 0ustar ubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/0000775000000000000000000000000012656574623023267 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/epp/0000775000000000000000000000000012656574623024053 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/epp/downloads/0000775000000000000000000000000012656574623026045 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/epp/downloads/release/0000775000000000000000000000000012656574623027465 5ustar ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/epp/downloads/release/version/ubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/epp/downloads/release/versi0000775000000000000000000000000012656574623030536 5ustar ././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/epp/downloads/release/version/point_release/ubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/epp/downloads/release/versi0000775000000000000000000000000012656574623030536 5ustar ././@LongLink0000644000000000000000000000023200000000000011600 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/epp/downloads/release/version/point_release/eclipse-java-linux-gtk.tar.gz.sha512ubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/epp/downloads/release/versi0000664000000000000000000000024012656574623030534 0ustar c58b4e12d671ea45d6c73c39adbb34a9763e42b888d52d1bf31420a894e160ba2f8ed52a0bc95e6b2b55e671cb54ead2e39dd5728738151ad2b2acc665c5621b eclipse-java-linux-gtk.tar.gz ././@LongLink0000644000000000000000000000023100000000000011577 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/epp/downloads/release/version/point_release/eclipse-php-linux-gtk-x86_64.tar.gzubuntu-make-16.02.1/tests/data/server-content/www.eclipse.org/technology/epp/downloads/release/versi0000664000000000000000000000041412656574623030537 0ustar ЎTJ0\)"]dɉo#,nJ7U 1h '.)Ԣ 9IΪ92QN iK^j^ hc;m+N}c)Ԣ 5rIΪ924Җ<-AJv86wsoT8cJ3\Zk(2cT%)Ԣ 5rIΪ924Җ<-AJv86wsoT8cJ3\Zk(2cT%)Ԣ 5rIΪ924Җ<-AJv86wsoT8cJ3\Zk(2cT% Swift.org - Download Swift

Download Swift

Latest Development Snapshots

Development Snapshots are prebuilt binaries that are automatically created from mainline development branches. These snapshots are not official releases. They have gone through automated unit testing, but they have not gone through the full testing that is performed for official releases.

Platform Download Date
Apple Platforms Xcode Swift 2.2 Snapshot Debugging Symbols
Linux Ubuntu 15.10 Swift 2.2 Snapshot Signature
Linux Ubuntu 14.04 Swift 2.2 Snapshot Signature

Swift is covered by the Swift License at swift.org/LICENSE.txt.

Apple Platforms

Xcode includes a release of Swift that is supported by Apple. You can try out a version that is still in development by downloading one of the packages above.

Playgrounds are not currently supported for downloadable Swift packages.

To submit to the App Store you must build your app using the version of Swift that comes included within Xcode.

Requirements for Tools

  • OS X 10.11 (El Capitan)
  • Xcode 7.2 (including prerelease versions)

Supported Target Platforms

  • OS X 10.9.0 or later
  • iOS 7.0 or later
  • watchOS 2.0 or later
  • tvOS 9.0 or later

Installation

  1. Download the latest package release.

  2. Run the package installer, which will install an Xcode toolchain into /Library/Developer/Toolchains/.

    An Xcode toolchain (.xctoolchain) includes a copy of the compiler, lldb, and other related tools needed to provide a cohesive development experience for working in a specific version of Swift.

  3. Quit Xcode if it is already running.

  4. Start Xcode with the custom toolchain you downloaded to enable the open source version of Swift:

    $ xcrun launch-with-toolchain /Library/Developer/Toolchains/swift-latest.xctoolchain
    

    swift-latest.xctoolchain is a symlink to your most recently installed toolchain, such as swift-2.2-SNAPSHOT-2015-12-01-a.xctoolchain. The name of each toolchain indicates the date the toolchain was built from the open source master branch (which tracks bleeding-edge development on Swift).

    Within a running instance of Xcode launched with launch-with-toolchain, Xcode uses the downloaded toolchain for building Swift code, debugging, and even code completion and syntax coloring. If you quit Xcode, you must relaunch it with launch-with-toolchain to continue using the downloaded toolchain; otherwise, Xcode uses its default toolchain the next time you launch it.

  5. To use the Swift tools directly from the command line, add the Swift toolchain to your path as follows:

    $ export PATH=/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin:"${PATH}"
    

Code Signing on OS X

The OS X .pkg files are digitally signed by the developer ID of the Swift open source project to allow verification that they have not been tampered with. All binaries in the package are signed as well.

The Swift toolchain installer on OS X should display a lock icon on the right side of the title bar. Clicking the lock brings up detailed information about the signature. The signature should be produced by Developer ID Installer: Swift Open Source (V9AUD2URP3).

If the lock is not displayed or the signature is not produced by the Swift open source developer ID, do not proceed with the installation. Instead, quit the installer and please email swift-infrastructure@swift.org with as much detail as possible, so that we can investigate the problem.

Older Releases

Download Date
Xcode Swift 2.2 Snapshot Debugging Symbols
Xcode Swift 2.2 Snapshot Debugging Symbols
Xcode Swift 2.2 Snapshot Debugging Symbols
Xcode Swift 2.2 Snapshot Debugging Symbols
Xcode Swift 2.2 Snapshot Debugging Symbols
Xcode Swift 2.2 Snapshot Debugging Symbols

Linux

Packages for Linux are tar archives including a copy of the Swift compiler, lldb, and related tools. You can install them anywhere as long as the extracted tools are in your PATH.

Note that nothing prevents Swift from being ported to other Linux distributions beyond the ones mentioned below. These are only the distributions where these binaries have been built and tested.

Requirements

  • Ubuntu 14.04 or 15.10 (64-bit)

Supported Target Platforms

  • Ubuntu 14.04 or 15.10 (64-bit)

Older Releases

Download Date
Ubuntu 15.10 Swift 2.2 Snapshot Signature
Ubuntu 15.10 Swift 2.2 Snapshot Signature
Ubuntu 15.10 Swift 2.2 Snapshot Signature
Ubuntu 15.10 Swift 2.2 Snapshot Signature
Ubuntu 15.10 Swift 2.2 Snapshot Signature
Ubuntu 15.10 Swift 2.2 Snapshot Signature
Download Date
Ubuntu 14.04 Swift 2.2 Snapshot Signature
Ubuntu 14.04 Swift 2.2 Snapshot Signature
Ubuntu 14.04 Swift 2.2 Snapshot Signature
Ubuntu 14.04 Swift 2.2 Snapshot Signature
Ubuntu 14.04 Swift 2.2 Snapshot Signature
Ubuntu 14.04 Swift 2.2 Snapshot Signature

Installation

  1. Install required dependencies:

    $ sudo apt-get install clang libicu-dev
    
  2. Download the latest binary release above.

    The swift-<VERSION>-<PLATFORM>.tar.gz file is the toolchain itself. The .sig file is the digital signature.

  3. If you are downloading Swift packages for the first time, import the PGP keys into your keyring:

    $ gpg --keyserver hkp://pool.sks-keyservers.net \
          --recv-keys \
          '7463 A81A 4B2E EA1B 551F  FBCF D441 C977 412B 37AD' \
          '1BE1 E29A 084C B305 F397  D62A 9F59 7F4D 21A5 6D5F'
    

    or:

    $ wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
    

    Skip this step if you have imported the keys in the past.

  4. Verify the PGP signature.

    The .tar.gz archives for Linux are signed using GnuPG with one of the keys of the Swift open source project. Everyone is strongly encouraged to verify the signatures before using the software.

    First, refresh the keys to download new key revocation certificates, if any are available:

    $ gpg --keyserver hkp://pool.sks-keyservers.net --refresh-keys Swift
    

    Then, use the signature file to verify that the archive is intact:

    $ gpg --verify swift-<VERSION>-<PLATFORM>.tar.gz.sig
    ...
    gpg: Good signature from "Swift Automatic Signing Key #1 <swift-infrastructure@swift.org>"
    

    If gpg fails to verify because you don’t have the public key (gpg: Can't check signature: No public key), please follow the instructions in Active Signing Keys below to import the keys into your keyring.

    You might see a warning:

    gpg: WARNING: This key is not certified with a trusted signature!
    gpg:          There is no indication that the signature belongs to the owner.
    

    This warning means that there is no path in the Web of Trust between this key and you. The warning is harmless as long as you have followed the steps above to retrieve the key from a trusted source.

    If gpg fails to verify and reports “BAD signature”, do not use the downloaded toolchain. Instead, please email swift-infrastructure@swift.org with as much detail as possible, so that we can investigate the problem.

  5. Extract the archive with the following command:

    $ tar xzf swift-<VERSION>-<PLATFORM>.tar.gz
    

    This creates a usr/ directory in the location of the archive.

  6. Add the Swift toolchain to your path as follows:

    $ export PATH=/path/to/usr/bin:"${PATH}"
    

    You can now execute the swift command to run the REPL or build Swift projects.

Active Signing Keys

The Swift project uses one set of keys for snapshot builds, and separate keys for every official release. We are using 4096-bit RSA keys.

The following keys are being used to sign toolchain packages:

  • Swift Automatic Signing Key #1 <swift-infrastructure@swift.org>

    Download
    https://swift.org/keys/automatic-signing-key-1.asc
    Fingerprint
    7463 A81A 4B2E EA1B 551F FBCF D441 C977 412B 37AD
    Long ID
    D441C977412B37AD

    To import the key, run:

    $ gpg --keyserver hkp://pool.sks-keyservers.net \
          --recv-keys \
          '7463 A81A 4B2E EA1B 551F  FBCF D441 C977 412B 37AD'
    

    Or:

    $ wget -q -O - https://swift.org/keys/automatic-signing-key-1.asc | gpg --import -
    
  • Swift 2.2 Release Signing Key <swift-infrastructure@swift.org>

    Download
    https://swift.org/keys/release-key-swift-2.2.asc
    Fingerprint
    1BE1 E29A 084C B305 F397 D62A 9F59 7F4D 21A5 6D5F
    Long ID
    9F597F4D21A56D5F

    To import the key, run:

    $ gpg --keyserver hkp://pool.sks-keyservers.net \
          --recv-keys \
          '1BE1 E29A 084C B305 F397  D62A 9F59 7F4D 21A5 6D5F'
    

    Or:

    $ wget -q -O - https://swift.org/keys/release-key-swift-2.2.asc | gpg --import -
    

Swift and the Swift logo are trademarks of Apple Inc.

ubuntu-make-16.02.1/tests/data/server-content/swift.org/builds/0000775000000000000000000000000012656574623021263 5ustar ubuntu-make-16.02.1/tests/data/server-content/swift.org/builds/swift-mock-ubuntu15.10.tar.gz0000664000000000000000000000050112656574623026376 0ustar pϗVj0 sS٠-aöC>4%i7Ja44("# ˬs:ٺ*VUjWD,D}6o,qCoW? S2>طOw #sm ^p`'VHx. r!dTjc"kp,OU"~}b ÔIN0"lg6'b?*g~fff' `ubuntu-make-16.02.1/tests/data/server-content/swift.org/builds/swift-mock-ubuntu15.10.tar.gz.sig0000664000000000000000000000032512656574623027163 0ustar -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iF4EABEIAAYFAlaXqx4ACgkQRW999b1nhTFx0QD/bROb8zkxcG4CxtORFM4pWz0+ 12ZJYsDjKeKQ/NLb5KUA/jAgffKldSN8R3aFahLe34H6UTJ63aM6gjVH4NezEEnz =sVIk -----END PGP SIGNATURE----- ubuntu-make-16.02.1/tests/data/server-content/swift.org/builds/swift-mock-ubuntu14.04.tar.gz0000777000000000000000000000000012656574623033516 2swift-mock-ubuntu15.10.tar.gzustar ubuntu-make-16.02.1/tests/data/server-content/swift.org/builds/swift-mock-ubuntu14.04.tar.gz.sig0000777000000000000000000000000012656574623035060 2swift-mock-ubuntu15.10.tar.gz.sigustar ubuntu-make-16.02.1/tests/data/server-content/android-studio-fake.tgz0000664000000000000000000000061712656574623022442 0ustar PGUN0SԸ @NRh :oqHcZF )HNo'3-}Y1\ZR-pA(J iT "/#־2e؊ƒߞcw,_ >Wk O~+F "* + @k?qj$IlVfH WfS3wIuO ӗĽgIfb\ iX1Z?_ *BZs>8pnE`>G|ZjZaU a Unity on Linux: Release Notes and Known Issues | Unity Community
  1. Missing a module? More about the new installer in 5.3 here
  2. VS Code Unity debugger extension preview
  3. Unity Developer Contest here

Unity on Linux: Release Notes and Known Issues

Discussion in 'Linux Editor Support & Feedback (Experimental)' started by natosha.bard, Aug 26, 2015.

Thread Status:
Not open for further replies.
  1. natosha.bard

    natosha.bard

    Unity Technologies

    Joined:
    Feb 24, 2011
    Messages:
    25
    Hi! This thread will be used to post new builds of Unity for Linux, including release notes and known issues.

    Today, we're releasing the first public build, so this post contains extra information about system requirements and what you can expect. Future releases will also be posted in this thread.

    Installer Types and Supported Systems

    The Unity Editor for Linux is packaged into two types of installers:

    • A .deb package, which can be installed via the Ubuntu Software Center and is expected to work on installations of Ubuntu 12.04 or newer.
    • A platform-agnostic self-extracting shell script, which is designed for other distributions.
    Unity Technologies is providing official support for Ubuntu 12.04 or newer. People are welcome to use other distributions with the understanding that we do not guarantee support.

    Machines also need a modern graphics card with vendor-supported graphics drivers (provided by NVIDIA, AMD, or Intel).

    We do not explicitly support running the Linux editor inside a virtual machine due to limitations related to GPU virtualization (although it does usually work).

    Supported Target Platforms
    The Unity Editor for Linux supports export to the following platforms:
    • Linux / Windows / Mac Standalone
    • Android (additional dependencies needed, see below)
    • WebGL (additional dependencies needed, see below)
    • Tizen (additional dependencies needed, see below)
    • SamsungTV
    • Legacy WebPlayer
    Dependencies and Recommended Packages
    The dependencies for Unity itself are:
    • gconf-service
    • lib32gcc1 (>= 1:4.1.1)
    • lib32stdc++6 (>= 4.6)
    • libasound2 (>= 1.0.23)
    • libc6 (>> 2.15)
    • libc6-i386 (>= 2.15)
    • libcairo2 (>= 1.6.0)
    • libcap2 (>= 2.10)
    • libcups2 (>= 1.4.0)
    • libdbus-1-3 (>= 1.2.14)
    • libexpat1 (>= 1.95.8)
    • libfontconfig1 (>= 2.8.0)
    • libfreetype6 (>= 2.3.9)
    • libgcc1 (>= 1:4.1.1)
    • libgconf-2-4 (>= 2.31.1)
    • libgdk-pixbuf2.0-0 (>= 2.22.0)
    • libgl1-mesa-glx | libgl1
    • libglib2.0-0 (>= 2.31.8)
    • libglu1-mesa | libglu1
    • libgtk2.0-0 (>= 2.24.0)
    • libnspr4 (>= 1.8.0.10)
    • libnss3 (>= 3.14.3)
    • libpango1.0-0 (>= 1.22.0)
    • libstdc++6 (>= 4.6)
    • libx11-6 (>= 2:1.4.99.1)
    • libxcomposite1 (>= 1:0.3-1)
    • libxcursor1 (>> 1.1.2)
    • libxdamage1 (>= 1:1.1)
    • libxext6
    • libxfixes3
    • libxi6 (>= 2:1.2.99.4)
    • libxrandr2 (>= 2:1.2.99.2)
    • libxrender1
    • libxtst6
    • zlib1g (>= 1:1.1.4)
    • debconf (>= 0.5) | debconf-2.0
    The Ubuntu Software Center will install these automatically if using the .deb package. If using the self-extracting shell script (or another distribution), you're on your own.

    To export players to certain targets, there are other dependencies:

    For WebGL:

    • ffmpeg | libav-tools
    • nodejs
    • java6-runtime
    • gzip
    For Android and Tizen:
    • java7-jdk
    These recommended packages are included in the Recommends section of the .deb package.

    We're also not currently bundling the dependencies for MonoDevelop (and doing so is a bit complicated), so the easiest way to ensure you can run the bundled MonoDevelop is to first install the upstream MonoDevelop from the Ubuntu Software Center.

    Reporting Bugs

    The 'Report a Bug' link currently directs users to this area of the forum, which is dedicated to feedback and issues with the Linux Editor. This is the primary location for providing feedback and reporting issues with the Linux Editor.

    Crashes will launch the bug reporter, and you should use this to submit a bug in this case (the bug reporter attaches stacktrace and other information we need to investigate crashes). After submitting your bug with the bug reporter, please post on the forum with the case number you receive in your confirmation mail.


    And finally, here is the information for today's release:

    Build #2015082501

    Official Installer for 64-bit Ubuntu Linux:
    http://download.unity3d.com/download_unity/unity-editor-5.1.0f3+2015082501_amd64.deb

    Unsupported Installer for Other 64-bit Distributions:
    http://download.unity3d.com/download_unity/unity-editor-installer-5.1.0f3+2015082501.sh

    Release Notes
    • Initial release
    Known Issues

    The Linux Editor currently has some known issues:

    • The asset store window cannot be docked into the main editor window
    • Drag and drop between separate editor windows (e.g build settings window and main editor window) does not work
    • Drag and drop from outside the application does not work
    • Moving/Dragging undocked editor windows doesn't feel native yet
    • Context menus at the bottom of the screen have unintuitive initial scroll position
    • "Open in Unity" doesn't work when browsing the Asset Store from an external browser
    • Idle CPU usage is higher than it should be.
    • Certain systems may experience "Service unavailable" errors when trying to log in. WORKAROUND: Launch Unity with LD_PRELOAD=/usr/lib/libresolv.so.2 /path/to/Unity (check the path to your local libresolv) (Kudos to spacepluk and the other hardcore investigators!)
     
    Last edited by a moderator: Aug 27, 2015
  2. natosha.bard

    natosha.bard

    Unity Technologies

    Joined:
    Feb 24, 2011
    Messages:
    25
    Hello lovely people! We have prepared a new build for you. Links and release notes below. Happy testing!

    Build #2015090301

    Official Installer for 64-bit Ubuntu Linux:
    http://download.unity3d.com/download_unity/unity-editor-5.1.0f3+2015090301_amd64.deb

    Unsupported Installer for Other 64-bit Distributions:
    http://download.unity3d.com/download_unity/unity-editor-installer-5.1.0f3+2015090301.sh

    Release Notes
    • Fix login autofail for some users (depend on system libpq5, don't ship conflicting libs)
    • Allow mouse capture in game view
    • Fix context menus in Animator window
    • Allow interaction with game view header UI in play mode
    • Set default new-project location to XDG_DOCUMENTS_DIR
     
  3. natosha.bard

    natosha.bard

    Unity Technologies

    Joined:
    Feb 24, 2011
    Messages:
    25
    Hi again lovely people! We have prepared another build for you. Happy testing!

    Build #2015091501

    Official Installer for 64-bit Ubuntu Linux:
    http://download.unity3d.com/download_unity/unity-editor-5.1.0f3+2015091601_amd64.deb

    Unsupported Installer for Other 64-bit Distributions:
    http://download.unity3d.com/download_unity/unity-editor-installer-5.1.0f3+2015091501.sh

    Release Notes
    • Make reported mouse offsets consistent everywhere
    • Fix direction of mouse scroll delta in play mode
    • Report mouse button events when cursor is locked in play mode
    • Support "Open in Unity" for Asset Store packages (opens new Unity instance for now)
    • Fix Asset Store for comma-decimal locales
    • Make popups less prone to inadvertently close
    • Fix shift+key in game view
    • Don't crash on first run if XDG user directories aren't configured
    • Fix interaction with Sprite Editor slice dropdown
    • Fix intermittent crashes when opening/closing child windows
    • Don't double-report IMGUI key events in play mode
    • Fix initialization of fixed-size child windows (color picker)
     
  4. Tak

    Tak

    Unity Technologies

    Joined:
    Mar 8, 2010
    Messages:
    193
    It's been a while, but hopefully it will have been worth it.

    Build #2015101801

    Official Installer for 64-bit Ubuntu Linux:
    http://files.unity3d.com/levi/unity-editor-5.2.2f1+20151018_amd64.deb

    Unsupported Installer for Other 64-bit Distributions:
    http://files.unity3d.com/levi/unity-editor-installer-5.2.2f1+20151018.sh

    Release Notes
    • Update to Unity 5.2.2f1
    • Avoid crash when creating input context fails at startup
    • Make WebGL build output directory layout match the one generated on other platforms
    • Don't leak file handles when communicating with external processes (e.g. audio importer)
    • Known issue: There's a small regression in cursor offset handling in the game view
     
    Last edited: Nov 20, 2015
  5. Tak

    Tak

    Unity Technologies

    Joined:
    Mar 8, 2010
    Messages:
    193
    Some known issues in this one, but we wanted to give everybody a chance to play with it over the winter holidays. Enjoy, and we'll see you next year!

    Build #2015121801

    Official Installer for 64-bit Ubuntu Linux:
    http://download.unity3d.com/download_unity/linux/unity-editor-5.3.0f4+20151218_amd64.deb
    (sha1sum
    282ca0f7bd25dc2d3f0a1f9d493ecffe9bb9fb36)

    Unsupported installer for Other 64-bit Distributions:
    http://forum.unity3d.com/threads/unity-on-linux-release-notes-and-known-issues.350256/unity-editor-installer-fake.sh
    (sha1sum
    ef83d577413153873495e6e355cd230796533c91)

    Torrent (Includes both installers):
    http://files.unity3d.com/levi/unity-editor-5.3.0f4+20151218.torrent

    Release Notes
    • Update to Unity 5.3.0f4
    • Update to MonoDevelop 5.9
    • All fixes reported for build #2015101801
    • Keyboard input for web views should behave similarly to Unity 5.1 builds
    • Known issue: Cursor offset in game view is still present
    • Known issue: MonoDevelop's application icon is missing
    • Editor still uses legacy OpenGL rendering backend on Linux
     
    Last edited: Dec 18, 2015
    Wulfara, bluenote10, RossB25 and 38 others like this.
Thread Status:
Not open for further replies.
././@LongLink0000644000000000000000000000023400000000000011602 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/forum.unity3d.com/threads/unity-on-linux-release-notes-and-known-issues.350256/unity-editor-installer-fake.shubuntu-make-16.02.1/tests/data/server-content/forum.unity3d.com/threads/unity-on-linux-release-notes0000664000000000000000000002413112656574623030423 0ustar i #!/bin/bash echo This is a script doing things... __ARCHIVE_BEGINS_HERE__ unity-editormock/0000775000175000017500000000000012571036405014557 5ustar didrocksdidrocksunity-editormock/unity-editor-icon.png0000664000175000017500000000000012571036405020635 0ustar didrocksdidrocksunity-editormock/Editor/0000775000175000017500000000000012571036350016004 5ustar didrocksdidrocksunity-editormock/Editor/Unity0000775000175000017500000000002712571036350017041 0ustar didrocksdidrocks#!/bin/bash sleep 300 unity-editormock/Editor/chrome-sandbox0000775000175000017500000000000012571036324020632 0ustar didrocksdidrocks ubuntu-make-16.02.1/tests/data/server-content/twinery.org/0000775000000000000000000000000012656574623020346 5ustar ubuntu-make-16.02.1/tests/data/server-content/twinery.org/index.html0000664000000000000000000002274712656574623022357 0ustar Twine / An open-source tool for telling interactive, nonlinear stories

Twine is an open-source tool for telling interactive, nonlinear stories.

You don't need to write any code to create a simple story with Twine, but you can extend your stories with variables, conditional logic, images, CSS, and JavaScript when you're ready.

Twine publishes directly to HTML, so you can post your work nearly anywhere. Anything you create with it is completely free to use any way you like, including for commercial purposes.

Twine was originally created by Chris Klimas in 2009 and is now maintained by a whole bunch of people at several different repositories.

Editing a story in Twine 1.4.
A bird's-eye view of a story map in Twine 1.4.
The story list in Twine 2.0.
Editing a story in Twine 2.0.

Twine has been used to create hundreds of works. Here's a sample:

Refresh Works

To have your work listed here, add it to the IFDB.

A new tool has emerged that empowers just about anyone to create a game. It's called Twine. It's extremely easy to use, and it has already given rise to a lively and diverse development scene.

Carolyn Petit, Gamespot

Although plenty of independent games venture where mainstream games fear to tread, Twine represents something even more radical: the transformation of video games into something that is not only consumed by the masses but also created by them.

Laura Hudson, The New York Times Magazine

The simple beauty of Twine is this: if you can type words and occasionally put brackets around some of those words, you can make a Twine game.

Kitty Horrorshow

If you're interested in making interactive fiction then there's no better place to start than Twine. It's possibly the simplest game making tool available, it will take you mere minutes to get started, and it has a wonderfully simple visual editor.

Richard Perrin

And aside from being free, it's really not programming at all — if you can write a story, you can make a Twine game.

Anna Anthropy

Twine is the closest we've come to a blank page. It binds itself and it can bind itself along an infinite number of spines extending in any direction.

Porpentine

@twinethreads is the official Twitter account for Twine, with news, interesting links, and new works.

If you have a link you'd like us to share, tweet at us to let us know!

ubuntu-make-16.02.1/tests/data/server-content/twinery.org/twine_fake_linux64.zip0000664000000000000000000002400012656574623024573 0ustar twine-foo/0000775000175000017500000000000012616634105013161 5ustar didrocksdidrockstwine-foo/Twine0000775000175000017500000000002412616634105014171 0ustar didrocksdidrocks#!/bin/sh sleep 60 ubuntu-make-16.02.1/tests/data/server-content/twinery.org/twine_fake_linux32.zip0000777000000000000000000000000012656574623031016 2twine_fake_linux64.zipustar ubuntu-make-16.02.1/tests/data/server-content/twinery.org/img/0000775000000000000000000000000012656574623021122 5ustar ubuntu-make-16.02.1/tests/data/server-content/twinery.org/img/logo.svg0000664000000000000000000000000012656574623022571 0ustar ubuntu-make-16.02.1/tests/data/server-content/simplefile0000664000000000000000000000001412656574623020126 0ustar foo bar baz ubuntu-make-16.02.1/tests/data/server-content/www.arduino.cc/0000775000000000000000000000000012656574623020727 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.arduino.cc/checksums.md5sum.txt0000664000000000000000000000046512656574623024673 0ustar 65a7305053e2f20aeaf772120ba9657c arduino-1.6.5-linux32.tar.xz 65a7305053e2f20aeaf772120ba9657c arduino-1.6.5-linux64.tar.xz 035be823fa0f39a0d9b74863987137b9 arduino-1.6.5-macosx.zip c0bfb988e7998a54d60505d2fe8eb3e5 arduino-1.6.5-r2-windows.exe 134e0672f4920c01777d4d89b1733c59 arduino-1.6.5-r2-windows.zip ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.arduino.cc/download_handler_arduino-1.6.5-linux64.tar.xzubuntu-make-16.02.1/tests/data/server-content/www.arduino.cc/download_handler_arduino-1.6.5-linux64.0000664000000000000000000005267612656574623027751 0ustar Arduino - Donate

Contribute to the Arduino Software

Consider supporting the Arduino Software by contributing to its development. (US tax payers, please note this contribution is not tax deductible). Learn more on how your contribution will be used.

SINCE MARCH 10TH 2015, THE ARDUINO IDE HAS BEEN DOWNLOADED SO MANY TIMES. IMPRESSIVE! THIS IDE IS NO LONGER JUST FOR ARDUINO BOARDS. HUNDREDS OF COMPANIES AROUND THE WORLD ARE USING IT TO PROGRAM THEIR DEVICES, INCLUDING COMPATIBLES, CLONES, AND EVEN COUNTERFEIT. YOU CAN HELP ACCELERATE THE DEVELOPMENT OF THE ARDUINO IDE BY CONTRIBUTING TOWARDS THE EFFORT OF MAKING IT BETTER.

Share

ubuntu-make-16.02.1/tests/data/server-content/www.arduino.cc/en/0000775000000000000000000000000012656574623021331 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.arduino.cc/en/Main/0000775000000000000000000000000012656574623022215 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.arduino.cc/en/Main/Software0000664000000000000000000006654212656574623023747 0ustar Arduino - Software

Download the Arduino Software
ARDUINO 1.6.5
The open-source Arduino Software (IDE) makes it easy to write code and upload it to the board. It runs on Windows, Mac OS X, and Linux. The environment is written in Java and based on Processing and other open-source software.
This software can be used with any Arduino board.
Refer to the Getting Started page for Installation instructions.
ARDUINO SOFTWARE
HOURLY BUILDS

Download a preview of the incoming release with the most updated features and bugfixes. Windows
Mac OS X (Mac OSX Lion or later)
Linux 32 bit , Linux 64 bit

LAST UPDATE
14 April 2015, 08:41:16 CET
ARDUINO 1.0.6 / 1.5.x / 1.6.x
PREVIOUS RELEASES

Download the previous version of the current release, the classic Arduino 1.0.x, or the Arduino 1.5.x Beta version.

All the Arduino 00xx versions are also available for download. The Arduino IDE can be used on Windows, Linux (both 32 and 64 bits), and Mac OS X.

Source Code

Active development of the Arduino software is hosted by GitHub. See the instructions for building the code.
Source code of Arduino is available here.

Other Software
Easy Installation Procedure (recommended): Download the Upgrade Image then please follow the steps in the Yún sysupgrade tutorial.
Advanced Installation Procedure: This procedure is only recommended to advanced users who wish to completely re-flash the Yún including its U-Boot bootloader. These instructions on reflashing the base images are for reference only. Following them will void your Yún's warranty.

Packages list
The list of available packages for the Yún is available here.
See the list of changes.
Terms of Use

By downloading the software from this page, you agree to the specified terms.

THE ARDUINO SOFTWARE IS PROVIDED TO YOU "AS IS" AND WE MAKE NO EXPRESS OR IMPLIED WARRANTIES WHATSOEVER WITH RESPECT TO ITS FUNCTIONALITY, OPERABILITY, OR USE, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR INFRINGEMENT. WE EXPRESSLY DISCLAIM ANY LIABILITY WHATSOEVER FOR ANY DIRECT, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR SPECIAL DAMAGES, INCLUDING, WITHOUT LIMITATION, LOST REVENUES, LOST PROFITS, LOSSES RESULTING FROM BUSINESS INTERRUPTION OR LOSS OF DATA, REGARDLESS OF THE FORM OF ACTION OR LEGAL THEORY UNDER WHICH THE LIABILITY MAY BE ASSERTED, EVEN IF ADVISED OF THE POSSIBILITY OR LIKELIHOOD OF SUCH DAMAGES.

Share

ubuntu-make-16.02.1/tests/data/server-content/www.arduino.cc/download_arduino_asset32.tar.xz0000664000000000000000000002400012656574623026767 0ustar arduino-foo/0000775000175000017500000000000012540507643013476 5ustar didrocksdidrocksarduino-foo/lib/0000775000175000017500000000000012540507543014243 5ustar didrocksdidrocksarduino-foo/lib/arduino_icon.ico0000664000175000017500000000000012540507543017376 0ustar didrocksdidrocksarduino-foo/arduino0000775000175000017500000000007112540507502015055 0ustar didrocksdidrocks#!/bin/sh $(dirname $0)/java-fake processing.app.Base arduino-foo/java-fake0000775000175000017500000000002412540034420015231 0ustar didrocksdidrocks#!/bin/sh sleep 60 ubuntu-make-16.02.1/tests/data/server-content/www.arduino.cc/download_arduino_asset64.tar.xz0000664000000000000000000002400012656574623026774 0ustar arduino-foo/0000775000175000017500000000000012540507643013476 5ustar didrocksdidrocksarduino-foo/lib/0000775000175000017500000000000012540507543014243 5ustar didrocksdidrocksarduino-foo/lib/arduino_icon.ico0000664000175000017500000000000012540507543017376 0ustar didrocksdidrocksarduino-foo/arduino0000775000175000017500000000007112540507502015055 0ustar didrocksdidrocks#!/bin/sh $(dirname $0)/java-fake processing.app.Base arduino-foo/java-fake0000775000175000017500000000002412540034420015231 0ustar didrocksdidrocks#!/bin/sh sleep 60 ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.arduino.cc/download_handler_arduino-1.6.5-linux32.tar.xzubuntu-make-16.02.1/tests/data/server-content/www.arduino.cc/download_handler_arduino-1.6.5-linux32.0000664000000000000000000005267612656574623027744 0ustar Arduino - Donate

Contribute to the Arduino Software

Consider supporting the Arduino Software by contributing to its development. (US tax payers, please note this contribution is not tax deductible). Learn more on how your contribution will be used.

SINCE MARCH 10TH 2015, THE ARDUINO IDE HAS BEEN DOWNLOADED SO MANY TIMES. IMPRESSIVE! THIS IDE IS NO LONGER JUST FOR ARDUINO BOARDS. HUNDREDS OF COMPANIES AROUND THE WORLD ARE USING IT TO PROGRAM THEIR DEVICES, INCLUDING COMPATIBLES, CLONES, AND EVEN COUNTERFEIT. YOU CAN HELP ACCELERATE THE DEVELOPMENT OF THE ARDUINO IDE BY CONTRIBUTING TOWARDS THE EFFORT OF MAKING IT BETTER.

Share

ubuntu-make-16.02.1/tests/data/server-content/localhost/0000775000000000000000000000000012656574623020047 5ustar ubuntu-make-16.02.1/tests/data/server-content/localhost/index.html0000664000000000000000000017406212656574623022056 0ustar Download Android Studio and SDK Tools | Android Developers
 

Android Studio

The official Android IDE

  • Android Studio IDE
  • Android SDK tools
  • Android 5.0 (Lollipop) Platform
  • Android 5.0 emulator system image with Google APIs
Download Android Studio

To get Android Studio or stand-alone SDK tools, visit developer.android.com/sdk/

Intelligent code editor

At the core of Android Studio is an intelligent code editor capable of advanced code completion, refactoring, and code analysis.

The powerful code editor helps you be a more productive Android app developer.

Code templates and GitHub integration

New project wizards make it easier than ever to start a new project.

Start projects using template code for patterns such as navigation drawer and view pagers, and even import Google code samples from GitHub.

Multi-screen app development

Build apps for Android phones, tablets, Android Wear, Android TV, Android Auto and Google Glass.

With the new Android Project View and module support in Android Studio, it's easier to manage app projects and resources.

Virtual devices for all shapes and sizes

Android Studio comes pre-configured with an optimized emulator image.

The updated and streamlined Virtual Device Manager provides pre-defined device profiles for common Android devices.

Android builds evolved, with Gradle

Create multiple APKs for your Android app with different features using the same project.

Manage app dependencies with Maven.

Build APKs from Android Studio or the command line.

More about Android Studio

Download Android Studio
  • Built on IntelliJ IDEA Community Edition, the popular Java IDE by JetBrains.
  • Flexible Gradle-based build system.
  • Build variants and multiple APK generation.
  • Expanded template support for Google Services and various device types.
  • Rich layout editor with support for theme editing.
  • Lint tools to catch performance, usability, version compatibility, and other problems.
  • ProGuard and app-signing capabilities.
  • Built-in support for Google Cloud Platform, making it easy to integrate Google Cloud Messaging and App Engine.

For more details about features available in Android Studio, read the guide to Android Studio Basics.

If you have been using Eclipse with ADT, be aware that Android Studio is now the official IDE for Android, so you should migrate to Android Studio to receive all the latest IDE updates. For help moving projects, see Migrating to Android Studio.

System Requirements

Windows

  • Microsoft® Windows® 8/7/Vista/2003 (32 or 64-bit)
  • 2 GB RAM minimum, 4 GB RAM recommended
  • 400 MB hard disk space + at least 1 G for Android SDK, emulator system images, and caches
  • 1280 x 800 minimum screen resolution
  • Java Development Kit (JDK) 7
  • Optional for accelerated emulator: Intel® processor with support for Intel® VT-x, Intel® EM64T (Intel® 64), and Execute Disable (XD) Bit functionality

Mac OS X

  • Mac® OS X® 10.8.5 or higher, up to 10.9 (Mavericks)
  • 2 GB RAM minimum, 4 GB RAM recommended
  • 400 MB hard disk space
  • At least 1 GB for Android SDK, emulator system images, and caches
  • 1280 x 800 minimum screen resolution
  • Java Runtime Environment (JRE) 6
  • Java Development Kit (JDK) 7
  • Optional for accelerated emulator: Intel® processor with support for Intel® VT-x, Intel® EM64T (Intel® 64), and Execute Disable (XD) Bit functionality

On Mac OS, run Android Studio with Java Runtime Environment (JRE) 6 for optimized font rendering. You can then configure your project to use Java Development Kit (JDK) 6 or JDK 7.

Linux

  • GNOME or KDE desktop
  • GNU C Library (glibc) 2.11 or later
  • 2 GB RAM minimum, 4 GB RAM recommended
  • 400 MB hard disk space
  • At least 1 GB for Android SDK, emulator system images, and caches
  • 1280 x 800 minimum screen resolution
  • Oracle® Java Development Kit (JDK) 7

Tested on Ubuntu® 12.04, Precise Pangolin (64-bit distribution capable of running 32-bit applications.

Other Download Options

SDK Tools Only

If you prefer to use a different IDE or run the tools from the command line or with build scripts, you can instead download the stand-alone Android SDK Tools. These packages provide the basic SDK tools for app development, without an IDE. Also see the SDK tools release notes.

Platform Package Size SHA-1 Checksum
Windows installer_r24.0.1-windows.exe (Recommended) 92180986 bytes 505d7a95647bccc194b7aa707854422d9c7288d5
android-sdk_r24.0.1-windows.zip 140743633 bytes cc49974e8bfcc865ffe0d887e9a74cf52085c632
Mac OS X android-sdk_r24.0.1-macosx.zip 88535741 bytes 7097c09c72645d7ad33c81a37b1a1363a9df2a54
Linux android-sdk_r24.0.1-linux.tgz 141304203 bytes bc1ccd6b05beb06f59a2011c5a7f2bbab8e87f02

All Android Studio Packages

Select a specific Android Studio package for your platform. Also see the Android Studio release notes.

Platform Package Size SHA-1 Checksum
Windows android-studio-bundle-135.1641136.exe
(Recommended)
868344232 bytes 1931dbaeadb52f5e0a8ba6e2ae60d9df20b2076b
android-studio-ide-135.1641136.exe
(No SDK tools included)
260272840 bytes 464d1c5497ab3d1bdef441365791ab36c89cd5ae
android-studio-ide-135.1641136-windows.zip 246249059 bytes 6d6856aca83f6ff747ca40b10f70edfbbcccd91c
Mac OS X android-studio-ide-1641136.dmg 245729073 bytes 49506ba2cf6b56be4f7d07e6a00c4ec3ba2249d5
Linux android-studio-ide-135.1641136-linux.zip 243917559 bytes 4a582c6e35700f00332783b0b83783f73499aa60
Linux android-studio-ide-135.1641136-linux.zip 243917559 bytes 4f64664ebe496cc6d54f417f25a1707f156d74d2
ubuntu-make-16.02.1/tests/data/server-content/localhost/base-framework-fake64.tgz0000664000000000000000000000063312656574623024562 0ustar yLVr0=C=X7!yOHOuk>+^â%F` * v+i{EkZ b هtr0:{OM?u+MG @~ Jq$aa@ltռ(WӪ(v[GͿ5~H&{ޯ_;:ǝIqL{qw>{Qs7 Cq}+wZ7kan_0 sK_ ubuntu-make-16.02.1/tests/data/server-content/localhost/base-framework-fake32.tgz0000664000000000000000000000063412656574623024556 0ustar 'zLVr0=C=X7! Dart SDK - Dart API docs

 
Dart SDK

Welcome to the Dart API reference documentation, covering the official Dart API libraries. Some of the most fundamental Dart libraries include:

  • dart:core: Core functionality such as strings, numbers, collections, errors, dates, and URIs.
  • dart:html: DOM manipulation for web apps.
  • dart:io: I/O for command-line apps.

Except for dart:core, you must import a library before you can use it. Here's an example of importing dart:html and dart:math:

import 'dart:html';
import 'dart:math';

You can install more libraries using the pub package manager. For information on finding, using, and publishing libraries with pub, see pub.dartlang.org.

The main site for learning and using Dart is www.dartlang.org. Check out these additional pages:

This API reference is automatically generated from the source code in the Dart project. If you'd like to contribute to this documentation, see Contributing.

Libraries

dart:async

Support for asynchronous programming, with classes such as Future and Stream.

dart:collection

Classes and utilities that supplement the collection support in dart:core.

dart:convert

Encoders and decoders for converting between different data representations, including JSON and UTF-8.

dart:core

Built-in types, collections, and other core functionality for every Dart program.

dart:developer

Interact with developer tools such as the debugger and inspector.

dart:html

HTML elements and other resources for web-based applications that need to interact with the browser and the DOM (Document Object Model).

dart:indexed_db

A client-side key-value store with support for indexes.

dart:io

File, socket, HTTP, and other I/O support for server applications.

dart:isolate

Concurrent programming using isolates: independent workers that are similar to threads but don't share memory, communicating only via messages.

dart:js

Support for interoperating with JavaScript.

dart:math

Mathematical constants and functions, plus a random number generator.

dart:mirrors

Basic reflection in Dart, with support for introspection and dynamic invocation.

dart:profiler

Please see 'dart:developer'.

dart:svg

Scalable Vector Graphics: Two-dimensional vector graphics with support for events and animation.

dart:typed_data

Lists that efficiently handle fixed sized data (for example, unsigned 8 byte integers) and SIMD numeric types.

dart:web_audio

High-fidelity audio programming in the browser.

dart:web_gl

3D programming in the browser.

dart:web_sql

An API for storing data in the browser that can be queried with SQL.

ubuntu-make-16.02.1/tests/data/server-content/code.visualstudio.com/0000775000000000000000000000000012656574623022300 5ustar ubuntu-make-16.02.1/tests/data/server-content/code.visualstudio.com/License0000664000000000000000000003456512656574623023622 0ustar Index

MICROSOFT PRE-RELEASE SOFTWARE LICENSE TERMS

MICROSOFT VISUAL STUDIO CODE PREVIEW

These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. They apply to the software named above. The terms also apply to any Microsoft services or updates for the software, except to the extent those have additional terms.

IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW.

  1. INSTALLATION AND USE RIGHTS.
    1. General. You may use the software to develop and test your applications.
    2. Demo use. The uses permitted above include use of the software in demonstrating your applications.
    3. Backup copy. You may make one backup copy of the software, for reinstalling the software.
    4. Third Party Programs.
      1. The software may include third party components with separate legal notices or governed by other agreements, as described in the ThirdPartyNotices file accompanying the software. Even if such components are governed by other agreements, the disclaimers and the limitations on and exclusions of damages below also apply.
      2. The software contains third party components licensed under open source licenses with source code availability obligations. Copies of those licenses are included in the ThirdPartyNotices file or accompanying credits file. You may obtain the complete corresponding source code from us if and as required under the relevant open source licenses by sending a money order or check for $5.00 to: Source Code Compliance Team, Microsoft Corporation, 1 Microsoft Way, Redmond, WA 98052 USA. Please write third party source code for Visual Studio Code in the memo line of your payment. We may also make the source available at http://thirdpartysource.microsoft.com/.
  2. TERM. The term of this agreement is until 30/04/2016 (day/month/year) or next public release of the software, whichever is first.
  3. PRE-RELEASE SOFTWARE. This software is a pre-release version. It may not operate correctly or work the way a final version of the software will. Microsoft may change it for the final, commercial version. Microsoft also may not release a commercial version. Microsoft is not obligated to provide maintenance, technical support or updates to you for the software.
  4. DATA. The software may collect information about you and your use of the software, and send that to Microsoft. Microsoft may use this information to provide services and improve our products and services. For this pre-release version, users cannot opt out of data collection. Some features in the software may enable collection of data from users of applications you develop using the software. If you use these features to enable data collection in your applications, you must comply with applicable law, including providing appropriate notices to users of your applications. You can learn more about data collection and use in the help documentation and the privacy statement at http://go.microsoft.com/fwlink/?LinkID=528096&clcid=0x409. Your use of the software operates as your consent to these practices.
  5. FEEDBACK. If you give feedback about the software to Microsoft, you give to Microsoft, without charge, the right to use, share and commercialize your feedback in any way and for any purpose. You also give to third parties, without charge, any patent rights needed for their products, technologies and services to use or interface with any specific parts of a Microsoft software or service that includes the feedback. You will not give feedback that is subject to a license that requires Microsoft to license its software or documentation to third parties because we include your feedback in them. These rights survive this agreement.
  6. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not
    • work around any technical limitations in the software;
    • reverse engineer, decompile or disassemble the software, or otherwise attempt to derive the source code for the software except, and solely to the extent: (i) permitted by applicable law, despite this limitation; or (ii) required to debug changes to any libraries licensed under the GNU Lesser General Public License which are included with and linked to by the software;
    • remove, minimize, block or modify any notices of Microsoft or its suppliers in the software;
    • use the software in any way that is against the law; or
    • share, publish, or lend the software, or provide it as a hosted solution for others to use, or transfer the software or this agreement to any third party.
  7. SUPPORT SERVICES. Because this software is as is, we may not provide support services for it.
  8. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.
  9. EXPORT RESTRICTIONS. Microsoft software, online services, professional services and related technology are subject to U.S. export jurisdiction. You must comply with all applicable international and national laws including the U.S. Export Administration Regulations, the International Traffic in Arms Regulations, Office of Foreign Assets Control sanction programs, and end-user, end use and destination restrictions by the U.S. and other governments related to Microsoft products, services and technologies. For additional information, see http://www.microsoft.com/exporting.
  10. APPLICABLE LAW. If you acquired the software in the United States, Washington law applies to interpretation of and claims for breach of this agreement, and the laws of the state where you live apply to all other claims. If you acquired the software in any other country, its laws apply.
  11. LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the laws of your state or country. This agreement does not change your rights under the laws of your state or country if the laws of your state or country do not permit it to do so. Without limitation of the foregoing, for Australia, YOU HAVE STATUTORY GUARANTEES UNDER THE AUSTRALIAN CONSUMER LAW AND NOTHING IN THESE TERMS IS INTENDED TO AFFECT THOSE RIGHTS.
  12. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED AS-IS. YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  13. LIMITATION ON AND EXCLUSION OF DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.

    This limitation applies to (a) anything related to the software, services, content (including code) on third party Internet sites, or third party applications; and (b) claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your state or country may not allow the exclusion or limitation of incidental, consequential or other damages.

* * *

ubuntu-make-16.02.1/tests/data/server-content/simplefile-with-no-content-length0000664000000000000000000000001412656574623024440 0ustar foo bar baz ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/0000775000000000000000000000000012656574623023347 5ustar ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/datagrip/0000775000000000000000000000000012656574623025142 5ustar ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/datagrip/datagrip-fake.tar.gz.sha256ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/datagrip/datagrip-fake.tar0000664000000000000000000000012712656574623030351 0ustar 9f299e74f163fe303b1882a225c30b6a63325ac3b8f6bce891d6c6bee70212b2 datagrip-fake.tar.gz ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/datagrip/datagrip-fake.tar.gzubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/datagrip/datagrip-fake.tar0000664000000000000000000002565712656574623030370 0ustar V{TSݶ! t"(U:(E{OФ&MAiҤHU@:R)"ޥ79;=w1=odso~k=Ɗ%R'//,w@PPP\\ ~ mWbBbBD剱 jWqmο??O<_\O%;;Yz[Y:| !1KD?+g;DD.h8BN?ԟ7# {#. Wo~]_;G{l1h7K= DE3 a!1!a?@)o%ۇz!gwcT 0QvK[@ee jio{ϽVwQuECFmil[;ɲmke;ȲVupTa{CgkI6y9K,J]-}YepW򰅋#pqI~!1qqQpJAA>a)QA˪.yISV,Gy IJJ   ]sXyee[OK5aQn-P^Y6\+ݿNǍehK e'枭?뇶gÎo\c^F#ruReqRV嗤_lo]/n+m n'8yw5;F6JLUVr<mO8I/W_ݗB]o\Z:j}/αJliGhM(ʸPD:Sy17)\i^{-C8PKB&a)W\OT}̛-nD7.w?L7T]rAJW{tv{;Uݾԫ2X:l ~w_qyoPj&VE]|=LVB6&ugۓ?=%tC0 LsgX`qMVXpiod >fr]IϔoLZ Bحxy8FL8@[[l_H0x'`3EDS+q%j˸pH1WhO܍6f6ތ"S  } A1IQ (B99]J }=,ku[<Dt Xܨ?ʐ"#/)Y=S_Y rv2 /s*_[;˟.Ōo.(+Yu7̳vX$9PCO,K4R j͇:&o |inHaje b_2%6K-5!myi!va]0{l/v-??ϥH2uJ^eyʄ.o-ޜ7Y*I \^'CYhHaLԒ:Ǵ:/,7tOשt֐q5΃FٓʉUOV>9I`#6:a Lػڪ`J:TN,\O_qmW9x< &)29zu(x/@"Koj@ԩy2^ Ǻ)*,,u5<-4#:ߴe~|c\pdQ*j,+Z7ȍKDDPB=+cv^FNA/ڭ;IjxН~9h~0la)xqWBߘvur6h2+4,>9;Mѩ/bT^e茜 7evK8~lJ3sA|;g wRBOd<% 2W=4UY4wz({4^Ԅ:4( ?U0Z4Z{KD`sipETI4%݋9,JM@3z%(B"$I;% ɧR#zCt$&H צ##qT*\ ,4g{х(06g,ްɖ- PuDqEɖ$=἞j ApI_kI"hԋ9Yiث;zKoH8]NT$Dwrݼ>q3W/ ǍȘ11DGK/PH)ȅ)dO"Durf_~E^];zmїW𧓄Ǣ*$xҽ|bL'DC]{wpо5ӂ4b7K7%*o=ژi{)[ɜHW%%p-AP|b3gVvI؆ ӳX芫pb>jR 緎_ ' _'U0y^y\:Q't$57S+d wf Ѿw/q'g8&>;:aqx%lٿp:} JӁ.O♿! dM0fO9{| 減LFC:,axίmPB;co8kOQ]0Tv01'p#<9%-N;vomZ7w}f#6R+Τfn5ӰV^/9M=iœwdyrϞ?oo)Ш,Ezg?c_UVRn5_ߒc'v]ש6%W#/ތ3"EcI-AN:iYY/'IպM—}͒B mbGfz3x bVǯVY̴m1f (C IU~S`Q'`l9fj:G}|铵^):ٴY;1k9~f*+s~;@Sy|\ytC j.eĖ)kҝ; ZԻnM?T j]}`hƜ.|!tûiXvi0ۮ4^ ̒0BVDФAH:qz'UStN' $< ,_l Hv<$^}3UVm1C>~}[GYTltOn$a-4N?W z11:|.̰P?iXde kB2xU>@u 5zbx첞à ws01>l^D$(2 ĵSّ4k8)ÿa9'|.nDɸqsy:wo&wB٬#2# ݍYO8Ϩ҈GO3^`Q~ =Y|}OƊڞrbF'{3&y˫7+l>'Ƞ}S/Hf5Vs!$9!qJ%ɍ֬ï쥷}9 .Mnn1u#/0bPbgc|UoݩS!' Iü8ٜZO0ըeKӷruWɃ$,2XhbDc"@q\ @,=O'QysuQ1VY5><0=DbC$]wl~o1P>*oNy}q#'0P+Aбf\vrtQ5~ѳzkv8--Žر\J,pGqk~j+maB5RJ 7`5>':XҒ^rF+Ol1p߇OՌ ,^a;Q:tOD&5>AT|myKd(QXTBL>«\l obQx}ܖ,M*>LzX9vy^V+4Uuͅbա&=xHxKWد[27Vj$=d{ 2 .tPBǬM6^D܃٥W(y13P:A<]\Tu2\JgVc!þ2?}- ³\Kb&bA{l",{1,=摧&G kCqAGs#v?|FLL~qyWGx-zNAXRMPoTځPc pr.1ޣ3?ʣ8~|A:!(Ldgh~;Ak6\2F+bRϸB;]tmSɠu3Z+E dڰ20wKr^ݬ>\?;8t-_J4j(>br~/齈oi8Y+-79ڙ{}zYC r+XX 3k3_Oil@nO,+o7Ң)eGipAGp2ޭgH Zico#` KBݫN@}ϳH ݴGV xL*I?9)T&qAsWdۯy eyD((,x_:OT~- E= |K0"O_J \ ƭ7&^vկXZuߋhS!+^C׶[J}Ʋ5wm>d|i @muYD*\:z4"曚 SKHZHf5Giڎ#jIanyk_*qMR36Z/5YkYC?)# i[QZ;+ڀKhr-H(Yٙk՝"^b ~8/@@!UU Ǯ!m բH2R%yUiKR&|;I-7LAJ["'` N26ۆCY|j'ldT,|(EoFs&W Q$4 jJA皀#!z(L\mw-m ~%NԙC:乞`YZOsx$#^5igj&2*FiP{ OWkO*8)`XT rLN!8/:2 c৻ K CbF&5>&oɐ~b-WȲIfGWyY9\m$:Rs%K*GɁor.ߚ=Ro&Z[v |û)msڼnFRPrEE>p?_w[7ᕸ_+@B@{U'GGS?д g7Uza@+@լ$|CC+ |,S;x]v䡺@اཟoZ7B]m\yXc߉aVu69U]W:Am.[^ܵ4.{ݓ}>|dü6,'7mn݉*QSl8dE.)A$,D nQ)i;niB 6ї Џۗg9DOQL7z4+OZ@_ܹ.@R?&FY%m_ jhV<̃Vu ܽ/c G9[0r XմYe!}<z;nA ?@PBI,CTFCFrU %*ٸi|1|2]9-ԢkgVwh;p$9ڣ m4Fe"W3&f*?$>L8it_бЋ;t ]n!9pM_̧p-X%ثp Ȕ^1A0z?AϦLq2޳#\ijb@qaln("7TR`^'O?llo)]vŏwKӈ@͂X$AVW-/;8S 6N,$.HI')\*"&R PQ[מp$3^Qr|$ L62@T: oW@pbGI% j(C:Fizf8m +,(?͂Wl`1Rz0(@SipG7xu:_Z!{kbD}'V=hj^ Ȑ zm3;W#vիj1zuRDTa:=}Ǣ煥M '#qY۞xIF!Æޥhs^7b5jJ9 s wh;{(97w:s'CchCs.j,ZY-$J= x_L.oxicf[_^ؔu/bV\sc`'0yer\+h0Ԉj"Ą:PhQ 6(<[\AbU+ $nZ!l{S<-aR rB"Xcyx}rDD+L3_Biv;Hhm+^q 8Hd~g dp\]-Mz>f#梄.kH X)Hkq-FZτ*<c5+u ڝtt{L;uMQV+EZ #;c2c% *S[^e!!3@MܥyS cSj&? {fX'&!*Fp[ o~H~!YpW:Yw0AFF@F/@7/큒} (q9JǮp~ #;?oh|Nhꠝo)=#ȟ<)h|S&ijuŭ9“~[Ҹox/l6 ߤ W{ڎ&EtCt2wOJxT8=3`TZ{kA܉|,|dy۸Z̻4sO`5i kAE[_ #,B%C\LO޼>OfRC(?p`i# qBAE09^gq=;@C Z| 8IU'I]o,vda;%Bg'FsD݋:<KRAn҇40v\5tշ5i|f5rx/vm10Cf̂DQxH5SZ VgZnRyVL&QA }^4PvZ 3Xlwr3l|ܗS@z:$cA2,1{҈ͱO Ai̻xF 󏜷\jc /@/<0r'r]YjGr-X4ob´ESzN ٣IGR^ߘãe&tȓi3Q҉gu``B#{YKgz,].p}F[3+HKv嗆Q# 4CQñ2-Pʧ.CCq3KO;#F(vhK`Wynʡ̜^Ϯ$F,&#WVָwvŋ ݏp^B ^Z{/dZ)qoZ 0˓ 5;!|YI`қ~5T_)QxS r;~K Aͼy}׆WsS1SoHLRJDV=Sxq82@2 TV=խc_]K6^Ze`$1ZL~ .']Qb:&هJG{J;<\+O կ|,|n+4Ӧɍކd1`HgppɜI\6Ⱥ*Єu&˩ی'K4Lb(wF?t^\`Ks '0'T=F&n!7\H%ɻ]YTo-$M*#yR/|јAI !2=P Mhh#ȓ&yf!]?i@$$2޾HFD)Iݷ;jV4,ܤ)%m9˸THd݌T5dNd~J T[ i7ޱ?Hw=>̓i՜%_m>tU&5gͯMx+#;5:pk`uFPⳲ]\dقj^nw -QÒ>{\~xjW|G00w[V% fУ*_P#EBN;4y}ww>+m:'=ٴ`|Ҝu{rj.\ Ck5-mXfŞt.LS| &4WT>WPēTԪ$> A'MA߶RT~h?_ņg/!$7ПPVO?'Ŀ 2Bubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/products/0000775000000000000000000000000012656574623025212 5ustar ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/products/releases?code=CL0000664000000000000000000000122212656574623030203 0ustar {"CL":[{"date":"2015-12-10","type":"release","downloads":{"windows":{"link":"https://download.jetbrains.com/cpp/clion-1.2.2.exe","size":175081456,"checksumLink":"https://download.jetbrains.com/cpp/clion-1.2.2.exe.sha256"},"mac":{"link":"https://download.jetbrains.com/cpp/CLion-1.2.2-custom-jdk-bundled.dmg","size":227019443,"checksumLink":"https://download.jetbrains.com/cpp/CLion-1.2.2-custom-jdk-bundled.dmg.sha256"},"linux":{"link":"https://data.services.jetbrains.com/cpp/clion-fake.tar.gz","size":220687306,"checksumLink":"https://data.services.jetbrains.com/cpp/clion-fake.tar.gz.sha256"}},"version":"1.2.2","majorVersion":"1.2","build":"143.1184"}]} ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/products/releases?code=PS0000664000000000000000000000130012656574623030224 0ustar {"PS":[{"date":"2015-12-10","type":"release","downloads":{"windows":{"link":"https://download.jetbrains.com/webide/PhpStorm-10.0.2.exe","size":166004232,"checksumLink":"https://download.jetbrains.com/webide/PhpStorm-10.0.2.exe.sha256"},"mac":{"link":"https://download.jetbrains.com/webide/PhpStorm-10.0.2-custom-jdk-bundled.dmg","size":195039438,"checksumLink":"https://download.jetbrains.com/webide/PhpStorm-10.0.2-custom-jdk-bundled.dmg.sha256"},"linux":{"link":"https://data.services.jetbrains.com/phpstorm/PhpStorm-fake.tar.gz","size":212579385,"checksumLink":"https://data.services.jetbrains.com/phpstorm/PhpStorm-fake.tar.gz.sha256"}},"version":"10.0.2","majorVersion":"10.0","build":"143.1184"}]} ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/products/releases?code=WS0000664000000000000000000000131012656574623030234 0ustar {"WS":[{"date":"2015-12-07","type":"release","downloads":{"windows":{"link":"https://download.jetbrains.com/webstorm/WebStorm-11.0.2.exe","size":157871800,"checksumLink":"https://download.jetbrains.com/webstorm/WebStorm-11.0.2.exe.sha256"},"mac":{"link":"https://download.jetbrains.com/webstorm/WebStorm-11.0.2-custom-jdk-bundled.dmg","size":183965019,"checksumLink":"https://download.jetbrains.com/webstorm/WebStorm-11.0.2-custom-jdk-bundled.dmg.sha256"},"linux":{"link":"https://data.services.jetbrains.com/webstorm/WebStorm-fake.tar.gz","size":132160662,"checksumLink":"https://data.services.jetbrains.com/webstorm/WebStorm-fake.tar.gz.sha256"}},"version":"11.0.2","majorVersion":"11.0","build":"143.1184"}]} ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/products/releases?code=IIU0000664000000000000000000000126312656574623030340 0ustar {"IIU":[{"date":"2015-12-08","type":"release","downloads":{"windows":{"link":"https://download.jetbrains.com/idea/ideaIU-15.0.2.exe","size":386606040,"checksumLink":"https://download.jetbrains.com/idea/ideaIU-15.0.2.exe.sha256"},"mac":{"link":"https://download.jetbrains.com/idea/ideaIU-15.0.2-custom-jdk-bundled.dmg","size":438180436,"checksumLink":"https://download.jetbrains.com/idea/ideaIU-15.0.2-custom-jdk-bundled.dmg.sha256"},"linux":{"link":"https://data.services.jetbrains.com/idea/idea-ultimate-fake.tar.gz","size":390459277,"checksumLink":"https://data.services.jetbrains.com/idea/idea-ultimate-fake.tar.gz.sha256"}},"version":"15.0.2","majorVersion":"15.0","build":"143.1184"}]} ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/products/releases?code=RM0000664000000000000000000000137712656574623030236 0ustar {"RM":[{"date":"2015-12-10","type":"release","downloads":{"windows":{"link":"https://download.jetbrains.com/ruby/RubyMine-8.0.2.exe","size":198777656,"checksumLink":"https://download.jetbrains.com/ruby/RubyMine-8.0.2.exe.sha256"},"mac":{"link":"https://download.jetbrains.com/ruby/RubyMine-8.0.2-custom-jdk-bundled.dmg","size":225350927,"checksumLink":"https://download.jetbrains.com/ruby/RubyMine-8.0.2-custom-jdk-bundled.dmg.sha256"},"linux":{"link":"https://data.services.jetbrains.com/ruby/rubymine-fake.tar.gz","size":175331255,"checksumLink":"https://data.services.jetbrains.com/ruby/rubymine-fake.tar.gz.sha256"}},"notesLink":"https://confluence.jetbrains.com/display/RUBYDEV/RubyMine+8.0+Kusunoki","version":"8.0.2","majorVersion":"8.0","build":"143.1184"}]} ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/products/releases?code=PCE0000664000000000000000000000126312656574623030321 0ustar {"PCE":[{"date":"2015-12-10","type":"release","downloads":{"windows":{"link":"https://download.jetbrains.com/python/pycharm-edu-2.0.3.exe","size":150777464,"checksumLink":"https://download.jetbrains.com/python/pycharm-edu-2.0.3.exe.sha256"},"mac":{"link":"https://download.jetbrains.com/python/pycharm-edu-2.0.3.dmg","size":181589445,"checksumLink":"https://download.jetbrains.com/python/pycharm-edu-2.0.3.dmg.sha256"},"linux":{"link":"https://data.services.jetbrains.com/python/pycharm-educational-fake.tar.gz","size":117436402,"checksumLink":"https://data.services.jetbrains.com/python/pycharm-educational-fake.tar.gz.sha256"}},"version":"2.0.3","majorVersion":"2.0","build":"143.1371"}]} ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/products/releases?code=PCC0000664000000000000000000000131312656574623030313 0ustar {"PCC":[{"date":"2015-12-10","type":"release","downloads":{"windows":{"link":"https://download.jetbrains.com/python/pycharm-community-5.0.2.exe","size":169759968,"checksumLink":"https://download.jetbrains.com/python/pycharm-community-5.0.2.exe.sha256"},"mac":{"link":"https://download.jetbrains.com/python/pycharm-community-5.0.2-jdk-bundled.dmg","size":170811847,"checksumLink":"https://download.jetbrains.com/python/pycharm-community-5.0.2-jdk-bundled.dmg.sha256"},"linux":{"link":"https://data.services.jetbrains.com/python/pycharm-fake.tar.gz","size":136420461,"checksumLink":"https://data.services.jetbrains.com/python/pycharm-fake.tar.gz.sha256"}},"version":"5.0.2","majorVersion":"5.0","build":"143.1184"}]} ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/products/releases?code=DG0000664000000000000000000000125612656574623030206 0ustar {"DG":[{"date":"2016-01-27","type":"release","downloads":{"windows":{"link":"https://download.jetbrains.com/datagrip/datagrip-1.0.2.exe","size":127639968,"checksumLink":"https://download.jetbrains.com/datagrip/datagrip-1.0.2.exe.sha256"},"mac":{"link":"https://download.jetbrains.com/datagrip/datagrip-1.0.2-custom-jdk-bundled.dmg","size":142337722,"checksumLink":"https://download.jetbrains.com/datagrip/datagrip-1.0.2-custom-jdk-bundled.dmg.sha256"},"linux":{"link":"https://data.services.jetbrains.com/datagrip/datagrip-fake.tar.gz","size":136235809,"checksumLink":"https://data.services.jetbrains.com/datagrip/datagrip-fake.tar.gz.sha256"}},"version":"1.0.2","majorVersion":"1.0"}]}ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/products/releases?code=PCP0000664000000000000000000000136112656574623030333 0ustar {"PCP":[{"date":"2015-12-10","type":"release","downloads":{"windows":{"link":"https://download.jetbrains.com/python/pycharm-professional-5.0.2.exe","size":208571048,"checksumLink":"https://download.jetbrains.com/python/pycharm-professional-5.0.2.exe.sha256"},"mac":{"link":"https://download.jetbrains.com/python/pycharm-professional-5.0.2-jdk-bundled.dmg","size":241356892,"checksumLink":"https://download.jetbrains.com/python/pycharm-professional-5.0.2-jdk-bundled.dmg.sha256"},"linux":{"link":"https://data.services.jetbrains.com/python/pycharm-professional-fake.tar.gz","size":187822566,"checksumLink":"https://data.services.jetbrains.com/python/pycharm-professional-fake.tar.gz.sha256"}},"version":"5.0.2","majorVersion":"5.0","build":"143.1184"}]} ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/products/releases?code=IIC0000664000000000000000000000124112656574623030312 0ustar {"IIC":[{"date":"2015-12-08","type":"release","downloads":{"windows":{"link":"https://download.jetbrains.com/idea/ideaIC-15.0.2.exe","size":247237112,"checksumLink":"https://download.jetbrains.com/idea/ideaIC-15.0.2.exe.sha256"},"mac":{"link":"https://download.jetbrains.com/idea/ideaIC-15.0.2-custom-jdk-bundled.dmg","size":283902393,"checksumLink":"https://download.jetbrains.com/idea/ideaIC-15.0.2-custom-jdk-bundled.dmg.sha256"},"linux":{"link":"https://data.services.jetbrains.com/idea/idea-fake.tar.gz","size":230939309,"checksumLink":"https://data.services.jetbrains.com/idea/idea-fake.tar.gz.sha256"}},"version":"15.0.2","majorVersion":"15.0","build":"143.1184"}]} ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/idea/0000775000000000000000000000000012656574623024251 5ustar ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/idea/idea-ultimate-fake.tar.gzubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/idea/idea-ultimate-fake.ta0000664000000000000000000031374712656574623030246 0ustar Tv֖.XS{DCѺډ4-Q6Twu JI%sWՓ~~u>ӏ2?.|œjW4Eq8&JV8d,;qWk/C(&4{ `@Cg+:Y}Ye-pS?5t69'xbys1>8$Y,B`4dIKpX-bh2YD e_:p)eA3j>ЉBxMO\c&'NycWcn<{׍ N7|uk(PX~"ˇd7O~!8e?q΃b .gy2^a:Yͧo`0P ndП5W6#.Ygaݼ<8{Ygd& >lz?^@l??T=*g\g~ļD !;H0}<`*"+c']02ZtK'2 mMZy~Qfx!2 ɀ- 1rXMP@[1r" ",,MmevdVr?[t4 tXn0a,٣a4t^΂y>&'p yDI>d Ȑwa4MY&^-A<_ၙȎe3MP2ʖsh.xǣl7e{0Q:<]=| /ܝixŒbÇڍ[|z8}txH )EM@6آI^)/գOvgb+d6u\a=k1Ȉ'hσ??6_ܰ'˗=ʚ2[ ͓@Hel H˜?'ufhF it›*ShL&U?_}/- :IPM^  i$LRh%W!g#7\z!PZG"E~iԛ^MZ&19#hbm ~$:T,p+ gR~dWV %~p^k ]@RXV{bPG /Zk]21B JUN(ȑ?fͻm3=? \k0c R?cd?M"8hgܧ0P2݂g~~zqޞ<::h~/wG\-j0zX{@ qZHǙ|X8b&kV<M/J5f<<&]8&WdGGG~,>6C/^¬kMᅒV9}B X +9:<:,>cTv^~Glto=nw}ϧ nQߢߚ|}_$tg闗[y|/hy $zBA*HU'r5+Da:9OSR@~?)u#IJsa()' }`VKށb{j&S:!it0Y%}8f3JƔwpb.(__ ||;7LSx/ ^qEo` Q}=+wԌc7uj:Ԧ& truRL5ۦ$=_MhJ4%;$V5{/0D4Sd2: ]N~ye76 EOG"eBUrI y?0,.dM;eU,=u9G98[!K70  GI*mNMe[I2JᄥkF7zɓlcz )#x78,hPCt"ߴֹaMǭ~i2~|c͐@xaYBÌm^&đ,s53=ԄI]S*dngV?k Aw AGQȃ,(ODx|Mm&΄P k5(9Q.S9Q;GMŞjyMmF-2*0BB6f8♀Rac*xW# g38 $>eAq^@\嬌EWA:f<ÄI@3cҳZrAˆ&+TRC70g+,%C,Ʌ,w96͈CҺ0A\a83UR!ӧ 3ˊnIr2rvi]H d~ :l*n_K̃hQ xԴjM,7p~51"08rѳE]whX}b(|ϰL-\ÅeYjg2JJGNU욌yXpW` ` *0L{\VeZshUA)hNmZV< @<$ |Z& ji$Šs RW2}o|1@>/6NAoVsOAiPJudۙ?[:6~q lrsrmX.a댺a _jx>bҲ\uDuz-e t"*|5-+-ͬ2C0K_*\S3tIUvi ('Ow m xO,;AGnwigxmu);lep+COi,4*j)n hL!>I8D+z>ZܵRoaEH#% GXZɢثNi|ׁכkZ;WSm읶b-Z;;kx-yfjK~DSҮÚҿO;0?KC F=䢞! l. {OϨ_h_|ڠ7_a)f'؝aowz?^7 =u޶NKD/%`c+S|O6hܓZ>l~n gTEuZQzJ4woZaeʤEFC m>:=9E8Rٹ$Ѩ93_N5/aGFtsyFmcCK*(p1 12n#-W_Qp=!vNh9D , yeтژHr$7CWaqi H8/P ┌ eXLBnI?UeTD2K>>mv $L}Jo$~(:!xԉɍZ2,S̑j2 WI`1Gb*b5duH$s"r/D_0- Ëبptm `CXG4JȂq2ҕOr/89t +PӐ*8ڋ+DHKb%Zڼb$7R%u1bh8[}C 喁[/Cg~ @aݜEh L +DxzOu8]E*SDwTŒanz7g%,&hC@=krmr&j]J}2#7ޤ y&b0Y( 'j0%OvHwF chy H/ FEU7l*$,J~b$fJtE/ pp^}-Y֕}!; .LQAdQo+}5Wp쿬iM$4tНQ(r`$P eFn8b BJeaC%8[)|æ6Q"?9TV!^S,LY#Vs*?h , y23t=FÜxd5,wxzr.K6'3/^̱Tnn"q4Ne 0EPY+MECp_po 4;LApeJF4PQub)`AZ)G=L|w||=hvpy]sZt҈g$Y|I{G{Gq*5!T8 &  S bh2ʛ ?5\*$ "mqܡ@+20h6GR/v{)RKkY:[0s1WAPsx̏DDL _} Dci I3ˑVLÛCS\[tyBq;a1(QԈE]:ā;|8}s#ED\.XA]٠lF$W;-8#86Qd GgKYE|ľ (]˫|A\%SH] c7-E Z6vLDٽbBH; C0NGxuG2&ǸLDL;y6\X*9^DCp;}/׭P(ms_ަ O*h<@vpovށa(d:OnB @Ol.<`% N F'菈\vn*"W؆sA8 b-u5B]MPWS)WS)T­)~b tK)mlߩK)rC={hKGUZ\j J}q/)9?khI- C%Tǔ"\0V _W{6C,k#D)EXajl l $UVZJ`{5ְVjJ:o1fxVk|>ȴ­RFyyz,Nk ÀTYo||0\/sDk'zTDkhq5NƉ8'Dϟs !%Z|~~CH>SބdI[Fׁh84p*)mj+P*nWa NX}cN28Ja\2\kaZ&bpkkqo5v΍N̄+spʏ˗U l|> y.^\WgQ[8epfi$ɦ)ec}]tbQ5kc bA51 Xkc bA51 Xkc bA51 Xkc bA51 Xkc b|= (K?-_P"WՈ?lM43ɋ nh(Ov t+4ZMЖz灢U 'tbKt\[-( <2 P({Vc&119m}bJgM\Y89|\j4\p;nc7t12"&n=$М8<o"a$')nsf$-QXfA= ,e{䰳 :(ErdVP:+MՐU<0vzaaZ+ŽVnR%"vJ6Ju䘕+2n ט&h{AEkY*=?%&V6[@uY1[W@>u_%"Bǒku\LRc0&GE_jWD=k )Np=ĖV.ڃNT<˝f0B2 JmR#m=Ah4+5l[&nkup]DP/s{vɢ)Ir6ag0E-E^1SEbf= bhg7ʓ-&2pzːj"oa$ J,槜9ʓ V@Vm6SiUWiZR\@JYPEC$]ա""ᴐCZ?J~B*Ő{x#{H ws9'nUNk@@}*L\&JD(*T.%-@kN3#zN9i,.F\ *B 0en 0vEAY#” fB a`B_vOh6x c\$+`V)Nx4 ? lSB$=;? i+nfv}2I%DOwʃ4: BҒ@Kq8A* 0Zla˱i눕M* #m̠63 r>7.k :Lٕuݤ㲻αz%z&/Kl\];^ NЊne\Fԃ{'0⡂,Cg ļug|a ]:̴g]S_L9rȍ| obIՍ#*lJK FjD>/GuY'EgPx7sM ń$Sn]hK`:SiIO.D7\=Fy؛/.d,FQCeN?H%dBQ+x%or9{.Z5w>Bp]nUrKe 1b@`0-{]M>23%EJzB?/8`AuM"_h8I@Wo7`z{ PdE_w޶c~9Avp_oZoۼCo?}6Qk~3<6jxM6h05"~X/2H/@ߋ@w>̴ԯk侀"'AKkSN=z'";8ofFkNovXK"FN m?|>Ba5Lo2L"^W"i ܨ `sYY]Au\4O*`_k 5?Yw|x\?;<_P6XWsW%y,nY10zN$-,!` *#DepzoAsLKŧ% 2+c갻A<VwRiq"F7SI&1ʴyHbҽHV4:շXE5s̅ ES⳵= _Jp"\95t.݃+nULM<f}|mr ʖI3Ac.>AkPKW]R,]Y:$4\bYkJKq)JEyup*&'ˊ') $KE`<Ӂl /^0}eci6w۷AB4hB'jlDe0c42#5//.ZX6DjJ!6BjQU U0(|!u@DU8 @_YxPB2"8=1rCquCr_0`r =eJgȌa{ -"E׍B z#h)hd\˕BqV]S.uR7^7nY*hKԥRA_TP]*.*]]*TVکˊ|I>CTTF9*]EMRHu)~U)r'I O66U>s>y'\"#WVNl*.[&"RPDgof0:D G =xrQu"_Z$rnx/^y@}Z7=Ӟa[nuN8Zb=%ѻ7Ѱ2'uٓ?F-DR?VKԥG#KեG#kȟӺH]z.=RKԥG#u鑺?ex w;;z<;8_#3&&-^*n^狹'@XKPs$4:tF*WS^‘65T5`wI `x-qhSxs`aPYCE4z6hp.u29%;Nr-(`=/V(PSkfݑ$Qlb. _u.W6 ea 'бΈ?C"81gJX G!~Q9v ߆!E wf\-wjA|׮&I@qh"*_T},=c8c~{t5>?;&![2 3Lu9C6i8ZJhP%nl:PJХRrP*;; kDsS`E'ڃò1dzwYX޽&I}MmBKBy=U?YB3Bfm6d-7?;,>i.vۉyTX `sGҩWUZ1IsU 2mhoes!wҹ@k qQxbE=BܭB8=/)Sm։Q;̆$UQ)չƥ>`&P|e\[\SܹOn1#S-T#mzG\Ϟe(rM X =dh^md4j?o*yvSȪxp^ɳp>dBeN({z+>r!5Ψ|1HQ Bi%ϩ4 aڸ<` tR/f4dծEWp,NkiiUBfӢĩ&)X"%Fn6*AUV2n jH21g" yhfhe\VJ!'R{T>l1jvŽ)Ҝ-.X:5uW߸ [Wɸ`.!+[zhzY@@- ?M<_tժi;݉UTKDΠ`ro$amuG-Nkq$ ˛Yuz\e9HjL8CGDtR>*HSAbӂT}ȲqzPaRf4>VUa Nib, 9Мt&{S@vq#$jҔ&nV*=.84JLx̩LF&;w{и.ӫgD\Evkf`TUe5r)tnj_Ie/arU$Yj7Ui%E*Q&aA -KǦaoT唝+{ *BoК؝p`D,~3AdUyrk+q*诌ӏ~UL$p:/ѕr錯QVT+ӝ2}?Yr*tw$^*ҀYÙETbVÂAmJZSF@x6[`HW@NGqri h߮ `߶`e\c+d 7FbL<#{~}`kO ;ӢfV,AD{l3o;iTz@sDXvb v=hVss1#JIP셓$*kUI"UYrwKUz;ew;/~?F踌x#Ā؈!. nرUsg l??Ijk۳:6_R7CvjaNo8G:vJ^pKN8gơ/ YcpDhs'̊f=uR.Y,ANLs<VcBˋ%-΂Œ˝ es{{ ՛.+Gs"{Ap.*i Tg;!rl7Br¡*nC Pl$"Xlzoi(rʼnX4?Jl.sL 7%օ%q}Gm۽0Ys{5U:E MW]t5L!FaO.!m\F g[m% }u>~_ CO/!>;7dy,.f¢,ޣ` XG= ^o\I"-8D2pcj^<1y0{\iayayAyhƀsj(Hާ;?XŏS(w~\Fh? -7tF^.b2RKaM7D*}k$^w1nLiGJ`+eM 1Fpv^+8.iVCBm+0oԟS㔼q*mAt=i V_xf,LRM2\b!gHbiI]#Zg"zU=ڒVdq*^ڐxnNLi')@(3GPʠ&M@^hZE|m=NUjhA*lSB>ݦ<#ukfA]fZĴ&7Tm,IX/ږ 3~-}9 :ŕ2j̐њ jiP,ZI~TW-ѧ8Fy若C<s&u@ gN<>c Ji AeG ܋K ? ִ%S@x-R9iK'QL #bk4{@/s-:Y˖g;Uj';YG8LvǬ©d[E >@f/-k|6%?w*1@z `:DT K.D aԺE>MҘ58:a^e~9 |Vʥe10FOp*Mc7px#\iǎ`BBaHA|ouXHŎπ>Vz J=l̽ˡZJxm-}֡ P^6Wl;[Ms-1'G:[AP24ia+*ȕ{ٶYyy-S2V`xo XnT>d"!Os1ߞan"qweQyό$8ELvBB:Efp+BOHF BmEZ7,6Pڔ eU`KQ#3IڲMd0>L7y *+67]WR"2].@G_;!ܫ8xLBQ2*[pFН>.B(/ycFANWkGYe>W3+SZD'\`.MTg(]P(v7 J"%NgC"bΔ9\BK| '؝PgS%@-O BhI㮪%fL+ *_2@ cCy"iw)vcXxԄߛJ;8jLJm I'~M0w\ ιsMmӎQֵ&\`>#b% 2)cTN:ʕVUHUiQ18ߑ;< Ȭ9f@L9YEZ0ܜ\Yib+f]ԶꫭC&Zˎ1v]9dǍQюB:iJXʖg=8M&%q{X=snIC͖ 񊓳:h,ұ!ݰ5hnK2EiXth\>ir! US.9h:{24}Yi!щl* ,c8X<1^ RXS`vhg&".A*F^0AɉT@[(Ř:gFh5R´VʠwL`@Om?N7"WY?5;/և#u*3P Lٵ[t*;I!_R)6sL_ ,Wf!uWĒݠFU4y[S& C ;ڛNdž;stY0ZOa3?hV4D!'|]Q4E1ff̟y2ijm(wHU΃t1u88DTu ֔0D6^a&0k[-Q 48uqt~~[H.?Vh(:_hHMPju&]by%[Җ, !Pֿf|iVĤ*,XM4UO:RApq(Vlj-ԁP2y'yFi*.N2^.R3u]Zkk&3|q Gk[ ^J~aE:/+=cA:ƈ5 &>yN!&RT@\"O+f<BzG ԝ(&Gܑ-/a1~}WH8 2HSv c%I@1PàfMB |#͛Rw»nҍRR Z-UTǔvӏ!?5XK` e`,C5XK`,a5XK`,Q%jD 5XK`,Q%jV 5XK`,Q%jD 5XK`,!K`,A,Q%K]7A'ݛb?{X*y矶߶ 1v4S_oWQDZ&"Tu5 vn}%*bQnjx/sbL﫼#4ו!sz&z&l}423{F?ā(Uʭ[;wNl9'dL6YT+̚pde͉:oyÌوl#+غW""'4uOAMVjYNYżyG`wHٔ88ـ;SCQamx)5}KMkq8"}{==R6oxžL3ex7:XNgՔ`cqdSfEk1;x03άr?_0=<l@ǃ;B>LLHU~P!`e:jNY)QǶ+Fc""N^Иw~#T81. %49;+071l4Sp]tb@UI%H&PFB"r|B_qXW VdW+0+`DJ#PX3&`Dt̼FKӊUtpc)Q( 6f!J2F"F0>4KQ {5 6k"0+ʦP"dKNP:[ȍA/[аERJWi(!*WAV|C]* 8PɷGv.P-C xG5,CltDuڔz FGE@S7p+N3G@} s°FHDp$9xZ,=?hqdƩ &y1Tpݩ9!,,fIE ɵW:*8y\U\ +Je>L4 srɒRZLl)hx*1(GÍk r-&$}GPS]O8xl| 3e:ZXԲs6IH"I|qB4]:@-D!*vJ9z@qV<hVG8 N`d-  ԗ^S=NxЙ' pbIWF\\ ;Z粐h ,.nCtއj|im;B_}Euǡ(1?l먉x' %gi;-"Un[ yP,~ϹP$lBߤ- ^@|QG<rGzŰ?Nx:3e :k.DNqg6 66vJ tvL.OL[A?x6UKy&d6N>-9]ƨ 4:Q]Pos殦&`~Y+U݄wI瞠vX.6254#lZ^x\')3/Lj7,Ahlue,k: dTph*{(GZCr5F6a+T=!LMŇM#SLd4f9۳c|NTP:yOEW * YY+.ƺr[Aө5`[Pa Oy{’K~;mڧ6~g_ o;e^Td,I nFr~F?_ !4n ?vz'Ni9Z\yi~Հ6z>k6 ag*`8 FkR7mt?lG}_/[+ҋ=oNMcyMҔ%o;N%o؀tzQUɮzOK}qkc^etÑڛ^v5xۃڂApz`ЦMjrFܣBuVu T0_5L}1 HAyGTC_*UоV4tX dB\GSV[6{ jtVH8%o)jHƈ"!obM5֚7t)D yT:cEdP;T-ځ6e8JKOʦ!|Tj!MFS 7E7HrȊkUe.#̿h ^Uʑ(xZ4Jd0-Q+"ޯ\ɮ,>!hQИbUئ#"ߠ#)_H*qN2QAzTDkDԹ,sЅ(էցP]"̚ds4sȳk;4 n!C4JVeJ2T^_BRe+Q]ԃviJQe ,Q` B YKME {̣|mgY֙}2|JhCFw\g7KZ@ H %H|8BϸLS=h.o$Am}n; - rIv7nE~Z7}C'i]a%?˓7%AzզeQ'!,ϙ4 ^g@ )0F@uͫڰ[*Np~ŀJ^:]]?/.\K^H;ou.{r{LW]9Θ!. CX^M TWmaTij;LOzR*OZFկw rn ́!wz?^Hy쎐skC fyD)nho16 O;'D<8;iuHS&hd#UymL;MVCҠy6&,kP `(ײ[ rQ.9 Xxѷ4Ϛ&ʪ};$]5[Nz|u};;5W诎Wq 2o\I@ eA1lrRW*Wr "bI)o WYRx)kX ZbOuHu.wD MU`Dv[vRt`_j=D*sɌt~K4p$YXV0 yW;I*9EgkcՂ, /4ʦ;z̤Qhʱ¿aj*i͎]VgTvqz29Yeep.I*m鵅U@U7[Do~Y _ C)l:J SϊkACgaȿNZ #57GtSDO0%bC^i79篓dqx|-[i2@^BYu+O)d10zcu-DSd.sqTpiJq[NMÊ )re9aX)b+"O5͌뎉픤'*-ĩB54{|۸P$KW"ro*vRl~.YyV Бyjl0hM.+B8 }cdc(ĝ<0GoSxӲf)n4NQȥD9HBڵnp`x= t!{[S2,gn v  )^th%*g ذqVfp3PN%sJZ#V7'λ3΢a.x4T\+J14}=K/K}uVw8?:6?{_?OF/y+'O<9@OڽG2~Qc]}7/бfRp[_}A`qdo݇Vj/nZj^J(:!n!ޟE}>[X߾?<huʛVuý}^ /8IyƻCh%hUr a , ?:'+uQZb-e{?Yb?OIlp4jZv3K9F$I\OZe~ݢ/=`:u>`vW{9y}ԙl 9ç=uQ8A9ip;y4=z0:H-1#zGBj:ϲix.zFyٻڱA n㭠1B#\kq9sK罭IkW̮b}Oan( A4uxmS)0DF0Q6NVᠤ+T4k('ydrjS2I 6\TwuG7c.&yMg*(,ǥ`RN-#;0)Gfv>h vu`ӶدlL><^Ij!6ӆ7W%RV_/2UeȦG'eU^+N6?NN7OrvJSS3Iët{5n^gtyczȰdTF$ ި ̚l(Ry&>BjVps"äyB{`򾘏^XbwgNs\nY[VI?-Oܲ8f(-bŪS-@6Xnx*z˂ac%| ]Jq22ч{(r$;mZxh='(..1Ȍ)h*W[Spۙ>ˠC'Fphyk^_8ϞbdŧM烎!_2ty؝sYbW{/qa@|zCT%@OyUJk̈́ڪ4pBBQʅE3L<˔;#Ow))vk?:B ,uT Lz+|k7&,c&fŦY.gڏ ;bvʳh y\2eo%Y C0.rZd5hN~x 3J;x9{ IrGx)?d=_Q?r> ^(~~ntVaVsx6fcm]O3%(TݦoZ 00̳/*{xܓ ,6*9a-~LO"Ŷ>La <765w,;sMCdU8M{/o{d:5!# T:쏼)ʥ$w%A>bfJnӔcߪ 4pxw]f nۡWT#a ;ˢ{=m L ~;jn.q< {hB'Bq5}^淥bOn--ܟ+$sSVTQ +(> ‘wwVyox`Ao_ƊTaOI/ӓ3Jxb!$yN5spj %uJbp_hEvb6lu]'*t4jqE<:WB] A5Yt; T)qcz4hV- >""Q7ՓFm[ׇٮد8| βZ7Gt&9[^ ?eAAHTWPb)ӪtSN'|z{@Q)_Oy4 꺇!Bn|(>eadÇ|OvMV='SFyhtti I>Z!7G'@c&;m:%vs}8Wщk莹.\=" ՠM,YnÔK^y ]ZSŚSq6%r)VCItA1ľOJ]7쨘eQUkZEJCk%$%HI- M/=@a>u 6?CQ$#B0hڥ|q' IPl M$]+KDum;p'4[eӿ!/=5 ]SLOv7CcXc*[V} C@\)ivvyz2%[?>% 5n^~jY[\o|k^G4tNMсRu+R|di`-gյkc'XDЈ T͖Dmզ#Жfg8 {P-8D7<Ob.mRN!4 6P\l뫷(2O:V13a1# Y Ih:Z ߝ ?{.UYǁʼnY%-g u]T㫂D&Ǩ2`3vc >:ޥ" LZXB:70`gڥ6d4iU"Te_J}vI  a6K5!CڣH y3a>>"gpcCy |b\FLؼ@it+8<Qk6 8wY4yqtܫ\S㷸mn`c^!H2Bh."B/+G,Q+^fw n\{˭# DH c[x ~,Uvnkw D\E=UUą7pL&]KШK QݝSN}*#Y4D+F@YJrp8?P{ahK*&܏.bAޘ1onOޱ WWiZ>5häTn3Ap4>==;!iot9yH ]5ò.M\5qb%bSFkI7}(z殽7:uN;~_a 99+S0$2rұw&jQV4筆Z4B ^`" ŀ]> 8.%̈&s G;ꂲͅgR#A G̓Aż6`T0owЦe\F,O9U6V)pφo>$ =QcV_yo^{3nVZ=1Eˌ=hhV!lٵlFXW>ˍsd @t!g]@?Lk ؽVp?D~c Ay#F(j9ti=`-AQM4x1ju DmL>)@3AJP(mM4D(,9_ɐ)-g:^Oo9$@ԋo^{!܎l;f"4Z;.r|Uj2Rb4_bdq zջX WSNY\5q1)2E3Q@$_*StX.S!z}b7s9m0}2\3+n)L5!0U+O㳞uf4cQ7q*\W0-km YRiAܢ\F)R-K4*"rzSJOU *TԔhOf7 9vTixa꯳+Va̹b (19r'@#w/⧊C3\wp1a)qjRN 9 6>C+tLWOL Wq-0`i_DL7b8G?ZE1FIN{;#3IFB~}Ԩ.nU'v;282]I4Y1Vsl>ֿi=QWKh6P1'`Gax?(;W\/D -uhN찊5-j4v^UٿX\߈wf\md&┹9mBp'Ț_UW1åVw̠(6Ҷák,F3ѳPr)ec*7Ǵ?x0mIǬhłlRżog?x3Cd0H0_=@9B'џcYUN7m;Ḉ7` N@y~Ꮼ2J .}t~ Q2i N 0'p5o#*)R,Ԉq'qa$ϷNa(ނkoqyek?㌒lxuD|gDoBo~a<(Dв]IdR *TI {!z|9\brQʂB[hZh m;s q nZ=eA)RI62NPVݏ#ms\7W Lo9BF#2%W 1er)ib&YvI"lMކ d `•}ndzu&+6GJb鹵#107f:*/j#_A_`( hS^mos!ɲ vB=3w ٗt恿`{>+2_'ez#ڥ$EnCРr#"CI#\D$>l"`kDv+鮊)lnW]4M]) eSWmlTN.9.늡?S-m_˞vL Qろ$@x^vy}_Ч䓠-YP3\}et~L"B3MhUiU=b)rG'GGw }"p[S0̳{ ^p"< LGYw}ɉPS9ۺe≄!N GAL*.=;!(*ߜ7}45!'~dG|+=ӈ_; p/,4 +I08}C֝'Ƿdz PQKODpR#UUq2_5&c&"%*Ě>Ec[/^v(ImÍN++'ޅ`[O7V͇4"Z`SU2keDZ+fR餝=|'PR%mfNI~[J/YvipKSLnxm:\(yi=[Yt<8\}ȏQ؜jgI\ˬeE}тJ5-AF?=نzZdݜh]j qI%bpwG9ڒ@Xb)zJA;Y$f:Sr>KTyWM9,HtsWhޯ(`P|tOO|cC]hLhWUcլ}a?!AX_T]VQ }-\WX٥/]Kxɋ'YW٣>ĜJx3IɷJ_W>C8f37/1P^:iI晙Ҁ9`,"1 %}]v'SkRfB㧔- rL d[VR^hp"~ePL8@K8Yۘt{"@_21y;]Dt}ZO;޸]fvm:'ԫt0[*eQo $|&[ 9q7a>F0ْZԓ"`'BݟV09 |T@ԎFפhh4י^Q7X C! .1]_<< ?ME_Ơ:$|rB(u[z+b`IK8$Xrya3!2IH̹bJ-OgpEo8QV"qP6ҹ`HIS CI)2px 2s:c2+18a6cXi@>UĕL9W[y21?-OrG's(J![:ec]W׷b k(BHFtnr:?R#PG7=oGf=;ū;h2@$S(F ^\S'VtUz;]-0@ª뽺 uyC;4(G5`*όO( EUf-k}5+NߩZy[CObnىm`IRt㐕1uQԠc?呒f :(1Á/z}bP+[-UNnCh]Ih7]l= #4rwW'jٓP٬"^ ,F GlZn1DSq;\||[swOaK6]}ML6^ N@?P\,qbXVY Nɀ292E6EXOYv_4+3:ו3;6ϐ.譻\it^z< úB֮n+L]{dpb){ %yW\p1;](Sx~QZu_vX/׷ڲ]TTDjI7> ܥ$k@%+)~e Ir33HLBtJ ieI CГ7|<$: 4No?M1y 'qЅ-'JRCncB!w%GK h=]N|gDs^!RB>Er/qWun7zaIC:a' iujBA g7#ћTQxLCJA'P9aHl8tlp“ؚϋ%h|hNZm  Un ǵޕ@/:ʖM'З@E) "g7+(\,PJřM/Ӎ.LWpvHZw <[ZC.)U"DNqUwA]@>(b0A / ŷYZRl[+ZyapmEp*[ED+7aekAuueǫ8 0VD]WTrjYR?'@j Oܤ46j]#Tn? *@dbqp-<2 z!̯]QE(˾XB CDc/; X9[,F%0(֚.py;*ZGjphT H SwrsAM4E7d~h3ӧ% *r.A { o\4|9bIqn)m*b 1 . w8ή3BhB{c&0gr(ેwM#T lQÑTX:=Pi蒀ok"^Ls B"c͌ۮ؛c[V\)uࣳ%,t<}Y57ғgvn{ BwfD9L}Ạ`b#mJRe&֪r 4`  T aBa^ޚ]I =u4⿦l3J p6z~9I-(p-qP#%A%q+@tv B's K+xMYgE]gs6j #47rVfvNl6.WSv|y4hbr˄ߦ_+ME3o9~}E`&W6vCoA<;lu;aDXVzJ1,@ 8%U"PMSFDϋI3E%YU`٪Lh,hB bQ#4u^C?+OF[|o BCpiO"R$Xqq-K#|a84 lrv9HN摻D5CSD9RSMdU1t9s<@ao4D3\6Y|cAA#2Xo NnMv ,4vo46$"tcz= Ww#V.aK 1EQtכ",4JdDZ" FNWZ1+u2muryW.YLo">g\'Ow0whAi%A5 $5cDJ;Erk=ZnpJiN;R׿;:P2E8QpE ƤBZx*=2!*@41_vBBAl; lxҶ 6-l4H"}'! æ|xwDQ|Q7f@JA( voĢiYOӇpz1"P)Cs5~L=~=O"DGwvʣģ38hC^/ɾ;K=MˈMF3 O5|^88wtpt?P9(qRL9 9,7YE4KY bmu_K֤Eʛȿ|E|*tsj"U9W҂BGTqzbJ=.?VBv-l}Wv^鳔JGa"IY'3}n%D|9Q]o6Fs͠.ȰaE5$bG 3ĩGpws0((+̞6X3)#ߐ9ih|UdGɵudu_)85bbݦku!t3 ?Օ"73J_ ߑvJ y ݮ_Q5\%M5h ɒOe[(M3 mMدTS =֊t,#&d[%'ERi_e1Qp"?`R$JlRb.v1HI+ LQ8Bv`~" O#8$m6-/ i%GG$|+6PA#)q]Φ v'^ G-W3GRZvu{vE|2ޖEA:r`֭:ІD#nHE˻0EqXd•L*yWNi h:\ l$شcdV˜Ch](d܆uVbw m"Gsz!0L_MwAR +U/~)\EqWuT|,n-*'бȈ,8{a6# O1EeR}jKf& $xSbgwrpƒ!OE(Ue>% cPN#By<$r {겧Tv:W:-J+|R ƆQ.Hf5U&A㎀b@TƳ]4i\9, n4R 'EkZQg̳黎X)F/`㯶hOĊQkV\xXҲ5D6yTϬҗltB& R\\!nc2T!8 }:ҞK0*-"I :{S8 c`]H>@-U \*Q*P'dH=ߴQ;l@o?zW_gdMM ƽR$Ht<uPȃ>m?h?lEo'MdWŗ7cssӧ17{sgsw+~ts{xsӝ7p+h@W}r*-6-3xr1>NY{\(Ћ K,} ]ɼUN@']495(^A;ق?zHC6yR& wSH$ UN_o|{_33Л(JN n-Qqsc0Mӥd\b cL %udl1)J" <+FїES#ʻd%%거 )e"`!x+돫CZzCW*QS&6eMTw*+cF?6$:: .k%G^!dd@0fx-RD@A !Y}}6Ҝ O''gduay?@1ܺO{Ą[LF߳<|z.c汣Dd-CׅCc# Ysͽ#3xt䧆gw.y*|kk#~}Mnk.c,y[oQtR? $*Gł es˪K/0 r[G&nȿZʨ~B߂2PW %򮄰L*cqsn qKqbY9mn= xs-> "#mxNIT"RaF$ u$IYIINC!-hFN P8K%+(dv<8^U @_e''ѫHUCAL "%i*ܗAB%'%ϟg?)fy^l?y_;7r>܇5-5'ik Vu=6%aa=_'lVXO6l6_nzjIYE/5'ڎ_bX%@-B}ߋȭ%zC֊-rkAz?؂~l7x|WCKұk{54 E-rvuuxMt/B6JUiJځ&.9H?/KZ!Zz%>wG|Bf!Ru3Փ9b^5|o\40b,Z@:DEp-eC <)Jߎ ĔA$q4Ѩ/9z0W2p6Otƞt{o|$.R˜eGĐ.-ODyڻAãGuiq&?Ft@+ &0_A_ˋotF}5 79R'uƓRtF-+}QݙzM)攝V*4 u#O .b7 cJo'PsxqOB>EOWSwS*? ?Ó(uY拉~%xWNhmoDlG7dDL@uwg=Pk]A ( kwXM8椂&}KVфoH+?V[~z_#+v;_z[. WE w&(4/!*a {lYQ"uo1<~rgXxObKU ឧn/BQJ?IVˊD[G#CD@'@ Pa(EK}Ue qԉ %!O?0V*^.9,{_17>%X[ QޕxWn6"Ub(iDU嘆d!LRCQ#*8tw5Y=R eG zU!d0yoDd*iVš"X~p97s? F.v.= 1CW2@㌤ *΁R# 7Rɽf ] Hs*cLCW/ԓU:$9?X^NOPE!sak4ڪ+`݉&OBL'v@l3gߐ(MRo@F(Ly )aL$CL5,>pXP+6t؉I6j(!=3* OBֶ'%al)e~#<u*]]_6Gyd-i$)d~~P ~\8zpf%UX%; }g$#>'SRUxŕ`'N X!{BG0Q=PTu7Q٭H<~DŊrԻ֋]܈C.qf ҋ]а_eKAjrʈ]D"bc3U%A*N09aa.T:XN4%Xb| @t<%vZ?eOBa[7@4٠ `IZby [ JN+Ǐ@$.Ɍ,$e0^smǑ6YU1 DWC9Q6cK=jH:y_' %/t0B Uu.sEuB(`bVGą;YoYTA Bsz- e3uDc!,2vUsdXD-jn]W_VR{(30RdW|1n{6fLPC΄|1.1 cULF \xF:)!3{ E<xy%F)mTXCAM㩨i*KKg./ׇ `kMzԤ3`uXT&'TfLQ@"8KԖ,,}?1-E~|kvԟU%frΈZi_ m-W753F_S-ęe)kѶJ+tCS֥j5^-ieSQ+i2'# tM."V%t N(b^줫3e[ XrfQt2+Lad;5Cxxh7B!1;x;\6}Us2]^JmcHj%%BDX(Yt' "&1}KgjcVzgN#WqYEFL$2cbFXXOO >5I#޼wNr]H6ɘQ= ^t.hlՉ3)%U*$$I$l `F卽H w3qe*chFıY:% $]g@i˹| v21+ ]NI-P æcBV'2Z>&Hj>T7ڬJzz)〩S!cQ\ FTE 8,#8{JS{8u9Xdg ";\2t<@fn+12N2g "1--'K*we*$ڷg"I~l(f˙j!z?3=[#-R#v.߅|wZm ;$cVFoҫ*#6~xm"Wfٓ.>Rf"7,hv00 ?|۴)Ⱦ$,Ol"V c:M#FxƾK0[j{ o^}^( ^) q4}[yÛ\svR:*,Wep'} 1gXebnhqå_1z7FCbLJK1)yxфұFio;5:5϶5mxuKM4(?I $[kqmB*Ynl \$,׃}>%i+P_g/t}sE{be"+Q",}-އCjc"7(:bwMk.Ů?E>Њm;ϙ=$2Ē, 9Vh&<wyTӛSՂ nΥS}Ģ$]?0$ ' qg>6 tN:t^bHtZ膠ҝ$5/L0f:&ksIvm)$ٮ8OAʪEq}M+p!<[f,R`.1e"@¨D!aYb4:p?{jD`WRO Q-1Dy[f% -erl7)-?;k]L<W!`6??gu'P [Mg??~O&$>LInlf[?xwwwۋoy@mF l>A esu>LeC>d]탕>oΚ|q>yO] I{[ Znj u?P{B@{?]=Vt[FzWnxWatZcl!T;Z;eS[ߩj%j!,? jP+W  숴Sf FS|ЩҞ8T7ϚX)==<CBa\YrL`~*)Nn;/'%%0huڸ}O=hwH"wiPNWJTwS6wSf[k÷yӪFuh ~ zb0(> :!H _vja^TKkc`{if`{ji4Mhö B=s t 5!<޵vZCfнt?s~0ImQn-gIq g DiQHioS`X @ab{x8C8 t!Z[5{%ZIY>.i{4ɘUMi΋?? ?0ýpxqRbO77`%%9Mo{;gϻ??7?l@P@_+n9W ,7w?17?olO~{']w̮ڽDzv3Gt3GsGuGvGrGpGuGC7Y}2n1OzULYOdxVg!Z6:hvU(*NBjRzb̀9 ӿ^Xtkv Rv)\s@\aa@UZIk+cl 4ym|0+"/s(GjvS@~ְtiN U|esB̓KϹ8`,807W<0&,',+^ϝgZ>~G0h93q@>{;VF.Ơ,~pt{.>S+FxLMdKFa>" y8k֋}n稬tV<">H 6b^1f3,T.H)T Ti^o0Sx\ R]m9ygץG 55EG^O(_1EXxܫka`̮ʵ>YğƼqPVVIu4 K{+.?8VXRJL ̼)V Y's[?!8V.;qqe55;̼b U9Q\c4$Y (R5CM*:-pu+_hy|5m޹z҆:@ ;4]Y J_DGfrΰz)㟹 > iܢ',@:wZ'2<)?|ZEq~@0oB}qd"XX'-,DʄUo|(4aʕj(PO٣*> (yRd[śi21-"QNs` rv3?IE 2~`9$p&PM'6J#tΆ}Bi 5 [\ &w3VG*GtQ\7o'rΛbaFg$ Ptߡ#WR'ÿ1o촡;? §Oo'џ:iaiЛfNHÃU-ԶOn9[ ]%r5J?c< x}%m산aAB=%RAn7),m\N!]Hط5mom/ oԂ+$}Q!҇꒸xKuڪּ#'7289$GpWd; ;`ʹm?=~+Px#NtBξDN7Ov ]K g,LP-IT]H6SoLx%xRv9둆9&Eu ߟidk67ܟP/vjZ9N2Yž\SBMfyp6ju>.\@wn[??䧑s k.y7,!3hwT=deзf2Wo|(~4=2VN<\_P9E=T_@9E}CJ?϶v?[O9q3{^k{Ik:_m*ӕ/(X2׮_?dM)K .|iJ7ݳ#칸ZA1M442X͛/Wz1cL)P N7(PӍNm9@T1,rRy22L+3CfiIy@;VF IȔFiE)L̖^-n'Pܭ,QJ@Z?Lr4K#!wKZJmۙA/ m٠ʯbA$clzcwvc-TSnh C٫Eh8 ^J2ĕIJ_Gk,MٴOZ"%;MjS8;YqW⸶x #k&=kB{Xٵނ|błݬ\{g;hwQ+ 뾦V*LQ涰 anԑ<<'V\0|oY0NpΑ Ҹ օ)*Mj=S]O )òVѷ+U/oD8ܹKr鎔'x9ڊӵ'F6xY9|FR$웱~Ęu>^'rڸ\>lw" ap1ǧ<5 [O*O@L qV(agPcw!~mcx qvYm_5vS;fV*A-~.3Hg_A)/kpD@\P:K67`C;(ǜs=Mae`ObCd1)ˍ/\O cIΆO䖳['•PMkW? (%2c4eЋeI+_3Uo wM(Y3&gJ!O=zكIz[E|0H䅝OPһul!aYz=Aה}HuaS۷c&^‘6L ԙ+^`!Q^sN4Rj\}xeyP ^l_IsSKlY茺6uTF*UG՜fޱ&}h1q+j(awl9 wF:.Hӊv]f>'!X;&RL`Ǩ`aO.hՉmUz@?Uq)VLUC'_ Iq.S#jۢ{^KH! fol$9w=1[į&(p8Kf  KƎVj`xhwd$οq["3˸V_;r>if͆i_rFقJV-cq YdzID)I䘅B,K66"2LK+m<âMҔYգ:xa 2 z3?zΨlZojQ1 C,HK AEOz(K_ymzt6hx}O}pur\We>N *`_09c=ָuOQ_[͐"Ɩt1)7iZ@CNuO#X/K6m oJh#(%ZE]Uq_{lVl,Z,_zoR| I SA6d-˸ 4kq EXzIubB<2a}>!)>9(}" %>] )tHhA)cxuCfsdT> ,ĵW8le:, r᧘RemT+G9cޞ bJM|3} z'm8gz:SB7*G~ <?;gA%/~/js(>\zpmMUQLmwX}ƒ0gTBfju4mҭ[_\ z xqZa?Jqz 2ʖ'k5zbnx/vsFQfF v6^2swuCAQ0b͛~-WEYM216S}o. ӍGS'j|>=QNʼnفotSd} ]W=[Il]j ' Viߩ~M6ʲ ]4_.a n=O%^_{¹& i?mlx[3G) 8} BaG mvhEqK0IEcA^X—ۓi C oo 2pĩ6{#D 41ֆhGgckX1yOC#hh{#89:\x?{'i :w?ZS,qb .WlprL?CUZOa"Og'\tHTn =>CHb\ I>@{{=GGX~a) 7j*:$-VIiœ+0X^k 4,+K#V8>@W7C3N1-rv.GWzQJI{ C)8y4ȇ檳ïӜPĶaN\JΣ IѦ.I+/#;!ޯ`zy%w?/bks* zaTḞH$SH%9b,av5lvGo93CSg)2 V(Z @1r<%ޮ!Ja&zmjŕN1tq}T~v8DTkz9 >oJrO}&U8C`g3AozAEZPFkJA4C05O#Jp&Ǡ4:.QIf<8qGd(:r}R[rE[vq!F0Nz~Y ,akM5 5Sk J g$ߐfɈ R9Pl5־6gQII<`~eף9"d9z].Zbl@\d+*+1xgjg#y # ^J1{B;FŢ/dM"%}`n~6JZr]e9mP =f)=G:|e_N=Ҹ0_ZCuk`ᡘ.vFdOZ+Oj6sR`/6܁ʮ|# ԼLk@E> Rn{п(K ,m\+b܇)g8=-BWD5 ӪqPOvҜfb.EvYc0lq>CX,=/L3.|ZE#CђγbV'V^V)IPe2Ф1u/d4g0X<(o-LtXȨscV鎹'R#w ڲE\a3ILy$ծ.5R=,u)$_%7}4b. @Euz8z|Wa9&CdV g7:υ|-.%. :?ֺCȶԾ)#Sp ysWn[b)=f `.94ʧ\j8Mݮ6R0Q+V $]7T7YIq̪ Mp;. *-әT B&&> >.AqYdXK9=.7MNIbfmtv7!,難ӁTM^׼ع8V'atB쟗V<~c^~@wnRq3BM1ʅea}{Tn+7-?9XgYXe[EF\HDFj}3 )7RbEZT\96O?e:mf{[0Cnp`K濧v㗜iɢkzh$#2t1hv)rS&Tt@w\zǮI1C5Bj/WC/6|Q@GI|N ,{tgs'6 OЍ[[lnuy59kxw?n>C~ ?Oߧ,&Q4_34ޙ"QP?XO~44u 1jؐ7$]dH>_tyMvۍf>ap8u%&ec㣦e2lxlWI@kohxm خ6R΢i_0Bwr֞:Կ)G%frqd1_)a8HP5 ǁԈQ\|́UAly 4u5Ap#TBO͟DϚSc盍GϿ6{Þ<}Ⱦ_?up{:ѻZ̦_ v~jGٟ=}ְ=C~?p%ӭM${%`c{ɋi^ݧ %9CSЇAļ1IW @:XoO~LEFE~9tJFn` ⨖"҇9y MEJl6ObfuiWQjdJo=<(apNf~Oǖl+d%QmxUP%<``70'pfDrIEr;;I~onomm|[nԏf/#H70m=YH"LR#нDhXU8S* 2I+ gUmT1D#1{@m;0[)E[T_bG\=rȉ l2s1b$I'k"ǰRZY*K1%|ש):Q.aoazT|:z RιX̤h3mx6NH lf Klzk.#]hfK _uX f PT7f1\~*x7\^b$|ЖO],)M뉂!q$qSϊ 3e#·tf" {Fʊn7O'Xstcۆi5HY̌;ZZڪJQPaf+{MsduBK9M^]u_a ")*_fœ1|a^gLGḀDnbA1طo)6 2)"N$S9Rb)fj-M֏='Px5rZ!R[}{WǦʢRkV ?'lm&gH. N>*yK9SC4.b*Kۘ/**J$@BR }pff6oD?>f[l&܎јR({B]L ړM}r!cA(&5 ܸ9Ύ '3ZuPE#IоtP'+coݜ]p'0W{%Uֶ%/1h*&/cX(0tQ6=d+]RJȟQ׋'A>(㙴:dRY9t|o$6 *" t!ɔYji8 7ChzJ_.XT$#_c^I}KF.M٢e[5Q-mdT1YJf`%h<`1W^P"sXM`cʏK} SɼATP-=ڄx4o/j=r D: kI^V.)wLE!i=i]֝BH3`4SH#ߣ W,|-B%5kWlQ5I'u3ה3M O2<ֽڽC3]1ݘ/;Fd]m^K?)dڼمuh,Aٝe0OSl 0}$fp>& 䝮*^~9]zBR%i7DڋڎL]& JwV䋈@q1rŨyTymJHi5jV5:#ԻM 2~=:!Fz?seuF}#܄*JKU,ee(1֟5Nt k<*[uGmL2{gt)7Rke;j͈QH.)W4cYq=|S¼>/&Xz^zݞlm.gƼ_$3m/h"W 6 J%Hf~K /ߣiO1{yu*ຓ毈G*<5k]㳣UGt]P͉ N ƣ\#-v$$ju=#zR=RbF[GP!oǘG>%}v!/Ǫ2\@u(0xd w8?'hJβ>²:"/E_lad_r71]lW(JU6Dp!;:8<| %o?~KY#n1x(^gZƆ+KRa:e"w{dI*Ŗuz+.t`1"u'oX9;_E#)M',;|R-k9 7[Z&&[tʫ<2ĚJhb&OIE1S̝HDۑIa/<*m(^8LRi@lxF\Jу^R[gTjj B!pʾampfO4M' > y00WbIӆixGNfJ\9FIu|ѱSۗS`^n6]}:=Jqzc%, IoֻL_yhh\dxG_h"7.>y@xC*gq-i`Y 1{l |*,$b&e)%lCvFl\]vϊtJB\\/VZ35sifwgB4S?D4a _$_t{d)-\=w7?~/.pW,v/)MU]Ҳ*˂Anj7zB\CLOc Q YX.sp:%0K=wx5܇ -ЅS PedSTb4,毝 '&<ݠ:Q2)<]'\rMΈįbX+˧HBs-66Bk8Z$ gC8(<MeMۡ F ]@IU Lbサboػbc 忧 ߾x7~̙yf@FbE'r<Ãb z t!%iڒHKd"bO7,Dž|ZbKdb.ܾzBuVIaW_f́WXi~X{CO>%R\.JY <  B2 b1"Ez6jɜTe9 *&E:{F@2Ƌ }QP /3GdPx)yp6Ke@d( B;BɑZGr8Sh0^?>5/|\7L)P捐ZȈ$ɉ_1G#@.='v iBE乱l2P)sd/0|ǂ*h3o\Nwۙu>gwK{v֌qc 呉po>T(3##|"? ȱŴ}M`.tOا,F)RzVH&\k`5 SVJ(Uz )6g`=^ Leq88('a CKx֨^p΃s A)bMc%`Q€'PGaEFW$03' knAr$ZPµtYÛ)%JE|?D&r 85!,K+U;x~'A>? S&I$ Πhn uia7pUڌs1__1Zq/nt2X hf0o])B" L€밊@v0.!DzD]j*#DgTuȋqN|YX;x`9[ _E +U@ )SX b0|8*t⢤F>AIxgb(+j dè$CόOzXbd DbLT# HJ`ӵ0 gE+N8"%0%,4G1GM>1å H.Ȋep"v5,:C ma.Va2u$P Eէ5P%cd{Nj% V"an_ڹ%W6 : ; V>haIQed!Vh߃:2 _\gIɁ 2drMWM+QY8:=[+1uApԁL 1nMhc&:@7VAb1LY7FI1<%ʁf-AJ& TP APZ#&iE)Yojh&Oki*X `JFlz8g',q+pF1L\WҎ7>R ՘>_qC MK! SIˈ}-!<5W̏Q)CXKY/"p`ŊZ Y ЩIsVi hX &siЀB*y(p+ˡՈwz+>]S%) /O"L zPPL o|n zᯓ^|:ɀZ:Y! HqH SڒXX2L8Z~4=A6Z|j/!b3V2]0Of!.CТ VQL*A3$@ ݛ Ya-JA *%,E)L[Sh|P_wBn ԪlBlSYk$ ĈiF#!v&BJWɚ"& YyZVbZ)-2^X: >'J$.۳D!2vloT L ,zBwL"H .Rfaiuc t!qDH<L RNzBST5+$1A8.'vS@Oo$Af>Ndq   .,jbN|2!µ#Q3J˃ 2b;Ve҆.5YDQ< 4ipn?mt]Ib+iRLn1TAH*wհg)RYR$R .$ʊVhghgțx^IG)nݥaY@'%rlk'f3)"Ý3TJ ^xx%M8;%<ɓNAXfs21]i3LS|,T1(NG@w%:8G0j]K[U RDuQؙaNbKt0L-%+eY|,f4?F`n">2tN$f9 1er+=Z|Df贈iŎE~6P YnFԏaR8P먦>eԬ4)w/E.:1pBpt\1ȃfEh݈8Ea&'E,<^W nW0(V$AV8\ ~{HbFyP8a k gT?'Xp2nAFf9gcFQ?&zBn9Łd|ZAW Xj;z B~J`K@ 5󓙺` *4RTx7rz#N%a9&©=PuB?[7TDUĜ EFEwtHN%D!v~(#@) ~Ab!H))$/%*ދaтqd$:ʭ]g_D_*_/GD bap{NTH/ FJ%aA0?#R- GBw| /2Z"DDwpEA+/3$,@(K`F⸈H.$@@5LJUXL(  @Q9GSS EÞ$wP*Pq$}a~$!H:$PF?&/%RЃT&TGJ:~GgDu.G_?'P 8 :MN ābhI'jtT1Q1b>hA!!0?U_V8C8O)NR"#A.ah&1a c DM6Йԫ|2pj B ~gj B:#,hzPҮ[Rfr } EU>P qk7 *B/PSSz|pjuH=@\h` FU6^p:1e(8ԵJ͏QL$@ UjIР $2^O~H2Jd 3 Q:; HQ1x@ JIW*Z Q'#>Z 2LJ |H& Yag@(>((1 e:d&=ոx?E4Z>S ]pB\L HǞz<{Ɉ}vGp#y!r C8loPyrS!2RJ7RaI 8s&>lik1R8b}1æ[ȷ k)x D2;$!v=򡃠luy`o&2͓8@1>f 9 5Vv5iJp!x g#UăNNe B.Edh ↀh 0m`W[T.vJG9smcƙjwc& ˧E aakvmN'rgX,o7'_ LpOE3LȖ )6 P -iت^[P `(ϘPq3ynɉ:Fl+ i~'яM8Yp0K)HC t:5dXRR݅[gBrЀA@<ùʦ:{Kڢ@XBmHݡ3#ec`S TfX*[ |C]J̦ B^ @&( #!PJlD--X*+Ug:"UeI25s^ ؀P+:"]*e[ڝr\vDMȉwNL/\(R X2Ϗ鋊IbI=aA4BZJ`yjqHUI/(% ZiN,AI HG,~$.guJL]b'* LOU xL1^-e$-Gb1Iw2 0}QX +ƚEhJç< @$VHF§i8Yܘe$&LYR8>:F'9 PxX,Q$N^'t%[aK YzbosfHC$"*>8dži"Kf a"!T[ i@\:ԋCA]T$:`?#8-& @F z]L$:JGD35TPuع ng ) s@OTž]d0d@g6A! 1gE2"AgZl" ìug= ɚ 9(`NR)tPBPGd5¢")' 7:&<|+TJbRIIU߬DV[i3`n L=d_2"㿻5s׏/| ; ,ŴWk | #H,hu$$A pe! U$1΀dh9;8 C P>p̀OX.,,(hbZ)S(\oQt {P!bifG"): D^,YC,sK^Oe{4iR$7]S˕||#4I!s&6̛aKXK]4#/2c&CXx$,0*r-%p]|Q샟fg '&< s%~P_4!P!ᄵ CZ/VbRvBs>p)O?@`4==w'> >~$FCLo7T |{yRV5++K$ňTT259'BЏ $MS EE>Q:x6\ԕEâ8r=A-halRi#Glvl7/)ȥ17l֠[@ .V "1`(6edN'ڸ5b(F+ 5_)R2 ba*P1W,l6c` cs!qFUU!l=g/D>˱w vyvRXw`bLD TMh(OBN9 dY@_,;HNА,C{osrgՓ*4?٣.U>%Oց`{F֗FEKTo*Aa'!̰@gUC+8.N8 J@|+S:5T=rū͜3j8t > B{H0=5' 44\@"!8f2.Bh`6 եayTd7;VN/FW9ai^)I?$;^͂"r"gltAC ^U'=MLQl$g[I!7zRq b$VBy%HmU*D"49 P2UjrǨث gv9giA)}2ý)Wd`\K'4'^+`3;k4 v\"0 K8Ag,Y{$ݩ*zGJaFݟebpdY野&{)]P/qMT [%U^Z8~;SnT~ efW,QV%lFPeX<23S kn h#dhĄERyDJ)XN1 łnE4b` `7?% ^1 +,4l-F8`9@ k;]"#Yg: J̀1[cUm+HRu:qa"'ex&@}aC.{/a=n6Y?eyuBx4*4fbGВ6s@CC$l(FQ\I k2:#%`S3eZgH"X ޺0,V|!/UZQS:#t*r-! 'رU1٬/ΈŐY.V4@@Gljq$}!cZt&)BT/ EH#tƐ2SйNYBAc(-q8wiv HL{&RN>w8 .=_ "jbq*q+Ȃ>H^ͥB$=(Zl/P-ܝ *>u:ޣ@H,>|3<U0; XM{I`yX lHX&r+ŀi wX;_VK+6` 2<ޕ#O$%C1}$(\~B}f8f@][1S F ] ҧC)Pnq!.x :(4I :%u6[2;B >MƱ d9 W!0pl MB3Yn>vءW} >М5O&6&j]V5Ғ[5Ӑ#Iz CXx_@-ŠWPfL9"VJeb] hOln>leD R++=l_QRb|*3jE-I5L_/fuh&I^\tF/GUja^^8@/@d8X,3=6JŻ5ސy@GiZUrz:b]Œ#6U4NY3 :_Y BnĊLN)ug‚d8ir ƫU8:?a9U@AM8)#]e,:?gq8xFg@eT,*@m̲!^ E9z)@,iSb*.LskqEI$C$r" `ЈCD ZEY,1V+p94E ׎f?3۔ٞa*-xШFƩqT Bˀ5$')}$]/ DK ^CP0:wzS0 >vYn=w]:d_ Y zOI2Eq09{LalL(OlvqeHH%$n`` @=L$t"M0, QLF0L ^NTN ėEv~Q(ҹz,ljRsZzeZYbR QWaY1 L$!b!@h!ZbHbv8C։į p*r] &Щ;]Xە8 N}FMYRre oa\5G6!QgEd+Z IsAK!ri".*:&3K=т@U .&&K 0,RSBZ-riObL_!ODq@R<["Qj D=9ʐ!SI0phT zXǐ}h'\3%ܨzq.N@k\̹MMct\EWI`  70fALi*P)R@|@ a$N*Dfb8-L&#wU' ܀G+xq^M?ff-4s\OH@c>(T"DAiKk8dJ-abĵ6luXhf:`N0؟4 -JKBX-1OHQGZPtFRĚX& <&dYLMXqERuD{Y:іsc`C ˍ14嘘Zk6F.hK/"J"kI܄0= j|/[EImHS2EF@m 92jf:t@>(]6L8;qS|JKk] ZO\g'#AD>1CX|`sSjE }o)PRd Bc.L9=j~YCxP3҅$r{ , UXtEʬLܿ#, 2 O /ĿbfJ+PgG?sxLdI@//ҏ$N^HW"(S0VƊo X JƊX kX p+~Xw]BB1G 9?5uo%pso_p,8|IXE(C`pmtp $l $eޱ9=QfJ5_rs41_@L*i2ˉ/BrM:{ö  MEamHGZ h1PaDT}G74 3eQ % Pf45T^vx1?eghW}+ "M~E02=*0  í/T%GL#)\RB ;%U#IF5`P#9#FhR#i/NAsr vOA}PAL)P@f@aֱAxHFP2H|:8#i KsUJ)Ҩ,Y %#MU qq@P}k]6 I\۽D L# tpܽ\Q9>OTKMNhrUR\RREXLj$䣵wV{@m@ Sad>EA 6F)զk*n(N8A^4yd=Ne*4qp*>Üp$fk!G̃ITXC]:sPE22Z&56Lejٔ_7O7=G>"‚*keZAI]sœw[qRC+Ӓ0rXxզ|Ј/[Nn5曬[og~߱ξ*,w ?YԒw-RNW\IuIv:rñwWc-WMjZ&}=ycXEoMz t^;Dͨ' icQO>hs^W{웕C'9zO>PCܝ Z6㮝oiB֍9R=_x o[֨Ss׮z:Y]3.~\G3W=v>10!a7%ydw=6o?. >mh6mδ%>p[y[.]r֯h:6_Mߵ9N37X/S*ĝdܧ`Q6=S6~y%=k8^ U=}{hƌ*|:.Ox}G]JG4XŴԵRƺDWiah˭8{峱YՠǚM2[lhLk|޶l[/CWwZ&nrVν;jM{:a}[֙mʽ3/N7%ԇ)_Ox1kY] /nW̭5yWm::/Ç>Q:g, ˯:~4ꊚļhwr"#tm?/dd̩GK Vn[nj~kV.Xb9>ohk\{OK"5=d3}8CHc[/dIfuۭfS1lWM/߫(N:WXԩW96vL{x~rM<{^wlqWhvon4Ͳut8ͦ-ޏ; oAq&_;8w?/fmvaxE/9vu#=m 1^jI'0oaW6Q_j{AK"L}2̧|Plܩ7w|_qӫ);C췦|Q5 ;/grmھbHWϴxozYf?zZ2b{igwNݤOmT3ˉX98sˈՍz}3]ol~货U}=dbxhsE%?^cu>22YV8ix}t5c_;V2䣗M~eT/~+{~Oflx1_\y>~݆gؐn2׷0MbR1g==z)>閯?v5(y>ܗh@rcr~́{?x 7p#~QrcFߜvu=֣fwĮAAn1R]iWt5æYb޶s&x9B]+"}m6{EEv>8\``{9]Хf=ǭFW72rOe+<4cAfs^''b4/웿K-9;Yr.nuZZ}7ݷ>ԱSۗw;vp4_ltWޡ%Ɗ)vGR|+DN{xW_<A=ELs8tdt 5|D}]Cf6%?_~~j59|g(wj^IiH#YT_x˛ I6=2m-o6!8Cw? ߙ6c/=.~Ky[}j?MU~`M1 u c/ 퓄M)/3OF[lj͋A5k\+Lo2lt#_[8^˓s]1\M:yXu6EswQ_,p=\3eg6;?qJ'mİn<7o_lЊl]{&97-/|~>]x/l_DA{n#Ki*nmz}BlJv ?^U%6os_| dX\~_ϫ&̨tvH@ysTeАw!B3mr\jNmV}_zy3]v(hQ:4)S?Z4z5Og;_jkv(^TY|ź)g{h[fm_t癙67<ǂ uMc:8#eUwKMk+| u@}@w6n1/V,&mX֔QzLw"mc%#-Uջ6SFKz۾n7xo oW^ݡQFVhL{koƮ-r)5%]/gw+w{E=`b`:[7Lyœc}ZھR`sOG]Â!ZÅS]xY~n01SjַgB(*z' ;m 0YL0Scʼn7O&.w|w=$4C s}>wFtil;=>NlYXtڗ˛Mc^!?Na֪+x&w)O26_LCU<\'N|x[ j3_>Ѽ{|Mκ>]::ͪ Qέ~ 1j}WO٪bk=w}߾x.u_qe<&+;;KwwqJ]>F,j>vo _z~jc=WntUkeyAM/8O|҃\[,{˯la5;]ًaq}N۷,{1#66Ԓn,Ejc&tӂףDMi5ʴJC'ou6wәruU ^h ڤ,UMug^jcǧ{\hugI9Nwv:? zmFP8Oyw삻W'ww}SNjK?4L)v4nj rC]'t|:xŔվQϹQ=m5Fݲ樎U3. .m}O›\Ý[/.1FQy Baҫ;f"k~MW.v{Ljɷ737[ӱ I۴ͨ{M.6̳6?:P>fݾ[V±fOjʗw޸[eӷ}~D&s+ٽ~ '-Z7\{} c/sdoOL,wo]:sGcnɅuVOm5k ޻՜W ~njZS[%a.C1YjSe[s9瞭>zjf .Ǥ~|z1EsЎƍ/XfՍkV zcKmyF>)ˍt9K>" vgx*|[9{7 {CV']7&pvn U<{{g!*>izM9묫l oC׭70o{OS>6hae 7i|/k~{\=1s}&O‚ҵc __3i&<-j=3kU;GŴ3kd^(_f&RSGȻDFhf6l;#|F \gonjgsuGÊW{nWm]j6Fr[({fԩ9srf .T^6?UB9c۝\3̒C+Ʒ$}w>>/JsxKo-;j">N-47$lz(xHiԑByv0,\q?7*_ҹH<ҳЂFꅺS̏S;[fǰ6ޔMYVǹm !{7:mTܪsg>~,?r G8OWζci,|yT΢ jἑ OF }rxB^g-ep,oLlȾ[QQΏx^6zyԟӷCׇ ρm|=$qtZ{YU fy?E3yFSF=VMIh5uZwrm02_oQ軏׃_( ieMn 3v7Lվ ε8h<Z{Fgz\wwɆ7j'\#lW-{)Lze9>ZoNq_*x-fcɓk$;c_kF48Y`w끢ko4ݸp *8i;jFz٢ܛ}-r.5Jaa [SBkx't8gaptڒ%ude,??L.N]:4H^_ļr|bwyQ:tiK'M;^vj'gj&y~+g;"FUtjYU_Xԃs5Z1AJъk]3yƇE{-RmTcUN*1\7|Wh=Nm=5sWOrd}-j\?SmgҢqYڋfM/u8"KL҆i34+2Ԏ>?Q5핝}O=*zAqZ48x?Ϸ::GrBG8gC̹mىW*OKI75C6~ˬhdSUo's`m~z[_EcU黌<<[/jm#q́ښ&(/ܟe}u6V99熯CG jN<~OAyɮzcyixb}yvX~fࢅ)ϓ~⭺%vj/ >//g͖޲0}K7ȅ3;=hUүMm݀3 ?kfYza`W;-kl\Vl +oWoݡVKˁ-?^1eLMr׾R$I69TsKhlkKZ^K瑽,K~ Q*-gXr+Y= }Saw }?E4cjɩƹ\Yaj3mv+=KH͍ډ>43S^!Ǹ&N굷;2yDtۡmWkZū|םy.Q2>ۮal.9Y&Mramszu89ioĵy.@cDsk4[cmXZƚKʏo$UvҏvTUXuo+]YGmi_ͻ/{m|s?mY3:lYդ;VO]ХYSZ;C{-:jƗKG_M:bՅ:m܆/moY)~K_Y1Su:^lX$z;O^~볻G㽧\4eռyi<'M~q-[z\xy}ͪ@󴥖rO>+7툅Wܨֻwߺvʚ,/=k)j3#!rG,uxo~W|=sh?nlf+L ^cIomp'է3 7bar Bvr]:v}htS 4o6jk뺢v0[O6[>u>'Eu0LxV|Q:Qز_Fˤ/E9?7d­N?)h̙=J^8KYryoݷ m83֪u- t|nuo"{}yAV)nQ5n~z{vz맋>m}Usw^]h4b?3?gG_^n6穼gr>mSum߾%; ;Mm^ýW6^pǭ{޲'f@{4nk*!SgDx4uC# *Y`gwLw "JP?+UJF&EȨ_{H{IEJV\tK"zyEiIm{F#ɠ0VM}MbUʤP:=*K& D)RRȓCʇkԍV5G?@RѤmIWq%6tet[^#κoF8{{x{x4w^ ybZ&MO)EUiG3=oS73PhddDߛPf<ui{Cࣩ+ ~VI.fw|oyxPny_+C69_O+Xz_WRSd#RKo?Rkk9t= <WZ1R5 Wj: \)`oT Q Ԅ?A]QcF= U+?};WPƢxP|rz/1 t̐B}er s/haϨ?8>'u|28?Q0z<Ћ`q=3?q"UNQ}ڋd Q8Ʒpȧ"mQyaJv펦 Jp.>FݡwT\]XEDȓ[y>9,r$U" -`e `+'gh`5B=``j 30_f|S\=#<"DSX' T/Cf~ς[ b"/)&QНy8sRzDtJxGR6OzI__+sG[<`ԀOBb@}Ќ>cr⚨+ѿɮ`ty#Z&s{6v?&itIj\koSE ][gcoGYf1ij17ehQ3Up_¡03g3jcLF0&"z:g`&ԥ16CO0TmR]]ԫsYUUSW0LlH0L,H&RW]_iRMOV*u"B7ojCd*<ME=;O9TZ<,->8/a*]z$aa yUJ A7)z EMuR50Tא[ʞ z;\)uzX36s7Ǭ]Sg9ohxy&@WLp:@ז?mlm*Z #x wtb{ Z{KVx?e`ouVvta;bV:2V:nw17ҁUYr{A)_?YS!8W(g, JKH7PtV/,„?s-yΤ%tȳd>tkXoiq_t- c+sβo{ҭS:륳:w QZ\&t(Ȝ'S4Wy =o+n^ԗ}?jSi= ܣ?:{D O{(9kݗW}^i3Iri-H#cBs侺޽} zksٔJ>1տ~3oyyLQh?;| {(1gL]{:<|.uHۈ5k_?zF|02~]وo#*#ăFpW Ndߍ2GSf̱17?gc̰1W '2P|Odr32GNOd=9ND渂Ecw1W是;q%l$U(XKj*xIT4ip70z e$YP%J񐏌z &M`_\\YSAs:JAU|TQ7rޢT6>3)^S{BćF㣁x,meĠe$EBZvHŒXIʖBIy4zBj/"OZ ľPf~Hمa2|oj=S/]2~׽׿o[/{/~>/9ŁR\RMZq'gF;_px3gw$d 1"@Ҍ$0kɰQTѰ~%Q;gn=Y_;So ʱ%a*%I]4 e! VYL1Ww=0AmC75V(Ƹ! iﷻuQB{)Txw~a9F=5s]6@ =JbJ}~vL(do$|&=>$*"8ŬGq~J49ـ72R xy4ި'3 x㻾,(^ިgƳG^ &_Z^[4P-1.%88;g/sQ[m >G070`tMzMik0md)1uhY MԞE &U`jܚɏPU̙[; L^F ȥ)1.%apl쟍Fky՘ &m'Q=U_ƌ< v8ױvKs|}6smE CwD]u-޳ėREހ}p zQ9ބg Cm1~AۡK/ 4Nx,?{< @_L4zEW_L`!W(n>/G17@P)hsp^Ι M@r)x&)֌_$`9/eyx׋%rD'DN[U[NQXQ>""±"*y",R"<~G?12}D?3n($S|ۡ _1;AWg% iҢى7[Ƶp[`+pq*t H寷oX:'+%}HwJdL>3!<ޢ r0%_s6*K'KzDH%':K>/[$W[gS-x%S"!R^m8G Vc=un sGo7cyƌ3>Nxn7>?KtkԌtg;uf'ʌ#3g޺0®gqnHw3>i'+yqs0V~,Mv]!ỶC(Rm>ĿBLf3ُH$Í= n7hRٸ 6LO?*vn<s;ES\jYш28Q 9(-y0e嚌1ͪy/#nmUs`H^zVCKfg0$t?!X ,mbg0$t'?!m Ėag0$t?!?!ɥGX .=Z6ԟ1A(?F?p fϳXYb&.7+ oggpV՟{X~vGf͹T(kw84kKO4`coFhT첨-lFf)yݍ`ۮe&OE7ok{nf w˄0[$Ff4- I*gu8{<&**ǥ:!>Wo ު׾F/F9>@)ulv5 D)8ںL)T~qSn"byD>2k:.Yf+D)~ح՞ %xn6|NXA ԧ qfsI Q )m 8~e !cگI!Vsh6 Bh_U߹wΙ*xit _b 18$v%_ !A FC:|nmn/.nnf$:*I5 ة5+ӂ XO1aW'@k:\34b6W־Ԯ!;oI`dj?ئ`tQ/HAl@\fc V0D.Me2s`DDlL_iNׇ7A$Q,g Z CԪFnϿmaK1XN%4s-PhXΤ,-DUzPN5ממ\ -g1[D!S0͔86@z TdriNXXv OGWɖx †A%'wYQWry <뭹4 \;Bu|/:/T-ɤ$-c mvLc} "Yz6a[VcpsYfzv{h./Q\ yIQ.e {wC\Y˷4IDF/jKZl +E .򦾫zι?ƥߤOe~,h;ߚC#u6{jpicǀzg>])0i>2Ɵ9P[z6 Ie#p/LTiมh1$>(Xݥ>8z}0(qkO/d#X@ &3߽Vκw\z/ŚaUOm7BoGOV)hBQ#)?_ta$8W$A)S{κ}_.Dx$_IlZ1Ռ돰UKbQ-Dⲏ*(}Lˎp!d!' 0A"ދO38OSyAk.G>!|͵SqY5U~E+- ȃ},4.wpgi$#2ZwɞK*oQS[j&wS?wSǁ9b~ ^%Y$aJD;Y]`zZ1瘪$yxڐ^|6OIG7ق}Ns^ ړvȍvN"]XtsLjاM4c-DCWt sGhf<:b>u6e1TV߇ּkhґiPϻJ>xX-`c{e9f[\{)I`з/yg`zER/GhNnG1b+E} ouSSY~H~Ӓ|3_)g֓iڧ0Qcx[3 DDn;M58%i}h/Ɩq6i$C۰U[^$/<[86RQυ _;w-DDIL;}iIҐ P[ԉ76`;F> ZaAF` Yun eGYuCy4d}ْ}/ڱA21$6VIyhQ~EQڇ n::$fӠUjY΍`r-9;hע5+Ѻ6@VY9};՞ۊ͟Km^)kWV4_Y:ae Yx q+к?;Tehnm=rWx+ټJq8x5ޭ& M=#x#_Kj8 x1HrK [9I}+Tgiq3νy`Ȣ=jt) B2=RhXZe)EҲA]Wj]wh/ >0i1IS_fyix:%Y~ F<1MA*G[G&+Qz4;QݐaGGb{=VXX>~)$6Y4N/XoRrBVy 9FCoJձ@{+x24$Z jOm=%*W]3sv<+iTjH\yTm'6 lݹYs۳08o8)&!oXH'\g͍ޜ]1Al]vHkgjlrA}_=M_{sC(2!)Z4Vԛ%4?꽡K)!$ ,KuATP+_BSBᕅ/*>|!za|ӌķՓlN:1_^KE;Ԯ?;yKƁyljXmVwi ߥONPSlZ>/j6Mq5@VU|'k;̷Ĉ"lM{1R֗ `ꋫ4.`3x56ν9=8oS<= O B#k-|!ꆍb\fF~f`>*kwƟUm/la'wP!+a!E-RF(-.@ZO1W\SUŅw/Aq{v~p)KGJK6.}cF ŵxhir೔R\4T3{gZN9ŮIw\+NJڔqC]˩jW%}b"-T**.<竜ZXQ^R/&ґw*pRZ`Ejnv';g^j./\5yy+]Eže#'\[GvvQ嫨pU,'x32VwW,+w-).:Ha8~`x*W\gGS-nRܔ㙓LzfLQf̙d9s@Q).;]^ae?Y*b[$Z\^瑓ee*9s(Ë+4s&P*JVK*Vd6 Y~'v& .*/^65w͞9S9f89=J5#K j{UWEU4$*EW݋++.H,|p*ip-.("5eA9ubZHXu S.^;˩WHT*T.[VPٿ;V z2usrܔ7sZ~^μ<J?*GV~gUWIEz䦲-3Tbj_@'Gvn([OЪ].U]%`#)kbPU VUѤ%E4r\K R<#+Q8@.]\ T򥋫*aE-D ^LEjUPEbFp6bDwTZ=R4:&wWxtpmNJ!ڑTvj,PM1,pe.p&$ф:%թK ۋ*^b|P~u^vTU,ٸs5;Aإu(O!y2ٹ[]o߆lK#Ō;&g_\wQ8Eww[(RTU)!K A0`Sw?~Ϫ)!.l?IMK7Э!:a`AŘ{}<pPBD1mSBv?O ؝Ǭ+!s3M@Y (j#Fc~b':X7\knHqpxZߕtn#;Bt O t EpLt}/,JH^\D"%{@t //貈.mUOT._?* #н<øt*!{^u![%o` vl ? Cw@},S$]vJH]"t;rEZs|&0_aᏵM܊G:,y-X&)jDxַCF)d_+% `'fh]dN#M\aa;q.p~R [1\e(?I  +8㓕X|^>Mcg>]~ew-W@Dyg[Fp]o,ۻ'coB-;tKP!-ofx=_hT7g%~>bbpm4/ď' D|. n/[D1LkKOx>Fp_+'-c|GX⯋l!~b 8"~Iq]@y4̋Y۞;fmmoo7RKwg3 ~IcU ;#Μ_%{,O-3xs\h=M-N9exUl`뵨XH-/,(/V &ѣLJ'mik]b,vt +hw+ew/-.S[Xg'! v$/sG=2rȇ=-YhIŽc4w(x#htsd ·m1o( Y5|n+Y\S#چbY6rj?7fS(aGW>ǘ_HU&gֹs$f)9Hca\4kW勆,95S>0fۣ5̞1 U t媋u Jequ~e73#o5f͈ݬ^Nu;rF0!g73bmHl8tUb2M$D^ O41]ƣh c1achir@ "J*K Vm)Į]U< O3{® ZXMh`4VJs]e8ңe=P6'u'u4`X-( Y9UXLo*Lam\,,M7iĉ.&.4,ǥm1nE LD{g18KFR2n_1e)YPk|t8RDfT)~dh|nlve SS(`w386q"Sx>tFwH"e&,a6mr~sߜe %{2`k"彸E?Eȧ8}G#/^@_ #7m?B>""௏sm7.bw  `_!|pv=0v/F|4wq7[gr~A 2 R x㹂4x"Ӏ7; xk]2F| |ot1Wiy,7{5'i7E#|O~o_Osb xM|ǀi_fF{ x)}f_a1>~OWʍ!Q|>рwesaiU?؀2^j~b7>ksF5|?܀_n0k sр7>+xĀO7 [{ Lr)^: )*88{`FC5 3kܟ0PŸ@0T 0>9t ?(p:ڄ?c҄?ʄ?C vJsx0W9lS9sxpoE+I?_~sef1?\9T|sp?Ep++ݟMRt7RtPtTtRtݟC_ݟC/CݟCwW+?(pZ*?c)?Qt>+O=g`Bm'ԓ靛ɔutJ~/?Q:(uڍ|lޥXsL~A «>el`7[mvgjR<6D-ۘfox[mXL,Uf3C^6KWoQ,/ÞDjਡbWM(^mmп뾶VO|C}mC vܿ~ܿ˃ ¯qNl VֱԂkB>3}mXܦWԋsǽV¼ƧNߕ ڇ̩NJ˴^0Y~>:%pjȸ2vﰱ?ftZw l__A{ʊ; ,G{-wiytӃv3?G[#9,en䱬ײmaCP&bX.ܡ3~sm9+(-D]z+u/`/1 ^C1U0473Kr G֏  ra LUwLv,י|h:8VIqyjP{$0ۼ}vuyj&ťc<8ԩ`hնaY7Nc$M[ۅhwT`\CM`.,b=1][{Z9G4zy]{=-%mN'6kv7Q^3G!cͣh*~ [&[U ^p&?:֥36ۘ=NPڎVC.id9{zN^$nCEx; m[?G牰,-bXyg;e_X>0}JbI~TmX@DzM$@̯V|\2ϙU7б9|UO{?uyٳiv݈= <@yk)aQG]Ž)gOоI>:Qzbhwp 79i&+|'㬔g!({nZhEj[kP<΍SwCi|0KD:37toVP_hbڙHz\G=~Hc8{go҄I8g5Y}] 8 .>(fN$1čg 3^sjۜ`ᬋ,*ޫr#zk/fkn,ZFTo`[{@H9QţNDb^_Qsoo!I-̿å?oNRֲg I$Ig\L}%jl > nm; ڳֱ-cح~okrY1{8wL,ew*޾}qpT6nG; ?B0:l0s  qw*&V;Xӣ5 O[t =|%y 8&2UCghl )hQ_1}\puDOsUl_?ֿ'Q[̽:*P_\l@&8orR4Mxj. LqC˛K&`0a-Oz2{3"BP*;~.}78z Fr kruaj}L'v,[H z|k?Mb0_{?^v;跛~3? ؄x^FR=e=Vz;`)s/#9-7tcFl<\%+G=iքuFMɞMh 18Vx¸zGy"Өy0]}v$2jLkb_*7/%PSFؼ''yX,$A_odoCu?nf^$h&DHLH[!#!;.17`wb'l)ڛQ5}2kem,EvA_KҼɉoxoŸ܌/s !nh%E>"N|ud+7{rNRuCv [3^s"yLwg2yyDy?Cz2ܼͧ6d lݪ~&d$v⫽5gԮɵglgNZ/vz¬fݔOu2& <60 kS({kjwv LMĂ7 B*Ch1SCmAhK/VDm".WoZ<7o[|4XH j\{?U0LJWk4elI_6FZWj Ѐg-Ȋa4= I'Λ绢Iİ-f{ŴSrNx6(x)߇`aK#ƅ=0g пy#IW=K:9O xw70v6U}^"49o;كSGtM(O`~}.u&6{N-%+;_>~Y}I@^5ie[eM)Dr_wh6Uu艇=e[ҏX}ye/@"gzSS(Ÿ_ $*}M ~Bk "[h7߳c*oO[>Q}?4k(/;{ |y2cCIhgyH`6y}.WАtVhӦ%eԡKe2G zN.0xwy _NjUΎX&ߚS]H(q|Wh>ccɶe+B#G*xjǑN;*PB5/ چ٦̋-mih3ᲂc._l,8lsLt-ϚXȫE}ކu)y wnSWiMA`|taE{aٙ=hVywx hHļ@;9~>w iTL73BHE_ }5\pWÿW[\p_E 5?px`ZeKkc 3 LK<y)tQ$uFC;=vhE )t Oau>JHaR'x OPx~mW9mqwAAm"qjB K9jnδ[ƿȔ'!\'\IȜ>6nmlC:ѫW;8 ?3lti 5Qk$O2"{k%oiI`Q>^3I>!_;," ־.(:HƄgv¬.dmXDSߞdOр:_ xi|h-vf$$)Qay>ܰ@M"|)'?cr8_~COof߯P:Y>ƯFMQMKؐUkʆiLEG?Pr_CP&y>_QU`+qMdC!<>$~?OxBNoR|&饼0A/;gnC<޾]]J__Lҟ">DG)^a5IT DDOpa3E9ux].^ڄݷ "ʽz'%水 ɽܻJ "%>78KM"^D0(mcH[Ft>?$g,PLAl#n향+/iz+Kv06}D8DcE8UDX"¥"\-‡E7UKv0(_CD8VSE8O%"\*"|XOp[Eac{E8DcE8UDX"¥"\-‡E7UKv02.@wrVo,e+dǒ,6 l+d'. >p[LVQ%#!mHku2hIoEBLzw PX~Fll %4i%sP |\d,$Hy_mdxvtՒIo>p%Z-DaEWOKz~.0v[__H&ҟt-CV9<"p7Zҟ%BǛv&%䗎_ Ooa@%Sg=].wX aiWL/KK.ܩ^ ;,z9[kOXov6agQ 7EE)fT~%p=yuПF5^5BH|Vcϧ_BKY |jGf]}2cyȌ >?9oy3]^6{֌O=3^2{njOi J=`_&|>n}T3:+JGV|Y~,?R+-x[7+_>% [hmO%)܏_6E6 \Gw~Yzz\JCء=!𚥾P̛}pNPb'd.wd3l_NK} L|Δx\ϗp~&8Sw|.xFhՂ>M)DFL2i /J|eE>_qq][=h]MB_9-=Q¯YZ:?OF"B%׈r"%~wWQGG}Y4Oi՟_:1>2Ms-BFm+7-,@igm>__f?QC?.9#ϊ@Fq\(~Y|C;#࿊?*WĈq'A>I $Aؗ~^LU~E dsu':M >ק1B>L$)@ c#Y.gFϋ_o ~fvg^~:~P`,fP>A$|_!ʵ귓Eq9Ć\{qJ.+WI%"Gļ#l4A/lM _̸_~E'?.?| 8^ (;_# _~CȃB?t\zEo%z+ӈ2;C.A ]H8@?IxPԑF@~T+E\qsjK5V1*LQx ;ť&sἨvumkBV1fVzAuœ$k.65t}j όX{A-|LS^&EQgV'H^WCI.g0W6naelq'̥[q+5:䧕?K!]9l(A!w!O8IlZFyt<[NBIy6Wgg?ua6/Ӥ\$), *OKuV?%8*p->&l*:[&o`0TF cbȺ/c5+ ?j Yv \>]Xm{dA߲8j}ϳ|Ŀ.<-fZzhQxo5os;AEL x*]G8(4'zünd`;`ӢmhѧN{Eܡ1@7?np/̳Z RaWcPh9 S@,˒&Juޓ62j#U~ 6a`8X7 LSD@cEXD2&@)[cBTOI٢*8rhi0bkf=Ѭ7I,dac`rˍaJy27>ʭeȴӰg-n9S!r- 'TD@AOt1C6s~W:[xM߅ܠODM. MD3Tr`4D-dm̠UzlUR5=.Dt Q9^?"m\xlrVʗv4K"p>X U҉;$ (fvnqY£H.Pr#kۃ͚%ނXk0W+(4}l7Z%  E:Rh:^ y:,$n1ĉ8ՇbR,ֽ%D|#f 2 /g 7AC2ʤX̠h-Jc7G2vWdG?rKD+$pw'U3&1)=#NHxb LGy-yRm|J_e/\̳9sKK-X ,ŠO VZb6>l~ݨ:)^u?^lkmI$4"!kQQΎ* ]dH9M8h*7+L{3.:8RTI8qwT~iIxYb"?xv~|}8C'w|DOŇst=gUQËމjoI9i?4= ]KǖD]Fhz`ZQbt(cΣt*}0da/Bmxy;wx/d"X3(O1Z^xǛEO$v4[G>l +7ٹSß[q,3Kk ^k'0$JLƝ$W{qgڛqov ؤ#CPzxNFf8g_GCkf3O;:૰^}ꠊlYxk#2_d1,Õ.zR|6^_fӋ`py~?;mU1v#ZܳS*,6k@kz=i@+Š^A߰iqma+^?F6x߅>/iʸE0*C!mQݣ_8ly~2%;|rwg܀쇟Uo7k|dSRݴT{=-Gy{Z\$ ,ZD#)}؄{5>O^b&sLeP (]Yd;^4 "Ւ{a>anGuŅ\WYJcRn4̊3b>̦Q/YYٗv0YTۺT :~s%LU|:qW" 'O 3΃[V2<"3&Pؙ؝G|x@GA9S4_bb>!oU=I8͊xK3|O~ńPy>)&i+(}tmFWX\HtTjfxrEr4U(  zd,eٷnvaN?]n"@;<9zzbUn- yE#`M.V[r|e4FL A,$aR:D_sM(|7O_txo=t9jPJpȭ) ]EiHqsׂd),o'<Ν17_Gv`,(Z'굦)N3\4L!Øau, n'P]$8JK,nT3&+LŅ`΄HCK?)4Bl#<@Q"6%iUoJCYY2RnDlR;{Tk*#DXV29Akfp kAE,YZ~[X G,4.~AyЈpZm^뷮Azmwlo5˜k%uÚ8:Pp[;GAMq\?׌kɈ;ʻ goEّ |#B&EϚ8%B*i4~"avKk&3xE'TPۘ8'  0_Z,9CG_V Y" OfL<DI3ذnj9ZbFl&h1S2f>x"u䝯 3x-GWXk10ra8#/1=o,o8TX&"hf^c\ٓ `p! Y+'6%EE"Gp֦+FCb |zwcYF*2xK7b:>-ȀOk+ (a5$BuPIH kK:l#Ze^&6͆F1HDfpPh'GkfAǡWK ]Oi|SdGڣDJPYOWҠb%iS{|1&_q1Si}:)rRh#*<6}銚HzmapP7B[Jڣ<GR]G]ZDQxaM @[9\=pR"Ni+y5‘@+X<5 X;E Cׁ:l!a@=\;Q"԰w1;Bmz(*"P_P7l8ehtz^bU` $ctPwqѿ80#ůMȚ6V"g" T[>ORm8N7OвiLufUb(ڭ@ CDt*q!2d-&Z\x1*:6JƤͮRorITFn.2< /SQ0XglTB߲y7xޱD/3hT(иd8 = w_zCj|+aD6+P=g#!Y f(L1 (zMj^t7A[TV[ZqƨǏc73#~2::{2йFM+B,?f%Ԧ|]DN:u4MH-(3Q%Dy#SP#BNku=EՆxip wiRvK~=BN='/s,UilL&H6C+>Ƒ"s80-ј%'y~[E;dɩpgmgܿ0 (\FfZtOJZa3FD7xT{ .Xڞ=5$#s5i̝{hz;JMT,^ݓlf9L|F{)FfH1{3yL.ܥ=?C*.\k"HLev\qZOyn!:;,]Ans4~ IĵӦ/VϐčL. BXq̬cR3@M>b ?4eL$N/_ķp9 V/ erg_RH: zdh.:h "EF_""J2`M>nABܡZ`"hg+2a-4 =|l-nf X;,>]!00 B?ک %,tUrKҝh5޶[`驔8ฐN\Q"zB'z&86G"ilj39t6M\bϪl[/ tQ0 #@ ƪݼ()PC]Pa6rI 썇Lbkl3ߖ(ѝ.V,1ਬqH xyG:m DP[N^tCơeJyM*.xarͣ8O7u4xa%~ U[8ϛ:.K5c{fY=zzXRNd" Re[z֮Y}=;⿼-Xg궶wv?=98eN[?dG]m7 6u~lr_} ?&E&EU o?tӌdή?og0aԚ.|n7ѽ?ɖW^}p낀KrA\ׯ{n) ط@sjZs\y 5hjx:0i|83A!7p2_c^Zl-.п.s(׏LW6mNw'So=-hi#PP0X ԅ!vM?K#fװ*=3ԁG?U!KjJQeO ȒZEڡ T&U "Qb-+g*(&{7 Z J6 *'ڢ5Pu6K IFK_q :F1**=.vS^猏u;tr9mk^c%Jb{)@Wq|Y^g906p !knvUQ wϡAv|0Yl3QX5A%O)ϮQޠSj=N CI) E讻@zD'<42{ș:'a`B%b"ѴtH=ehK;^&5LGr0jHQYvEj@M8*'?vJ_:IFf l8hV1|VISBB0Do9b? ;Ӓp!J%9qd1/&2J[0E&e90d)35԰WLH v`X#Lǹ;p,䓂\ylS5got!%=< !e,Y4넧lrʱOdm3h1 ]j`"^ b3 8 Pj$U5h0bS[Aw uP_Q>tEk9w\"ޢ|Ou=DBW9X~ !HUg~߇e^ZPb(„gt'E^^(&cmVd|X-HgvdyD(_z]mwpD"F{6E #Zl"0T{Xdjpq0˿b`E)LGYegSbf:+W Kk7/#16O% M꿒0!嚫h39&pxHn~c&ZVV&NDu l _5*1|)a1j 6p'FpN%20[K>ĸ600qwڢlr0$ѯ/0fPKfɢe,nI{Lc8G YŠk`5ߖyRLRV .*+d &A6Fq8n8%H鬒6́e]V3!r?6]e|}QF. )o@㽐fJ5S_~ !\<(`2FqDbuL\$TP2\Π>$H%cp,h@yh ;X4?[9!+\7\$wX%rglE. 2TS.PB\EAѶC/-H4hK~GSL C|y;I3yjֶF wMdܔ\b?JM#V2<4hW! 8&\22&lJUv_0`.1t$pS !wwzYw-;%޾Y bq:Ԍ ¨^Z ZՍn+Hrq>R}qUsmdTὬ;n'3ׇl2pT'/x 3W9up_ xZߛMlR>pǰnCu@M8V>,lkٜ8ŞVs"q50(!=غ7[`n"r1mLAi6F7zF,( IcIO=#_a#V]p*5," ӈ Ҡ؋ =*|b|<5n Rcd5qJ < 60ʳh2cNv[h e~2b|#H^k2k_SDXFBvH ] g@FV(2~jAX-jsGHv:l[I^[O0d9e=7ApUvzMg ~@J"ʶQ8"BXܩ;M>5ۆ"}iKݔbU CZ;BC=ή2}+E MXF[2< 1% mS8CXiFf~xƍd1!^1^.('q PSuϷ!V ~X#$f  sl4,;v"r!P$o,ehF(5`3{^F@ǚu]:f: Y񬡳ccPԳ]u | >|!CϢu5{㻀8S"iM|dSvJfG61(@LpP=nc#k=Wvx*Mq-#oǁ6|`3h.-|ԇ;尺?/w>7!+x[ | #s>͇GGm z-hto#|TrB0> lT$;*NvV_OqݞD x9-tOed34~d7Y2x\3ZƨwߎMfxo \F#j[Ns=Φv~`~O}?~E^ڠ6q5sfپ i;z&yQJ*4V2(1{IMQ`ʨ\O!* ƫO$N藾6c!hDO~gt:JQA>h㋬ 6+-Z)Υٌ-5.fɏy%E0N{G;Ú!?]eQeޔ+cQq0]y_6Yc_9jÌ;"a7 FF{|%c|cDY;NiR|QrM]$[s.lfmPL_`+)ufTlN;f\-LɼJ; @>nђ+*ņĝeB1 E!cyY >w{.?+{x1: WS0d̽m̲al1|rRxe{x ~Ȗ-O῰^ 3ԝZ..?>.T$@oɕC3SV QaR\{ Wiɢ4LNݜ`Nu-N{XDHZe%*QY;0mODz$YyHH9%cSxR2՜7&"[$ba,բ7S_D[ P\BŖZEǸ,H/΍7ĈX rM!9BEijz.UVBN@f2IE8$BbUslatwBfIqU@;{v86֞I:0*Tˢzw垟 [:J>LEO/{\ǏķآtQ⣴.֫D"oMIҨ5/B7]3>j, {_ߦ؞o`zfv(`Fu"WGQ=Re < :]&i*d5aχ`T/oM;ʛ~~f~5+f\ z,ݴahV*FiTrF *ijelA&/R%™8uY".}댻c¨,WjG&^:T8"5c ڔ줶<#"8\a l.-tp@- 譸9Cqrkcl#v00im %, :6#=AKZU@[yU`}Bs)'"큀Y7L ~:Z̢؄wd/6ɒ I3N*CQBZP8Ot"2l\+ћ\l} x D*X6ż}5aI)c,sSGg\(tγ% &89ڭ_g'c 5I8 +4`!6jq!X,`&0U)0aB'fZ!Bģ%ut!`9Dč/] Qsր븶|鼡σ'Z ˶V3t+yrLЎ$Hֵ8v츘2S:NkAE*V+KDځ .;˟KIvk2R/j~ "NM&S-TϣyF)80iU(@RWG3ԧfxW\HZ/#^DU΢/Ԃ#ڬ}9H:OPP8:;זtz.k*AkV#+_K ߥ:͹o3!!l>e&nwy;Ӏ84] 4Y3W\iD;zfJ̑j yʦ@L xaxJS pޚ|V G $4Z_ "[|| p}#ޙ;QlID.+s&zQ71m|+ !B|^ouRۘ z0{"m3%EGܐ#xBu)EcWUʟ}˝-!m|݊P|b87Xgz=^lq/x:Rÿ(edI#ƆB.5sBA\A%"S"c?rYP|B6}xyғ /ޜ̶Gt9z1- k0dK].*L=`f3x:V{(\:+*%-GfWLt^ AˮܾQᦵK>-rf1~eU3Ak5=|OC5>g!Q1`9W 9Er'41,YaN܆ ds`IQ o\VnRHAL[9k#{jEm%k%H+l9ܐiw8Xr\|wA93 ;B EC}.fC>+eH_'yt+R" 5~h2M!p,Ф+mGpcYǰ=,wD9~M&H|}ty!n z( Qx$UMA($y3,5R/mi_T໎Ab?GV Z`v}ZY $e<[TX0P:XmX3H)34}A9p-_^Q]b޳fL cZ'gSQ(2zJq2ǡ8+4?yz)W+K5,C5'Wk# 3J*.pK`X]ӂs^ DKIm cg2A $ϪWJw (cD:tّrM IT#IKL$s/┻__:ʾkDP|ÚD4LijEE7mV3XCF$-zżP C7r(g o/Shuܱ=)Ll30'bV4~a2ehv&Do҅/<(ԅ Mu+j)8 %fD#?0ӮEPlNT,;:A2$J Lм\Q 1wNIe̒3<ֽ^]:MkgJAtdĤ*%8@ #5"Yg ^>T[1Ar0R!֦XZ^k9°ĝ׌qq/I稥y{ao!3y!.l*/37'ܢwBage߁=.K6NiJcfm/&'Io'x𽺈QRX񁓩OwA<=va. BӀ /Vhxv}Ν%>[L *Zp/kL)z̗Ǧ<8AD2"W5Ao_ !M G_B w{1w%'QC m)ՋX",rW"K^fdtVG5$]?ςQSPĂL0g,$1ס#6H8.q2Q]'hish8"QCu_jed#O|٣C-5`$ S#9y^n R2 x5h@x j]b!pc_N< UBqe\Kgl,1܆кIhLk.L67- #4|&w8葐9aKAes-j--LXnpA#Zn1ER1/Qf^p#+x֦ _}i! QIi8˵%."/ec]leNQ!y^{Ȅ$4jJ}- ILjy\G7ϐ,h;?]]5hOy6y|] TKP|B :0'VkٗDP[1bH YeK8ppku*%^:]6]!4ďԩbq\:pn,73Dm+[ 4[;N $-iUazzC˗C@ -f<Q > hnZMrD+%=mP(`.,gpN5)ّ:YJ=D8qMxHH.kmZ_)d=D6TO"PG}ࢎ+H?"z3^՚:]NC`@!o#аOCl+M%0.bK=jx,hZ2$ ${!),^tj:lv;r/ >O!Xf&oװ9<8Y ZyKϦM&Kl41̐ߵxc:mԋJFr(d͓zȅQ06ZT f5a}QNmA8cs G+9PAL,49M\A7V,uI3|:'wQPNbs )W}3Hw܆Բt=s k~lqB㘇ͥ-%.ydҴ*'\ v/[iHu/q ])ejp$i!8$˺9!. M1K2jG9F&q"CfNl)ʥ͐nXY⺠K>x2u(Nr"Lty5ZnQ?\OR:!5#!"TG "@dbrZu)į0hE2_""o.B}e 1Jx ;^6P1rhеaUjk͖8yR5?<3U)eKf0w/al4C n-ǂfx̨tű(b$S-[aQZ%r h-ϣ$j'#!K>\P/&!H +-wGrAMt.iwZGqɡB3SLU8\T r9gkF|Zr&..DDE] uSkp/bBhBz,Cax5(_-kX`J6RkVΡ]0OK l4*s(LRـDkִw"ьcK$n&"`T ETuPUeE(|GBɚFA,&Uqm,uf_#ô/\tl)#r4U [bZ/{xcC0}$Uo{ˌqBi4xv%h)=4.in|@c5˿pEgн5NF+9{e.6l'p#KOyu$$!?`9vV\ /ĹTrD3cIf-+\)mGcbW"4z!Ohq6 )Pj!8!r GRT Vt _-/ƼJ˅qR@$Ky'pL(4诉dPRm[6HɎ LP.AcIYиT*8XboE'TdVB-oRqvU-;3ZV "q '1o&Ek#GK! \ AHjV፣. d&_\ڛkb3 7U/v 630B0XNFddD?1gpxsD©:#]CleR*ѐ6Q`Hh!NkBŞ SGhE'&C|:clY1@ Iua5ɟȮ=tE,0`žO:=/ њ ` EȡG[h~p*[{hES\_^WuduPqA] -~8 * mT<_X|P 3f^,ۼ[ mHg+/{UY4\.wg=yǫ; 0̩ xoK2htL]eX$RX(P#o}Ji&,c3#b` G`\+f$3L;=3@j{GWbpv=Q>!B` 9-Q @X8G ,C޿Z5S~' tހaw4‰hޜ4~f3 ?Bo/:/@t^c&> y0vB" bL`SB{ ,o|2lwgA14i@:(ڧXOKg* .ah]EP {- ~]2"dTCup~gk]E#ӃQ^XY5?MAY"4p7>AψM9O |=lt~s")?;U꒖S*N!HN9)MV*MRNj؅}/Izr oGCh" 5SC34R3)-)Y+H7B־ZccTȦwMq8\\?Kt&_M՞%yxx%n'"cKMQ5FHhs1u9=tQ ⯱ކPó4淵;ߙw(qdOD 1TI#oHth|e]dIJ;j12+'ӣk0׈"oqή Ak )e'6}3#ѷ+ ;( OF°,u-(gIS*Bhv0xawmM+ uM~nF:&ܑdY9'y9i)ưxI$2f!r?q e׫]ez\Կy[(U'zȞZ.lJ FV ӻE~XHO^Ҥ4L2yVNeL 8]lZ̗bK$K̕0(nq+oܖ3qTg $UHnlJ˦jhiwF+ȏʩ:)U6Ya>RJEw9vt,bq杽q DʤBId $Xq0]4kpƒ!/YUy2# sP~&h,⹱wwdvS6Z.=gFBD")31D?JvX "1y ʓ,T:H Šux y]KfLTbj?8-ÎK(aX < PFVhlt@&]{!.&QC9HKCp|=`TUj[ AAgpQyrvK#2-lbħG@ 8lyjJkd8\t BQ舁*J_K70G̮q#/39휒yGd]*]?ȥ43|>atj~kbؐ8u+2ygN#/lڴ 1Si--Ek(Ao?Zƪ' 4R0m+'DاF^ Z[.\헰;Nw>A=xZwww~>?kS}>LS݃=s޳SʗSΟ)Skۻۻj_>4^GyҤɧ8yK9r@GuA9KLG-b_4u.|D^*'B ^l|ȁƛ 9$ϕQ1ҐJuR& sSH$f,(5v8V4zsVBBߜ@DPv\Ƙ26KgB1%g dS9 ( xWUP;i b3 _`+rkiIrx)`)eXɝD8+p J)'\0X,5%`"1u-1KY%)5Lyʮ?7빀7u'aU)08Ү/rS)XD DsD4w$$e$ Y[3@j4K@O.ӳSI: LAŽCT 8XY:u+*T_O>ϴq* Ɂ dvD$LrC[((w:4=?wl}Uk|~>:;1f2̘wDߢ\LXd6K~Vʻ~>\_qæ" KX&?Ag*Q{2`}v_{~^RTQӢbxc Yu:G%X;zYKoϬ[dւ1u]+ǰدwl١8-AKǡl *+i9 {p)s$lY磍5ڬS+ 9,}{F5}[ZHt c=U8fƄz{'ZbEK[ O@WLM3Ыn-E h[p 7':5. #@)Hh2G*ZD-lA~_\ٹiwZ I4C&q rfWRJ=eu_T'OVS/?xsrx5퀨Zy zEVF5s쨁oHUeH j5ԠiJ lꑶԠjL$ҍw)E'ٽgO qǛ_1W9?<OQ?e+*A+xhb ?N|:ޟ; иgRD⩯>?}/O\-yQy}mdk_a1V;ZV: 6:#/TF^4*Y" sk XK>@lG{@/#m(`/& /PkE8`#jj!V(*HD8paww4)BU>?cn]gϸjpgRB)t^cֿc&8s͚;g'9 N{bk٠>|}?e[7F }0AG*xY5h >dC_X d u{?riXDK>jka q!NHab'5öw5v"QSN9G(m*ݎ_I[MZ[k#Hwmܭ>*\%FFD]D*5n$'9CE뭞&'HykO h ["ڳO uQm-eT[иhY5I0V$'ܦV"=r2G$XzhxZǺ4ҹqsR8y\~UX±KiBIrihrdbw ʨ9dc8JD1=ausbɁu@lsξSDix~GEmYCOC?/ 4O<]|7R  /V gBM;1FبΘ'!nI 3<֔r:R.wuLc%f~~$t"g82?n+L;'x*!a]hJPz\ч,d :䔓rŔb`'N X}!o\BXycTBMPݱ1N}u#؟8it(t8աu)[1ȩrM:$6"N0n;V+ ťj*$] `QELՁ%2.61Rui78c#c'E@-y#dfg4+pVqêhN ӫ\Vۘ3Er-KQFf}ax٘>gaVrv׵δ GമiLHGe"qa<גrte). G^_p6](uL9K#Z#Sa) Ҟ fȦN'6.E&E "TV{mZY1cySwTOocYshMZ"&>gJrb )D,?RѠ.Sal_9JՋҵ%@E ۝jy랬Sl_xoG θ_lEɵ}Kd<NuZ=D˒눀rSBF HJPsa@F "0OAd ES~QWDNJ5- [Ko Nĩ2]SSaV/.ln4"ѕV~u::&r»(ZvG䰙:wI4hkt~[8h˩$'"֝"i_$8tOqQVRTV7@*oPt-P0>{ ~كQ ) $t>5krIBP29$cdFS4b hei:eG;t 1d`w)1yرIIJI{wpk KǞٶCvkwX&R7 .D[E#?NRKr|ݻB_0MV`j ŚmnX@&RX")%Rϫއ_(@)ȇֱl(j:NQyM]1~l[w76GDW2I:e&%;i6d= C΂{6jv0T͋P /X:]ƣr1+eT^ kFqљh-ԁqKOPʃS' 6!(u'cw#ȚLl]ζYE@<uFU\bϪ6pHAl=qRlt0%E OQ0Л<$=>Pq4.FKCCv9S8zuz~yvFK<Y  'xhĒ#RoFLaxJ1̆R )Cid6C>=Ay YbQڙ+T.6JT*Jbmo"CmM.X mԾ\ 2Q"'bL9;D3(нu;Zhn^,~Q1r'ݨ((r4ѦPܣ4;> ߋutR|bem h% hOXѦֈmi37eYW`gURl7A6nxC5DKM3Gf@{Q&IlaĶJpc[&4&1a@{P(lnD?ea;M”d&N<6]HVƦ<RZIoy0P=|eW{,9sYE#ٵ1&3'od&7 &$ yMM, xi`Hfw?;k>Q6 SXiƹ[ofC]FTiRnZrs\z~{"lz&ֱi+{w6U׈^Bz-v3-t3lllllll´O̾O]o_Cm:ՆsvhGoO(꭪wa!\H;mP`uXu U wI =IZ,D:Z븅81t.\Sx)[C!BT)n^`q18DM;l˪)?J5 8Z]TR3L`z]ze&JQ.1c$W^PI{) Ej165<IlG.|,} mڼD0E.j48✾\j@2J?^)F䈗.^ho'Cizk *oXY e 9lkׄ ' L $aHO]Y.\jrpæaO W3+nf?78 =f̞&͞83DJH'.,YFh( S|3p*vⓄ,Pb짤d:IC !"F2+hzUXHۑ@P.f!C0pKc1ѥϐy&w&d6_TOVY;.)Lq&KF6hu|fNJ Q(ŕι4H9g435I &_q9.9eTMEz.s$8T\('9Fi>.Ȧ]u?g.[;1eX\:jTN\y͛,dT\WB@(/eul,:g#Còsr'ɝ7:S;:N|sL1fQn833}5xE2sR3G嘅9Ekx Vx`U'5+aq["R*>9,/W" ahfGRNKMc"Ϡ~.℅z;pD AH}޷FzNOK7A/f) -\PB(.Fch'oL)GGtN~6~Q)Y&HG M[4S_eIiQTXbA;:1[NvRelq$M(`TakܯϽ1+A"j@=!^?P0j`3%SKFO #~c?v*s8}5W>\r2%=1-n S-dqJ湀%(__gE%)` cnI kbA-gQKLaψcZ2dNh)̟?%0FKa-3Zg A?ay4~Oa?#)0"9ݝ2zJKfYYR].~=67t]ҋ @-\0[A^=9A"V W)Vw6**(bHRf֮nS _P1U2=y; @CHQMGuvʭkΊ^MǛѪyEi"U !h|ir-ͼ% kGk(f by+)ů'[TLVO^*rT{T=84. O7 y!&TM #p"7&6H72kk='Bl %:w#hDe$,ĠUYe,-[,fOqdʸ/W@eOoL^\T:_ 5XȩJG9} "/I|"c(_`.yp☝d4X)K¥ݑrR:c*ժ<1Wy''=+.Z uޥ0Y!'&3Rށ {!Q=wbTBWT^o+_yimo&1%TxVT}o0 V *Ajr݅m)'RjT"eOL"z}Dk"ݹtɟ4h+R'ݥ.fxC呐,AyI(d#*#lj@$z\\\*䊽AX%l}8UylI|q,/y{!} v&~L<212Č"8RWRQx3zV\YCtJ)7E O ^q? @zX7 @Y_D3_w܀;_Qw~!rx?^dEfZkDؤbcQLmՎ4n%qJ68)Vu8%XPd8ASc&;[qEf6%i77XܳP`HBJZ*":O@%Ql2Q4Q`S'ĪYlaH`^"NnihShcsf +ެqbB{I[ۥ0.M-VMp8E*|FS5^kye^ĕYm#VL5ʯ*hܶsmw@I3peV0@=i^.nĘJI(ʈ)y Y[oS4j1(+"WPgKRyymx**A,ѫHu>CM9 .}cB{ʃs,EF# b92 'X81 aBoR88MLE)RVT+@;YR`deD1jrchʵ#d ޸Ա)M;'ּyʘ-,n-#-%`[~h \U5?z`X4ްwHEj,͍u4}xӑ#I*1gmĨK2z#?`%Z"QaQ $&QKDA̪5WNHЪ)=x,?$ &Ϙz,*N%x"4zY9~?QiENQfH*=%e8Nl|)ѡ258Mbm 6,=5IC #"/ R ~Hu5 zՍ[tdsf*b@DI]1hЩʫΑ ,4J6n!nX^Ҵbس4dpY+^,[FbJKy^^N@E +*Q,m""Ya\~eWE)v\D}2TsUq 0 B}>Hz:ڕ%#KK,'8$@BE1@!.uscF?w5D.fD-{TG;PD@1q+t^T!;eb%?x eڊ1y%?6DK5A/D.CPН8ކt{*x1HZ!YRxtr`7gZ;AuWgpB˫򂢧lG+xV Y,=ܠ0UhrѴ VF|9TۙáL F0Oa5>D}Z4D<,BkZ(Sm{V|ORMUp{5(r-gQH0es iɝhqYW6Ԁ0YͩTݨ/! 1`pBH-j_С{H$)i\Fa&:NMaKb%_|!]찓/(%dl'N(z&m 6JUniL{KvFE'S4SCՂFC`յf1uzE:/*zIgi߰]hy4PͬY kR<_LdC5DQ7 d+|DUgjXfPi 3ݜ&P(t|o fo5LM48éjojGITV?gj#{br3YSX+MZԢN47S7N[eٺ 6̞yUx)]'{K݁OO#پV%*/ot'_Xzj d<\㪤Y0'䍵@Qzgqz>%SNRNL:: 6цt  1%U!S;0 ޢb_lͳ ndFt*gVkYB\6{XBK ѽw8ZW'_v]Qm@s@F8-QFQ?{W|23r{3|efy|^v^9_j eơ!8`K+Wl g&!9sl.ea}iR a99mBQ$GvO) qS(k,h` b4c ѡ.pYέRt|"SO_jA"stN~NQfYX:2/7KAڞ6uf49* "5ԫg GOsQ)QYz~L_0}GEL2GBaxz|i1): ff)Ҡzu]̡mpb1I0|C^VE8dp0 7ė+q*)yхyPo9L' <C~J (oBLvR~:x-!~ԔױErO7Kh-P_ &B&ϦZd@i{<3CUM"(Zl#kB:pLc2:EW˪"L(˰#))baSHYP;e[8[v5LH~]-QY1DhblZ)Y^%OwX4& U 3Yr)ɍaFX@H[b ª < L2lgG'M{Vĉ(A Y0R"s.XIgal˃)ڶuw`Έnۀ6$H]<0)k*[P7'l"ښ1l$<AG %9JKu[꼡!H晧bД*WYa"4a ? X')[#9v[Paؚ)~oUR`Ţ𯿊]Yp66Xl[a lWq=kf{V*h8f29\8[raøxI:󉎗 xx,0Tjjc hBOFKU -ULܲٯb6UƓ}÷\$>S{o&؎lGh0H t -/#b,5e Uװ'ƅױk L*nf V3&j-G,u' J*+ֶLNaj-}!NE :'*J/姊4xmh] eZ "J;x|Q҈Da&"Nwuy( T8yq;vZ|A貤g!z/pB,4f&r#]B$3 O7 NkU_Xwc\+@d.8t %qqR-CKUͽBH 9&Ӑ0?i]J`( Rr5hg[fRi|φyʯcRN:L210a -Lo<&=Y6K!v#8$f2q+(i'9#;ҪT bȩL*T֎ؐGBpSRNG%(6R!+TwN"3 \{ _01"tO^9=9%&③70|"騛rKqnA6.OWj5xbLȪ=g2/z` MBI4hD)8%7c"RD~]0uT-<(VIT27/ il4sSoL{Azy A< г|_*ղ6pް̛!NGc*c `Spyϧ`Ӑ4FPuH@)"c LNt(ç WG*s122浄%Tfo2P#>L=TYφdl=ǟ7`>UHV3]i~:p67͐DhLz }HqX quaMYi<# X߳f(2S##PV0eu%]/x@ ~'A%!kd\ pl( '\K4ՅFG:dcɿ4yz)ʜ&tc2bnnOU]N5k4C +*TATt)!\CYU m)ymLS]eK0G+OY@5؜l"'CWUr=V!~$cN ܮ{"%}B&i`!4tOCcoq!G::n 7Z=bWڄ⹍~VMe%43)02NQt NǔBR˧KLg&(,_%jGDylH=^C,=i bR`O~{=GOz'JW$]v@Qр(ضSN>4)YRe#mE\x1 ?EkJ$"Zå_j+XEy y_$/B[=UNafG>.L'JHu䝅ϗ :T>,^!P\Sd/m2_?KNDHz|EurG M6Sbo/ZGqT5&rAVgE6D;.d±ïQƼx@LfYk ĠQ*bH-874xkD*0+- Q[X i~8uvdbS//R6r KU]Gmpwƹ ;DhWj|&dCY%ܐ(*ij]a,Ee>N:P S/4lԫqx)Rk~jj>~CWg},ԧKAxdjk+D6d+hPq5 N6lΉdhQ?Y$_ιDc!27Z/!z ^VĢ46gŠ w_C T-JNb* BKJnNu ڱ)[΃1,h#ޠ ,̔dyTXN$r29P=0v9:RPIC<$p2j pR$ӳ0^w< <37AJbWLneקMfҀɋ&ņ08FCy:Ys<>Cns = l3 UzFS^s*"՛ VrZ:$Iۉ63[]%.Ch@unx-~;Ď@ /8f>c ?|:}x0AWhsS 0~=4y8_kXG h}9jdh{ c.(%ZɸiS| , :^w7+62M!K?8Nc e H<{4%E$B*T&SW:) # Ƒ1dYښdWQh(=QHPeBd@Fx4upT 5("UUDWBT_ 9\>1FwPQ! 1:F(*T %&}m5(ٟ<ȋ!sAI|e*XD%(G$2Bb?j=~1>j -<"Yu)hl k`͂dE?D[qaW) F`'G3شt-ABY<$j%j49#؊6J&#AD96L*x`CoOT,*4 ;lڣ3^2sQz꜅% (M݆TًY@6S.rZđ+QPWҠ:We1rvZ؜Be4, zurSPhe17QKT6"Ppp\⾀$Xg>qL.ab)u$7'(wsLA^vNu)(2Tz<,,*m((8y4cN.63B dxldZ/(aJ pf (gtN׊h: kwQn8L\,\'腶0\sJA)D*ظmcf*ɝV=^S\:>Ǡ.. 3sX[9Espr 3slfQROWf7,p9a  {~B)Omdf &}>)p:߅_aP?ms|bfb`-]Tm̑0#-6!,Qv9&Ws6Y\ `g[u랑UфRXE ވɖZ}HKf/{7?r9ԻWP-;$Þ6r|q*-bG oÖOsnQNXeg HvDs|%T^;Ay"0Q%:Q DYyߧD 661' ^'];H&!AslҰpPeoꢴ*H]H!K2[L$vke&nAv<`{ ]##h!P5~U xcg fKDXFIe@ajN#i% ZCaQ:R'4TkdYPCdCؖP@ goIN!2̶HÓ%vMq:3 !Zۨn7؀Ls)%[dHVݱgQm ڭ4A(T@%#XYBQ(Ԍ!ϳ,Q>Z+[O+OY0 Pj6&F#l@^cwcrf?\ilY$$d ރQ :w$~6]o]^ 4&{ h`&|KQ/JYdXKƆ܏tQ4gc΀7!<-Ǟ S ф\*k/"z`8Z@h)`tBEf@9S> Jx5aLcs5p\P5%N<j[HsJ@nB !h`*tˆe\P#.ٞ'ԩK 23EOPU= NXNa(dpb|o?yL ;1T ˁaR5{]hv6bϹxH%yU锕hpU1t0ҫ䘌bv)T!ARz^^\w4`Qg:D9}$,0#[8;\&v h'G,^بkeOUA, ?7T{Kxf]cof)}Q9Xe~.ie ӀǨweB3[LWw UpE>`F;|zk[=9ybpۂE>@X|i}GLK;p({'S,ƞWU}3"驩qչ=w X%v`(u)ȺvdHsS:56kK'\~`Q7'"FAԔ .õZ깖 (dP(6~QSvOȀaF]ۉ %Z\7sNDC P٘CP($sbv=[rɀkgؙ zcn6GaT XDފN&Wu$lrg%Wx 1UnLTĶ4xpxYOpyBZ {+è)CIROJ6C00 CEdg;ֵ~%$"LLW9㭈@[AS4rM55{:株'b:>-RWQG[ jFzj]G+-Gć hT#ěfXA׻%e E5a="3U'nd5 +Jtb5|%qNBJQIj9*dWUIdCW 0f8?ID4C2UZ眗Ou/,b8m+* ,6"Syimo&1%x!!&=.b>_P>"~"SO&'BWW];&໧|/UB%5pR ZR%i+R'ݥ.p QI xc KFNB&UG;1~'8 ӴGjGKg[QPK>2g՝}8Uy $G,JNQE"T(R;~$hPY+.ƌvtcml>]6lfcWHns"\Ĺ(Auim!V͉tJ:Rˁǥ~É |ސŨ,G1u@uT")rʑ. :v4<%`6>M2PbF q aقM[t Ympeu^])7uZ!^q?)dKޝDAĀD$^<{+0ue/m!QE.J'E(5Bxa' K@(B I)LD: I7I :tTlL}R픫ő~ ;U XL'%FAXw 2W\2(擳%!pE6햒)lA"]59ЈNl+<$sRD1qqIv0鉏ⶮJ>QM'B$J;JTo r$Sb#Y/= yKbB=h9aM.M-VMd¦?N g>yժlD_I#"!N/(Idsj ʭG?]qRfVպRS֘IMGŚVafυJՔy՚=1P pfDŸ хm83ZAW,{ymc*'O>)F=U i2xS=0׽vGqm* !@Hu>CM9 .}@*c ZA""# b92(tj|:L0k׹qDE)RVUQ\qɑw*䬦k/F(E2Fo\րئG ۃWk<ՁhZ7&%`[~h( ڪZ,%-X4 a%$ҿ"5gƊRҶ9r$ ni&CXRm)0|IFoH]w-TEEhK"˸O4$CXC+'Ȥ%}p}3Q(LD;N=oT_DЖF^/D+Lc E8ezO;B!2//xjN"=~ĸhl[I@-jY_GXO )`.`TWD:D՟mqV_,-@gT-,oCkDU;Fq䚛":MEXC\QH(\:o#:]ةe*, E,T_ϑBbB.x6Q8z5Mn5/y=eTt@l`W} @A4.T$+ U4ߪyo %.+Wz~ߓHQ[Fй*Gȸx%MC}>Hzڮpʈ%y/8.Se#&(pԢI€Hިscwubp˻Q0{]X \=IEp8@9B;źjk=UKQWz>CL']2j,$fmA/#J3VF9xҙ >F y:vl&ԕ.jPL~\FmSLG_=~r.ʓ52y4!t}qPWHic*2J2/,S9<)ht-906dn~ M_C T/gCWEDg$>-Qz(z\\O#_/H "?6g]w|;\taekfdtT|SN0K9H?#!~~-')-l4&43 Z"'Ihv@*м$451y)NhVOhK[R@>m7[\ [?o ~[ "7R@[so6L$w-o7.l|!7|@|{E7{8=,\Bu7nyC7n6Ppitz1B7 ,y3@7W 4ys1@7/Lxfso6٨f[m62v7mi8wKIo r%0-nv3Àg7 Rfnv @[ t|usGY7_T7Mlu3NIt @dK7&|tE7, tK@ ~n M S~ <+>%6 |NM;,H>a&\n?~!~ö?R=@"[OWlę BgɃt#S@LvJ$&ߔQ)ㄢyYtpj[Mc+<8nG=DMk>]e*a ^╵UGTwibh˞_J^~[ (L7 7Pa*鱙jTp 5EvZ0 @ dHҡ?$::BC ErcWYryErK *TT蒐M$)fJBQ[rc[ÈU_V0gr/$s9ꡑQy*-B3*,fV0Tl]PsI's!!5fx{diq.Kn>xJ AI6Lb#g}XFA>l BFFJǠCAQ6F3?gt^,˩H$ry)Q ៹ņub#>+DOɃ{9)G+/-M4 LM뗑q@+> /f2/+EPl kXqzH.FyC wR|^6G|a)Uf ė4"8P=LʋH( < pD'DFQ4ƍn֢G?zgRAuc|Ij$UB`V&UWP}2C:B\Y2?s3N0$Oa(&}P3RN@R3l}抙*vEPm;qYmyj͐, :*FH2L-r2?!ʹAa#5u, P+ͺH). MTO _>!Fj*⚅,+qJC}B'̶%&[Eƨ/,WȂ],^ :f#쉸4H$,Gջ¢^XgecBA!!~f 65\٪/qҨj֓wR2@50 Hm5-QOH6P 4,m^ɦ,<5ԷhjU-9ϥ=v]w>k{^esT8grXqLȬ1 EEazkhBq̪`/j|bϜ3.sNx'&N8I|bӻu>k3~)w{NseN);S/\u{W|}^<] 3G/smux]NBq&-j; ]ŗOj6`س>f_›6|m_fs{> kX3:[וҾt9=dq9~^}6 7$xK-ۂ]Ý{VmZ+aޭ.O9ȴf ~雵p ____ťVLhao}#s7y}p=N\Ͼm_)9cFO}wm~>iI1eVՓON}輶^qӱ`O<S5~NOXevק)O_|+T3fQ7+G­Þ|ÍWN{}ypꃭf]n>YW] OxpVmw[7tI}۔|}[.k+>Mm35ewOzE;tdvL3+۴I6'kE|_wCMU &pogևv|xߒgu}aK[Gp/r+&߳{7^7pתgG'8VgOiאI~VAO :zǜ w)ɺY%o6_qԏ~;׶\zcBu C7shU9X^Ye1 צp{ɝg\QaQO&|/^Uߘ=c>;qFnoߓSk se^za! .yo<5\ʫf8Ɯ^)aU5'~ry ϻ˶^GbTzf>x\/qkugmpÚ=?~!dc=N<݁Ϝ55a9nڞn]W/ؽs] +2?{썝wn\x۷>RxmYzV}4xʮq55C֝x3͕tWFMrWifoû?ͼ~S''F(ᆗLxqqPA<~?}a@n7޶aVaw:A}x>V7z)'a!מ:iv>]o%tIk?uW{f]/gݱ>2:bWOP|e뵅W9ޅ}ZwޯUki'G^rn|~ɳ*{a͎z?rȒWfn셂#/Maq 7lO[byһg;?zqm|t=O9bQ OtϯYvԲ[j]fvҎMIݓՇǾޱhWޯqZ+S٧{_7yk7g>#Okz{ tl˺z*VN9!Ո-%IÎtN|[)I~k=?<ϮylFΝk=}덙}O '|i;o=ngɟ=~*KۻǍ6U}^ɧ֟jqK>//޺ק+u?[=r' ~7uy߿ #~;ϙI 3zN8>5u=ƼүFxܘPtpҞOXa?tҟnߧnⳝ/6t 6=~E[Wp-. ps_ۮuž~j5޻y|*0yJC=;̎ۏ..䭵.4gdw}/ٹ!7ma%g<ճ}/P8ű=>Z{?tyTo?%ޭOHyuྩvY|L[,vBcmӺ/{?]Zp/^'~꥽fuo̭~ဓ\Ƕ_t6WN8,˟"4#zx[F<7;=WI;Nyzᭇ~˯[8p?ZwAm;{e5opoKOa^Ѯ;Ihͅ73\{_v|ڴzļ8k2k~a7ݕEzXuy{~A]aޮtf}EZuevl}{-ps#/̽kv?c38KKziMއ$Hn/Pe~༃7ߺG-u6\vSۍC]]/l}I;V;⢤U5>Is)G^spm?ԟo.?1/twu/ޒ屹:ON]Zom֮uȒƝvvTv/)p]~~ÿuf'a_'[.\>?:-zWvǞmwnIJwI۵ Oy -c^;dpMڝc%O=%ccNğ{>2)mvsG1~γVS^VʏGI>퇷Oxgoc^<<}N2C}b_ug]?OϜ8?z}r/dv~Moii?$|oF;-]/v-K> =lp.{OƲ#lop튱DOѻ C7.۲|\껷5[ﰿeػuۗ/8]]G[ۮq]}B΢w-X5SKz{+]NjآzvLZ7_>=nrI3oӻo<{;9;ۻ:ˋ{-M0Ś*]mfizZ8>ϓztG-< :rAEgt]V~oa+A߰_:Em[t߫ꚛJç|q˺oG_l >{a܏vӮԻw~tW~14}e[:}^pѸȱ^叿6AyΗ^U·^|=']:[NZːn#:.|'_~ę{6?i7Swҽ_Nx9a%8?ǔ|c?Kvݻ+|S_s }iϝC֜',꡹:ilu[ img?>BWd޹~ƸuT[]-'D~9Y7}{jׯ+?"qX^Bד}7{÷߸Хt_a{>sݲtXFƲ1_?>o8m&rc[g+O玛ͥMwG1A,{I\VZӣs >Ay #7}~qzތp᧬>_O4Ƌ_Vߗ[qɾRƻ=1!۷>C^z携_wqOy=܋tik>A _7yf<}هxmϹpo-_7uܙ=+ed$Gno^XUiJ'__<3n+oӋ|pyhy_hwˆv{mhó?q/w,(8wk Wo^p+}7x%kõޮcϻ'{*ߘx>r9'}wꬍv}pۛiQwrޝ#ڞx19U?raЛOA#nksN{ *y՛/09+]wo` 7=୮nܯ뻟e1{k?iӹ7:3zn~;5׈|qlk'y7 }w]YU[*_[{qE[6*l;PA{"BDŇƈֶik7[mm֥ gm]k]n7čϙ\H~_/s̙3gΝ}ayă'v^woiSʷ"'\J7r7.Wv~Hkڽ0awM=]vN+)=͞_h*RnaSN}RUN'_fhcT~ S^<VawWO,X-ejާ͝]n~n|vcuWӎOf^?ķ?K|i/x7,r*oG,I;T}sf{gϏ{ޯ8*69^oTn8>wqo6|])_vW+W=8Wp 䒗^78ۛ5qKG\TߊrB{NqvuƢ]iGuZ00i'yav}6]ש8u.O K{fэIw; zWw_:z8,a@y^7ꄯRqie[&~z'(wfOUpZE#ˉUg.oq,zە[8|Kem/m~Y%_WO^;m~>^䣍o9ԭbfbǿlGFl:gʞ\ౡ Wz=E꾯:Rk-C/~-ߴ%b +O,yjkw6?Sl2yv:'ؖ7i+ݛL;l/vMΛS>j]+-G$FճϬxC\Ϛ>_׼Y^33Yx4Mo>zѢK_u9d)U]`2/՞Oؔp%w.ϴ[ǟ^0nɱ+wW5aqh̫Luh&wngkwNi3zdڏZAϵYE7;f_rɯ^%ݷ"C엉V7޾ҭ/=6n""Ye=nI}n; v߽won{Tmu2jB˝kiom\lIjv5KC>Ĥ/{OI;?jigTߨyprrq~WCjVaBWzko53'z;g6K݆oy9g [3״Z5GfM{{#{N2/۞jM{4}"[O/ Y]qgo&-]qhѱTuK~M?͊o~3 p5_}VR&Puu7y%7Ϳl@7u樷[i=opaێf/J֨ycl罔-=> ب⠾go~W-Cj^Ll?:7^}Щ3] ߧjø{߸l`n^ǧvvəN5]h˛{L_~&Z3堧4Tz둲Uܹry}If<{?x'ޱ><A?s_軵/OYt`;߼zkӱܮ7_Sy]rUAﵟTX"}W'^lܰN/YS_Ŀ6dGϙz`фnF.O- 08ڿӶQ%~2նo.9쳀U;-5'6yrʏ]0~ўm=3|ca<^| 9筜rnζ[MJ8wdsw#u|ܨOܿ[Ɵ hx7,"+) b 5rƇrsKN?w0~f$:D듚L!Y!&DgfeԤ b$O C1#F.o0CøQqF}&EH 9ge&'&@CxDe>5a1Y  lq\F3<+8,5_|+OX;_q9~><{׸?j|gϚO;[bw}{`kWd2;r_T s2I'@#@oDdn\>p?}јB|s;2\+}n'"Kk7ߖ5 ;-j*zn&zV_B9E[=h)Ha d}H`ځ0咷~$j+v6 naY>- ~ߙſ/7Qy~M[kQ}[@} m$B߭ ܿJ_{60x08=9ǥW{qg2I<͞#?Y8Zths1)fKN|Xl5)uYtst 5N ,&;;1)=SgI=r #9ޑs9l1;=A0o\*3sesLψhdP!N?*J2hHlrKݠe [r #;Wd/Ctoyzz3z؍SN9I. [zp0 XYx80C>nL^90vz5 !;aZ a=,4cʡ O;15 A W|0os/Q36aOzfAq<*ť?@1W喂G/,5٪ ȧN/tP#D5= CT)Rp&ho)7T7-( Po؎ZHh+dg6 A\YdE^>M?^B(ssHaIғ,#Gs)aulgfrDS(\/@^ƃm.cWn|hQޔhBPB6ҡ{\7v᨞gxG2dvqp{48g}BR;&p[`o叺 %6v1EDwȃ*~zW95WDreϘ.4BPD?)e-`tخdAqFV Dtn̻(5VW# w.׋56o;~ODkRoǻn*%+ Нn;9GtGEW&ڄUKJBL8:%q?!n2o$?\s^E]m# 2e/lTV#9>YQBޗBwFe 0 ]DӇb;L7O09#c^$$o!]tm} K0 ='n_A p  Jv ;:i9GAN'qA&9;sAusO<0]K=S{+ǡ2+~p E+7h3<\9Av27.UF$&bC>Gy*e{r6f=n9uss=D {n{&F/9`a5 {D:F^7=*I<8\$&IK\TT?z.!~x:AO=D"""p,쌬YI:%r9ԥ[(7*֑ ICX5ٞ]bucI" Y̔ =Q!F]vΘfʜ2+ӍH=L=|hRv[۠]I+Θ0][1m:nɂ:h%Ԣ>-`%{ℸ,.m.;Ȏw#[Ւ-e?;o>}_!dh/nHE 4VI9V;cr l΍fx Q^ {j=^c.S9/ cI:XVvB(U4Y5-s~_-ŲQX]m|pނi BOɃsK νX(~/sg< T%SyDe| _wr^L?xvr]E7}sC^θ W5E>oti_\u~(pӧ3uʉk#~ޏ[i&f0`rB?<5 Y?Jsuisu3_:a܏4s?9 eN{α'O9řyxCgp= ɬ&UJ {iuB[D9/Dx~Dx~[/>&‹d/-‹E]+‹^|H%-Q嶾M*+;EŽsncoY `lJk)o!]dJ+cX7 ! y'W[4g8l;NvR9R>ۣ!HZ]qu᥸7֓txGToóu) ̅IQ^_5(&5WҌ*h!ZsLŀS.;Q+7LZLfy{LH\& i,4?Qx#Z H&$6L819!Uyqu)>Ō hqZzxBܞ|x)T=)IR+¾cR*Zy 8c6ȉ/,:A2s]#5<[x@fjn)gQ Z/0fVda3y'դbh |tpƈ#L7qL~q,dET? —@"&3}$Dsc9Y; YKh|b^pk&bw8Ev!~nx_lr { ^\%9JX sz KxFv-Շ 0wb9S  š@8(ȥ0 _J=3,3Y(ByC1Xha/o]edmn,dpNda* BaGDG#=($Q2ɱ kJ$K$%ti)9_kaW%B8_0Np$B]?%k!v^pm%{!c|< zD{ItMĿ0n7I8sK B9q  zJʗ?S^kB(Aa/F>s%q!~A*?Is^aIzaRU3-!"B6u5z,IjU$'8$Rs˱Hai{I.Is%B(>ʷqz)spRX4*$ UlR* I$Y?I$0Ns_9,YV{~/4KϻH/ݸWl`81H=4,dpwP# |NMxw北;}w=3>83^axow7?vSg|V?gҮל~v}onGv=oixF׳xnHqocNOMm਼7lOGxFJ߁i=a;D|vcJʝJ b=$,hGW/c$~VIw'ܭ*sQ.n7m~uoI}ʏ\Nƿ5B".Yƿ5訋|.^[ip1x[߇]'wbƿG45~xqЩ_FSrMa&ёFOI'M909}Ir+Y#!!>Iz qf a !mgØ32*wZA3_vQWR ;5?paR}:߸"k07E xo\Tldq2NfxW}?gp W}zȜGC?$x ߌ/iP6ޱNJLO(Wr޸' <#puЌ p{;~_x>5;5<7qcG]į|0/*'B8qe#/=!Iop v]x^Nߐs$Q_(~"IJ$./*ǿ.I$&7IүO8swJ~YDKI~c$%pgISR$p~Z K -$+ܪ j-;U*J5N/>?)1H08X8eC@bILB. u9t i\ eg蓍_FFV2GJN7 1΃YKgrk eB Yyy@ |sr2tb.eLh߀;4^<;rnj>sV<{:p3r^ b9 IXKgR\-*g˱3آwAa2d grz2*fOܜ%u> z ,c6SDu9X-yeS~9Of3T=QIƧJ g01 )CoI1IM!b^»l.! ( }`~8k !0as+€!,*&c4 [qL  C`30a!LnF s\.`~İ#̩>q0q1TV1*OrZ aî0b؍ð;}a mV {p6 {^ư}a0Ǖbq0wC0 yCXOaxc|zw:]9fLaFI(AiX!QpJ1tEJm/kM=(YiF K[NO`bRĥ%'0J^R}DO`ĴFLIO`̴RR"'0JjZ?QbN%7?QxR$Ր%:1+I˰.&p_%p)גGx+בGx7GG8G8I#<[I#@aH#\cwI \Eԟ?'' _aB͘cӸOr\ĴU^Z,CKbxg5dÿ:nB ]b)RH["c7n'/Зչ]$ wGhHH|oՠ9SKfH*T8;~0@O|1u![BFq&._ Vc/)WeX,rsmB4B0\ĥR0T"q9m<Zg,+@rEq'. r"#wGwD)\g"|HcNe2= UĪa2UFTjHCZ׭<(1555D8M3)o"VZ4^=.G?ӶĪ;vuV9 B,ȁsHub И"q4W+ Q B)P;XL9tDb)M49˹~CLE8٠I16I“iŋrLp"3o"x}߿ &^BkL"H'9,R=9-= j4uX+ @h7Ϯxuj+}|{kGP'iWe+ߖ,yDW~ h"amnwȈV rǎ<]$&-K8%yދ]k+UFGl?5e&W B߲ MUzi+h(56iblkP0њA6j'lrVw?s i\jy37 =-IRɾrT#RVAǭqi0N{&_h٠|e+`P\R ]d6"HEHD?Ln5HX,M}p&֛"}0}*j2>ќLf<BMMa\v\N%-@'V4'A@v})bxCz9w4Ixt*\@C {eہ3H"K"$pH8XXL 6#j*v;[Թ!qc}(gP~030>O 1^nM8MSX[okknм>HRɓAYx8[;{75dGJbu—  {  k8tz_ԥʕ3Q,>4̇9H6ҶлHYGqȏ/6XoҠCO,wΆl8՟$sǚw9C49W)ofdlYh7?ʕ@L l6㹰e]ic؋]Ā+yII%9{q>;iE*UɒA$%m S3% xh'j)#DYe^%uOkK3X'I R#ѣ:j8R P{)wEE@ǯl/TZn~FkiLqV퀢dשM(I3DvtIh"~3, 1Va&+m[m]P,7g*TЊFo3 W0aV;YyAVjq+G.g>y&.8:юw1 /e BRIyiE2pZN.1::Rqd?AT ֫ej\`ѥT)`+_6=+ 3:Ԣ(ٝTpߍVXߢ/*sVm}J3B gʲYjXh܆%T;JfQ~nF5 /{)PnoiQͫi zQSON^N@KW%%5쁤WYLth#,2gZPNk8n&{Y WF6BG" d]d<H"Eow'\o GB[y0|W.NElmV+?@]hS. )+ W(hJZTCWyD7p4bR/nl:h.L>ȃ\Gwucl Gv|Ӽz\a <[^Z[.'wU~rc0<iZ\_ }hbHS;d M&"Ou"WP59IQAϱ  !^f kO>EY~œ!M|74#: 櫭d&҉ eR9P ʨf4Dlg'}i'esO:]bMNQ7`{{T)%i%&u1zwiWr1$.[a Zz*Fg.ØXjHQp&@C`)B<Q{ ZY-ȣYԏ>%I-,=hPI+O@7pA],:DmD`-݋bU* .ڊW Xc\'&;8. M;hlIelUyj_}G#uS$L11?W2J߅G`t0j5P^]AѻGM7TշE< )Ĉ[Q\sWt2<_'z_1#>>E"}[ s8)[!#jq2,iWD暥P |X=>W8Q!ȕ06m0x/Sua7Z*1#ȸ7Wn琙~Ix/C^^Z# 1SN>P0u.9MdsdaFv3#,E#eB֩4Qy8-a6FnYbz|"0 | U,ia% o+k5f|[CE&/Š893RD?X[ 4q ު-áet9gΐmxr8iqu q2Cg,<1~3(d pgFABɋZqIᶉE8.dܒ+LZTQVԽhQ"#p *e*m fNd?9;LJY|Xqil }FQo0r}r)*1v Ȑs ;,OX!} r`&j^V>&iR ikJ7nfD\izՠYCءA RgBz*#}^QG_)!AI}.iFc HC荳r %:) MI7dg$- M r9wWIAIC8lgᑜ]dTƬ,UFւ0?dД973kAj`HJ3r29)Ԯ)ӡ[qq\V3jD7nf8.6.!pcōoB.'+EMQ@Q?7JϜxij3䑤YliMsы+=X2UYPyY9 RiAI$?Δd7tM/5a$mɓMPĘ2IPgH(/=s~RFzIEw5t7es`@T3YL07=;mˆXl\ITLʄ.Ux)\UޘJ?YEk2;zDe>8BC*tނl.dГ2rᆏ5z|#t q8-\ Fz=B>NDTP윤yԬZM^ҷxRA @ ST AO6B4j2O .P.Ԥd@`#́}56t تؤ)0rTrB< &9 8SFIƚJϜaT[:JT/i!jJ1#T{h$SQ5,*>Wu7]w@SUDS' 0p`T-HCgCuYjx<@N Y;IWCMU̙G g TT!9'=lIbx`WC l;"qa6Ͽ*|gMz^a*(m)%bAf<`R]Xa*jpOm0GgJJsQ 1]dTU4 R 5 UXI;6iXm ގ셳wA)&*)!k4fFjh!4t^R."VW}t^VdCqbklhXk̈́'';wy Y{|9m8m)tcQcp_M\nh=z!h} $D(t\_17M)Th*}r(Q^&P v@qQ\.^q8t끂\ C:|Dt+9W]iKE] =?FmD2'~HOH \)˯$?h cȾ  Bp)G$p}_m{p7O|KzThOgOx%)omX7=iIy\Iңos o~@OJ\ *_+G\/gG{H Wޓ+Qx~(KH.7I^.(/J: r2k^83%gde \#? ٧OƉtpZ,A:;#Gm h׬\Fl]~>_a9[G>OCTE?̢:r|F9thOK(45#Tt1Y~$4vsd 26K/ ?j:j˵Y\FHqkaf]]% &j̖QtdKmA~c%CUzəuDCb'Ơp$h}WX㵡olj N!tidΜ5|РmCOߤq:PhAo'w $<ߤ#Fޘ6'ֈ61wz-wvZn#'F2rNfϩ`t:Q_Q) 5qs.֚cx> RvC0V'&4ڊs=>sclFfJL+S|N!u"/tb:Fnj!:;ɔ $SDj.mcږBlUaVdx[/l@i3vۄFcblc(1ңdDP69d @ :`ZlL@Bbzۘ$FN28vʼn8w |g##2w~}#BnNP{- -Ds8o/EsNM[|w(/ ~PoJ')pN-|E~f:_AM'dV1*I}~Y0ŊB 7()B!,o5Ks,+UH 6##V΃aA {H:ٿ௷\kƞv>^uNe~`m7f\˘]oɅƋ~ z .[]3^ | 9xo|%s&>.} @2.)rA <,wA仸p-pA_ܮ.S]wAM.#]Y.]j2W"..\=9}ȪgXs/G У!|;R)p^vop؝w'6Kƒ T>qnB$ׂ<BP|@%‹sa"E/^wFuV&#‹M.fMD4^b.[ᛉ"'r^)EZA믏Dx9"kN_*·mD*^/>pNE"|/['wṧx+DN"D"J Dx9(-w"|w~(O>kfsFi"|O>[%"|"/>gEx^Z>\ ?[Ex񖋶BkHVqZuh (/m}Ak,ߣۺ",0aT̟Co5mϡ¨ ?.fԟC;Q1-&'?&#̟`(ژ?[Jc s800WQu1GF9|0*a?_ݟ>F%g.ݟÛ^F5g6ݟ&1?n9 ܎sp{a8?)w"g8?a8?wz#܅sݟC՜ݟC;rv-94A;g0A9<pgp ݟ{rv9p0gpC9?#ԟn9?/9|p! 8u,-i+HPGs|ΟaNE[P5_\6zq{gz F1B;Deu@5ז]UiM~7MԞ#~ (QDa~ךI N`IBv/sC CCb;b.NLo.1a0.>Dw1]^`f4Ux7-YҢ^ {ɣ$.`v'YT<Ր뗥W{:-Z Nm\5/#ݭenn ߏwq^ U歴bs4)H6Ҫ>%)dbv1PA `]s/烰'oBsNDm4tӠ&ۉ'wf {XUZG\= Mz4GH@Vw?CH?^u֛K{HۢN, B>6>o. _ɪ::$n@_ʛP}&՗jKGzrsNQSdz'N>'>~ܾTI;V$i}tRL~tX6Nz0=]=28&4G~ o2g_$}8*̳kT/ 鑛!Ig#">"`Ġ_,!sM=`j"tЅ<|nXkP{94_Л?'Kiu#|4f̊& #a;b pǁuϻ!bH0?Ԛ;ыĵꔒ*A۾(κ ¢ÍWr.,WH"IP~.NPt(X%SA`C1-mGb֌jDbA3Vnt 鋫 Xq|6|:|J5]Ӆ]Bsy͛(3h崤vBrX!W5cB0yq_ AWc5px@2Æ~8\ua=7 L4?Zش#eaMZ&c\/$~uEzP'q8@Y}HZKhN*:+>Fi;P*}>|&(җ >8RY.5 Ź0n @Um(k R:ӱ _yԢDɯE!|SC<~q]!P`",x@ۈ? ;dV0}LFNDÿ )Q;( 9;[MZ]2mB2 H,5C^2| tj`ByPN:uX~LZӝj̓?]ϖ^]KW EeCqkbU|_[JKbj{*_{ 0³; 6|u^G\k/cv&Hܧ6@CC]MD\ص4cxVJrG&2>ljLVaVQNZXzz{h^M0f^z݉f`sz3o@k?Ǜh̏ïx% pphxM[Ћ9 /9y}ܴ0qK3΃ĿC+Θ럂-Q$=PMw(/\矆+{HowSɯC 땫V-p[݊ :GeAN ھBB~yShjxEW"a!tCX Г/e9PXxub>> }wUc՘5 -1ގ>4U E;U;?"?E{p|b|(qxQFLkxMUWCFxURK./Jq xiF0 &v3.'k뒹(W]}pTfTRt!  $H,BWB"V(d "bJ'a]c:Ǫ0-RaBFV5({{9~{:_ڴ:;'٬3iB|zdk/<)Z'KUT VSɾ | >eGW^lԬdspD_=l³Y1a~6tE#ڔ3y7{zV:}?o|`Nvb(HUOƗlbJ`W6`>''xpHPv {rG*ǟ仳C`88jSy9>-[_|c?O2 F`p?Z{55\6sNkO &&fE5LEAylBy '4;0/>!ZRMc@T=ȷ5lA5Ns.uMD]^%zAq Mͷ<ߵҴV V 9kZYä4\hJa8h\kJ6r7*S`w )!nЀTk#+.FVϟRwZ7_37ޖ펊IuM/B1#PCm{xW 6h,`_Ӟ`A3Q` BZ.:+Bug>- i-(*uRךO|#*  p {GjHp5$\ Wh| _C{׀W{4֪Aִx,j ,1e/ǀ\ 29؃өi,jQs@Ľ!Y>g>{ Ȳ4m/ȃk׈wkZG Aox k@nk w< 3265=Ԉ;@}izOrȬ^H2'U⭨8dijQ]s)wg̼f\c[52p{SySx{!ԦMɛ#0\,@f9x>!1= ڃO26"{I?H˃6Cn 7Ȳ]  ߇T9ǒ797'a91_),sώ+&?i;;60k= Oj ڱÁߓkڝrnw΀~$xwih@+|)-v" ?Fn Ŕ S26CTt}lh_opo0Od|]g#J8#p3P~x$~ (OE?DbKAX3p)ܿ@n":>w>V^{?؜> }Wf6BZ])$s(<3; B;IL'Ζ{#g)sE]ř t?G\Z(H鉳7iZ⌌d8C`<;~ tx!,Hz kaJR!G. ŤѵnnW\ α!jN$S=\^Gr$B$\Br-F|N$$K2?Or$B$\Br-F|N$$K2uOr$B$\Br-F|N$$K2U"\MgU:YUrfgbXI!]y0Ή^I?Y6a$}9>>6 ^!ٟ$I#O់iB)Uے @?QR|1D(ϛb<#36oÛg)J|FN8 Insc=tu|^zOҗߪ_;o^;o_:N)KI aq'x}5D 0Te? x)2Sbvbkq.h__C8\e %9Fa~r).:i*ޞ?O_w/3 ?M1 ⏖py.K]ƾk /d~>==\VK&W|jƓyҌ;ό'O+3Cf(6Mx>nx|T3.ϊ M3O'ۏ[++%<@C|ydK[(g.y veS7(<\ɞsdA9z|  z#NtmQ3ME鷏[ȉŘ6s s.pp6U&;+N'_< ٳFQ'FF%oϛmy?E{~Dy#L~_Al| dowm6'6yܝoиz_R)!}`?OFΗl*OuHvn˵&wlN)Sol6< w'CmE6C6Eg6՛o˩*/[tl 񾤋YE1hMӸJJPS<»iٚ@JҬL6lg/O?Dg4C hIhw?jcˆG/`x~&Y.ō;/iQ~qK*3U"{!3("qfA;p<$؂՞?1(ꠑSe*E7PqZQ9y&ZJdZQf51*2Q1 jȎ*QjLȌbQdm_ݪ̏6Sʼz{[@q$Yőm"jz,e3C-3Abfqʄ-xXͤ<}2IYW̬&&V;U8YBĘvaܸiXeZV0}ZRwc.u*|t_xUcT-[[zK'WU+V㗵ߑ /_"!6sscU/L^F0{Gz:Jz˦~pm3O<ܗr]ͨ`©NW{w47\ K|םw% 0o,X# EJ֓Bk$B"$B"@lljubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/phpstorm/0000775000000000000000000000000012656574623025223 5ustar ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/phpstorm/PhpStorm-fake.tar.gzubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/phpstorm/PhpStorm-fake.tar0000664000000000000000000010205412656574623030415 0ustar :TwUP@9 \Bpwwwwwwwwwve>lWWS353_˙Bm-X8Y~Y18234X_###++? ar#v\1436? DdĐAd qaπl hr3!!9 !!9[kcFǧ %L`k\l~5}ʊMa%b$w؃>We|a_K Tq/Ȱܖ;k%%{Q|=QjqEثu<¹y}"̫kV'W`a3 8~naajsb9Vi_XQEjŭ7>kұޙW 8C|b>\w3Iotik=ȪPgv;܃ڃʃ҃Mz3v\{= gE[Ţ[>_m92n8{<+1tb v.Oǐpjֹ]A㲢R.+cd+ /ޒ8juJK)|";Ր2tŵiI+M1Ȳe"r`29 -Q86TQ\ }Y{N,kkbͩ;$ݏ4Pp]q \S8裛DT 9R}%;|ܶ}# UBx$f0ܸ[?iq{],xW1FPǑOXM^rа`P>oxO?FfXSMxFlϥ0p'|ˀ.QZ# Z/wXd1+iCg4+g\/!Ƃ{~LDD:4By|n⛦zCMy:{ .--cuAg&(G\WEGplIPꁝW֩_ c ʍ "bGM ]CUzje^!* J̮3'22Xuf >`?o+Ti VK6>/_' qx}9s me͖Y?y zn{?vud.vA/l/8j[.+h6(yb̨;2z?} 8ǿ8Q[@E"[ Jx /r7Wb7A[-C6i#_7o^*`@4w|ނf/5^(.!1W^*r/#<}ƄNNm\J8wd8K{1o8 YNWu9(XNr'9r]ze\\o~/eA܇"`JN$=x.;i>Wl{AKLǿG]-eAz'((&rrVoBaΉč{eە4buQ3 ✃H=Äi@+7zѬ'k++gDk&5_-ڲ޹-/@qj>,WWᵑRoU$4~n Cu3{k 1`…7~r $-Z,,$jLWԾOZy#['YLL1pN6>lE J|k/H!}me";0*#a$5,d(Ff~!HUC6F豳 IA|KV(Xe-w}r֙un}MI,K"G#LP>8b>lЯ,H]%K9<`gxz)x1޺Pn eqsÿ+xth Wj@}bF(/Ffx9B}&8w_>Qy30 2&rf0zk%6 w6T^*~z&'SFS0Whl>F  ?~ =pgRbmzLyKzy v,HHj7ٽ/W*QU)+J){N;>~iĝKŜH׾ Wf`?nwg8p ']Y`\;a˜3v0u[OVAOOxk*<";y^߈L/Y,]o"j{>}0? 2Z[iļ|;xWm&OD fhO*'6V*\%~˹;3/l~:!9&\Qtq;7)*љ[hhΑ#죸'O];ؠAËQ|3qEE%}߶k߆|E>w{utj7ggA)⎿3'Uz@H룉HBqw1 "ak烏Z+5bAB]aYxm²wvOe?KxZ ~^'za!N,mw /6? *ܗf ㈤/Jѭ6!|h%X*Q%Dv:Ԉ]y|NCF׭J>I^|!ɴl˖hx͵/|a} z 8xŖ5P|"V:Kbm;&LpSC$ޯ<)f4Q|P~U1A@Vݍ z#/O;fqežI%6BIxMz&7O <`,*NouC9g>w2"튔6cFǧ7~ƳѠ {=VF':_~ `"x7"|+mOjorh!2aC }s E7»%P79LQ ]_;ڻpUi0W=ZXUB ~G$v?3SivD#Cq5t)tj:#鱰!ٟ+6K[ʌ6Փ$f'/e:w}P 4? M=aZ2v&{Y%Yːݓ!0BO1iZ]'#u“o͹Y>Bxwp!xFCڟڎ!=x `]8G9( SWclvjt3]~ 3h\R&^ SBI[˰\9ExF$2B.o9S`FbE_T;..TC4g^w P cC \W=zv{EH<Y\8An $$ɖ=*O15l $rIpd pMs߆7` TR(brzV(Q%'vnKf&t9 uO:.|"0 WpEK)畹 |`Z4M`dܾgx%ȕa-k}4Is܎m p5H'?P[Ӈ+-ICSyXl{jSwIu6b#fܵg&Zɶ^9 IR6lvU^Dm^5i49gňw9 aIP;]=weU*xSd{8 m _+ ok/^gS,C19/2MrOEX5C*UҙwR~\Bl"L껺(\sJ2~n,% ֪/WPUN%GmEn̅z0C-_m}BdCP7u6ˇcD7 c56UQ3?:c7$9Kn[FO߮Q0DzB?9Dm+b$ EKvE sPTwWzyqAWHarIC1( }tv{ꇡ[q{G=A]~~(V\_!,f6+să-=Zs$({]$8֟*KHGag|gϚټδP!{M}~|2p #JHoZtN1y ֜13*>KFܻ9AaE9\EޓJn?}f0taIɓO}PCKC(!Em(rY\8ա ?ڎ.+{xIڴ?oߖ{>&KބD~|CҨtʉɏmEAb̡|}%vǥXz1c+;Ugp#g M 3X侪P|ƐmNp(֛Eҹc%Rܓtd-/uØWA,dNQ.9u}ja01X.#$TVqNQ_ <>m:hNqa{+=,| yYh)]<`"z:=qjn5H2,zYYԺ󇗠 U$&;$n>gKwgJLږ"`Z$7d R1 ٖR Nr/LSbWIfCՃ*[Ű"'jG$ yȸ߼D`Đ*nL ~mn IJ \`hNSS_@ aS$y-;3Ct VT^)Ru 8訫'j[8or,ˀ\  ;nlksstA~$FrLM9Ì P"}U>`YF%ٸ8-+ BS!c7=ze7;G[UM"._l,.m`Ɍ h+%ډ 'TȴF3'>&q5ՄyRm3l*᝝'"{o++əo=J|a3ͯm(:'5::h~EBASARJN`]lp`CA^qvVԀ ~^Os!vS6VOX=)_:YРSHD+qMI+`-I #:; -)dB̕!pBXok&΁(!QWۘaaC F0;ġP h;P0UM~۟4 %KXD+y:47c-((.ˡpۊR`(8-0􄄾P"|2cNpsSvmqtX,wG-ݓFШ/+LX8 Er )'G%'Mm_rI] ϩX3{~ĈH\R| llA+=O I:}wv_ζTr` =[k =1CG X2vqHnUJtiCn;>JTG*K1{or8:aʱXA"ED'yʗ:n9CBr!k !vش?SX*p=MZr8's>9N$T$^ܮR"H:u17ny˦QPԸFbG0.QlV6>.U8&IlJh2"*t}/ۉSbMG֗f/9µ.icymr|6kS*!inZ)k\ȕs6}|M3} #P-<ϵ{kXt>S% >x qAR}& ZQ.aymT\<uzIDrB[~=ư޾{i;Ԝ֖ʌ[sJ}.UYB^rAk_;+%nc12.L{($YBOΒ#X& 񡯇 Sނ_ظen;7r%'G=cK? z<lR_HW:]c ĥlQ܈Yyx>#@fj׸HR= mjL5zp)\J@C0:7X?`I,CA8 /'"Kn'N62 ؖ[*š?;|D\: q_Lk׶yLX* h=9S[Ӧҁ۷.f'!j.S .tְV<έe Į.%f)¥|Lljšuj@ŽVK#B}N}FHf \w{Deݝ@;t [۶C8SY4!K:Ѹ-^O悲j~03cYIqt2k|S k7xߺQO铻;0W#* \13FG\qY(=K# mYJ }u@&5d cKV$f `g2B?]"cī_r]Q~I(˞i!kM]ALrR!ɨc$Ǖ#z+`OQ*#.FxŶ7bwYic=J; {ej_]/M[s*uIqbRޒᔰ0xhZ39v-?"Lے4"4Ij$=||__Y[_:'VM֢~pdC/KׂqB5tS2g-8MfC=gyBzd]]))b;Kĝ/m~h*ݼ-#whh畾#mϐ!Ks>O' lThM}"5~"=jf]5$ kvxtdsxIJ,{ڴabZuFnjQ=CCwdJyNvc=40lfUqqaA7kAeľ}@-iHy'UΘ&OAL(yjiGtjvBySoLE;Qb)% OWkpTs#-P''sl^ ix߷`T)əI i@evPI Ey{=Hף#=,QA0?mwLşƑC}ΓGC/ޘT"K Vf#.cH[ 6hJǢlˋoC8=n3%Cp7a#(`urʄkݜD EYAC/p`H3)(KT(Ij]tav(m3Y^ޝr{;4Q7$M B gG]ۂ$n\ _,HNm;=OG؞w c ڍ\{#~F{Urfpo&V. E")jJL g Mʠ'e`S>ĥyb-'}twאELGvm +Hcz>w6#`:s}Mfok(8n^yIMNlD-K7R:~yD\'J$h@k'I`Sw}~@)`6'>~I%i |7R1p9ZҶWҨ{fKs}Z{KڷaG><PXk0i![G'/3jo sbT^]z*n2x"x:x9vDpq#NG;ُ3Dzw=VU - hgJPkhS-%)eJcyY‚fѤƽsaekOix0uj*Mb:оbи'2&%zI *Z\vLsMi9<p,J Q ;ɆG Rɀ&Ѽ%3ė]BpJܚ-M<}<9NCMx.V(|5V@lxaQ_}8x&OmsOQV Q4[O:p jr79 Z>= I\P ss2<6\fugVC{>|'Ȭ~Xt.,5_m8uη:\`*Gr]c~Ώl.?MWC zP>A1sMcѦi=Y=i{~cv:?y{R@,(m7fA9kDiaa˝m r]O~b /ׂV(םܕP.wi7N$)#n;8ʂwdzbq+`h ㆊ$@f\˗NlZNVugǡf2` Sf[%u*17M ȡ{Q~M5UJiQJAD_NCm{$嶢M2QJMocq8SSˇ>#0L&͠Mjx٥8  Yuv^zvmCLɺBhXi9aWOoH:az'Mu@~ S*Fѓ I:g Nϗ,ߡ ǞS#saXOuPn='q ,kOjp4[:yD)&F l; OǛtI4={ ; KvV Cwg (%4 l%AYh уRu;~{i,g̈W!KC1PW*;8$NĺZMU/<\GYŶsf]hE&06=oUnMCݟ]oˏ fےbe&BH[ܐJOg֟A.rK7QwP3y7UL5# C:q{]Q|=^7V>~<"U^-Z jM^ Aӝ7Vj/P)]C!TCB/' =(l^MQW~f+rxzjy8&%f YsЊf>ѣ]m.u<)LwEVG_,TؿN{CFc =Mέrͯ.@xz _{jT8 _w6׻d*?O6M&v|<ܦ|u+`:pʸWl4OfWXiop_ LvX<'CVK2aכm(n1l޹&cDS[Dt%R]MY{xL7 ^x~'fOQQ8+*of"V8:ߞ+Ŧ;Wv/nynπtk9̫K D=96U0TXNjTӘ\G r:8j4V*-U2U=A(1߇"}P+u})qtQ;Uh-,>)zu4Yi'I59r3ʞw{ ޅF=| ,ꓜk<BE?a }MX6KR97] tYy'}Ύ 3U?}3hh:'q6cq7˪T(4VUz\G]a!kQN{8o:!"`*dJ2!1Q_(S^ʢ2"ڻ`!P(&λY> W1ܷE Z!WB^me{N f,7RҿjR8;uD4FrC'mH%*WvSu8JD rirytLf,F{GM%Xޝe6jgPD2OrI F;lo) } ӊ+n{qhŧ?)r> 1 -':nXc߆C>9St[WC<1ޮ*#=f?ūbi/ѼaOD&[hQ|7*__hK)-@ҿ:]`koXytjZ$ _xnZ 5jX=Mj'gX؇xȩ.N{.E.ŏSfa@ [D* Āˤo`;McMϰ ,\9š^3HZ(|3 [BE^ ?H?@/'.Wu{D7]%Kf՝F*݂8CZ+3WW(rb ar0EtYNg0"m-~3%9>2ap #Ѧƹ/Ia7#iyaN),B-?nvu,a43X7k}HO\g;y% Z%q\&ۊ5 `}i4*%J݁^5#*0p杣eϧLd6*j_[PC  =TD9nuLqF[Z"kfLJ/_C(c,:`(]\4,1320YD GXތ_:)V8O}ڇV(5]J~E\ )l\T'V (0E%\gWqw=nT_06k8tͣ;a#Zox7pdo{ZuKb#!\T S KC'W=vuO|F=à]',&&4M8Zu.R_PW),]<RF9Nq\Z ]aCг_;l³I?i4c8X`IDAT sU^@DϟT?#r \}X:7͐N<0116v' ga:f~G}^uۭgO|"l鬆g;N N#O<v,H. bީF.-,TKbvruۆ2+@h@ܕR;,]eu}i[Ģʰ_o C.B́ pO<̖=_JBkQO=K \oxMct$c>p}?:GO X[P;v6MQ[A=#k[sn2qPFuzg1Eq.GHW\§o4z4nrم0.cw( N n\\)(Ta„_VJ?w&vܥyfG$ IbG`s*5F;կ|x$o7`,wkЈ *j^~N8d#'Elמ~ԤűقQ ddL@g 9CoٔW*lHMWȥ ZVtkKV|} @'JAOp,)\0&"h:s%P|ZvK(noz?]=<@t8XGZFߋI2<4&}ߋ=TfS^xR#^湒D#9[| QGيR He!\QiOgf NϭC <.Ym80RV?߂Ia!r0 EFOVPo0p" \+w~%w$bJsI({p6mT ׃= <==Sg:x ƈh/aAW^apv&6w? WDvҕ2Cz,Ffx i1/øD]}J k=:PTwo (YQ @4?" @Hv(l3 pqO8~L]'f:O3iE97,&n^$ej:0cɌ1"zoJzh>HI9>iq`5v>V/1>3U<c!?!F"wB%4K74/r^br!R`,]"pvX'X<Cx CGDxbN%x&*7xjg3<'t> c#xمa^- /`63/apV b`3hG ˖2˭y35>fӅzϷ'CM~RԒ~!//Sd6H+ 0NAL|cZ% \HZ oz@0>}006~v$WiōgohlQHz;[?6# va@7\kSL A杦rPqa_(b'Ӓ4 ͫ6 uN zz℥n VhpJ"|}J@yg~c1Gj1NR/A;\OQ *COoydT~˂tߔ,V` ^_~\ ވw7>+HN>?;Dos8KкEzyFohq&:Hؓ>c Xo0J$L l3=n#w+;AHo6e3?x\_zt)ϽO^v:K#sv.ࠐi^9BeB,9ODM W}H+ o:Bm\qS6&%UQ55gO}[Q18w(C@>cvXSD4"kVqTY0F#(ᯚ0=‸ao\/c}u緪wd#fi\m̀Oƈ^ {S;/ro'VB|EN%P/ӒK ʈ+5I6#J0@oXD$>VVG5#*?<lD灸YH\D$#p@L^s8_PzgzwCet;O?YV^kLXc4KvEVx3,D\CuV3X;VH(OHH< g*:.!y6 *x{84gԳ?Y&-M_'r!oE#Fyg҇p_MAaPPpe?"lں!wT3Tit*\“֮؛K_/+a?9]80LNZXC8D=NCK\_b0^"u@)h8!28 GG_ '?4O*~D4@-ŰD,*"ӧզ;_Tg҆Ǜqç :ZXYΰ LӌVܽUȌ#jFft=G9Jĉә1cEh¼m@^TU^X 6Z_BK.ÂoXp+^E'1Z&]o\r٫KEg.cFA CX8CzR^$R ˒4nP )}*@Buog}, F,~]\jkڶ(*00(]/ޙNxD3-2WO|MF]EPʳbⶄx D1x:76ZQxg ˠK1 I+E~k)b]8?1k[6\AF+D9Om"aȈyd کfNq**OzElSsTz,Uڱ!NA.!@" H^Gֆ UU\!xI𽦆1zO \Zۭs!IqhxqqC!t2!y`pÒSر_qCE`Q1&%]a t7R0hXqa+M@ܑG9ELf!y sz*f+ \lZz$AohZ&Ful/eAq?ˏ_3Ioh0= k!!u GUy`xriGGN8܁lFT3]fbXx;"s`~|ӝ~`3Lk_Q{fh LVY+#ׁ& oX.o#,~O@[?f12l 5nC7/eT 5,)#'x2:)](Iގi vI`LW,jw.b-; ӧLm'"ȝ%>rQv*D 4:Po}xI* OpP%CKKx0_>$nя1qSO)-| @₄HubR c3`W|VrG-0BP`3:}0I(.K]_(ASNi!NCz/5-BodYp;x)D #Hq-Q6gDq$(av2"`Bu8F¯R׊@#ɠItRCDL&"CF`H>'KV-=1'F:3UYi D> U(4E@]!Ѫx_)Oץ*׃#I%{8>(M^!<*o\si. &mmbjG˒9pAxH?2{ʀ7u-%^I''h PlyH8xN Fq @ H̀3Ui,z,a}C/jɥQR`_2.(Ab^N2,ZU@S$=):%݂>C=<<6|5a>\7@VMkPña}(չA|pZ,HIQHEI#;љ;c G' w>2PQ#,?pp{[j =U&B(?\DZI[y@ n0(6n=|Ο@*W1R}C +/j1"^4Xfkbײ[Ͳ0([ZĭZfpTD^a(_~|u>`P D|K䴛alu6GbY).Rk9Ԏa:`X&"=7>Ms/a9"p9$BAspK:A h{²Wx࣬3gB&/u0^(0 DWuX~ʋG9$J`G+,j:3bO1`8Ch t @sACSn%i9C89JڡBR(qn=`uܠ5.הͨL);4t:=WMD R,3j 1i5V H5kBClmizja_fƶm/'glYz…Z<ݨ qIӉewDxg^e{97n޾W͜[^-"&77׵9Hp@KB \ά8v,muhq yhɒxc6oxhsO\(s"c/:DX^',M<Ϛթf҈Ĝ$5ޒУr:͸^o#Lԥ8~ނ;PIgԗ,r0㗹B3<ǤsD=4\Y( {-^Ö[Cս!] QQI!X!N7d X/C?p7ShKTZs;;JʦӋu+.Y!Z$, Nе97=$ # izd `̇+&0EjMgb?t\Fgzم'y%/b #陴/ް|a=2=Z:y0jH9B"CT#C-pWtr̓ ]tsv(Ώ_[$Wk2Pk?fQָLOq/Όm귝-ӣAan| +FR; bq7Ioռyi v:c$..nZ0-W)2C8**.?`-k|US+-axs: -".S4Eh}o@-!*FbΰS<;L~9*Nx?WA7⤓RoU3@ZsgOH>\O\ dsii!NڂA?ULMJY ]ʕ_殀FBr 2G`_~C<@Eʕ*G{pȫ0WJM˗VP0|i;dČvqu-C_y?92L4|ӟ_f0ta,6,d9wڰaY_ EP74B-:mAɏhKD~V9s#|E:O~]æXO#E| ܠc *V 3H0=ZV̈錪 ?X50PP RjŊZ-zՈ`)'i]XC ӫV)>@/iI# #eLUnjWÏ `~e܋Yt43?vUUS|DkVNp!:W޻C J$S>z' ;ЍG8ڪuql~T\0q\ވcLVoR7~ccp:<ݾ*UQx}oZi!^lY8m+݌yx_1Dw cGѺw޵If D)Vwc WD??U\;)ɖwYl.<u̺]W_VǎF;yeu+udp9,A ,CJ~^G04h\9X=Ua-F;鑼OTu,G&}nҢG̴\r KE똸sP4%y2rjn(qT54e{x.4&^=w !Y=Z9W>S3}3=M }SS(4)V^m[N WNk6$PbU3(,,`sET>,;&94cUrʛ]d)USx7)U`qa Ƨ\Uߍpk:-%7 u`KC<yT墦:.TY,~[Y./sWc?>QxmI_xP/(^ނtE!$RF=e!?aHdW/ y.<$ɯ@ ڨl)<@9wMNĦwq9*/l;y"3q p7mL탴̖ GuϞXӂDg9Hd˩?r8V8N`eV*Oi߾}?VK!dʉ*w|1Zee Qhm5MX3-:,-@솕`uqt"\pM7?zӔ)?VOc=-\>TqXP\[9QhRǜP,0y|f4)ywo%9.t$[^wꖭ~] <,1 "cn^ `TGnQ+W.7ǿ5asˋ/Uhd mhIAC GuôV@hyW 2rċk=PM0ˢ`cBG/|u0^/g,lP+@V*GFZSi=67OFi`8!*f91eFOz~4chpϤO3# _]}_[1h8"jԍ7פX  g|$,9GX/Ƈ(aTZ py_[6XR[R 1=;C_,]~aK[E e0~Q0O:a{z՟gb+l/x?XMp ^A+kLΆ+q 0t%[~Zui4"H<0>)OTm7Bm1(鯝q6r s-h:{ׁcNj/T7?t׾YE5%lw~]8^ N>V)@ݸopt?ꇑRLdDwV`VT$T2hMy?5@sRB.u߾>u]Ϩ]ƉmzAsWҴR\Fnc)0ò [㬹Y+W]v[ɯ9 L7 >Zg=xV)Z4ٕFk׏+XIL g֥wW5 uiKB;:A s\Q{~Gݧwaqc7VUhpmӪ3y p^ /yB4J%^+&qMں8/?;5ê^zf֩B R^aqvOnZ 7./֙N4 4[_X[ICqL&?HqsH_Pbg; Dςr4HX]ͰψQLѦO[0?`]a*"~Wq[A.妛AdD\B-x/zW˱nټe[ʹdUUkG#OW.>b[ Vjx ^_Yp&Q,m? /q'aDmIqy(T< 'mf؋{ꃆ>YҗmWlֵTW/T (g޴k-_2~tw g>B{'=R0َư1,~B<2ܱJG/APp xt0\f&lWQb?w`K&9 ۮ,}47s7yƽoK\c88e(# %/;'fh\= x-~{GB]S?z>|5a`vo쯘 hK ʐW@>"ǘ]nHhiјR{ AkDy-.FS>/N9mzȴ|5  w܃qV/@nXXNC|@uGt$0zTF T5>>c "0+|SF)]k@}\8!8Hgu `~n?h7\^ #ߐ/PL?:T|qq_wI69Iyď<{ԝb*z2P׷Efڸ9E|/<|$CHڑ+&C[>&Fz G4$E 2 gV<|}P݄R8Dx#Ȍ6jl|#v  Q<~4|9⃾I[g>-Uy1@U8]\rEG yQ8a8\1:z_r_.:қ5D!s*hagq-TpW~J]K΄4SDG`o/lq4Cn"\cE2%~W<?ժ b=E7_5pv{;dڰWw_弨_p^:R-|G ჾ@!|@u"H\Vv 5MlU4 |=F )yu R^i|b1hn&1Va얞mTD7;Zq'“<qP.e[`f1;*Ih^ڄ ߭5,/Ó=ŀ|- r[*m."U,$RP2)HP>X"+zA=;zCGs\ˮy:Z L_DhwƣsmYn_P>͎ؾ< IP풃Ir_U`WQ)v榯O;_JAwpϒbʴEQrVc"fD":#]$)q@)+S|@%!%5$pP<@tbM4޹NzpUK; ΃Oaewh:',7=x {Yc%y#&lo+\røJi$31kR̘t&d~. b1.p\YZޗ3+/g\1C̙W[ @'3g8a&sø?8 .B{ܽu/0"I  M4SXD+'}:zPQ8402oMCO%r }\w1nWEaG#S@W$Zt|3:IJ<њoBiSwJYP"zu!RxWW,2 &\qF5XXR D!6R籖kتG.b4[sϪ]5L9!;K +'y:я Xin{IF:w>tJLI|99YrRgä7t^qv_[٤0-؆ͫXn,)]wN}Җ0ybћqyKn8)rxO)Xy[|V=bVUhT| x#l]i` 0H[;u#>hG{5[ߛZV5޺~vƂ${-9֊yn~LO`iMg(4!['MrB}w1mڴ_v_U9K\zE \t)&NP*#;p!pmOFLz\icT7 ơ>hͤ=D[;zgKNSzV~nM;^}w@TľXa0o>sh۞[뢥٬ԋ <7]=Z1^rGN.ebWe QUOs=w~65w;|ꖘ-cn;j{7rfnkNg~q> eu)W߼$@;ntվoYosᐆ$Y^=o={ EU9]Y> ;',j:*`BVu1 9\Xg hp0htg29w40tǏb9Ĩpj,_E^* jxRR.h p[& V{47}!YsC?P[ULz:L tVm_uus )ad['eg%%%fRs mhnjLCPĈA:%E@d'gRGH8=D"8Ƌ3sRS  M~#P77œM Li 0? $WA ;@o'ML AoflbL FzD̥K 4@P('eQ..̢TMD((/9?%VŞ+ZA!Z`hb4J,q k$&h? F(D././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/phpstorm/PhpStorm-fake.tar.gz.sha256ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/phpstorm/PhpStorm-fake.tar0000664000000000000000000000012712656574623030413 0ustar ce4ee9844f0d2febfce8ac6a380d5c5429374e3144e71a4c3f5107a763dc388c PhpStorm-fake.tar.gz ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/ruby/0000775000000000000000000000000012656574623024330 5ustar ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/ruby/rubymine-fake.tar.gz0000664000000000000000000000420212656574623030213 0ustar wT 4Tx)rDvy=Ce"# 16sQ8oRiJ;7if 3gϞWҠɵ溇s$6 bM !B0Nsu4sDA`gu.Qk`,I+J9q+5 Q&.ڇIlݾP\S_tx+t,">^6~f]sxTXc#'sܶX \t &$Yx(4ێ7],-B.>:uY'qZ׵Chދ)f݊~fiV'=iyCAnr_e4BɌ"Y@u"9]eQ*ilPRi4uശ)I@;;.JnV1J/PX;M&ض"'8reڽoAFC]X_,֕‰xS/ (J 3Ƃ W bЉ(tM6+Kh705(<w}QU),1J=H9xEy%Tr yN$m-y|i/qYrɚmٹT삾Rx  M;@QC1nMRӛ* ''G w2抽cTP 1Nۏ1ӓZ?sd咝k;%]mkap|+y3lx䦶N});uv兽ǎ޹sOi12DSÔV1?D^^Bt66dY%Va% \*J`}y7+Z.Bk6::4UU6per'W͒UߖnDZ_HlPIN\/›д|֡ʠSg"wZcɅPbq(&Վ3Bj@8+*J) uBxՈ~D€Q]Fo:2MWG?# z[xYbPB&GQL-:<85 >UekrՉlW׵g9] Q-81c1l'm1h4Fqxp讜՜Àtus>|UF.0\ P,ՁPLR0  MIauҒ06c3)!T%l;kXG 4 ?33Amwܙ ?\AF4A"1Y0y ~?D?ƌ vRcHW?Ejq8/A?<%C././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/ruby/rubymine-fake.tar.gz.sha256ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/ruby/rubymine-fake.tar.gz.0000664000000000000000000000021012656574623030264 0ustar b47c7d4e0f68ce3b674623cef8fbbac5170493aa9b1899c93016fbb81d328852 tests/data/server-content/www.jetbrains.com/ruby/rubymine-fake.tar.gz ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/0000775000000000000000000000000012656574623024670 5ustar ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/pycharm-educational-fake.tar.gzubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/pycharm-educational0000664000000000000000000003406612656574623030555 0ustar ZTupMbY--B -bfff, mLnv&6vg.wbODwVTUtVuvo1aa+@V60';+ da39 k898Yɿ??}?[7S={+F#C'FV&&Vf}3kfs=g=Fc= ğ '`VV0+O!V?ߛ*+FF@N5?uK/P'8/?p,l,ll?09 TdrUJRT罋_o!tdcgo27JY) ?D]2Hz*]n,IN߄}I*>B"#$ e#@*N2bVVВӔX.OuccmbB>uzfX4hBXo>Fwm:ܣ!M^#=yjϜNҺCG<5KG䞧3k+ zUͲKDo'\kk S~6]Թt"cE>_IܢtlWlTŗ %P2߱FBa9^ohVg'c J*VZsN#hI{$WPœY S 7o$+-^OӳЛ$/_B|V9^SIߐ5,L [8l OيcM k,O8dm"(Hٱ>|vw3m0qF}kmQ'OUnB`SADᘙ P\YT0)2kT6>K53&ٶjrgAA/шh\aRw>x~Ougt52_p6{-"l޽ixtF mwg4x1"AGKS.No"br{p+<:+ζ~'a[ ~;iw;SGIl;W۱m+`O:7-+?Yfyo 3qc+hGRᆞ\ar+b*c,Lpr( wa}zącпoF_ wKd멶pϻ$ E2Sh9?:=tk!λ%#iJsi[I`Si{˯V<6>504$%o1i@TTZ~ޖN~- b -" !jyǑ[:[đ2gû/xGG1k ŠPI$ Qp`W$sb%3}  TX =笽WX1.aF$9p)|.g׺B>0u*dSdiwlSzxs{iK J>EC>94ۆ^g/ils橪qݼhT<,@:v;q!sUiQ 4!w"b}$U\Mݳ4\Uw ;g\nf4(:x oܟ{}j%ORvyܛ}2c]0Y~cyPt} x [] Cw跉֍毡gU?%C`!rцR}嵤t-P ")whz;u{b 1s :]^CFW~RKRD~3=Bkt.OLoP֢ີ 7.+윉 t1Piot?46D"oZ3 /dv294CGE52'|[-G2hWFZ 丁^|;l\ch ~\`0`pv^X4\"@ʠ9]o -hvѫь%#.)%%o{`"ˬx`6BU2YЬCVrB ?Ω!é.7~rjb,mO֑=mɍ{]B5O^[JLO+yf{87)X݈xaxߟ av]S!Av;?/!P$*C5x(e6 ½x?>`oy~=zWXl-[lF8-_uE34X0gױf,Ygr34> n>1:N%E:]4x ltJ +!EVJҴA%W<0M< Q3eqZi :y{h8{/W}7 żB,å.'V5%)"Eu5^f,C<˭s2Ck.K{NE2؅ً,n]L\2loHg< $laP24Jdmgr-7셪T<>ϔ⃖ F MĘMdϋoq4rD19[!Y Qte6ͨ#U?w$v#ʁux }~ `KB` S1I+ Sfc D@=<:{iB&:89#;s%b|Hb"}%d?nk mP2-h@">EۥŅDU)J'g`-- SK=ԯ@57o$ ~p)9dq{{5}e e.7񽷜D%nQL6-BiY]H]H3*E?,̄SWfIZ0'S_/H `/I-wdzLv6i*Zy,;WdR2ގ8bsUzrj3 >:`rlx{w-V{9ǔn"G{Y/oɏ0Y%J"&I?$ؖW6Q`IpȒ)'bR6+=j9\8`J= ^ލF d _;$n|NIr#@C z9?[!A[YH&ƄuVRqB&Ȣzɴ<. =ӕϡD$V+ q3w^`:V$˘ x^ME!$7+yԚ' wRgp$ ,8n:NC&-l`~:%A-*|*+ئy9[@g|Yr.B/GQv #7D{[ZbG( 8<8T"r},e.1Y- ^qCq1d|ѴnҬ&Y|spdiyFH֔`7+ |);i;$' s4!=?ϟwђu1O9.'V`BE&AQ*Qq*ak2+HZ{S߸JƵV; #" gש?q: Iv(4nxcļh&{iJHNk.Rˠ?TE]!ciS>\9侅3%UcBGD!=>h|Xj{$@kCx&"E{svҒ$TXCGI )Veg<5z.WbfZ!dcyb˛`l,1٪`(O|qc }x'a5c =BLF"f%IU$pKhn7~6(w;F1pjWeʭ>:Hv[Q.^en]+6@}o ,z|(X}y~vr=Ȱ| 0u?xN+-8Fpܿ!~*m0)C@__C16}]Jns#~.f7̏q[ ؑKM}+-iK}yG=ew U!CTϚG0Mr|NXYvF&J& 2cF̪MמRC.GRGMrT`XT|I~^֌e]<OSd{Z J/yn3N [)˽O"^}Ns&JŽ]X JXqiDa072؄u~}na8ewK&sVg, ɊS- oFj-OBaNfrF.sOk63(B7H{t+Ƿs=7m|H( :Y ,IJKjMo)؅T ш}Im3!ڬe*Fy+.Py(2]07knkd͓4RHs9֬yOX:eg |bH|7od%0s2&[;Iǭc_=՛hk5$$(=ѴPD/LSS;PFEMxvygKi;yBh$RU#3Q&q411j\raF\LK0P`D4aGMA6R 0 p ذj1 4M 5<g˄t=8t?dH?R<Fq ݓ)Q68{%eJe8W^i3*f"sV=Z>6V;s?,_xo &O"֌m%.?;yBVM9FrULoFcΰ6FkKގG}xDNIF!q&1&3Ҭ'fӒ)=o%2zm/NZƷY5J2:.NIL67qDiA>m!q@FUE @%-*<0qbzpb^ u` ҇bϪf.x0X8Bܜ~,5'Fgtԯ22/y!?K8wn;H螙H[ eפq*]0BnG(vRUF[\t ~j<\xV 4c#SH»$ۮf;=@ j?H ?ҧ- ?^.gϷJZ{ެR߿sПO7oN2w~1y/P-ؿy"O7Y6]eɫwUgp+3ә~HhzRI0ﳳ<1b=cciP ЗQw,;'*ims5;2fq|,qP>ưQw~x^[4c9҅{\b49foŁ#KH75nH8-/UW$|d#S |V+J.?x]]*Lއ!_$wm?%j* KrVJy&'XXø2p$l}Bplfc;,cNky=]ex֜BQ j~`.<߯>&ΫӀ]Ĝ@UZ٩{$Wt@Y e! PY|ۡ;|ry©ǮjB IC>HDy._cyJ7;N=w:B>.FMy-8{CP9m-E !|Lff,r(DxlIvDRͲC*rÞw7ZA=8r `R*iS%Hg8!gMTn9f穰-5q`)ˮ>([_[IBUڧ`Iewb)h+R׍m"S[U \F93&xmrS؄} w%ƻXᚙg2T}An[nF|!NSu`lΥA&hcDmh5W$0"Wʨ~5:u2Ùn_n06hl\ X6I0O734Qf$ncrB](']4װ>sDr>P *& U<*~p=]?jo6 y RoHB{TvZMa )v;>EIo6 .!c|\lR~U.Ķֽ# $r5Z Zx?,{1!Yd#x"?Ҫr/JM7/n+掇r8zLYһ82CS /%$٢d'%˭1d/4K[YSRgN0h#2%ĮD{>ՆRJ:0/iVLYb+uZ(P xʳ˵ރpˋ}l#bo4vdЧC;r2[BhG6j8 KU!mX~ͷ8Uh>hy+I8ļ*H?vB%# ju xUv;1||YbxLHD햹.eb)O,dw*4 Tλ(SDT:g٪wdX#HMcx V_#~}4},JDFί)E;,(BhKL鑉VV&p`@yT 8Rj2R1B5x&e{ym15P> ,1ò0n0W}/!P#\z&߻ff-ʼn.:Yy 7J,.kZaKh,W۾|.B7=PԄy(XVTKЁc_sP d7QHևU?CL)~Q쿟C8G"25uYT׉調BPFmh/_G@$Sv9e&vGߩ6-<'wPx3 i({pלkR<#n*3͂H >A KẴɜUwkYRe,@{ψTSrp37Ixw?weN_{w^ÚcB ]u3lα-D6~ZS-VM:5^rg!,ù%LLLؠ⍼MwF+dr[Њ5Ҙ,qKSEA$IJa3GEӁGy/:_7ˉߵ K,BT$(DR WrhdbS)&cb1i;∆DLR/3&Q#*0~Efg WP$xp!ҳ'}ٱh*<1YtEڵTX]f`Sԃy|J *i-3۸kM9{ogq\}T6ͥoPZl偬cX`Q+?2w#@(?Y:2X!/qES%dk/o^ek/=vE-}dYU51k!Ï 61_VS_})U@Xh$`ŗ+iFx׻9ZQ5kR G1QyqeX@TbC/YDK'eW?jt峕 熿,{jeCFLd yʲ&kw d[Jqơi֊(kPxh칒0u ;Դ4 ẂA8`F2>QE਩%VL[3=U[<4fcaFs#۸dY}MaY? z@Qʱa! }~[ '"EKNh dz3(-'LG^=f*ӏJѠf^y2_r=[aεc۞N,O>OU7F]-{;)%E)KJ{xku豿r:\UdӪG{eEƮQ ;|qr崐+sJX3ߎV PcpXg[Uį{ns&@:BKQdg1M+ԲU).qQd 5%@ED@HUY ]*H5 6_%\hp-m2;C_ZrN~9#6ƣ%f/ʋU+F<|WZGiSbw:gg޷*!j Fճ "ZWB~cHh ʐ ``}W2|L:Hr0ypd67<7̊(=v7 E9H"g*B6ז/uGF4ww.7i^x8\XmHIyL=I|CꪗВՠ dɧ‚<&Eqͻһ/ְ!}OLFh%W{1@,_>s@(&7QK }Zx䐤G^@;^ؚT0爢LhOMcr<-q#AwAV8-" Dh!˰ziYr΄m[ -],G38>25(GW I#xDRFw\#yoOkN+kЖ4{ӪD7ʄsF%?ry+JdzWQ7bi 4:ґ~BZžW]aw]}1[ias$ P,<ѸZJP`bˊ-,~D\&m8~VeMS˯,e{i2ޤo7VSyET 3M]U'C-P^'G.U0#.3kߒ4!vΕc+D(_R h͛i.k^X53SR;.Juj5Z;?uSj߁a]ʝ=48/!>0SPBmG?KkFxY]H$CZŅbvo\g1=;4\JŪMn\O(蒙tGR@S2"G\w\vo*7 8LObY?!wY҅,([3Ҧ t`Ǥr KOD3f^YXŗ?ZpcNEf4ap6]Uz!貰Ti]x ,ɩJDؘejҀ}f{ '6,Y6 ~˄j<6TCNc@'NDU;qxwJPI:1ڧ(QӢYA{#1S}]0#aq/%<+[Z@$(S)򧝝Ύ"DSefI nD\ k>rce^>rݑ-Diф){ڭ,j :L nџIV_l|ed-Bs ]sLv`[vv_5'%qnNǾMb0BT[OUwcbRi4.e)lO@]yj2BYsBd+v]Q^'댾3q|aN- g$-3Ju(5ѯ)~LAEuDVVA3#[&-O4@pXҶRc*$MMHVXG=NHFTP^bA#\/lv%GjhX UU%b{aIb#7C;\NR5 Icu'= v=[mA"Y]o /A}2k(!&$[7BL=~fg-rzz7+[cjt3P,3Z S)1CUF)\}Ϧq %^{XT4iHg򏪃ʑRѫ#ڵ(Mp$Dʗ8w _kUj3-:kN}[;=} D˄u$h_K da?_L ,Y9Y37?2Qp3t2s4ֳ6Z __-֑DkhfogeMFN6F| dM :Fv@V0;P HM ~ӿf 9ܿ?u?:>_vV_ELubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/pycharm-fake.tar.gz0000664000000000000000000003364412656574623030400 0ustar Tul]y1|lc3333C q)ffffff}zjѨͨ5z'J-Zj{80ظZ8{0Xؘ -l$XXX8#+ + wrlw)ƎvFVNwYǿ`IVsrrK =s?Yl,l@6V0;+)?p)N戈 Zc G[ Հhhd߽̉OMۚrN0vvV? BQ^"-%7ぇ05L Mv&@i3%c!>㗴\q_۝u+s$]p?q'hHhOP=^U11]AlpX`E4it,:rrsZk=(lh TǹO/l+-:UV+Q_3CUxXOX_=W}"QfxWNÓz mwƕft25%Srz-dV9B돠3nk .З)s(6} d"Oq1`_R7%Ut>f(jD/ynPʭ+A#K$M[5A"b ܍y:|22 >P'zcHGӃTgjHZ&Y(5aMcb/T@ ]6P0XR3͕!Rv#$4q]ySZ0=KZUE0fND[^2' ,%w|:RйtP3$߸2\x⬵[@ez㥂ku0 I4}~f?. uXu`g'%9Uĺ@qil)7X>UF{NQ)I&:POޟ,+>3rvB5QB;VA_fPD@XO|8 5AQ]XsR^1"0i){iE q\LN'o J-1vȋ؍c82`P(O[ tHR9JIECg_^=i mbMLҨZXjv(:P zl=U4Ù:.B68ر+^M3]E !Ώ=f>]\Iz+OmUN-Kqz9~8{zurbg$/B$GtJvGй$[\|0DS4aK&G9`{9X:||w|E jL(GgLy^5͡palVw}{dznH= ^vMbl鉗J~G/{d ޛw/5͇HhY.҉K/X%,w :j7%9Ȑ\?~b!o]^e`rܜnz<;%d5M`~*1q_'z|p'9z;g.z5#QtNemx` |xzo1ӹ= Q2.WTC>L|npo|n%a m/wpJc?B|1<ߨtrIqIDF,]Z|EV)sҵ 8h|sTg|}w- 7(#xs4a#M3=;`t|=_8V>_ Iy+Bw3,V BtõkotHzב"9T*7n.W@T94qD/UO N~~|mwkz=E0 xEȅԙu$̈́{74Ia,RlMb,A?!f4z //ncϳ.3݃c?K;5jޡ"I?wB rWz@_7hGdh6iߘr<|qw.)dG6 Wl]{Kd;UrY<{Idx>$.xIl4ʗÑS͇m\K5`C8H%o'58 =*=_WiK vr\b*n[Q NJkLNI|GU?,Jͅ7ƍ2ņ%BgP>f:p|rBӾH0subwAzN*HLxfuY-dK ~w{B5'uṱ (ҿI6<8|śZR?"dRTho$TF < Uܕ'<*B!AݓPɻ` Ӫ][pFWwB5Qf?Пj/{vK ssԵFCb#Ǝ@bvAtWJ+d|k2K}`܈c=ca~(b04^G`U;QAsZGک/5R '7@\l!JS]S}vQm͗c>W= _Ӊe *'# 2Է͊ɶ(ӻU}=!E*7L6hIUm"3mj `lyQ3lCya@N!s!j* <ްD6fŎ#-i J"D t$m锹=4To#UOX%L*-[$H@B_!H<$43v\*kIjg/ ˫mJ{T I{rD|Xg<(oYрm/'#'Q< f8wo#d I SmNWt.)ucXL>Sa<(?hEv,S&25%-q'i9mi:ZyPFq9x/ED ՏosD1 r'D쟠/el -dE0WbߤhF_#[,/O:ֈ @9CMJ+Rm2)ňLPӶ+62-q);WV8ar ;`-ulɚ1 dXXX_ o9ny\IoFe&윉}$XoڞP )ZxuMtl}8:ȨaPTVƅE=6G >]AVe[z4G A { 3$#"P m)cw)_tFף0pQS/\^3v$E% \^Zyr@?Wh$/c ^:B^`/m!Dfw0]?%r_D/h]~7GkM(dڬeV 6 As[cW#P9k5Y(J!6xUW^oM+C{6GyF1^│㒿PTr#SV}^Vݹ3۫}:˽h.,TE|z}N9}Mo}@/L XwKwݬH\㉾MJ)O`^6?.{h`:ʈ2x_$'? VXT`W{qyR7#ë!G'o;bEQ6'iHeDSo#|ĈN%cC%#/QyOCv"~hokc#.%h*! cƈtT\;Ҭ[VLJ]'ʤ#׎sN#Rү֥lCye͇EnozV2 $߿! -y +כ4abmX#f兜P'c7Y2?HqQF@\rsxTEr ;jbI0oxۛ٬|BdtMkD=)~C8?1- z eJ醃I+Fg?G-JgPrVs( BT>Tpuq*{cG2?Y ^Oܙ"l(пl.lH@kt_ "kOi%QHbP4ر_3tb+j̿CD|azn\0^ Ęzĝz#N,yVH*M!a &M섪Q&_R1ӿ2v0nBOA9f>9 z|zV~XҹA6OOsTTMLp_~8ёdtfְO)n=YGb}Y>(L6 he< Bv\brKc2a-CR˔aQ(6gړ[DIծ̗|#q(-`a}vKHbMo+ݧn׽.!?P[x'_=2pAi魆ܦ1)Tv+܉8-% JcOc6&-c54灾_-ZDmV'a4T }$$e׷,Z L7×J,H9m捧B[E()eB፪,ve؃0)qlK&2FZ/ތZxlp7XٳxϨ^UU_R3H?OQQƫrk S"c~yk3%FX*gވ1@5{rn(O76*?]B؉sC5 |73+Z8K2넏@vWD|0d*d&_}uF4߳MZn̴2^KiJM<_ bIתY.A[6mAB)_!>Zq"xOXFS/(t8 zz3%Eg &N)8T#lPN7jᐨ2h;tҹ C'Hc"dU6{?(uFn3.86Wa6rwG,v0r@2_uU>:$bzd%uN|3 ;`j&>u${Al^ '*( 8u˥e2EN8|PrdGܹJWt#P$R!lfɗA<&rPȶ<$&ΡkJE_>8U7@1}qEz#351W+l,VaNtDd< H E!pfYYFAد2 W&bC6ABPd v!A㧌c 7 F̻JݔձV׼e$!/|AKEti$0tIRt'?ֲINuHPR" eq]Eĉ\[16V)K G$OIiL4hhwY`u~dsy]кF$CA=g<ӂX=SNRwiO 66=&U_OY%axrak2f>C|s ~m&f>FLC#HC_>'S|-Eki^>ldTdi q:_/?$lJ8M0UKG>rRan馢R:>\;a߈āS?$]|) JpK&~@1$~Arbak7"cA {u3SmtޒJIʀaگPn\o~fݮ롳}`58?:Yh7t@9 pE.lDZ ["TsOR-sh8xn߶#ߧw{.}lۛEV2$!0 w_2p ¥tב7l_a O37ɛAr#oY0W9OtOU ^Lto%$rШADh >{V'p8`]8w^xm^PLspJ#7/MD ȱJ$ѝ  ^ܛ @;yE3wqaF#唝)$5=SVmWR׋jy$OX'D["LsN:4pU':!{#oKnàr`-eyׇK:x Peaj)ZxRT8D #4(4oHq|&]3.8rxHY$PR ]Wc Sk]=k:R1)9>CO9# ]+, r)!:cQty/Ely3w[ h^$w/aϣF0^h9vaq?Xʲ\> p֔fgVM&ReuEՑXر_S&n7O-xj'q|Un#W^&5V7inhteZ4,NdP![c#YU,& 'ל dZn WZy\R8o]9LOÝŨYJPc^SP9^gMr9y١qk2`ڥ@]bdǼ=,PKZxLtsx-cЊT^fw3#N-tBK@$U/D^~v}߬;-D%ŕ⢺n}dL18߭%6A*p&?_/(%m |wWr>o aMxО]6 a䛉:dm!zP؟xOƤLӃ0VޓJ*ܢkw|0\P4գ$ж[E,)yPt$<4i]PPz4I+ h¸YX3g9i3"orBx7Y̯©,J\TW(z:E$z@|",=*I؀b֙IJʐZwt1`>P 4;"]͏hi y/ bNiTeM~>* ?GV!+K-BGUmk8 "{& ALWї"L Z?XHh4MNG_(Rv)U7jdYg0'N!n5hmx-Ze; #("iGE U(Q+3$?[ʭƪFXrF/02$lzux7 RvBh>Icz=FD*2Nu"鑸…klҜxLjӍ0c(DBbUͦŸwyx*t 5RFbd5!GYQȩV q&1!{Ʌn#?Dl}2#eʥQsvǜyxK|7:vn{eQ$;G'k¿:$^s FR5oYzM|<|`U䩽ТH} ꃅ%PdVCV8#i:`S9uk8,o7r+Xh{uѯ_A,͑Mv2Wa@l ҭm$'C*YN=R]!} /$G&tҚa3 <{YHwSr"@YI|~·:CzO=c 0%12t" u먼+8\M.~ց() C\ۂO E.n1dY2M(Q0Zl@cc&762%̀ZHm0r4pe2.gsS|ʝ|Tg"uu'+uJhXR`+!4lR_k)Ebk0ۅ uRSaxSss}7r x/jř!銳<1UUOI@7%0ɢ2,Ph5MY-[>`n,+`4{>ȟ1۫gZ nGtF{#>¥#DXqjᥡKYQ .=,\1,jrTT#r$uz@U^zd6֣t JsBqaB}P^2u74Q1V.N0bPw}&!+ URHϏ ?\4ݕSlGݕbގXe_,)jϥV#F=Wg3Mp%͟PZ`]f1!&8Cq#Lܵ&@L+N,qKB]eL:3N: vwQ=]\4{if2p"m|RvjDyTXymPzĖo#H( ʅPrZ)K0op){rTSuTvajsy},խoQFw{ԥn`hי9#9U<'\tEYy_p]==b a@U.fflEYFNDtu)rlwN+@ 3X*.fCuc@aMYGPvAqfǣVe )g/rC}RF-ծT.]0IhE\Z~^! VG IbQyWþg!k` TS& C nѦL! %ddgWCAa_S\J"xIR8P5,/iV$&g;Mi]Oo^/;Ldv^QTFS1=zxUQHkJx 3<ێN<xJ,% ;f$b0gj2NT9CKI+3.{GŸ+Ic釧7wAџ4Xh]dfUmGta]nyuI!a;s&A?g++vH'4wj*xTRYŒ>]7w$0ƭ9<E!aeRRTdF~&vؖj7*CI)w*H38P-!ϋVAJwyD0[o,TVsn.*K#o&זVPE6cj7;ӑ}AXZT۬f\t_Û|Xmek,  AW>ӺYKc`ɉ/-_%o:}UcP/.g{k՘ӥr4:LUiɬōRT t V"Ȅ2 eʕ,r'`˅d`w{_rgcpK*7}F Z+:tW?WͩFU WDAOǜیO\?v/JJLL ? 4c-q GcqWi-k)ek,qwf Tၖ Ё[Ygx ]*S8$CƢ"HwF]􄬈=SZ[)e@H K5j* ͊,d9{N-h {Qr SR>P9M 2%\fj?"Pb50տĈ 9L_6L(;냁7N-W~+ػ ԛ&#@uw:H~ce`^!f超ܑ獒<_hdr0bС0"gk_1 >J➚Ћ8f( `O̱R"_~_#awg_C2lJԕ:;q/[I70PatN5,JZ,G7gIbt ̵-?AV_,o6E8U>벿_E:,Ըa핤b}_I*"JQG#S]UF],sNP/UFƣe҆a?OX?VC;d7ʑ̉vdT~)O2TIOw-o3]6$[[OxzMUv%x,dRPЇJZK]1NܼP\b/@;mX@?`9k@qupU'&#ӋWwe^E0HqY`cGoиu?4+͋ +T%8pwn_~f{cDɠwzZ/FPȂd6U)+J)H0I 6ᅴCqӣ/?'#J6ol\ 6?74A:O樭z?+0\v#B>u=^mk4ӳ DFajK}ՌKbݙsQx zy0iqy > ڿo??fY99`V?\?+_N&&@Nſ/)LJ././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/pycharm-educational-fake.tar.gz.sha256ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/pycharm-educational0000664000000000000000000000014212656574623030541 0ustar d79e343c70f2dcf1e929329ff155ce666ff4aeac0d8e672b8922ae8c236662cd pycharm-educational-fake.tar.gz ././@LongLink0000644000000000000000000000017100000000000011602 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/pycharm-professional-fake.tar.gz.sha256ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/pycharm-professiona0000664000000000000000000000014312656574623030602 0ustar e875a98c6199a6748019b838af6f5e696521c0b04715620fdcd11c83c80e0217 pycharm-professional-fake.tar.gz ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/pycharm-fake.tar.gz.sha256ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/pycharm-fake.tar.gz0000664000000000000000000000012612656574623030365 0ustar f1da47377d7b8db8d31d1ca93bd329853c74738e7947e00297ad1e28d3a2ee1b pycharm-fake.tar.gz ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/pycharm-professional-fake.tar.gzubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/python/pycharm-professiona0000664000000000000000000006101212656574623030604 0ustar  TP߷yzp!48݂ww;g~W}^սojf޷{u^kzW5'^\\\\\TXn7Qq}_06?Cq73=D^Vy98x9kr?_??Y |Y9;ں{qO7/Xy ?Bwb?o^sg o]PiQi3sԼԜ,]\,mͩ5ۮnT.֎y9QQ̬퍿Sq1s+%(8b7w2b`~Er{Z[|O/ѿ_~^U|'{դTn/6cڛ4  7y'=4S{Xv1oҋing t9lbcCzu6Ucpz:DzvXhdpM$: |itM[Q7;{x`9[Oߛg6adEWΈJF63)0:J|1m,GE<3V1dThכIq`r#6%rx} |yMr-?[1{ZqfH"R(W(TdƆ˒e6Dfy]:P4+,VnǶEQ;Aoe8l]G5TFhΆ|E9%/eXA$mrcrS㋸&&$lm7MI"<ՂiպkmE|kzp]yTt˗N="" _ /77T3>&g5hiiȡegG322Q`03,*yX\@\qQNQ U_#iCg‚ 3#uy>:/Js"kk4Et 3-v vĶGYsWr?ޘAˆ&IYլjo 'پbi}. psTɟ;Z0y߇OZ4f? D5]0?ldPoڴ9]ѝ gN"iM]/!e?goSh%'N9ǕiOl7 x>66fH2^A-mD[u Q)'-r犄T=&3;36ֳ?9z| MSkw ZRi(*AAۊV3x. O />dhF[!lE+M# b0ڡ}YWz1*7^՝Ѧf^-c=eؙOOknGEzGݙ}/-pS+>9x3ѦyDsMʏr /6HN]:§pp.6糶i,ʂQr A 4AF;$e(XwqMLc-)(g3,he.` N=Ѵ*[M@oB33+w-^2*&v=0O/NSqv4s@%CzNNJ+^K+R'*6N3!՜mCfZ3HUx(O_g ,MxH-Y7t{yHիrT؃љڼ ڙ Ò bϒHDq`7C.n[(S :)n&N5}2z}8ke{ ͫkozrIpD8\@֚v±T68Gl_m>%XˏQ-eьi _8OLjLXG  ˱j@h"[TL"MMõ~^ǖ1zA+[ tO{Cأ"EGDj: Qhk|7Sk7S\gEh\:@TBAgGСmGl0e*(JrOTvp̤-}=3wo I?]<[_ 4~FQ8:iټEA3X?d5GHv)tZ%.K4D@L"YL MD VtD JPeI$`p ĆXD`5p0Y|bQW۫'|4Yʯd屒,hBI,PcJ}*ɏ/}[#G{()2Fz}@7tNK;q>{ (vFuUR0{篋NȻ>t s01&Hm#f/1=YMoi@M\N0@esPH) ۷xKWn(P Y[B<^r9|5 l 70?wp E~MChf//щn:chC1P7E!v]@l~8=YЂ:|^.}o͢oMb^DoS o_,HS9':}/_pg.^ƛ0u77/>5"sDdah5D[@zi˙wetxNzo‚XG= IF?.`[HaT`LF$zhH GHЌDNn{?E>ַٲA"HC(eqqxP@6Q#H6ֽ|U㽏gn#"C2`9 FVj?T~#ogwD"4.-74oHv c80Rf? q/b|A}9qc#nf56i:,~7?>Z܁81f1x(6J#jC|s=J0Us/0HVj5G$_bUy"҇f>:j8K0s2k8[){[>2;1.:ZHzHR5`>' P$"Iu0W%Y''exq4?KqQy;|aHKjd?S ϸM5E-CLbQrMPb}62^BsI.~m[ic B]I4``2~egW{w^]SL-|7oKx=KhνnSa]0޴a!@ rph+V 3Ik4[v2l[vMK _" (xJ8| ܄۰]1!>L@,߄\ (w+ +15G!,4(wg/a1(!8jcgPނ@39Ђ>"#}nFDy(Md_{bDd7}에}AJ sZuoʾ/j1tg{=ʔ%>XWSyOHs\MəZQڡYL8;G+1'" V-g8yl&TD :#@(u %y= *^2n?a\`uc 1=#f8v);|e(ujKN)7)^ӵJ~5vy3jHPwo;# xڳ[O!?@ߦ_#*sR?['%Jkv(H}ɷ*e$/ur[ӷoP`:VWċ4C<o؊gF=I/D})"=Upubh0BÝ(E8:U7BRV`JP*ћ X h{4B:gJeB 3w<+]Ls빬 gvw_h uks0]] }[̟b/Z W; cL֢ HOQXiRT"C;e8t>;SY(~}D^vY72ItlPƲvӴ}J ԕϫ 1'Zts jw5H#b#[(eMW:e-B6 w7X(QRS4(<`_f?"~ۆyAؿ7\4tʕ-GO2\E%6/ m,[t38Ws(/v0ĝ6?pT(0e~},Ȭzpg7RO rkenWZ+Ъd -%(5M5 @7%@[vnPEvmWSqʩ/5v:;=2BbXzjƦ-֜uk:PO ?b7\϶@RzDB@"@_(`'(6AԅHOӳN|[ןo GLM6j'زVtxV_~[u[s|Uvb+?4d,xɼX?ϓ.7CŢ fj$C(IzcQixLrԍfW,kk.7^b8Q4z`d$R*?>i`H; ^UyH.gI|-y#\|@;nb )J2sPo[SYC _{C@ }KOpˑ@ĵ]ևJr'gݼhݨz7jX5܋d(`ZcGs-l릻։z:MH\* i_q[<HA ̭g>9 ;>)h~Qlt-(=!@B5.!\|Π*Ow"^h]Jz-9"NKǮLZR9}։TϙB5z[dl8z$[U+WES6U }xi꠯=(R~%kzJƺaWs;9%GA&mnH}8󗕧^SbX-in-hՒ>[C +Wӱ}-]󨃥6؏HNSrNtax牯4׏U۽//76&)E.S9뺜2JR);ٌF*f'v dM!U0KVp3K/_8apb]vfwFBj8uN_\>ޘ 6Iɤl% OWz?IfUp-y<^5nSd!Obkĝ~jJu-1]E%!{@) {c-X}_kYkg%q ȃ o'זm7 3xk2/ 仕;" 7cR:NE%RUK88)( j)Al7@M9꼢VlelUo>,!~P5RbWlf *_,͍[׵}30أNfG♌. QU#O6$-qAP $iVFzzc)k5w*֭߄Y;Gdq4_즔68g>툐 YG+ ݀~C%Phgpi0L=L FK`*k3:2 ӱ o+EfH }!'+3h3#[ cuĎ-$(;=ᴾIm`B<`#a@xA0EO{wn0-_\Rh+b`4O)Yb ͝ RE=lG l⁰S?cAR_!7%MHIEǟnvW>h{(?<"Bu-)C1&$ޗ%FX`o-g+.[ ;޸Z@$-i^yKլF(1 @ixu+BȎ.>\@dA_Nq^v9p)uY)%3I;+{XrɂN$ _N~C!n \b|fss |hp̂{e>Upi~+Ӿ>8ceM,==ځS l9{1.ߍm|) 6Y=U4Mœ+j/ 5#Njggb:pi:)(;m[A2J8Ki2O\6,Ot.Ύ-[}&Is^nZpЫ6M2~κ:Z2"d:{ګ|.@ _^>_h!8t.c5 {_LML{MSi1 +.3mSdO$]YcȾF.Ē[ 6VՉu͎:ȞC̗WT&81hUg9It}WIyE f&sA Xa]xiU:j#w4dҫ ISQW8忩ߨX느CC:lS69y/ɷy~b#QؚG 57ݕk5iٻJ`.r[NT<9׶y\Rk!艪?59~PTs=^Ma.XP6aHKoRlꃻ@[&/,!I~d)9v#A)ddnv5uLJ9_S2(zOH^Ylam MY:E*'bSyD掽֏юBܔ.JR{|݉s5ur^݉yrӅ9[8 NNfn]G Bcc1HHCӬғ^O45ɔ"ݭѼ]f;>ԊϕrN^N=\$QVW=_DzZ>JR'H/x~eQeqzvg-]D5qb0h m )cˬ$eQ(i2VqKP"'3&k]P֍P73*fxKe<>sОȂL q ԋ6_D';#x1XD@U;@+d:ˑH86[CĴ.亀slD&/;NʏqŘ5Jaoqʈ")b0wcA"6oLtd1<4i*$2]< e%,W[Aއ [8 OUxN(uHΎp.2i၍Ӱ_j.gZGKFl4f-]P2pO$\9r*AYX=_V2F6!3(!*l'𥳐H86l.XWIe@د|wCP9y.\ P}Eͺ(KtOc+pKnv;Z{]4:9xMWSBrQε,/ŐtL/3m[W* 8Ib|Tg A,9y?DS>۝U2+FbÜ8l,op3 ewvŵNyں߹A*D].HT*U.gV͋;! ɭR^:X!V_wxh^)9z17vבRt9@UX&h4O VB&!g,x!_ݢm?DI\qv%(~;K)ـc! J7ż6$ۊ]j 8^үW!hx ^<( !2kTjlވ 9$QwX0aۨZ@.^V@E=2~p(oh6qX]@p)=UHT&+ icM/ʛO+qpE'訪tB &6k2]^fIi׏Ǚäq*J*MU\F"6 o_l'=),}m؊ 7f㌐jO_kV՛biKdʼދ8Γ"'>32Y=3~z$T_L7xDv-TcNtZU| /-`% 1-yqQҀVI\)|&GJC>RĚ=[0V5hca5cwӢYhF]Jp,XJD ,➱o'pKVˌ񾔦#|"1۾QKjTcω`uB'IMؗƧ6.ʊ)a tąC0%6j3/LXP@ J յj7ݨ*MvߠsdڜTӋk 7pQV6?== >΅e36XD-{6`AauR<Oe>{$d|ً`,fg [Va7#HOx6@2}`+;l-H6/dC6XwW&bLIg2Kϟb~|%$6_yaS0Q y(gM?ZSnKұO%PΫE`F"3aC%9 c8C$}W 9͌.7\+Q$$fa(eA,~/YP/ȭ2}Fcl}=a3&:[lNii֤3>G*!bف5..~HVJb :W]nKmKW4 c(˞I~}oe?ȂTțB._+bTsϫ0Wsd7u_M <YLGz@.$W5XMZa@(F>* %'I)7]>9A>?Pocx|p9w3~F|qM~W !SP6GG1!V @=28ڙƙ)t -ʡōR =|EfA.vx$3y!JLa7[~&? hg 6+28z#üQIyoT]|DWu^x=CBzO(]"FƔa(/h_ ?F!(eKqy= b=!auP.)(]Neߏ nno 4'0mmM̊,=/qKրqFg&ǐָa^T1{.">9FdCq)m;o~=g4b/oJ۱K~ < zҎT6c*nQ$K9*j~|.7R<ƕ( txCGQK  H08Eg;j,(K+Vl"M?]<[Ǻaf20UN&Akt$+8I ˺r~0W#$m֗E…˧ A;r뛿KݳR]s%|X믩HuUĊ3eD4L \X +3OФa}Ԧ/{ F1 /de_@7 cQQƦf;Grfc-hl­HT0z wP'Z}=)15?0en}qv\stk|SF"IB05A?)c& QZªs, 9Kj $@-> Og[HOG0aa^;Yt{XӲϜO$#.FEz1DE DM~\ߓf:V^ThJZ]qcݼH Cgrz9\Ip~6(pUQ"*п#H,~44_HPwJS%dZ z_sG3ַ%٪[b7Vu؍zYy&rv8wSwZjjZ? ]#?ZcaDŽԼd8'V22D xZD~3ch<$P!Q"ǂu2é5 5KJM#)*Z@6!b:B\ >3 |;;}eۄѱD=ʥs,UwY%#) nyU#?ڕ#X[|!er#Lx:=_>n#bmjÐrpQ4h. Ѽ9f9 mH,kV^ '_g$ZR F;ߑFց){o3|_*}Wfk)u߶|{>$O$µ<㣂9Z,'7tۅbn;e52dj.0d/ g H*}I3EF%eKJtJ_8r <#x_ TDrBr֬譣r64QAzۇ'`RnZ^dF xW+ё;+ 43ӵcl.atT*<#0ۆ/\MHBϗ7Ka00̡ nu8:k “@TҞ6afqyNog19GJvn4./y޺`SH) ك^0^߱?r EF]oγW7l c"9'dvw>Y#q3 3f> oB0sL;ywF/f_ +^T-bš],JIJX#tx'D^KrDNdzޭ4kf^Ӟ-pΒ,c3>J,]\Ȁ.몹2*c1TOgBa:f=%6n{]%tݖ; CiA0 !*]1J>ă#~'5T"o'cc dWL*+ scR_##LrE:QO;WqNr;pm~SurʸQb3R#OkVSC3XW7h.fp?HЧm[ e7cEPل 2ڟhw"^%S̘PCNGT 5:8ߚr(-A?@(LtDzF~B#Bv].5^GoNn09,u Q!_;F%.`?w6uk3[]Hs^Yׂl??l:㉌9 VZPmU!i}lHğ!s\i){7Tfjb._ģs@{Sn/(;:$<1ЎALFu,fO1 6jp;|= W}"RNDξOP'͗I I)6͜,^ <ӣuE\~[xZ,_qSE.S$EA]HKl)RrէxT]ۼ:S)a1^.CP .L9B F$#19B~Qf$qT̨-v;N4@8)dY$a^|u}21f~\SZ>'LՑ-wIhJxjڼh?$ ~I~u=sQbGI'9vr8J&Nokw6u_M?ht6r+L;Pd'2̙1Yi d ߌdDTr? Ѹ!,NYzȟzNaQ{mdk!pV#N!8 By%EF!MOVsM;3'?B(=}_}/$6hH]sNt nt0`]a1gщl5Х (ߠ|'Lb&cia bP+ 8Y'㓿ƔR*1c nodcM\鲋'_/Aĸ20[Tj9 ,Ѓ7(+PQAe^h{v8H8MU'/_zL!{(~uztK5N#Gُ$w)s٣Q Fm1"݉$A~$TZ0iBL6b!5"ec8 h<ˤ4kF9wnh1G/ZTRPM?D0%{LFxK͒L; .z7n?bJ:3.iDNG^8 7_& ؈A+~uђ=R!=XBݞ\DQz^\ Wٲ:u,a ȦOWXpT* 4ޚ_Uߣ9.__IJ|}ACS!:,'G*" RPuS^w0nD  D$@~أ!&a,pw1;h{" I`+ZttIL{4 iS^H,C~/0#hY3={~>yw>)T# f\*h` 'Evdd7bv0_23Z8b!!ͦx>lrx ak{=Źj_P]یm(nCYvh"=ׂ~C|^X!ӝJ e#Dbh#*]6 ~%WgH &R֦˥- 6PC4(!#% Hw 0H0PH(twH7H( >dOxw=Gw4LBDys@#AV`F>%Q>lZDMݸ_է.L/c_ ʓGjn7OB"({ Q qcn]`1gkevS16T+M]ީH i?e}Zj6Kz 44:ڄ +QtC+ ${~Y&S'Vۡ9 E=3 ~h@ ^hw,'TKqӯ/8@G+mv:|f᫄O~jZ7wyb4{/ ^OW., H].P{=H3YdㅞsϼFdw}}@'Sʕp6#!3aDhl`|@h κLi߽$-C#ܧ!ri[cDz=Kŧ d**\^TEɐS=QR;cJOK@ xSF<Uը-paV|+yσ4wK-We<.gY$fԎ@#l)⧞bW?n? qs[lè.2pb@1y=ޘ.ll4%^{%[r>t.:?SiDzwhtIӃ/ [W%q*+|樜HSseN*GktVGwqps P*t6XaH]N^t{ժ! ;ǬoDP01<45#VzS8D T q] 2{,&؜A^l`^= bۺgByNH  $F EJZ"14qd)pO@V+Ʊe(u*TMEI\p/$50)^#[%eQ="9!Ё֙H4U?+sL!=|!':]gR {9 S ͉aIZ,T/?aZl,C˂$O\IlQ9ƟuJUHh%*W )Z{UIB:ʭxzscb-|)Vo&2S2uIb(iղ|9.Vw8کYRݹ:th?+mpІ:pvM~c@,{|zB[gCl[i6~E =-5Vl1Q6|1مl1 伅BN!w<8#tB1h,CZwcf0<> ܗ\e)2:").!i9 7rol˾F\&^nhS Όl R.Jڮ %fL֡l%uG]9KdM}H6նc_nhߠ|q7)"|\2xSvfڞj=YM 0 j ّcP3^r^%>rB8o^"08)#6EW',Um;+ f"hwY;|]x|zIuP_T7c8Ձ|ȩ}vN'|W1WvlhH9/#xʼU3T#4QP#C%J¿sY<h_MumetԠYdr㈘̌>̏~훾^]]T O*x*ִc N8ڏ ό}N,7zKP6ݙʑF5TKIҽ[/$[OR4^SJE^:{\o`F7r&>', ,wŅ9d44vDtA)? -Z"=\GeuEK[yE2x~c:B,Ėzŀ"a|Z;Z0hoF#~unTBlAgxǶN`Ц UwFw?pĮjJPF `u\W݋#޳,)a EPn=hjٓOڕEwPR{:u-)\ѧX|>~zkGtЫ-A濈v։,՗h:j@%/$hp;F@9"0SDbG]84XqTYFO,Z&.")i*\jzy\Z:r6YD [sM妦,9vN\ 3* -!~DQhsYG,p;}!:x*>dC쒙Jױ3]f.f9· jbx*GchVH pOU-Ը]O*бn Yҕv-F[,@ ;&p7Tjն&:=Zk$?J0|r0ޛh96nr7޾>KȊmNLϵ+1zBNy,|8J/771|+DTzQM&% 2h3с - qÝ/CNoo7/gg!GMg N MܻZ78Y׻>xl@ۢx&m^nfBrolLoUEk{͆NodX$ۆYv7)ϻ#K$mrlK2O}w?2Ǥ{? ĸb LyK(MmA),6nWb䚾3f3Q4:20aD2[,jLMMfbҦ;$e32aLXV{*NSdA]LD\t(J c(|TpVzY>?9g*r#ev[d5p{\sǾ$5!&M;%1(ͷu2TSr*L;ϊhRW=^XJ׻ŃJn|NݙpT Xb}qg4(vt9^eDQM3쇰 Y%} oTU,dp0hUb #n;< 6^ضoj&y OaYܮE"sORfĪ|?}>ggfV̯z2)@,/󪝭}5#:Dw ^3$, t5t6@ּuˌ92÷el#48R]PKQ8yyzuiF s7r$hW #p }$bӜl^mοlԕ)Ji$f8j7[_UPzxڽi1VxE~ick/E.+ٰdW0-.,x"hA1oBIIsalQX񑓷|Bl!)cF(T+|yuWz =ǧg`]C[bz{7G (O 受dbs4+ϘʚDOM%'3 Kn s plf1agH|,78Í^2nt{LdK_0do7~U:76H ^Mh$P+'Ahʇ[ۈ0ֵk}uqjǃ2ǵ NV*WifD0jaad/mHԯ`;jD%sN\0VIWs٩&}gauAC`T<_>%YEEөc՗5m/"|F\\ j^?<_ϓ]-j7NNIDjhH 6 ._݈Y%z`ݺo/) bNgq4DCɿLh# хiڕΕt h,L] T\DԘ}t/=a-/#-)œ˾kg>i%*ѻ4YA0ErA6֯Gn52\bPh9׿ QsMOCrD޼Ķ7XQϕ\0^}n92Õs ^4JšnI8*" BD]"t@_id2fqo>B kttuwy˳8IɎO"5wqSnJ7&G!VfrX{4$n%~iyv\DN? ^j|(RѕRuiQ؁xNՅ%Pp: _sHץ$r@(stJD'M; b c(S:T!WY֕$?b ȗz>k_b EL~|lPP[*9kl.o\1zo0s[^CMK\, 26x\uJ=8:д {~DdTiY:&Gl .{ܦD{ j5FE4lw3H e蓼+Qu23ԕpREgL)ώ3BG&X$au!e3?_XJ,/s0ӘACNW*UQI]"U)A4K"OWnTaa |/@6LD_h!Ǵ Y9PhĨ?^V,[VY m|0ԯئ9!%JuPG^aaz7U>%j8ؕgaBETot`opj۱kaEC8+Fm tB!$`fXD$9]lB#X)^y)6$u,#JV;(vQuN&o޻Z-ZRh[>'w e ֛+]Xʳ…5J&A^v^}bPQmREbf\j@^:Hk@Bj,NUZ$f` Tߒ!-`,P-3 k`H_0mEN5=w&l.i6܉ğ3Å;+sKvGDej.fd9O0rr{rj<q>XqImJjKA^.pjYq-u,UEOvF)xFm5ymfJ-,϶Gmjx66`? ` ܖg׶xs9zo,{l2jHGIfǗ`^VSuqg1 J[S=;*- oC`aY9Y?Fy}=s w^u g?hLOR&;'攂{;Tp&' LudVOɰ51BHpMhMۗӅ5<4,x%.= 9:F1haGY aaHe j[wG64dP=rl~.ֆ6ZTR- .r `/+H/qM'+-2 }ʵ^]uի,#3 Mk>C2ݨQzeq;Ϩ}k{p;ۤvAm'6qw9o=HW( x.qg$3{9 eX7fIc>xJz[:rW< ZB2}+ncpgSO⯺Y/]6+4>4 RK Rj):&K,Vdv˛Vtk\_]L˲ƌ1iTǻ@ Rzk̐SAQD\4rn"} j>g2D=^"i(,Mhݕ'["aҿ_+Ó3нF[%81~ldon^]i5eJuX=z)JytNگ)҇޹LCk4QB4.\~|?ͅ%>(QK wcQf9, 恥k;m,a lX.߆N2n^g`4)q&[DC-/? 4ͧ7+tb. k#p]g*h .<˾8 He0-SN+؄E$m "48h Q%&37{lBtk# ɾ`Ը`ΰ`lV6Wco0BX1qbS3XT%R4]+Msa|M{r׵]Sqи; Rpy0[0@wmBOLj@.|TߚTxNr nϾٮc⃢96`9!;w'oG@1mBW&NȐZT ㋾' W/;!?98.\ ou?c١Oe91q4 R~y1;W\eI}=-*5~ȴ]YFN k4mxPt@o>d9 28L}7\.M mOsEb@ )4z9ncġ£k1b^BU֏_JlZim 񡼇Ίz]^q1aݵҲiddZ]=$aXWI#$ 鸪g&p7E 2?FpT狣*q tv%Q6^b^I ( (o\eßnc69@|xn8 MJm)k%1q6$(H`hf/bO>qb|.]XD3ǞTaMw5̕ه X/WFLH~9U7>%t:|Lݸ1ƔU8ig~u~K#(BwZUg380|\ȉCt/C&C҈娪ToauFxϥDüژ*Cb{lؼi98V*Wc}uS[MF#}:GGw9Sp=k7w(Ee ‘@_R+Ӌ9\[ʮ^fЫF0t"[b7ʶgX+y 33IS_ ˾o @C~>QGYNDDG2]<Ix0,3Ŧ!3 mgvm }u9$4Й7jgW;5?& 澽ʏHd6ܓiٗ'22j6ADU K5q֫9w-jK=~KEG"=mRWmu]DEQ/J{SY*s*č$r94;_ &pQigdتOx~)> ޚC&cGDRRV]VczSSZޚ/bqsFb('T&d2>y>f@wL' g v1e&P"xbP<%n6Ǽptݽ'S;B6/$%)/;cڂ X!t\__]{hV wga$ p=0LN';8N>%Ģïˁӊ[.60v()K fLkIcorVʃgؿN A9OH 7uO*W\9M) ixVV+Ç~D,Dr[dŴ{Z% ex XzQĥIz{\jK`:Ew^x5j4@lS[iFg&*P$ZL`vj*P;'=pel_lT٭%^m~Ɏ2F˪^nW2`' ћM3=ȐXjK^{a/6~~TbȬDnWz}u| qn[$0Y׵m*`*!Ի>sN}jV)'#7.mgM̩/i6R[Kֺ5EN̈??8-?aDot~p}Zc,XbPka-[|c2 <]=h+H|9U s u(<|2Gȣ=y8Ef(:N pc>9j[rbxkO]bZј˔vi,egu[R;S뜗@"ۇ!x~Fܰ[(ħ58!oB7 !\CLI435At=9Y=L֕e5h]>9dh4;V<*S9#o GחLb|Ӱ}$(\|NvbWD*^_|r]|h+rԦaGo{]ATݩN\P6URंg  ^=]e~r`p%1<@lČћKss,4X6*nq?;ߴc;=Qv.|DWraVڻ{͸Σ7IL9O`3"i XY[^دb-OE6PO:{Ua[NB2sZ$б#X'mpĈ AQ*ziH]>7~bXϔ5q)xYo`JqZl򬞳4 = oLfM'EnJ _vUctpkCUx{@rN?;6ls԰HcsâMvp>uṓd˫^nmo!=qw)wynKH `|0}lH*B_/Fb=]qՋ~܋{xl-k40p|v^|֍RU9V |\aK a=B7ZfЪb[>٠j@ c$L0?u5WYNR͹=̲»wUCA6km) QU7AVg`gT7Xv(!Vбt*n뛍66 2>X*JEyGH *z|*QF\e@y4҂vl%Y.z#c< ScK:j)~bg wqC:"1*ynKK1lf$0l({- s֛ tr0`yz~uy!!hT܇2@EmDDDFU3Fa7|wHL«{.r-~PtE;?BV,u d~$kgנ-C֧Jt:|U/WdHL@dV𰳲Qd?~: >}o+-ۤr$t *Ҏo974'otFwjӚ7e  <2 a.0(H[ */$Fwօa20mip8=rC[} O[I_x vޮvyׯd=^nB0濓~l9ecI=C _ǣboduXtZ/0,$ ?} 5=ʀ'0 RG]|\L[J:y>adKomV]VCqsm"\$oqH X8|GMP(x5! {.-,9 .K>x:Xb>֐rƐVwkVI`~`J@ {+:1k錿+@]/A1h_ovvlRd*b|0;EkI,i^|']:Yٳ8OlY- Si|?{y}Yhk8|EjX@8(;]7k3!lsG m4<Ox~'1V~- CFIxIcSA`R2h /T=)-g k1;!f싧e0?@ W Dl/ُ>J7m;Vi Jp`BRw"a*)gԩOʖ_aOgcB}$@iQT|>ކA1s"޷V3 dIȺN# X_OLBAM±3v}$9jQIqb! qyʧ0~']B6{䁀2ABjp$?<\~pztaN5$2|t ubad#k݋FJ51€V&zildggD22VU?{!e pb3Q Ys/([MF' ULb 85\Mg3vj:@ zCeb@[37 -< S$ǞiJ5oWWvgZߢLTM3=rJO4g@d.YُZ1 `V|h .>QlnR#)&ƨoص(Ǣi }/jAOF{Ksl`Sȏ?tcXԙi`44E 6^Q3f R}6m2%!mHh`q9Eʝm\5=PߋeM6vd>*-͚.M"Px:ǞCPQ/;cJSTOM3՚7]9laѶB  FriPA\feLj͆ d,MbWJ LJd5:&o ]~ /wuu q[bDDF} U\N;r_ ir u0ygsgOmxDcS-eCo2M ۥ!'ʃknhMThynRZ-$`;l'&]!G''++Q78\ԊѡthnkubwTaXA,۔*q߽aӵˤCp {X(n#z:m r}ցE`x~_L4 slQӋNϏbF$S&-TB`*.x竮gsӛ t;jOujlk!2%9rm6‘eS E*7%zR:ԃݣJ'x6^?F>w2}sF&6/N1gv`Vn.J|k. x!?frL>U:RByquS%*7 *ynbKJr( Ni#O(,ѽoA5=>`/%,>w1߼P:ح:r-NZ i+79zi.O'G[Kh_[o!7%ߣ"9F/A؀<@BMYKFPgK  xxx?̿ݟ oxyx`{_zڿ刏jg&ă__'_H+WW/_@o  }U{ǧq`?V 7ןNAw)Wfcbw3y}¿oK+6././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/webstorm/WebStorm-fake.tar.gz.sha256ubuntu-make-16.02.1/tests/data/server-content/data.services.jetbrains.com/webstorm/WebStorm-fake.tar0000664000000000000000000000012612656574623030366 0ustar 9aa3c7492528f64ee5435c58ba8fbf965dab8afb243287be7c09da68fdd35ba8 WebStorm-fake.tar.gz ubuntu-make-16.02.1/tests/data/server-content/netbeans.org/0000775000000000000000000000000012656574623020444 5ustar ubuntu-make-16.02.1/tests/data/server-content/netbeans.org/images_www/0000775000000000000000000000000012656574623022615 5ustar ubuntu-make-16.02.1/tests/data/server-content/netbeans.org/images_www/v6/0000775000000000000000000000000012656574623023150 5ustar ubuntu-make-16.02.1/tests/data/server-content/netbeans.org/images_www/v6/download/0000775000000000000000000000000012656574623024757 5ustar ubuntu-make-16.02.1/tests/data/server-content/netbeans.org/images_www/v6/download/8.0.42/0000775000000000000000000000000012656574623025510 5ustar ubuntu-make-16.02.1/tests/data/server-content/netbeans.org/images_www/v6/download/8.0.42/js/0000775000000000000000000000000012656574623026124 5ustar ubuntu-make-16.02.1/tests/data/server-content/netbeans.org/images_www/v6/download/8.0.42/js/files.js0000664000000000000000000001332412656574623027567 0ustar add_file("bundles/netbeans-8.0.2-cpp-linux.sh", 64918528, "285d6e80e29f81721c30484b46e777c5", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-cpp-macosx.dmg", 74669666, "8899b05d84fa8e811a6941db4741d941", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-cpp-windows.exe", 65278083, "7c3bab29057218f84cfa38195333af58", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-javaee-linux.sh", 193630208, "f32610617199535a571e38b3159cbaac", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-javaee-macosx.dmg", 232529311, "73f08bbf2cf4bb47d3a1f08d929700d2", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-javaee-windows.exe", 193989011, "4c6c95bf52f44d2f450510dca8a0cebd", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-javase-linux.sh", 93768704, "dba75e7ded8bd547453ba494c912701b", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-javase-macosx.dmg", 110086645, "613537a17e123c1faddfe9d5351d77c3", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-javase-windows.exe", 94127660, "a2e6c6493ed38b8ced245ca3db1f47c5", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-linux.sh", 207093760, "53db51921a647937102711304da8791b", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-macosx.dmg", 254750888, "9326a88ba7ef811dce17bfd8098f98c9", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-php-linux.sh", 65642496, "b3e48d280f008222870479da35fc543e", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-php-macosx.dmg", 75107146, "b811586702ebe7ea1a01a125aad5217f", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-php-windows.exe", 66001594, "a77c1173c410fd0268f497dd620e85a6", "en,ja,zh_CN,pt_BR,ru"); add_file("bundles/netbeans-8.0.2-windows.exe", 214031621, "88784c8af119d8c209ff9362e28ddb5f", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/hg-l10n-201411181905.zip", 398787, "ca1e063a47f0babd8264fe0692c51d6b", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/ide-l10n-201411181905.zip", 23231968, "c18b1485573239ec96dff074facc6fbf", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/netbeans-8.0.2-201411181905-cpp.zip", 111603456, "1e43d4f7f853bf1b566860bdbd3487a8", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/netbeans-8.0.2-201411181905-javaee.zip", 275221970, "fde236d943d5f627de0bd965d43fdb8c", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/netbeans-8.0.2-201411181905-javase.zip", 183444026, "04fe706d10b2f3d91f442c1a26d20a8d", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/netbeans-8.0.2-201411181905-php.zip", 111220461, "687c5b24d66ab1fca2570a82760b037a", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/netbeans-8.0.2-201411181905-platform-src.zip", 28703552, "fdb7e6631529ffe6eab6d861a2ec3821", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/netbeans-8.0.2-201411181905-src.zip", 196585461, "0adf2a4c7b49608f4046763ec4b89c4c", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/netbeans-8.0.42-201411181905.zip", 315562592, "1e07ec8775939ba6d35731831bdb7bf0", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/stableuc-l10n-201411181905.zip", 6998313, "5f75a9f5aaf05e2100532a486a04e245", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/testdist-201411181905.zip", 112315976, "61ff3f963dcd21b09e410e2188d43929", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-all-in-one.zip", 312895518, "ed2c0279eaa0385f95b162b10dbf9f73", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-apisupport.zip", 2841186, "2311b200773d173b4de8ae5a2f6ada5a", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-cnd.zip", 12834808, "3a493512ed50e5a97431bf4e02ecee7f", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-dlight.zip", 712651, "3bcd16886d1f97fc9cd376ef66420911", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-enterprise.zip", 89503039, "25b1525129f4d97b50e195e63caf5d6d", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-ergonomics.zip", 2297116, "9d9ac8f39f831dad616df1b128c7f9fa", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-extide.zip", 2718443, "742f2cbca50b1e984d7299866d038e0a", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-groovy.zip", 6821555, "2ca0687d9cca95dd769f1563a5fbaae6", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-harness.zip", 6494112, "190eb6510f4c4410f1c75157d4b4b9f1", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-ide.zip", 74187561, "a316941dda4f5b92cfa0bac77157d023", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-javacard.zip", 9207712, "37af5e0bf00fbcf665678a798dc802ea", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-java.zip", 74256455, "9e1dc93c3d59b7f640cedb5c69f40fb2", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-mobility.zip", 1990959, "be4ebb1a7da832be4dad961b08a4560f", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-nb-etc.zip", 1762454, "6d75e978a97c652f34e4aa51b6ea218d", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-php.zip", 6586741, "223dcb4b903d8d1425cdd503e8daaeaa", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-platform.zip", 16084644, "a6453755adcddcbde8ea6a7fc80287b8", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-profiler.zip", 5104067, "10643d587edc0e2590a761944ddfef7a", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-webcommon.zip", 7973598, "1dd5e493b876c125aeceed75a6126fb2", "en,ja,zh_CN,pt_BR,ru"); add_file("zip/moduleclusters/netbeans-8.0.2-201411181905-websvccommon.zip", 606041, "49b2b752a47b06058783261bc8f88bd1", "en,ja,zh_CN,pt_BR,ru"); ubuntu-make-16.02.1/tests/data/server-content/netbeans.org/downloads/0000775000000000000000000000000012656574623022436 5ustar ubuntu-make-16.02.1/tests/data/server-content/netbeans.org/downloads/zip.html0000664000000000000000000003362312656574623024135 0ustar
ubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/0000775000000000000000000000000012656574623022430 5ustar ubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/0000775000000000000000000000000012656574623025001 5ustar ubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/0000775000000000000000000000000012656574623026574 5ustar ubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/stable/0000775000000000000000000000000012656574623030046 5ustar ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/stable/release/ubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/stable/re0000775000000000000000000000000012656574623030375 5ustar ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/stable/release/1.12.1/ubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/stable/re0000775000000000000000000000000012656574623030375 5ustar ././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/stable/release/1.12.1/sdk/ubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/stable/re0000775000000000000000000000000012656574623030375 5ustar ././@LongLink0000644000000000000000000000022300000000000011600 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/stable/release/1.12.1/sdk/dartsdk-linux-x64-release.zipubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/stable/re0000664000000000000000000000051012656574623030373 0ustar PKuF dart-sdk/PKuF dart-sdk/bin/PK uFdart-sdk/bin/dartPK?uF Adart-sdk/PK?uF A'dart-sdk/bin/PK? uF Rdart-sdk/bin/dartPK././@LongLink0000644000000000000000000000022400000000000011601 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/stable/release/1.12.1/sdk/dartsdk-linux-ia32-release.zipubuntu-make-16.02.1/tests/data/server-content/storage.googleapis.com/dart-archive/channels/stable/re0000777000000000000000000000000012656574623034326 2dartsdk-linux-x64.zipustar ubuntu-make-16.02.1/tests/data/server-content/www.rust-lang.org/0000775000000000000000000000000012656574623021404 5ustar ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.rust-lang.org/rust-fake-i686-unknown-linux-gnu.tar.gz.sha256ubuntu-make-16.02.1/tests/data/server-content/www.rust-lang.org/rust-fake-i686-unknown-linux-gnu.tar0000664000000000000000000000015212656574623030126 0ustar 2a0db6efe370a900491d9e9db13e53ffd00b01dcd8458486f9f3fc3177f96af3 rust-fake-i686-unknown-linux-gnu.tar.gz ubuntu-make-16.02.1/tests/data/server-content/www.rust-lang.org/downloads.html0000664000000000000000000002676712656574623024306 0ustar Downloads · The Rust Programming Language

1.4.0 

October 29, 2015

The current stable release of Rust , updated every six weeks and backwards-compatible.

Linux (.tar.gz)
64-bit
32-bit
Mac (.pkg)
64-bit
32-bit
Windows (GNU ABI ) (.msi)
64-bit
32-bit
Windows (MSVC ABI ) (.msi)
64-bit
 
Source

An easy way to install the stable binaries for Linux and Mac is to run this in your shell:

$ curl -sSf https://static.rust-lang.org/rustup.sh | sh

Beta  (1.5)

A preview of the upcoming stable release, intended for testing by crate authors. Updated as needed.

Scheduled for stable release
December 10, 2015
.

Linux (.tar.gz)
64-bit
32-bit
Mac (.pkg)
64-bit
32-bit
Windows (GNU ABI ) (.msi)
64-bit
32-bit
Windows (MSVC ABI ) (.msi)
64-bit
 
Source

An easy way to install the beta binaries for Linux and Mac is to run this in your shell:

$ curl -sSf https://static.rust-lang.org/rustup.sh | sh -s -- --channel=beta

Nightly  (1.6)

The current development branch. It includes unstable features that are not available in the betas or stable releases.

Linux (.tar.gz)
64-bit
32-bit
Mac (.pkg)
64-bit
32-bit
Windows (GNU ABI ) (.msi)
64-bit
32-bit
Windows (MSVC ABI ) (.msi)
64-bit
32-bit
 
Source

An easy way to install the nightly binaries for Linux and Mac is to run this in your shell:

$ curl -sSf https://static.rust-lang.org/rustup.sh | sh -s -- --channel=nightly

Discover other downloads in the archives.


There are two prominent ABIs in use on Windows: the native (MSVC) ABI used by Visual Studio, and the GNU ABI used by the GCC toolchain. Which version of Rust you need depends largely on what C/C++ libraries you want to interoperate with: for interop with software produced by Visual Studio use the MSVC build of Rust; for interop with GNU software built using the MinGW/MSYS2 toolchain use the GNU build.

MSVC builds of Rust additionally require an installation of Visual Studio 2013 (or later) so rustc can use its linker. No additional software installation is necessary for basic use of the GNU build.

Rust's support for the GNU ABI is more mature, and is recommended for typical uses.

././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.rust-lang.org/rust-fake-x86_64-unknown-linux-gnu.tar.gzubuntu-make-16.02.1/tests/data/server-content/www.rust-lang.org/rust-fake-x86_64-unknown-linux-gnu.t0000664000000000000000000000067212656574623030054 0ustar !pVN wݧ8V:0E]m=eلh~pΦuL"%SdHJ"(KL״żR*O;׿ymG_L )=?Ô9>8\ݿDA@\.[/Dy^?re#mSӹo.FCu>2)w ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.rust-lang.org/rust-fake-i686-unknown-linux-gnu.tar.gzubuntu-make-16.02.1/tests/data/server-content/www.rust-lang.org/rust-fake-i686-unknown-linux-gnu.tar0000777000000000000000000000000012656574623037530 2rust-fake-x86_64-unknown-linux-gnu.tar.gzustar ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootubuntu-make-16.02.1/tests/data/server-content/www.rust-lang.org/rust-fake-x86_64-unknown-linux-gnu.tar.gz.sha256ubuntu-make-16.02.1/tests/data/server-content/www.rust-lang.org/rust-fake-x86_64-unknown-linux-gnu.t0000664000000000000000000000015412656574623030047 0ustar 2a0db6efe370a900491d9e9db13e53ffd00b01dcd8458486f9f3fc3177f96af3 rust-fake-x86_64-unknown-linux-gnu.tar.gz ubuntu-make-16.02.1/tests/data/server-content/golang.org/0000775000000000000000000000000012656574623020114 5ustar ubuntu-make-16.02.1/tests/data/server-content/golang.org/dl/0000775000000000000000000000000012656574623020513 5ustar ubuntu-make-16.02.1/tests/data/server-content/golang.org/dl/index.html0000664000000000000000000012567112656574623022524 0ustar Downloads - The Go Programming Language

Downloads

After downloading a binary release suitable for your system, please follow the installation instructions.

If you are building from source, follow the source installation instructions.

Stable versions

go1.3.3 ▾

File name Kind OS Arch SHA1 Checksum
go1.3.3.src.tar.gz Source b54b7deb7b7afe9f5d9a3f5dd830c7dede35393a
go1.3.3.darwin-386-osx10.6.tar.gz Archive OS X 10.6+ 32-bit 04b3e38549183e984f509c07ad40d8bcd577a702
go1.3.3.darwin-386-osx10.8.tar.gz Archive OS X 10.8+ 32-bit 88f35d3327a84107aac4f2f24cb0883e5fdbe0e5
go1.3.3.darwin-386-osx10.6.pkg Installer OS X 10.6+ 32-bit 49756b700670ae4109e555f2e5f9bedbaa3c50da
go1.3.3.darwin-386-osx10.8.pkg Installer OS X 10.8+ 32-bit a89b570a326e5f8c9509f40be9fa90e54b3bf7a7
go1.3.3.darwin-amd64-osx10.6.tar.gz Archive OS X 10.6+ 64-bit dfe68de684f6e8d9c371d01e6d6a522efe3b8942
go1.3.3.darwin-amd64-osx10.8.tar.gz Archive OS X 10.8+ 64-bit be686ec7ba68d588735cc2094ccab8bdd651de9e
go1.3.3.darwin-amd64-osx10.6.pkg Installer OS X 10.6+ 64-bit 9aec7e9eff11100a6db026d1b423d1250925e4c4
go1.3.3.darwin-amd64-osx10.8.pkg Installer OS X 10.8+ 64-bit 6435e50059fe7fa0d60f1b15aab7f255a61816ce
go1.3.3.freebsd-386.tar.gz Archive FreeBSD 32-bit 875a5515dd7d3e5826c7c003bb2450f3129ccbad
go1.3.3.freebsd-amd64.tar.gz Archive FreeBSD 64-bit 8531ae5e745c887f8dad1a3f00ca873cfcace56e
go1.3.3.linux-386.tar.gz Archive Linux 32-bit c26c1bb756f83e63d0dc850c2128367d17b99af09c7e5407e8e7de50e9716d41
go1.3.3.linux-amd64.tar.gz Archive Linux 64-bit c26c1bb756f83e63d0dc850c2128367d17b99af09c7e5407e8e7de50e9716d41
go1.3.3.windows-386.zip Archive Windows 32-bit ba99083b22e0b22b560bb2d28b9b99b405d01b6b
go1.3.3.windows-386.msi Installer Windows 32-bit 6017a0e1667a5a41109f527b405bf6e0c83580f5
go1.3.3.windows-amd64.zip Archive Windows 64-bit 5f0b3b104d3db09edd32ef1d086ba20bafe01ada
go1.3.3.windows-amd64.msi Installer Windows 64-bit 25112a8c4df93dc4009e65eff00bc4ef76f94e46

go1.3.2 ▾

File name Kind OS Arch SHA1 Checksum
go1.3.2.src.tar.gz Source 67d3a692588c259f9fe9dca5b80109e5b99271df
go1.3.2.darwin-386-osx10.6.tar.gz Archive OS X 10.6+ 32-bit d1652f6e0ed3063b7b43d2bc12981d927bc85deb
go1.3.2.darwin-386-osx10.8.tar.gz Archive OS X 10.8+ 32-bit d040c85698c749fdbe25e8568c4d71648a5e3a75
go1.3.2.darwin-386-osx10.6.pkg Installer OS X 10.6+ 32-bit d20375615cf8e36e3c9a9b6ddeef16eff7a4ea89
go1.3.2.darwin-386-osx10.8.pkg Installer OS X 10.8+ 32-bit f11930cfb032d39ab445f342742865c93c60ec14
go1.3.2.darwin-amd64-osx10.6.tar.gz Archive OS X 10.6+ 64-bit 36ca7e8ac9af12e70b1e01182c7ffc732ff3b876
go1.3.2.darwin-amd64-osx10.8.tar.gz Archive OS X 10.8+ 64-bit 323bf8088614d58fee2b4d2cb07d837063d7d77e
go1.3.2.darwin-amd64-osx10.6.pkg Installer OS X 10.6+ 64-bit e1529241fcef643e5f752c37dc4c86911df91338
go1.3.2.darwin-amd64-osx10.8.pkg Installer OS X 10.8+ 64-bit fd8637658fcb133423e794c44029ce3476b48e0c
go1.3.2.freebsd-386.tar.gz Archive FreeBSD 32-bit fea3ef264120b5c3b4c50a8929d56f47a8366503
go1.3.2.freebsd-amd64.tar.gz Archive FreeBSD 64-bit 95b633f45156fbbe79076638f854e76b9cd01301
go1.3.2.linux-386.tar.gz Archive Linux 32-bit 3cbfd62d401a6ca70779856fa8ad8c4d6c35c8cc
go1.3.2.linux-amd64.tar.gz Archive Linux 64-bit 0e4b6120eee6d45e2e4374dac4fe7607df4cbe42
go1.3.2.windows-386.zip Archive Windows 32-bit 86160c478436253f51241ac1905577d337577ce0
go1.3.2.windows-386.msi Installer Windows 32-bit 589c35f9ad3506c92aa944130f6a950ce9ee558b
go1.3.2.windows-amd64.zip Archive Windows 64-bit 7f7147484b1bc9e52cf034de816146977d0137f6
go1.3.2.windows-amd64.msi Installer Windows 64-bit a697fff05cbd4a4d902f6c33f7c42588bcc474bc

go1.3.1 ▾

File name Kind OS Arch SHA1 Checksum
go1.3.1.src.tar.gz Source bc296c9c305bacfbd7bff9e1b54f6f66ae421e6e
go1.3.1.darwin-386-osx10.6.tar.gz Archive OS X 10.6+ 32-bit 84f70a4c83be24cea696654a5b55331ea32f8a3f
go1.3.1.darwin-386-osx10.8.tar.gz Archive OS X 10.8+ 32-bit 244dfba1f4239b8e2eb9c3abae5ad63fc32c807a
go1.3.1.darwin-386-osx10.6.pkg Installer OS X 10.6+ 32-bit 16e0df7b90d49c8499f71a551af8b595e2faa961
go1.3.1.darwin-386-osx10.8.pkg Installer OS X 10.8+ 32-bit 13296cd9a980819bf2304d7d24a38a1b39719c13
go1.3.1.darwin-amd64-osx10.6.tar.gz Archive OS X 10.6+ 64-bit 40716361d352c4b40252e79048e8bc084c3f3d1b
go1.3.1.darwin-amd64-osx10.8.tar.gz Archive OS X 10.8+ 64-bit a7271cbdc25173d0f8da66549258ff65cca4bf06
go1.3.1.darwin-amd64-osx10.6.pkg Installer OS X 10.6+ 64-bit 49bf5f14d2683fb99161fcb7025af60ec2d3691f
go1.3.1.darwin-amd64-osx10.8.pkg Installer OS X 10.8+ 64-bit 5d4728e0b3c3fd9fc657cc192c6b9fb3f837823b
go1.3.1.freebsd-386.tar.gz Archive FreeBSD 32-bit 586debe95542b3b56841f6bd2e5257e301a1ffdc
go1.3.1.freebsd-amd64.tar.gz Archive FreeBSD 64-bit 99e23fdd33860d837912e8647ed2a4b3d2b09d3c
go1.3.1.linux-386.tar.gz Archive Linux 32-bit 36f87ce21cdb4cb8920bb706003d8655b4e1fc81
go1.3.1.linux-amd64.tar.gz Archive Linux 64-bit 3af011cc19b21c7180f2604fd85fbc4ddde97143
go1.3.1.windows-386.zip Archive Windows 32-bit 64f99e40e79e93a622e73d7d55a5b8340f07747f
go1.3.1.windows-386.msi Installer Windows 32-bit df37e307c52fbea02070e23ae0a49cb869d54f33
go1.3.1.windows-amd64.zip Archive Windows 64-bit 4548785cfa3bc228d18d2d06e39f58f0e4e014f1
go1.3.1.windows-amd64.msi Installer Windows 64-bit 88c5d9a51a74c2846226a08681fc28cd3469cba0

go1.3 ▾

File name Kind OS Arch SHA1 Checksum
go1.3.src.tar.gz Source 9f9dfcbcb4fa126b2b66c0830dc733215f2f056e
go1.3.darwin-386-osx10.6.tar.gz Archive OS X 10.6+ 32-bit 159d2797bee603a80b829c4404c1fb2ee089cc00
go1.3.darwin-386-osx10.8.tar.gz Archive OS X 10.8+ 32-bit bade975462b5610781f6a9fe8ac13031b3fb7aa6
go1.3.darwin-386-osx10.6.pkg Installer OS X 10.6+ 32-bit 07e7142540558f432a8750eb6cb25d6b06ed80bb
go1.3.darwin-386-osx10.8.pkg Installer OS X 10.8+ 32-bit c908ecdb177c8a20abd61272c260b15e513f6e73
go1.3.darwin-amd64-osx10.6.tar.gz Archive OS X 10.6+ 64-bit 82ffcfb7962ca7114a1ee0a96cac51c53061ea05
go1.3.darwin-amd64-osx10.8.tar.gz Archive OS X 10.8+ 64-bit 8d768f10cd00e0b152490291d9cd6179a8ccf0a7
go1.3.darwin-amd64-osx10.6.pkg Installer OS X 10.6+ 64-bit 631d6867d7f4b92b314fd87115e1cefadeeac2ab
go1.3.darwin-amd64-osx10.8.pkg Installer OS X 10.8+ 64-bit 4e8f2cafa23797211fd13f3fa4893ce3d5f084c4
go1.3.freebsd-386.tar.gz Archive FreeBSD 32-bit 8afa9574140cdd5fc97883a06a11af766e7f0203
go1.3.freebsd-amd64.tar.gz Archive FreeBSD 64-bit 71214bafabe2b5f52ee68afce96110031b446f0c
go1.3.linux-386.tar.gz Archive Linux 32-bit 22db33b0c4e242ed18a77b03a60582f8014fd8a6
go1.3.linux-amd64.tar.gz Archive Linux 64-bit b6b154933039987056ac307e20c25fa508a06ba6
go1.3.windows-386.zip Archive Windows 32-bit e4e5279ce7d8cafdf210a522a70677d5b9c7589d
go1.3.windows-386.msi Installer Windows 32-bit d457a86ce6701bb96608e4c33778b8471c48a764
go1.3.windows-amd64.zip Archive Windows 64-bit 1e4888e1494aed7f6934acb5c4a1ffb0e9a022b1
go1.3.windows-amd64.msi Installer Windows 64-bit e81a0e4f551722c7682f912e0485ad20a287f2ef

go1.2.2 ▾

File name Kind OS Arch SHA1 Checksum
go1.2.2.src.tar.gz Source 3ce0ac4db434fc1546fec074841ff40dc48c1167
go1.2.2.darwin-386-osx10.6.tar.gz Archive OS X 10.6+ 32-bit 360ec6cbfdec9257de029f918a881b9944718d7c
go1.2.2.darwin-386-osx10.8.tar.gz Archive OS X 10.8+ 32-bit 4219b464e82e7c23d9dc02c193e7a0a28a09af1a
go1.2.2.darwin-386-osx10.6.pkg Installer OS X 10.6+ 32-bit dff27e94c8ff25301cd958b0b1b629e97ea21f03
go1.2.2.darwin-386-osx10.8.pkg Installer OS X 10.8+ 32-bit f1fb44aa22cba3e81dc33f88393a54e49eae0d8b
go1.2.2.darwin-amd64-osx10.6.tar.gz Archive OS X 10.6+ 64-bit 24c182718fd61b2621692dcdfc34937a6b5ee369
go1.2.2.darwin-amd64-osx10.8.tar.gz Archive OS X 10.8+ 64-bit 19be1eca8fc01b32bb6588a70773b84cdce6bed1
go1.2.2.darwin-amd64-osx10.6.pkg Installer OS X 10.6+ 64-bit 2d4b49f1105a78e1ea31d7f9ea0b43909cc209be
go1.2.2.darwin-amd64-osx10.8.pkg Installer OS X 10.8+ 64-bit 5d78f2a3fe82b01fe5dfcb267e703e754274b253
go1.2.2.freebsd-386.tar.gz Archive FreeBSD 32-bit d226b8e1c3f75d31fa426df63aa776d7e08cddac
go1.2.2.freebsd-amd64.tar.gz Archive FreeBSD 64-bit 858744ab8ff9661d42940486af63d451853914a0
go1.2.2.linux-386.tar.gz Archive Linux 32-bit d16f892173b0589945d141cefb22adce57e3be9c
go1.2.2.linux-amd64.tar.gz Archive Linux 64-bit 6bd151ca49c435462c8bf019477a6244b958ebb5
go1.2.2.windows-386.zip Archive Windows 32-bit 560bb33ec70ab733f31ff15f1a48fe35963983b9
go1.2.2.windows-386.msi Installer Windows 32-bit 60b91a7bf68596b23978acb109d1ff8668b7d18f
go1.2.2.windows-amd64.zip Archive Windows 64-bit 9ee22fe6c4d98124d582046aab465ab69eaab048
go1.2.2.windows-amd64.msi Installer Windows 64-bit c8f5629bc8d91b161840b4a05a3043c6e5fa310b

Unstable versions

go1.4beta1 ▾

This is an unstable version of Go. Use with caution.

File name Kind OS Arch SHA1 Checksum
go1.4beta1.src.tar.gz Source f2fece0c9f9cdc6e8a85ab56b7f1ffcb57c3e7cd
go1.4beta1.darwin-386-osx10.6.tar.gz Archive OS X 10.6+ 32-bit a360e7c8f1d528901e721d0cc716461f8a636823
go1.4beta1.darwin-386-osx10.8.tar.gz Archive OS X 10.8+ 32-bit d863907870e8e79850a7a725b398502afd1163d8
go1.4beta1.darwin-386-osx10.6.pkg Installer OS X 10.6+ 32-bit ee4d1f74c35eddbdc49e9fb01e86a971e1bb54a7
go1.4beta1.darwin-386-osx10.8.pkg Installer OS X 10.8+ 32-bit c118f624262a1720317105d116651f8fb4b80383
go1.4beta1.darwin-amd64-osx10.6.tar.gz Archive OS X 10.6+ 64-bit ad8798fe744bb119f0e8eeacf97be89763c5f12a
go1.4beta1.darwin-amd64-osx10.8.tar.gz Archive OS X 10.8+ 64-bit e08df216d9761c970e438295129721ec8374654a
go1.4beta1.darwin-amd64-osx10.6.pkg Installer OS X 10.6+ 64-bit 831e95cc381cc1afd6c4bfa886e86790f1c96de6
go1.4beta1.darwin-amd64-osx10.8.pkg Installer OS X 10.8+ 64-bit dc0b5805ba117654dd95c84ce7872406380de3d5
go1.4beta1.freebsd-386.tar.gz Archive FreeBSD 32-bit 65045b7a5d2a991a45b1e86ad11252bc84043651
go1.4beta1.freebsd-amd64.tar.gz Archive FreeBSD 64-bit 42fbd5336437dde85b34d774bfed111fe579db88
go1.4beta1.linux-386.tar.gz Archive Linux 32-bit 122ea6cae37d9b62c69efa3e21cc228e41006b75
go1.4beta1.linux-amd64.tar.gz Archive Linux 64-bit d2712acdaa4469ce2dc57c112a70900667269ca0
go1.4beta1.windows-386.zip Archive Windows 32-bit a6d75ca59b70226087104b514389e48d49854ed4
go1.4beta1.windows-386.msi Installer Windows 32-bit 1f8d11306d733bec975f2d747b26810926348517
go1.4beta1.windows-amd64.zip Archive Windows 64-bit 386deea0a7c384178aedfe48e4ee2558a8cd43d8
go1.4beta1.windows-amd64.msi Installer Windows 64-bit ec3ec78072128d725878404a5ce27bd1c1e7132b

go1.3rc2 ▾

This is an unstable version of Go. Use with caution.

File name Kind OS Arch SHA1 Checksum
go1.3rc2.src.tar.gz Source 53a5b75c8bb2399c36ed8fe14f64bd2df34ca4d9
go1.3rc2.darwin-386-osx10.6.tar.gz Archive OS X 10.6+ 32-bit 600433eccda28b91b2afe566142bce759d154b49
go1.3rc2.darwin-386-osx10.8.tar.gz Archive OS X 10.8+ 32-bit 36fa30bfdeb8560c5d9ae57f02ec0cdb33613cb5
go1.3rc2.darwin-386-osx10.6.pkg Installer OS X 10.6+ 32-bit c41c4e55017d3d835cf66feaaf18eeaeabaa066a
go1.3rc2.darwin-386-osx10.8.pkg Installer OS X 10.8+ 32-bit 4cbdcccac38eed1ebffbbf1eba594724e5d05a77
go1.3rc2.darwin-amd64-osx10.6.tar.gz Archive OS X 10.6+ 64-bit 84c25957096d4700f342c10f82f1f720bf646f6e
go1.3rc2.darwin-amd64-osx10.8.tar.gz Archive OS X 10.8+ 64-bit 1bd241130b5e7a3eb4876fbb17257b16ea9db67d
go1.3rc2.darwin-amd64-osx10.6.pkg Installer OS X 10.6+ 64-bit 18c8ed409a7ba97a61e00f00982361d7c84f7fdb
go1.3rc2.darwin-amd64-osx10.8.pkg Installer OS X 10.8+ 64-bit 33d2129c26ea0cb5f147fa5f24395c8ed5c4433f
go1.3rc2.freebsd-386.tar.gz Archive FreeBSD 32-bit 3e5394e0f4eb99c32510dda48eb4dc1af9717a41
go1.3rc2.freebsd-amd64.tar.gz Archive FreeBSD 64-bit bbaba53742cf43d96abca710cf49fe8c0ede6673
go1.3rc2.linux-386.tar.gz Archive Linux 32-bit 7462cb654712ef6785ccae5b75ed393de6f49da2
go1.3rc2.linux-amd64.tar.gz Archive Linux 64-bit 3a7d86a3245b4c8bd4dc5b1ff4e0073c2d1b81b5
go1.3rc2.windows-386.zip Archive Windows 32-bit f3f7a995baf77742b813723bc823d584466cb26f
go1.3rc2.windows-386.msi Installer Windows 32-bit a1138a6f7d22768eac73dfb254a1af8531aaeb1b
go1.3rc2.windows-amd64.zip Archive Windows 64-bit 607b6ed4830785d166d83029a76e6975b2e99068
go1.3rc2.windows-amd64.msi Installer Windows 64-bit dba588d51f9b9353c7bdc271cecea065eea06250

go1.3rc1 ▾

This is an unstable version of Go. Use with caution.

File name Kind OS Arch SHA1 Checksum
go1.3rc1.src.tar.gz Source 6a9dac2e65c07627fe51899e0031e298560b0097
go1.3rc1.darwin-386-osx10.6.tar.gz Archive OS X 10.6+ 32-bit a15031c21871d9ffb567c7d204653b32f0d84737
go1.3rc1.darwin-386-osx10.8.tar.gz Archive OS X 10.8+ 32-bit 7ace88dfe731c38e83cee27f23eb2588419cf249
go1.3rc1.darwin-386-osx10.6.pkg Installer OS X 10.6+ 32-bit 8de0f308c51cec5fcec45fde762967723ef61eb9
go1.3rc1.darwin-386-osx10.8.pkg Installer OS X 10.8+ 32-bit 498e0840c44258e6b29eb5aa34b2fb3c31e79fdd
go1.3rc1.darwin-amd64-osx10.6.tar.gz Archive OS X 10.6+ 64-bit d250f20d84c310aa82053dea16743b223bbf933a
go1.3rc1.darwin-amd64-osx10.8.tar.gz Archive OS X 10.8+ 64-bit e3fb91fcfa2dfa97e451de9048ec5788713bc94e
go1.3rc1.darwin-amd64-osx10.6.pkg Installer OS X 10.6+ 64-bit 02e6537c9a3f0cc80dcf901b40683eeab6d8bebf
go1.3rc1.darwin-amd64-osx10.8.pkg Installer OS X 10.8+ 64-bit 17c42d6e6b5ca99fcd1e6927a79652d7e630a226
go1.3rc1.freebsd-386.tar.gz Archive FreeBSD 32-bit 953a95277ef06da98f0b8d7bb9bd02f4846374ff
go1.3rc1.freebsd-amd64.tar.gz Archive FreeBSD 64-bit 3c0a03ee5a64f6db46298fa3ad26d577ef7b2db5
go1.3rc1.linux-386.tar.gz Archive Linux 32-bit 07c656173c444e4373a799141c1cb28128a345eb
go1.3rc1.linux-amd64.tar.gz Archive Linux 64-bit affaccfd69a694e0aa59466450e4db5260aeb1a3
go1.3rc1.windows-386.zip Archive Windows 32-bit d43c973adede9e8f18118a2924d8b825352db50a
go1.3rc1.windows-386.msi Installer Windows 32-bit 23534cce0db1f8c0cc0cf0f70472df59ac26bbfa
go1.3rc1.windows-amd64.zip Archive Windows 64-bit 312358b64711fd827f9dfb0cef61383f9eb5057b
go1.3rc1.windows-amd64.msi Installer Windows 64-bit d089fbe3c12b8ec8d3e30526b3eb604c9ae84c7d

Older versions

Older releases of Go are available at Google Code.

ubuntu-make-16.02.1/tests/data/server-content/golang.org/fake.go.linux-386.tar.gz0000664000000000000000000000036312656574623024233 0ustar ƶXTһN0`~S U$mj#'}|Bz :r||ߕOXlrd^034V3Tn #@ Ww_KU>ٸ6?q9GV*K/씿5?>߬sgV+ah)I]6_V^urړCS$iO?O{$?(ubuntu-make-16.02.1/tests/data/server-content/golang.org/fake.go.linux-amd64.tar.gz0000777000000000000000000000000012656574623030734 2fake.go.linux-386.tar.gzustar ubuntu-make-16.02.1/tests/data/server-content/www.scala-lang.org/0000775000000000000000000000000012656574623021472 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.scala-lang.org/fake-scala.tgz0000664000000000000000000000037412656574623024213 0ustar :UN0UOI[(=,{C7A t,&C\ZZJ6qmME֚SmܤIN4ؓ]}?5|_4w'\ç8_ez?,c+gbPq^tKJrI"IU4MwՂ|UbSu$5=w}s'_jO53N+/4.(ubuntu-make-16.02.1/tests/data/server-content/www.scala-lang.org/download/0000775000000000000000000000000012656574623023301 5ustar ubuntu-make-16.02.1/tests/data/server-content/www.scala-lang.org/download/index.html0000664000000000000000000003460612656574623025307 0ustar Download | The Scala Programming Language

Download

Choose one of three ways to get started with Scala!
1

Download Scala 2.11.7 binaries for your system (All downloads).

Need help installing?

~ or ~
2

Get started with Typesafe Activator
Typesafe Activator is a browser-based or command-line
tool that helps developers get started with Scala.

~ or ~

Release Notes

For important changes, please consult the release notes.

Software Requirements

The Scala software distribution can be installed on any platform with a Java runtime, version 1.6 or later.

Additional information

You can find the links to prior versions or the latest development version below. To see a detailed list of changes for each version of Scala please refer to the changelog. Note that the different major releases of Scala (e.g. Scala 2.9.3 and Scala 2.10.1) are not binary compatible.

License

The Scala distribution is released under the 3-clause BSD license.
ubuntu-make-16.02.1/tests/daily_runs/0000775000000000000000000000000012656574623014341 5ustar ubuntu-make-16.02.1/tests/daily_runs/install_build_tests_depends0000775000000000000000000000051512656574623022041 0ustar #!/bin/bash # install test depends from autopkgtests requirements and build-deps # devscripts and equivs are needed for mk-build-deps apt -y --no-install-recommends install $(grep Depends debian/tests/control | tr -d , | tr -d @ | sed 's/Depends: builddeps//') devscripts equivs mk-build-deps -i -t "apt -y --no-install-recommends" ubuntu-make-16.02.1/tests/daily_runs/get_binary_depends0000775000000000000000000000457212656574623020124 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import argparse import sys if __name__ == '__main__': parser = argparse.ArgumentParser(description="Parse debian/control for provided binary package and echo all " "dependencies.") parser.add_argument("binary", help="binary package name to grab dependencies") args = parser.parse_args() try: in_binary_section = False in_depends_section = False depends = [] with open("debian/control") as f: for line in f.readlines(): line = line.rstrip() if line == "Package: {}".format(args.binary): in_binary_section = True if not in_binary_section: continue if line.startswith("Depends: "): line = line.replace("Depends: ", "") in_depends_section = True elif line.startswith("Recommends: "): line = line.replace("Recommends: ", "") in_depends_section = True else: # we are getting out of the depends or binary sections if not line: in_binary_section = False elif line[0] != " ": in_depends_section = False if not in_depends_section: continue line_deps = line.split(",") depends.extend([dep.strip() for dep in line_deps if (dep.strip() != "" and dep.strip()[0] != "$")]) except OSError: print("Can't find debian/control") sys.exit(1) print(" ".join(depends)) ubuntu-make-16.02.1/tests/small/0000775000000000000000000000000012656574623013300 5ustar ubuntu-make-16.02.1/tests/small/test_frameworks_loader.py0000664000000000000000000016717312656574623020436 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests the framework loader""" import argparse from contextlib import suppress import importlib import os import shutil import sys import tempfile from ..data.testframeworks.uninstantiableframework import Uninstantiable, InheritedFromUninstantiable from ..tools import get_data_dir, change_xdg_path, patchelem, LoggedTestCase, INSTALL_DIR import umake from umake import frameworks from umake.frameworks.baseinstaller import BaseInstaller from umake.settings import UMAKE_FRAMEWORKS_ENVIRON_VARIABLE from umake.tools import NoneDict, ConfigHandler from unittest.mock import Mock, patch, call class BaseFrameworkLoader(LoggedTestCase): """Unload and reload the module to ensure we clean all class dict""" @classmethod def setUpClass(cls): super().setUpClass() importlib.reload(frameworks) cls.CategoryHandler = frameworks.BaseCategory def setUp(self): """Ensure we don't have any config file loaded""" super().setUp() change_xdg_path('XDG_CONFIG_HOME', self.config_dir_for_name("foo")) def tearDown(self): change_xdg_path('XDG_CONFIG_HOME', remove=True) # we reset the loaded categories self.CategoryHandler.categories = NoneDict() super().tearDown() def config_dir_for_name(self, name): """Return the config dir for this name""" return os.path.join(get_data_dir(), 'configs', name) def fake_arch_version(self, arch, version): """Help to mock the current arch and version on further calls""" self._saved_current_arch_fn = umake.frameworks.get_current_arch self.get_current_arch_mock = Mock() self.get_current_arch_mock.return_value = arch umake.frameworks.get_current_arch = self.get_current_arch_mock self._saved_current_ubuntu_version_fn = umake.frameworks.get_current_ubuntu_version self.get_current_ubuntu_version_mock = Mock() self.get_current_ubuntu_version_mock.return_value = version umake.frameworks.get_current_ubuntu_version = self.get_current_ubuntu_version_mock def restore_arch_version(self): """Restore initial current arch and version""" umake.frameworks.get_current_arch = self._saved_current_arch_fn umake.frameworks.get_current_ubuntu_version = self._saved_current_ubuntu_version_fn class TestFrameworkLoader(BaseFrameworkLoader): """This will test the dynamic framework loader activity""" @classmethod def setUpClass(cls): super().setUpClass() sys.path.append(get_data_dir()) cls.testframeworks_dir = os.path.join(get_data_dir(), 'testframeworks') @classmethod def tearDownClass(cls): sys.path.remove(get_data_dir()) super().tearDownClass() def setUp(self): super().setUp() # fake versions and archs self.fake_arch_version("bar", "10.10.10") # load custom framework-directory with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "testframeworks"): frameworks.load_frameworks() self.categoryA = self.CategoryHandler.categories["category-a"] def tearDown(self): self.restore_arch_version() super().tearDown() def test_load_main_category(self): """The main category is loaded""" self.assertEqual(len([1 for category in self.CategoryHandler.categories.values() if category.is_main_category]), 1, str(self.CategoryHandler.categories.values())) def test_get_main_category(self): """main_category property returns main category""" main_category = [category for category in self.CategoryHandler.categories.values() if category.is_main_category][0] self.assertEqual(self.CategoryHandler.main_category, main_category) def test_load_category(self): """There is at least one category (not main) loaded""" self.assertTrue(len([1 for category in self.CategoryHandler.categories.values() if not category.is_main_category]) > 0, str(self.CategoryHandler.categories.values())) def test_get_category_by_prog_name(self): """categories index returns matching category""" category = self.CategoryHandler.categories["category-a"] self.assertEqual(category.name, "Category A") def test_get_framework_by_prog_name(self): """Framework index returns matching framework""" framework = self.categoryA.frameworks["framework-a"] self.assertEqual(framework.name, "Framework A") def test_get_category_not_existing(self): """the call to get category returns None when there is no match""" self.assertIsNone(self.CategoryHandler.categories["foo"]) def test_get_category_prog_name(self): """prog_name for category is what we expect""" self.assertEqual(self.categoryA.prog_name, "category-a") self.assertEqual(self.CategoryHandler.categories["category-b"].prog_name, "category-b") def test_multiple_files_loaded(self): """We load multiple categories in different files""" # main category, + at least 2 other categories self.assertTrue(len(self.CategoryHandler.categories) > 2, str(self.CategoryHandler.categories)) self.assertIsNotNone(self.categoryA) self.assertIsNotNone(self.CategoryHandler.categories["category-b"]) def test_frameworks_loaded(self): """We have frameworks attached to a category""" self.assertTrue(len(self.categoryA.frameworks) > 1, str(self.categoryA.frameworks)) self.assertTrue(self.categoryA.has_frameworks()) def test_framework_not_existing(self): """the call to get a framework returns None when there is no match""" self.assertIsNone(self.categoryA.frameworks["foo"]) def test_frameworks_doesn_t_mix(self): """Frameworks, even with the same name, don't mix between categories""" self.assertNotEqual(self.categoryA.frameworks["framework-a"], self.CategoryHandler.categories["category-b"].frameworks["framework-a"]) def test_has_more_than_one_framework(self): """more than one frameworks in a category is correctly reported""" self.assertFalse(self.categoryA.has_one_framework()) def test_empty_category_loaded(self): """We still load an empty category""" self.assertIsNotNone(self.CategoryHandler.categories["empty-category"]) def test_has_frameworks_on_empty_category(self): """has_frameworks return False on empty category""" self.assertFalse(self.CategoryHandler.categories["empty-category"].has_frameworks()) self.assertFalse(self.CategoryHandler.categories["empty-category"].has_one_framework()) def test_one_framework_category(self): """A category with one framework is reported as so""" self.assertTrue(self.CategoryHandler.categories["one-framework-category"].has_one_framework()) def test_framework_prog_name(self): """prog_name for framework is what we expect""" self.assertEqual(self.categoryA.frameworks["framework-a"].prog_name, "framework-a") self.assertEqual(self.categoryA.frameworks["framework-b"].prog_name, "framework-b") def test_nothing_installed(self): """Category returns that no framework is installed""" self.assertEqual(self.categoryA.is_installed, self.CategoryHandler.NOT_INSTALLED) def test_category_fully_installed(self): """Category returns than all frameworks are installed""" self.assertEqual(self.CategoryHandler.categories["category-b"].is_installed, self.CategoryHandler.FULLY_INSTALLED) def test_category_half_installed(self): """Category returns than half frameworks are installed""" self.assertEqual(self.CategoryHandler.categories["category-c"].is_installed, self.CategoryHandler.PARTIALLY_INSTALLED) def test_frameworks_loaded_in_main_category(self): """Some frameworks are loaded and attached to main category""" self.assertTrue(len(self.CategoryHandler.main_category.frameworks) > 1, str(self.CategoryHandler.main_category.frameworks)) self.assertIsNotNone(self.CategoryHandler.main_category.frameworks["framework-free-a"]) self.assertIsNotNone(self.CategoryHandler.main_category.frameworks["framework-free---b"]) def test_frameworks_report_installed(self): """Frameworks have an is_installed property""" category = self.CategoryHandler.categories["category-c"] self.assertFalse(category.frameworks["framework-a"].is_installed) self.assertTrue(category.frameworks["framework-b"].is_installed) def test_default_framework(self): """Test that a default framework flag is accessible""" framework_default = self.categoryA.frameworks["framework-a"] self.assertEqual(self.categoryA.default_framework, framework_default) def test_default_install_path(self): """Default install path is what we expect, based on category-and framework prog_name""" self.assertEqual(self.categoryA.frameworks["framework-b"].install_path, os.path.expanduser("~/{}/category-a/framework-b".format(INSTALL_DIR))) def test_specified_at_load_install_path(self): """Default install path is overriden by framework specified install path at load time""" self.assertEqual(self.categoryA.frameworks["framework-a"].install_path, os.path.expanduser("~/{}/custom/frameworka".format(INSTALL_DIR))) def test_no_restriction_installable_framework(self): """Framework with an no arch or version restriction is installable""" self.assertTrue(self.categoryA.frameworks["framework-a"].is_installable) def test_right_arch_right_version_framework(self): """Framework with a correct arch and correct version is installable""" self.assertTrue(self.CategoryHandler.categories["category-d"].frameworks["framework-c"].is_installable) def test_unsupported_arch_framework(self): """Framework with an unsupported arch isn't registered""" self.assertIsNone(self.CategoryHandler.categories["category-d"].frameworks["framework-a"]) def test_unsupported_version_framework(self): """Framework with an unsupported arch isn't registered""" self.assertIsNone(self.CategoryHandler.categories["category-d"].frameworks["framework-b"]) def test_child_installable_chained_parent(self): """Framework with an is_installable chained to parent""" self.assertTrue(self.CategoryHandler.categories["category-e"].frameworks["framework-a"].is_installable) def test_child_installable_overridden(self): """Framework with an is_installable override to True from children (with unmatched restrictions)""" self.assertTrue(self.CategoryHandler.categories["category-e"].frameworks["framework-b"].is_installable) def test_child_installable_overridden_false(self): """Framework with an is_installable override to False from children (with no restrictions)""" self.assertIsNone(self.CategoryHandler.categories["category-e"].frameworks["framework-c"]) def test_check_not_installed_wrong_path(self): """Framework isn't installed path doesn't exist""" self.assertFalse(self.CategoryHandler.categories["category-f"].frameworks["framework-a"].is_installed) def test_check_installed_right_path_no_package_req(self): """Framework is installed if right path but no package req.""" self.assertTrue(self.CategoryHandler.categories["category-f"].frameworks["framework-b"].is_installed) def test_check_unmatched_requirements_not_installed(self): """Framework with unmatched requirements are not registered""" self.assertIsNone(self.CategoryHandler.categories["category-f"].frameworks["framework-c"]) def test_no_root_need_if_no_requirements(self): """Framework with not requirements don't need root access""" self.assertFalse(self.categoryA.frameworks["framework-a"].need_root_access) def test_uninstalled_framework_marked_for_removal_only_not_registered(self): """Uninstalled framework marked for removal only isn't not registered (as we can't install it back)""" self.assertIsNone(self.CategoryHandler.categories["category-r"].frameworks["framework-r-uninstalled"]) def test_installed_framework_not_installable_registered(self): """Installed framework not installable are still registered (can be used for removal)""" self.assertIsNotNone(self.CategoryHandler.categories["category-r"] .frameworks["framework-r-installed-not-installable"]) def test_installed_framework_marked_for_removal_only_registered(self): """Installed framework marked for removal only is registered to be able to remove it""" self.assertIsNotNone(self.CategoryHandler.categories["category-r"].frameworks["framework-r-installed"]) def test_installed_framework_marked_for_removal_only_not_installable(self): """Installed framework that are marked for removal only are not installable""" self.assertFalse(self.CategoryHandler.categories["category-r"].frameworks["framework-r-installed"] .is_installable) def test_parse_category_and_framework_run_correct_framework(self): """Parsing category and framework return right category and framework""" args = Mock() args.category = "category-a" args.destdir = None args.framework = "framework-b" args.accept_license = False args.remove = False with patch.object(self.CategoryHandler.categories[args.category].frameworks["framework-b"], "setup")\ as setup_call: self.CategoryHandler.categories[args.category].run_for(args) self.assertTrue(setup_call.called) self.assertEqual(setup_call.call_args, call(install_path=None, auto_accept_license=False)) def test_parse_no_framework_run_default_for_category(self): """Parsing category will run default framework""" args = Mock() args.category = "category-a" args.destdir = None args.framework = None args.accept_license = False args.remove = False with patch.object(self.CategoryHandler.categories[args.category].frameworks["framework-a"], "setup")\ as setup_call: self.CategoryHandler.categories[args.category].run_for(args) self.assertTrue(setup_call.called) self.assertEqual(setup_call.call_args, call(install_path=None, auto_accept_license=False)) def test_parse_category_and_framework_run_correct_remove_framework(self): """Parsing category and framework with --remove run remove on right category and framework""" args = Mock() args.category = "category-a" args.destdir = None args.framework = "framework-b" args.accept_license = False args.remove = True with patch.object(self.CategoryHandler.categories[args.category].frameworks["framework-b"], "remove")\ as remove_call: self.CategoryHandler.categories[args.category].run_for(args) self.assertTrue(remove_call.called) remove_call.assert_called_with() def test_parse_no_framework_run_default_remove_for_category(self): """Parsing category with --remove will run default framework removal action""" args = Mock() args.category = "category-a" args.framework = None args.remove = True args.accept_license = False args.destdir = None with patch.object(self.CategoryHandler.categories[args.category].frameworks["framework-a"], "remove")\ as remove_call: self.CategoryHandler.categories[args.category].run_for(args) self.assertTrue(remove_call.called) remove_call.assert_called_with() def test_parse_no_framework_with_no_default_returns_errors(self): """Parsing a category with no default returns an error when calling run""" args = Mock() args.category = "category-b" args.framework = None args.accept_license = False args.remove = False self.assertRaises(BaseException, self.CategoryHandler.categories[args.category].run_for, args) self.expect_warn_error = True def test_parse_category_and_framework_cannot_run_remove_with_destdir_framework(self): """Parsing category and framework with remove and destdir raises an error""" args = Mock() args.category = "category-a" args.framework = "framework-b" args.remove = True args.accept_license = False self.assertRaises(BaseException, self.CategoryHandler.categories[args.category].run_for, args) self.expect_warn_error = True def test_parse_category_and_framework_cannot_install_not_installable_but_installed_framework(self): """We cannot install frameworks that are not installable but already installed (and so, registered)""" self.expect_warn_error = True args = Mock() args.category = "category-r" args.destdir = None args.framework = "framework-r-installed-not-installable" args.accept_license = False args.remove = False self.assertRaises(BaseException, self.CategoryHandler.categories[args.category].run_for, args) def test_parse_category_and_framework_can_remove_not_installable_but_installed_framework(self): """Parsing category and frameworks with --remove can remove not installable but installed framework""" args = Mock() args.category = "category-r" args.destdir = None args.framework = "framework-r-installed" args.accept_license = False args.remove = True with patch.object(self.CategoryHandler.categories[args.category].frameworks["framework-r-installed"], "remove")\ as remove_call: self.CategoryHandler.categories[args.category].run_for(args) self.assertTrue(remove_call.called) remove_call.assert_called_with() def test_parse_category_and_framework_get_accept_license_arg(self): """Parsing category and framework get the accept license arg""" args = Mock() args.category = "category-a" args.destdir = None args.framework = "framework-b" args.accept_license = True args.remove = False with patch.object(self.CategoryHandler.categories[args.category].frameworks["framework-b"], "setup")\ as setup_call: self.CategoryHandler.categories[args.category].run_for(args) self.assertTrue(setup_call.called) self.assertEqual(setup_call.call_args, call(install_path=None, auto_accept_license=True)) def test_uninstantiable_framework(self): """A uninstantiable framework isn't loaded""" # use the string as we fake the package when loading them self.assertNotIn(str(Uninstantiable).split('.')[-1], [str(type(framework)).split('.')[-1] for framework in self.CategoryHandler.main_category.frameworks.values()]) def test_inherited_from_uninstantiable_framework(self): """We can attach a framework which inherit from an uninstantiable one""" # use the string as we fake the package when loading them self.assertIn(str(InheritedFromUninstantiable).split('.')[-1], [str(type(framework)).split('.')[-1] for framework in self.CategoryHandler.main_category.frameworks.values()]) class TestFrameworkLoaderWithValidConfig(BaseFrameworkLoader): """This will test the dynamic framework loader activity with a valid configuration""" @classmethod def setUpClass(cls): super().setUpClass() sys.path.append(get_data_dir()) cls.testframeworks_dir = os.path.join(get_data_dir(), 'testframeworks') @classmethod def tearDownClass(cls): sys.path.remove(get_data_dir()) super().tearDownClass() def setUp(self): # load valid configuration super().setUp() change_xdg_path('XDG_CONFIG_HOME', self.config_dir_for_name("valid")) # load custom framework-directory with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "testframeworks"): frameworks.load_frameworks() self.categoryA = self.CategoryHandler.categories["category-a"] def tearDown(self): change_xdg_path('XDG_CONFIG_HOME', remove=True) super().tearDown() def test_config_override_defaults(self): """Configuration override defaults (explicit or implicit). If not present in config, still load default""" # was overridden with at load time self.assertEqual(self.categoryA.frameworks["framework-a"].install_path, "/home/didrocks/quickly/ubuntu-make/adt-eclipse") # was default self.assertEqual(self.categoryA.frameworks["framework-b"].install_path, "/home/didrocks/foo/bar/android-studio") # isn't in the config self.assertEqual(self.CategoryHandler.categories['category-c'].frameworks["framework-a"].install_path, os.path.expanduser("~/{}/category-c/framework-a".format(INSTALL_DIR))) class TestFrameworkLoaderSaveConfig(BaseFrameworkLoader): """This will test the dynamic framework loader activity being able to save some configurations""" @classmethod def setUpClass(cls): super().setUpClass() sys.path.append(get_data_dir()) cls.testframeworks_dir = os.path.join(get_data_dir(), 'testframeworks') @classmethod def tearDownClass(cls): sys.path.remove(get_data_dir()) super().tearDownClass() def setUp(self): super().setUp() # load custom framework-directory with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "testframeworks"): frameworks.load_frameworks() self.categoryA = self.CategoryHandler.categories["category-a"] self.config_dir = tempfile.mkdtemp() change_xdg_path('XDG_CONFIG_HOME', self.config_dir) def tearDown(self): change_xdg_path('XDG_CONFIG_HOME', remove=True) shutil.rmtree(self.config_dir) super().tearDown() def test_call_mark_in_config_save_config(self): """Calling mark_in_config save path in the configuration""" # load custom framework-directory self.categoryA.frameworks["framework-b"].mark_in_config() self.assertEqual(ConfigHandler().config, {'frameworks': { 'category-a': { 'framework-b': { 'path': os.path.expanduser('~/{}/category-a/framework-b'.format(INSTALL_DIR)) }}}}) def test_call_setup_save_and_then_mark_in_config_tweaked_path(self): """Calling mark_in_config with a custom install path save it in the configuration""" # load custom framework-directory fw = self.categoryA.frameworks["framework-b"] fw.setup() fw.install_path = "/home/foo/bar" self.categoryA.frameworks["framework-b"].mark_in_config() self.assertEqual(ConfigHandler().config, {'frameworks': { 'category-a': { 'framework-b': {'path': '/home/foo/bar'} }}}) def test_call_remove_from_config(self): """Calling remove_from_config remove a framework from the config""" ConfigHandler().config = {'frameworks': { 'category-a': { 'framework-b': {'path': os.path.expanduser('~/{}/category-a/framework-b'.format(INSTALL_DIR))} }}} self.categoryA.frameworks["framework-b"].remove_from_config() self.assertEqual(ConfigHandler().config, {'frameworks': {'category-a': {}}}) def test_call_remove_from_config_keep_other(self): """Calling remove_from_config remove a framework from the config but keep others""" ConfigHandler().config = {'frameworks': { 'category-a': { 'framework-b': {'path': os.path.expanduser('~/{}/category-a/framework-b'.format(INSTALL_DIR))}, 'framework-c': {'path': os.path.expanduser('~/{}/category-a/framework-c'.format(INSTALL_DIR))} }, 'category-b': { 'framework-b': {'path': os.path.expanduser('~/{}/category-a/framework-b'.format(INSTALL_DIR))} }}} self.categoryA.frameworks["framework-b"].remove_from_config() self.assertEqual(ConfigHandler().config, {'frameworks': { 'category-a': { 'framework-c': { 'path': os.path.expanduser('~/{}/category-a/framework-c'.format(INSTALL_DIR)) }}, 'category-b': { 'framework-b': { 'path': os.path.expanduser('~/{}/category-a/framework-b'.format(INSTALL_DIR)) }}}}) class TestFrameworkLoadOnDemandLoader(BaseFrameworkLoader): """This will test the dynamic framework loader activity. This class doesn't load frameworks before the tests does""" @classmethod def setUpClass(cls): super().setUpClass() sys.path.append(get_data_dir()) cls.testframeworks_dir = os.path.join(get_data_dir(), 'testframeworks') @classmethod def tearDownClass(cls): sys.path.remove(get_data_dir()) super().tearDownClass() def setUp(self): super().setUp() # fake versions and archs self.fake_arch_version("foo", "10.04") def tearDown(self): self.restore_arch_version() super().tearDown() def loadFramework(self, framework_name): """Load framework name""" with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', framework_name): frameworks.load_frameworks() def install_category_parser(self, main_parser, categories=[]): """Install parser for those categories""" categories_parser = main_parser.add_subparsers(dest="category") category_parsers = [] for category in categories: with patch('umake.frameworks.is_completion_mode') as completionmode_mock: completionmode_mock.return_value = False self.loadFramework("testframeworks") category_parsers.append(self.CategoryHandler.categories[category] .install_category_parser(categories_parser)) return category_parsers def test_arch_report_issue_framework(self): """Framework where we can't reach arch and having a restriction isn't installable""" self.get_current_arch_mock.side_effect = BaseException('arch detection failure!') self.loadFramework("testframeworks") # restricted arch framework isn't installable self.assertIsNone(self.CategoryHandler.categories["category-d"].frameworks["framework-a"]) # framework with no arch restriction but others are still installable self.assertTrue(self.CategoryHandler.categories["category-d"].frameworks["framework-b"].is_installable) # framework without any restriction is still installable self.assertTrue(self.CategoryHandler.categories["category-a"].frameworks["framework-a"].is_installable) self.expect_warn_error = True def test_version_report_issue_framework(self): """Framework where we can't reach version and having a restriction isn't installable""" self.get_current_ubuntu_version_mock.side_effect = BaseException('version detection failure!') self.loadFramework("testframeworks") # restricted version framework isn't installable self.assertIsNone(self.CategoryHandler.categories["category-d"].frameworks["framework-b"]) # framework with no version restriction but others are still installable self.assertTrue(self.CategoryHandler.categories["category-d"].frameworks["framework-a"].is_installable) # framework without any restriction is still installable self.assertTrue(self.CategoryHandler.categories["category-a"].frameworks["framework-a"].is_installable) self.expect_warn_error = True def test_check_not_installed_wrong_requirements(self): """Framework isn't installed if path and package requirements aren't met""" with patch('umake.frameworks.RequirementsHandler') as requirement_mock: requirement_mock.return_value.is_bucket_installed.return_value = False self.loadFramework("testframeworks") self.assertFalse(self.CategoryHandler.categories["category-f"].frameworks["framework-c"].is_installed) requirement_mock.return_value.is_bucket_installed.assert_called_with(['foo', 'bar']) # is_bucket_available is called when it's not installed requirement_mock.return_value.is_bucket_available.assert_has_calls([call(['foo', 'bar'])]) def test_check_installed_with_matched_requirements(self): """Framework is installed if path and package requirements are met""" with patch('umake.frameworks.RequirementsHandler') as requirement_mock: requirement_mock.return_value.is_bucket_installed.return_value = True self.loadFramework("testframeworks") self.assertTrue(self.CategoryHandler.categories["category-f"].frameworks["framework-c"].is_installed) requirement_mock.return_value.is_bucket_installed.assert_called_with(['foo', 'bar']) # we don't call is_bucket_available if requirements are met self.assertFalse(call(['foo', 'bar']) in requirement_mock.return_value.is_bucket_available.call_args_list) def test_check_requirements_inherited_from_category(self): """Framework without package requirements are inherited from category""" with patch('umake.frameworks.RequirementsHandler') as requirement_mock: self.loadFramework("testframeworks") self.assertEqual(self.CategoryHandler.categories["category-g"].frameworks["framework-b"] .packages_requirements, ["baz"]) def test_check_requirements_from_category_merge_into_exiting(self): """Framework with package requirements merged them from the associated category""" with patch('umake.frameworks.RequirementsHandler') as requirement_mock: self.loadFramework("testframeworks") self.assertEqual(self.CategoryHandler.categories["category-g"].frameworks["framework-a"] .packages_requirements, ["buz", "biz", "baz"]) def test_root_needed_if_not_matched_requirements(self): """Framework with unmatched requirements need root access""" with patch('umake.frameworks.RequirementsHandler') as requirement_mock: requirement_mock.return_value.is_bucket_installed.return_value = False self.loadFramework("testframeworks") self.assertTrue(self.CategoryHandler.categories["category-f"].frameworks["framework-c"].need_root_access) def test_no_root_needed_if_matched_requirements_even_uninstalled(self): """Framework which are uninstalled but with matched requirements doesn't need root access""" with patch('umake.frameworks.RequirementsHandler') as requirement_mock: requirement_mock.return_value.is_bucket_installed.return_value = True self.loadFramework("testframeworks") # ensure the framework isn't installed, but the bucket being installed, we don't need root access self.assertFalse(self.CategoryHandler.categories["category-f"].frameworks["framework-a"].is_installed) self.assertFalse(self.CategoryHandler.categories["category-f"].frameworks["framework-a"].need_root_access) def test_root_needed_setup_call_root(self): """Framework with root access needed call sudo""" with patch('umake.frameworks.subprocess') as subprocess_mock,\ patch.object(umake.frameworks.os, 'geteuid', return_value=1000) as geteuid,\ patch('umake.frameworks.MainLoop') as mainloop_mock,\ patch('umake.frameworks.RequirementsHandler') as requirement_mock: requirement_mock.return_value.is_bucket_installed.return_value = False self.loadFramework("testframeworks") self.assertTrue(self.CategoryHandler.categories["category-f"].frameworks["framework-c"].need_root_access) self.CategoryHandler.categories["category-f"].frameworks["framework-c"].setup() self.assertEqual(subprocess_mock.call.call_args[0][0][0], "sudo") self.assertTrue(mainloop_mock.return_value.quit.called) def test_no_root_needed_setup_doesnt_call_root(self): """Framework without root access needed don't call sudo""" with patch('umake.frameworks.subprocess') as subprocess_mock,\ patch.object(umake.frameworks.os, 'geteuid', return_value=1000) as geteuid,\ patch.object(umake.frameworks.sys, 'exit', return_value=True) as sys_exit_mock,\ patch('umake.frameworks.RequirementsHandler') as requirement_mock: requirement_mock.return_value.is_bucket_installed.return_value = True self.loadFramework("testframeworks") self.assertFalse(self.CategoryHandler.categories["category-f"].frameworks["framework-c"].need_root_access) self.CategoryHandler.categories["category-f"].frameworks["framework-c"].setup() self.assertFalse(subprocess_mock.call.called) self.assertFalse(sys_exit_mock.called) def test_root_needed_setup_doesnt_call_root(self): """setup doesn't call sudo if we are already root""" with patch('umake.frameworks.subprocess') as subprocess_mock,\ patch.object(umake.frameworks.sys, 'exit', return_value=True) as sys_exit_mock,\ patch.object(umake.frameworks.os, 'geteuid', return_value=0) as geteuid,\ patch('umake.frameworks.RequirementsHandler') as requirement_mock,\ patch('umake.frameworks.switch_to_current_user') as switch_to_current_use_mock: requirement_mock.return_value.is_bucket_installed.return_value = False self.loadFramework("testframeworks") self.assertTrue(self.CategoryHandler.categories["category-f"].frameworks["framework-c"].need_root_access) self.CategoryHandler.categories["category-f"].frameworks["framework-c"].setup() self.assertFalse(subprocess_mock.call.called) self.assertFalse(sys_exit_mock.called) geteuid.assert_called_once_with() switch_to_current_use_mock.assert_called_once_with() def test_completion_mode_dont_use_expensive_calls(self): """Completion mode bypass expensive calls and so, register all frameworks but those marked as only for removal (so read config)""" with patch('umake.frameworks.ConfigHandler') as config_handler_mock,\ patch('umake.frameworks.RequirementsHandler') as requirementhandler_mock,\ patch('umake.frameworks.is_completion_mode') as completionmode_mock: completionmode_mock.return_value = True self.loadFramework("testframeworks") self.assertTrue(completionmode_mock.called) self.assertFalse(requirementhandler_mock.return_value.is_bucket_installed.called) # test that a non installed framework is registered self.assertIsNotNone(self.CategoryHandler.categories["category-e"].frameworks["framework-c"]) def test_use_expensive_calls_when_not_in_completion_mode(self): """Non completion mode have expensive calls and don't register all frameworks""" with patch('umake.frameworks.ConfigHandler') as config_handler_mock,\ patch('umake.frameworks.RequirementsHandler') as requirementhandler_mock,\ patch('umake.frameworks.is_completion_mode') as completionmode_mock: completionmode_mock.return_value = False self.loadFramework("testframeworks") self.assertTrue(completionmode_mock.called) self.assertTrue(len(config_handler_mock.return_value.config.mock_calls) > 0, str(config_handler_mock.return_value.config.mock_calls)) self.assertTrue(requirementhandler_mock.return_value.is_bucket_installed.called) # test that a non installed framework is registered self.assertIsNone(self.CategoryHandler.categories["category-e"].frameworks["framework-c"]) def test_install_category_and_framework_parsers(self): """Install category and framework parsers contains works""" main_parser = argparse.ArgumentParser() categories_parser = main_parser.add_subparsers() with patch('umake.frameworks.is_completion_mode') as completionmode_mock: completionmode_mock.return_value = False self.loadFramework("testframeworks") category_parser = self.CategoryHandler.categories['category-a'].install_category_parser(categories_parser) self.assertTrue('category-a' in categories_parser.choices) self.assertTrue('framework-a' in category_parser.choices) self.assertTrue('framework-b' in category_parser.choices) def test_parse_category_and_framework(self): """Parsing category and framework return right category and framework""" main_parser = argparse.ArgumentParser() self.install_category_parser(main_parser, ['category-a']) args = main_parser.parse_args(["category-a", "framework-a"]) self.assertEqual(args.category, "category-a") self.assertEqual(args.framework, "framework-a") self.assertEqual(args.destdir, None) def test_parse_framework(self): """Parsing framework get default parser framework options""" main_parser = argparse.ArgumentParser() self.install_category_parser(main_parser, ['category-a']) args = main_parser.parse_args(["category-a", "framework-a"]) self.assertEqual(args.category, "category-a") self.assertEqual(args.framework, "framework-a") self.assertEqual(args.destdir, None) self.assertFalse(args.remove) with self.assertRaises(AttributeError): args.accept_license def test_parse_framework_with_optional_accept_license(self): """Parsing framework with optional auto accept license argument""" main_parser = argparse.ArgumentParser() self.install_category_parser(main_parser, ['category-a']) args = main_parser.parse_args(["category-a", "framework-b", "--accept-license"]) self.assertEqual(args.category, "category-a") self.assertEqual(args.framework, "framework-b") self.assertEqual(args.destdir, None) self.assertFalse(args.remove) self.assertTrue(args.accept_license) def test_parse_invalid_categories_raise_exit_error(self): """Invalid categories parse requests exit""" def error_without_message(x): raise SystemExit() main_parser = argparse.ArgumentParser() main_parser.print_usage = lambda x: "" main_parser.error = error_without_message self.install_category_parser(main_parser, []) self.assertRaises(SystemExit, main_parser.parse_args, ["category-a", "framework-a"]) def test_parse_invalid_frameworks_return_error(self): """Invalid framework parse requests exit""" def error_without_message(x): raise SystemExit() main_parser = argparse.ArgumentParser() self.install_category_parser(main_parser, ["category-a"]) category_parser = main_parser._actions[1].choices["category-a"] category_parser.print_usage = lambda x: "" category_parser.error = error_without_message self.assertRaises(SystemExit, main_parser.parse_args, ["category-a", "framework-aa"]) def test_parse_no_category_return_empty_namespace(self): """No category or framework returns an empty namespace""" main_parser = argparse.ArgumentParser() self.install_category_parser(main_parser, ['category-a']) self.assertEqual(main_parser.parse_args([]), argparse.Namespace(category=None)) def test_install_category_with_no_framework(self): """Install category with no framework returns None""" main_parser = argparse.ArgumentParser() self.assertEqual(self.install_category_parser(main_parser, ['empty-category']), [None]) def test_install_main_category(self): """Main category install directly at root of the parser""" main_parser = argparse.ArgumentParser() main_cat_parser = self.install_category_parser(main_parser, ['main'])[0] self.assertTrue('framework-free---b' in main_cat_parser.choices) self.assertTrue('framework-free-a' in main_cat_parser.choices) self.assertFalse('framework-a' in main_cat_parser.choices) def test_parse_main_category(self): """Main category elements can be directly accessed""" main_parser = argparse.ArgumentParser() self.install_category_parser(main_parser, ['main']) args = main_parser.parse_args(["framework-free-a"]) self.assertEqual(args.category, "framework-free-a") self.assertEqual(args.destdir, None) self.assertFalse("framework" in args) def test_run_framework_in_main_category(self): """Frameworks command from main category can be run as usual""" main_parser = argparse.ArgumentParser() self.install_category_parser(main_parser, ['main']) args = main_parser.parse_args(["framework-free-a"]) with patch.object(self.CategoryHandler.main_category.frameworks["framework-free-a"], "setup") as setup_call: self.CategoryHandler.main_category.frameworks["framework-free-a"].run_for(args) self.assertTrue(setup_call.called) class TestEmptyFrameworkLoader(BaseFrameworkLoader): """This will test the dynamic framework loader activity with an empty set of frameworks""" @classmethod def setUpClass(cls): super().setUpClass() sys.path.append(get_data_dir()) cls.testframeworks_dir = os.path.join(get_data_dir(), 'testframeworksdoesntexist') @classmethod def tearDownClass(cls): sys.path.remove(get_data_dir()) super().tearDownClass() def setUp(self): super().setUp() # load custom unexisting framework-directory with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "testframeworksdoesntexist"): frameworks.load_frameworks() def test_invalid_framework(self): """There is one main category, but nothing else""" main_category = [category for category in self.CategoryHandler.categories.values() if category.is_main_category][0] self.assertEqual(self.CategoryHandler.main_category, main_category) self.assertEqual(len(self.CategoryHandler.categories), 1, str(self.CategoryHandler.categories)) class TestDuplicatedFrameworkLoader(BaseFrameworkLoader): """This will test the dynamic framework loader activity with some duplicated categories and frameworks""" @classmethod def setUpClass(cls): super().setUpClass() sys.path.append(get_data_dir()) cls.testframeworks_dir = os.path.join(get_data_dir(), 'duplicatedframeworks') @classmethod def tearDownClass(cls): sys.path.remove(get_data_dir()) super().tearDownClass() def setUp(self): super().setUp() with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "duplicatedframeworks"): frameworks.load_frameworks() self.categoryA = self.CategoryHandler.categories["category-a"] self.expect_warn_error = True # as we load multiple duplicate categories and frameworks def test_duplicated_categories(self): """We only load one category when a second with same name is met""" # main + categoryA self.assertEqual(len(self.CategoryHandler.categories), 2, str(self.CategoryHandler.categories)) self.assertEqual(self.CategoryHandler.categories["category-a"].name, "Category A") def test_duplicated_frameworks(self): """We only load one framework when a second with the same name is met""" self.assertEqual(len(self.categoryA.frameworks), 1, str(self.categoryA.frameworks)) def test_main_category_empty(self): """The main category (unused here) is empty by default""" self.assertEqual(len(self.CategoryHandler.main_category.frameworks), 0, str(self.CategoryHandler.main_category.frameworks)) class TestMultipleDefaultFrameworkLoader(BaseFrameworkLoader): """This will test if we try to load multiple default frameworsk in loader""" @classmethod def setUpClass(cls): super().setUpClass() sys.path.append(get_data_dir()) cls.testframeworks_dir = os.path.join(get_data_dir(), 'multipledefaultsframeworks') @classmethod def tearDownClass(cls): sys.path.remove(get_data_dir()) super().tearDownClass() def setUp(self): super().setUp() with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "multipledefaultsframeworks"): frameworks.load_frameworks() self.categoryA = self.CategoryHandler.categories["category-a"] self.expect_warn_error = True # as we load multiple default frameworks in a category def test_multiple_defaults(self): """Setting multiple defaults frameworks to a category should void any default""" self.assertIsNone(self.categoryA.default_framework) self.assertEqual(len(self.categoryA.frameworks), 2, str(self.categoryA.frameworks)) # ensure they are still loaded def test_one_default_in_main_category(self): """Reject default framework for main category""" self.assertIsNone(self.CategoryHandler.main_category.default_framework) self.assertEqual(len(self.CategoryHandler.main_category.frameworks), 1, str(self.CategoryHandler.main_category.frameworks)) # ensure it's still loaded class TestNotLoadedFrameworkLoader(BaseFrameworkLoader): def setUp(self): super().setUp() self.CategoryHandler = frameworks.BaseCategory def test_get_no_main_category(self): """main_category returns None when there is no main category""" self.assertIsNone(self.CategoryHandler.main_category) def test_get_with_no_category(self): """categories is empty when there is no category loaded""" self.assertEqual(len(self.CategoryHandler.categories), 0, str(self.CategoryHandler.categories)) class TestAbstractFrameworkLoader(BaseFrameworkLoader): """Test the loader skips abstract frameworks.""" @classmethod def setUpClass(cls): super().setUpClass() sys.path.append(get_data_dir()) cls.testframeworks_dir = os.path.join(get_data_dir(), 'abstractframeworks') @classmethod def tearDownClass(cls): sys.path.remove(get_data_dir()) super().tearDownClass() def setUp(self): super().setUp() # load custom unexisting framework-directory with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "abstractframeworks"): frameworks.load_frameworks() self.categoryA = self.CategoryHandler.categories["category-a"] def test_load(self): """Previous loading should have been successful""" self.assertFalse(self.categoryA.has_frameworks()) self.expect_warn_error = False # Should be silent. class TestInvalidFrameworksLoader(BaseFrameworkLoader): """Test the loader handles badly formatted frameworks.""" @classmethod def setUpClass(cls): super().setUpClass() sys.path.append(get_data_dir()) cls.testframeworks_dir = os.path.join(get_data_dir(), 'invalidframeworks') @classmethod def tearDownClass(cls): sys.path.remove(get_data_dir()) super().tearDownClass() def test_invalid_framework_loading(self): """Frameworks that don't have a Framework type aren't loaded""" with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "invalidframeworks"): frameworks.load_frameworks() self.assertEqual(len(self.CategoryHandler.categories["category-a"].frameworks), 0, self.CategoryHandler.categories["category-a"].frameworks) class TestFrameworkLoaderCustom(BaseFrameworkLoader): """This will test the dynamic framework loader activity with custom path""" @classmethod def setUpClass(cls): super().setUpClass() sys.path.append(get_data_dir()) cls.testframeworks_dir = os.path.join(get_data_dir(), 'testframeworks') @classmethod def tearDownClass(cls): sys.path.remove(get_data_dir()) super().tearDownClass() def setUp(self): super().setUp() # fake versions and archs self.fake_arch_version("bar", "10.10.10") self.dirs_to_remove = [] def tearDown(self): self.restore_arch_version() with suppress(KeyError): os.environ.pop(UMAKE_FRAMEWORKS_ENVIRON_VARIABLE) for path in self.dirs_to_remove: sys.path.remove(path) with suppress(FileNotFoundError): shutil.rmtree(path) with suppress(ValueError): sys.path.remove(path) super().tearDown() @patch("umake.frameworks.get_user_frameworks_path") def test_load_additional_frameworks_in_home_dir(self, get_user_frameworks_path): """Ensure we load additional frameworks from home directory""" temp_path = tempfile.mkdtemp() self.dirs_to_remove.append(temp_path) shutil.copy(os.path.join(get_data_dir(), "overlayframeworks", "overlayframeworks.py"), temp_path) get_user_frameworks_path.return_value = temp_path # load home framework-directory with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "testframeworks"): frameworks.load_frameworks() # ensure that the overlay is loaded self.assertEqual(self.CategoryHandler.categories["category-a-overlay"].name, "Category A overlay") # ensure that the other frameworks are still loaded self.assertEqual(self.CategoryHandler.categories["category-a"].name, "Category A") def test_load_additional_frameworks_with_env_var(self): """Ensure we load additional frameworks set in an environment variable""" temp_path = tempfile.mkdtemp() self.dirs_to_remove.append(temp_path) os.environ[UMAKE_FRAMEWORKS_ENVIRON_VARIABLE] = temp_path shutil.copy(os.path.join(get_data_dir(), "overlayframeworks", "overlayframeworks.py"), temp_path) # load env framework-directory with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "testframeworks"): frameworks.load_frameworks() # ensure that the overlay is loaded self.assertEqual(self.CategoryHandler.categories["category-a-overlay"].name, "Category A overlay") # ensure that the other frameworks are still loaded self.assertEqual(self.CategoryHandler.categories["category-a"].name, "Category A") @patch("umake.frameworks.get_user_frameworks_path") def test_load_additional_frameworks_with_two_categories(self, get_user_frameworks_path): """Ensure we load additional frameworks in a path with two categories""" temp_path = tempfile.mkdtemp() self.dirs_to_remove.append(temp_path) shutil.copy(os.path.join(get_data_dir(), "overlayframeworks", "overlayframeworks.py"), temp_path) shutil.copy(os.path.join(get_data_dir(), "overlayframeworks", "withcategory2.py"), temp_path) get_user_frameworks_path.return_value = temp_path # load home framework-directory with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "testframeworks"): frameworks.load_frameworks() # ensure that both overlay are loaded self.assertEqual(self.CategoryHandler.categories["category-a-overlay"].name, "Category A overlay") self.assertEqual(self.CategoryHandler.categories["category-a2-overlay"].name, "Category A2 overlay") # ensure that the other frameworks are still loaded self.assertEqual(self.CategoryHandler.categories["category-a"].name, "Category A") @patch("umake.frameworks.get_user_frameworks_path") def test_load_additional_frameworks_with_same_filename(self, get_user_frameworks_path): """Ensure we load additional frameworks in a path with same filename""" temp_path = tempfile.mkdtemp() self.dirs_to_remove.append(temp_path) shutil.copy(os.path.join(get_data_dir(), "overlayframeworks", "withcategory.py"), temp_path) get_user_frameworks_path.return_value = temp_path # load home framework-directory with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "testframeworks"): frameworks.load_frameworks() # ensure that the duplicated filename (but not category) is loaded self.assertEqual(self.CategoryHandler.categories["category-a-overlay"].name, "Category A overlay") # ensure that the other frameworks with the same name is still loaded self.assertEqual(self.CategoryHandler.categories["category-a"].name, "Category A") @patch("umake.frameworks.get_user_frameworks_path") def test_load_additional_frameworks_with_duphome_before_system(self, get_user_frameworks_path): """Ensure we load additional frameworks from home before system if they have the same names""" temp_path = tempfile.mkdtemp() self.dirs_to_remove.append(temp_path) shutil.copy(os.path.join(get_data_dir(), "overlayframeworks", "duplicatedcategory.py"), temp_path) get_user_frameworks_path.return_value = temp_path # load home framework-directory with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "testframeworks"): frameworks.load_frameworks() # ensure that the overlay one is loaded categoryA = self.CategoryHandler.categories["category-a"] self.assertEqual(categoryA.name, "Category A") self.assertEqual(categoryA.frameworks["framework-a-from-overlay"].name, "Framework A from overlay") # ensure that the other frameworks are still loaded self.assertEqual(self.CategoryHandler.categories["category-b"].name, "Category/B") self.expect_warn_error = True # expect warning due to duplication @patch("umake.frameworks.get_user_frameworks_path") def test_load_additional_frameworks_with_dup_progname_env_before_home_before_system(self, get_user_frameworks_path): """Ensure we load additional frameworks from env before home and system if they have the same names""" # env var temp_path = tempfile.mkdtemp() self.dirs_to_remove.append(temp_path) os.environ[UMAKE_FRAMEWORKS_ENVIRON_VARIABLE] = temp_path shutil.copy(os.path.join(get_data_dir(), "overlayframeworks", "duplicatedcategory2.py"), temp_path) # home dir temp_path = tempfile.mkdtemp() self.dirs_to_remove.append(temp_path) shutil.copy(os.path.join(get_data_dir(), "overlayframeworks", "duplicatedcategory.py"), temp_path) get_user_frameworks_path.return_value = temp_path # load env and home framework-directory with patchelem(umake.frameworks, '__file__', os.path.join(self.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "testframeworks"): frameworks.load_frameworks() # ensure that the env overlay one is loaded categoryA = self.CategoryHandler.categories["category-a"] self.assertEqual(categoryA.name, "Category A") self.assertEqual(categoryA.frameworks["framework-a-from-overlay-2"].name, "Framework A from overlay 2") # ensure that the other frameworks are still loaded self.assertEqual(self.CategoryHandler.categories["category-b"].name, "Category/B") self.expect_warn_error = True # expect warning due to duplication class TestProductionFrameworkLoader(BaseFrameworkLoader): """Load production framework-and ensure there is no warning and no error""" def test_load_scala(self): """Can load production frameworks""" frameworks.load_frameworks() self.assertTrue(len(self.CategoryHandler.categories) > 0, str(self.CategoryHandler.categories)) self.assertIsNotNone(self.CategoryHandler.main_category) self.assertEqual(len(self.CategoryHandler.categories["scala"].frameworks), 1, str(self.CategoryHandler.categories["scala"].frameworks)) def test_ignored_frameworks(self): """Ignored frameworks aren't loaded""" frameworks.load_frameworks() self.assertNotIn(BaseInstaller, frameworks.BaseCategory.main_category.frameworks.values()) class TestCustomFrameworkCantLoad(BaseFrameworkLoader): """Get custom unloadable automatically frameworks to test custom corner cases""" class _CustomFramework(umake.frameworks.BaseFramework): def __init__(self): super().__init__(name="Custom", description="Custom uninstallable framework", category=umake.frameworks.MainCategory()) def setup(self): super().setup() def remove(self): super().remove() @property def is_installable(self): return False def test_call_setup_on_uninstallable_framework(self): """Calling setup on uninstallable framework return to main UI""" fw = self._CustomFramework() with patch("umake.frameworks.UI") as UIMock: fw.setup() self.assertTrue(UIMock.return_main_screen.called) self.expect_warn_error = True ubuntu-make-16.02.1/tests/small/test_settings.py0000664000000000000000000000712312656574623016554 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program is distributed in he 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests the umake settings handler""" import os import shutil import tempfile from ..tools import get_data_dir, LoggedTestCase from unittest.mock import patch from umake import settings class TestVersionHandler(LoggedTestCase): """This will test the version handler""" def setUp(self): super().setUp() self.from_dev_opt = settings.from_dev self.version_dir = tempfile.mkdtemp() self.initial_env = os.environ.copy() self.initial_os_path_join = os.path.join os.environ["PATH"] = "{}:{}".format(os.path.join(get_data_dir(), "mocks"), os.getenv("PATH")) self.version_file_path = os.path.join(self.version_dir, "version") open(self.version_file_path, "w").write("42.02") def tearDown(self): # remove caching shutil.rmtree(self.version_dir) settings.from_dev = self.from_dev_opt # restore original environment. Do not use the dict copy which erases the object and doesn't have the magical # _Environ which setenv() for subprocess os.environ.clear() os.environ.update(self.initial_env) os.path.join = self.initial_os_path_join super().tearDown() def return_fake_version_path(self, *args): '''Only return fake version path if the request was for that one''' if args[-1] == "version": return self.version_file_path return self.initial_os_path_join(*args) @patch("os.path.join") def test_version_release(self, path_join_result): """Ensure we are returning the right version for a release""" path_join_result.side_effect = self.return_fake_version_path os.environ.clear() os.environ.update(self.initial_env) self.assertEquals(settings.get_version(), "42.02") @patch("os.path.join") def test_version_git(self, path_join_result): """Ensure we are returning the right version for a git repo""" settings.from_dev = True path_join_result.side_effect = self.return_fake_version_path self.assertEquals(settings.get_version(), "42.03-25-g1fd9507") @patch("os.path.join") def test_version_git_fail(self, path_join_result): """Ensure we are returning last known version + unknown if git fails""" settings.from_dev = True path_join_result.side_effect = self.return_fake_version_path os.environ["PATH"] = "{}:{}".format(os.path.join(get_data_dir(), "mocks", "fails"), os.getenv("PATH")) self.assertEquals(settings.get_version(), "42.02+unknown") @patch("os.path.join") def test_version_git_not_installed(self, path_join_result): """Ensure we are returning last known version + unknown if git isn't installed""" settings.from_dev = True path_join_result.side_effect = self.return_fake_version_path os.environ["PATH"] = "" self.assertEquals(settings.get_version(), "42.02+unknown") ubuntu-make-16.02.1/tests/small/test_decompressor.py0000664000000000000000000003565312656574623017432 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the decompressor module""" import os from time import time from unittest.mock import Mock import shutil import stat import tempfile from ..tools import get_data_dir, LoggedTestCase from umake.decompressor import Decompressor class TestDecompressor(LoggedTestCase): """This will test the decompressor class""" @classmethod def setUpClass(cls): super().setUpClass() cls.compressfiles_dir_orig = os.path.join(get_data_dir(), "compress-files") def setUp(self): super().setUp() self.on_done = Mock() self.tempdir = tempfile.mkdtemp() self.compressfiles_dir = os.path.join(self.tempdir, "source-files") shutil.copytree(self.compressfiles_dir_orig, self.compressfiles_dir) def tearDown(self): shutil.rmtree(self.tempdir) super().tearDown() def wait_for_callback(self, mock_function_to_be_called, timeout=10): """wait for the callback to be called until a timeout. Add temp files to the clean file list afterwards""" timeout_time = time() + 5 while not mock_function_to_be_called.called: if time() > timeout_time: raise(BaseException("Function not called within {} seconds".format(timeout))) def test_decompress(self): """We decompress a valid .tgz file successfully""" filepath = os.path.join(self.compressfiles_dir, "valid.tgz") Decompressor({open(filepath, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 1, str(results)) for fd in results: self.assertIsNone(results[fd].error) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content', 'simplefile'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content', 'subdir'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content', 'subdir', 'otherfile'))) self.assertEqual(self.on_done.call_count, 1, "Global done callback is only called once") def test_decompress_move_dir_content(self): """We decompress a valid file decompressing one subdir content (other files in root are kept in place)""" filepath = os.path.join(self.compressfiles_dir, "valid.tgz") Decompressor({open(filepath, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='server-content')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 1, str(results)) for fd in results: self.assertIsNone(results[fd].error) self.assertTrue(os.path.isdir(self.tempdir)) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'simplefile'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'subdir'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'subdir', 'otherfile'))) def test_decompress_invalid_file(self): """We return an error if the compressed file is invalid""" self.expect_warn_error = True filepath = os.path.join(self.compressfiles_dir, "invalid.tgz") Decompressor({open(filepath, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 1, str(results)) for fd in results: self.assertIsNotNone(results[fd].error) self.assertEqual(self.on_done.call_count, 1, "Global done callback is only called once") def test_decompress_content_glob(self): """We decompress a valid file decompressing one subdir content with a glob schema""" filepath = os.path.join(self.compressfiles_dir, "valid.tgz") Decompressor({open(filepath, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='server-*')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 1, str(results)) for fd in results: self.assertIsNone(results[fd].error) self.assertTrue(os.path.isdir(self.tempdir)) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'simplefile'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'subdir'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'subdir', 'otherfile'))) def test_decompress_zip(self): """We decompress a valid zip file successfully""" filepath = os.path.join(self.compressfiles_dir, "valid.zip") Decompressor({open(filepath, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 1, str(results)) for fd in results: self.assertIsNone(results[fd].error) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content', 'simplefile'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content', 'executablefile'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content', 'subdir'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content', 'subdir', 'otherfile'))) def test_decompress_zip_good_permission(self): """We decompress a valid zip file successfully, retaining the right permissions""" filepath = os.path.join(self.compressfiles_dir, "valid.zip") Decompressor({open(filepath, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 1, str(results)) for fd in results: self.assertIsNone(results[fd].error) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content'))) simplefile = os.path.join(self.tempdir, 'server-content', 'simplefile') self.assertTrue(os.path.isfile(simplefile)) execfile = os.path.join(self.tempdir, 'server-content', 'executablefile') self.assertTrue(os.path.isfile(execfile)) self.assertEqual(oct(stat.S_IMODE(os.lstat(simplefile).st_mode)), '0o664') self.assertEqual(oct(stat.S_IMODE(os.lstat(execfile).st_mode)), '0o775') def test_decompress_exec(self): """We decompress a valid executable file successfully""" filepath = os.path.join(self.compressfiles_dir, "simple.bin") Decompressor({open(filepath, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 1, str(results)) for fd in results: self.assertIsNone(results[fd].error) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'android-ndk-foo'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'android-ndk-foo', 'ndk-which'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'android-ndk-foo', 'ndk-build'))) def test_decompress_file_with_archive(self): """We decompress a .sh file containing an archive successfully""" filepath = os.path.join(self.compressfiles_dir, "script_with_archive.sh") with open(filepath, 'rb') as fd: for line in fd: if line.startswith(b"== ARCHIVE TAG =="): break Decompressor({fd: Decompressor.DecompressOrder(dest=self.tempdir, dir='')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 1, str(results)) for fd in results: self.assertIsNone(results[fd].error) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content', 'simplefile'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content', 'subdir'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content', 'subdir', 'otherfile'))) def test_decompress_wrong_dir_content(self): """We decompress a valid file, but the selected subdir isn't valid""" self.expect_warn_error = True filepath = os.path.join(self.compressfiles_dir, "valid.tgz") Decompressor({open(filepath, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='doesnt-exists')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 1, str(results)) for fd in results: self.assertIsNotNone(results[fd].error) def test_decompress_content_keep_existing_files(self): """We decompress a valid file in a directory which already have some content. This one is left.""" filepath = os.path.join(self.compressfiles_dir, "valid.tgz") open(os.path.join(self.tempdir, "foo"), 'w').write('') Decompressor({open(filepath, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 1, str(results)) for fd in results: self.assertIsNone(results[fd].error) self.assertTrue(os.path.isdir(self.tempdir)) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content', 'simplefile'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content', 'subdir'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content', 'subdir', 'otherfile'))) # the original file is there here self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'foo'))) def test_decompress_move_dir_content_keep_existing_files(self): """We decompress a valid file changing dir in a directory which already have some content. This one is left.""" filepath = os.path.join(self.compressfiles_dir, "valid.tgz") open(os.path.join(self.tempdir, "foo"), 'w').write('') Decompressor({open(filepath, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='server-content')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 1, str(results)) for fd in results: self.assertIsNone(results[fd].error) self.assertTrue(os.path.isdir(self.tempdir)) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'simplefile'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'subdir'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'subdir', 'otherfile'))) # the original file is there here self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'foo'))) def test_decompress_multiple(self): """We decompress multiple valid .tgz file successfully""" filepath1 = os.path.join(self.compressfiles_dir, "valid.tgz") filepath2 = os.path.join(self.compressfiles_dir, "valid2.tgz") Decompressor({open(filepath1, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir=''), open(filepath2, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 2, str(results)) for fd in results: self.assertIsNone(results[fd].error) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content', 'simplefile'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content', 'subdir'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content', 'subdir', 'otherfile'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content2'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content2', 'simplefile2'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'server-content2', 'subdir2'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'server-content2', 'subdir2', 'otherfile'))) self.assertEqual(self.on_done.call_count, 1, "Global done callback is only called once") def test_decompress_multiple_with_dir(self): """We decompress multiple valid .tgz file successfully with different dir to extract""" filepath1 = os.path.join(self.compressfiles_dir, "valid.tgz") filepath2 = os.path.join(self.compressfiles_dir, "valid2.tgz") Decompressor({open(filepath1, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='server-content'), open(filepath2, 'rb'): Decompressor.DecompressOrder(dest=self.tempdir, dir='server-content2')}, self.on_done) self.wait_for_callback(self.on_done) results = self.on_done.call_args[0][0] self.assertEqual(len(results), 2, str(results)) for fd in results: self.assertIsNone(results[fd].error) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'simplefile'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'subdir'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'subdir', 'otherfile'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'simplefile2'))) self.assertTrue(os.path.isdir(os.path.join(self.tempdir, 'subdir2'))) self.assertTrue(os.path.isfile(os.path.join(self.tempdir, 'subdir2', 'otherfile'))) self.assertEqual(self.on_done.call_count, 1, "Global done callback is only called once") ubuntu-make-16.02.1/tests/small/test_tools.py0000664000000000000000000015223412656574623016060 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program is distributed in he 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests the various umake tools""" from concurrent import futures from contextlib import contextmanager, suppress from gi.repository import GLib import os import shutil import subprocess import stat import sys import tempfile from textwrap import dedent from time import time import threading from . import DpkgAptSetup from ..tools import change_xdg_path, get_data_dir, LoggedTestCase, INSTALL_DIR from umake import settings, tools from umake.tools import ConfigHandler, Singleton, get_current_arch, get_foreign_archs, get_current_ubuntu_version,\ create_launcher, launcher_exists_and_is_pinned, launcher_exists, get_icon_path, get_launcher_path, copy_icon,\ add_exec_link from unittest.mock import patch, Mock class TestConfigHandler(LoggedTestCase): """This will test the config handler using xdg dirs""" def setUp(self): super().setUp() self.config_dir = tempfile.mkdtemp() change_xdg_path('XDG_CONFIG_HOME', self.config_dir) def tearDown(self): # remove caching Singleton._instances = {} change_xdg_path('XDG_CONFIG_HOME', remove=True) shutil.rmtree(self.config_dir) super().tearDown() def config_dir_for_name(self, name): """Return the config dir for this name""" return os.path.join(get_data_dir(), 'configs', name) def test_singleton(self): """Ensure we are delivering a singleton for TestConfigHandler""" config1 = ConfigHandler() config2 = ConfigHandler() self.assertEqual(config1, config2) def test_load_config(self): """Valid config loads correct content""" change_xdg_path('XDG_CONFIG_HOME', self.config_dir_for_name("valid")) self.assertEqual(ConfigHandler().config, {'frameworks': { 'category-a': { 'framework-a': {'path': '/home/didrocks/quickly/ubuntu-make/adt-eclipse'}, 'framework-b': {'path': '/home/didrocks/foo/bar/android-studio'} } }}) def test_load_no_config(self): """No existing file gives an empty result""" change_xdg_path('XDG_CONFIG_HOME', self.config_dir_for_name("foo")) self.assertEqual(ConfigHandler().config, {}) def test_load_invalid_config(self): """Existing invalid file gives an empty result""" change_xdg_path('XDG_CONFIG_HOME', self.config_dir_for_name("invalid")) self.assertEqual(ConfigHandler().config, {}) self.expect_warn_error = True def test_save_new_config(self): """Save a new config in a vanilla directory""" content = {'foo': 'bar'} ConfigHandler().config = content self.assertEqual(ConfigHandler().config, content) with open(os.path.join(self.config_dir, settings.CONFIG_FILENAME)) as f: self.assertEqual(f.read(), 'foo: bar\n') def test_save_config_without_xdg_dir(self): """Save a new config file with an unexisting directory""" os.removedirs(self.config_dir) self.test_save_new_config() def test_save_config_existing(self): """Replace an existing config with a new one""" shutil.copy(os.path.join(self.config_dir_for_name('valid'), settings.CONFIG_FILENAME), self.config_dir) content = {'foo': 'bar'} ConfigHandler().config = content self.assertEqual(ConfigHandler().config, content) with open(os.path.join(self.config_dir, settings.CONFIG_FILENAME)) as f: self.assertEqual(f.read(), 'foo: bar\n') def test_dont_create_file_without_assignment(self): """We don't create any file without an assignment""" ConfigHandler() self.assertEqual(len(os.listdir(self.config_dir)), 0) def test_transition_old_config(self): """Transition udtc old config to new umake one""" with tempfile.TemporaryDirectory() as tmpdirname: shutil.copy(os.path.join(self.config_dir_for_name("old"), "udtc"), tmpdirname) change_xdg_path('XDG_CONFIG_HOME', tmpdirname) self.assertEqual(ConfigHandler().config, {'frameworks': { 'category-a': { 'framework-a': {'path': '/home/didrocks/quickly/ubuntu-make/adt-eclipse'}, 'framework-b': {'path': '/home/didrocks/foo/bar/android-studio'} } }}) # file has been renamed self.assertTrue(os.path.exists(os.path.join(tmpdirname, "umake")), "New umake config file exists") self.assertFalse(os.path.exists(os.path.join(tmpdirname, "udtc")), "Old udtc config file is removed") class TestGetUbuntuVersion(LoggedTestCase): def setUp(self): """Reset previously cached values""" super().setUp() tools._version = None def tearDown(self): """Reset cached values""" tools._version = None super().tearDown() def get_lsb_release_filepath(self, name): return os.path.join(get_data_dir(), 'lsb_releases', name) @patch("umake.tools.settings") def test_get_current_ubuntu_version(self, settings_module): """Current ubuntu version is reported from our lsb_release local file""" settings_module.LSB_RELEASE_FILE = self.get_lsb_release_filepath("valid") self.assertEqual(get_current_ubuntu_version(), '14.04') @patch("umake.tools.settings") def test_get_current_ubuntu_version_invalid(self, settings_module): """Raise an error when parsing an invalid lsb release file""" settings_module.LSB_RELEASE_FILE = self.get_lsb_release_filepath("invalid") self.assertRaises(BaseException, get_current_ubuntu_version) self.expect_warn_error = True @patch("umake.tools.settings") def test_get_current_ubuntu_version_no_lsb_release(self, settings_module): """Raise an error when there is no lsb release file""" settings_module.LSB_RELEASE_FILE = self.get_lsb_release_filepath("notexist") self.assertRaises(BaseException, get_current_ubuntu_version) self.expect_warn_error = True class TestCompletion(LoggedTestCase): def setUp(self): super().setUp() self.initial_env = os.environ.copy() def tearDown(self): # restore original environment. Do not use the dict copy which erases the object and doesn't have the magical # _Environ which setenv() for subprocess os.environ.clear() os.environ.update(self.initial_env) super().tearDown() def test_in_completion_mode(self): """We return if we are in completion mode""" os.environ["_ARGCOMPLETE"] = "1" self.assertTrue(tools.is_completion_mode()) def test_not_incompletion_mode(self): """We are not in completion mode by default""" self.assertFalse(tools.is_completion_mode()) class TestArchVersion(DpkgAptSetup): def setUp(self): """Reset previously cached values""" super().setUp() tools._current_arch = None tools._foreign_arch = None def tearDown(self): """Reset cached values""" tools._current_arch = None tools._foreign_arch = None super().tearDown() def dpkg_error(self, *args, **kwargs): """Simulate a dpkg failure""" raise subprocess.CalledProcessError("dpkg failure", cmd="dpkg") def test_get_current_arch(self): """Current arch is reported""" with patch("umake.tools.subprocess") as subprocess_mock: subprocess_mock.check_output.return_value = "fooarch" self.assertEqual(get_current_arch(), "fooarch") def test_get_current_arch_twice(self): """Current arch is reported twice and the same""" with patch("umake.tools.subprocess") as subprocess_mock: subprocess_mock.check_output.return_value = "fooarch" self.assertEqual(get_current_arch(), "fooarch") self.assertEqual(get_current_arch(), "fooarch") self.assertEquals(subprocess_mock.check_output.call_count, 1, "We cache older value") def test_get_current_arch_no_dpkg(self): """Assert an error if dpkg exit with an error""" with patch("umake.tools.subprocess") as subprocess_mock: subprocess_mock.check_output.side_effect = self.dpkg_error self.assertRaises(subprocess.CalledProcessError, get_current_arch) def test_get_foreign_arch(self): """Get current foreign arch (one)""" with patch("umake.tools.subprocess") as subprocess_mock: subprocess_mock.check_output.return_value = "fooarch" self.assertEqual(get_foreign_archs(), ["fooarch"]) def test_get_foreign_archs(self): """Get current foreign arch (multiple)""" with patch("umake.tools.subprocess") as subprocess_mock: subprocess_mock.check_output.return_value = "fooarch\nbararch\nbazarch" self.assertEqual(get_foreign_archs(), ["fooarch", "bararch", "bazarch"]) def test_get_foreign_archs_error(self): """Get current foreign arch raises an exception if dpkg is in error""" with patch("umake.tools.subprocess") as subprocess_mock: subprocess_mock.check_output.side_effect = self.dpkg_error self.assertRaises(subprocess.CalledProcessError, get_foreign_archs) def test_add_new_foreign_arch(self): """Add a new foreign arch and check that we can retrieve it (cache invalidated)""" tools.add_foreign_arch("foo") self.assertEqual(get_foreign_archs(), ["foo"]) def test_add_foreign_arch_already_in(self): """Add a foreign arch which was already there should be a noop""" with patch("umake.tools.subprocess") as subprocess_mock: subprocess_mock.check_output.return_value = "foo" subprocess_mock.call.side_effect = subprocess.call tools.add_foreign_arch("foo") self.assertFalse(subprocess_mock.call.called) def test_add_current_arch(self): """Add the current arch should be a noop""" tools._current_arch = "foo" with patch("umake.tools.subprocess") as subprocess_mock: subprocess_mock.call.side_effect = subprocess.call tools.add_foreign_arch("foo") def test_add_new_foreign_arch_fail(self): """Add a new foreign arch, but failing should raise an exception""" with patch("umake.tools.subprocess") as subprocess_mock: subprocess_mock.call.return_value = 1 self.assertRaises(BaseException, tools.add_foreign_arch, "foo") class TestToolsThreads(LoggedTestCase): """Test main loop threading helpers""" def setUp(self): super().setUp() self.mainloop_object = tools.MainLoop() self.mainloop_thread = None self.function_thread = None self.saved_stderr = sys.stderr def tearDown(self): Singleton._instances = {} sys.stderr = self.saved_stderr super().tearDown() def patch_stderr(self): class writer(object): def write(self, data): print(data) sys.stderr = writer() # function that will complete once the mainloop is started def wait_for_mainloop_function(self): timeout_time = time() + 5 while not self.mainloop_object.mainloop.is_running(): if time() > timeout_time: raise(BaseException("Mainloop not started in 5 seconds")) def wait_for_mainloop_shutdown(self): timeout_time = time() + 5 while self.mainloop_object.mainloop.is_running(): if time() > timeout_time: raise(BaseException("Mainloop not stopped in 5 seconds")) def get_mainloop_thread(self): self.mainloop_thread = threading.current_thread().ident def start_glib_mainloop(self): # quit after 5 seconds if nothing made the mainloop to end GLib.timeout_add_seconds(5, self.mainloop_object.mainloop.quit) GLib.idle_add(self.get_mainloop_thread) self.mainloop_object.run() @patch("umake.tools.sys") def test_run_function_in_mainloop_thread(self, mocksys): """Decorated mainloop thread functions are really running in that thread""" # function supposed to run in the mainloop thread @tools.MainLoop.in_mainloop_thread def _function_in_mainloop_thread(future): self.function_thread = threading.current_thread().ident self.mainloop_object.quit() executor = futures.ThreadPoolExecutor(max_workers=1) future = executor.submit(self.wait_for_mainloop_function) future.add_done_callback(_function_in_mainloop_thread) self.start_glib_mainloop() self.wait_for_mainloop_shutdown() # mainloop and thread were started self.assertIsNotNone(self.mainloop_thread) self.assertIsNotNone(self.function_thread) self.assertEqual(self.mainloop_thread, self.function_thread) @patch("umake.tools.sys") def test_run_function_not_in_mainloop_thread(self, mocksys): """Non decorated callback functions are not running in the mainloop thread""" # function not supposed to run in the mainloop thread def _function_not_in_mainloop_thread(future): self.function_thread = threading.current_thread().ident self.mainloop_object.quit(raise_exception=False) # as we don't run that from the mainloop executor = futures.ThreadPoolExecutor(max_workers=1) future = executor.submit(self.wait_for_mainloop_function) future.add_done_callback(_function_not_in_mainloop_thread) self.start_glib_mainloop() self.wait_for_mainloop_shutdown() # mainloop and thread were started self.assertIsNotNone(self.mainloop_thread) self.assertIsNotNone(self.function_thread) self.assertNotEqual(self.mainloop_thread, self.function_thread) def test_singleton(self): """Ensure we are delivering a singleton for RequirementsHandler""" second = tools.MainLoop() self.assertEqual(self.mainloop_object, second) def test_mainloop_run(self): """We effectively executes the mainloop""" with patch.object(self.mainloop_object, "mainloop") as mockmainloop: self.mainloop_object.run() self.assertTrue(mockmainloop.run.called) @patch("umake.tools.sys") def test_mainloop_quit(self, mocksys): """We quit the process""" def _quit_ignoring_exception(): self.mainloop_object.quit(raise_exception=False) # as we don't run that from the mainloop GLib.idle_add(_quit_ignoring_exception) self.start_glib_mainloop() self.wait_for_mainloop_shutdown() mocksys.exit.assert_called_once_with(0) @patch("umake.tools.sys") def test_mainloop_quit_with_exit_value(self, mocksys): """We quit the process with a return code""" def _quit_ignoring_exception(): self.mainloop_object.quit(42, raise_exception=False) # as we don't run that from the mainloop GLib.idle_add(_quit_ignoring_exception) self.start_glib_mainloop() self.wait_for_mainloop_shutdown() mocksys.exit.assert_called_once_with(42) @patch("umake.tools.sys") def test_unhandled_exception_in_mainloop_thead_exit(self, mocksys): """We quit the process in error for any unhandled exception, logging it""" @tools.MainLoop.in_mainloop_thread def _function_raising_exception(): raise BaseException("foo bar") _function_raising_exception() self.patch_stderr() self.start_glib_mainloop() self.wait_for_mainloop_shutdown() mocksys.exit.assert_called_once_with(1) self.expect_warn_error = True class TestLauncherIcons(LoggedTestCase): """Test module for launcher icons handling""" @classmethod def setUpClass(cls): super().setUpClass() cls.server_dir = os.path.join(get_data_dir(), "server-content") def setUp(self): super().setUp() self.local_dir = tempfile.mkdtemp() os.mkdir(os.path.join(self.local_dir, "applications")) os.mkdir(os.path.join(self.local_dir, "icons")) change_xdg_path('XDG_DATA_HOME', self.local_dir) self.current_desktop = os.environ.get("XDG_CURRENT_DESKTOP") os.environ["XDG_CURRENT_DESKTOP"] = "Unity" def tearDown(self): change_xdg_path('XDG_DATA_HOME', remove=True) shutil.rmtree(self.local_dir) if self.current_desktop: os.environ["XDG_CURRENT_DESKTOP"] = self.current_desktop super().tearDown() def get_generic_desktop_content(self): """Return a generic desktop content to win spaces""" return dedent("""\ [Desktop Entry] Version=1.0 Type=Application Name=Android Studio Icon=/home/didrocks/{install_dir}/android-studio/bin/studio.png Exec="/home/didrocks/{install_dir}/android-studio/bin/studio.sh" %f Comment=Develop with pleasure! Categories=Development;IDE; Terminal=false StartupWMClass=jetbrains-android-studio """.format(install_dir=INSTALL_DIR)) def write_desktop_file(self, filename): """Write a dummy filename to the applications dir and return filepath""" result_file = os.path.join(self.local_dir, "applications", filename) with open(result_file, 'w') as f: f.write("Foo Bar Baz") return result_file @patch("umake.tools.Gio.Settings") def test_can_install(self, SettingsMock): """Install a basic launcher, default case with unity://running""" SettingsMock.list_schemas.return_value = ["foo", "bar", "com.canonical.Unity.Launcher", "baz"] SettingsMock.return_value.get_strv.return_value = ["application://bar.desktop", "unity://running-apps"] create_launcher("foo.desktop", self.get_generic_desktop_content()) self.assertTrue(SettingsMock.list_schemas.called) SettingsMock.return_value.get_strv.assert_called_with("favorites") SettingsMock.return_value.set_strv.assert_called_with("favorites", ["application://bar.desktop", "application://foo.desktop", "unity://running-apps"]) self.assertTrue(os.path.exists(get_launcher_path("foo.desktop"))) self.assertEqual(open(get_launcher_path("foo.desktop")).read(), self.get_generic_desktop_content()) @patch("umake.tools.Gio.Settings") def test_can_update_launcher(self, SettingsMock): """Update a launcher file""" SettingsMock.list_schemas.return_value = ["foo", "bar", "com.canonical.Unity.Launcher", "baz"] SettingsMock.return_value.get_strv.return_value = ["application://bar.desktop", "unity://running-apps"] create_launcher("foo.desktop", self.get_generic_desktop_content()) new_content = dedent("""\ [Desktop Entry] Version=1.0 Type=Application Name=Android Studio 2 Icon=/home/didrocks/{install_dir}/android-studio/bin/idea2.png Exec="/home/didrocks/{install_dir}/android-studio/bin/studio2.sh" %f Comment=Develop with pleasure! Categories=Development;IDE; Terminal=false StartupWMClass=jetbrains-android-studio """.format(install_dir=INSTALL_DIR)) create_launcher("foo.desktop", new_content) self.assertTrue(os.path.exists(get_launcher_path("foo.desktop"))) self.assertEqual(open(get_launcher_path("foo.desktop")).read(), new_content) @patch("umake.tools.Gio.Settings") def test_can_install_without_unity_running(self, SettingsMock): """Install a basic launcher icon, without a running apps entry (so will be last)""" SettingsMock.list_schemas.return_value = ["foo", "bar", "com.canonical.Unity.Launcher", "baz"] SettingsMock.return_value.get_strv.return_value = ["application://bar.desktop", "application://baz.desktop"] create_launcher("foo.desktop", self.get_generic_desktop_content()) self.assertTrue(SettingsMock.list_schemas.called) SettingsMock.return_value.set_strv.assert_called_with("favorites", ["application://bar.desktop", "application://baz.desktop", "application://foo.desktop"]) @patch("umake.tools.Gio.Settings") def test_can_install_already_in_launcher(self, SettingsMock): """A file listed in launcher still install the files, but the entry isn't changed""" SettingsMock.list_schemas.return_value = ["foo", "bar", "com.canonical.Unity.Launcher", "baz"] SettingsMock.return_value.get_strv.return_value = ["application://bar.desktop", "application://foo.desktop", "unity://running-apps"] create_launcher("foo.desktop", self.get_generic_desktop_content()) self.assertFalse(SettingsMock.return_value.set_strv.called) self.assertTrue(os.path.exists(get_launcher_path("foo.desktop"))) @patch("umake.tools.Gio.Settings") def test_install_no_schema_file(self, SettingsMock): """No schema file still installs the file""" SettingsMock.list_schemas.return_value = ["foo", "bar", "baz"] create_launcher("foo.desktop", self.get_generic_desktop_content()) self.assertFalse(SettingsMock.return_value.get_strv.called) self.assertFalse(SettingsMock.return_value.set_strv.called) self.assertTrue(os.path.exists(get_launcher_path("foo.desktop"))) @patch("umake.tools.Gio.Settings") def test_already_existing_file_different_content(self, SettingsMock): """A file with a different file content already exists and is updated""" SettingsMock.list_schemas.return_value = ["foo", "bar", "baz"] result_file = self.write_desktop_file("foo.desktop") create_launcher("foo.desktop", self.get_generic_desktop_content()) self.assertEqual(open(result_file).read(), self.get_generic_desktop_content()) @patch("umake.tools.Gio.Settings") def test_create_launcher_without_xdg_dir(self, SettingsMock): """Save a new launcher in an unexisting directory""" shutil.rmtree(self.local_dir) SettingsMock.list_schemas.return_value = ["foo", "bar", "baz"] create_launcher("foo.desktop", self.get_generic_desktop_content()) self.assertTrue(os.path.exists(get_launcher_path("foo.desktop"))) def test_desktop_file_exists(self): """Launcher exists""" self.write_desktop_file("foo.desktop") self.assertTrue(launcher_exists("foo.desktop")) def test_desktop_file_doesnt_exist(self): """Launcher file doesn't exists""" self.assertFalse(launcher_exists("foo.desktop")) @patch("umake.tools.Gio.Settings") def test_launcher_exists_and_is_pinned(self, SettingsMock): """Launcher exists and is pinned if the file exists and is in favorites list""" SettingsMock.list_schemas.return_value = ["foo", "bar", "com.canonical.Unity.Launcher", "baz"] SettingsMock.return_value.get_strv.return_value = ["application://bar.desktop", "application://foo.desktop", "unity://running-apps"] self.write_desktop_file("foo.desktop") self.assertTrue(launcher_exists_and_is_pinned("foo.desktop")) @patch("umake.tools.Gio.Settings") def test_launcher_isnt_pinned(self, SettingsMock): """Launcher doesn't exists and is pinned if the file exists but not in favorites list""" SettingsMock.list_schemas.return_value = ["foo", "bar", "com.canonical.Unity.Launcher", "baz"] SettingsMock.return_value.get_strv.return_value = ["application://bar.desktop", "unity://running-apps"] self.write_desktop_file("foo.desktop") self.assertFalse(launcher_exists_and_is_pinned("foo.desktop")) @patch("umake.tools.Gio.Settings") def test_launcher_exists_but_isnt_pinned_in_none_unity(self, SettingsMock): """Launcher exists return True if file exists, not pinned but not in Unity""" os.environ["XDG_CURRENT_DESKTOP"] = "FOOenv" SettingsMock.list_schemas.return_value = ["foo", "bar", "com.canonical.Unity.Launcher", "baz"] SettingsMock.return_value.get_strv.return_value = ["application://bar.desktop", "unity://running-apps"] self.write_desktop_file("foo.desktop") self.assertTrue(launcher_exists_and_is_pinned("foo.desktop")) @patch("umake.tools.Gio.Settings") def test_launcher_exists_but_not_schema_in_none_unity(self, SettingsMock): """Launcher exists return True if file exists, even if Unity schema isn't installed""" os.environ["XDG_CURRENT_DESKTOP"] = "FOOenv" SettingsMock.list_schemas.return_value = ["foo", "bar", "baz"] self.write_desktop_file("foo.desktop") self.assertTrue(launcher_exists_and_is_pinned("foo.desktop")) @patch("umake.tools.Gio.Settings") def test_launcher_exists_but_not_schema_in_unity(self, SettingsMock): """Launcher exists return False if file exists, but no Unity schema installed""" SettingsMock.list_schemas.return_value = ["foo", "bar", "baz"] self.write_desktop_file("foo.desktop") self.assertFalse(launcher_exists_and_is_pinned("foo.desktop")) @patch("umake.tools.Gio.Settings") def test_launcher_doesnt_exists_but_pinned(self, SettingsMock): """Launcher doesn't exist if no file, even if pinned""" SettingsMock.list_schemas.return_value = ["foo", "bar", "com.canonical.Unity.Launcher", "baz"] SettingsMock.return_value.get_strv.return_value = ["application://bar.desktop", "application://foo.desktop", "unity://running-apps"] self.assertFalse(launcher_exists_and_is_pinned("foo.desktop")) def test_can_copy_icon(self): """Copy a basic icon""" # we copy any file and treat it as an icon copy_icon(os.path.join(self.server_dir, "simplefile"), "foo.png") self.assertTrue(os.path.exists(get_icon_path("foo.png"))) self.assertEqual(open(os.path.join(self.server_dir, "simplefile")).read(), open(get_icon_path("foo.png")).read()) def test_can_update_icon(self): """Update a basic icon with a new content""" copy_icon(os.path.join(self.server_dir, "simplefile"), "foo.png") copy_icon(os.path.join(self.server_dir, "biggerfile"), "foo.png") self.assertTrue(os.path.exists(get_icon_path("foo.png"))) self.assertEqual(open(os.path.join(self.server_dir, "biggerfile")).read(), open(get_icon_path("foo.png")).read()) def test_can_copy_icon_with_glob(self): """Copy an icon with glob pattern matching""" # we copy any file and treat it as an icon copy_icon(os.path.join(self.server_dir, "sim*file"), "foo.png") self.assertTrue(os.path.exists(get_icon_path("foo.png"))) self.assertEqual(open(os.path.join(self.server_dir, "simplefile")).read(), open(get_icon_path("foo.png")).read()) def test_create_icon_without_xdg_dir(self): """Save a new icon in an unexisting directory""" shutil.rmtree(self.local_dir) copy_icon(os.path.join(self.server_dir, "simplefile"), "foo.png") self.assertTrue(os.path.exists(get_icon_path("foo.png"))) def test_get_icon_path(self): """Get correct launcher path""" self.assertEqual(get_icon_path("foo.png"), os.path.join(self.local_dir, "icons", "foo.png")) def test_get_launcher_path(self): """Get correct launcher path""" self.assertEqual(get_launcher_path("foo.desktop"), os.path.join(self.local_dir, "applications", "foo.desktop")) @patch("umake.tools.settings") def test_create_exec_path(self, settings_module): """Create link to the executable""" settings_module.DEFAULT_BINARY_LINK_PATH = os.path.join(self.local_dir, ".local", "share", "umake", "bin") add_exec_link(os.path.join(self.server_dir, "simplefile"), "foo") self.assertTrue(os.path.exists(os.path.join(settings_module.DEFAULT_BINARY_LINK_PATH, "foo"))) class TestMiscTools(LoggedTestCase): def test_get_application_desktop_file(self): """We return expect results with normal content""" self.assertEqual(tools.get_application_desktop_file(name="Name 1", icon_path="/to/icon/path", exec="/to/exec/path %f", comment="Comment for Name 1", categories="Cat1:Cat2"), dedent("""\ [Desktop Entry] Version=1.0 Type=Application Name=Name 1 Icon=/to/icon/path Exec=/to/exec/path %f Comment=Comment for Name 1 Categories=Cat1:Cat2 Terminal=false """)) def test_get_application_desktop_file_with_extra(self): """We return expect results with extra content""" self.assertEqual(tools.get_application_desktop_file(name="Name 1", icon_path="/to/icon/path", exec="/to/exec/path %f", comment="Comment for Name 1", categories="Cat1:Cat2", extra="Extra=extra1\nFoo=foo"), dedent("""\ [Desktop Entry] Version=1.0 Type=Application Name=Name 1 Icon=/to/icon/path Exec=/to/exec/path %f Comment=Comment for Name 1 Categories=Cat1:Cat2 Terminal=false Extra=extra1 Foo=foo """)) def test_get_application_desktop_file_all_empty(self): """We return expect results without any content""" self.assertEqual(tools.get_application_desktop_file(), dedent("""\ [Desktop Entry] Version=1.0 Type=Application Name= Icon= Exec= Comment= Categories= Terminal=false """)) def test_strip_tags(self): """We return strip tags from content""" self.assertEqual(tools.strip_tags("content content content contentcontent\n content" "\ncontent content"), "content content content contentcontent\n content\ncontent content") def test_strip_invalid_tags(self): """We return trip tags even if invalid""" self.assertEqual(tools.strip_tags("content content content contentcontent\n content" "\ncontent content"), "content content content contentcontent\n content\ncontent content") def test_strip_without_tags(self): """We return unmodified content if there is no tag""" self.assertEqual(tools.strip_tags("content content content contentcontent\n content" "\ncontent content"), "content content content contentcontent\n content\ncontent content") def test_raise_inputerror(self): def foo(): raise tools.InputError("Foo bar") self.assertRaises(tools.InputError, foo) def test_print_inputerror(self): self.assertEqual(str(tools.InputError("Foo bar")), "'Foo bar'") @patch("umake.tools.os") def test_switch_user_from_sudo(self, osmock): """Test switch user account from root to previous user under SUDO""" osmock.getenv.return_value = 1234 osmock.geteuid.return_value = 0 tools.switch_to_current_user() osmock.setegid.assert_called_once_with(1234) osmock.seteuid.assert_called_once_with(1234) @patch("umake.tools.os") def test_switch_user_from_non_sudo(self, osmock): """Test switch user from a non sudo command (non root), dosen't call anything""" osmock.getenv.return_value = 1234 osmock.geteuid.return_value = 1234 tools.switch_to_current_user() self.assertFalse(osmock.setegid.called) self.assertFalse(osmock.seteuid.called) self.assertFalse(osmock.getenv.called) @patch("umake.tools.os") def test_switch_user_from_root(self, osmock): """Test switch user from root, let it as root""" osmock.getenv.return_value = 0 osmock.geteuid.return_value = 0 tools.switch_to_current_user() osmock.setegid.assert_called_once_with(0) osmock.seteuid.assert_called_once_with(0) @patch("umake.tools.os") @patch("umake.tools.switch_to_current_user") def test_as_root(self, switch_to_current_usermock, osmock): """Switch as root when everything is permitted""" with tools.as_root(): osmock.seteuid.assert_called_once_with(0) osmock.setegid.assert_called_once_with(0) self.assertFalse(switch_to_current_usermock.called, "didn't switch to current user in context") self.assertTrue(switch_to_current_usermock.called, "switch back to user when exiting context") @patch("umake.tools.os") @patch("umake.tools.switch_to_current_user") def test_as_root_euid_perm_denied(self, switch_to_current_usermock, osmock): """Switch as root raise exception when euid permission is denied""" def raiseException(self): raise PermissionError("") osmock.seteuid.side_effect = raiseException exception_raised = False try: with tools.as_root(): pass except PermissionError: exception_raised = True self.assertTrue(exception_raised, "Permission Error was raised") self.assertTrue(switch_to_current_usermock.called, "switch back to user when exiting context") @patch("umake.tools.os") @patch("umake.tools.switch_to_current_user") def test_as_root_egid_perm_denied(self, switch_to_current_usermock, osmock): """Switch as root raise exception when egid permission is denied""" def raiseException(self): raise PermissionError("") osmock.setegid.side_effect = raiseException exception_raised = False try: with tools.as_root(): pass except PermissionError: exception_raised = True self.assertTrue(exception_raised, "Permission Error was raised") self.assertTrue(switch_to_current_usermock.called, "switch back to user when exiting context") @patch("umake.tools.os") @patch("umake.tools.switch_to_current_user") def test_as_root_with_lock(self, switch_to_current_usermock, osmock): """Ensure we don't try to switch as root before the lock is released""" def as_root_function(): with tools.as_root(): method_called_as_root() method_called_as_root = Mock() executor = futures.ThreadPoolExecutor(max_workers=1) # take main lock in that thread and start other one tools.root_lock.acquire() future = executor.submit(as_root_function) # we didn't get any root switch self.assertFalse(osmock.seteuid.called, "we didn't switch to root yet with seteuid") self.assertFalse(osmock.setegid.called, "we didn't switch to root yet with setegid") # release it tools.root_lock.release() # wait for the executor to finish in 1s and ensure that root was called future.result(1) osmock.seteuid.assert_called_once_with(0) osmock.setegid.assert_called_once_with(0) self.assertTrue(switch_to_current_usermock.called, "switch back to user when exiting context") class TestUserENV(LoggedTestCase): def setUp(self): super().setUp() self.orig_environ = os.environ.copy() self.local_dir = tempfile.mkdtemp() os.environ['SHELL'] = '/bin/bash' def tearDown(self): shutil.rmtree(self.local_dir) # restore original environment. Do not use the dict copy which erases the object and doesn't have the magical # _Environ which setenv() for subprocess os.environ.clear() os.environ.update(self.orig_environ) super().tearDown() @patch("umake.tools.os.path.expanduser") def test_add_env_to_user(self, expanderusermock): """Test that adding to user env appending to an existing .profile file""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n") tools.add_env_to_user("one path addition", {"FOOO": {"value": "bar"}}) expanderusermock.assert_called_with('~') profile_content = open(profile_file).read() self.assertTrue("Foo\nBar\n" in profile_content, profile_content) # we kept previous content self.assertTrue("export FOOO=bar\n" in profile_content, profile_content) self.assertTrue("bar" in os.environ["FOOO"], os.environ["FOOO"]) @patch("umake.tools.os.path.expanduser") def test_add_env_to_user(self, expanderusermock): """Test that adding to user env a list concatenate them to an existing .profile file""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n") tools.add_env_to_user("one path addition", {"FOOO": {"value": ["bar", "baz"]}}) expanderusermock.assert_called_with('~') profile_content = open(profile_file).read() self.assertTrue("Foo\nBar\n" in profile_content, profile_content) # we kept previous content self.assertTrue("export FOOO=bar:baz\n" in profile_content, profile_content) self.assertTrue("bar" in os.environ["FOOO"], os.environ["FOOO"]) @patch("umake.tools.os.path.expanduser") def test_add_env_to_user_with_shell_zsh(self, expanderusermock): """Test that adding to user env appending to an existing .zprofile file""" os.environ['SHELL'] = '/bin/zsh' expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".zprofile") open(profile_file, 'w').write("Foo\nBar\n") tools.add_env_to_user("one path addition", {"FOOO": {"value": "bar"}}) expanderusermock.assert_called_with('~') profile_content = open(profile_file).read() self.assertTrue("Foo\nBar\n" in profile_content, profile_content) # we kept previous content self.assertTrue("export FOOO=bar\n" in profile_content, profile_content) self.assertTrue("bar" in os.environ["FOOO"], os.environ["FOOO"]) @patch("umake.tools.os.path.expanduser") def test_add_env_to_user_keep(self, expanderusermock): """Test that adding to user env appending to an existing env""" os.environ["FOOO"] = "foo" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n") tools.add_env_to_user("one path addition", {"FOOO": {"value": "bar"}}) expanderusermock.assert_called_with('~') profile_content = open(profile_file).read() self.assertTrue("Foo\nBar\n" in profile_content, profile_content) # we kept previous content self.assertTrue("export FOOO=bar:$FOOO\n" in profile_content, profile_content) self.assertEqual(os.environ["FOOO"], "bar:foo") @patch("umake.tools.os.path.expanduser") def test_add_env_to_user_not_keep(self, expanderusermock): """Test that adding to user env without keep replace an existing env""" os.environ["FOOO"] = "foo" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n") tools.add_env_to_user("one path addition", {"FOOO": {"value": "bar", "keep": False}}) expanderusermock.assert_called_with('~') profile_content = open(profile_file).read() self.assertTrue("Foo\nBar\n" in profile_content, profile_content) # we kept previous content self.assertTrue("export FOOO=bar\n" in profile_content, profile_content) self.assertTrue("bar" in os.environ["FOOO"], os.environ["FOOO"]) self.assertFalse("foo" in os.environ["FOOO"], os.environ["FOOO"]) self.assertEqual(os.environ["FOOO"], "bar") @patch("umake.tools.os.path.expanduser") def test_add_env_to_user_empty_file(self, expanderusermock): """Test that adding to user env append to an non existing .profile file""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") tools.add_env_to_user("one path addition", {"FOOO": {"value": "/tmp/foo"}}) expanderusermock.assert_called_with('~') profile_content = open(profile_file).read() self.assertTrue("export FOOO=/tmp/foo\n" in profile_content, profile_content) self.assertTrue("/tmp/foo" in os.environ["FOOO"], os.environ["FOOO"]) @patch("umake.tools.os.path.expanduser") def test_add_to_user_path_twice(self, expanderusermock): """Test that adding to user env twice doesn't add it twice in the file""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n") tools.add_env_to_user("add twice", {"FOOO": {"value": "/tmp/foo"}}) expanderusermock.assert_called_with('~') profile_content = open(profile_file).read() self.assertTrue("Foo\nBar\n" in profile_content, profile_content) # we kept previous content self.assertTrue("export FOOO=/tmp/foo\n" in profile_content, profile_content) tools.add_env_to_user("add twice", {"FOOO": {"value": "/tmp/foo"}}) # ensure, it's only there once profile_content = open(profile_file).read() self.assertEqual(profile_content.count("export FOOO=/tmp/foo"), 1, profile_content) @patch("umake.tools.os.path.expanduser") def test_add_to_user_path_twice_with_new_content(self, expanderusermock): """Test that adding to some env twice for same framework only add the latest""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n") tools.add_env_to_user("add twice", {"FOOO": {"value": "/tmp/foo"}}) expanderusermock.assert_called_with('~') profile_content = open(profile_file).read() self.assertTrue("Foo\nBar\n" in profile_content, profile_content) # we kept previous content self.assertTrue("export FOOO=/tmp/foo\n" in profile_content, profile_content) tools.add_env_to_user("add twice", {"FOOO": {"value": "/tmp/bar"}}) # ensure, it's only there once profile_content = open(profile_file).read() self.assertEqual(profile_content.count("export FOOO=/tmp/bar"), 1, profile_content) @patch("umake.tools.os.path.expanduser") def test_add_to_user_path_twice_other_framework(self, expanderusermock): """Test that adding to user env with another framework add them twice""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n") tools.add_env_to_user("add twice", {"FOOO": {"value": "/tmp/foo"}}) expanderusermock.assert_called_with('~') profile_content = open(profile_file).read() self.assertTrue("Foo\nBar\n" in profile_content, profile_content) # we kept previous content self.assertTrue("export FOOO=/tmp/foo\n" in profile_content, profile_content) tools.add_env_to_user("add twice with other framework", {"BAR": {"value": "/tmp/bar"}}) # ensure, it's only there once profile_content = open(profile_file).read() self.assertTrue("export FOOO=/tmp/foo\n" in profile_content, profile_content) self.assertTrue("export BAR=/tmp/bar\n" in profile_content, profile_content) @patch("umake.tools.os.path.expanduser") def test_add_env_to_user_multiple(self, expanderusermock): """Test that adding to user with multiple env for same framework appending to an existing .profile file""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n") tools.add_env_to_user("one path addition", {"FOOO": {"value": "bar"}, "BAR": {"value": "foo"}}) expanderusermock.assert_called_with('~') profile_content = open(profile_file).read() self.assertTrue("Foo\nBar\n" in profile_content, profile_content) # we kept previous content self.assertTrue("export FOOO=bar\n" in profile_content, profile_content) self.assertTrue("export BAR=foo\n" in profile_content, profile_content) self.assertEqual(os.environ["FOOO"], "bar") self.assertEqual(os.environ["BAR"], "foo") @patch("umake.tools.os.path.expanduser") def test_add_path_to_user(self, expanderusermock): """Test that adding to user path doesn't export as PATH is already exported""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n") tools.add_env_to_user("one path addition", {"PATH": {"value": "/tmp/bar"}}) expanderusermock.assert_called_with('~') profile_content = open(profile_file).read() self.assertTrue("Foo\nBar\n" in profile_content, profile_content) # we kept previous content self.assertTrue("\nPATH=/tmp/bar:$PATH\n" in profile_content, profile_content) self.assertTrue("/tmp/bar" in os.environ["PATH"], os.environ["PATH"]) @patch("umake.tools.os.path.expanduser") def test_remove_user_env(self, expanderusermock): """Remove an env from a user setup""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n# Ubuntu make installation of framework A" "\nexport FOO=bar\n\nexport BAR=baz") tools.remove_framework_envs_from_user("framework A") profile_content = open(profile_file).read() self.assertEqual(profile_content, "Foo\nBar\nexport BAR=baz") @patch("umake.tools.os.path.expanduser") def test_remove_user_env_end(self, expanderusermock): """Remove an env from a user setup being at the end of profile file""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n# Ubuntu make installation of framework A" "\nexport FOO=bar\n\n") tools.remove_framework_envs_from_user("framework A") profile_content = open(profile_file).read() self.assertEqual(profile_content, "Foo\nBar\n") @patch("umake.tools.os.path.expanduser") def test_remove_user_env_not_found(self, expanderusermock): """Remove an env from a user setup with no matching content found""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\nexport BAR=baz") tools.remove_framework_envs_from_user("framework A") profile_content = open(profile_file).read() self.assertEqual(profile_content, "Foo\nBar\nexport BAR=baz") @patch("umake.tools.os.path.expanduser") def test_remove_user_env_no_file(self, expanderusermock): """Remove an env from a user setup with no profile file""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") tools.remove_framework_envs_from_user("framework A") self.assertRaises(FileNotFoundError, open, profile_file) @patch("umake.tools.os.path.expanduser") def test_remove_user_env_multiple_frameworks(self, expanderusermock): """Remove an env from a user setup restraining to the correct framework""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n# Ubuntu make installation of framework B\nexport BAR=bar\n\n" "# Ubuntu make installation of framework A\nexport FOO=bar\n\nexport BAR=baz") tools.remove_framework_envs_from_user("framework A") profile_content = open(profile_file).read() self.assertEqual(profile_content, "Foo\nBar\n# Ubuntu make installation of framework B\nexport BAR=bar\n\n" "export BAR=baz") @patch("umake.tools.os.path.expanduser") def test_remove_user_env_multiple_lines(self, expanderusermock): """Remove an env from a user setup having multiple lines""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n# Ubuntu make installation of framework A" "\nexport FOO=bar\nexport BOO=foo\n\nexport BAR=baz") tools.remove_framework_envs_from_user("framework A") profile_content = open(profile_file).read() self.assertEqual(profile_content, "Foo\nBar\nexport BAR=baz") @patch("umake.tools.os.path.expanduser") def test_remove_user_multiple_same_framework(self, expanderusermock): """Remove an env from a user setup, same framework being repeated multiple times""" expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".profile") open(profile_file, 'w').write("Foo\nBar\n# Ubuntu make installation of framework A\nexport BAR=bar\n\n" "# Ubuntu make installation of framework A\nexport FOO=bar\n\nexport BAR=baz") tools.remove_framework_envs_from_user("framework A") profile_content = open(profile_file).read() self.assertEqual(profile_content, "Foo\nBar\nexport BAR=baz") @patch("umake.tools.os.path.expanduser") def test_remove_user_env_zsh(self, expanderusermock): """Remove an env from a user setup using zsh""" os.environ['SHELL'] = '/bin/zsh' expanderusermock.return_value = self.local_dir profile_file = os.path.join(self.local_dir, ".zprofile") open(profile_file, 'w').write("Foo\nBar\n# Ubuntu make installation of framework A" "\nexport FOO=bar\n\nexport BAR=baz") tools.remove_framework_envs_from_user("framework A") profile_content = open(profile_file).read() self.assertEqual(profile_content, "Foo\nBar\nexport BAR=baz") class TestUserShell(LoggedTestCase): def setUp(self): super().setUp() self.orig_environ = os.environ.copy() os.environ['SHELL'] = '/bin/bash' def tearDown(self): os.environ = self.orig_environ.copy() super().tearDown() def test_return_shell_bash(self): """Default setup should change the bash profile""" self.assertTrue(tools._get_shell_profile_file_path().endswith(".profile")) def test_can_override_zsh_with_SHELL(self): """Can return zsh profile if set""" os.environ['SHELL'] = '/bin/zsh' self.assertTrue(tools._get_shell_profile_file_path().endswith(".zprofile")) def test_return_bash_if_nosense(self): """Return bash if content is garbage""" os.environ['SHELL'] = 'contain_nothing' self.assertTrue(tools._get_shell_profile_file_path().endswith(".profile")) def test_return_bash_if_empty(self): """Return bash if no key""" os.environ.pop('SHELL') self.assertTrue(tools._get_shell_profile_file_path().endswith(".profile")) ubuntu-make-16.02.1/tests/small/test_cli.py0000664000000000000000000002736712656574623015477 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the cli module""" import importlib from ..tools import LoggedTestCase from umake.ui.cli import mangle_args_for_default_framework import os import sys from ..tools import get_data_dir, change_xdg_path, patchelem import umake from umake import frameworks class TestCLIFromFrameworks(LoggedTestCase): """This will test the CLI module with loaded Frameworks""" @classmethod def setUpClass(cls): super().setUpClass() importlib.reload(umake.frameworks) change_xdg_path('XDG_CONFIG_HOME', os.path.join(get_data_dir(), 'configs', "foo")) sys.path.append(get_data_dir()) cls.testframeworks_dir = os.path.join(get_data_dir(), 'testframeworks') with patchelem(umake.frameworks, '__file__', os.path.join(cls.testframeworks_dir, '__init__.py')),\ patchelem(umake.frameworks, '__package__', "testframeworks"): frameworks.load_frameworks() # patch the BaseCategory dictionary from the umake.ui.cli one umake.ui.cli.BaseCategory = frameworks.BaseCategory @classmethod def tearDownClass(cls): change_xdg_path('XDG_CONFIG_HOME', remove=True) sys.path.remove(get_data_dir()) super().tearDownClass() def test_mangle_args_none(self): """No option goes are preserved""" self.assertEqual(mangle_args_for_default_framework([]), []) def test_mangle_args_options_only(self): """Options only goes are preserved""" self.assertEqual(mangle_args_for_default_framework(["--foo", "-b"]), ["--foo", "-b"]) def test_mangle_args_unknown_category(self): """Unknown category are preserved""" self.assertEqual(mangle_args_for_default_framework(["barframework", "-b"]), ["barframework", "-b"]) def test_mangle_args_for_framework(self): """Well formatted framework command are preserved""" self.assertEqual(mangle_args_for_default_framework(["category-a", "framework-a"]), ["category-a", "framework-a"]) def test_mangle_args_for_framework_none_default(self): """Well formatted none default framework command are preserved""" self.assertEqual(mangle_args_for_default_framework(["category-a", "framework-b"]), ["category-a", "framework-b"]) def test_mangle_args_for_framework_with_framework_options(self): """Well formatted framework command with framework options are preserved""" self.assertEqual(mangle_args_for_default_framework(["category-a", "framework-a", "--bar", "install_path", "--foo"]), ["category-a", "framework-a", "--bar", "install_path", "--foo"]) def test_mangle_args_for_framework_global_options(self): """Well formatted framework with global options are preserved""" self.assertEqual(mangle_args_for_default_framework(["category-a", "framework-a"]), ["category-a", "framework-a"]) def test_mangle_args_default_framework(self): """Choose default framework for the category""" self.assertEqual(mangle_args_for_default_framework(["category-a"]), ["category-a", "framework-a"]) def test_mangle_args_without_framework_with_framework_options(self): """Don't choose any framework for a category with default framework and framework options""" self.assertEqual(mangle_args_for_default_framework(["category-a", "install_path", "--foo"]), ["category-a", "install_path", "--foo"]) def test_mangle_args_for_framework_with_global_options(self): """Global options are preserved""" self.assertEqual(mangle_args_for_default_framework(["-v", "--debug", "category-a", "framework-a"]), ["-v", "--debug", "category-a", "framework-a"]) def test_mangle_args_for_framework_with_global_and_framework_options(self): """Global options and framework options are preserved""" self.assertEqual(mangle_args_for_default_framework(["-v", "category-a", "framework-a", "--bar", "install", "--foo"]), ["-v", "category-a", "framework-a", "--bar", "install", "--foo"]) def test_mangle_args_for_default_framework_with_global_options(self): """Global options are preserved, completing with default framework""" self.assertEqual(mangle_args_for_default_framework(["-v", "category-a"]), ["-v", "category-a", "framework-a"]) def test_mangle_args_for_default_framework_with_simple_options(self): """Global and framework simple options are preserved, completing with default framework with simple options""" self.assertEqual(mangle_args_for_default_framework(["-v", "category-a", "--foo", "--bar"]), ["-v", "category-a", "framework-a", "--foo", "--bar"]) def test_mangle_args_with_global_framework_extended_options(self): """Global options and framework extended options are preserved, NOT completing with default framework""" self.assertEqual(mangle_args_for_default_framework(["-v", "category-a", "--bar", "install_path", "--foo"]), ["-v", "category-a", "--bar", "install_path", "--foo"]) def test_mangle_args_with_global_framework_options_after_install(self): """Global and extended framework options are preserved after install_path, NOT completing with dft framework""" self.assertEqual(mangle_args_for_default_framework(["-v", "category-a", "install_path", "--foo"]), ["-v", "category-a", "install_path", "--foo"]) def test_mangle_args_for_default_framework_after_install_with_sep(self): """Add the default framework if the install path has a sep""" self.assertEqual(mangle_args_for_default_framework(["category-a", "install/path"]), ["category-a", "framework-a", "install/path"]) def test_mangle_args_with_global_framework_options_after_install_with_sep(self): """Global and ext framework options are preserved after install_path with sep, completing with dft framework""" self.assertEqual(mangle_args_for_default_framework(["-v", "category-a", "install/path", "--foo"]), ["-v", "category-a", "framework-a", "install/path", "--foo"]) def test_mangle_args_with_global_framework_options_between_install_with_sep(self): """Global and ext framework options are preserved before install_path with sep, completing with dft framework""" self.assertEqual(mangle_args_for_default_framework(["-v", "category-a", "--bar", "install/path", "--foo"]), ["-v", "category-a", "framework-a", "--bar", "install/path", "--foo"]) def test_mangle_args_for_framework_in_main_category(self): """framework in main category is preserved""" self.assertEqual(mangle_args_for_default_framework(["framework-free-a"]), ["framework-free-a"]) def test_mangle_args_for_framework_in_main_category_with_framework_options(self): """framework in main category with framework simple options are preserved""" self.assertEqual(mangle_args_for_default_framework(["framework-free-a", "--foo"]), ["framework-free-a", "--foo"]) def test_mangle_args_for_framework_in_main_category_with_framework_extended_options(self): """framework in main category with framework extended options are preserved""" self.assertEqual(mangle_args_for_default_framework(["framework-free-a", "--foo", "install_path"]), ["framework-free-a", "--foo", "install_path"]) def test_mangle_args_for_framework_in_main_category_with_global_and_framework_extended_options(self): """framework in main category with framework global and extended options are preserved""" self.assertEqual(mangle_args_for_default_framework(["-v", "framework-free-a", "--foo", "install_path"]), ["-v", "framework-free-a", "--foo", "install_path"]) def test_mangle_args_for_framework_in_main_category_with_global_and_framework_extended_options_and_path(self): """framework in main category with framework global and extended options are preserved and path""" self.assertEqual(mangle_args_for_default_framework(["-v", "framework-free-a", "--foo", "install/path"]), ["-v", "framework-free-a", "--foo", "install/path"]) def test_mangle_args_for_category_without_default_framework(self): """No framework in a category without default are preserved""" self.assertEqual(mangle_args_for_default_framework(["category-f"]), ["category-f"]) def test_mangle_args_for_category_without_default_framework_with_extended_options(self): """No framework in a category with ext. option without default are preserved""" self.assertEqual(mangle_args_for_default_framework(["category-f", "--foo", "install_path"]), ["category-f", "--foo", "install_path"]) def test_mangle_args_for_category_without_default_framework_with_install_path(self): """No framework in a category without default are preserved with install path""" self.assertEqual(mangle_args_for_default_framework(["category-f", "--foo", "install/path"]), ["category-f", "--foo", "install/path"]) def test_mangle_args_for_category_without_default_framework_with_global_and_extended_options(self): """No framework in a category without default are preserved with global and ext options""" self.assertEqual(mangle_args_for_default_framework(["-v", "category-f", "--foo", "install_path"]), ["-v", "category-f", "--foo", "install_path"]) def test_mangle_args_for_category_with_remove_global_options(self): """We mangle the remove option if global (before the category name) to append it to the framework option""" self.assertEqual(mangle_args_for_default_framework(["--remove", "category-a", "framework-a"]), ["category-a", "framework-a", "--remove"]) def test_mangle_args_for_category_with_remove_framework_options_middle(self): """We mangle the remove option if framework (between category and framework)""" self.assertEqual(mangle_args_for_default_framework(["category-a", "--remove", "framework-a"]), ["category-a", "framework-a", "--remove"]) def test_mangle_args_for_category_with_remove_framework_options(self): """We don't change the remove option if after framework""" self.assertEqual(mangle_args_for_default_framework(["category-a", "framework-a", "--remove", "--bar"]), ["category-a", "framework-a", "--remove", "--bar"]) def test_mangle_args_for_category_with_short_remove_global_options(self): """We mangle the -r remove option if global (before the category name) to append it to the framework option""" self.assertEqual(mangle_args_for_default_framework(["-r", "category-a", "framework-a"]), ["category-a", "framework-a", "-r"]) ubuntu-make-16.02.1/tests/small/test_interactions.py0000664000000000000000000003311312656574623017414 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests the various umake available interactions""" from ..tools import LoggedTestCase from umake.tools import InputError from umake.interactions import Choice, TextWithChoices, LicenseAgreement, InputText, YesNo, DisplayMessage,\ UnknownProgress from unittest.mock import Mock class TestInteractions(LoggedTestCase): """Test various interactions""" def test_choices(self): """We can instantiate with a choices interactions""" choices = [Choice(0, "Choice0", lambda: ""), Choice(1, "Choice1", lambda: ""), Choice(2, "Choice2", lambda: "")] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.choices, choices) self.assertEqual(inter.content, "Foo Content") def test_choices_with_text_shorcut(self): """We can instantiate choices interactions with shortcut""" choices = [Choice(0, "Choice0", lambda: "", txt_shorcut="A"), Choice(1, "Choice1", lambda: "", txt_shorcut="B"), Choice(2, "Choice2", lambda: "", txt_shorcut="C")] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.choices, choices) self.assertEqual(inter.content, "Foo Content") def test_choices_with_default(self): """We can instantiate choices interactions with a default""" choices = [Choice(0, "Choice0", lambda: ""), Choice(1, "Choice1", lambda: "", is_default=True), Choice(2, "Choice2", lambda: "")] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.choices, choices) self.assertEqual(inter.content, "Foo Content") def test_choices_prompt(self): """We give a prompt for normal choice""" choices = [Choice(0, "Choice0", lambda: ""), Choice(1, "Choice1", lambda: ""), Choice(2, "Choice2", lambda: "")] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.prompt, "Foo Content [Choice0/Choice1/Choice2] ") def test_choices_prompt_with_newline(self): """We give a prompt with newline before options if requested""" choices = [Choice(0, "Choice0", lambda: ""), Choice(1, "Choice1", lambda: ""), Choice(2, "Choice2", lambda: "")] inter = TextWithChoices("Foo Content", choices, newline_before_option=True) self.assertEqual(inter.prompt, "Foo Content\n[Choice0/Choice1/Choice2] ") def test_choices_prompt_with_txt_shortcut(self): """We give a prompt with txt shortcut if any""" choices = [Choice(0, "Choice0", lambda: "", txt_shorcut="A"), Choice(1, "Choice1", lambda: "", txt_shorcut="B"), Choice(2, "Choice2", lambda: "", txt_shorcut="c")] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.prompt, "Foo Content [Choice0 (A)/Choice1 (B)/Choice2 (c)] ") def test_choices_prompt_with_partial_txt_shortcut(self): """We give a prompt, some choices having txt shortcut""" choices = [Choice(0, "Choice0", lambda: "", txt_shorcut="A"), Choice(1, "Choice1", lambda: ""), Choice(2, "Choice2", lambda: "", txt_shorcut="c")] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.prompt, "Foo Content [Choice0 (A)/Choice1/Choice2 (c)] ") def test_instantiate_with_multiple_defaults_raises(self): """Instantiating with multiple defaults raises""" choices = [Choice(0, "Choice0", lambda: "", is_default=True), Choice(1, "Choice1", lambda: "", is_default=True), Choice(2, "Choice2", lambda: "")] self.assertRaises(BaseException, TextWithChoices, "Foo Content", choices) self.expect_warn_error = True def test_choices_choose_run_right_callback(self): """Choose call the correct callback""" callback1 = Mock() callback2 = Mock() choices = [Choice(0, "Choice0", Mock()), Choice(1, "Choice1", callback1), Choice(2, "Choice2", callback2)] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.choose(choice_id=1), callback1.return_value) self.assertEqual(inter.choose(choice_id=2), callback2.return_value) def test_choices_choose_with_shorcut_run_right_callback(self): """Choose with text shortcut calls the correct callback""" callback1 = Mock() callback2 = Mock() choices = [Choice(0, "Choice0", Mock(), txt_shorcut="A"), Choice(1, "Choice1", callback1, txt_shorcut="B"), Choice(2, "Choice2", callback2, txt_shorcut="C")] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.choose(answer='B'), callback1.return_value) self.assertEqual(inter.choose(answer='C'), callback2.return_value) def test_choices_choose_with_label_run_right_callback(self): """Choose with label calls the correct callback""" callback1 = Mock() callback2 = Mock() choices = [Choice(0, "Choice0", Mock(), txt_shorcut="A"), Choice(1, "Choice1", callback1, txt_shorcut="B"), Choice(2, "Choice2", callback2, txt_shorcut="C")] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.choose(answer='Choice1'), callback1.return_value) self.assertEqual(inter.choose(answer='Choice2'), callback2.return_value) def test_choices_choose_with_partial_shorcut_run_right_callback(self): """Choose with some having text shortcut calls the correct callback""" callback1 = Mock() choices = [Choice(0, "Choice0", Mock()), Choice(1, "Choice1", callback1, txt_shorcut="B"), Choice(2, "Choice2", Mock())] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.choose(answer='B'), callback1.return_value) def test_choices_choose_with_shorcut_no_right_casse(self): """Choose with shortcut without respecting the casse""" callback1 = Mock() choices = [Choice(0, "Choice0", Mock(), txt_shorcut="A"), Choice(1, "Choice1", callback1, txt_shorcut="B"), Choice(2, "Choice2", Mock())] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.choose(answer='b'), callback1.return_value) def test_choices_choose_with_label_no_right_casse(self): """Choose with label without respecting the casse""" callback1 = Mock() choices = [Choice(0, "Choice0", Mock()), Choice(1, "Choice1", callback1), Choice(2, "Choice2", Mock())] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.choose(answer='chOIce1'), callback1.return_value) def test_reject_invalid_choices(self): """TestChoice with Choices with the same id raises""" choices = [Choice(0, "Choice0", lambda: ""), Choice(1, "Choice1", lambda: ""), Choice(0, "Choice2", lambda: "")] self.assertRaises(BaseException, TextWithChoices, "Foo Content", choices) self.expect_warn_error = True def test_choices_wrong_choice_id_raise(self): """Wrong choice_id raises an exception""" callback1 = Mock() callback2 = Mock() choices = [Choice(0, "Choice0", Mock()), Choice(1, "Choice1", callback1), Choice(2, "Choice2", callback2)] inter = TextWithChoices("Foo Content", choices) self.assertRaises(InputError, inter.choose, choice_id=3) def test_choices_wrong_txt_shortcut_raise(self): """Wrong txt shortcut raises an exception""" choices = [Choice(0, "Choice0", Mock(), txt_shorcut='A'), Choice(1, "Choice1", Mock(), txt_shorcut='B'), Choice(2, "Choice2", Mock(), txt_shorcut='C')] inter = TextWithChoices("Foo Content", choices) self.assertRaises(InputError, inter.choose, answer='Z') def test_choices_wrong_label_raise(self): """Wrong label answer raises an exception""" choices = [Choice(0, "Choice0", Mock()), Choice(1, "Choice1", Mock()), Choice(2, "Choice2", Mock())] inter = TextWithChoices("Foo Content", choices) self.assertRaises(InputError, inter.choose, answer='abc') def test_choices_choose_default(self): """Choices with a default without any answer return callback""" callback1 = Mock() choices = [Choice(0, "Choice0", Mock()), Choice(1, "Choice1", callback1, is_default=True), Choice(2, "Choice2", Mock())] inter = TextWithChoices("Foo Content", choices) self.assertEqual(inter.choose(), callback1.return_value) def test_choices_choose_no_default_raises(self): """We raise an exception if there is no default and we choose without any answer""" choices = [Choice(0, "Choice0", Mock()), Choice(1, "Choice1", Mock()), Choice(2, "Choice2", Mock())] inter = TextWithChoices("Foo Content", choices) self.assertRaises(InputError, inter.choose) def test_license_agreement(self): """We can instantiate a license agreement interaction""" callback_yes = Mock() callback_no = Mock() inter = LicenseAgreement("License content", callback_yes, callback_no) self.assertEqual(inter.content, "License content") self.assertEqual(len(inter.choices), 2, str(inter.choices)) def test_license_agreement_choice(self): """We have right callbacks called in license choices""" callback_yes = Mock() callback_no = Mock() inter = LicenseAgreement("License content", callback_yes, callback_no) self.assertEqual(inter.choose(choice_id=0), callback_yes.return_value) self.assertEqual(inter.choose(choice_id=1), callback_no.return_value) self.assertEqual(inter.choose(answer='a'), callback_yes.return_value) self.assertEqual(inter.choose(answer='N'), callback_no.return_value) self.assertEqual(inter.choose(), callback_no.return_value) def test_license_agreement_input(self): """We return a license agreement input""" inter = LicenseAgreement("License content", lambda: "", lambda: "") self.assertEqual(inter.input, "[I Accept (a)/I don't accept (N)] ") def test_input_text(self): """We can instantiate an input text""" inter = InputText("Content", lambda: "") self.assertEqual(inter.content, "Content") self.assertEqual(inter.default_input, "") def test_input_text_with_default_input(self): """We can instantiate an input text with a default input""" inter = InputText("Content", lambda: "", default_input="This is a default input") self.assertEqual(inter.default_input, "This is a default input") def test_input_text_callback(self): """An input text runs callback with the result as argument""" callback_fn = Mock() inter = InputText("Content", callback_fn) inter.run_callback("Foo Bar Baz") callback_fn.assert_called_once_with("Foo Bar Baz") def test_yesno(self): """We can instantiate a YesNo""" inter = YesNo("Content?", lambda: "", lambda: "") self.assertEqual(inter.content, "Content?") self.assertEqual(len(inter.choices), 2, str(inter.choices)) self.assertEqual(inter.prompt, "Content? [Yes (y)/No (N)] ") def test_yesno_choose_default(self): """Default is No""" yes_callback = Mock() no_callback = Mock() inter = YesNo("Content?", yes_callback, no_callback) inter.choose("") self.assertTrue(no_callback.called) self.assertFalse(yes_callback.called) def test_yesno_choose_default_overriden(self): """Default is No""" yes_callback = Mock() no_callback = Mock() inter = YesNo("Content?", yes_callback, no_callback, default_is_yes=True) inter.choose("") self.assertTrue(yes_callback.called) self.assertFalse(no_callback.called) def test_yesno_run_answers(self): """Yes runs yes in different ways""" yes_callback = Mock() no_callback = Mock() inter = YesNo("Content?", yes_callback, no_callback) self.assertEqual(inter.choose(choice_id=0), yes_callback.return_value) self.assertEqual(inter.choose(choice_id=1), no_callback.return_value) self.assertEqual(inter.choose(answer='Y'), yes_callback.return_value) self.assertEqual(inter.choose(answer='N'), no_callback.return_value) self.assertEqual(inter.choose(answer='yEs'), yes_callback.return_value) self.assertEqual(inter.choose(answer='nO'), no_callback.return_value) def test_display_message(self): """We can instantiate a message display""" inter = DisplayMessage("Content") self.assertEqual(inter.text, "Content") def test_unknown_progress(self): """We can instantiate an unknown progress""" def foo(): yield inter = UnknownProgress(foo) inter.bar = "BarElement" self.assertEqual(inter.bar, "BarElement") ubuntu-make-16.02.1/tests/small/test_ui.py0000664000000000000000000001421112656574623015325 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the generic ui module""" from concurrent import futures from gi.repository import GLib from time import time from unittest.mock import Mock, patch from ..tools import LoggedTestCase import threading from umake.tools import MainLoop, Singleton from umake.ui import UI class TestUI(LoggedTestCase): """This will test the UI generic module""" def setUp(self): super().setUp() self.mockUIPlug = Mock() self.mockUIPlug._display.side_effect = self.display_UIPlug self.contentType = Mock() self.ui = UI(self.mockUIPlug) self.mainloop_object = MainLoop() self.mainloop_thread = None self.function_thread = None self.display_thread = None self.time_display_call = 0 def tearDown(self): Singleton._instances = {} super().tearDown() # function that will complete once the mainloop is started def wait_for_mainloop_function(self): timeout_time = time() + 5 while not self.mainloop_object.mainloop.is_running(): if time() > timeout_time: raise(BaseException("Mainloop not started in 5 seconds")) def wait_for_mainloop_shutdown(self): timeout_time = time() + 5 while self.mainloop_object.mainloop.is_running(): if time() > timeout_time: raise(BaseException("Mainloop not stopped in 5 seconds")) def get_mainloop_thread(self): self.mainloop_thread = threading.current_thread().ident def start_glib_mainloop(self): # quit after 5 seconds if nothing made the mainloop to end GLib.timeout_add_seconds(5, self.mainloop_object.mainloop.quit) GLib.idle_add(self.get_mainloop_thread) self.mainloop_object.run() def display_UIPlug(self, contentType): """handler to mock _display and save the current thread""" self.time_display_call = time() self.assertEqual(self.contentType, contentType) self.display_thread = threading.current_thread().ident self.mainloop_object.quit(raise_exception=False) def test_singleton(self): """Ensure we are delivering a singleton for UI""" other = UI(self.mockUIPlug) self.assertEqual(self.ui, other) def test_return_to_mainscreen(self): """We call the return to main screen on the UIPlug""" UI.return_main_screen() self.assertTrue(self.mockUIPlug._return_main_screen.called) @patch("umake.tools.sys") def test_call_display(self, mocksys): """We call the display method from the UIPlug""" UI.display(self.contentType) self.start_glib_mainloop() self.wait_for_mainloop_shutdown() self.assertTrue(self.mockUIPlug._display.called) self.assertIsNotNone(self.mainloop_thread) self.assertIsNotNone(self.display_thread) self.assertEqual(self.mainloop_thread, self.display_thread) @patch("umake.tools.sys") def test_call_display_other_thread(self, mocksys): """We call the display method on UIPlug in the main thread from another thread""" def run_display(future): self.function_thread = threading.current_thread().ident UI.display(self.contentType) executor = futures.ThreadPoolExecutor(max_workers=1) future = executor.submit(self.wait_for_mainloop_function) future.add_done_callback(run_display) self.start_glib_mainloop() self.wait_for_mainloop_shutdown() self.assertTrue(self.mockUIPlug._display.called) self.assertIsNotNone(self.mainloop_thread) self.assertIsNotNone(self.function_thread) self.assertIsNotNone(self.display_thread) self.assertNotEqual(self.mainloop_thread, self.function_thread) self.assertEqual(self.mainloop_thread, self.display_thread) @patch("umake.tools.sys") def test_call_delayed_display(self, mocksys): """We call the display method from the UIPlug in delayed_display with 50ms waiting""" UI.delayed_display(self.contentType) now = time() self.start_glib_mainloop() self.wait_for_mainloop_shutdown() self.assertTrue(self.mockUIPlug._display.called) self.assertIsNotNone(self.mainloop_thread) self.assertIsNotNone(self.display_thread) self.assertEqual(self.mainloop_thread, self.display_thread) self.assertTrue(self.time_display_call - now > 0.05) @patch("umake.tools.sys") def test_call_delayed_display_from_other_thread(self, mocksys): """We call the display method from the UIPlug in delayed_display with 50ms waiting, even on other thread""" now = 0 def run_display(future): nonlocal now self.function_thread = threading.current_thread().ident now = time() UI.delayed_display(self.contentType) executor = futures.ThreadPoolExecutor(max_workers=1) future = executor.submit(self.wait_for_mainloop_function) future.add_done_callback(run_display) self.start_glib_mainloop() self.wait_for_mainloop_shutdown() self.assertTrue(self.mockUIPlug._display.called) self.assertIsNotNone(self.mainloop_thread) self.assertIsNotNone(self.function_thread) self.assertIsNotNone(self.display_thread) self.assertNotEqual(self.mainloop_thread, self.function_thread) self.assertEqual(self.mainloop_thread, self.display_thread) self.assertTrue(self.time_display_call - now > 0.05) ubuntu-make-16.02.1/tests/small/test_download_center.py0000664000000000000000000006340612656574623020071 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the download center module using a local server""" from enum import Enum import os from os.path import join, getsize from time import time from unittest.mock import Mock, call from ..tools import get_data_dir, CopyingMock, LoggedTestCase from ..tools.local_server import LocalHttp from umake.network.download_center import DownloadCenter, DownloadItem from umake.tools import ChecksumType, Checksum class TestDownloadCenter(LoggedTestCase): """This will test the download center by sending one or more download requests""" server = None @classmethod def setUpClass(cls): super().setUpClass() cls.server_dir = join(get_data_dir(), "server-content") cls.server = LocalHttp(cls.server_dir) @classmethod def tearDownClass(cls): super().tearDownClass() cls.server.stop() def setUp(self): super().setUp() self.callback = Mock() self.fd_to_close = [] def tearDown(self): super().tearDown() for fd in self.fd_to_close: fd.close() def build_server_address(self, path, localhost=False): """build server address to path to get requested""" return "{}/{}".format(self.server.get_address(localhost=localhost), path) def wait_for_callback(self, mock_function_to_be_called): """wait for the callback to be called until a timeout. Add temp files to the clean file list afterwards""" timeout = time() + 5 while not mock_function_to_be_called.called: if time() > timeout: raise(BaseException("Function not called within 5 seconds")) for calls in mock_function_to_be_called.call_args[0]: for request in calls: if calls[request].fd: self.fd_to_close.append(calls[request].fd) if calls[request].buffer: self.fd_to_close.append(calls[request].buffer) def test_download(self): """we deliver one successful download""" filename = "simplefile" url = self.build_server_address(filename) request = DownloadItem(url, None) DownloadCenter([request], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) with open(join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.fd.read()) self.assertTrue('.' not in result.fd.name, result.fd.name) self.assertIsNone(result.buffer) self.assertIsNone(result.error) def test_redirect_download(self): """we deliver one successful download after being redirected""" filename = "simplefile" # We add a suffix to make the server redirect us. url = self.build_server_address(filename + "-redirect") request = DownloadItem(url, None) DownloadCenter([request], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) self.assertEqual(result.final_url, self.build_server_address(filename)) with open(join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.fd.read()) self.assertIsNone(result.buffer) self.assertIsNone(result.error) def test_header_download(self): """we deliver one successful download with some headers""" filename = "simplefile" url = self.build_server_address(filename + '-headers?header=test') request = DownloadItem(url, headers={"header": "test"}) DownloadCenter([request], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) with open(join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.fd.read()) self.assertTrue('.' not in result.fd.name, result.fd.name) self.assertIsNone(result.buffer) self.assertIsNone(result.error) def test_cookies(self): """Test handing of outgoing and incoming cookies.""" filename = "simplefile" url = self.build_server_address(filename) # The server is rigged to inc the 'int' cookie by one. cookies = {'int': '5'} request = DownloadItem(url, None, cookies=cookies) DownloadCenter([request], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) self.assertEqual('6', result.cookies['int']) def test_content_encoding(self): """Ensure we perform (or don't) content decoding properly.""" # Use an existing .gz file, at data/server-content/www.eclipse.org/.../eclipse-standard-luna-R-linux-gtk.tar.gz filename = "www.eclipse.org/technology/epp/downloads/release/version/"\ "point_release/eclipse-java-linux-gtk.tar.gz" length = 10240 compressed_length = 266 url = self.build_server_address(filename + '-setheaders?content-encoding=gzip') request = DownloadItem(url) DownloadCenter([request], self.callback, download=False) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) self.assertEqual(length, len(result.buffer.getvalue())) # Reset the callback mock. self.callback = Mock() request = DownloadItem(url, ignore_encoding=True) DownloadCenter([request], self.callback, download=False) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) self.assertEqual(compressed_length, len(result.buffer.getvalue())) def test_download_keep_extensions(self): """we deliver successful downloads keeping the extension""" filename = "android-studio-fake.tgz" url = self.build_server_address(filename) request = DownloadItem(url, None) DownloadCenter([request], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) with open(join(self.server_dir, filename), 'rb'): self.assertTrue(result.fd.name.endswith('.tgz'), result.fd.name) def test_download_with_md5(self): """we deliver once successful download, matching md5sum""" filename = "simplefile" request = self.build_server_address(filename) DownloadCenter([DownloadItem(request, Checksum(ChecksumType.md5, '268a5059001855fef30b4f95f82044ed'))], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][request] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) with open(join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.fd.read()) self.assertIsNone(result.buffer) self.assertIsNone(result.error) def test_download_with_sha1sum(self): """we deliver once successful download, matching sha1sum""" filename = "simplefile" request = self.build_server_address(filename) DownloadCenter([DownloadItem(request, Checksum(ChecksumType.sha1, '0562f08aef399135936d6fb4eb0cc7bc1890d5b4'))], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][request] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) with open(join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.fd.read()) self.assertIsNone(result.buffer) self.assertIsNone(result.error) def test_download_with_sha256sum(self): """we deliver once successful download, matching sha256sum""" filename = "simplefile" request = self.build_server_address(filename) DownloadCenter([DownloadItem(request, Checksum(ChecksumType.sha256, 'b1b113c6ed8ab3a14779f7c54179eac2b87d39fcebbf65a50556b8d68caaa2fb'))], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][request] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) with open(join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.fd.read()) self.assertIsNone(result.buffer) self.assertIsNone(result.error) def test_download_with_sha512sum(self): """we deliver once successful download, matching sha512sum""" filename = "simplefile" request = self.build_server_address(filename) DownloadCenter([DownloadItem(request, Checksum(ChecksumType.sha512, '74e20d520ba4ecfdb59d98ac213deccecf591c9c6bfc5996ac158ab6facd6611cce7dd2' '2120b63ebe9217f159506f352ce0ee6c0c2a1d200841ae21635dc5f9a'))], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][request] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) with open(join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.fd.read()) self.assertIsNone(result.buffer) self.assertIsNone(result.error) def test_download_with_no_checksum_value(self): """we deliver one successful download with a checksum type having no value""" filename = "simplefile" url = self.build_server_address(filename) request = DownloadItem(url, Checksum(ChecksumType.md5, None)) DownloadCenter([request], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) with open(join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.fd.read()) self.assertTrue('.' not in result.fd.name, result.fd.name) self.assertIsNone(result.buffer) self.assertIsNone(result.error) def test_download_with_progress(self): """we deliver progress hook while downloading""" filename = "simplefile" filesize = getsize(join(self.server_dir, filename)) report = CopyingMock() request = DownloadItem(self.build_server_address(filename), None) DownloadCenter([request], self.callback, report=report) self.wait_for_callback(self.callback) self.assertEqual(report.call_count, 2) self.assertEqual(report.call_args_list, [call({self.build_server_address(filename): {'size': filesize, 'current': 0}}), call({self.build_server_address(filename): {'size': filesize, 'current': filesize}})]) def test_download_with_multiple_progress(self): """we deliver multiple progress hooks on bigger files""" filename = "biggerfile" filesize = getsize(join(self.server_dir, filename)) report = CopyingMock() request = DownloadItem(self.build_server_address(filename), None) dl_center = DownloadCenter([request], self.callback, report=report) self.wait_for_callback(self.callback) self.assertEqual(report.call_count, 3) self.assertEqual(report.call_args_list, [call({self.build_server_address(filename): {'size': filesize, 'current': 0}}), call({self.build_server_address(filename): {'size': filesize, 'current': dl_center.BLOCK_SIZE}}), call({self.build_server_address(filename): {'size': filesize, 'current': filesize}})]) def test_multiple_downloads(self): """we deliver more than on download in parallel""" requests = [DownloadItem(self.build_server_address("biggerfile"), None), DownloadItem(self.build_server_address("simplefile"), None)] DownloadCenter(requests, self.callback) self.wait_for_callback(self.callback) # ensure we saw 2 different requests callback_args, callback_kwargs = self.callback.call_args map_result = callback_args[0] self.assertIn(self.build_server_address("biggerfile"), map_result) self.assertIn(self.build_server_address("simplefile"), map_result) # ensure each temp file corresponds to the source content for filename in ("biggerfile", "simplefile"): with open(join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), map_result[self.build_server_address(filename)].fd.read()) self.assertEqual(self.callback.call_count, 1, "Global done callback is only called once") def test_multiple_downloads_with_reports(self): """we deliver more than on download in parallel""" requests = [DownloadItem(self.build_server_address("biggerfile"), None), DownloadItem(self.build_server_address("simplefile"), None)] report = CopyingMock() DownloadCenter(requests, self.callback, report=report) self.wait_for_callback(self.callback) self.assertEqual(report.call_count, 5) # ensure that first call only contains one file callback_args, callback_kwargs = report.call_args_list[0] map_result = callback_args[0] self.assertEqual(len(map_result), 1, str(map_result)) # ensure that last call is what we expect result_dict = {} for filename in ("biggerfile", "simplefile"): file_size = getsize(join(self.server_dir, filename)) result_dict[self.build_server_address(filename)] = {'size': file_size, 'current': file_size} self.assertEqual(report.call_args, call(result_dict)) self.assertEqual(self.callback.call_count, 1, "Global done callback is only called once") def test_404_url(self): """we return an error for a request including a 404 url""" request = DownloadItem(self.build_server_address("does_not_exist"), None) DownloadCenter([request], self.callback) self.wait_for_callback(self.callback) # no download means the file isn't in the result callback_args, callback_kwargs = self.callback.call_args result = callback_args[0][self.build_server_address("does_not_exist")] self.assertIn("404", result.error) self.assertIn("File not found", result.error) self.assertIsNone(result.buffer) self.assertIsNone(result.fd) self.expect_warn_error = True self.assertEqual(self.callback.call_count, 1, "Global done callback is only called once") def test_multiple_with_one_404_url(self): """we raise an error when we try to download 404 urls""" requests = [DownloadItem(self.build_server_address("does_not_exist"), None), DownloadItem(self.build_server_address("simplefile"), None)] DownloadCenter(requests, self.callback) self.wait_for_callback(self.callback) # we should have the two content, one in error callback_args, callback_kwargs = self.callback.call_args map_result = callback_args[0] self.assertEqual(len(map_result), 2, str(map_result)) self.assertIsNotNone(map_result[self.build_server_address("does_not_exist")].error) self.assertIsNotNone(map_result[self.build_server_address("simplefile")].fd) self.expect_warn_error = True self.assertEqual(self.callback.call_count, 1, "Global done callback is only called once") def test_in_memory_download(self): """we deliver download on memory objects""" filename = "simplefile" url = self.build_server_address(filename) request = DownloadItem(url, None) DownloadCenter([request], self.callback, download=False) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) with open(join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.buffer.read()) self.assertIsNone(result.fd) self.assertIsNone(result.error) def test_unsupported_protocol(self): """Raises an exception when trying to download for an unsupported protocol""" filename = "simplefile" url = self.build_server_address(filename).replace('http', 'sftp') request = DownloadItem(url, None) DownloadCenter([request], self.callback, download=False) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][url] self.assertIn("Protocol not supported", result.error) self.assertIsNone(result.buffer) self.assertIsNone(result.fd) self.expect_warn_error = True def test_download_with_wrong_md5(self): """we raise an error if we don't have the correct md5sum""" filename = "simplefile" request = self.build_server_address(filename) DownloadCenter([DownloadItem(request, Checksum(ChecksumType.md5, 'AAAAA'))], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][request] self.assertIn("Corrupted download", result.error) self.assertIsNone(result.buffer) self.assertIsNone(result.fd) self.expect_warn_error = True def test_download_with_wrong_sha1(self): """we raise an error if we don't have the correct sha1""" filename = "simplefile" request = self.build_server_address(filename) DownloadCenter([DownloadItem(request, Checksum(ChecksumType.sha1, 'AAAAA'))], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][request] self.assertIn("Corrupted download", result.error) self.assertIsNone(result.buffer) self.assertIsNone(result.fd) self.expect_warn_error = True def test_download_with_wrong_sha256(self): """we raise an error if we don't have the correct sha256""" filename = "simplefile" request = self.build_server_address(filename) DownloadCenter([DownloadItem(request, Checksum(ChecksumType.sha256, 'AAAAA'))], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][request] self.assertIn("Corrupted download", result.error) self.assertIsNone(result.buffer) self.assertIsNone(result.fd) self.expect_warn_error = True def test_download_with_no_size(self): """we deliver one successful download, even if size isn't provided. Progress returns -1 though""" filename = "simplefile-with-no-content-length" url = self.build_server_address(filename) request = DownloadItem(url, None) report = CopyingMock() DownloadCenter([request], self.callback, report=report) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) with open(join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.fd.read()) self.assertIsNone(result.buffer) self.assertIsNone(result.error) self.assertEqual(report.call_count, 2) self.assertEqual(report.call_args_list, [call({self.build_server_address(filename): {'size': -1, 'current': 0}}), call({self.build_server_address(filename): {'size': -1, 'current': 8192}})]) def test_download_with_wrong_checksumtype(self): """we raise an error if we don't have a support checksum type""" class WrongChecksumType(Enum): didrocksha = "didrocksha" filename = "simplefile" request = self.build_server_address(filename) DownloadCenter([DownloadItem(request, Checksum(WrongChecksumType.didrocksha, 'AAAAA'))], self.callback) self.wait_for_callback(self.callback) result = self.callback.call_args[0][0][request] self.assertIn("Unsupported checksum type", result.error) self.assertIsNone(result.buffer) self.assertIsNone(result.fd) self.expect_warn_error = True class TestDownloadCenterSecure(LoggedTestCase): """This will test the download center in secure mode by sending one or more download requests""" server = None @classmethod def setUpClass(cls): super().setUpClass() cls.server_dir = join(get_data_dir(), "server-content") cls.server = LocalHttp(cls.server_dir, use_ssl=["localhost"]) @classmethod def tearDownClass(cls): super().tearDownClass() cls.server.stop() def setUp(self): super().setUp() self.callback = Mock() self.fd_to_close = [] def tearDown(self): super().tearDown() for fd in self.fd_to_close: fd.close() def test_download(self): """we deliver one successful download under ssl with known cert""" filename = "simplefile" # The host name is important here, since we verify it, so request # the localhost address. url = TestDownloadCenter.build_server_address(self, filename, True) request = DownloadItem(url, None) # prepare the cert and set it as the trusted system context os.environ['REQUESTS_CA_BUNDLE'] = join(get_data_dir(), 'localhost.pem') try: DownloadCenter([request], self.callback) TestDownloadCenter.wait_for_callback(self, self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) with open(os.path.join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.fd.read()) finally: del os.environ['REQUESTS_CA_BUNDLE'] def test_redirect_download(self): """we deliver one successful download after being redirected""" filename = "simplefile" # We add a suffix to make the server redirect us. url = TestDownloadCenter.build_server_address(self, filename + "-redirect", localhost=True) request = DownloadItem(url, None) os.environ['REQUESTS_CA_BUNDLE'] = join(get_data_dir(), 'localhost.pem') try: DownloadCenter([request], self.callback) TestDownloadCenter.wait_for_callback(self, self.callback) result = self.callback.call_args[0][0][url] self.assertTrue(self.callback.called) self.assertEqual(self.callback.call_count, 1) self.assertEqual(result.final_url, TestDownloadCenter.build_server_address(self, filename, localhost=True)) with open(os.path.join(self.server_dir, filename), 'rb') as file_on_disk: self.assertEqual(file_on_disk.read(), result.fd.read()) self.assertIsNone(result.buffer) self.assertIsNone(result.error) finally: del os.environ['REQUESTS_CA_BUNDLE'] def test_with_invalid_certificate(self): """we error on invalid ssl certificate""" filename = "simplefile" url = TestDownloadCenter.build_server_address(self, filename) request = DownloadItem(url, None) DownloadCenter([request], self.callback) TestDownloadCenter.wait_for_callback(self, self.callback) result = self.callback.call_args[0][0][url] self.assertIn("CERTIFICATE_VERIFY_FAILED", result.error) self.assertIsNone(result.buffer) self.assertIsNone(result.fd) self.expect_warn_error = True ubuntu-make-16.02.1/tests/small/__init__.py0000664000000000000000000001131512656574623015412 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2016 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Some common tools between small tests""" import apt import os import shutil import stat import tempfile from ..tools import get_data_dir, LoggedTestCase, manipulate_path_env from unittest.mock import Mock from umake import tools class DpkgAptSetup(LoggedTestCase): """This parent class is there to setup and teardown a dpkg chroot test environment""" @classmethod def setUpClass(cls): super().setUpClass() apt.apt_pkg.config.set("Dir::Cache::pkgcache", "") apt.apt_pkg.config.set("Dir::Cache::srcpkgcache", "") apt.apt_pkg.config.clear("APT::Update::Post-Invoke") apt.apt_pkg.config.clear("APT::Update::Post-Invoke-Success") apt.apt_pkg.config.clear("DPkg::Post-Invoke") cls.apt_package_dir = os.path.join(get_data_dir(), "apt") cls.apt_status_dir = os.path.join(cls.apt_package_dir, "states") def setUp(self): super().setUp() self.chroot_path = tempfile.mkdtemp() # create the fake dpkg wrapper os.makedirs(os.path.join(self.chroot_path, "usr", "bin")) self.dpkg = os.path.join(self.chroot_path, "usr", "bin", "dpkg") with open(self.dpkg, "w") as f: # Don't nest fakeroot calls when having some dpkg hook scripts f.write("#!/bin/sh\nprependfakeroot=''\nif [ -z \"$FAKEROOTKEY\" ]; then\nprependfakeroot=fakeroot\nfi\n " "$prependfakeroot /usr/bin/dpkg --root={root} --force-not-root --force-bad-path " "--log={root}/var/log/dpkg.log \"$@\"".format(root=self.chroot_path)) st = os.stat(self.dpkg) os.chmod(self.dpkg, st.st_mode | stat.S_IEXEC) # for arch cache support tools._current_arch = None tools._foreign_arch = None manipulate_path_env(os.path.dirname(self.dpkg)) # apt requirements apt_etc = os.path.join(self.chroot_path, 'etc', 'apt') os.makedirs(apt_etc) os.makedirs(os.path.join(self.chroot_path, 'var', 'log', 'apt')) with open(os.path.join(apt_etc, 'sources.list'), 'w') as f: f.write('deb file:{} /'.format(self.apt_package_dir)) # dpkg requirements dpkg_dir = os.path.join(self.chroot_path, 'var', 'lib', 'dpkg') os.makedirs(dpkg_dir) os.mkdir(os.path.join(os.path.join(dpkg_dir, 'info'))) os.mkdir(os.path.join(os.path.join(dpkg_dir, 'triggers'))) os.mkdir(os.path.join(os.path.join(dpkg_dir, 'updates'))) open(os.path.join(dpkg_dir, 'status'), 'w').close() open(os.path.join(dpkg_dir, 'available'), 'w').close() self.dpkg_dir = dpkg_dir cache = apt.Cache(rootdir=self.chroot_path) apt.apt_pkg.config.set("Dir::Bin::dpkg", self.dpkg) # must be called after initializing the rootdir cache cache.update() cache.open() if hasattr(self, "handler"): self.handler.cache = cache self.done_callback = Mock() self._saved_seteuid_fn = os.seteuid self._saved_setegid_fn = os.setegid self._saved_geteuid_fn = os.geteuid self._saved_getenv = os.getenv self.user_uid, self.user_gid = (4242, 4242) os.seteuid = Mock() os.setegid = Mock() os.geteuid = Mock() os.geteuid.return_value = self.user_uid os.getenv = Mock(side_effect=self._mock_get_env) def tearDown(self): # remove arch cache support manipulate_path_env(os.path.dirname(self.dpkg), remove=True) tools._current_arch = None tools._foreign_arch = None shutil.rmtree(self.chroot_path) os.seteuid = self._saved_seteuid_fn os.setegid = self._saved_setegid_fn os.geteuid = self._saved_geteuid_fn os.getenv = self._saved_getenv super().tearDown() def _mock_get_env(self, env, default=None): if os.geteuid() == 0: if env == "SUDO_UID": return str(self.user_uid) elif env == "SUDO_GID": return str(self.user_gid) return self._saved_getenv(env) ubuntu-make-16.02.1/tests/small/test_requirements_handler.py0000664000000000000000000006254412656574623021144 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Tests for the download center module using a local server""" import os import shutil import subprocess from time import time from unittest.mock import Mock, call, patch import umake from . import DpkgAptSetup from umake.network.requirements_handler import RequirementsHandler from umake import tools class TestRequirementsHandler(DpkgAptSetup): """This will test the download center by sending one or more download requests""" @classmethod def setUpClass(cls): super().setUpClass() cls.handler = RequirementsHandler() def count_number_progress_call(self, call_args_list, tag): """Count the number of tag in progress call and return it""" count = 0 for call in call_args_list: if call[0][0]['step'] == tag: count += 1 return count def wait_for_callback(self, mock_function_to_be_called, timeout=10): """wait for the callback to be called until a timeout. Add temp files to the clean file list afterwards""" timeout_time = time() + timeout while not mock_function_to_be_called.called: if time() > timeout_time: raise(BaseException("Function not called within {} seconds".format(timeout))) def test_singleton(self): """Ensure we are delivering a singleton for RequirementsHandler""" other = RequirementsHandler() self.assertEqual(self.handler, other) def test_install(self): """Install one package""" self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertEqual(self.done_callback.call_args[0][0].bucket, ['testpackage']) self.assertIsNone(self.done_callback.call_args[0][0].error) self.assertTrue(self.handler.is_bucket_installed(["testpackage"])) def test_install_multi_arch_current_arch(self): """We install a multi_arch package corresponding to current arch""" multi_arch_name = "testpackage:{}".format(tools.get_current_arch()) self.handler.install_bucket([multi_arch_name], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertEqual(self.done_callback.call_args[0][0].bucket, [multi_arch_name]) self.assertIsNone(self.done_callback.call_args[0][0].error) self.assertTrue(self.handler.is_bucket_installed(["testpackage"])) def test_install_perm(self): """When we install one package, we first switch to root""" self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) os.seteuid.assert_called_once_with(0) os.setegid.assert_called_once_with(0) def test_install_return_error_if_no_perm(self): """Return an exception when we try to install and we can't switch to root""" os.seteuid.side_effect = PermissionError() self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertIsNotNone(self.done_callback.call_args[0][0].error) self.assertFalse(self.handler.is_bucket_installed(["testpackage"])) self.expect_warn_error = True def test_install_perm_switch_back_user(self): """When we install one package, we switch back to user at the end""" umake.network.requirements_handler.os.geteuid.return_value = 0 self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) # we call it twice and the latest is the user id self.assertEqual(os.seteuid.call_count, 2) self.assertEqual(os.seteuid.call_args, call(self.user_uid)) self.assertEqual(os.setegid.call_args, call(self.user_gid)) def test_install_progress(self): """Install one package and get progress feedback""" progress_callback = Mock() self.handler.install_bucket(["testpackage"], progress_callback, self.done_callback) self.wait_for_callback(self.done_callback) downloading_msg = self.count_number_progress_call(progress_callback.call_args_list, RequirementsHandler.STATUS_DOWNLOADING) installing_msg = self.count_number_progress_call(progress_callback.call_args_list, RequirementsHandler.STATUS_INSTALLING) self.assertTrue(downloading_msg > 1) self.assertTrue(installing_msg > 1) # the first download call is at 0% of progress. testpackage is 1byte to download self.assertEqual(progress_callback.call_args_list[0][0][0], {'step': 0, 'pkg_size_download': 1, 'percentage': 0.0}) callfound = False for call in progress_callback.call_args_list: if call[0][0] == {'step': 1, 'percentage': 0.0}: callfound = True break self.assertTrue(callfound, "We expect to have one install step at 0% call in the list") def test_install_multiple_packages(self): """Install multiple packages in one shot""" self.handler.install_bucket(["testpackage", "testpackage0"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertEqual(self.done_callback.call_args[0][0].bucket, ['testpackage', 'testpackage0']) self.assertIsNone(self.done_callback.call_args[0][0].error) self.assertTrue(self.handler.is_bucket_installed(["testpackage", "testpackage0"])) def test_install_multiple_packages_progress(self): """Install multiple packages in one shot and ensure that progress is global""" progress_callback = Mock() self.handler.install_bucket(["testpackage", "testpackage0"], progress_callback, self.done_callback) self.wait_for_callback(self.done_callback) downloading_msg = self.count_number_progress_call(progress_callback.call_args_list, RequirementsHandler.STATUS_DOWNLOADING) installing_msg = self.count_number_progress_call(progress_callback.call_args_list, RequirementsHandler.STATUS_INSTALLING) self.assertTrue(downloading_msg > 1) self.assertTrue(installing_msg > 1) # the first download call is at 0% of progress. testpackage is 1byte to download self.assertEqual(progress_callback.call_args_list[0][0][0], {'step': 0, 'pkg_size_download': 1, 'percentage': 0.0}) def test_install_pending(self): """Appending two installations and wait for results. Only the first call should have progress""" done_callback0 = Mock() self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.handler.install_bucket(["testpackage0"], lambda x: "", done_callback0) self.wait_for_callback(self.done_callback) self.wait_for_callback(done_callback0) self.assertTrue(self.handler.is_bucket_installed(["testpackage", "testpackage0"])) def test_install_pending_order(self): """Installation order of pending requests are respected""" done_callback = Mock() done_callback.side_effect = self.done_callback done_callback0 = Mock() done_callback0.side_effect = self.done_callback ordered_progress_callback = Mock() progress_callback = Mock() progress_callback.side_effect = ordered_progress_callback progress_callback0 = Mock() progress_callback0.side_effect = ordered_progress_callback self.handler.install_bucket(["testpackage"], progress_callback, done_callback) self.handler.install_bucket(["testpackage0"], progress_callback0, done_callback0) self.wait_for_callback(done_callback) self.wait_for_callback(done_callback0) self.assertEqual(self.done_callback.call_args_list, [call(RequirementsHandler.RequirementsResult(bucket=['testpackage'], error=None)), call(RequirementsHandler.RequirementsResult(bucket=['testpackage0'], error=None))]) # we will get progress with 0, 1 (first bucket), 0, 1 (second bucket). So 4 progress signal status change current_status = RequirementsHandler.STATUS_DOWNLOADING current_status_change_count = 1 calls = ordered_progress_callback.call_args_list for current_call in calls[1:]: if current_call[0][0]['step'] != current_status: current_status = current_call[0][0]['step'] current_status_change_count += 1 self.assertEqual(current_status_change_count, 4) def test_install_pending_callback_not_mixed(self): """Callbacks are separated on pending requests""" done_callback = Mock() done_callback.side_effect = self.done_callback done_callback0 = Mock() done_callback0.side_effect = self.done_callback global_progress_callback = Mock() progress_callback = Mock() progress_callback.side_effect = global_progress_callback progress_callback0 = Mock() progress_callback0.side_effect = global_progress_callback self.handler.install_bucket(["testpackage"], progress_callback, done_callback) self.handler.install_bucket(["testpackage0"], progress_callback0, done_callback0) self.wait_for_callback(done_callback) self.wait_for_callback(done_callback0) self.assertTrue(progress_callback.call_count < global_progress_callback.call_count) self.assertTrue(progress_callback0.call_count < global_progress_callback.call_count) self.assertTrue(done_callback.call_count < self.done_callback.call_count) self.assertTrue(done_callback0.call_count < self.done_callback.call_count) def test_install_twice(self): """Test appending two installations and wait for results. Only the first call should have progress""" progress_callback = Mock() progress_second_callback = Mock() done_callback = Mock() self.handler.install_bucket(["testpackage"], progress_callback, done_callback) self.handler.install_bucket(["testpackage"], progress_second_callback, self.done_callback) self.wait_for_callback(done_callback) self.wait_for_callback(self.done_callback) self.assertTrue(self.handler.is_bucket_installed(["testpackage"])) self.assertFalse(progress_second_callback.called) def test_deps(self): """Installing one package, ensure the dep (even with auto_fix=False) is installed""" self.handler.install_bucket(["testpackage1"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertTrue(self.handler.is_bucket_installed(["testpackage1", "testpackage"])) def test_fail(self): """An error is caught when asking for the impossible (installing 2 packages in conflicts)""" self.handler.install_bucket(["testpackage", "testpackage2"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertIsNotNone(self.done_callback.call_args[0][0].error) both_package_installed = self.handler.is_bucket_installed(["testpackage"]) and \ self.handler.is_bucket_installed(["testpackage2"]) self.assertFalse(both_package_installed) self.expect_warn_error = True def test_install_shadow_pkg(self): """We return an error if we try to install a none existing package""" self.handler.install_bucket(["foo"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertIsNotNone(self.done_callback.call_args[0][0].error) self.expect_warn_error = True def test_error_in_dpkg(self): """An error while installing a package is caught""" with open(self.dpkg, mode='w') as f: f.write("#!/bin/sh\nexit 1") # Simulate an error in dpkg self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertIsNotNone(self.done_callback.call_args[0][0].error) self.expect_warn_error = True def test_is_installed_bucket_installed(self): """Install bucket should return True if a bucket is installed""" self.handler.install_bucket(["testpackage", "testpackage1"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertTrue(self.handler.is_bucket_installed(['testpackage', 'testpackage1'])) def test_is_installed_bucket_half_installed(self): """Install bucket shouldn't be considered installed if not fully installed""" self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertFalse(self.handler.is_bucket_installed(['testpackage', 'testpackage1'])) def test_is_installed_bucket_not_installed(self): """Install bucket should return False if a bucket is not installed""" self.assertFalse(self.handler.is_bucket_installed(['testpackage', 'testpackage1'])) def test_is_bucket_installed_multi_arch_current_arch(self): """Installed bucket should return True even if contains multi-arch part with current package""" self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertTrue(self.handler.is_bucket_installed(["testpackage:{}".format(tools.get_current_arch())])) def test_is_bucket_installed_with_unavailable_package(self): """Bucket isn't installed if some package are even not in the cache""" self.assertFalse(self.handler.is_bucket_installed(["testpackagedoesntexist"])) def test_is_bucket_installed_with_unavailable_multiarch_package(self): """Bucket isn't installed if some multiarch package are even not in the cache""" self.assertFalse(self.handler.is_bucket_installed(["testpackagedoesntexist:foo"])) def test_is_bucket_installed_with_foreign_archs_package_not_installed(self): """After adding a foreign arch, test that the package is not installed and report so""" subprocess.call([self.dpkg, "--add-architecture", "foo"]) self.handler.cache.open() # reopen the cache with the new added architecture self.assertFalse(self.handler.is_bucket_installed(['testpackagefoo:foo'])) def test_is_bucket_uptodate_bucket_uptodate(self): """Up to date bucket is reported as such""" self.handler.install_bucket(["testpackage", "testpackage1"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertTrue(self.handler.is_bucket_uptodate(['testpackage', 'testpackage1'])) def test_is_bucket_uptodate_bucket_not_installed(self): """Not installed bucket is not uptodate""" self.assertFalse(self.handler.is_bucket_uptodate(['testpackage', 'testpackage1'])) def test_is_bucket_uptodate_bucket_half_installed(self): """bucket shouldn't be considered up to date if not fully installed""" self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertFalse(self.handler.is_bucket_uptodate(['testpackage', 'testpackage1'])) def test_is_bucket_uptodate_multi_arch_current_arch(self): """Installed bucket should return as being uptodate even if contains multi-arch part with current package""" self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertTrue(self.handler.is_bucket_uptodate(["testpackage:{}".format(tools.get_current_arch())])) def test_is_bucket_uptodate_with_unavailable_package(self): """Bucket isn't uptodate if some package are even not in the cache""" self.assertFalse(self.handler.is_bucket_uptodate(["testpackagedoesntexist"])) def test_is_bucket_uptodate_with_unavailable_multiarch_package(self): """Bucket isn't uptodate if some multiarch package are even not in the cache""" self.assertFalse(self.handler.is_bucket_uptodate(["testpackagedoesntexist:foo"])) def test_is_bucket_uptodate_with_foreign_archs(self): """After adding a foreign arch, test that the package is uptodate and report so""" subprocess.call([self.dpkg, "--add-architecture", "foo"]) self.handler.cache.open() # reopen the cache with the new added architecture self.handler.install_bucket(["testpackagefoo:foo"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertTrue(self.handler.is_bucket_uptodate(['testpackagefoo:foo'])) def test_is_bucket_uptodate_with_foreign_archs_package_not_installed(self): """After adding a foreign arch, test that the package is not uptodate and report so""" subprocess.call([self.dpkg, "--add-architecture", "foo"]) self.handler.cache.open() # reopen the cache with the new added architecture self.assertFalse(self.handler.is_bucket_uptodate(['testpackagefoo:foo'])) def test_is_bucket_uptodate_with_possible_upgrade(self): """If one package of the bucket can be upgraded, tell it's not up to date""" shutil.copy(os.path.join(self.apt_status_dir, "testpackage_installed_dpkg_status"), os.path.join(self.dpkg_dir, "status")) self.handler.cache.open() self.assertFalse(self.handler.is_bucket_uptodate(["testpackage"])) def test_is_bucket_available(self): """An available bucket on that platform is reported""" self.assertTrue(self.handler.is_bucket_available(['testpackage', 'testpackage1'])) def test_is_bucket_available_multi_arch_current_arch(self): """We return a package is available on the current platform""" self.assertTrue(self.handler.is_bucket_available(['testpackage:{}'.format(tools.get_current_arch())])) def test_unavailable_bucket(self): """An unavailable bucket on that platform is reported""" self.assertFalse(self.handler.is_bucket_available(['testpackage42', 'testpackage404'])) def test_is_bucket_available_foreign_archs(self): """After adding a foreign arch, test that the package is available on it""" subprocess.call([self.dpkg, "--add-architecture", "foo"]) self.handler.cache.open() # reopen the cache with the new added architecture self.assertTrue(self.handler.is_bucket_available(['testpackagefoo:foo', 'testpackage1'])) def test_is_bucket_unavailable_with_foreign_archs(self): """After adding a foreign arch, test that the package is unavailable and report so""" subprocess.call([self.dpkg, "--add-architecture", "foo"]) self.handler.cache.open() # reopen the cache with the new added architecture self.assertFalse(self.handler.is_bucket_available(['testpackagebar:foo', 'testpackage1'])) def test_bucket_unavailable_but_foreign_archs_no_added(self): """Bucket is set as available when foreign arch not added""" self.assertTrue(self.handler.is_bucket_available(['testpackagefoo:foo', 'testpackage1'])) def test_bucket_unavailable_foreign_archs_no_added_another_package_not_available(self): """Bucket is set as unavailable when foreign arch not added, but another package on current arch is unavailable""" self.assertFalse(self.handler.is_bucket_available(['testpackagefoo:foo', 'testpackage123'])) def test_apt_cache_not_ready(self): """When the first apt.Cache() access tells it's not ready, we wait and recover""" origin_open = self.handler.cache.open raise_returned = False def cache_call(*args, **kwargs): nonlocal raise_returned if raise_returned: return origin_open() else: raise_returned = True raise SystemError with patch.object(self.handler.cache, 'open', side_effect=cache_call) as openaptcache_mock: self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertEqual(openaptcache_mock.call_count, 2) def test_upgrade(self): """Upgrade one package already installed""" shutil.copy(os.path.join(self.apt_status_dir, "testpackage_installed_dpkg_status"), os.path.join(self.dpkg_dir, "status")) self.handler.cache.open() self.assertTrue(self.handler.is_bucket_installed(["testpackage"])) self.assertEqual(self.handler.cache["testpackage"].installed.version, "0.0.0") self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertEqual(self.done_callback.call_args[0][0].bucket, ['testpackage']) self.assertIsNone(self.done_callback.call_args[0][0].error) self.assertTrue(self.handler.is_bucket_installed(["testpackage"])) self.assertEqual(self.handler.cache["testpackage"].installed.version, "0.0.1") def test_one_install_one_upgrade(self): """Install and Upgrade one package in the same bucket""" shutil.copy(os.path.join(self.apt_status_dir, "testpackage_installed_dpkg_status"), os.path.join(self.dpkg_dir, "status")) self.handler.cache.open() self.assertTrue(self.handler.is_bucket_installed(["testpackage"])) self.assertEqual(self.handler.cache["testpackage"].installed.version, "0.0.0") self.assertFalse(self.handler.is_bucket_installed(["testpackage0"])) self.handler.install_bucket(["testpackage", "testpackage0"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertEqual(self.done_callback.call_args[0][0].bucket, ['testpackage', 'testpackage0']) self.assertIsNone(self.done_callback.call_args[0][0].error) self.assertTrue(self.handler.is_bucket_installed(["testpackage", "testpackage0"])) self.assertEqual(self.handler.cache["testpackage"].installed.version, "0.0.1") def test_install_with_foreign_foreign_arch_added(self): """Install packages with a foreign arch added""" subprocess.call([self.dpkg, "--add-architecture", "foo"]) self.handler.cache.open() # reopen the cache with the new added architecture bucket = ["testpackagefoo:foo", "testpackage1"] with patch("umake.tools.subprocess") as subprocess_mock: subprocess_mock.check_output.side_effect = subprocess.check_output self.handler.install_bucket(bucket, lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertFalse(subprocess_mock.call.called) self.assertEqual(self.done_callback.call_args[0][0].bucket, bucket) self.assertIsNone(self.done_callback.call_args[0][0].error) self.assertTrue(self.handler.is_bucket_installed(bucket)) def test_install_with_foreign_foreign_arch_not_added(self): """Install packages with a foreign arch, while the foreign arch wasn't added""" bucket = ["testpackagefoo:foo", "testpackage1"] self.handler.install_bucket(bucket, lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertEqual(self.done_callback.call_args[0][0].bucket, bucket) self.assertIsNone(self.done_callback.call_args[0][0].error) self.assertTrue(self.handler.is_bucket_installed(bucket)) def test_install_with_foreign_foreign_arch_add_fails(self): """Install packages with a foreign arch, where adding a foreign arch fails""" bucket = ["testpackagefoo:foo", "testpackage1"] with patch("umake.tools.subprocess") as subprocess_mock: subprocess_mock.call.return_value = 1 self.handler.install_bucket(bucket, lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertTrue(subprocess_mock.call.called) self.assertFalse(self.handler.is_bucket_installed(bucket)) self.expect_warn_error = True def test_cant_change_seteuid(self): """Not being able to change the euid to root returns an error""" os.seteuid.side_effect = PermissionError() self.handler.install_bucket(["testpackage"], lambda x: "", self.done_callback) self.wait_for_callback(self.done_callback) self.assertEqual(self.done_callback.call_args[0][0].bucket, ['testpackage']) self.assertIsNotNone(self.done_callback.call_args[0][0].error) self.assertFalse(self.handler.is_bucket_installed(["testpackage"])) self.expect_warn_error = True ubuntu-make-16.02.1/tests/__init__.py0000664000000000000000000000277412656574623014313 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Ensure we keep a sane formatting syntax""" import os import pep8 from .tools import get_root_dir import umake from unittest import TestCase class CodeCheck(TestCase): def test_pep8(self): """Proceed a pep8 checking Note that we have a .pep8 config file for maximum line length tweak and excluding the virtualenv dir.""" pep8style = pep8.StyleGuide(config_file=os.path.join(get_root_dir(), '.pep8')) # we want to use either local or system umake, but always local tests files umake_dir = os.path.dirname(umake.__file__) results = pep8style.check_files([umake_dir, os.path.join(get_root_dir(), "tests"), os.path.join(get_root_dir(), "bin")]) self.assertEqual(results.get_statistics(), []) ubuntu-make-16.02.1/tests/tools/0000775000000000000000000000000012656574623013330 5ustar ubuntu-make-16.02.1/tests/tools/check_and_kill_process0000775000000000000000000000301012656574623017720 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA from contextlib import suppress import os import signal import sys kill_process = sys.argv[1] == "True" process_grep = sys.argv[2:] for pid in os.listdir('/proc'): if not pid.isdigit() or int(pid) == os.getpid(): continue # ignore processes that are closed in between with suppress(IOError): cmdline = open(os.path.join('/proc', pid, 'cmdline'), 'r').read() for process_elem in process_grep: if process_elem not in cmdline or "run_in_umake_dir" in cmdline or sys.argv[0] in cmdline: break # we found it else: signal_to_send = signal.SIGTERM if kill_process: signal_to_send = signal.SIGKILL os.kill(int(pid), signal_to_send) sys.exit(0) sys.exit(1) ubuntu-make-16.02.1/tests/tools/sign-asset0000775000000000000000000000141412656574623015333 0ustar #!/bin/sh set -e usage="$(basename "$0") [-h] file_to_sign asc_public_sig -- create a temporary gpg key, sign and publish a public signature where: -h show this help text file_to_sign: path to the file to sign with this new gpg key. a .sig file alongside will be created. asc_public_sig: path to the public gpg key signature. This one will be appended A temporary gpg key is created and then deleted" if [ $# -ne 2 ] || [ $1 = '-h' ] || [ $2 = '-h' ]; then echo "$usage" exit fi tmpdir=`mktemp -d` chmod 700 $tmpdir gpg --homedir $tmpdir --gen-key --batch << EOF Key-Type: DSA Name-Email: ubuntu-make@ubuntu.com Expire-Date: 0 EOF gpg --homedir $tmpdir --armor -b --sign $1 mv $1.asc $1.sig gpg --homedir $tmpdir --armor --export >> $2 rm -rf $tmpdir ubuntu-make-16.02.1/tests/tools/get_path_from_desktop_file0000775000000000000000000000171212656574623020625 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import os import sys sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) from tests.tools import get_path_from_desktop_file print(get_path_from_desktop_file(sys.argv[1], sys.argv[2])) ubuntu-make-16.02.1/tests/tools/get_launcher_path0000775000000000000000000000166312656574623016740 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import os import sys sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) from tests.tools import get_desktop_file_path print(get_desktop_file_path(sys.argv[1])) ubuntu-make-16.02.1/tests/tools/run_in_umake_dir0000775000000000000000000000151412656574623016571 0ustar #!/bin/bash # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA cd $1 shift [[ $(env | grep VIRTUAL_ENV) == *env ]] && . env/bin/activate export $(dbus-launch) command=$@ bash -l -c "$command" ubuntu-make-16.02.1/tests/tools/run_local_server0000775000000000000000000000260712656574623016627 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import logging import os import sys sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) import sys from tools import get_data_dir from tools.local_server import LocalHttp logging.basicConfig(level=logging.DEBUG, format="%(asctime)s [%(name)s] %(levelname)s: %(message)s") # start a connection hostname = sys.argv[2] ftp_redir = (sys.argv[2].lower() == 'true') server_dir = os.path.join(get_data_dir(), "server-content") LocalHttp(server_dir, multi_hosts=True, port=int(sys.argv[1]), use_ssl=sys.argv[3:], ftp_redir=ftp_redir) ubuntu-make-16.02.1/tests/tools/local_server.py0000664000000000000000000002227412656574623016371 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Class enabling having a local http(s) server""" from concurrent import futures from http.server import HTTPServer, SimpleHTTPRequestHandler import http.cookies import logging import os import posixpath import ssl from . import get_data_dir import urllib import urllib.parse logger = logging.getLogger(__name__) # TO CREATE THE CERTIFICATES: # openssl req -new -x509 -nodes -days 3600 -out server.crt -keyout server.key (file the fqdn name) # cat server.key server.crt > server.pem # server loads the server.pem # put the .crt file in /usr/local/share/ca-certificates and run sudo update-ca-certificates class LocalHttp: """Local threaded http server. will be serving path content""" def __init__(self, path, multi_hosts=False, use_ssl=[], port=9876, ftp_redir=False): """path is the local path to server multi_hosts will transfer http://hostname/foo to path/hostname/foo. This is used when we potentially serve multiple paths. set use_ssl to a specific array of hostnames. We'll use the corresponding certificates. """ self.port = port self.path = path self.use_ssl = use_ssl handler = RequestHandler handler.root_path = path handler.multi_hosts = multi_hosts handler.ftp_redir = ftp_redir # can be TCPServer, but we don't have a self.httpd.server_name then self.httpd = HTTPServer(("", self.port), RequestHandler) handler.hostname = self.httpd.server_name # create ssl certificate handling for SNI case (switching between different host name) self.ssl_contexts = {} context_associated = False for hostname in self.use_ssl: pem_file = os.path.join(get_data_dir(), "{}.pem".format(hostname)) if os.path.isfile(pem_file): context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) context.load_cert_chain(pem_file) self.ssl_contexts[hostname] = context if not context_associated: context_associated = True self.httpd.socket = context.wrap_socket(self.httpd.socket, server_side=True) context.set_servername_callback(self._match_sni_context) executor = futures.ThreadPoolExecutor(max_workers=1) self.future = executor.submit(self._serve) def _match_sni_context(self, ssl_sock, server_name, initial_context): """return matching certificates to the current request""" logger.info("Request on {}".format(server_name)) try: ssl_sock.context = self.ssl_contexts[server_name] except KeyError: logger.warning("Didn't find corresponding context on this server for {}, keeping default" .format(server_name)) def _serve(self): logger.info("Serving locally from {} on {}".format(self.path, self.get_address())) self.httpd.serve_forever() def get_address(self, localhost=False): """Get public address""" server_name = 'localhost' if localhost else self.httpd.server_name return "http{}://{}:{}".format("s" if self.use_ssl else "", server_name, self.port) def stop(self): """Stop local server""" logger.info("Stopping serving on {}".format(self.port)) self.httpd.shutdown() self.httpd.socket.close() class RequestHandler(SimpleHTTPRequestHandler): root_path = os.getcwd() def __init__(self, request, client_address, server): self.headers_to_send = [] super().__init__(request, client_address, server) def end_headers(self): """don't send Content-Length header for a particular file""" # we can send 404, so ensure that we have a valid path attribute if hasattr(self, "path") and self.path.endswith("-with-no-content-length"): for current_header in self._headers_buffer: if current_header.decode("UTF-8").startswith("Content-Length"): self._headers_buffer.remove(current_header) for key, value in self.headers_to_send: self.send_header(key, value) super().end_headers() def translate_path(self, path): """translate path given routes Most of it is a copy of the parent function which can't be override and uses cwd """ # Before we actually abandon the query params, see if they match an # actual file. # Need to strip the leading '/' so the join will actually work. current_root_path = RequestHandler.root_path if RequestHandler.multi_hosts: current_root_path = os.path.join(RequestHandler.root_path, self.headers["Host"].split(":")[0]) file_path = posixpath.normpath(urllib.parse.unquote(path))[1:] file_path = os.path.join(current_root_path, file_path) if os.path.exists(file_path): return file_path # abandon query parameters path = path.split('?', 1)[0] path = path.split('#', 1)[0] path = path.split('&', 1)[0] # Don't forget explicit trailing slash when normalizing. Issue17324 trailing_slash = path.rstrip().endswith('/') path = posixpath.normpath(urllib.parse.unquote(path)) words = path.split('/') words = filter(None, words) # root path isn't cwd but the one we specified and translated path = current_root_path for word in words: drive, word = os.path.splitdrive(word) head, word = os.path.split(word) if word in (os.curdir, os.pardir): continue path = os.path.join(path, word) if trailing_slash: path += '/' return path def do_GET(self): """Override this to enable redirecting paths that end in -redirect or rewrite in presence of ?file=""" cookies = http.cookies.SimpleCookie(self.headers['Cookie']) if 'int' in cookies: cookies['int'] = int(cookies['int'].value) + 1 for cookie in cookies.values(): self.headers_to_send.append(('Set-Cookie', cookie.OutputString(None))) if self.path.endswith('-redirect'): self.send_response(302) self.send_header('Location', self.path[:-len('-redirect')]) self.end_headers() elif 'setheaders' in self.path: # For paths that end with '-setheaders', we fish out the headers from the query # params and set them. url = urllib.parse.urlparse(self.path) params = urllib.parse.parse_qs(url.query) for key, values in params.items(): for value in values: self.headers_to_send.append((key, value)) # Now we need to chop off the '-setheaders' part. self.path = url.path[:-len('-setheaders')] super().do_GET() elif 'headers' in self.path: # For paths that end with '-headers', we check if the request actually # contains the header with the specified value. The expected header key # and value are in the query params. url = urllib.parse.urlparse(self.path) params = urllib.parse.parse_qs(url.query) for key in params: if self.headers[key] != params[key][0]: self.send_error(404) # Now we need to chop off the '-headers' part. self.path = url.path[:-len('-headers')] super().do_GET() else: # keep special ?file= to redirect the query if '?file=' in self.path: self.path = self.path.split('?file=', 1)[1] self.path = self.path.replace('&', '?', 1) # Replace the first & with ? to make it valid. if RequestHandler.ftp_redir: self.send_response(302) # We need to remove the query parameters, so we actually parse the URL. parsed_url = urllib.parse.urlparse(self.path) new_loc = 'ftp://' + RequestHandler.hostname + parsed_url.path self.send_header('Location', new_loc) self.end_headers() return super().do_GET() def log_message(self, fmt, *args): """Log an arbitrary message. override from SimpleHTTPRequestHandler to not output to stderr but log in the logging system """ logger.debug("%s - - [%s] %s\n" % (self.address_string(), self.log_date_time_string(), fmt % args)) ubuntu-make-16.02.1/tests/tools/remove_path0000775000000000000000000000154012656574623015567 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import os import sys import shutil try: os.remove(sys.argv[1]) except OSError: shutil.rmtree(sys.argv[1])ubuntu-make-16.02.1/tests/tools/check_user_in_group0000775000000000000000000000167012656574623017277 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import os import sys sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) from tests.tools import is_in_group if is_in_group(sys.argv[1]): sys.exit(0) sys.exit(1) ubuntu-make-16.02.1/tests/tools/run_in_umake_dir_async0000775000000000000000000000162612656574623017772 0ustar #!/bin/bash # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # setup dbus environment and launch a command, pwd being the umake dir. # Start command in async mode cd $1 shift [[ $(env | grep VIRTUAL_ENV) == *env ]] && . env/bin/activate export $(dbus-launch) $@ & ubuntu-make-16.02.1/tests/tools/__init__.py0000664000000000000000000001516012656574623015444 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Common tools between tests""" # DO NOT IMPORT HERE umake.* directly, only lazy import it in function. # This file is imported by runtests, before the coverage is enabled. from io import StringIO from contextlib import contextmanager, suppress from copy import deepcopy import grp import importlib import logging import os import re import shutil import xdg.BaseDirectory import pexpect from unittest import TestCase from unittest.mock import Mock logger = logging.getLogger(__name__) BRANCH_TESTS = False DOCKER = None UMAKE = "umake" INSTALL_DIR = ".local/share/umake" SYSTEM_UMAKE_DIR = "/usr/lib/python3/dist-packages/umake" BINARY_DIR = "bin" class LoggedTestCase(TestCase): """A base TestCase class which asserts if there is a warning or error unless self.expect_warn_error is True""" def setUp(self): super().setUp() self.error_warn_logs = StringIO() self.__handler = logging.StreamHandler(self.error_warn_logs) self.__handler.setLevel(logging.WARNING) logging.root.addHandler(self.__handler) self.expect_warn_error = False def tearDown(self): super().tearDown() logging.root.removeHandler(self.__handler) if self.expect_warn_error: self.assertNotEqual(self.error_warn_logs.getvalue(), "") else: self.assertEqual(self.error_warn_logs.getvalue(), "") self.error_warn_logs.close() def get_data_dir(): """Return absolute data dir path""" return os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'data')) def get_root_dir(): """Return absolute project root dir path""" return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) def get_tools_helper_dir(): """Return an absolute path to where the runner helpers are""" return os.path.abspath(os.path.dirname(__file__)) def assert_files_identicals(filename1, filename2): """Assert if the files content are identical""" if open(filename1).read() != open(filename2).read(): logger.error("{}: {}\n{}: {}".format(filename1, open(filename1).read(), filename2, open(filename2).read())) raise AssertionError("{} and {} aren't identical".format(filename1, filename2)) class CopyingMock(Mock): """Mock for recording calls with mutable arguments""" def __call__(self, *args, **kwargs): args = deepcopy(args) kwargs = deepcopy(kwargs) return super().__call__(*args, **kwargs) def change_xdg_path(key, value=None, remove=False): if value: os.environ[key] = value if remove: with suppress(KeyError): os.environ.pop(key) import umake.tools importlib.reload(xdg.BaseDirectory) with suppress(KeyError): umake.tools.Singleton._instances.pop(umake.tools.ConfigHandler) umake.tools.xdg_config_home = xdg.BaseDirectory.xdg_config_home umake.tools.xdg_data_home = xdg.BaseDirectory.xdg_data_home @contextmanager def patchelem(element, attr, value): old_value = getattr(element, attr) setattr(element, attr, value) yield setattr(element, attr, old_value) def manipulate_path_env(value, remove=False): """prepend value to PATH environment. If remove is true, remove it""" path = os.environ["PATH"].split(os.pathsep) if remove: path.remove(value) else: path.insert(0, value) os.environ["PATH"] = os.pathsep.join(path) @contextmanager def swap_file_and_restore(filepath): """Let changing the file in the context manager and restore to original one if needed""" try: original_content = open(filepath).read() yield original_content finally: open(filepath, 'w').write(original_content) def set_local_umake(): global UMAKE global BRANCH_TESTS UMAKE = "./bin/umake" BRANCH_TESTS = True def get_docker_path(): global DOCKER if DOCKER is None: DOCKER = shutil.which("docker.io") if not DOCKER: DOCKER = shutil.which("docker") return DOCKER def local_which(filename): """Find filename in $PATH and return it if present""" for dir in os.environ["PATH"].split(os.pathsep): file_path = os.path.join(dir, filename) if os.path.isfile(file_path): return file_path return None def get_desktop_file_path(desktop_filename): """get the desktop file path""" if not desktop_filename: return "" from umake.tools import get_launcher_path importlib.reload(xdg.BaseDirectory) return get_launcher_path(desktop_filename) def get_path_from_desktop_file(desktop_filename, key): """get the path referred as key in the desktop filename exists""" desktop_file_path = get_desktop_file_path(desktop_filename) if not get_desktop_file_path(desktop_file_path): return "" path = "" with open(desktop_file_path) as f: for line in f: p = re.search(r'{}=(.*)'.format(key), line) with suppress(AttributeError): path = p.group(1) # sanitize the field with unescaped quotes for separator in ('"', "'", " "): elem_paths = path.split(separator) path = "" for elem in elem_paths: if not elem: continue # the separator was escaped, read the separator element if elem[-1] == "\\": elem += separator path += elem # stop for current sep at first unescaped separator if not path.endswith("\\" + separator): break return path def is_in_group(group): """return if current user is in a group""" for group_name in [g.gr_name for g in grp.getgrall() if os.environ["USER"] in g.gr_mem]: print(group_name) if group_name == group: return True return False def spawn_process(command): """return a handle to a new controllable child process""" return pexpect.spawnu(command, dimensions=(24, 250)) ubuntu-make-16.02.1/tests/tools/check_launcher_exists_and_is_pinned0000775000000000000000000000173412656574623022472 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import os import sys sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) from umake.tools import launcher_exists_and_is_pinned if launcher_exists_and_is_pinned(sys.argv[1]): sys.exit(0) sys.exit(1) ubuntu-make-16.02.1/tests/tools/path_exists0000775000000000000000000000150112656574623015606 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import os import sys if os.path.exists(sys.argv[1]): sys.exit(0) sys.exit(1) ubuntu-make-16.02.1/tests/tools/get_file_perms0000775000000000000000000000150412656574623016242 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import os import stat import sys print(stat.filemode(os.stat(sys.argv[1]).st_mode)) ubuntu-make-16.02.1/.pep80000664000000000000000000000017612656574623011707 0ustar [pep8] exclude = env/ max-line-length = 120 # ignore "Identation is not multiple of 4" for continuation line ignore = "E111" ubuntu-make-16.02.1/bin/0000775000000000000000000000000012656574623011576 5ustar ubuntu-make-16.02.1/bin/umake0000775000000000000000000000203112656574623012622 0ustar #!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import os import sys # Run local umake from this helper root_dir = os.path.dirname(os.path.dirname(__file__)) sys.path.insert(0, root_dir) from umake import main # Stamp that we are running a local version from umake import settings settings.from_dev = True if __name__ == '__main__': main() ubuntu-make-16.02.1/umake/0000775000000000000000000000000012656574624012131 5ustar ubuntu-make-16.02.1/umake/version0000664000000000000000000000000712656574623013535 0ustar 16.02.1ubuntu-make-16.02.1/umake/decompressor.py0000664000000000000000000001303112656574623015205 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA from collections import namedtuple from concurrent import futures from glob import glob import logging import os import shutil import stat import subprocess import tarfile import tempfile import zipfile logger = logging.getLogger(__name__) class Decompressor: """Handle decompression of various file in separate threads""" DecompressOrder = namedtuple("DecompressOrder", ["dir", "dest"]) DecompressResult = namedtuple("DecompressResult", ["error"]) # override _extract_member to preserve file permissions: # http://bugs.python.org/issue15795 class ZipFileWithPerm(zipfile.ZipFile): def _extract_member(self, member, targetpath, pwd): targetpath = super()._extract_member(member, targetpath, pwd) mode = member.external_attr >> 16 & 0x1FF os.chmod(targetpath, mode) return targetpath def __init__(self, orders, on_done): """Decompress all fds in threads and send on_done callback once finished order is: { "fd": DecompressOrder(dir=directory to decompress (this will become the new root) dest=destination directory to use for decompressing) ) } Return a dict of DecompressResult on the on_done callback: { "fd": DecompressResult(error=optional error if anything went wrong" } """ self._orders = orders self._decompressed = {} self._done_callback = on_done executor = futures.ThreadPoolExecutor(max_workers=3) for fd in orders: logger.info("Requesting decompression to {}".format(orders[fd].dest)) future = executor.submit(self._decompress, fd, orders[fd].dir, orders[fd].dest) future.tag_fd = fd future.tag_dest = orders[fd].dest future.add_done_callback(self._one_done) def _decompress(self, fd, dir, dest): """decompress one entry dir can be a regexp""" logger.debug("Extracting to {}".format(dest)) # we temporarily extract to this destination the archive content tempdest = tempfile.mktemp(dir=dest) # We don't use shutil to automatically select the right codec as we need to ensure that zipfile # will keep the original perms. archive = None is_archive = False try: try: # the fd isn't forcibly at position 0 (like in Unity3D where we offset the script part) archive = tarfile.open(fileobj=fd, mode='r|*') logger.debug("tar file") except tarfile.ReadError: archive = self.ZipFileWithPerm(fd.name) logger.debug("zip file") is_archive = True archive.extractall(tempdest) except: # try to treat it as self-extractable, some format don't like being opened at the same time though, so link # it. # error out if we had a valid archive which had an issue extracting if is_archive: raise name = "{}.safe".format(fd.name) os.link(fd.name, name) fd.close() st = os.stat(name) os.chmod(name, st.st_mode | stat.S_IEXEC) archive = subprocess.Popen([name, "-o{}".format(tempdest)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) archive.communicate() logger.debug("executable file") os.remove(name) try: dir_path = glob(os.path.join(tempdest, dir))[0] except IndexError: raise BaseException("Couldn't find {} in tarball".format(dir)) for filename in os.listdir(dir_path): shutil.move(os.path.join(dir_path, filename), os.path.join(dest, filename)) shutil.rmtree(tempdest) def _one_done(self, future): """Callback that will be called once one decompress finishes. (will be wired on the constructor) """ result = self.DecompressResult(error=None) if future.exception(): logger.error("A decompression to {} failed: {}".format(future.tag_dest, future.exception()), exc_info=future.exception()) result = result._replace(error=str(future.exception())) logger.info("Decompression to {} finished".format(future.tag_dest)) self._decompressed[future.tag_fd] = result if len(self._orders) == len(self._decompressed): self._done() def _done(self): """Callback that will be called once all download finishes. uris of the temporary files will be passed on the wired callback """ logger.info("All pending decompression done to {} done.".format([self._orders[fd].dest for fd in self._orders])) self._done_callback(self._decompressed) ubuntu-make-16.02.1/umake/settings.py0000664000000000000000000000327612656574623014352 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import os from xdg.BaseDirectory import xdg_data_home DEFAULT_INSTALL_TOOLS_PATH = os.path.expanduser(os.path.join(xdg_data_home, "umake")) DEFAULT_BINARY_LINK_PATH = os.path.expanduser(os.path.join(DEFAULT_INSTALL_TOOLS_PATH, "bin")) OLD_CONFIG_FILENAME = "udtc" CONFIG_FILENAME = "umake" LSB_RELEASE_FILE = "/etc/lsb-release" UMAKE_FRAMEWORKS_ENVIRON_VARIABLE = "UMAKE_FRAMEWORKS" from_dev = False def get_version(): '''Get version depending if on dev or released version''' version = open(os.path.join(os.path.dirname(__file__), 'version'), 'r', encoding='utf-8').read().strip() if not from_dev: return version import subprocess try: # use git describe to get a revision ref if running from a branch. Will append dirty if local changes version = subprocess.check_output(["git", "describe", "--tags", "--dirty"]).decode('utf-8').strip() except (subprocess.CalledProcessError, FileNotFoundError): version += "+unknown" return version ubuntu-make-16.02.1/umake/__pycache__/0000755000000000000000000000000012656574625014340 5ustar ubuntu-make-16.02.1/umake/tools.py0000664000000000000000000003713312656574623013651 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA from collections import namedtuple from contextlib import contextmanager, suppress from enum import unique, Enum from gettext import gettext as _ from gi.repository import GLib, Gio from glob import glob import logging import os import re import shutil import signal import subprocess import sys from textwrap import dedent from time import sleep from threading import Lock from umake import settings from xdg.BaseDirectory import load_first_config, xdg_config_home, xdg_data_home import yaml import yaml.scanner import yaml.parser logger = logging.getLogger(__name__) # cache current arch. Shouldn't change in the life of the process ;) _current_arch = None _foreign_arch = None _version = None profile_tag = _("# Ubuntu make installation of {}\n") root_lock = Lock() @unique class ChecksumType(Enum): """Types of supported checksum algorithms.""" md5 = "md5" sha1 = "sha1" sha256 = "sha256" sha512 = "sha512" class Checksum(namedtuple('Checksum', ['checksum_type', 'checksum_value'])): """A combination of checksum algorithm and actual value to check.""" pass class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] class ConfigHandler(metaclass=Singleton): def __init__(self): """Load the config""" self._config = {} old_config_file = load_first_config(settings.OLD_CONFIG_FILENAME) config_file = load_first_config(settings.CONFIG_FILENAME) if old_config_file: if not config_file: config_file = old_config_file.replace(settings.OLD_CONFIG_FILENAME, settings.CONFIG_FILENAME) os.rename(old_config_file, config_file) logger.debug("Opening {}".format(config_file)) try: with open(config_file) as f: self._config = yaml.load(f) except (TypeError, FileNotFoundError): logger.info("No configuration file found") except (yaml.scanner.ScannerError, yaml.parser.ParserError) as e: logger.error("Invalid configuration file found: {}".format(e)) @property def config(self): return self._config @config.setter def config(self, config): config_file = os.path.join(xdg_config_home, settings.CONFIG_FILENAME) logging.debug("Saving new configuration: {} in {}".format(config, config_file)) os.makedirs(os.path.dirname(config_file), exist_ok=True) with open(config_file, 'w') as f: yaml.dump(config, f, default_flow_style=False) self._config = config class NoneDict(dict): """We don't use a defaultdict(lambda: None) as it's growing everytime something is requested""" def __getitem__(self, key): return dict.get(self, key) class classproperty(object): """Class property, similar to instance properties""" def __init__(self, f): self.f = f def __get__(self, obj, owner): return self.f(owner) class MainLoop(object, metaclass=Singleton): """Mainloop simple wrapper""" def __init__(self): self.mainloop = GLib.MainLoop() # Glib steals the SIGINT handler and so, causes issue in the callback # https://bugzilla.gnome.org/show_bug.cgi?id=622084 signal.signal(signal.SIGINT, signal.SIG_DFL) def run(self): self.mainloop.run() def quit(self, status_code=0, raise_exception=True): GLib.timeout_add(80, self._clean_up, status_code) # only raises exception if not turned down (like in tests, where we are not in the mainloop for sure) if raise_exception: raise self.ReturnMainLoop() def _clean_up(self, exit_code): self.mainloop.quit() sys.exit(exit_code) @staticmethod def in_mainloop_thread(function): """Decorator to run a function in a mainloop thread""" # GLib.idle_add doesn't propagate try: except in the mainloop, so we handle it there for all functions def wrapper(*args, **kwargs): try: function(*args, **kwargs) except MainLoop.ReturnMainLoop: pass except BaseException: logger.exception("Unhandled exception") GLib.idle_add(MainLoop().quit, 1, False) def inner(*args, **kwargs): return GLib.idle_add(wrapper, *args, **kwargs) return inner class ReturnMainLoop(BaseException): """Exception raised only to return to MainLoop without finishing the function""" class InputError(BaseException): """Exception raised for errors in the input. Attributes: expr -- input expression in which the error occurred msg -- explanation of the error """ def __init__(self, value): self.value = value def __str__(self): return repr(self.value) def get_current_arch(): """Get current configuration dpkg architecture. Possible outputs: * amd64 * i386 """ global _current_arch if _current_arch is None: _current_arch = subprocess.check_output(["dpkg", "--print-architecture"], universal_newlines=True).rstrip("\n") return _current_arch def get_foreign_archs(): """Get foreign architectures that were enabled""" global _foreign_arch if _foreign_arch is None: _foreign_arch = subprocess.check_output(["dpkg", "--print-foreign-architectures"], universal_newlines=True)\ .rstrip("\n").split() return _foreign_arch def add_foreign_arch(new_arch): """Add a new architecture if not already loaded. Return if new arch was added""" global _foreign_arch # try to add the arch if not already present arch_added = False if new_arch not in get_foreign_archs() and new_arch != get_current_arch(): logger.info("Adding foreign arch: {}".format(new_arch)) with open(os.devnull, "w") as f: with as_root(): if subprocess.call(["dpkg", "--add-architecture", new_arch], stdout=f) != 0: msg = _("Can't add foreign architecture {}").format(new_arch) raise BaseException(msg) # mark the new arch as added and invalidate the cache arch_added = True _foreign_arch = None return arch_added def get_current_ubuntu_version(): """Return current ubuntu version or raise an error if couldn't find any""" global _version if _version is None: try: with open(settings.LSB_RELEASE_FILE) as lsb_release_file: for line in lsb_release_file: line = line.strip() if line.startswith('DISTRIB_RELEASE='): tag, release = line.split('=', 1) _version = release break else: message = "Couldn't find DISTRIB_RELEASE in {}".format(settings.LSB_RELEASE_FILE) logger.error(message) raise BaseException(message) except (FileNotFoundError, IOError) as e: message = "Can't open lsb-release file: {}".format(e) logger.error(message) raise BaseException(message) return _version def is_completion_mode(): """Return true if we are in completion mode""" return os.environ.get('_ARGCOMPLETE') == '1' def get_user_frameworks_path(): """Return user frameworks local path""" return os.path.expanduser(os.path.join('~', '.umake', 'frameworks')) def get_icon_path(icon_filename): """Return local icon path""" return os.path.join(xdg_data_home, "icons", icon_filename) def get_launcher_path(desktop_filename): """Return launcher path""" return os.path.join(xdg_data_home, "applications", desktop_filename) def launcher_exists(desktop_filename): """Return true if the desktop filename exists""" exists = os.path.exists(get_launcher_path(desktop_filename)) if not exists: logger.debug("{} doesn't exist".format(desktop_filename)) return False return True def launcher_exists_and_is_pinned(desktop_filename): """Return true if the desktop filename is pinned in the launcher""" if not launcher_exists(desktop_filename): return False if os.environ.get("XDG_CURRENT_DESKTOP") != "Unity": logger.debug("Don't check launcher as current environment isn't Unity") return True if "com.canonical.Unity.Launcher" not in Gio.Settings.list_schemas(): logger.debug("In an Unity environment without the Launcher schema file") return False gsettings = Gio.Settings(schema_id="com.canonical.Unity.Launcher", path="/com/canonical/unity/launcher/") launcher_list = gsettings.get_strv("favorites") res = "application://" + desktop_filename in launcher_list if not res: logger.debug("Launcher exists but is not pinned (pinned: {}).".format(launcher_list)) return res def copy_icon(source_icon_filepath, icon_filename): """copy icon from source filepath to xdg destination as icon_filename globs are accepted in the filepath""" icon_path = get_icon_path(icon_filename) os.makedirs(os.path.dirname(icon_path), exist_ok=True) for file_path in glob(source_icon_filepath): logger.debug("Copy icon from {} to {}".format(file_path, icon_path)) shutil.copy(file_path, icon_path) break else: logger.warning("Didn't find any icon for the launcher.") def create_launcher(desktop_filename, content): """Create a desktop file and an unity launcher icon""" # Create file in standard location launcher_path = get_launcher_path(desktop_filename) os.makedirs(os.path.dirname(launcher_path), exist_ok=True) logger.debug("Create launcher as {}".format(launcher_path)) with open(launcher_path, "w") as f: f.write(content) if "com.canonical.Unity.Launcher" not in Gio.Settings.list_schemas(): logger.info("Don't create a launcher icon, as we are not under Unity") return gsettings = Gio.Settings(schema_id="com.canonical.Unity.Launcher", path="/com/canonical/unity/launcher/") launcher_list = gsettings.get_strv("favorites") launcher_tag = "application://{}".format(desktop_filename) if launcher_tag not in launcher_list: index = len(launcher_list) with suppress(ValueError): index = launcher_list.index("unity://running-apps") launcher_list.insert(index, launcher_tag) # FIXME: working around a bug in glib: https://bugzilla.gnome.org/show_bug.cgi?id=744030 sleep(1.5) ########## gsettings.set_strv("favorites", launcher_list) def add_exec_link(exec_path, destination_name): bin_folder = settings.DEFAULT_BINARY_LINK_PATH os.makedirs(bin_folder, exist_ok=True) add_env_to_user("Ubuntu Make binary symlink", {"PATH": {"value": bin_folder}}) full_dest_path = os.path.join(bin_folder, destination_name) with suppress(FileNotFoundError): os.remove(full_dest_path) os.symlink(exec_path, full_dest_path) def get_application_desktop_file(name="", icon_path="", exec="", comment="", categories="", extra=""): """Get a desktop file string content""" return dedent("""\ [Desktop Entry] Version=1.0 Type=Application Name={name} Icon={icon_path} Exec={exec} Comment={comment} Categories={categories} Terminal=false {extra} """).format(name=name, icon_path=icon_path, exec=exec, comment=comment, categories=categories, extra=extra) def strip_tags(content): """Strip all HTML tags from content""" return re.sub('<[^<]+?>', '', content) def switch_to_current_user(): """Switch euid and guid to current user if current user is root""" if os.geteuid() != 0: return # fallback to root user if no SUDO_GID (should be su - root) os.setegid(int(os.getenv("SUDO_GID", default=0))) os.seteuid(int(os.getenv("SUDO_UID", default=0))) @contextmanager def as_root(): # block all other threads making sensitive operations root_lock.acquire() try: os.seteuid(0) os.setegid(0) yield finally: switch_to_current_user() root_lock.release() # TODO: make that useful for more shells def _get_shell_profile_file_path(): """Return profile filepath for current preferred shell""" current_shell = os.getenv('SHELL', '/bin/bash').lower() profile_filename = '.zprofile' if 'zsh' in current_shell else '.profile' return os.path.join(os.path.expanduser('~'), profile_filename) def remove_framework_envs_from_user(framework_tag): """Remove all envs from user if found""" profile_filepath = _get_shell_profile_file_path() content = "" framework_header = profile_tag.format(framework_tag) try: with open(profile_filepath, "r", encoding='utf-8') as f: content = f.read() except FileNotFoundError: return if framework_header not in content: return while framework_header in content: framework_start_index = content.find(framework_header) framework_end_index = content[framework_start_index:].find("\n\n") content = content[:framework_start_index] + content[framework_start_index + framework_end_index + len("\n\n"):] # rewrite .profile and omit framework_tag with open(profile_filepath + ".new", "w", encoding='utf-8') as f: f.write(content) os.rename(profile_filepath + ".new", profile_filepath) def add_env_to_user(framework_tag, env_dict): """Add args to user env in .profile (.zprofile if zsh) if the user doesn't have that env with those args env_dict is a dictionary of: { env_variable: { value: value, keep: True/False } } value is either a list (in that case, it's concatenated) or a string If keep is set to True, we keep previous values with :$OLDERENV.""" profile_filepath = _get_shell_profile_file_path() remove_framework_envs_from_user(framework_tag) envs_to_insert = {} for env in env_dict: value = env_dict[env]["value"] if isinstance(value, list): value = os.pathsep.join(value) if env_dict[env].get("keep", True) and os.environ.get(env): os.environ[env] = value + os.pathsep + os.environ[env] value = "{}{}${}".format(value, os.pathsep, env) else: os.environ[env] = value envs_to_insert[env] = value with open(profile_filepath, "a", encoding='utf-8') as f: f.write(profile_tag.format(framework_tag)) for env in envs_to_insert: value = envs_to_insert[env] logger.debug("Adding {} to user's {} for {}".format(value, env, framework_tag)) export = "" if env != "PATH": export = "export " f.write("{}{}={}\n".format(export, env, value)) f.write("\n") ubuntu-make-16.02.1/umake/ui/0000775000000000000000000000000012656574624012546 5ustar ubuntu-make-16.02.1/umake/ui/__pycache__/0000755000000000000000000000000012656574625014755 5ustar ubuntu-make-16.02.1/umake/ui/cli/0000775000000000000000000000000012656574624013315 5ustar ubuntu-make-16.02.1/umake/ui/cli/__pycache__/0000755000000000000000000000000012656574625015524 5ustar ubuntu-make-16.02.1/umake/ui/cli/__init__.py0000664000000000000000000001636012656574623015433 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Module for loading the command line interface""" import argcomplete from contextlib import suppress import logging import os from progressbar import ProgressBar, BouncingBar import readline import sys from umake.interactions import InputText, TextWithChoices, LicenseAgreement, DisplayMessage, UnknownProgress from umake.ui import UI from umake.frameworks import BaseCategory from umake.tools import InputError, MainLoop from umake.settings import get_version logger = logging.getLogger(__name__) def rlinput(prompt, prefill=''): readline.set_startup_hook(lambda: readline.insert_text(prefill)) try: return input(prompt + " ") finally: readline.set_startup_hook() class CliUI(UI): def __init__(self): # This this UI as current super().__init__(self) def _return_main_screen(self, status_code=0): # quit the shell MainLoop().quit(status_code=status_code) def _display(self, contentType): # print depending on the content type while True: try: if isinstance(contentType, InputText): contentType.run_callback(result=rlinput(contentType.content, contentType.default_input)) elif isinstance(contentType, LicenseAgreement): print(contentType.content) contentType.choose(answer=input(contentType.input)) elif isinstance(contentType, TextWithChoices): contentType.choose(answer=input(contentType.prompt)) elif isinstance(contentType, DisplayMessage): print(contentType.text) elif isinstance(contentType, UnknownProgress): if not contentType.bar: contentType.bar = ProgressBar(widgets=[BouncingBar()]) with suppress(StopIteration, AttributeError): # pulse and add a timeout callback contentType.bar(contentType._iterator()).next() UI.delayed_display(contentType) # don't recall the callback return False else: logger.error("Unexcepted content type to display to CLI UI: {}".format(contentType)) MainLoop().quit(status_code=1) break except InputError as e: logger.error(str(e)) continue @MainLoop.in_mainloop_thread def run_command_for_args(args): """Run correct command for args""" # args.category can be a category or a framework in main target = None try: target = BaseCategory.categories[args.category] except AttributeError: target = BaseCategory.main_category.frameworks[args.category] target.run_for(args) def mangle_args_for_default_framework(args): """return the potentially changed args_to_parse for the parser for handling default frameworks "./ [global_or_common_options] category [options from default framework]" as subparsers can't define default options and are not optional: http://bugs.python.org/issue9253 """ result_args = [] skip_all = False pending_args = [] category_name = None framework_completed = False args_to_append = [] for arg in args: # --remove is both installed as global and per-framework optional arguments. argparse will only analyze the # per framework one and will override the global one. So if --remove is before the category name, it will be # ignored. Mangle the arg and append it last then. if not category_name and arg in ("--remove", "-r"): args_to_append.append(arg) continue if not arg.startswith('-') and not skip_all: if not category_name: if arg in BaseCategory.categories.keys(): category_name = arg # file global and common options result_args.extend(pending_args) pending_args = [] result_args.append(arg) continue else: skip_all = True # will just append everything at the end elif not framework_completed: # if we found a real framework or not, consider that one. pending_args will be then filed framework_completed = True if arg in BaseCategory.categories[category_name].frameworks.keys(): result_args.append(arg) continue # take default framework if any after some sanitization check elif BaseCategory.categories[category_name].default_framework is not None: # before considering automatically inserting default framework, check that this argument has # some path separator into it. This is to avoid typos in framework selection and selecting default # framework with installation path where we didn't want to. if os.path.sep in arg: result_args.append(BaseCategory.categories[category_name].default_framework.prog_name) # current arg will be appending in pending_args else: skip_all = True # will just append everything at the end pending_args.append(arg) # this happened only if there is no argument after the category name if category_name and not framework_completed: if BaseCategory.categories[category_name].default_framework is not None: result_args.append(BaseCategory.categories[category_name].default_framework.prog_name) # let the rest in result_args.extend(pending_args) result_args.extend(args_to_append) return result_args def main(parser): """Main entry point of the cli command""" categories_parser = parser.add_subparsers(help='Developer environment', dest="category") for category in BaseCategory.categories.values(): category.install_category_parser(categories_parser) argcomplete.autocomplete(parser) # autocomplete will stop there. Can start more expensive operations now. arg_to_parse = sys.argv[1:] if "--help" not in arg_to_parse: # manipulate sys.argv for default frameworks: arg_to_parse = mangle_args_for_default_framework(arg_to_parse) args = parser.parse_args(arg_to_parse) if args.version: print(get_version()) sys.exit(0) if not args.category: parser.print_help() sys.exit(0) CliUI() run_command_for_args(args) ubuntu-make-16.02.1/umake/ui/__init__.py0000664000000000000000000000346512656574623014666 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Abstracted UI interface that will be overriden by different UI types""" from gi.repository import GLib from umake.tools import Singleton, MainLoop class UI(object, metaclass=Singleton): currentUI = None def __init__(self, current_UI): UI.currentUI = current_UI @classmethod def return_main_screen(cls, status_code=0): cls.currentUI._return_main_screen(status_code=status_code) @classmethod @MainLoop.in_mainloop_thread def display(cls, contentType): """display in main thread this UI contentType. Can be delayed by 50 ms, like for pulse or message""" # TODO: add check for current framework == framework sending contentType cls.currentUI._display(contentType) @classmethod @MainLoop.in_mainloop_thread def delayed_display(cls, contentType): GLib.timeout_add(50, cls._one_time_wrapper, cls.currentUI._display, contentType) @staticmethod def _one_time_wrapper(fun, contentType): """To be called with GLib.timeout_add(), return False to only have one call""" fun(contentType) return False ubuntu-make-16.02.1/umake/frameworks/0000775000000000000000000000000012656574624014311 5ustar ubuntu-make-16.02.1/umake/frameworks/ide.py0000664000000000000000000011146512656574623015433 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014-2015 Canonical # # Authors: # Didier Roche # Tin Tvrtković # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Generic IDE module.""" from abc import ABCMeta, abstractmethod from bs4 import BeautifulSoup from concurrent import futures from contextlib import suppress from gettext import gettext as _ import grp from io import StringIO import json import logging import os from os.path import join import pwd import platform import re import subprocess from urllib import parse import shutil import umake.frameworks.baseinstaller from umake.interactions import DisplayMessage, LicenseAgreement from umake.network.download_center import DownloadCenter, DownloadItem from umake.tools import as_root, create_launcher, get_application_desktop_file, ChecksumType, Checksum, MainLoop,\ strip_tags, add_env_to_user, add_exec_link from umake.ui import UI logger = logging.getLogger(__name__) def _add_to_group(user, group): """Add user to group""" # switch to root with as_root(): try: output = subprocess.check_output(["adduser", user, group]) logger.debug("Added {} to {}: {}".format(user, group, output)) return True except subprocess.CalledProcessError as e: logger.error("Couldn't add {} to {}".format(user, group)) return False class IdeCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="IDE", description=_("Generic IDEs"), logo_path=None) class BaseEclipse(umake.frameworks.baseinstaller.BaseInstaller, metaclass=ABCMeta): """The Eclipse Foundation distribution.""" def __init__(self, *args, **kwargs): if self.executable: current_required_files_path = kwargs.get("required_files_path", []) current_required_files_path.append(os.path.join(self.executable)) kwargs["required_files_path"] = current_required_files_path download_page = 'https://www.eclipse.org/downloads/' kwargs["download_page"] = download_page kwargs["exec_rel_path"] = "eclipse" super().__init__(*args, **kwargs) self.icon_url = os.path.join(self.download_page, "images", self.icon_filename) self.bits = '' if platform.machine() == 'i686' else 'x86_64' self.headers = {'User-agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu " "Chromium/41.0.2272.76 Chrome/41.0.2272.76 Safari/537.36"} @property @abstractmethod def download_keyword(self): pass @property @abstractmethod def executable(self): pass def download_provider_page(self): logger.debug("Download application provider page") DownloadCenter([DownloadItem(self.download_page, headers=self.headers)], self.get_metadata, download=False) def parse_download_link(self, line, in_download): """Parse Eclipse download links""" url_found = False if self.download_keyword in line and self.bits in line: in_download = True else: in_download = False if in_download: p = re.search(r'href="(.*)" title', line) with suppress(AttributeError): self.sha512_url = self.download_page + p.group(1) + '.sha512&r=1' url_found = True DownloadCenter(urls=[DownloadItem(self.sha512_url, None)], on_done=self.get_sha_and_start_download, download=False) return (url_found, in_download) @MainLoop.in_mainloop_thread def get_metadata(self, result): """Download files to download + license and check it""" logger.debug("Parse download metadata") error_msg = result[self.download_page].error if error_msg: logger.error("An error occurred while downloading {}: {}".format(self.download_page, error_msg)) UI.return_main_screen(status_code=1) in_download = False url_found = False for line in result[self.download_page].buffer: line_content = line.decode() (_url_found, in_download) = self.parse_download_link(line_content, in_download) if not url_found: url_found = _url_found if not url_found: logger.error("Download page changed its syntax or is not parsable") UI.return_main_screen(status_code=1) @MainLoop.in_mainloop_thread def get_sha_and_start_download(self, download_result): res = download_result[self.sha512_url] sha512 = res.buffer.getvalue().decode('utf-8').split()[0] # you get and store self.download_url url = re.sub('.sha512', '', self.sha512_url) if url is None: logger.error("Download page changed its syntax or is not parsable (missing url)") UI.return_main_screen(status_code=1) if sha512 is None: logger.error("Download page changed its syntax or is not parsable (missing sha512)") UI.return_main_screen(status_code=1) logger.debug("Found download link for {}, checksum: {}".format(url, sha512)) self.download_requests.append(DownloadItem(url, Checksum(ChecksumType.sha512, sha512))) self.start_download_and_install() def post_install(self): """Create the Eclipse launcher""" DownloadCenter(urls=[DownloadItem(self.icon_url, None)], on_done=self.save_icon, download=True) icon_path = join(self.install_path, self.icon_filename) comment = self.description categories = "Development;IDE;" create_launcher(self.desktop_filename, get_application_desktop_file(name=self.name, icon_path=icon_path, exec='"{}" %f'.format(self.exec_path), comment=comment, categories=categories)) def save_icon(self, download_result): """Save correct Eclipse icon""" icon = download_result.pop(self.icon_url).fd.name shutil.copy(icon, join(self.install_path, self.icon_filename)) logger.debug("Copied icon: {}".format(self.icon_url)) class EclipseJava(BaseEclipse): """The Eclipse Java Edition distribution.""" download_keyword = 'eclipse-java' executable = 'eclipse' def __init__(self, category): super().__init__(name="Eclipse", description=_("Eclipse Java IDE"), dir_to_decompress_in_tarball='eclipse', desktop_filename='eclipse-java.desktop', category=category, only_on_archs=['i386', 'amd64'], packages_requirements=['openjdk-7-jdk'], icon_filename='java.png') class EclipsePHP(BaseEclipse): """The Eclipse PHP Edition distribution.""" download_keyword = 'eclipse-php' executable = 'eclipse' def __init__(self, category): super().__init__(name="Eclipse PHP", description=_("Eclipse PHP IDE"), dir_to_decompress_in_tarball='eclipse', desktop_filename='eclipse-php.desktop', category=category, only_on_archs=['i386', 'amd64'], packages_requirements=['openjdk-7-jdk'], icon_filename='php.png') class EclipseCPP(BaseEclipse): """The Eclipse CPP Edition distribution.""" download_keyword = 'eclipse-cpp' executable = 'eclipse' def __init__(self, category): super().__init__(name="Eclipse CPP", description=_("Eclipse C/C++ IDE"), dir_to_decompress_in_tarball='eclipse', desktop_filename='eclipse-cpp.desktop', category=category, only_on_archs=['i386', 'amd64'], packages_requirements=['openjdk-7-jdk'], icon_filename='cdt.png') class BaseJetBrains(umake.frameworks.baseinstaller.BaseInstaller, metaclass=ABCMeta): """The base for all JetBrains installers.""" def __init__(self, *args, **kwargs): """Add executable required file path to existing list""" if self.executable: current_required_files_path = kwargs.get("required_files_path", []) current_required_files_path.append(os.path.join("bin", self.executable)) kwargs["required_files_path"] = current_required_files_path download_page = "https://data.services.jetbrains.com/products/releases?code={}".format(self.download_keyword) kwargs["download_page"] = download_page super().__init__(*args, **kwargs) @property @abstractmethod def download_keyword(self): pass @property @abstractmethod def executable(self): pass @MainLoop.in_mainloop_thread def get_metadata_and_check_license(self, result): logger.debug("Fetched download page, parsing.") page = result[self.download_page] error_msg = page.error if error_msg: logger.error("An error occurred while downloading {}: {}".format(self.download_page, error_msg)) UI.return_main_screen(status_code=1) try: key, content = json.loads(page.buffer.read().decode()).popitem() download_url = content[0]['downloads']['linux']['link'] checksum_url = content[0]['downloads']['linux']['checksumLink'] except (json.JSONDecodeError, IndexError): logger.error("Can't parse the download URL from the download page.") UI.return_main_screen(status_code=1) logger.debug("Found download URL: " + download_url) logger.debug("Downloading checksum first, from " + checksum_url) def checksum_downloaded(results): checksum_result = next(iter(results.values())) # Just get the first. if checksum_result.error: logger.error(checksum_result.error) UI.return_main_screen(status_code=1) checksum = checksum_result.buffer.getvalue().decode('utf-8').split()[0] logger.info('Obtained SHA256 checksum: ' + checksum) self.download_requests.append(DownloadItem(download_url, checksum=Checksum(ChecksumType.sha256, checksum), ignore_encoding=True)) self.start_download_and_install() DownloadCenter([DownloadItem(checksum_url)], on_done=checksum_downloaded, download=False) def post_install(self): """Create the appropriate JetBrains launcher.""" icon_path = join(self.install_path, 'bin', self.icon_filename) comment = self.description + " (UDTC)" categories = "Development;IDE;" create_launcher(self.desktop_filename, get_application_desktop_file(name=self.description, icon_path=icon_path, exec='"{}" %f'.format(self.exec_path), comment=comment, categories=categories)) class PyCharm(BaseJetBrains): """The JetBrains PyCharm Community Edition distribution.""" download_keyword = 'PCC' executable = "pycharm.sh" def __init__(self, category): super().__init__(name="PyCharm", description=_("PyCharm Community Edition"), category=category, only_on_archs=['i386', 'amd64'], dir_to_decompress_in_tarball='pycharm-community-*', desktop_filename='jetbrains-pycharm.desktop', packages_requirements=['openjdk-7-jdk', 'jayatana'], icon_filename='pycharm.png') class PyCharmEducational(BaseJetBrains): """The JetBrains PyCharm Educational Edition distribution.""" download_keyword = 'PCE' executable = "pycharm.sh" def __init__(self, category): super().__init__(name="PyCharm Educational", description=_("PyCharm Educational Edition"), category=category, only_on_archs=['i386', 'amd64'], dir_to_decompress_in_tarball='pycharm-edu*', desktop_filename='jetbrains-pycharm.desktop', packages_requirements=['openjdk-7-jdk', 'jayatana'], icon_filename='pycharm.png') class PyCharmProfessional(BaseJetBrains): """The JetBrains PyCharm Professional Edition distribution.""" download_keyword = 'PCP' executable = "pycharm.sh" def __init__(self, category): super().__init__(name="PyCharm Professional", description=_("PyCharm Professional Edition"), category=category, only_on_archs=['i386', 'amd64'], dir_to_decompress_in_tarball='pycharm-*', desktop_filename='jetbrains-pycharm.desktop', packages_requirements=['openjdk-7-jdk', 'jayatana'], icon_filename='pycharm.png') class Idea(BaseJetBrains): """The JetBrains IntelliJ Idea Community Edition distribution.""" download_keyword = 'IIC' executable = "idea.sh" def __init__(self, category): super().__init__(name="Idea", description=_("IntelliJ IDEA Community Edition"), category=category, only_on_archs=['i386', 'amd64'], dir_to_decompress_in_tarball='idea-IC-*', desktop_filename='jetbrains-idea.desktop', packages_requirements=['openjdk-7-jdk', 'jayatana'], icon_filename='idea.png') class IdeaUltimate(BaseJetBrains): """The JetBrains IntelliJ Idea Ultimate Edition distribution.""" download_keyword = 'IIU' executable = "idea.sh" def __init__(self, category): super().__init__(name="Idea Ultimate", description=_("IntelliJ IDEA"), category=category, only_on_archs=['i386', 'amd64'], dir_to_decompress_in_tarball='idea-IU-*', desktop_filename='jetbrains-idea.desktop', packages_requirements=['openjdk-7-jdk', 'jayatana'], icon_filename='idea.png') class RubyMine(BaseJetBrains): """The JetBrains RubyMine IDE""" download_keyword = 'RM' executable = "rubymine.sh" def __init__(self, category): super().__init__(name="RubyMine", description=_("Ruby on Rails IDE"), category=category, only_on_archs=['i386', 'amd64'], dir_to_decompress_in_tarball='RubyMine-*', desktop_filename='jetbrains-rubymine.desktop', packages_requirements=['openjdk-7-jdk', 'jayatana'], icon_filename='rubymine.png') class WebStorm(BaseJetBrains): """The JetBrains WebStorm IDE""" download_keyword = 'WS' executable = "webstorm.sh" def __init__(self, category): super().__init__(name="WebStorm", description=_("Complex client-side and server-side javascript IDE"), category=category, only_on_archs=['i386', 'amd64'], dir_to_decompress_in_tarball='WebStorm-*', desktop_filename='jetbrains-webstorm.desktop', packages_requirements=['openjdk-7-jdk', 'jayatana'], icon_filename='webstorm.svg') class PhpStorm(BaseJetBrains): """The JetBrains PhpStorm IDE""" download_keyword = 'PS' executable = "phpstorm.sh" def __init__(self, category): super().__init__(name="PhpStorm", description=_("PHP and web development IDE"), category=category, only_on_archs=['i386', 'amd64'], dir_to_decompress_in_tarball='PhpStorm-*', desktop_filename='jetbrains-phpstorm.desktop', packages_requirements=['openjdk-7-jdk', 'jayatana'], icon_filename='webide.png') class CLion(BaseJetBrains): """The JetBrains CLion IDE""" download_keyword = 'CL' executable = "clion.sh" def __init__(self, category): super().__init__(name="CLion", description=_("CLion integrated C/C++ IDE"), category=category, only_on_archs=['amd64'], dir_to_decompress_in_tarball='clion-*', desktop_filename='jetbrains-clion.desktop', packages_requirements=['openjdk-7-jdk', 'jayatana'], icon_filename='clion.svg') class DataGrip(BaseJetBrains): """The JetBrains DataGrip IDE""" download_keyword = 'DG' executable = "datagrip.sh" def __init__(self, category): super().__init__(name="DataGrip", description=_("DataGrip SQL and databases IDE"), category=category, only_on_archs=['i386', 'amd64'], dir_to_decompress_in_tarball='DataGrip-*', desktop_filename='jetbrains-datagrip.desktop', packages_requirements=['openjdk-7-jdk', 'jayatana'], icon_filename='product.png') class Arduino(umake.frameworks.baseinstaller.BaseInstaller): """The Arduino Software distribution.""" ARDUINO_GROUP = "dialout" def __init__(self, category): if os.geteuid() != 0: self._current_user = os.getenv("USER") self._current_user = pwd.getpwuid(int(os.getenv("SUDO_UID", default=0))).pw_name for group_name in [g.gr_name for g in grp.getgrall() if self._current_user in g.gr_mem]: if group_name == self.ARDUINO_GROUP: self.was_in_arduino_group = True break else: self.was_in_arduino_group = False super().__init__(name="Arduino", description=_("The Arduino Software Distribution"), category=category, only_on_archs=['i386', 'amd64'], download_page='http://www.arduino.cc/en/Main/Software', dir_to_decompress_in_tarball='arduino-*', desktop_filename='arduino.desktop', packages_requirements=['openjdk-7-jdk', 'jayatana', 'gcc-avr', 'avr-libc'], need_root_access=not self.was_in_arduino_group, required_files_path=["arduino"]) self.scraped_checksum_url = None self.scraped_download_url = None # This is needed later in several places. # The framework covers other cases, in combination with self.only_on_archs self.bits = '32' if platform.machine() == 'i686' else '64' @MainLoop.in_mainloop_thread def get_metadata_and_check_license(self, result): """We diverge from the BaseInstaller implementation a little here.""" logger.debug("Parse download metadata") error_msg = result[self.download_page].error if error_msg: logger.error("An error occurred while downloading {}: {}".format(self.download_page, error_msg)) UI.return_main_screen(status_code=1) soup = BeautifulSoup(result[self.download_page].buffer, 'html.parser') # We need to avoid matching arduino-nightly-... download_link_pat = r'arduino-[\d\.\-r]+-linux' + self.bits + '.tar.xz$' # Trap no match found, then, download/checksum url will be empty and will raise the error # instead of crashing. with suppress(TypeError): self.scraped_download_url = soup.find('a', href=re.compile(download_link_pat))['href'] self.scraped_checksum_url = soup.find('a', text=re.compile('Checksums'))['href'] self.scraped_download_url = 'http:' + self.scraped_download_url self.scraped_checksum_url = 'http:' + self.scraped_checksum_url if not self.scraped_download_url: logger.error("Can't parse the download link from %s.", self.download_page) UI.return_main_screen(status_code=1) if not self.scraped_checksum_url: logger.error("Can't parse the checksum link from %s.", self.download_page) UI.return_main_screen(status_code=1) DownloadCenter([DownloadItem(self.scraped_download_url), DownloadItem(self.scraped_checksum_url)], on_done=self.prepare_to_download_archive, download=False) @MainLoop.in_mainloop_thread def prepare_to_download_archive(self, results): """Store the md5 for later and fire off the actual download.""" download_page = results[self.scraped_download_url] checksum_page = results[self.scraped_checksum_url] if download_page.error: logger.error("Error fetching download page: %s", download_page.error) UI.return_main_screen(status_code=1) if checksum_page.error: logger.error("Error fetching checksums: %s", checksum_page.error) UI.return_main_screen(status_code=1) match = re.search(r'^(\S+)\s+arduino-[\d\.\-r]+-linux' + self.bits + '.tar.xz$', checksum_page.buffer.getvalue().decode('ascii'), re.M) if not match: logger.error("Can't find a checksum.") UI.return_main_screen(status_code=1) checksum = match.group(1) soup = BeautifulSoup(download_page.buffer.getvalue(), 'html.parser') btn = soup.find('button', text=re.compile('JUST DOWNLOAD')) if not btn: logger.error("Can't parse download button.") UI.return_main_screen(status_code=1) base_url = download_page.final_url cookies = download_page.cookies final_download_url = parse.urljoin(base_url, btn.parent['href']) logger.info('Final download url: %s, cookies: %s.', final_download_url, cookies) self.download_requests = [DownloadItem(final_download_url, checksum=Checksum(ChecksumType.md5, checksum), cookies=cookies)] # add the user to arduino group if not self.was_in_arduino_group: with futures.ProcessPoolExecutor(max_workers=1) as executor: f = executor.submit(_add_to_group, self._current_user, self.ARDUINO_GROUP) if not f.result(): UI.return_main_screen(status_code=1) self.start_download_and_install() def post_install(self): """Create the Arduino launcher""" icon_path = join(self.install_path, 'lib', 'arduino_icon.ico') comment = _("The Arduino Software IDE") categories = "Development;IDE;" create_launcher(self.desktop_filename, get_application_desktop_file(name=_("Arduino"), icon_path=icon_path, exec='"{}" %f'.format(self.exec_path), comment=comment, categories=categories)) if not self.was_in_arduino_group: UI.delayed_display(DisplayMessage(_("You need to logout and login again for your installation to work"))) class BaseNetBeans(umake.frameworks.baseinstaller.BaseInstaller): """The base for all Netbeans installers.""" BASE_URL = "http://download.netbeans.org/netbeans" EXECUTABLE = "nb/netbeans" def __init__(self, category, flavour=""): """The constructor. @param category The IDE category. @param flavour The Netbeans flavour (plugins bundled). """ # add a separator to the string, like -cpp if flavour: flavour = '-' + flavour self.flavour = flavour super().__init__(name="Netbeans", description=_("Netbeans IDE"), category=category, only_on_archs=['i386', 'amd64'], download_page="https://netbeans.org/downloads/zip.html", dir_to_decompress_in_tarball="netbeans*", desktop_filename="netbeans{}.desktop".format(flavour), packages_requirements=['openjdk-7-jdk', 'jayatana'], required_files_path=[os.path.join("bin", "netbeans")]) @MainLoop.in_mainloop_thread def get_metadata_and_check_license(self, result): """Get the latest version and trigger the download of the download_page file. :param result: the file downloaded by DownloadCenter, contains a web page """ # Processing the string to obtain metadata (version) try: url_version_str = result[self.download_page].buffer.read().decode('utf-8') except AttributeError: # The file could not be parsed or there is no network connection logger.error("The download page changed its syntax or is not parsable") UI.return_main_screen(status_code=1) preg = re.compile(".*/images_www/v6/download/.*") for line in url_version_str.split("\n"): if preg.match(line): line = line.replace("var PAGE_ARTIFACTS_LOCATION = \"/images" "_www/v6/download/", "").replace("/\";", "") self.version = line.strip() if not self.version: # Fallback logger.error("Could not determine latest version") UI.return_main_screen(status_code=1) self.version_download_page = "https://netbeans.org/images_www/v6/download/" \ "{}/js/files.js".format(self.version) DownloadCenter([DownloadItem(self.version_download_page)], self.parse_download_page_callback, download=False) @MainLoop.in_mainloop_thread def parse_download_page_callback(self, result): """Get the download_url and trigger the download and installation of the app. :param result: the file downloaded by DownloadCenter, contains js functions with download urls """ logger.info("Netbeans {}".format(self.version)) # Processing the string to obtain metadata (download url) try: url_file = result[self.version_download_page].buffer.read().decode('utf-8') except AttributeError: # The file could not be parsed logger.error("The download page changed its syntax or is not parsable") UI.return_main_screen(status_code=1) preg = re.compile('add_file\("zip/netbeans-{}-[0-9]{{12}}{}.zip"'.format(self.version, self.flavour)) for line in url_file.split("\n"): if preg.match(line): # Clean up the string from js (it's a function call) line = line.replace("add_file(", "").replace(");", "").replace('"', "") url_string = line if not url_string: # The file could not be parsed logger.error("The download page changed its syntax or is not parsable") UI.return_main_screen(status_code=1) string_array = url_string.split(", ") try: url_suffix = string_array[0] md5 = string_array[2] except IndexError: # The file could not be parsed logger.error("The download page changed its syntax or is not parsable") UI.return_main_screen(status_code=1) download_url = "{}/{}/final/{}".format(self.BASE_URL, self.version, url_suffix) self.download_requests.append(DownloadItem(download_url, Checksum(ChecksumType.md5, md5))) self.start_download_and_install() def post_install(self): """Create the Netbeans launcher""" create_launcher(self.desktop_filename, get_application_desktop_file(name=_("Netbeans IDE"), icon_path=join(self.install_path, "nb", "netbeans.png"), exec=self.exec_path, comment=_("Netbeans IDE"), categories="Development;IDE;")) class VisualStudioCode(umake.frameworks.baseinstaller.BaseInstaller): PERM_DOWNLOAD_LINKS = { "i686": "http://go.microsoft.com/fwlink/?LinkID=620885", "x86_64": "http://go.microsoft.com/fwlink/?LinkID=620884" } def __init__(self, category): super().__init__(name="Visual Studio Code", description=_("Visual Studio focused on modern web and cloud"), category=category, only_on_archs=['i386', 'amd64'], expect_license=True, download_page="https://code.visualstudio.com/License", desktop_filename="visual-studio-code.desktop", required_files_path=["Code"], dir_to_decompress_in_tarball="VSCode-linux-*", packages_requirements=["libgtk2.0-0"]) def parse_license(self, line, license_txt, in_license): """Parse Android Studio download page for license""" if 'SOFTWARE LICENSE TERMS' in line: in_license = True if in_license and "* * *" in line: in_license = False if in_license: license_txt.write(line.strip() + "\n") return in_license def parse_download_link(self, line, in_download): """We have persistent links for Visual Studio Code, return it right away""" url = None with suppress(KeyError): url = self.PERM_DOWNLOAD_LINKS[platform.machine()] return ((url, None), in_download) def post_install(self): """Create the Visual Studio Code launcher""" create_launcher(self.desktop_filename, get_application_desktop_file(name=_("Visual Studio Code"), icon_path=os.path.join(self.install_path, "resources", "app", "resources", "linux", "code.png"), exec=self.exec_path, comment=_("Visual Studio focused on modern web and cloud"), categories="Development;IDE;")) class LightTable(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="LightTable", description=_("LightTable code editor"), category=category, only_on_archs=['amd64'], download_page="https://github.com/LightTable/LightTable/releases", desktop_filename="lighttable.desktop", required_files_path=["LightTable"], dir_to_decompress_in_tarball="lighttable-*", checksum_type=ChecksumType.md5) def parse_download_link(self, line, in_download): """Parse LightTable download links""" url, md5 = (None, None) if '
  • Ubuntu' in line: in_download = True p = re.search(r'(\w+)
  • ', line) with suppress(AttributeError): md5 = p.group(1) if in_download is True and "-linux.tar.gz" in line: p = re.search(r'href="(.*.-linux.tar.gz)"', line) with suppress(AttributeError): url = "https://github.com" + p.group(1) return ((url, md5), in_download) def post_install(self): """Create the LightTable Code launcher""" create_launcher(self.desktop_filename, get_application_desktop_file(name=_("LightTable"), icon_path=os.path.join(self.install_path, "resources", "app", "core", "img", "lticon.png"), exec=self.exec_path, comment=_("LightTable code editor"), categories="Development;IDE;")) class SpringToolsSuite(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Spring Tools Suite", description=_("Spring Tools Suite IDE"), download_page="https://spring.io/tools/sts/all", dir_to_decompress_in_tarball='sts-bundle/sts-*', desktop_filename='STS.desktop', category=category, only_on_archs=['i386', 'amd64'], packages_requirements=['openjdk-7-jdk'], icon_filename='icon.xpm', required_files_path=["STS"]) self.arch = '' if platform.machine() == 'i686' else '-x86_64' def download_provider_page(self): logger.debug("Download application provider page") DownloadCenter([DownloadItem(self.download_page)], self.get_metadata, download=False) @MainLoop.in_mainloop_thread def get_metadata(self, result): """Download files to download""" logger.debug("Parse download metadata") error_msg = result[self.download_page].error if error_msg: logger.error("An error occurred while downloading {}: {}".format(self.download_page, error_msg)) UI.return_main_screen(status_code=1) in_download = False url_found = False for line in result[self.download_page].buffer: line_content = line.decode() (_url_found, in_download) = self.parse_download_link(line_content, in_download) if not url_found: url_found = _url_found if not url_found: logger.error("Download page changed its syntax or is not parsable") UI.return_main_screen(status_code=1) def parse_download_link(self, line, in_download): """Parse STS download link""" url_found = False in_download = False keyword = 'linux-gtk{}.tar.gz'.format(self.arch) if keyword in line: in_download = True if in_download: regexp = r'href="(.*.tar.gz)"' p = re.search(regexp, line) with suppress(AttributeError): url_found = True self.sha1_url = '{}.sha1'.format(p.group(1)) DownloadCenter(urls=[DownloadItem(self.sha1_url, None)], on_done=self.get_sha_and_start_download, download=False) return (url_found, in_download) @MainLoop.in_mainloop_thread def get_sha_and_start_download(self, download_result): res = download_result[self.sha1_url] sha1 = res.buffer.getvalue().decode('utf-8').split()[0] url = re.sub('.sha1', '', self.sha1_url) if url is None: logger.error("Download page changed its syntax or is not parsable (missing url)") UI.return_main_screen(status_code=1) if sha1 is None: logger.error("Download page changed its syntax or is not parsable (missing sha512)") UI.return_main_screen(status_code=1) logger.debug("Found download link for {}, checksum: {}".format(url, sha1)) self.download_requests.append(DownloadItem(url, Checksum(ChecksumType.sha1, sha1))) self.start_download_and_install() def post_install(self): """Create the Spring Tools Suite launcher""" categories = "Development;IDE;" create_launcher(self.desktop_filename, get_application_desktop_file(name=_(self.name), icon_path=os.path.join(self.install_path, self.icon_filename), exec='"{}" %f'.format(self.exec_path), comment=_(self.description), categories=categories)) ubuntu-make-16.02.1/umake/frameworks/baseinstaller.py0000664000000000000000000004470612656574623017525 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Downloader abstract module""" from contextlib import suppress from io import StringIO import logging from progressbar import ProgressBar import os import shutil import umake.frameworks from umake.decompressor import Decompressor from umake.interactions import InputText, YesNo, LicenseAgreement, DisplayMessage, UnknownProgress from umake.network.download_center import DownloadCenter, DownloadItem from umake.network.requirements_handler import RequirementsHandler from umake.ui import UI from umake.tools import MainLoop, strip_tags, launcher_exists, get_icon_path, get_launcher_path, \ Checksum, remove_framework_envs_from_user, add_exec_link logger = logging.getLogger(__name__) class BaseInstaller(umake.frameworks.BaseFramework): DIRECT_COPY_EXT = ['.svg', '.png', '.ico', '.jpg', '.jpeg'] def __new__(cls, *args, **kwargs): "This class is not meant to be instantiated, so __new__ returns None." if cls == BaseInstaller: return None return super().__new__(cls) def __init__(self, *args, **kwargs): """The Downloader framework isn't instantiated directly, but is useful to inherit from for all frameworks having a set of downloads to proceed, some eventual supported_archs.""" self.download_page = kwargs["download_page"] self.checksum_type = kwargs.get("checksum_type", None) self.dir_to_decompress_in_tarball = kwargs.get("dir_to_decompress_in_tarball", "") self.required_files_path = kwargs.get("required_files_path", []) self.desktop_filename = kwargs.get("desktop_filename", None) self.icon_filename = kwargs.get("icon_filename", None) self.match_last_link = kwargs.get("match_last_link", False) self.exec_rel_path = kwargs.get("exec_rel_path", None) for extra_arg in ["download_page", "checksum_type", "dir_to_decompress_in_tarball", "desktop_filename", "icon_filename", "required_files_path", "match_last_link", "exec_rel_path"]: with suppress(KeyError): kwargs.pop(extra_arg) super().__init__(*args, **kwargs) self._install_done = False self._paths_to_clean = set() self._arg_install_path = None self.download_requests = [] @property def exec_link_name(self): if self.desktop_filename: return self.desktop_filename.split('.')[0] return None @property def is_installed(self): # check path and requirements if not super().is_installed: return False for required_file_path in self.required_files_path: if not os.path.exists(os.path.join(self.install_path, required_file_path)): logger.debug("{} binary isn't installed".format(self.name)) return False if self.desktop_filename: return launcher_exists(self.desktop_filename) logger.debug("{} is installed".format(self.name)) return True def setup(self, install_path=None, auto_accept_license=False): self.arg_install_path = install_path self.auto_accept_license = auto_accept_license super().setup() # first step, check if installed if self.is_installed: UI.display(YesNo("{} is already installed on your system, do you want to reinstall " "it anyway?".format(self.name), self.reinstall, UI.return_main_screen)) else: self.confirm_path(self.arg_install_path) def reinstall(self): logger.debug("Mark previous installation path for cleaning.") self._paths_to_clean.add(self.install_path) # remove previous installation path self.confirm_path(self.arg_install_path) remove_framework_envs_from_user(self.name) def remove(self): """Remove current framework if installed Not that we only remove desktop file, launcher icon and dir content, we do not remove packages as they might be in used for other framework""" # check if it's installed and so on. super().remove() UI.display(DisplayMessage("Removing {}".format(self.name))) if self.desktop_filename: with suppress(FileNotFoundError): os.remove(get_launcher_path(self.desktop_filename)) os.remove(os.path.join(self.default_binary_link_path, self.exec_link_name)) if self.icon_filename: with suppress(FileNotFoundError): os.remove(get_icon_path(self.icon_filename)) with suppress(FileNotFoundError): shutil.rmtree(self.install_path) remove_framework_envs_from_user(self.name) self.remove_from_config() UI.delayed_display(DisplayMessage("Suppression done")) UI.return_main_screen() def confirm_path(self, path_dir=""): """Confirm path dir""" if not path_dir: logger.debug("No installation path provided. Requesting one.") UI.display(InputText("Choose installation path:", self.confirm_path, self.install_path)) return logger.debug("Installation path provided. Checking if exists.") with suppress(FileNotFoundError): if os.listdir(path_dir): # we already told we were ok to overwrite as it was the previous install path if path_dir not in self._paths_to_clean: if path_dir == "/": logger.error("This doesn't seem wise. We won't let you shoot in your feet.") self.confirm_path() return self.install_path = path_dir # we don't set it before to not repropose / as installation path UI.display(YesNo("{} isn't an empty directory, do you want to remove its content and install " "there?".format(path_dir), self.set_installdir_to_clean, UI.return_main_screen)) return self.install_path = path_dir if self.desktop_filename: self.exec_path = os.path.join(self.install_path, self.required_files_path[0]) # if self.exec_rel_path: # self.exec_path = os.path.join(self.install_path, self.exec_rel_path) self.download_provider_page() def set_installdir_to_clean(self): logger.debug("Mark non empty new installation path for cleaning.") self._paths_to_clean.add(self.install_path) self.download_provider_page() def download_provider_page(self): logger.debug("Download application provider page") DownloadCenter([DownloadItem(self.download_page)], self.get_metadata_and_check_license, download=False) def parse_license(self, line, license_txt, in_license): """Parse license per line, eventually write to license_txt if it's in the license part. A flag in_license that is returned by the same function helps to decide if we are in the license part""" pass def parse_download_link(self, line, in_download): """Parse download_link per line. in_download is a helper that the function return to know if it's in the download part. return a tuple of (None, in_download=True/False) if no parsable is found or ((url, md5sum), in_download=True/False)""" pass @MainLoop.in_mainloop_thread def get_metadata_and_check_license(self, result): """Download files to download + license and check it""" logger.debug("Parse download metadata") error_msg = result[self.download_page].error if error_msg: logger.error("An error occurred while downloading {}: {}".format(self.download_page, error_msg)) UI.return_main_screen(status_code=1) url, checksum = (None, None) with StringIO() as license_txt: in_license = False in_download = False for line in result[self.download_page].buffer: line_content = line.decode() if self.expect_license and not self.auto_accept_license: in_license = self.parse_license(line_content, license_txt, in_license) # always take the first valid (url, checksum) if not match_last_link is set to True: download = None if url is None or (self.checksum_type and not checksum) or self.match_last_link: (download, in_download) = self.parse_download_link(line_content, in_download) if download is not None: (newurl, new_checksum) = download url = newurl if newurl is not None else url checksum = new_checksum if new_checksum is not None else checksum if url is not None: if self.checksum_type and checksum: logger.debug("Found download link for {}, checksum: {}".format(url, checksum)) elif not self.checksum_type: logger.debug("Found download link for {}".format(url)) if url is None: logger.error("Download page changed its syntax or is not parsable (url missing)") UI.return_main_screen(status_code=1) if (self.checksum_type and checksum is None): logger.error("Download page changed its syntax or is not parsable (checksum missing)") logger.error("URL is: {}".format(url)) UI.return_main_screen(status_code=1) self.download_requests.append(DownloadItem(url, Checksum(self.checksum_type, checksum))) if license_txt.getvalue() != "": logger.debug("Check license agreement.") UI.display(LicenseAgreement(strip_tags(license_txt.getvalue()).strip(), self.start_download_and_install, UI.return_main_screen)) elif self.expect_license and not self.auto_accept_license: logger.error("We were expecting to find a license on the download page, we didn't.") UI.return_main_screen(status_code=1) else: self.start_download_and_install() def start_download_and_install(self): self.last_progress_download = None self.last_progress_requirement = None self.balance_requirement_download = None self.pkg_size_download = 0 self.result_requirement = None self.result_download = None self._download_done_callback_called = False UI.display(DisplayMessage("Downloading and installing requirements")) self.pbar = ProgressBar().start() self.pkg_to_install = RequirementsHandler().install_bucket(self.packages_requirements, self.get_progress_requirement, self.requirement_done) DownloadCenter(urls=self.download_requests, on_done=self.download_done, report=self.get_progress_download) @MainLoop.in_mainloop_thread def get_progress(self, progress_download, progress_requirement): """Global progress info. Don't use named parameters as idle_add doesn't like it""" if progress_download is not None: self.last_progress_download = progress_download if progress_requirement is not None: self.last_progress_requirement = progress_requirement # we wait to have the file size to start getting progress proportion info # try to compute balance requirement if self.balance_requirement_download is None: if not self.pkg_to_install: self.balance_requirement_download = 0 self.last_progress_requirement = 0 if self.last_progress_download is None: return else: # we only update if we got a progress from both sides if self.last_progress_download is None or self.last_progress_requirement is None: return else: # apply a minimum of 15% (no download or small download + install time) self.balance_requirement_download = max(self.pkg_size_download / (self.pkg_size_download + self.total_download_size), 0.15) if not self.pbar.finished: # drawing is delayed, so ensure we are not done first progress = self._calculate_progress() self.pbar.update(progress) def _calculate_progress(self): progress = self.balance_requirement_download * self.last_progress_requirement +\ (1 - self.balance_requirement_download) * self.last_progress_download normalized_progress = max(0, progress) normalized_progress = min(normalized_progress, 100) return normalized_progress def get_progress_requirement(self, status): """Chain up to main get_progress, returning current value between 0 and 100""" percentage = status["percentage"] # 60% is download, 40% is installing if status["step"] == RequirementsHandler.STATUS_DOWNLOADING: self.pkg_size_download = status["pkg_size_download"] progress = 0.6 * percentage else: if self.pkg_size_download == 0: progress = percentage # no download, only install else: progress = 60 + 0.4 * percentage self.get_progress(None, progress) def get_progress_download(self, downloads): """Chain up to main get_progress, returning current value between 0 and 100 First call initialize the balance between requirements and download progress""" # don't push any progress until we have the total download size if len(downloads) != len(self.download_requests): return total_size = 0 total_current_size = 0 for download in downloads: total_size += downloads[download]["size"] total_current_size += downloads[download]["current"] self.total_download_size = total_size self.get_progress(total_current_size / total_size * 100, None) def requirement_done(self, result): # set requirement download as finished if no error if not result.error: self.get_progress(None, 100) self.result_requirement = result self.download_and_requirements_done() def download_done(self, result): # set download as finished if no error for url in result: if result[url].error: break else: self.get_progress(100, None) self.result_download = result self.download_and_requirements_done() @MainLoop.in_mainloop_thread def download_and_requirements_done(self): # wait for both side to be done if self._download_done_callback_called or (not self.result_download or not self.result_requirement): return self._download_done_callback_called = True self.pbar.finish() # display eventual errors error_detected = False if self.result_requirement.error: logger.error("Package requirements can't be met: {}".format(self.result_requirement.error)) error_detected = True # check for any errors and collect fds fds = [] for url in self.result_download: if self.result_download[url].error: logger.error(self.result_download[url].error) error_detected = True fds.append(self.result_download[url].fd) if error_detected: UI.return_main_screen(status_code=1) # now decompress self.decompress_and_install(fds) def decompress_and_install(self, fds): UI.display(DisplayMessage("Installing {}".format(self.name))) # empty destination directory if reinstall for dir_to_remove in self._paths_to_clean: with suppress(FileNotFoundError): shutil.rmtree(dir_to_remove) # marked them as cleaned self._paths_to_clean = [] os.makedirs(self.install_path, exist_ok=True) decompress_fds = {} for fd in fds: direct_copy = False for ext in self.DIRECT_COPY_EXT: if fd.name.endswith(ext): direct_copy = True break if direct_copy: shutil.copy2(fd.name, os.path.join(self.install_path, os.path.basename(fd.name))) else: decompress_fds[fd] = Decompressor.DecompressOrder(dir=self.dir_to_decompress_in_tarball, dest=self.install_path) Decompressor(decompress_fds, self.decompress_and_install_done) UI.display(UnknownProgress(self.iterate_until_install_done)) def post_install(self): """Call the post_install process, like creating a launcher, adding env variables…""" pass @MainLoop.in_mainloop_thread def decompress_and_install_done(self, result): self._install_done = True error_detected = False for fd in result: if result[fd].error: logger.error(result[fd].error) error_detected = True fd.close() if error_detected: UI.return_main_screen(status_code=1) self.post_install() if self.exec_link_name: add_exec_link(self.exec_path, self.exec_link_name) # Mark as installation done in configuration self.mark_in_config() UI.delayed_display(DisplayMessage("Installation done")) UI.return_main_screen() def iterate_until_install_done(self): while not self._install_done: yield ubuntu-make-16.02.1/umake/frameworks/dart.py0000664000000000000000000000737212656574623015625 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Dartlang module""" from contextlib import suppress from gettext import gettext as _ import logging import os import platform import re import umake.frameworks.baseinstaller from umake.interactions import DisplayMessage from umake.network.download_center import DownloadItem from umake.tools import add_env_to_user, MainLoop from umake.ui import UI logger = logging.getLogger(__name__) _supported_archs = ['i386', 'amd64'] class DartCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Dart", description=_("Dartlang Development Environment"), logo_path=None) class DartLangEditorRemoval(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Dart Editor", description=_("Dart SDK with editor (not supported upstream anyymore)"), download_page=None, category=category, only_on_archs=_supported_archs, only_for_removal=True) class DartLang(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Dart SDK", description=_("Dart SDK (default)"), is_category_default=True, category=category, only_on_archs=_supported_archs, download_page="https://api.dartlang.org", dir_to_decompress_in_tarball="dart-sdk", required_files_path=[os.path.join("bin", "dart")]) @MainLoop.in_mainloop_thread def get_metadata_and_check_license(self, result): """Get latest version and append files to download""" logger.debug("Set download metadata") error_msg = result[self.download_page].error if error_msg: logger.error("An error occurred while downloading {}: {}".format(self.download_page, error_msg)) UI.return_main_screen(status_code=1) version = '' version_re = r'Dart SDK ([\d\.]+)' for line in result[self.download_page].buffer: p = re.search(version_re, line.decode()) with suppress(AttributeError): version = p.group(1) break else: logger.error("Download page changed its syntax or is not parsable") UI.return_main_screen(status_code=1) tag_machine = 'x64' if platform.machine() == 'i686': tag_machine = 'ia32' url = "https://storage.googleapis.com/dart-archive/channels/stable/release/{}/sdk/dartsdk-linux-{}-release.zip"\ .format(version, tag_machine) logger.debug("Found download link for {}".format(url)) self.download_requests.append(DownloadItem(url, None)) self.start_download_and_install() def post_install(self): """Add go necessary env variables""" add_env_to_user(self.name, {"PATH": {"value": os.path.join(self.install_path, "bin")}}) UI.delayed_display(DisplayMessage(_("You need to restart your current shell session for your {} installation " "to work properly").format(self.name))) ubuntu-make-16.02.1/umake/frameworks/rust.py0000664000000000000000000001336712656574623015671 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Tin Tvrtković # Jared Ravetch # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Rust module""" from contextlib import suppress from gettext import gettext as _ from glob import glob import logging import os import re from bs4 import BeautifulSoup import umake.frameworks.baseinstaller from umake.interactions import DisplayMessage from umake.network.download_center import DownloadItem, DownloadCenter from umake.tools import get_current_arch, add_env_to_user, ChecksumType, \ MainLoop, Checksum from umake.ui import UI logger = logging.getLogger(__name__) class RustCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Rust", description=_("Rust language"), logo_path=None) class RustLang(umake.frameworks.baseinstaller.BaseInstaller): # Button labels on the download page. arch_trans = { "amd64": "64-bit", "i386": "32-bit" } def __init__(self, category): super().__init__(name="Rust Lang", description=_("The official Rust distribution"), is_category_default=True, category=category, only_on_archs=['i386', 'amd64'], download_page="https://www.rust-lang.org/downloads.html", checksum_type=ChecksumType.sha256, dir_to_decompress_in_tarball="rust-*") def parse_download_link(self, line, in_download): """Parse Rust download link, expect to find a url""" url, sha1 = (None, None) arch = get_current_arch() if "{}-unknown-linux-gnu.tar.gz".format(self.arch_trans[arch]) in line: in_download = True if in_download: p = re.search(r'href="(.*)">', line) with suppress(AttributeError): url = p.group(1) p = re.search(r'(\w+)', line) with suppress(AttributeError): sha1 = p.group(1) if "" in line: in_download = False if url is None and sha1 is None: return (None, in_download) return ((url, sha1), in_download) @MainLoop.in_mainloop_thread def get_metadata_and_check_license(self, result): """Override this so we can use BS and fetch the checksum separately.""" logger.debug("Fetched download page, parsing.") page = result[self.download_page] error_msg = page.error if error_msg: logger.error("An error occurred while downloading {}: {}".format(self.download_page_url, error_msg)) UI.return_main_screen(status_code=1) soup = BeautifulSoup(page.buffer, 'html.parser') link = (soup.find('div', class_="install") .find('td', class_="inst-type", text="Linux (.tar.gz)") .parent .find(text=self.arch_trans[get_current_arch()]) .parent .parent) if link is None: logger.error("Can't parse the download URL from the download page.") UI.return_main_screen(status_code=1) download_url = link.attrs['href'] checksum_url = download_url + '.sha256' logger.debug("Found download URL: " + download_url) logger.debug("Downloading checksum first, from " + checksum_url) def checksum_downloaded(results): checksum_result = next(iter(results.values())) # Just get the first. if checksum_result.error: logger.error(checksum_result.error) UI.return_main_screen(status_code=1) checksum = checksum_result.buffer.getvalue().decode('utf-8').split()[0] logger.info('Obtained SHA256 checksum: ' + checksum) self.download_requests.append(DownloadItem(download_url, checksum=Checksum(ChecksumType.sha256, checksum), ignore_encoding=True)) self.start_download_and_install() DownloadCenter([DownloadItem(checksum_url)], on_done=checksum_downloaded, download=False) def post_install(self): """Add rust necessary env variables""" add_env_to_user(self.name, {"PATH": {"value": "{}:{}".format(os.path.join(self.install_path, "rustc", "bin"), os.path.join(self.install_path, "cargo", "bin"))}, "LD_LIBRARY_PATH": {"value": os.path.join(self.install_path, "rustc", "lib")}}) # adjust for rust 1.5 some symlinks magic to have stdlib craft available os.chdir(os.path.join(self.install_path, "rustc", "lib")) os.rename("rustlib", "rustlib.init") os.symlink(glob(os.path.join('..', '..', 'rust-std-*', 'lib', 'rustlib'))[0], 'rustlib') os.symlink(os.path.join('..', 'rustlib.init', 'etc'), os.path.join('rustlib', 'etc')) UI.delayed_display(DisplayMessage(_("You need to restart your current shell session for your {} installation " "to work properly").format(self.name))) ubuntu-make-16.02.1/umake/frameworks/__pycache__/0000755000000000000000000000000012656574625016520 5ustar ubuntu-make-16.02.1/umake/frameworks/scala.py0000664000000000000000000000506512656574623015753 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # Igor Vuk # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Scala module""" from contextlib import suppress from gettext import gettext as _ import logging import os import re import umake.frameworks.baseinstaller from umake.interactions import DisplayMessage from umake.tools import add_env_to_user from umake.ui import UI logger = logging.getLogger(__name__) class ScalaCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Scala", description=_("The Scala Programming Language"), logo_path=None) class ScalaLang(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Scala Lang", description=_("Scala compiler and interpreter (default)"), is_category_default=True, category=category, packages_requirements=["default-jre"], download_page="http://www.scala-lang.org/download/", dir_to_decompress_in_tarball="scala-*", required_files_path=[os.path.join("bin", "scala")]) def parse_download_link(self, line, in_download): """Parse Scala download link, expect to find a url""" if 'id="#link-main-unixsys"' in line: p = re.search(r'href="(.*)"', line) with suppress(AttributeError): url = p.group(1) return ((url, None), True) return ((None, None), False) def post_install(self): """Add the necessary Scala environment variables""" add_env_to_user(self.name, {"PATH": {"value": os.path.join(self.install_path, "bin")}, "SCALA_HOME": {"value": self.install_path}}) UI.delayed_display(DisplayMessage(_("You need to restart your current shell session for your {} installation " "to work properly").format(self.name))) ubuntu-make-16.02.1/umake/frameworks/nodejs.py0000664000000000000000000000624312656574623016151 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Nodejs module""" from contextlib import suppress from gettext import gettext as _ import logging import os import subprocess import umake.frameworks.baseinstaller from umake.interactions import DisplayMessage from umake.tools import get_current_arch, add_env_to_user, ChecksumType from umake.ui import UI logger = logging.getLogger(__name__) class NodejsCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Nodejs", description=_("Nodejs stable"), logo_path=None) class NodejsLang(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Nodejs Lang", description=_("Nodejs stable"), is_category_default=True, category=category, only_on_archs=['i386', 'amd64'], download_page="https://nodejs.org/dist/latest/SHASUMS256.txt", checksum_type=ChecksumType.sha256, dir_to_decompress_in_tarball="node*", required_files_path=[os.path.join("bin", "node")]) arch_trans = { "amd64": "x64", "i386": "x86" } def parse_download_link(self, line, in_download): """Parse Nodejs download link, expect to find a sha1 and a url""" url, shasum = (None, None) arch = get_current_arch() if "linux-{}.tar.xz".format(self.arch_trans[arch]) in line: in_download = True if in_download: url = self.download_page.strip("SHASUMS256.txt") + line.split(' ')[2].rstrip() shasum = line.split(' ')[0] if url is None and shasum is None: return (None, in_download) return ((url, shasum), in_download) def post_install(self): """Add nodejs necessary env variables and move module folder""" subprocess.call([os.path.join(self.install_path, "bin", "npm"), "config", "set", "prefix", "~/.node_modules"]) add_env_to_user(self.name, {"PATH": {"value": "{}:{}".format(os.path.join(self.install_path, "bin"), os.path.join(os.path.expanduser('~'), ".node_modules", "bin"))}}) UI.delayed_display(DisplayMessage(_("You need to restart your current shell session for your {} installation " "to work properly").format(self.name))) ubuntu-make-16.02.1/umake/frameworks/go.py0000664000000000000000000000566412656574623015302 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Go module""" from contextlib import suppress from gettext import gettext as _ import logging import os import re import umake.frameworks.baseinstaller from umake.interactions import DisplayMessage from umake.tools import get_current_arch, add_env_to_user, ChecksumType from umake.ui import UI logger = logging.getLogger(__name__) class GoCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Go", description=_("Go language"), logo_path=None) class GoLang(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Go Lang", description=_("Google compiler (default)"), is_category_default=True, category=category, only_on_archs=['i386', 'amd64'], download_page="https://golang.org/dl/", checksum_type=ChecksumType.sha256, dir_to_decompress_in_tarball="go", required_files_path=[os.path.join("bin", "go")]) def parse_download_link(self, line, in_download): """Parse Go download link, expect to find a sha and a url""" url, sha = (None, None) if "linux-{}".format(get_current_arch().replace("i386", "386")) in line: in_download = True if in_download: p = re.search(r'href="(.*)">', line) with suppress(AttributeError): url = p.group(1) p = re.search(r'(\w+)', line) with suppress(AttributeError): sha = p.group(1) if "" in line: in_download = False if url is None and sha is None: return (None, in_download) return ((url, sha), in_download) def post_install(self): """Add go necessary env variables""" add_env_to_user(self.name, {"PATH": {"value": os.path.join(self.install_path, "bin")}, "GOROOT": {"value": self.install_path, "keep": False}}) UI.delayed_display(DisplayMessage(_("You need to restart your current shell session for your {} installation " "to work properly").format(self.name))) ubuntu-make-16.02.1/umake/frameworks/android.py0000664000000000000000000002064212656574623016306 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Android module""" from contextlib import suppress from gettext import gettext as _ import logging import os import platform import re import umake.frameworks.baseinstaller from umake.interactions import DisplayMessage from umake.ui import UI from umake.tools import add_env_to_user, create_launcher, get_application_desktop_file, ChecksumType logger = logging.getLogger(__name__) _supported_archs = ['i386', 'amd64'] class AndroidCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Android", description=_("Android Development Environment"), logo_path=None) def parse_license(self, tag, line, license_txt, in_license): """Parse Android download page for license""" if line.startswith(tag): in_license = True if in_license: if line.startswith(''): in_license = False else: license_txt.write(line) return in_license def parse_download_link(self, tag, line, in_download): """Parse Android download links, expect to find a md5sum and a url""" url, md5sum = (None, None) if tag in line: in_download = True if in_download: p = re.search(r'href="(.*)"', line) with suppress(AttributeError): url = p.group(1) p = re.search(r'(\w+)', line) with suppress(AttributeError): # ensure the size can match a md5 or sha1 checksum if len(p.group(1)) > 15: md5sum = p.group(1) if "" in line: in_download = False if url is None and md5sum is None: return (None, in_download) return ((url, md5sum), in_download) class AndroidStudio(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Android Studio", description=_("Android Studio (default)"), is_category_default=True, category=category, only_on_archs=_supported_archs, expect_license=True, packages_requirements=["openjdk-7-jdk", "libncurses5:i386", "libstdc++6:i386", "zlib1g:i386", "jayatana"], download_page="https://developer.android.com/sdk/index.html", checksum_type=ChecksumType.sha1, dir_to_decompress_in_tarball="android-studio", desktop_filename="android-studio.desktop", required_files_path=[os.path.join("bin", "studio.sh")]) def parse_license(self, line, license_txt, in_license): """Parse Android Studio download page for license""" return self.category.parse_license('

    ', line, license_txt, in_license) def parse_download_link(self, line, in_download): """Parse Android Studio download link, expect to find a md5sum and a url""" return self.category.parse_download_link('id="linux-bundle"', line, in_download) def post_install(self): """Create the Android Studio launcher""" create_launcher(self.desktop_filename, get_application_desktop_file(name=_("Android Studio"), icon_path=os.path.join(self.install_path, "bin", "studio.png"), exec='"{}" %f'.format(os.path.join(self.install_path, "bin", "studio.sh")), comment=_("Android Studio developer environment"), categories="Development;IDE;", extra="StartupWMClass=jetbrains-android-studio")) class AndroidSDK(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Android SDK", description=_("Android SDK"), category=category, only_on_archs=_supported_archs, expect_license=True, packages_requirements=["openjdk-7-jdk", "libncurses5:i386", "libstdc++6:i386", "zlib1g:i386", "jayatana"], download_page="https://developer.android.com/sdk/index.html", checksum_type=ChecksumType.sha1, dir_to_decompress_in_tarball="android-sdk-linux", required_files_path=[os.path.join("tools", "android")]) def parse_license(self, line, license_txt, in_license): """Parse Android SDK download page for license""" return self.category.parse_license('

    ', line, license_txt, in_license) def parse_download_link(self, line, in_download): """Parse Android SDK download link, expect to find a SHA-1 and a url""" return self.category.parse_download_link('id="linux-tools"', line, in_download) def post_install(self): """Add necessary environment variables""" add_env_to_user(self.name, {"ANDROID_HOME": {"value": self.install_path, "keep": False}}) # add "platform-tools" to PATH to ensure "adb" can be run once the platform tools are installed via # the SDK manager add_env_to_user(self.name, {"PATH": {"value": [os.path.join("$ANDROID_HOME", "tools"), os.path.join("$ANDROID_HOME", "platform-tools")]}}) UI.delayed_display(DisplayMessage(_("You need to restart your current shell session for your {} installation " "to work properly").format(self.name))) # print wiki page message UI.delayed_display(DisplayMessage("SDK installed in {}. More information on how to use it on {}".format( self.install_path, "https://developer.android.com/sdk/installing/adding-packages.html"))) class AndroidNDK(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Android NDK", description=_("Android NDK"), category=category, only_on_archs=_supported_archs, expect_license=True, download_page="https://developer.android.com/ndk/downloads/index.html", checksum_type=ChecksumType.md5, dir_to_decompress_in_tarball="android-ndk-*", required_files_path=[os.path.join("ndk-build")]) def parse_license(self, line, license_txt, in_license): """Parse Android NDK download page for license""" return self.category.parse_license('

    Linux {}'.format(tag_machine), line, in_download) def post_install(self): """Add necessary environment variables""" add_env_to_user(self.name, {"NDK_ROOT": {"value": self.install_path, "keep": False}}) # print wiki page message UI.display(DisplayMessage("NDK installed in {}. More information on how to use it on {}".format( self.install_path, "https://developer.android.com/tools/sdk/ndk/index.html#GetStarted"))) class EclipseADTForRemoval(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Eclipse ADT", description="For removal only (not supported upstream anymore)", download_page=None, category=category, only_on_archs=_supported_archs, only_for_removal=True) ubuntu-make-16.02.1/umake/frameworks/__init__.py0000664000000000000000000003767212656574623016440 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Base Handling functions and base class of backends""" import abc from contextlib import suppress from gettext import gettext as _ from importlib import import_module, reload import inspect import logging import os import pkgutil import sys import subprocess from umake.network.requirements_handler import RequirementsHandler from umake.settings import DEFAULT_INSTALL_TOOLS_PATH, UMAKE_FRAMEWORKS_ENVIRON_VARIABLE, DEFAULT_BINARY_LINK_PATH from umake.tools import ConfigHandler, NoneDict, classproperty, get_current_arch, get_current_ubuntu_version,\ is_completion_mode, switch_to_current_user, MainLoop, get_user_frameworks_path from umake.ui import UI logger = logging.getLogger(__name__) class BaseCategory(): """Base Category class to be inherited""" NOT_INSTALLED, PARTIALLY_INSTALLED, FULLY_INSTALLED = range(3) categories = NoneDict() def __init__(self, name, description="", logo_path=None, is_main_category=False, packages_requirements=None): self.name = name self.description = description self.logo_path = logo_path self.is_main_category = is_main_category self.default = None self.frameworks = NoneDict() self.packages_requirements = [] if packages_requirements is None else packages_requirements if self.prog_name in self.categories: logger.warning("There is already a registered category with {} as a name. Don't register the second one." .format(name)) else: self.categories[self.prog_name] = self @classproperty def main_category(self): for category in self.categories.values(): if category.is_main_category: return category return None @property def prog_name(self): """Get programmatic, path and CLI compatible names""" return self.name.lower().replace('/', '-').replace(' ', '-') @property def default_framework(self): """Get default framework""" for framework in self.frameworks.values(): if framework.is_category_default: return framework return None def register_framework(self, framework): """Register a new framework""" if framework.prog_name in self.frameworks: logger.error("There is already a registered framework with {} as a name. Don't register the second one." .format(framework.name)) else: self.frameworks[framework.prog_name] = framework @property def is_installed(self): """Return if the category is installed""" installed_frameworks = [framework for framework in self.frameworks.values() if framework.is_installed] if len(installed_frameworks) == 0: return self.NOT_INSTALLED if len(installed_frameworks) == len(self.frameworks): return self.FULLY_INSTALLED return self.PARTIALLY_INSTALLED def install_category_parser(self, parser): """Install category parser and get frameworks""" if not self.has_frameworks(): logging.debug("Skipping {} having no framework".format(self.name)) return # framework parser is directly category parser if self.is_main_category: framework_parser = parser else: self.category_parser = parser.add_parser(self.prog_name, help=self.description) framework_parser = self.category_parser.add_subparsers(dest="framework") for framework in self.frameworks.values(): framework.install_framework_parser(framework_parser) return framework_parser def has_frameworks(self): """Return if a category has at least one framework""" return len(self.frameworks) > 0 def has_one_framework(self): """Return if a category has one framework""" return len(self.frameworks) == 1 def run_for(self, args): """Running commands from args namespace""" # try to call default framework if any if not args.framework: if not self.default_framework: message = _("A default framework for category {} was requested where there is none".format(self.name)) logger.error(message) self.category_parser.print_usage() UI.return_main_screen(status_code=1) self.default_framework.run_for(args) return self.frameworks[args.framework].run_for(args) class BaseFramework(metaclass=abc.ABCMeta): def __init__(self, name, description, category, logo_path=None, is_category_default=False, install_path_dir=None, only_on_archs=None, only_ubuntu_version=None, packages_requirements=None, only_for_removal=False, expect_license=False, need_root_access=False): self.name = name self.description = description self.logo_path = None self.category = category self.is_category_default = is_category_default self.only_on_archs = [] if only_on_archs is None else only_on_archs self.only_ubuntu_version = [] if only_ubuntu_version is None else only_ubuntu_version self.packages_requirements = [] if packages_requirements is None else packages_requirements self.packages_requirements.extend(self.category.packages_requirements) self.only_for_removal = only_for_removal self.expect_license = expect_license # don't detect anything for completion mode (as we need to be quick), so avoid opening apt cache and detect # if it's installed. if is_completion_mode(): # only show it in shell completion if it was already installed if self.only_for_removal: config = ConfigHandler().config try: if not os.path.isdir(config["frameworks"][category.prog_name][self.prog_name]["path"]): # don't show the framework in shell completion as for removal only and not installed return except (TypeError, KeyError, FileNotFoundError): # don't show the framework in shell completion as for removal only and not installed return category.register_framework(self) return self.need_root_access = need_root_access if not need_root_access: with suppress(KeyError): self.need_root_access = not RequirementsHandler().is_bucket_installed(self.packages_requirements) if self.is_category_default: if self.category == BaseCategory.main_category: logger.error("Main category can't have default framework as {} requires".format(name)) self.is_category_default = False elif self.category.default_framework is not None: logger.error("Can't set {} as default for {}: this category already has a default framework ({}). " "Don't set any as default".format(category.name, name, self.category.default_framework.name)) self.is_category_default = False self.category.default_framework.is_category_default = False if not install_path_dir: install_path_dir = os.path.join("" if category.is_main_category else category.prog_name, self.prog_name) self.default_install_path = os.path.join(DEFAULT_INSTALL_TOOLS_PATH, install_path_dir) self.default_binary_link_path = DEFAULT_BINARY_LINK_PATH self.install_path = self.default_install_path # check if we have an install path previously set config = ConfigHandler().config try: self.install_path = config["frameworks"][category.prog_name][self.prog_name]["path"] except (TypeError, KeyError, FileNotFoundError): pass # This requires install_path and will register need_root or not if not self.is_installed and not self.is_installable: logger.info("Don't register {} as it's not installable on this configuration.".format(name)) return category.register_framework(self) @property def is_installable(self): """Return if the framework can be installed on that arch""" if self.only_for_removal: return False try: if len(self.only_on_archs) > 0: # we have some restricted archs, check we support it current_arch = get_current_arch() if current_arch not in self.only_on_archs: logger.debug("{} only supports {} archs and you are on {}.".format(self.name, self.only_on_archs, current_arch)) return False if len(self.only_ubuntu_version) > 0: current_version = get_current_ubuntu_version() if current_version not in self.only_ubuntu_version: logger.debug("{} only supports {} and you are on {}.".format(self.name, self.only_ubuntu_version, current_version)) return False if not RequirementsHandler().is_bucket_available(self.packages_requirements): return False except: logger.error("An error occurred when detecting platform, don't register {}".format(self.name)) return False return True @property def prog_name(self): """Get programmatic, path and CLI compatible names""" return self.name.lower().replace('/', '-').replace(' ', '-') @abc.abstractmethod def setup(self): """Method call to setup the Framework""" if not self.is_installable: logger.error(_("You can't install that framework on this machine")) UI.return_main_screen(status_code=1) if self.need_root_access and os.geteuid() != 0: logger.debug("Requesting root access") cmd = ["sudo", "-E", "env", "PATH={}".format(os.getenv("PATH"))] cmd.extend(sys.argv) MainLoop().quit(subprocess.call(cmd)) # be a normal, kind user as we don't want normal files to be written as root switch_to_current_user() @abc.abstractmethod def remove(self): """Method call to remove the current framework""" if not self.is_installed: logger.error(_("You can't remove {} as it isn't installed".format(self.name))) UI.return_main_screen(status_code=1) def mark_in_config(self): """Mark the installation as installed in the config file""" config = ConfigHandler().config config.setdefault("frameworks", {})\ .setdefault(self.category.prog_name, {})\ .setdefault(self.prog_name, {})["path"] = self.install_path ConfigHandler().config = config def remove_from_config(self): """Remove current framework from config""" config = ConfigHandler().config del(config["frameworks"][self.category.prog_name][self.prog_name]) ConfigHandler().config = config @property def is_installed(self): """Method call to know if the framework is installed""" if not os.path.isdir(self.install_path): return False if not RequirementsHandler().is_bucket_installed(self.packages_requirements): return False return True def install_framework_parser(self, parser): """Install framework parser""" this_framework_parser = parser.add_parser(self.prog_name, help=self.description) this_framework_parser.add_argument('destdir', nargs='?', help=_("If the default framework name isn't provided, " "destdir should contain a /")) this_framework_parser.add_argument('-r', '--remove', action="store_true", help=_("Remove framework if installed")) if self.expect_license: this_framework_parser.add_argument('--accept-license', dest="accept_license", action="store_true", help=_("Accept license without prompting")) return this_framework_parser def run_for(self, args): """Running commands from args namespace""" logger.debug("Call run_for on {}".format(self.name)) if args.remove: if args.destdir: message = "You can't specify a destination dir while removing a framework" logger.error(message) UI.return_main_screen(status_code=1) self.remove() else: install_path = None auto_accept_license = False if args.destdir: install_path = os.path.abspath(os.path.expanduser(args.destdir)) if self.expect_license and args.accept_license: auto_accept_license = True self.setup(install_path=install_path, auto_accept_license=auto_accept_license) class MainCategory(BaseCategory): def __init__(self): super().__init__(name="main", is_main_category=True) def _is_categoryclass(o): return inspect.isclass(o) and issubclass(o, BaseCategory) def _is_frameworkclass(o): """Filter concrete (non-abstract) subclasses of BaseFramework.""" return inspect.isclass(o) and issubclass(o, BaseFramework) and not inspect.isabstract(o) def load_module(module_abs_name, main_category): logger.debug("New framework module: {}".format(module_abs_name)) if module_abs_name not in sys.modules: import_module(module_abs_name) else: reload(sys.modules[module_abs_name]) module = sys.modules[module_abs_name] current_category = main_category # if no category found -> we assign to main category for category_name, CategoryClass in inspect.getmembers(module, _is_categoryclass): logger.debug("Found category: {}".format(category_name)) current_category = CategoryClass() # if we didn't register the category: escape the framework registration if current_category not in BaseCategory.categories.values(): return for framework_name, FrameworkClass in inspect.getmembers(module, _is_frameworkclass): if FrameworkClass(current_category) is not None: logger.debug("Attach framework {} to {}".format(framework_name, current_category.name)) def load_frameworks(): """Load all modules and assign to correct category""" main_category = MainCategory() # Prepare local paths (1. environment path, 2. local path, 3. system paths). # If we have duplicated categories, only consider the first loaded one. local_paths = [get_user_frameworks_path()] sys.path.insert(0, get_user_frameworks_path()) environment_path = os.environ.get(UMAKE_FRAMEWORKS_ENVIRON_VARIABLE) if environment_path: sys.path.insert(0, environment_path) local_paths.insert(0, environment_path) for loader, module_name, ispkg in pkgutil.iter_modules(path=local_paths): load_module(module_name, main_category) for loader, module_name, ispkg in pkgutil.iter_modules(path=[os.path.dirname(__file__)]): module_name = "{}.{}".format(__package__, module_name) load_module(module_name, main_category) ubuntu-make-16.02.1/umake/frameworks/swift.py0000664000000000000000000001455012656574623016023 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Swift module""" from contextlib import suppress from gettext import gettext as _ import gnupg import logging import os import re import tempfile import umake.frameworks.baseinstaller from umake.interactions import DisplayMessage from umake.tools import add_env_to_user, as_root, MainLoop, get_current_ubuntu_version from umake.network.download_center import DownloadCenter, DownloadItem from umake.ui import UI logger = logging.getLogger(__name__) class SwiftCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Swift", description=_("Swift language"), logo_path=None) class SwiftLang(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Swift Lang", description=_("Swift compiler (default)"), is_category_default=True, packages_requirements=["clang", "libicu-dev"], category=category, only_on_archs=['amd64'], download_page="https://swift.org/download/", dir_to_decompress_in_tarball="swift*", required_files_path=[os.path.join("usr", "bin", "swift")]) self.asc_url = "https://swift.org/keys/all-keys.asc" def parse_download_link(self, line, in_download): """Parse Swift download link, expect to find a .sig file""" sig_url = None if '.tar.gz.sig' in line: in_download = True if in_download: p = re.search(r'href="(.*)" title="PGP Signature"', line) with suppress(AttributeError): sig_url = "https://swift.org" + p.group(1) logger.debug("Found signature link: {}".format(sig_url)) return (sig_url, in_download) @MainLoop.in_mainloop_thread def get_metadata_and_check_license(self, result): """Download files to download + license and check it""" logger.debug("Parse download metadata") error_msg = result[self.download_page].error if error_msg: logger.error("An error occurred while downloading {}: {}".format(self.download_page, error_msg)) UI.return_main_screen(status_code=1) in_download = False sig_url = None for line in result[self.download_page].buffer: line_content = line.decode() (new_sig_url, in_download) = self.parse_download_link(line_content, in_download) if str(new_sig_url) > str(sig_url): tmp_release = re.search("ubuntu(.....).tar", new_sig_url).group(1) if tmp_release <= get_current_ubuntu_version(): sig_url = new_sig_url if not sig_url: logger.error("Download page changed its syntax or is not parsable") UI.return_main_screen(status_code=1) DownloadCenter(urls=[DownloadItem(sig_url, None), DownloadItem(self.asc_url, None)], on_done=self.check_gpg_and_start_download, download=False) def _check_gpg_signature(self, gnupgdir, asc_content, sig): """check gpg signature (temporary stock in dir)""" gpg = gnupg.GPG(gnupghome=gnupgdir) imported_keys = gpg.import_keys(asc_content) if imported_keys.count == 0: logger.error("Keys not valid") UI.return_main_screen(status_code=1) verify = gpg.verify(sig) if verify is False: logger.error("Signature not valid") UI.return_main_screen(status_code=1) @MainLoop.in_mainloop_thread def check_gpg_and_start_download(self, download_result): asc_content = download_result.pop(self.asc_url).buffer.getvalue().decode('utf-8') sig_url = list(download_result.keys())[0] res = download_result[sig_url] sig = res.buffer.getvalue().decode('utf-8').split()[0] # When we install new packages, we are executing as root and then dropping # as the user for extracting and such. However, for signature verification, # we use gpg. This one doesn't like priviledge drop (if uid = 0 and # euid = 1000) and asserts if uid != euid. # Importing the key as root as well creates new gnupg files owned as root if # new keys weren't imported first. # Consequently, run gpg as root if we needed root access or as the user # otherwise. We store the gpg public key in a temporary gnupg directory that # will be removed under the same user rights (this directory needs to be owned # by the same user id to not be rejected by gpg).Z if self.need_root_access: with as_root(): with tempfile.TemporaryDirectory() as tmpdirname: self._check_gpg_signature(tmpdirname, asc_content, sig) else: with tempfile.TemporaryDirectory() as tmpdirname: self._check_gpg_signature(tmpdirname, asc_content, sig) # you get and store self.download_url url = re.sub('.sig', '', sig_url) if url is None: logger.error("Download page changed its syntax or is not parsable (missing url)") UI.return_main_screen(status_code=1) logger.debug("Found download link for {}".format(url)) self.download_requests.append(DownloadItem(url, None)) self.start_download_and_install() def post_install(self): """Add swift necessary env variables""" add_env_to_user(self.name, {"PATH": {"value": os.path.join(self.install_path, "usr", "bin")}}) UI.delayed_display(DisplayMessage(_("You need to restart your current shell session for your {} installation " "to work properly").format(self.name))) ubuntu-make-16.02.1/umake/frameworks/web.py0000664000000000000000000001354712656574623015451 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2015 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Web module""" from contextlib import suppress from functools import partial from gettext import gettext as _ import logging import os import platform import re import umake.frameworks.baseinstaller from umake.frameworks.ide import VisualStudioCode from umake.interactions import Choice, TextWithChoices from umake.network.download_center import DownloadItem from umake.ui import UI from umake.tools import create_launcher, get_application_desktop_file, MainLoop logger = logging.getLogger(__name__) _supported_archs = ['i386', 'amd64'] class WebCategory(umake.frameworks.BaseCategory): def __init__(self): super().__init__(name="Web", description=_("Web Developer Environment"), logo_path=None) class FirefoxDev(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Firefox Dev", description=_("Firefox Developer Edition"), category=category, only_on_archs=_supported_archs, download_page="https://www.mozilla.org/en-US/firefox/developer/all", dir_to_decompress_in_tarball="firefox", desktop_filename="firefox-developer.desktop", required_files_path=["firefox"]) self.arg_lang = None @MainLoop.in_mainloop_thread def language_select_callback(self, url): url = url.replace("&", "&") logger.debug("Found download link for {}".format(url)) self.download_requests.append(DownloadItem(url, None)) self.start_download_and_install() @MainLoop.in_mainloop_thread def get_metadata_and_check_license(self, result): """Diverge from the baseinstaller implementation in order to allow language selection""" logger.debug("Parse download metadata") error_msg = result[self.download_page].error if error_msg: logger.error("An error occurred while downloading {}: {}".format(self.download_page, error_msg)) UI.return_main_screen(status_code=1) arch = platform.machine() arg_lang_url = None default_label = '' tag_machine = '' if arch == 'x86_64': tag_machine = '64' reg_expression = 'Linux <" in line: in_download = True if in_download: regexp = r'href="(.*)"><.*64-' if get_current_arch() == "i386": regexp = r'href="(.*)"><.*32-' p = re.search(regexp, line) with suppress(AttributeError): url = p.group(1) if '


    ' in line: in_download = False if url is None: return (None, in_download) return ((url, None), in_download) def post_install(self): """Create the Stencyl launcher""" create_launcher(self.desktop_filename, get_application_desktop_file(name=_("Stencyl"), icon_path=os.path.join(self.install_path, "data", "other", "icon-30x30.png"), exec='"{}" %f'.format(self.exec_path), comment=self.description, categories="Development;IDE;", extra="Path={}\nStartupWMClass=stencyl-sw-Launcher".format(self.install_path))) def _chrome_sandbox_setuid(path): """Chown and setUID to chrome sandbox""" # switch to root with as_root(): try: os.chown(path, 0, -1) os.chmod(path, stat.S_ISUID | stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH) logger.debug("Changed setUID mode {}".format(path)) return True except Exception as e: logger.error("Couldn't change owner and file perm to {}: {}".format(path, e)) return False class Unity3D(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Unity3d", description=_("Unity 3D Editor Linux experimental support"), category=category, only_on_archs=['amd64'], download_page="http://forum.unity3d.com/threads/" + "unity-on-linux-release-notes-and-known-issues.350256/", match_last_link=True, checksum_type=ChecksumType.sha1, dir_to_decompress_in_tarball='unity-editor*', desktop_filename="unity3d-editor.desktop", required_files_path=[os.path.join("Editor", "Unity")], # we need root access for chrome sandbox setUID need_root_access=True, # Note that some packages requirements essential to the system itself are not listed (we # don't want to create fake packages and kill the container for medium tests) packages_requirements=["gconf-service", "lib32gcc1", "lib32stdc++6", "libasound2", "libcairo2", "libcap2", "libcups2", "libfontconfig1", "libfreetype6", "libgconf-2-4", "libgdk-pixbuf2.0-0", "libgl1-mesa-glx", "libglu1-mesa", "libgtk2.0-0", "libnspr4", "libnss3", "libpango1.0-0", "libpq5", "libxcomposite1", "libxcursor1", "libxdamage1", "libxext6", "libxfixes3", "libxi6", "libxrandr2", "libxrender1", "libxtst6", "monodevelop"]) # monodevelop is for mono deps, temporary def parse_download_link(self, line, in_download): """Parse Unity3d download links""" url, sha1 = (None, None) if ".sh" in line: in_download = True p = re.search(r'href="(.*.sh)" target', line) with suppress(AttributeError): url = p.group(1) if in_download is True and ')
    ' in line: p = re.search(r'(\w+)\)', line) with suppress(AttributeError): sha1 = p.group(1) return ((url, sha1), in_download) def decompress_and_install(self, fds): """Override to strip the unwanted shell header part""" logger.debug("Start looking at the archive inside the script") for line in fds[0]: if line.startswith(b"__ARCHIVE_BEGINS_HERE__"): logger.debug("Found the archive inside the script") break super().decompress_and_install(fds) def post_install(self): """Create the Unity 3D launcher and setuid chrome sandbox""" with futures.ProcessPoolExecutor(max_workers=1) as executor: # chrome sandbox requires this: https//code.google.com/p/chromium/wiki/LinuxSUIDSandbox f = executor.submit(_chrome_sandbox_setuid, os.path.join(self.install_path, "Editor", "chrome-sandbox")) if not f.result(): UI.return_main_screen(exit_status=1) create_launcher(self.desktop_filename, get_application_desktop_file(name=_("Unity3D Editor"), icon_path=os.path.join(self.install_path, "unity-editor-icon.png"), exec=self.exec_path, comment=self.description, categories="Development;IDE;")) class Twine(umake.frameworks.baseinstaller.BaseInstaller): def __init__(self, category): super().__init__(name="Twine", description=_("Twine tool for creating interactive and nonlinear stories"), category=category, only_on_archs=['i386', 'amd64'], download_page="http://twinery.org/", dir_to_decompress_in_tarball='twine*', desktop_filename="twine.desktop", required_files_path=["Twine"]) # add logo download as the tar doesn't provide one self.download_requests.append(DownloadItem("http://twinery.org/img/logo.svg", None)) def parse_download_link(self, line, in_download): """Parse Twine download links""" url = None regexp = r'href="(.*)" .*linux64' if get_current_arch() == "i386": regexp = r'href="(.*)" .*linux32' p = re.search(regexp, line) with suppress(AttributeError): url = p.group(1) return ((url, None), False) def decompress_and_install(self, fds): # if icon, we grab the icon name to reference it later on for fd in fds: if fd.name.endswith(".svg"): orig_icon_name = os.path.basename(fd.name) break else: logger.error("We couldn't download the Twine icon") UI.return_main_screen(exit_status=1) super().decompress_and_install(fds) # rename the asset logo self.icon_name = "logo.svg" os.rename(os.path.join(self.install_path, orig_icon_name), os.path.join(self.install_path, self.icon_name)) def post_install(self): """Create the Twine launcher""" create_launcher(self.desktop_filename, get_application_desktop_file(name=_("Twine"), icon_path=os.path.join(self.install_path, self.icon_name), exec='"{}" %f'.format(self.exec_path), comment=self.description, categories="Development;IDE;")) ubuntu-make-16.02.1/umake/interactions/0000775000000000000000000000000012656574624014633 5ustar ubuntu-make-16.02.1/umake/interactions/__pycache__/0000755000000000000000000000000012656574625017042 5ustar ubuntu-make-16.02.1/umake/interactions/__init__.py0000664000000000000000000001446512656574623016755 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # module gather different types of interactions with the UI from gettext import gettext as _ import logging from umake.tools import InputError logger = logging.getLogger(__name__) class Choice: def __init__(self, id, label, callback_fn, txt_shorcut=None, is_default=False): """Choice element containing label and callback function""" self.id = id self.label = label self.txt_shorcut = txt_shorcut self.callback_fn = callback_fn self.is_default = is_default class TextWithChoices: def __init__(self, content, choices=[], newline_before_option=False): """Content text with a list of multiple Choice elements""" current_ids = [] default_found = False for choice in choices: if choice.id in current_ids: message = "{} choice id is already in registered ids. Can't instantiate this " \ "interaction".format(choice.id) logger.error(message) raise BaseException(message) current_ids.append(choice.id) if choice.is_default: if default_found: message = "One default was already registered, can't register a second one in that choices set: {}"\ .format([choice.label for choice in choices]) logger.error(message) raise BaseException(message) default_found = True self.content = content self.choices = choices self.newline_before_option = newline_before_option def choose(self, choice_id=None, answer=None): """Return associated callback for choice""" for choice in self.choices: if (choice_id is not None and choice.id == choice_id) or\ (answer is not None and (choice.label.lower() == answer.lower() or (choice.txt_shorcut is not None and choice.txt_shorcut.lower() == answer.lower()))): return choice.callback_fn() msg = _("No suitable answer provided") if choice_id is not None: msg = _("Your entry '{}' isn't an acceptable choice. choices are: {}")\ .format(choice_id, [choice.id for choice in self.choices]) if answer is not None: txt_shortcuts = [choice.txt_shorcut for choice in self.choices if choice.txt_shorcut is not None] if txt_shortcuts: msg = _("Your entry '{}' isn't an acceptable choice. choices are: {} and {}")\ .format(answer, txt_shortcuts, [choice.label for choice in self.choices]) else: msg = _("Your entry '{}' isn't an acceptable choice. choices are: {}")\ .format(answer, [choice.label for choice in self.choices]) if not choice_id and not answer: for choice in self.choices: if choice.is_default: return choice.callback_fn() raise InputError(msg) @property def prompt(self): """Text prompt handling if we do have some shortcuts""" possible_answers = [] for choice in self.choices: answer = choice.label if choice.txt_shorcut: # NOTE: sum of answers answer += _(" ({})").format((choice.txt_shorcut)) possible_answers.append(answer) if self.newline_before_option: # NOTE: first is prompt, newline and then set of answers prompt = _("{}\n[{}] ").format(self.content, '/'.join(possible_answers)) else: # NOTE: first is prompt, then set of answers: prompt = _("{} [{}] ").format(self.content, '/'.join(possible_answers)) return prompt class LicenseAgreement(TextWithChoices): def __init__(self, content, callback_yes, callback_no): """License agreement text with accept/decline""" choices = [Choice(0, _("I Accept"), callback_yes, txt_shorcut=_("a")), Choice(1, _("I don't accept"), callback_no, txt_shorcut=_("N"), is_default=True)] super().__init__(content, choices=choices, newline_before_option=True) @property def input(self): """Text input prompt handling if we do have some shortcuts""" answers = [] for choice in self.choices: # NOTE: first element is choice, and then shortcut _("{} ({})") answer = _("{} ({})").format(choice.label, choice.txt_shorcut) answers.append(answer) # append different possible choices return _("[{}] ").format('/'.join(answers)) class InputText: def __init__(self, content, callback_fn, default_input=""): """Content text with an line input""" self.content = content self._callback_fn = callback_fn self.default_input = default_input def run_callback(self, result): self._callback_fn(result) class YesNo(TextWithChoices): def __init__(self, content, callback_yes, callback_no, default_is_yes=False): """Return a basic Yes No question, default being false or overriden""" super().__init__(content, [Choice(0, _("Yes"), callback_yes, txt_shorcut=_('y'), is_default=default_is_yes), Choice(1, _("No"), callback_no, txt_shorcut=_("N"), is_default=(not default_is_yes))]) class DisplayMessage: def __init__(self, text): self.text = text class UnknownProgress: def __init__(self, iterator): self.bar = None self._iterator = iterator ubuntu-make-16.02.1/umake/__init__.py0000664000000000000000000001123412656574623014242 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import argparse import gettext from gettext import gettext as _ import locale import logging import logging.config import os import sys from umake.frameworks import BaseCategory, load_frameworks from umake.tools import MainLoop from .ui import cli import yaml logger = logging.getLogger(__name__) # if set locale isn't installed, don't load up translations (we don't know what's the locale # user encoding is and python3 will fallback to ANSI_X3.4-1968, which isn't UTF-8 and creates # thus UnicodeEncodeError) try: locale.setlocale(locale.LC_ALL, '') gettext.textdomain("ubuntu-make") except locale.Error: logger.debug("Couldn't load default locale {}, fallback to English".format(locale.LC_ALL)) _default_log_level = logging.WARNING _datadir = None def _setup_logging(env_key='LOG_CFG', level=_default_log_level): """Setup logging configuration Order of preference: - manually define level - env_key env variable if set (logging config file) - fallback to _default_log_level """ path = os.getenv(env_key, '') logging.basicConfig(level=level, format="%(levelname)s: %(message)s") if level == _default_log_level: if os.path.exists(path): with open(path, 'rt') as f: config = yaml.load(f.read()) logging.config.dictConfig(config) logging.info("Logging level set to {}".format(logging.getLevelName(logging.root.getEffectiveLevel()))) def set_logging_from_args(args, parser): """Choose logging ignoring any unknown sys.argv options""" result_verbosity_arg = [] for arg in args: if arg.startswith("-v"): for char in arg: if char not in ['-', 'v']: break else: result_verbosity_arg.append(arg) args = parser.parse_args(result_verbosity_arg) # setup logging level if set by the command line if args.verbose == 1: _setup_logging(level=logging.INFO) elif args.verbose > 1: _setup_logging(level=logging.DEBUG) else: _setup_logging() class _HelpAction(argparse._HelpAction): def __call__(self, parser, namespace, values, option_string=None): parser.print_help() # retrieve subparsers from parser subparsers_actions = [ action for action in parser._actions if isinstance(action, argparse._SubParsersAction)] for subparsers_action in subparsers_actions: # get all subparsers and print help for choice, subparser in subparsers_action.choices.items(): print(_("* Command '{}':").format(choice)) print(subparser.format_help()) parser.exit() def main(): """Main entry point of the program""" if "udtc" in sys.argv[0]: print(_("WARNING: 'udtc' command is the previous name of Ubuntu Make. Please use the 'umake' command from now " "on providing the exact same features. The 'udtc' command will be removed soon.")) parser = argparse.ArgumentParser(description=_("Deploy and setup developers environment easily on ubuntu"), epilog=_("Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile."), add_help=False) parser.add_argument('--help', action=_HelpAction, help=_('Show this help')) # add custom help parser.add_argument("-v", "--verbose", action="count", default=0, help=_("Increase output verbosity (2 levels)")) parser.add_argument('-r', '--remove', action="store_true", help=_("Remove specified framework if installed")) parser.add_argument('--version', action="store_true", help=_("Print version and exit")) # set logging ignoring unknown options set_logging_from_args(sys.argv, parser) mainloop = MainLoop() # load frameworks and initialize parser load_frameworks() cli.main(parser) mainloop.run() ubuntu-make-16.02.1/umake/network/0000775000000000000000000000000012656574624013622 5ustar ubuntu-make-16.02.1/umake/network/download_center.py0000664000000000000000000002326512656574623017352 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Module delivering a DownloadCenter to download in parallel multiple requests""" from collections import namedtuple from concurrent import futures from contextlib import closing import hashlib from io import BytesIO import logging import os import tempfile import requests import requests.exceptions from umake.network.ftp_adapter import FTPAdapter from umake.tools import ChecksumType, root_lock logger = logging.getLogger(__name__) class DownloadItem(namedtuple('DownloadItem', ['url', 'checksum', 'headers', 'ignore_encoding', 'cookies'])): """An individual item to be downloaded and checked. Checksum should be an instance of tools.Checksum, if provided. Headers should be a dictionary of HTTP headers, if provided. Cookies should be a cookie dictionary, if provided.""" def __new__(cls, url, checksum=None, headers=None, ignore_encoding=False, cookies=None): return super().__new__(cls, url, checksum, headers, ignore_encoding, cookies) class DownloadCenter: """Read or download requested urls in separate threads.""" BLOCK_SIZE = 1024 * 8 # from urlretrieve code DownloadResult = namedtuple("DownloadResult", ["buffer", "error", "fd", "final_url", "cookies"]) def __init__(self, urls, on_done, download=True, report=lambda x: None): """Generate a threaded download machine. urls is a list of DownloadItems to download or read from. on_done is the callback that will be called once all those urls are downloaded. report, if not None, will be called once any download is in progress, reporting a dict of current download with current/size parameters The callback will get a dictionary parameter like: { "url": DownloadResult(buffer=page content as bytes if download is set to False. close() will clean it from memory, error=string detailing the error which occurred (path and content would be empty), fd=temporary file descriptor. close() will delete it from disk, final_url=the final url, which may be different from the start if there were redirects, cookies=a dictionary of cookies after the request ) } """ self._done_callback = on_done self._wired_report = report self._download_to_file = download self._urls = urls self._downloaded_content = {} self._download_progress = {} executor = futures.ThreadPoolExecutor(max_workers=len(urls)) for url_request in self._urls: # grab the md5sum if any # switch between inline memory and temp file if download: # Named because shutils and tarfile library needs a .name property # http://bugs.python.org/issue21044 # also, ensure we keep the same suffix path, ext = os.path.splitext(url_request.url) # We want to ensure that we don't create files as root root_lock.acquire() dest = tempfile.NamedTemporaryFile(suffix=ext) root_lock.release() logger.info("Start downloading {} to a temp file".format(url_request)) else: dest = BytesIO() logger.info("Start downloading {} in memory".format(url_request)) future = executor.submit(self._fetch, url_request, dest) future.tag_url = url_request.url future.tag_download = download future.tag_dest = dest future.add_done_callback(self._one_done) def _fetch(self, download_item, dest): """Get an url content and close the connexion. This will write the content to dest and check for md5sum. Return a tuple of (dest, final_url, cookies) """ url = download_item.url checksum = download_item.checksum headers = download_item.headers or {} cookies = download_item.cookies def _report(block_no, block_size, total_size): current_size = int(block_no * block_size) if total_size != -1: current_size = min(current_size, total_size) self._download_progress[url] = {"current": current_size, "size": total_size} logger.debug("Deliver download update: {} of {}".format(self._download_progress, total_size)) self._wired_report(self._download_progress) # Requests support redirection out of the box. # Create a session so we can mount our own FTP adapter. session = requests.Session() session.mount('ftp://', FTPAdapter()) try: with closing(session.get(url, stream=True, headers=headers, cookies=cookies)) as r: r.raise_for_status() content_size = int(r.headers.get('content-length', -1)) # read in chunk and send report updates block_num = 0 _report(block_num, self.BLOCK_SIZE, content_size) for data in r.raw.stream(amt=self.BLOCK_SIZE, decode_content=not download_item.ignore_encoding): dest.write(data) block_num += 1 _report(block_num, self.BLOCK_SIZE, content_size) final_url = r.url cookies = session.cookies except requests.exceptions.InvalidSchema as exc: # Wrap this for a nicer error message. raise BaseException("Protocol not supported.") from exc if checksum and checksum.checksum_value: checksum_type = checksum.checksum_type checksum_value = checksum.checksum_value logger.debug("Checking checksum ({}).".format(checksum_type.name)) dest.seek(0) if checksum_type is ChecksumType.sha1: actual_checksum = self.sha1_for_fd(dest) elif checksum_type is ChecksumType.md5: actual_checksum = self.md5_for_fd(dest) elif checksum_type is ChecksumType.sha256: actual_checksum = self.sha256_for_fd(dest) elif checksum_type is ChecksumType.sha512: actual_checksum = self.sha512_for_fd(dest) else: msg = "Unsupported checksum type: {}.".format(checksum_type) raise BaseException(msg) logger.debug("Expected: {}, actual: {}.".format(checksum_value, actual_checksum)) if checksum_value != actual_checksum: msg = ("The checksum of {} doesn't match. Corrupted download? " "Aborting.").format(url) raise BaseException(msg) return dest, final_url, cookies def _one_done(self, future): """Callback that will be called once the download finishes. (will be wired on the constructor) """ if future.exception(): logger.error("{} couldn't finish download: {}".format(future.tag_url, future.exception())) result = self.DownloadResult(buffer=None, error=str(future.exception()), fd=None, final_url=None, cookies=None) # cleaned unusable temp file as something bad happened future.tag_dest.close() else: logger.info("{} download finished".format(future.tag_url)) fd, final_url, cookies = future.result() fd.seek(0) if future.tag_download: result = self.DownloadResult(buffer=None, error=None, fd=fd, final_url=final_url, cookies=cookies) else: result = self.DownloadResult(buffer=fd, error=None, fd=None, final_url=final_url, cookies=cookies) self._downloaded_content[future.tag_url] = result if len(self._urls) == len(self._downloaded_content): self._done() def _done(self): """Callback that will be called once all download finishes. uris of the temporary files will be passed on the wired callback """ logger.info("All pending downloads for {} done".format(self._urls)) self._done_callback(self._downloaded_content) @classmethod def _checksum_for_fd(cls, algorithm, f, block_size=2 ** 20): checksum = algorithm() while True: data = f.read(block_size) if not data: break checksum.update(data) return checksum.hexdigest() @classmethod def md5_for_fd(cls, f, block_size=2 ** 20): return cls._checksum_for_fd(hashlib.md5, f, block_size) @classmethod def sha1_for_fd(cls, f, block_size=2 ** 20): return cls._checksum_for_fd(hashlib.sha1, f, block_size) @classmethod def sha256_for_fd(cls, f, block_size=2 ** 20): return cls._checksum_for_fd(hashlib.sha256, f, block_size) @classmethod def sha512_for_fd(cls, f, block_size=2 ** 20): return cls._checksum_for_fd(hashlib.sha512, f, block_size) ubuntu-make-16.02.1/umake/network/requirements_handler.py0000664000000000000000000003243512656574623020422 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Didier Roche # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Module delivering a DownloadCenter to download in parallel multiple requests""" import apt import apt.progress import apt.progress.base from collections import namedtuple from concurrent import futures from contextlib import suppress import fcntl import logging import os import tempfile import time from umake.tools import Singleton, add_foreign_arch, get_foreign_archs, get_current_arch, as_root logger = logging.getLogger(__name__) class RequirementsHandler(object, metaclass=Singleton): """Handle platform requirements""" STATUS_DOWNLOADING, STATUS_INSTALLING = range(2) RequirementsResult = namedtuple("RequirementsResult", ["bucket", "error"]) def __init__(self): logger.info("Create a new apt cache") self.cache = apt.Cache() self.executor = futures.ThreadPoolExecutor(max_workers=1) def is_bucket_installed(self, bucket): """Check if the bucket is installed The bucket is a list of packages to check if installed.""" logger.debug("Check if {} is installed".format(bucket)) is_installed = True for pkg_name in bucket: # /!\ danger: if current arch == ':appended_arch', on a non multiarch system, dpkg doesn't # understand that. strip :arch then if ":" in pkg_name: (pkg_without_arch_name, arch) = pkg_name.split(":", -1) if arch == get_current_arch(): pkg_name = pkg_without_arch_name if pkg_name not in self.cache or not self.cache[pkg_name].is_installed: logger.info("{} isn't installed".format(pkg_name)) is_installed = False return is_installed def is_bucket_available(self, bucket): """Check if bucket available on the platform""" all_in_cache = True for pkg_name in bucket: if pkg_name not in self.cache: # this can be also a foo:arch and we don't have added. Tell is may be available if ":" in pkg_name: # /!\ danger: if current arch == ':appended_arch', on a non multiarch system, dpkg doesn't # understand that. strip :arch then (pkg_without_arch_name, arch) = pkg_name.split(":", -1) if arch == get_current_arch() and pkg_without_arch_name in self.cache: # false positive, available continue elif arch not in get_foreign_archs(): # relax the constraint logger.info("{} isn't available on this platform, but {} isn't enabled. So it may be available " "later on".format(pkg_name, arch)) continue logger.info("{} isn't available on this platform".format(pkg_name)) all_in_cache = False return all_in_cache def is_bucket_uptodate(self, bucket): """Check if the bucket is installed and up to date The bucket is a list of packages to check if installed.""" logger.debug("Check if {} is uptodate".format(bucket)) is_installed_and_uptodate = True for pkg_name in bucket: # /!\ danger: if current arch == ':appended_arch', on a non multiarch system, dpkg doesn't # understand that. strip :arch then if ":" in pkg_name: (pkg_without_arch_name, arch) = pkg_name.split(":", -1) if arch == get_current_arch(): pkg_name = pkg_without_arch_name if pkg_name not in self.cache or not self.cache[pkg_name].is_installed: logger.info("{} isn't installed".format(pkg_name)) is_installed_and_uptodate = False elif self.cache[pkg_name].is_upgradable: logger.info("We can update {}".format(pkg_name)) is_installed_and_uptodate = False return is_installed_and_uptodate def install_bucket(self, bucket, progress_callback, installed_callback): """Install a specific bucket. If any other bucket is in progress, queue the request bucket is a list of packages to install. Return a tuple (num packages to install, size packages to download)""" logger.info("Installation {} pending".format(bucket)) bucket_pack = { "bucket": bucket, "progress_callback": progress_callback, "installed_callback": installed_callback } pkg_to_install = not self.is_bucket_uptodate(bucket) future = self.executor.submit(self._really_install_bucket, bucket_pack) future.tag_bucket = bucket_pack future.add_done_callback(self._on_done) return pkg_to_install def _really_install_bucket(self, current_bucket): """Really install current bucket and bind signals""" bucket = current_bucket["bucket"] logger.debug("Starting {} installation".format(bucket)) # exchange file output for apt and dpkg after the fork() call (open it empty) self.apt_fd = tempfile.NamedTemporaryFile(delete=False) self.apt_fd.close() if self.is_bucket_uptodate(bucket): return True need_cache_reload = False for pkg_name in bucket: if ":" in pkg_name: arch = pkg_name.split(":", -1)[-1] need_cache_reload = need_cache_reload or add_foreign_arch(arch) if need_cache_reload: with as_root(): self._force_reload_apt_cache() self.cache.update() self._force_reload_apt_cache() # mark for install and so on for pkg_name in bucket: # /!\ danger: if current arch == ':appended_arch', on a non multiarch system, dpkg doesn't understand that # strip :arch then if ":" in pkg_name: (pkg_without_arch_name, arch) = pkg_name.split(":", -1) if arch == get_current_arch(): pkg_name = pkg_without_arch_name try: pkg = self.cache[pkg_name] if pkg.is_installed and pkg.is_upgradable: logger.debug("Marking {} for upgrade".format(pkg_name)) pkg.mark_upgrade() else: logger.debug("Marking {} for install".format(pkg_name)) pkg.mark_install(auto_fix=False) except Exception as msg: message = "Can't mark for install {}: {}".format(pkg_name, msg) raise BaseException(message) # this can raise on installedArchives() exception if the commit() fails with as_root(): self.cache.commit(fetch_progress=self._FetchProgress(current_bucket, self.STATUS_DOWNLOADING, current_bucket["progress_callback"]), install_progress=self._InstallProgress(current_bucket, self.STATUS_INSTALLING, current_bucket["progress_callback"], self._force_reload_apt_cache, self.apt_fd.name)) return True def _on_done(self, future): """Call future associated bucket done callback""" result = self.RequirementsResult(bucket=future.tag_bucket["bucket"], error=None) if future.exception(): error_message = str(future.exception()) with suppress(FileNotFoundError): with open(self.apt_fd.name) as f: subprocess_content = f.read() if subprocess_content: error_message = "{}\nSubprocess output: {}".format(error_message, subprocess_content) logger.error(error_message) result = result._replace(error=error_message) else: logger.debug("{} installed".format(future.tag_bucket["bucket"])) os.remove(self.apt_fd.name) future.tag_bucket["installed_callback"](result) def _force_reload_apt_cache(self): """Loop on loading apt cache in case something else is updating""" try: self.cache.open() except SystemError: time.sleep(1) self._force_reload_apt_cache() class _FetchProgress(apt.progress.base.AcquireProgress): """Progress handler for downloading a bucket""" def __init__(self, bucket, status, progress_callback,): apt.progress.base.AcquireProgress.__init__(self) self._bucket = bucket self._status = status self._progress_callback = progress_callback def pulse(self, owner): percent = (((self.current_bytes + self.current_items) * 100.0) / float(self.total_bytes + self.total_items)) logger.debug("{} download update: {}% of {}".format(self._bucket['bucket'], percent, self.total_bytes)) report = {"step": self._status, "percentage": percent, "pkg_size_download": self.total_bytes} self._progress_callback(report) class _InstallProgress(apt.progress.base.InstallProgress): """Progress handler for installing a bucket""" def __init__(self, bucket, status, progress_callback, force_load_apt_cache, exchange_filename): apt.progress.base.InstallProgress.__init__(self) self._bucket = bucket self._status = status self._progress_callback = progress_callback self._force_reload_apt_cache = force_load_apt_cache self._exchange_filename = exchange_filename def error(self, pkg, msg): logger.error("{} installation finished with an error: {}".format(self._bucket['bucket'], msg)) self._force_reload_apt_cache() # reload apt cache raise BaseException(msg) def finish_update(self): # warning: this function can be called even if dpkg failed (it raised an exception around commit() # DO NOT CALL directly the callbacks from there. logger.debug("Install for {} ended.".format(self._bucket['bucket'])) self._force_reload_apt_cache() # reload apt cache def status_change(self, pkg, percent, status): logger.debug("{} install update: {}".format(self._bucket['bucket'], percent)) self._progress_callback({"step": self._status, "percentage": percent}) @staticmethod def _redirect_stdin(): # pragma: no cover (in a fork) os.dup2(os.open(os.devnull, os.O_RDWR), 0) def _redirect_output(self): # pragma: no cover (in a fork) fd = os.open(self._exchange_filename, os.O_RDWR) os.dup2(fd, 1) os.dup2(fd, 2) def _fixup_fds(self): # pragma: no cover (in a fork) required_fds = [0, 1, 2, # stdin, stdout, stderr self.writefd, self.write_stream.fileno(), self.statusfd, self.status_stream.fileno() ] # ensure that our required fds close on exec for fd in required_fds[3:]: old_flags = fcntl.fcntl(fd, fcntl.F_GETFD) fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC) # close all fds proc_fd = "/proc/self/fd" if os.path.exists(proc_fd): error_count = 0 for fdname in os.listdir(proc_fd): try: fd = int(fdname) except ValueError: print("ERROR: can not get fd for '%s'" % fdname) if fd in required_fds: continue try: os.close(fd) except OSError as e: # there will be one fd that can not be closed # as its the fd from pythons internal diropen() # so its ok to ignore one close error error_count += 1 if error_count > 1: print("ERROR: os.close(%s): %s" % (fd, e)) def fork(self): pid = os.fork() if pid == 0: # pragma: no cover # be root os.seteuid(0) os.setegid(0) self._fixup_fds() self._redirect_stdin() self._redirect_output() return pid ubuntu-make-16.02.1/umake/network/__pycache__/0000755000000000000000000000000012656574625016031 5ustar ubuntu-make-16.02.1/umake/network/ftp_adapter.py0000664000000000000000000000742112656574623016470 0ustar # -*- coding: utf-8 -*- # Copyright (C) 2014 Canonical # # Authors: # Tin Tvrtković # # This program 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; version 3. # # This program 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 # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA from collections import namedtuple from ftplib import FTP, error_perm from queue import Queue from threading import Thread import urllib.parse from requests import Response from requests.adapters import BaseAdapter import requests.exceptions class FTPAdapter(BaseAdapter): """An FTP adapter for requests. Supports streaming GETs and not much else.""" @staticmethod def get_connection(hostname, timeout=None): return FTP(host=hostname, timeout=timeout, user='anonymous') def send(self, request, stream=False, timeout=None, **kwargs): parsed_url = urllib.parse.urlparse(request.url) file_path = parsed_url.path # Strip the leading slash, if present. if file_path.startswith('/'): file_path = file_path[1:] try: self.conn = self.get_connection(parsed_url.netloc, timeout) except ConnectionRefusedError as exc: # Wrap this in a requests exception. # in requests 2.2.1, ConnectionError does not take keyword args raise requests.exceptions.ConnectionError() from exc resp = Response() resp.url = request.url try: size = self.conn.size(file_path) except error_perm: resp.status_code = 404 return resp if stream: # We have to do this in a background thread, since ftplib's and requests' approaches are the opposite: # ftplib is callback based, and requests needs to expose an iterable. (Push vs pull) # When the queue size is reached, puts will block. This provides some backpressure. queue = Queue(maxsize=100) done_sentinel = object() def handle_transfer(): # Download all the chunks into a queue, then place a sentinel object into it to signal completion. self.conn.retrbinary('RETR ' + file_path, queue.put) queue.put(done_sentinel) Thread(target=handle_transfer).start() def stream(amt=8192, decode_content=False): """A generator, yielding chunks from the queue.""" # We maintain a buffer so the consumer gets exactly the number of bytes requested. buffer = bytearray() while True: data = queue.get() if data is not done_sentinel: buffer.extend(data) if len(buffer) >= amt: result = buffer[:amt] buffer = buffer[amt:] yield result else: if buffer: yield buffer return Raw = namedtuple('raw', 'stream') raw = Raw(stream) resp.status_code = 200 resp.raw = raw resp.headers['content-length'] = size resp.close = lambda: self.conn.close() return resp else: # Not relevant for Ubuntu Make. raise NotImplementedError ubuntu-make-16.02.1/umake/network/__init__.py0000664000000000000000000000000012656574623015720 0ustar ubuntu-make-16.02.1/.travis.yml0000664000000000000000000000152412656574623013141 0ustar language: python sudo: required dist: trusty python: - "3.4" before_install: - sudo add-apt-repository -y ppa:ubuntu-desktop/ubuntu-make - sudo add-apt-repository -y ppa:ubuntu-desktop/ubuntu-make-builddeps - sudo apt-get update # install binary deps - sudo apt-get install -y $(tests/daily_runs/get_binary_depends ubuntu-make) # install tests requirements - sudo tests/daily_runs/install_build_tests_depends install: "" # we don't want to use virtualenv (see below) # as we can't use a system virtualenv anymore in travis CI and that # python-gobject isn't installable in pypy, we have to use system libraries # instead for both uncompiled and compiled modules. # The easiest way without hacking PYTHONPATH, PYTHONHOME is to use the system # python version by prepending it in the PATH. script: PATH="/usr/bin:$PATH" ./runtests pep8 small ubuntu-make-16.02.1/TODO0000664000000000000000000000004412656574623011514 0ustar - shell complete tests in runtests ubuntu-make-16.02.1/po/0000775000000000000000000000000012656574623011444 5ustar ubuntu-make-16.02.1/po/hr.po0000664000000000000000000001656712656574623012434 0ustar # Croatian translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2014-12-09 13:12+0000\n" "Last-Translator: Didier Roche \n" "Language-Team: Croatian \n" "Language: hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* Naredba '{}':" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" #: umake/__init__.py:111 msgid "Show this help" msgstr "Prikaži ovu pomoć" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Android Studio razvojno okruženje" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android Studio" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "Nije ponuđen prikladan odgovor" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "Vaš unos '{}' nije prikladan. Mogući unosi su: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "Vaš unos '{}' nije prikladan. Mogući unosi su: {} i {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr "" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "" #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Prihvaćam" #: umake/interactions/__init__.py:115 msgid "a" msgstr "" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Ne prihvaćam" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "" #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Da" #: umake/interactions/__init__.py:148 msgid "y" msgstr "d" #: umake/interactions/__init__.py:149 msgid "No" msgstr "Ne" ubuntu-make-16.02.1/po/de.po0000664000000000000000000002157512656574623012406 0ustar # German translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-10-27 10:42+0000\n" "Last-Translator: Oliver Jakobi \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "# Ubuntu make Installation von {}\n" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* Befehl '{}':" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "Entwicklerumgebungen einfach auf Ubuntu aufspielen und konfigurieren" #: umake/__init__.py:108 #, fuzzy msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "Beachten Sie, dass ebenfalls das Verhalten verschiedener \"debug logs\" " "konfiguriert werden kann, indem Sie LOG_CFG benutzen, was auf einen \"log " "yaml\"-Profil zeigt." #: umake/__init__.py:111 msgid "Show this help" msgstr "Diese Hilfe anzeigen" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "Erhöhe die Ausführlichkeit der Ausgabe" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "Entferne, falls installiert, das spezifizierte Framework" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "Allgemeine integrierte Entwicklungsumgebungen" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "Pure Eclipse Luna (4.4)" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "Eclipse Luna" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "PyCharm Community Ausgabe" #: umake/frameworks/ide.py:233 #, fuzzy msgid "PyCharm Educational Edition" msgstr "PyCharm Community Ausgabe" #: umake/frameworks/ide.py:249 #, fuzzy msgid "PyCharm Professional Edition" msgstr "PyCharm Community Ausgabe" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "IntelliJ IDEA Community Ausgabe" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "IntelliJ IDEA" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "Dartlang Entwicklungsumgebung" #: umake/frameworks/dart.py:49 #, fuzzy msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "Dart Software Development Kit mit Editor (Standard)" #: umake/frameworks/dart.py:56 #, fuzzy msgid "Dart SDK (default)" msgstr "Dart Software Development Kit mit Editor (Standard)" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 #, fuzzy msgid "Rust language" msgstr "Go Programmiersprache" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 #, fuzzy msgid "Scala compiler and interpreter (default)" msgstr "Google Compiler" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "Go Programmiersprache" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "Google Compiler" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Android Entwicklungsumgebung" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "Android Studio" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Android Studio Entwicklungsumgebung" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android NDK" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "Android NDK" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "{} kann nicht deinstalliert werden, da es nicht installiert ist" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" "Wenn der Name des standard Frameworks nicht gegeben ist, so sollte das " "Zielverzeichnis ein / enthalten" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "Entferne, falls installiert, das Framework" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "Web Entwicklerumgebung" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "Firefox Entwicklerausgabe" #: umake/frameworks/web.py:116 #, fuzzy msgid "Choose language: {}" msgstr "Go Programmiersprache" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "Firefox Aurora mit Entwicklerwerkzeugen" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "Spiele Entwicklungsumgebung" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 #, fuzzy msgid "Unity3D Editor" msgstr "Dart Editor" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "Keine passende Antwort verfügbar" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "Ihre Eingabe '{}' ist nicht erlaubt. Mögliche Eingaben sind: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "Ihre Eingabe '{}' ist nicht erlaubt. Mögliche Eingaben sind {} oder {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Ich akzeptiere" #: umake/interactions/__init__.py:115 msgid "a" msgstr "a" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Ich akzeptiere nicht" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "N" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Ja" #: umake/interactions/__init__.py:148 msgid "y" msgstr "j" #: umake/interactions/__init__.py:149 msgid "No" msgstr "Nein" #~ msgid "Stencyl Game developer environment" #~ msgstr "Stencyl Spiele Entwicklerumgebung" #~ msgid "Dart Editor for the dart language" #~ msgstr "Dart Editor für die dart Programmiersprache" ubuntu-make-16.02.1/po/en_AU.po0000664000000000000000000001647012656574623013003 0ustar # English (Australia) translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2014-12-09 13:09+0000\n" "Last-Translator: destiriser \n" "Language-Team: English (Australia) \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "Deploy and setup developers environment easily on Ubuntu" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" #: umake/__init__.py:111 msgid "Show this help" msgstr "" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "" #: umake/frameworks/android.py:111 msgid "Android SDK" msgstr "" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "Your entry '{}' isn't an acceptable choice. Choices are: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "Your entry '{}' isn't an acceptable choice. Choices are: {} and {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr "" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "" #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "I accept" #: umake/interactions/__init__.py:115 msgid "a" msgstr "" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "" #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "" #: umake/interactions/__init__.py:148 msgid "y" msgstr "" #: umake/interactions/__init__.py:149 msgid "No" msgstr "" ubuntu-make-16.02.1/po/zh_CN.po0000664000000000000000000001747612656574623013024 0ustar # Chinese (Simplified) translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2014-12-09 13:12+0000\n" "Last-Translator: Didier Roche \n" "Language-Team: Chinese (Simplified) \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* 命令 '{}':" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "在 Ubuntu 上轻松部署和设置开发环境" #: umake/__init__.py:108 #, fuzzy msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "请注意,您还可以通过 LOG_CFG 指向的 yaml 配置文件来设置不同的调试日志行为。" #: umake/__init__.py:111 msgid "Show this help" msgstr "显示本帮助" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "提升输出的级别 (2级)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "如已安装指定框架,请卸载" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Android 开发环境" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Android Studio 开发者环境" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android Studio" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "未安装,无法移除{}" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "如未提供默认框架名称,输出目录应包含斜杠 /" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "如已安装框架,请卸载" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "未提供合适的答案" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "您的输入 '{}' 不是一个可以接受的选择。选项有:{}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "您的输入 '{}' 不是一个可以接受的选择。选项有:{} 和 {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "我接受" #: umake/interactions/__init__.py:115 msgid "a" msgstr "a" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "我不接受" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "N" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "是" #: umake/interactions/__init__.py:148 msgid "y" msgstr "y" #: umake/interactions/__init__.py:149 msgid "No" msgstr "否" ubuntu-make-16.02.1/po/el.po0000664000000000000000000002407012656574623012407 0ustar # Greek translation for ubuntu-make # Copyright (c) 2015 Rosetta Contributors and Canonical Ltd 2015 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2015. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-05-03 22:41+0000\n" "Last-Translator: stratosg \n" "Language-Team: Greek \n" "Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-05-04 07:08+0000\n" "X-Generator: Launchpad (build 17474)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "# Το Ubuntu εγκαθιστά το {}\n" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* Εντολή '{}':" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "" "Αναπτύξτε και ρυθμίστε το προγραμματιστικό περιβάλλον εύκολα στο ubuntu" #: umake/__init__.py:108 #, fuzzy msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "Σημειώστε πως μπορείτε επίσης να ρυθμίστε διαφορετικές συμπεριφορές " "καταγραφών απασφαλμάτωσης χρησιμοποιώντας LOG_CFG δείχνοντας σε ένα log yaml " "προφίλ" #: umake/__init__.py:111 msgid "Show this help" msgstr "Εμφάνιση αυτής της βοήθειας" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "Αυξήστε τη λεκτική λεπτομέρεια εξόδου (2 επίπεδα)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "Αφαίρεση συγκεκριμένου πλάισιου αν έχει εγκατασταθεί" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "Γενικά IDE" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "PyCharm Έκδοση Κοινότητας" #: umake/frameworks/ide.py:233 #, fuzzy msgid "PyCharm Educational Edition" msgstr "PyCharm Έκδοση Κοινότητας" #: umake/frameworks/ide.py:249 #, fuzzy msgid "PyCharm Professional Edition" msgstr "PyCharm Έκδοση Κοινότητας" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "IntelliJ IDEA Έκδοση Κοινότητας" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "IntelliJ IDEA" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 #, fuzzy msgid "PHP and web development IDE" msgstr "IDE προγραμματιστή παιχνιδιών Stencyl" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 #, fuzzy msgid "You need to logout and login again for your installation to work" msgstr "" "Πρέπει να επανεκκινήσεις μια συνεδρία κελύφους για να δουλέψει η εγκατάστασή " "σου" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "Dartlang Περιβάλλον Ανάπτυξης" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 #, fuzzy msgid "Dart SDK (default)" msgstr "Android Στούντιο (προεπιλεγμένο)" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 #, fuzzy msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" "Πρέπει να επανεκκινήσεις μια συνεδρία κελύφους για να δουλέψει η εγκατάστασή " "σου" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 #, fuzzy msgid "Scala compiler and interpreter (default)" msgstr "Google μεταγλωττιστής (προεπιλεγμένος)" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "Google μεταγλωττιστής (προεπιλεγμένος)" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Android Περιβάλλον Ανάπτυξης" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "Android Στούντιο (προεπιλεγμένο)" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Στούντιο" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Περιβάλλον προγραμματιστή Android Στούντιο" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android NDK" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "Android NDK" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "Δεν μπορείς να αφαιρέσει {} ενώ δεν είναι εγκατεστημένο" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" "Εάν το προεπιλεγμένο όνομα πλαισίου δεν παρέχεται, το destdir πρέπει να " "περιέχει ένα /" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "Αφαιρέστε το πλάισιο αν είναι εγκατεστημένο" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "Περιβάλλον Ανάπτυξης Ιστού" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "Firefox Έκδοση Προγραμματιστή" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "Firefox Aurora με εργαλεία Προγραμματιστή" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "Περιβάλλον Ανάπτυξης Παιχνιδιών" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "IDE προγραμματιστή παιχνιδιών Stencyl" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "Δεν παρέχεται καμία καμία κατάλληλη απάντηση" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "" "Η καταχώρισή σας '{}' δεν ειναι μια αποδεκτή επιλογή. οι επιλογές είναι: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "" "Η καταχώρισή σας '{}' δεν είναι μια αποδεκτή επιλογή. οι επιλογές είναι: {} " "και {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Αποδέχομαι" #: umake/interactions/__init__.py:115 msgid "a" msgstr "α" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Δεν αποδέχομαι" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Ναι" #: umake/interactions/__init__.py:148 msgid "y" msgstr "" #: umake/interactions/__init__.py:149 msgid "No" msgstr "Όχι" #~ msgid "Stencyl Game developer environment" #~ msgstr "Περιβάλλον προγραμματιστή Παιχνιδιών Stencyl" ubuntu-make-16.02.1/po/zh_HK.po0000664000000000000000000001656312656574623013022 0ustar # Chinese (Hong Kong) translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2014-12-09 13:12+0000\n" "Last-Translator: Anthony Wong \n" "Language-Team: Chinese (Hong Kong) \n" "Language: zh_HK\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* 命令 '{}':" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "在 Ubuntu 上輕鬆部署和配置開發環境" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" #: umake/__init__.py:111 msgid "Show this help" msgstr "顯示此求助說明" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "提升輸出詳細級別 (2級)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Android 開發環境" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Android Studio 開發環境" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android Studio" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "未提供合適答案" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr "" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "" #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "接受" #: umake/interactions/__init__.py:115 msgid "a" msgstr "" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "不接受" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "" #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "" #: umake/interactions/__init__.py:148 msgid "y" msgstr "" #: umake/interactions/__init__.py:149 msgid "No" msgstr "" ubuntu-make-16.02.1/po/fa.po0000664000000000000000000001723712656574623012404 0ustar # Persian translation for ubuntu-make # Copyright (c) 2015 Rosetta Contributors and Canonical Ltd 2015 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2015. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-07-23 05:28+0000\n" "Last-Translator: Arash Badie Modiri \n" "Language-Team: Persian \n" "Language: fa\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" #: umake/__init__.py:111 msgid "Show this help" msgstr "این راهنما را نشان بده" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 #, fuzzy msgid "Rust language" msgstr "زبان Go" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "زبان Go" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "محیط توسعه Android" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "" #: umake/frameworks/android.py:111 msgid "Android SDK" msgstr "" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "نمی‌توانید «{}» را پاک کنید چون اصلا نصب نشده" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "محیط توسعه وب" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "نسخه‌ی توسعه‌دهنده Firefox" #: umake/frameworks/web.py:116 #, fuzzy msgid "Choose language: {}" msgstr "زبان Go" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "نسخه‌ی Aurora مرورگر Firefox به همراه ابزار توسعه" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "محیط توسعه‌ی بازی" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "پاسخ مناسبی داده نشد" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "«{}» ورودی قابل قبولی نیست. انتخاب‌ها «{}» و «{}»اند" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr "" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "" #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "قبول می‌کنم" #: umake/interactions/__init__.py:115 msgid "a" msgstr "" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "قبول نمی‌کنم" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "" #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "بلی" #: umake/interactions/__init__.py:148 msgid "y" msgstr "" #: umake/interactions/__init__.py:149 msgid "No" msgstr "خیر" ubuntu-make-16.02.1/po/zh_TW.po0000664000000000000000000002204112656574623013036 0ustar # Chinese (Traditional) translation for ubuntu-make # Copyright (c) 2015 Rosetta Contributors and Canonical Ltd 2015 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2015. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-05-03 05:28+0000\n" "Last-Translator: V字龍(Vdragon) \n" "Language-Team: Chinese (Traditional) \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-05-04 07:08+0000\n" "X-Generator: Launchpad (build 17474)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "# {} 的 Ubuntu make 安裝\n" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* 命令「{}」:" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "在 Ubuntu 上輕易地佈署與安裝開發環境" #: umake/__init__.py:108 #, fuzzy msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "注意您也可以使用 LOG_CFG 環境變數指向一個 YAML 格式除錯紀錄設定檔來設定不同的" "除錯紀錄行為。" #: umake/__init__.py:111 msgid "Show this help" msgstr "顯示此幫助訊息" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "增加輸出訊息的冗長程度(最多可提高 2 級)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "如果已被安裝的話移除指定的軟體框架" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "一般整合式開發環境" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "純粹的 Eclipse Luna (4.4) 整合式開發環境" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "Eclipse Luna 整合式開發環境" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "Eclipse Luna 整合式開發環境" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "PyCharm 社群版本" #: umake/frameworks/ide.py:233 #, fuzzy msgid "PyCharm Educational Edition" msgstr "PyCharm 社群版本" #: umake/frameworks/ide.py:249 #, fuzzy msgid "PyCharm Professional Edition" msgstr "PyCharm 社群版本" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "IntelliJ IDEA 社群版本" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "IntelliJ IDEA" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 #, fuzzy msgid "PHP and web development IDE" msgstr "Stencyl 遊戲開發者整合式開發環境" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 #, fuzzy msgid "You need to logout and login again for your installation to work" msgstr "您必須重新啟動殼程式(shell)工作階段您的安裝才會生效" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "Dartlang 開發環境" #: umake/frameworks/dart.py:49 #, fuzzy msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "Dart 軟體開發工具(SDK)與編輯器(預設)" #: umake/frameworks/dart.py:56 #, fuzzy msgid "Dart SDK (default)" msgstr "Dart 軟體開發工具(SDK)與編輯器(預設)" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 #, fuzzy msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "您必須重新啟動殼程式(shell)工作階段您的安裝才會生效" #: umake/frameworks/rust.py:43 #, fuzzy msgid "Rust language" msgstr "Go 程式語言" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 #, fuzzy msgid "Scala compiler and interpreter (default)" msgstr "Google 編譯器(預設)" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "Go 程式語言" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "Google 編譯器(預設)" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Android 開發環境" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "Android Studio(預設)" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Android Studio 軟體開發環境" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android NDK" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "Android NDK" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "您不能移除 {} 因為它沒有被安裝" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "如果軟體框架已經被安裝的話移除它" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "Web 開發環境" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "Firefox 開發版" #: umake/frameworks/web.py:116 #, fuzzy msgid "Choose language: {}" msgstr "Go 程式語言" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "內建開發工具的 Firefox Aurora" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "遊戲開發環境" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "Stencyl 遊戲開發者整合式開發環境" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 #, fuzzy msgid "Unity3D Editor" msgstr "Dart 編輯器" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "沒有得到適當的答案" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "您的「{}」輸入並不是個可接受的選項。可用選項有:{}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "您的「{}」輸入並不是個可接受的選項。可用選項有:{} 與 {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "我接受" #: umake/interactions/__init__.py:115 msgid "a" msgstr "a" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "我不接受" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "N" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "是" #: umake/interactions/__init__.py:148 msgid "y" msgstr "y" #: umake/interactions/__init__.py:149 msgid "No" msgstr "否" #~ msgid "Stencyl Game developer environment" #~ msgstr "Stencyl 遊戲開發環境" #~ msgid "Dart Editor for the dart language" #~ msgstr "用於 Dart 語言的 Dart 編輯器" ubuntu-make-16.02.1/po/pl.po0000664000000000000000000002167712656574623012434 0ustar # Polish translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-10-22 17:29+0000\n" "Last-Translator: Bartek Budzyński \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "# Instalacja {} przez Ubuntu make\n" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* Komenda '{}':" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "Łatwo wdróż i skonfiguruj środowisko programistyczne na Ubuntu" #: umake/__init__.py:108 #, fuzzy msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "Możesz również skonfigurować różne zachowania debug logów używając LOG_CFG " "wskazujących na profile logów yaml." #: umake/__init__.py:111 msgid "Show this help" msgstr "Wyświetla tę pomoc" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "Zwiększ dokładność wyniku (2 stopnie)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "Usuń wskazany framework, jeśli jest zainstalowany" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "generalne zintegrowane środowiska programistyczne" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "Zintegrowane środowisko programistyczne Eclipse Luna" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 #, fuzzy msgid "PHP and web development IDE" msgstr "" "deweloperskie zintegrowane środowisko programistyczne gier komputerowych - " "Stencyl" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 #, fuzzy msgid "You need to logout and login again for your installation to work" msgstr "" "Musisz ponownie uruchomić sesję powłoki do poprawnego działania instalacji" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 #, fuzzy msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "Dart SDK z edytorem" #: umake/frameworks/dart.py:56 #, fuzzy msgid "Dart SDK (default)" msgstr "Dart SDK z edytorem" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 #, fuzzy msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" "Musisz ponownie uruchomić sesję powłoki do poprawnego działania instalacji" #: umake/frameworks/rust.py:43 #, fuzzy msgid "Rust language" msgstr "Język Go" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 #, fuzzy msgid "Scala compiler and interpreter (default)" msgstr "Kompilator Google (domyślnie)" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "Język Go" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "Kompilator Google (domyślnie)" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Środowisko Programistyczne Android" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "Android Studio (domyślnie)" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "środowisko programistyczne Android Studio" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android NDK" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "Android NDK" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "Nie możesz usunąć {}, ponieważ nie jest zainstalowane" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" "Jeśli nazwa domyślnego frameworka nie jest określona, destdir powinien " "zawierać a /" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "Usuń framework, jeśli jest zainstalowany" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "Internetowe środowisko deweloperskie" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "Deweloperska Edycja Firefox" #: umake/frameworks/web.py:116 #, fuzzy msgid "Choose language: {}" msgstr "Język Go" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "Firefox Aurora z narzędziami deweloperskimi" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "Środowiska Deweloperskie Gier Komputerowych" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" "deweloperskie zintegrowane środowisko programistyczne gier komputerowych - " "Stencyl" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 #, fuzzy msgid "Unity3D Editor" msgstr "Edytor Dart" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "Nie podano właściwej odpowiedzi" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "Twój wybór '{}' nie jest dopuszczalny. Możliwe wybory to: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "Twój wybór '{}' nie jest dopuszczalny. Możliwe wybory to: {} i {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Zgadzam się" #: umake/interactions/__init__.py:115 msgid "a" msgstr "a" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Nie zgadzam się" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "N" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Tak" #: umake/interactions/__init__.py:148 msgid "y" msgstr "T" #: umake/interactions/__init__.py:149 msgid "No" msgstr "Nie" #~ msgid "Stencyl Game developer environment" #~ msgstr "środowisko deweloperskie gier komputerowych - Stencyl" ubuntu-make-16.02.1/po/eu.po0000664000000000000000000001644712656574623012431 0ustar # Basque translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2014-12-09 13:12+0000\n" "Last-Translator: Didier Roche \n" "Language-Team: Basque \n" "Language: eu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" #: umake/__init__.py:111 msgid "Show this help" msgstr "Erakutsi laguntza hau" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Androiderako garapen-ingurunea" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Android Studio garapen-ingurunea" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android Studio" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Onartzen dut" #: umake/interactions/__init__.py:115 msgid "a" msgstr "o" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Ez dut onartzen" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "E" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Bai" #: umake/interactions/__init__.py:148 msgid "y" msgstr "b" #: umake/interactions/__init__.py:149 msgid "No" msgstr "Ez" ubuntu-make-16.02.1/po/es.po0000664000000000000000000002217712656574623012424 0ustar # Spanish translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-02-13 11:11+0000\n" "Last-Translator: Adolfo Jayme \n" "Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-04-02 06:32+0000\n" "X-Generator: Launchpad (build 17413)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "# Instalación de {} con Ubuntu make\n" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* Orden «{}»:" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "Instalar y configurar entornos de desarrollo fácilmente en Ubuntu" #: umake/__init__.py:108 #, fuzzy msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "También puede configurar distintos comportamientos para los registros de " "depuración usando LOG_CFG apuntando a un perfil yaml." #: umake/__init__.py:111 msgid "Show this help" msgstr "Muestra esta ayuda" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "Aumentar detalles en la salida (2 niveles)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "Eliminar el marco especificado si está instalado" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "EID genéricos" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "Pure Eclipse Luna (4.4)" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "El entorno integrado de desarrollo Eclipse Luna" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "Eclipse Luna" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:233 #, fuzzy msgid "PyCharm Educational Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:249 #, fuzzy msgid "PyCharm Professional Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "IntelliJ IDEA Community Edition" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "IntelliJ IDEA" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 #, fuzzy msgid "PHP and web development IDE" msgstr "EID de desarrollo de juegos Stencyl" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 #, fuzzy msgid "You need to logout and login again for your installation to work" msgstr "" "Es necesario reiniciar la sesión de la consola para que la instalación entre " "en funcionamiento" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "Entorno de desarrollo Dartlang" #: umake/frameworks/dart.py:49 #, fuzzy msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "SDK de Dart con editor (predeterminado)" #: umake/frameworks/dart.py:56 #, fuzzy msgid "Dart SDK (default)" msgstr "SDK de Dart con editor (predeterminado)" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 #, fuzzy msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" "Es necesario reiniciar la sesión de la consola para que la instalación entre " "en funcionamiento" #: umake/frameworks/rust.py:43 #, fuzzy msgid "Rust language" msgstr "Lenguaje Go" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 #, fuzzy msgid "Scala compiler and interpreter (default)" msgstr "Compilador de Google (predeterminado)" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "Lenguaje Go" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "Compilador de Google (predeterminado)" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Entorno de desarrollo de Android" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "Android Studio (predeterminado)" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Entorno de desarrollo Android Studio" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android NDK" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "Android NDK" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "No se puede desinstalar {} ya que no está instalado" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" "Si no se especifica el nombre del marco predeterminado, destdir debe " "contener una /" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "Eliminar marco si está instalado" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "Entorno de desarrollo web" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "Firefox Developer Edition" #: umake/frameworks/web.py:116 #, fuzzy msgid "Choose language: {}" msgstr "Lenguaje Go" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "Firefox Aurora con herramientas de desarrollo" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "Entorno de desarrollo de juegos" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "EID de desarrollo de juegos Stencyl" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 #, fuzzy msgid "Unity3D Editor" msgstr "Editor de Dart" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "No se ha provisto una respuesta adecuada" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "Su entrada «{}» no es una opción aceptable. Las opciones son: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "Su entrada «{}» no es una opción aceptable. Las opciones son: {} y {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Acepto" #: umake/interactions/__init__.py:115 msgid "a" msgstr "a" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "No acepto" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "N" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Sí" #: umake/interactions/__init__.py:148 msgid "y" msgstr "s" #: umake/interactions/__init__.py:149 msgid "No" msgstr "No" #~ msgid "Stencyl Game developer environment" #~ msgstr "Entorno de desarrollo de juegos Stencyl" #~ msgid "Dart Editor for the dart language" #~ msgstr "Editor Dart para el lenguaje Dart" ubuntu-make-16.02.1/po/pt_BR.po0000664000000000000000000002225112656574623013014 0ustar # Brazilian Portuguese translation for ubuntu-make # Copyright (c) 2015 Rosetta Contributors and Canonical Ltd 2015 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2015. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-07-13 13:02+0000\n" "Last-Translator: Renato Cruz \n" "Language-Team: Brazilian Portuguese \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "# Ubuntu make instalação de {}\n" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* Comando '{}':" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "" "Instala e configura de maneira fácil um ambiente de programação no Ubuntu" #: umake/__init__.py:108 #, fuzzy msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "Note que você também pode configurar diferentes comportamentos para os logs " "de depuração usando LOG_CFG e apontando o log para o arquivo yaml." #: umake/__init__.py:111 msgid "Show this help" msgstr "Mostrar essa ajuda" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "Aumenta a verbosidade da saída (2 níveis)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "Remove um determinado framework se estiver instalado" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "IDEs genéricas" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "Eclipse Luna (4.4) puro" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "Ambiente de Desenvolvimento Integrado Eclipse Luna" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "Eclipse Luna" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:233 #, fuzzy msgid "PyCharm Educational Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:249 #, fuzzy msgid "PyCharm Professional Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "IntelliJ IDEA Community Edition" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "IntelliJ IDEA" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 #, fuzzy msgid "PHP and web development IDE" msgstr "IDE Stencyl para desenvolvimento de jogos" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 #, fuzzy msgid "You need to logout and login again for your installation to work" msgstr "Você precisa reiniciar a sessão shell para que sua instalação funcione" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "Ambiente de desenvolvimento Dartlang" #: umake/frameworks/dart.py:49 #, fuzzy msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "Dart SDK com editor (padrão)" #: umake/frameworks/dart.py:56 #, fuzzy msgid "Dart SDK (default)" msgstr "Dart SDK com editor (padrão)" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 #, fuzzy msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "Você precisa reiniciar a sessão shell para que sua instalação funcione" #: umake/frameworks/rust.py:43 #, fuzzy msgid "Rust language" msgstr "Linguagem Go" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 #, fuzzy msgid "Scala compiler and interpreter (default)" msgstr "Compilador Google (padrão)" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "Linguagem Go" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "Compilador Google (padrão)" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Ambiente de desenvolvimento Android" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "Android Studio (padrão)" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Ambiente de desenvolvimento Android Studio" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android NDK" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "Android NDK" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "Você não pode remover {} porque ele não está instalado" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" "Se o nome padrão do framework não for fornecido, o diretório de destino deve " "conter uma /" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "Remove o framework se estiver instalado" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "Ambiente para desenvolvimento Web" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "Firefox Developer Edition" #: umake/frameworks/web.py:116 #, fuzzy msgid "Choose language: {}" msgstr "Linguagem Go" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "Firefox Aurora com ferramentas para desenvolvedores" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "Ambiente para desenvolvimento de jogos" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "IDE Stencyl para desenvolvimento de jogos" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 #, fuzzy msgid "Unity3D Editor" msgstr "Editor Dart" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "Não há resposta adequada" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "A sua entrada '{}' não é uma opção aceitável, as opções são: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "A sua entrada '{}' não é uma opção aceitável, as opções são: {} e {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{}[{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Eu aceito" #: umake/interactions/__init__.py:115 msgid "a" msgstr "um(a)" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Eu não aceito" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "N" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{}({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Sim" #: umake/interactions/__init__.py:148 msgid "y" msgstr "s" #: umake/interactions/__init__.py:149 msgid "No" msgstr "Não" #~ msgid "Stencyl Game developer environment" #~ msgstr "Ambiente para desenvolvimento de jogos Stencyl" #~ msgid "Dart Editor for the dart language" #~ msgstr "Editor Dart para a linguagem dart" ubuntu-make-16.02.1/po/tr.po0000664000000000000000000001625412656574623012441 0ustar # Turkish translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-04-24 08:17+0000\n" "Last-Translator: Julian \n" "Language-Team: Turkish \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-05-04 07:08+0000\n" "X-Generator: Launchpad (build 17474)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" #: umake/__init__.py:111 msgid "Show this help" msgstr "Bu yardımı göster" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "Eclipse Luna" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "" #: umake/frameworks/android.py:111 msgid "Android SDK" msgstr "" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr "" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "" #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Kabul ediyorum" #: umake/interactions/__init__.py:115 msgid "a" msgstr "" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Kabul etmiyorum" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "" #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Evet" #: umake/interactions/__init__.py:148 msgid "y" msgstr "" #: umake/interactions/__init__.py:149 msgid "No" msgstr "" ubuntu-make-16.02.1/po/te.po0000664000000000000000000002166712656574623012430 0ustar # Telugu translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2014-12-09 13:12+0000\n" "Last-Translator: Didier Roche \n" "Language-Team: Telugu \n" "Language: te\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "# {} యొక్క Ubuntu make ఇన్స్టాలేషన్\n" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* ఆదేశం '{}':" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "సులభంగా డెవలపర్ల ఎన్విరాన్‌మెంట్‌ని సెటప్ చెయ్యి" #: umake/__init__.py:108 #, fuzzy msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "LOG_CFG ని ఏదైనా ఒక yaml ప్రొఫైల్‌ని సూచించేటట్టు చేయడం ద్వారా డీబగ్గింగ్ లాగ్‌ల పని విధానాన్ని మార్చవచ్చు" #: umake/__init__.py:111 msgid "Show this help" msgstr "ఈ సహాయాన్ని చూపించు" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "ఎక్కువ సమాచారాన్ని చూపించు (రెండు రెట్లు)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "ఫ్రేమ్‌వర్క్ ఇన్స్టాల్ అయి వుంటే తొలగించండి" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "ఆండ్రాయిడ్ డెవలెప్‌మెంట్ ఎన్విరాన్‌మెంట్" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "ఆండ్రాయిడ్ స్ట్యూయో" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "ఆండ్రాయిడ్ స్తూడియో డెవలపర్ ఎన్విరాన్‌మెంట్" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "ఆండ్రాయిడ్ స్ట్యూయో" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "{} ఇన్స్టాల్ అయి లేదు కాబట్టి దానిని తొలగించలేము" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "ఫ్రేమ్‌వర్క్ ఇన్స్టాల్ అయి వుంటే దానిని తొలగించు" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "తగిన సమాధానం ఇవ్వలేదు" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "మీ ఎంపిక '{}' తగినది కాదు. సరియైన ఎంపికలు: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "మీ ఎంపిక '{}' తగినది కాదు. సరియైన ఎంపికలు: {} మరియు {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "నాకు అంగీకారమే" #: umake/interactions/__init__.py:115 msgid "a" msgstr "a" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "నేను అంగీకరించను" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "N" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "అవును" #: umake/interactions/__init__.py:148 msgid "y" msgstr "అవును" #: umake/interactions/__init__.py:149 msgid "No" msgstr "కాదు" ubuntu-make-16.02.1/po/en_GB.po0000664000000000000000000001650212656574623012762 0ustar # English (United Kingdom) translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2014-12-09 13:09+0000\n" "Last-Translator: destiriser \n" "Language-Team: English (United Kingdom) \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "Deploy and setup developers environment easily on Ubuntu" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" #: umake/__init__.py:111 msgid "Show this help" msgstr "" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "" #: umake/frameworks/android.py:111 msgid "Android SDK" msgstr "" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "Your entry '{}' isn't an acceptable choice. Choices are: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "Your entry '{}' isn't an acceptable choice. Choices are: {} and {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr "" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "" #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "I accept" #: umake/interactions/__init__.py:115 msgid "a" msgstr "" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "" #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "" #: umake/interactions/__init__.py:148 msgid "y" msgstr "" #: umake/interactions/__init__.py:149 msgid "No" msgstr "" ubuntu-make-16.02.1/po/ubuntu-make.pot0000664000000000000000000001575612656574623014443 0ustar # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" #: umake/__init__.py:111 msgid "Show this help" msgstr "" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "" #: umake/frameworks/android.py:111 msgid "Android SDK" msgstr "" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr "" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "" #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "" #: umake/interactions/__init__.py:115 msgid "a" msgstr "" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "" #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "" #: umake/interactions/__init__.py:148 msgid "y" msgstr "" #: umake/interactions/__init__.py:149 msgid "No" msgstr "" ubuntu-make-16.02.1/po/ru.po0000664000000000000000000002666212656574623012446 0ustar # Russian translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-11-17 21:34+0300\n" "Last-Translator: Eldar Khayrullin \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Poedit 1.7.7\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "# Ubuntu make установка {}\n" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* Команда '{}':" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "Легкое развертывание и установка среды разработчика на ubuntu" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "Обратите внимание, что вы также можете настроить различное поведение ведения " "журнала отладки используя LOG_CFG, который указывает на профиль журнала yaml." #: umake/__init__.py:111 msgid "Show this help" msgstr "Показать эту справку" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "Увеличить многословность выхода (2 уровня)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "Удалить указанную среду, если она установлена" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "Напечатать версию и выйти" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "Общие интегрированные среды разработки" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "Чистый Eclipse Luna (4.4)" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "Интегрированная среда разработки Eclipse Luna" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "Eclipse Luna" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "PyCharm Общественная версия" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "PyCharm Учебная версия" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "PyCharm Профессиональная версия" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "IntelliJ IDEA Общественная версия" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "IntelliJ IDEA" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "Ruby в интегрированной среде разработки Rails" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" "Полная клиентская и серверная интегрированная среда разработки javascript" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "Интегрированная среда разработки PHP и веб" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "Интегрированная среда разработки CLion языка C/C++" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "Распространение ПО Arduino" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "Интегрированная среда разработки ПО Arduino" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "Arduino" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "Вам нужно завершить сеанс и войти снова для установки к работе" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "Интегрированная среда разработки Netbeans" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "Среда разработки Dartlang" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" "Комплект средств разработки Dart с редактором (больше не поддерживается)" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "Комплект средств разработки Dart" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" "Вам нужно перезапустить вашу текущую сессию оболочки для установки {} к " "работе правильно" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "Язык Rust" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "Официальная поставка Rust" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "Язык программирования Scala" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "Компилятор и интерпретатор Scala (по умолчанию)" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "Язык Go" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "Компилятор Google (по умолчанию)" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Среда разработки Android" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "Android Studio (по умолчанию)" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Среда разработки Android Studio" #: umake/frameworks/android.py:111 msgid "Android SDK" msgstr "Комплект средств разработки Android" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "Родной комплект разработки Android" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "Среда по умолчанию для категории {} была запрошена там где ее нет" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "Вы не можете установить эту среду на этой машине" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "Вы не можете удалить {}, поскольку он не установлен" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" "Если имя среды по умолчанию не предусмотрено, директория назначения должна " "содержать /" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "Удалить среду, если установлена" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "Принять лицензию без запроса" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "Веб среда разработки" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "Firefox Версия разработчика" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "Выбрать язык: {}" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "Firefox Aurora с инструментами разработчика" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "Установить в данном языке без запроса" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" "Visual Studio фокусируется на разработке современных веб и облачных " "приложений" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "Visual Studio Code" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "Окружение разработки игр" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "Интегрированная среда разработки разработчика игр Stencyl" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "Unity 3D Editor Linux экспериментальная поддержка" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "Редактор Unity3D" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "Инструмент для создания интерактивных и нелинейных историй Twine" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "Twine" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "Не указано приемлемого ответа" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "Ваш запись '{}' не является приемлемым выбором. возможные варианты: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "" "Ваш запись '{}' не является приемлемым выбором. возможные варианты: {} и {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Я принимаю" #: umake/interactions/__init__.py:115 msgid "a" msgstr "п" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Я не принимаю" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "Н" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Да" #: umake/interactions/__init__.py:148 msgid "y" msgstr "д" #: umake/interactions/__init__.py:149 msgid "No" msgstr "Нет" ubuntu-make-16.02.1/po/fr.po0000664000000000000000000002313112656574623012413 0ustar # French translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-11-23 15:36+0000\n" "Last-Translator: Didier Roche \n" "Language-Team: French \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-24 07:00+0000\n" "X-Generator: Launchpad (build 17850)\n" "Language: fr\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "# Ajouté par Ubuntu make de {}\n" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* Commande '{}':" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "" "Installez et déployez un environnement de développement facilement sur ubuntu" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "Il est également possible de configurer différents comportements et niveaux " "de logs en faisant pointer la variable d'environnement LOG_CFG vers un " "fichier de profile de log yaml." #: umake/__init__.py:111 msgid "Show this help" msgstr "Afficher cette aide" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "Augmenter la verbosité de la sortie (2 niveaux)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "Supprimer un environnement spécifique si installé" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "Afficher la version et quitter" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "Environnement de développement intégré" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "Eclipse Luna (4.4)" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "L'environnement de développement intégré Eclipse Luna" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "Eclipse Luna" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "Pycharm Édition Communautaire" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "PyCharm Édition Éducation" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "PyCharm Édition Professionelle" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "IntelliJ IDEA Édition Communautaire" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "IntelliJ IDEA" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "IDE Ruby on Rails" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" "IDE pour le développement d'applications javascript clientes et server" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "IDE pour PHP et web" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "IDE C/C++ CLion" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "Logiciels pour Arduino" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "IDE pour Arduino" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "Arduino" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" "We devez vous déconnecter et vous reconnecter pour que votre installation " "fonctionne" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "IDE Netbeans" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "Environnement de Développement Dartlang" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "Dart SDK avec éditeur (non supporté par upstream)" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "Dart SDK (défault)" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" "Vous devez redémarrer votre shell courant pour que votre installation {} " "fonctionne" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "Langage Rust" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "Distribution officielle Rust" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "Langage Scala" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "Compilateur et interpréteur Scala (défaut)" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "Langage Go" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "Compilateur Google (défaut)" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Environnement de développement Android" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "Android Studio (défaut)" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Environnement de développement Android Studio" #: umake/frameworks/android.py:111 msgid "Android SDK" msgstr "SDK Android" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "Android NDK" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" "Un framework par défaut pour la catégorie {} a été demandée, mais il n'y en " "a aucun" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "Vous ne pouvez pas installer ce framework sur cette machine" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "Vous ne pouvez supprimer {} puisqu'il n'est pas installé" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" "Si l'environnement par défaut n'est pas spécifié, destdir doit contenir un /" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "Supprime l'environnement si installé" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "Accepter la license sans demander" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "Environnement de développement Web" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "Firefox Édition Développeur" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "Votre langue : {}" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "Firefox Aurora avec outils développeur" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "Installer dans la lange choisie sans demander" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "Visual Studio pour le web moderne et cloud" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "Visual Studio Code" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "Environnement de développement de jeux" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "Éditeur de jeux Stencyl" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "Éditeur Unity 3D avec support expérimental pour Linux" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "Éditeur Unity 3D" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "Outil Twine de création interactive et non linéaire d'histoires" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "Twine" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "La réponse n'est pas satisfaisante" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "" "Votre entrée '{}' n'est pas un choix acceptable. Choisissez parmi: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "" "Votre entrée '{}' n'est pas un choix acceptable. Choisissez entre {} et {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "J'accepte" #: umake/interactions/__init__.py:115 msgid "a" msgstr "a" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Je ne les accepte pas" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "N" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Oui" #: umake/interactions/__init__.py:148 msgid "y" msgstr "o" #: umake/interactions/__init__.py:149 msgid "No" msgstr "Non" ubuntu-make-16.02.1/po/en_CA.po0000664000000000000000000001646212656574623012762 0ustar # English (Canada) translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2014-12-09 13:09+0000\n" "Last-Translator: destiriser \n" "Language-Team: English (Canada) \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "Deploy and setup developers environment easily on Ubuntu" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" #: umake/__init__.py:111 msgid "Show this help" msgstr "" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "" #: umake/frameworks/android.py:111 msgid "Android SDK" msgstr "" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "Your entry '{}' isn't an acceptable choice. Choices are: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "Your entry '{}' isn't an acceptable choice. Choices are: {} and {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr "" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "" #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "I accept" #: umake/interactions/__init__.py:115 msgid "a" msgstr "" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "" #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "" #: umake/interactions/__init__.py:148 msgid "y" msgstr "" #: umake/interactions/__init__.py:149 msgid "No" msgstr "" ubuntu-make-16.02.1/po/sv.po0000664000000000000000000001722212656574623012440 0ustar # Swedish translation for ubuntu-make # Copyright (c) 2015 Rosetta Contributors and Canonical Ltd 2015 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2015. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-05-02 09:00+0000\n" "Last-Translator: Lars Nyström \n" "Language-Team: Swedish \n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-05-04 07:08+0000\n" "X-Generator: Launchpad (build 17474)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "Installera och konfigurera utvecklares arbetsmiljö enkelt på Ubuntu" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" #: umake/__init__.py:111 msgid "Show this help" msgstr "Visa denna hjälptext" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "Avinstallera givet ramverk om det är installerat" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "Allmänna utvecklingsmiljöer" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 #, fuzzy msgid "PHP and web development IDE" msgstr "Stencyl spelutvecklingsmiljö" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "" #: umake/frameworks/android.py:111 msgid "Android SDK" msgstr "" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "Du kan inte avinstallera {} eftersom det inte är installerat" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "Avinstallera ramverket om det är installerat" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "Spelutvecklingsmiljö" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "Stencyl spelutvecklingsmiljö" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "Inget lämpligt svar angivet" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Jag godkänner" #: umake/interactions/__init__.py:115 msgid "a" msgstr "a" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Jag godkänner inte" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "N" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Ja" #: umake/interactions/__init__.py:148 msgid "y" msgstr "j" #: umake/interactions/__init__.py:149 msgid "No" msgstr "Nej" #~ msgid "Stencyl Game developer environment" #~ msgstr "Stencyl spelutvecklingsmiljö" ubuntu-make-16.02.1/po/id.po0000664000000000000000000002202412656574623012400 0ustar # Indonesian translation for ubuntu-make # Copyright (c) 2015 Rosetta Contributors and Canonical Ltd 2015 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2015. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-03-01 08:40+0000\n" "Last-Translator: Eka Y Saputra \n" "Language-Team: Indonesian \n" "Language: id\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-04-02 06:32+0000\n" "X-Generator: Launchpad (build 17413)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "# Instalasi Ubuntu make di {}\n" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* Command '{}':" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "Memasang dan mengatur lingkungan pengembangan dengan mudah di ubuntu" #: umake/__init__.py:108 #, fuzzy msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "Anda juga bisa mengonfigurasikan perilaku pencatatan debug yang berbeda " "menggunakan LOG_CFG yang merujuk ke sebuah profil pencatatan yaml" #: umake/__init__.py:111 msgid "Show this help" msgstr "Tampilkan bantuan ini" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "Tingkatkan verbositas output (2 level)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "Hapus framework yang ditentukan jika telah terinstal" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "IDE Generik" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "Pure Eclipse Luna (4.4)" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "The Eclipse Luna Integrated Development Environment" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "Eclipse Luna" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:233 #, fuzzy msgid "PyCharm Educational Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:249 #, fuzzy msgid "PyCharm Professional Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "IntelliJ IDEA Community Edition" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "IntelliJ IDEA" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 #, fuzzy msgid "PHP and web development IDE" msgstr "IDE untuk pengembangan game Stencyl" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 #, fuzzy msgid "You need to logout and login again for your installation to work" msgstr "" "Anda harus menjalankan sebuah sesi shell untuk membuat instalasi Anda bekerja" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "Dartlang Development Environment" #: umake/frameworks/dart.py:49 #, fuzzy msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "Dart SDK with editor (default)" #: umake/frameworks/dart.py:56 #, fuzzy msgid "Dart SDK (default)" msgstr "Dart SDK with editor (default)" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 #, fuzzy msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" "Anda harus menjalankan sebuah sesi shell untuk membuat instalasi Anda bekerja" #: umake/frameworks/rust.py:43 #, fuzzy msgid "Rust language" msgstr "Bahasa Go" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 #, fuzzy msgid "Scala compiler and interpreter (default)" msgstr "Google compiler (default)" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "Bahasa Go" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "Google compiler (default)" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Lingkungan Pengembangan Android" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "Android Studio (default)" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Lingkungan pengembangan Android Studio" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android NDK" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "Android NDK" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "Anda tak bisa menghapus {} sebab belum pernah diinstal" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" "Jika nama framework bawaan tidak tersedia, destdir harus memuat sebuah /" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "Hapus framework jika terinstal" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "Lingkungan Pengembangan Web" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "Firefox Developer Edition" #: umake/frameworks/web.py:116 #, fuzzy msgid "Choose language: {}" msgstr "Bahasa Go" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "Firefox Aurora with Developer tools" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "Lingkungan Pengembangan Game" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "IDE untuk pengembangan game Stencyl" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 #, fuzzy msgid "Unity3D Editor" msgstr "Dart Editor" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "Tak ada jawaban yang cocok" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "" "Entri '{}' Anda bukanlah pilihan yang bisa diterima. pilihannya adalah: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "" "Entri '{}' Anda bukanlah pilihan yang bisa diterima. pilihannya adalah: {} " "dan {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Setuju" #: umake/interactions/__init__.py:115 msgid "a" msgstr "" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Tidak setuju" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Ya" #: umake/interactions/__init__.py:148 msgid "y" msgstr "" #: umake/interactions/__init__.py:149 msgid "No" msgstr "Tidak" #~ msgid "Stencyl Game developer environment" #~ msgstr "Lingkungan pengembangan game Stencyl" #~ msgid "Dart Editor for the dart language" #~ msgstr "Dart Editor untuk bahasa Dart" ubuntu-make-16.02.1/po/it.po0000664000000000000000000002016512656574623012424 0ustar # Italian translation for ubuntu-make # Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2014. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-09-29 08:08+0000\n" "Last-Translator: Francesco \n" "Language-Team: Italian \n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-11-05 13:56+0000\n" "X-Generator: Launchpad (build 17838)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "# Ubuntu make installazione di {}\n" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "* Comando '{}'" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "Installa e configura facilmente un ambiente per sviluppatori su Ubuntu" #: umake/__init__.py:108 #, fuzzy msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" "Nota che è anche possibile configurare diversi schemi di debug utilizzando " "LOG_CFG puntando ad un profilo di log yaml." #: umake/__init__.py:111 msgid "Show this help" msgstr "Mostra questo aiuto" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "Aumenta la verbosità dell'output (2 livelli)" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "Rimuovi il framework specificato se installato" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "Eclipse Luna" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:233 #, fuzzy msgid "PyCharm Educational Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:249 #, fuzzy msgid "PyCharm Professional Edition" msgstr "PyCharm Community Edition" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "IntelliJ IDEA Community Edition" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "IntelliJ IDEA" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "Android Development Environment" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "Android Studio" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "Ambiente di sviluppo Android Studio" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android NDK" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "Android NDK" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "Non puoi rimuovere {} perchè non è installato" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" "Se non viene fornito il nome predefinito del framework, destdir dovrebbe " "contenere /" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "RImuovi il framework se installato" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "Nessuna risposta adeguata fornita" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "La tua scelta '{}' non è una scelta accettabile. Le scelte sono: {}" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "" "La tua scelta '{}' non è una scelta accettabile. Le scelte sono: {} e {}" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Accetto" #: umake/interactions/__init__.py:115 msgid "a" msgstr "a" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "Non accetto" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "N" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Sì" #: umake/interactions/__init__.py:148 msgid "y" msgstr "y" #: umake/interactions/__init__.py:149 msgid "No" msgstr "No" ubuntu-make-16.02.1/po/da.po0000664000000000000000000001633012656574623012373 0ustar # Danish translation for ubuntu-make # Copyright (c) 2015 Rosetta Contributors and Canonical Ltd 2015 # This file is distributed under the same license as the ubuntu-make package. # FIRST AUTHOR , 2015. # msgid "" msgstr "" "Project-Id-Version: ubuntu-make\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-11-17 09:26+0100\n" "PO-Revision-Date: 2015-04-28 19:25+0000\n" "Last-Translator: Aputsiaĸ Niels Janussen \n" "Language-Team: Danish \n" "Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2015-05-04 07:08+0000\n" "X-Generator: Launchpad (build 17474)\n" #: umake/tools.py:48 msgid "# Ubuntu make installation of {}\n" msgstr "" #: umake/__init__.py:99 msgid "* Command '{}':" msgstr "" #: umake/__init__.py:107 msgid "Deploy and setup developers environment easily on ubuntu" msgstr "" #: umake/__init__.py:108 msgid "" "Note that you can also configure different debug logging behavior using " "LOG_CFG that points to a log yaml profile." msgstr "" #: umake/__init__.py:111 msgid "Show this help" msgstr "Vis denne hjælp" #: umake/__init__.py:112 msgid "Increase output verbosity (2 levels)" msgstr "" #: umake/__init__.py:114 msgid "Remove specified framework if installed" msgstr "" #: umake/__init__.py:116 msgid "Print version and exit" msgstr "" #: umake/frameworks/ide.py:63 msgid "Generic IDEs" msgstr "" #: umake/frameworks/ide.py:76 msgid "Pure Eclipse Luna (4.4)" msgstr "" #: umake/frameworks/ide.py:128 msgid "The Eclipse Luna Integrated Development Environment" msgstr "" #: umake/frameworks/ide.py:131 msgid "Eclipse Luna" msgstr "" #: umake/frameworks/ide.py:217 msgid "PyCharm Community Edition" msgstr "" #: umake/frameworks/ide.py:233 msgid "PyCharm Educational Edition" msgstr "" #: umake/frameworks/ide.py:249 msgid "PyCharm Professional Edition" msgstr "" #: umake/frameworks/ide.py:265 msgid "IntelliJ IDEA Community Edition" msgstr "" #: umake/frameworks/ide.py:281 msgid "IntelliJ IDEA" msgstr "" #: umake/frameworks/ide.py:297 msgid "Ruby on Rails IDE" msgstr "" #: umake/frameworks/ide.py:314 msgid "Complex client-side and server-side javascript IDE" msgstr "" #: umake/frameworks/ide.py:331 msgid "PHP and web development IDE" msgstr "" #: umake/frameworks/ide.py:348 msgid "CLion integrated C/C++ IDE" msgstr "" #: umake/frameworks/ide.py:376 msgid "The Arduino Software Distribution" msgstr "" #: umake/frameworks/ide.py:475 msgid "The Arduino Software IDE" msgstr "" #: umake/frameworks/ide.py:478 msgid "Arduino" msgstr "" #: umake/frameworks/ide.py:484 msgid "You need to logout and login again for your installation to work" msgstr "" #: umake/frameworks/ide.py:504 umake/frameworks/ide.py:584 #: umake/frameworks/ide.py:587 msgid "Netbeans IDE" msgstr "" #: umake/frameworks/dart.py:43 msgid "Dartlang Development Environment" msgstr "" #: umake/frameworks/dart.py:49 msgid "Dart SDK with editor (not supported upstream anyymore)" msgstr "" #: umake/frameworks/dart.py:56 msgid "Dart SDK (default)" msgstr "" #: umake/frameworks/dart.py:97 umake/frameworks/rust.py:134 #: umake/frameworks/scala.py:66 umake/frameworks/go.py:76 #: umake/frameworks/android.py:135 msgid "" "You need to restart your current shell session for your {} installation to " "work properly" msgstr "" #: umake/frameworks/rust.py:43 msgid "Rust language" msgstr "" #: umake/frameworks/rust.py:56 msgid "The official Rust distribution" msgstr "" #: umake/frameworks/scala.py:40 msgid "The Scala Programming Language" msgstr "" #: umake/frameworks/scala.py:46 msgid "Scala compiler and interpreter (default)" msgstr "" #: umake/frameworks/go.py:39 msgid "Go language" msgstr "" #: umake/frameworks/go.py:46 msgid "Google compiler (default)" msgstr "" #: umake/frameworks/android.py:42 msgid "Android Development Environment" msgstr "" #: umake/frameworks/android.py:80 msgid "Android Studio (default)" msgstr "" #: umake/frameworks/android.py:100 msgid "Android Studio" msgstr "" #: umake/frameworks/android.py:103 msgid "Android Studio developer environment" msgstr "" #: umake/frameworks/android.py:111 #, fuzzy msgid "Android SDK" msgstr "Android NDK" #: umake/frameworks/android.py:147 msgid "Android NDK" msgstr "Android NDK" #: umake/frameworks/__init__.py:129 msgid "A default framework for category {} was requested where there is none" msgstr "" #: umake/frameworks/__init__.py:240 msgid "You can't install that framework on this machine" msgstr "" #: umake/frameworks/__init__.py:256 msgid "You can't remove {} as it isn't installed" msgstr "" #: umake/frameworks/__init__.py:285 msgid "" "If the default framework name isn't provided, destdir should contain a /" msgstr "" #: umake/frameworks/__init__.py:288 msgid "Remove framework if installed" msgstr "" #: umake/frameworks/__init__.py:291 msgid "Accept license without prompting" msgstr "" #: umake/frameworks/web.py:45 msgid "Web Developer Environment" msgstr "" #: umake/frameworks/web.py:51 umake/frameworks/web.py:120 msgid "Firefox Developer Edition" msgstr "" #: umake/frameworks/web.py:116 msgid "Choose language: {}" msgstr "" #: umake/frameworks/web.py:123 msgid "Firefox Aurora with Developer tools" msgstr "" #: umake/frameworks/web.py:129 msgid "Install in given language without prompting" msgstr "" #: umake/frameworks/web.py:141 umake/frameworks/web.py:226 msgid "Visual Studio focused on modern web and cloud" msgstr "" #: umake/frameworks/web.py:223 msgid "Visual Studio Code" msgstr "" #: umake/frameworks/games.py:42 msgid "Games Development Environment" msgstr "" #: umake/frameworks/games.py:48 msgid "Stencyl game developer IDE" msgstr "" #: umake/frameworks/games.py:85 msgid "Stencyl" msgstr "Stencyl" #: umake/frameworks/games.py:114 msgid "Unity 3D Editor Linux experimental support" msgstr "" #: umake/frameworks/games.py:154 msgid "Unity3D Editor" msgstr "" #: umake/frameworks/games.py:164 msgid "Twine tool for creating interactive and nonlinear stories" msgstr "" #: umake/frameworks/games.py:200 msgid "Twine" msgstr "" #: umake/interactions/__init__.py:73 msgid "No suitable answer provided" msgstr "" #: umake/interactions/__init__.py:75 umake/interactions/__init__.py:83 msgid "Your entry '{}' isn't an acceptable choice. choices are: {}" msgstr "" #: umake/interactions/__init__.py:80 msgid "Your entry '{}' isn't an acceptable choice. choices are: {} and {}" msgstr "" #: umake/interactions/__init__.py:100 msgid " ({})" msgstr " ({})" #: umake/interactions/__init__.py:104 msgid "" "{}\n" "[{}] " msgstr "" "{}\n" "[{}] " #: umake/interactions/__init__.py:107 msgid "{} [{}] " msgstr "{} [{}] " #: umake/interactions/__init__.py:115 msgid "I Accept" msgstr "Jeg accepterer" #: umake/interactions/__init__.py:115 msgid "a" msgstr "" #: umake/interactions/__init__.py:116 msgid "I don't accept" msgstr "" #: umake/interactions/__init__.py:116 umake/interactions/__init__.py:149 msgid "N" msgstr "" #: umake/interactions/__init__.py:125 umake/interactions/__init__.py:126 msgid "{} ({})" msgstr "{} ({})" #: umake/interactions/__init__.py:129 msgid "[{}] " msgstr "[{}] " #: umake/interactions/__init__.py:148 msgid "Yes" msgstr "Ja" #: umake/interactions/__init__.py:148 msgid "y" msgstr "" #: umake/interactions/__init__.py:149 msgid "No" msgstr "Nej" ubuntu-make-16.02.1/debian/0000775000000000000000000000000012656574623012250 5ustar ubuntu-make-16.02.1/debian/ubuntu-make.manpages0000664000000000000000000000001712656574623016220 0ustar debian/umake.1 ubuntu-make-16.02.1/debian/ubuntu-make.postinst0000664000000000000000000000036712656574623016320 0ustar #!/bin/sh set -e case "$1" in configure) register-python-argcomplete3 umake > /etc/bash_completion.d/umake ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac #DEBHELPER# exit 0 ubuntu-make-16.02.1/debian/changelog0000664000000000000000000007452412656574623014136 0ustar ubuntu-make (16.02.1) xenial; urgency=medium [ Galileo Sartor ] [ Didier Roche ] * Fix Visual Studio Code to use permanent links as the website changed. Adapt tests to it. -- Didier Roche Wed, 10 Feb 2016 09:43:20 +0100 ubuntu-make (16.02) xenial; urgency=medium [ Galileo Sartor ] * Add Nodejs support with always latest node and npm now available! * Add Lighttable IDE support. * Create symlinks in a bin/ directory which is now added to user's PATH for each .desktop file created. That way, people can run their app from the command line as well. * All of those covered by small medium and large tests. [ Patricio Pérez ] * Add Spring Tools Suite and its testsuite. [ Omer Sheikh ] * Add JetBrains Datagrip with tests * Add python-gnupg to requirements.txt. [ Didier Roche ] * Disable Visual Studio Code installation for now. Adapt tests for that change. -- Didier Roche Tue, 09 Feb 2016 08:47:49 +0100 ubuntu-make (16.01.2) xenial; urgency=medium [ Galileo Sartor ] * Add swift lang support with according tests. * Add support for Eclipse php with tests. * Add support for Eclipse cpp with tests. [ Evan McIntire ] * dd manpage that is generated from the --help text. [ Didier Roche ] * Fix, and implements some testing for Swift, Eclipse php and cpp. * Add gpg key support so that we can mock and add it to frameworks, working around some uid != euid limitations. * Compile local python file under current user name in tests. -- Didier Roche Wed, 20 Jan 2016 17:38:39 -0800 ubuntu-make (16.01.1) xenial; urgency=medium * Fix Go support as of 1.5.3, they now publishes a sha256 instead of a sha1 checksum. * Adapt tests to it. * A lot of work on tests: - add local/vm/remote args to runtests to easily run tests in locally, in an adt environment or remotely on the official infrastructure. - minimizing autopkgtests installation - docker fixes with proxy for medium tests - ensure we run with a dummy xorg driver - ensure compiz is running before running large and custom tests - fix TESTS=all triggering custom tests - fix not installing ubuntu-make package itself for git tests -- Didier Roche Thu, 14 Jan 2016 12:26:52 +0100 ubuntu-make (16.01) xenial; urgency=medium [ Galileo Sartor ] * Always deliver the latest Unity3D version (beta) to our users. * Ensure we always download latest available eclipse java IDE version. This enables users to now get eclipse Mars from Ubuntu Make! [ Didier Roche ] * Enable setting up Firefox Dev as default browser. * Move Visual Studio Code to IDE category. Keep it still on the web category for backward compatiblity. Adapts tests to ensure both category works (with a warning on the web one). * Move the testing infrastructure from jenkins to ubuntu autopkgtests: - create pep8/small/medium/large/all targets to mimic runautopkgtests behavior. - add a setup test bed, installing an ubuntu-desktop image, grabbing git branch or system package and generating stats info. - add another collecting coverage test to generate and copy stats to artefacts directory. - a custom target is triggered when one or more specific tests are desired like --env="TESTS=tests/small/.py tests.small.foo:TestClass:test_bar". - all those tests are handled by a TESTS env variable. If not set, we run pep8 and small tests. - creating utils and scripts to factorize most of the logic. * Protect against invalid tar archive that can be opened but not fully extracted. * Remove libxp6 dep from Stencyl as optional and not available from wily. * Install test dependencies from package and autopkgtests list. Use that logic in both autopkgtest infra and jenkins. * Make test_install_progress more robust as apt 1.1.5 changed its update signaling behavior. * Add in baseinstaller some way to only match last link when parsing. * Rework foreign architecture addition and detection to ensure we only call it once (we were calling them once per package previously), fix some races in cache handling. Move this facility to tools and restructure tests for this, while adding some more. * Add locks to avoid a race condition when creating temp file (to not create them as root) and add a new contextwrapper for as_root() with its tests. * Drop sshpass in favor of ssh key for docker image connection. * Some misc fixes: - Change some error messages and making them localizable. - fix an issue to avoid nested fakeroot calls. - Ensure we always kill children process and not the wrapper in container. - Add a fallback when os.getlogin() returns transient errors. - Normalize end of line tests comparaison. - Fix some possible failure when issuing a progressbar update. - Restructure, decouple and grab additional mocks for tests - Restore properly the initial environment in test_settings to avoid env leaks bugs. - Import cleanups. -- Didier Roche Tue, 12 Jan 2016 09:39:08 +0100 ubuntu-make (15.12.1) xenial; urgency=medium [ Eldar Khayrullin ] * Update Unity3D link to latest [ Didier Roche ] * Fix rust for their latest release as they changed rustlib directory * Adapt rust medium assets * Fix medium tests by changing unity server host * Some tidy up on BeautifulSoup latest release -- Didier Roche Thu, 17 Dec 2015 07:36:45 +0100 ubuntu-make (15.12) xenial; urgency=medium * Fix JetBrain's based IDE due to their new website deployement: - Use now their API directly. - Adapt medium tests and assets to follow that new structure. * Add a deprecation warning on udtc command (will be removed after 16.04 LTS) -- Didier Roche Fri, 11 Dec 2015 10:52:53 +0100 ubuntu-make (15.11.2) xenial; urgency=medium [ Abigail Buccaneer ] * Add JetBrains CLion C/C++ IDE support. [ Eldar Khayrullin ] * Complete Russian translation. [ Translation team ] * Refresh po files with latest community translations. Thanks to all our translator community! [ Didier Roche ] * Add Twine game editor support. * Ensure --help always show category help when following category, even if it has default frameworks. * Add tests (small/medium/large) to cover those. * Add ZSH completion to the same level as bash completion. * Fix visual studio icon which changed its path (detected thanks to our testsuite). * Add medium and large tests for CLion. * Fallback to plain english if language support isn't fully installed. * Fix incorrect pt_BR translations. * Add better description for jetbrain IDEs. * Create and move a bunch of Android tests to a mock BaseInstaller based one. This enables us to cut large test time by a magnitude of 2. Using that opportunity to add more tests and complete existing ones. * Standardize language test bed to run in plain english whatever your configuration is. * Misc. tests enhancements and tools fixes. * Move build dependencies only needed for tests to another ppa (ppa:ubuntu-desktop/ubuntu-make-builddeps) and add it in jenkins tests. This way, people using Ubuntu Make on older release are not impacted by the need of newer version of tests frameworks like pexpect and won't install them. Hook that ppa in Travis CI, our jenkins infra and refresh contributor intro to ask adding that ppa for testing. * Enhance our jenkins job for testing a pull request branch and other minor test job enhancements. * Update French translations. * Update translation template for new and updated frameworks. -- Didier Roche Tue, 24 Nov 2015 08:06:03 +0100 ubuntu-make (15.11.1) xenial; urgency=medium [ Fabio Colella ] * Added support for Netbeans IDE, with possibility of extension to support its flavours. * Add large and initial support for medium tests. [ Jared Ravetch ] * Add Rust support, installing the latest rust compiler and tools version. * Initial support for medium and large tests. * Override GOROOT value instead of appending it (Go doesn't support GOROOT having multiple values). [ Eldar Khayrullin ] * Update unity3d version up to 5.1.0f3+2015091501. [ Sebastian Schuberth ] * Change android NDK env variable to use NDK_ROOT instead of ANDROID_NDK. [ Didier Roche ] * Fix webstorm icon renamed upstream. * Ship version file as part of the install (Now --version really works on packaged flavor as well) + stamp generated binary with correct version. * Fix BaseInstaller to not crash when all downloads assets are 404 + add medium tests for this. * Ensure -r global option behave like --remove. * Some style, refactoring and formatting tidy up for recent merges and changes. * Add medium assets, certificates and additional failure test cases for netbeans and rust. * Update docker container for medium tests with new certificates. * Readd Travis CI integration running pep8 and small tests (with badge status and updated wording in README). New pushes and pull requests are now automatically tested on those 2 kinds of tests. * Fix and updates dependencies for package and pip virtualenv deps. * Standardize the test environment so that people running tests using for instance zsh are not impacted. * Finish up shipping static files support for future frameworks. * Using scala framework for loading tests and making autopkgtests pass on armel64 (android not available on this arch). * Improve releasing script and migrate gbp config to new headers. [ Translators ] * Refreshed translation template and updated translations. Thanks to all our translators! - new supported languages: fa, pt_BR - Updating the following languages: de, en_AU, en_CA, en_GB, eu, hr, it, pl, ru, te, zh_CN, zh_HK -- Didier Roche Tue, 10 Nov 2015 09:12:26 +0100 ubuntu-make (15.11) xenial; urgency=medium [ Omer Sheikh ] * Change default install path to ~/.local/share/umake/, depending on $XDG_DATA_HOME. * Add tests for those. * Improve tests stability in different environment (particularly jenkins) by creating wrapper around pexpect.spawnu. The wrapper sets the virtual terminal dimensions before calling pexpect.spawnu. This is to solve the problem of newline and carriage returns appearing in the stdout of created processes when testing under jenkins. [ Sebastian Schuberth ] * Fix changelog name. * Set the ANDROID_HOME and NDK_ROOT environment variables for android NDK frameworks. [ Jared Ravetch ] * Fix user message when prompting user to restart shell session. [ Didier Roche ] * Add a --version option to print current ubuntu make version. The rules are: - if the user is on a released version, then print this version - if the user is on a git branch, use: - version-#commits-shortsha1 if there is no local or staged changes - version-#commits-shortsha1-dirty if there is some locals or staged changes - finally, if the user is a local checkout, but without git history, just print: version+unknown * Fix --remove when used before a category name. Now, you can properly umake --remove and the framework will be removed. * Fix framework env variables not removed for zsh shells on --remove. * Fix cmd list mangling for large Android NDK tests. * Add some autoreleasing script, to bump version, add them to stage, tag and commit. * Enable multiple decompressions to end up in same directory and adapt frameworks to this new framework API. * Adjust DownloadCenter number of threads to match number of assets to download. * Make BaseInstaller supporting multiple assets downloads and fix it to only reflect download progress when we have all download size data. We could have one download finishing up (and so global being at 100%) while other downloads didn't start yet. Ensure we have all assets size before reporting first download global progress. * Fix as well cleaned path to not be removed. * Filter in BaseInstaller to not decompress assets that are files to copy. * Add a bunch of small, medium and large tests for versioning, removal, env variable cleanups, parallel decompressions in the same directory, done callback counts for decompression and downloads. * Add a way to specify multiple ports (and hosts) in medium tests. This will be used in future frameworks which rely both on https and http downloads. Test tools can now expose multiple ports inside the container. Changed as well all medium tests to adapt to this new API. * Ensure we source .profile when executing command in container. * Various changes to run medium tests even on system installed version. * Save new jenkins jobs enabling medium tests and add branch-targeted jenkins job to test branches not merged yet into master. * Better medium tests stability support and optimization. * Package new version of pexpect and add dependency markers. * Some PR post-merge fixes and various refactoring. * Remove WIP marker in README. -- Didier Roche Tue, 03 Nov 2015 10:39:04 +0100 ubuntu-make (15.10) wily; urgency=medium * Fix Dartlang download due to its new website layout. * Fix pycharm educational link as their linux download returned some windows binary. * Adapt medium tests assets to those new website layouts and new certificates. * Add support for frameworks to poke for download on multiple hosts (needed for the Dartlang case). * Add support for medium tests to have a SNI server to cope with requests on multiple hosts when faking server inside the container, including delivering the correct content and certificate. * Ensure that probing for reinstall in frameworks is only requiring the right engagement level from the user (and add tests for this). * Add some generic frameworks functionality for detecting intallation state, enabling to remove a lot of similar code in all frameworks. * Handle properly directory which doesn't exists in archive to decompress. * Ensure that a logging config selection via conffile display the selected logging level. * Enhance logging and debugging support. * Add a bunch of new tests and raised the test coverage to reach 93%. * Add missing requirements from contributor documentation. Big thanks to aung for this! * Make CI jenkins jobs being more resilient to random failures (distro, network…). * Test jenkins jobs are now archived. * Misc code cleanups and dead code removal. -- Didier Roche Thu, 08 Oct 2015 10:19:14 +0200 ubuntu-make (15.09.2) wily; urgency=medium * Ignore continuation line having to be a multiple of 4 in older pep8 release (making identation not aligned with above line). * This then trigger new warnings for double spaces, fix them. -- Didier Roche Thu, 10 Sep 2015 08:00:33 +0200 ubuntu-make (15.09.1) wily; urgency=medium * Add support for installing android SDK only by Sebastian Schuberth - add associated set of medium and large tests. * Rationalize exit status of umake by Omer Sheikh - every error now, in addition to print some errors, exits as expect with an exit code of 1. - add and modify large tests, to ensure that each framework (those using BaseInstaller and those having some dedicated code path) are behaving the same for errors. - mock in medium tests bad page download to exercise the error code path here as well. * Fix some pep8 issues (trusty only), some small tests broken by previous merges. -- Didier Roche Thu, 10 Sep 2015 07:24:23 +0200 ubuntu-make (15.09) wily; urgency=medium * Unity 3D editor experimental support. You can install it through: umake games unity3d. Only amd64 is currently supported upstream. * Fix Arduino download as upstream web pages changes. Support more release version format and ensure we don't raise an exception but only log an error. * Add license support to Android NDK. * Adapt and add large and medium tests for both Unity 3D and Android NDK. * Various enhancements to enable decompressing shell-embedded archives without copying entire files. Add corresponding tests. * Refactor Android license parsing to be reusable to future Android SDK support. * Fix a bug where if license was after the download links, we wouldn't find the license. * Better add_to_user_env API for contributors. * Minor cosmetic and small bug fixes. -- Didier Roche Tue, 01 Sep 2015 10:51:32 +0200 ubuntu-make (15.08) wily; urgency=medium * Add scala support and add related medium and large tests. (Igor Vuk) * Fix Visual Studio Code download URL as VSCode updated their download mechanism on their website. (Vartan Simonian) * Fix progress bar out of range exception. (Anton Antonov) * Change medium VSC assets to match new download page. * Do some pep8 fixes triggered by new pep8 version. -- Didier Roche Thu, 13 Aug 2015 07:43:12 +0200 ubuntu-make (0.9.2) wily; urgency=medium * Enable language selection in firefox developer tools (thanks to Omer Sheikh): - Now the installation of firefox developer tools enable to choose interactively one of the available language (default being US). - add a --lang= parameter to switch to another language in non interactive mode. - additional tests and mocks for the new options and capability * Prevent double error logging when a TextWithChoice doesn't get the correct user's input. Adapt tests to it. * Fix a double empty [] when no shortcut is present. * Updated README to improve readability. Moved to more passive language. (thanks Brian P. Sizemore) -- Didier Roche Tue, 04 Aug 2015 09:06:57 +0200 ubuntu-make (0.9.1) wily; urgency=medium * Change test to prevent FTBFS with 3.5: assert_has_calls() * Print whole process output before getting the pexpect exception to get more info when a medium or large test is failing -- Didier Roche Fri, 24 Jul 2015 11:59:57 +0200 ubuntu-make (0.9.0) wily; urgency=medium * Force depending only on default python3 for the current ubuntu version. -- Didier Roche Tue, 21 Jul 2015 10:21:29 +0200 ubuntu-make (0.9) wily; urgency=medium * New arduino support. Thanks to Tin Tvrtković to have provided most of the work. * Fix parsing for Visual Studio Code 32 bits as upstream page changed. * Deprecate Dart Editor framework (marked for remove only) and add Dart SDK new framework as per Dart 1.11, the Editor is not supported anymore. * Added or adapt tests for those new cases. * Refresh and add helpers to large and medium tests to factorize them much more and aligning information we check from the .desktop files (exec and icon paths). * Remove tests data from umake runtime. * Some test cleanups and mock refresh (android studio, Visual Studio Code, Android NDK). -- Didier Roche Tue, 21 Jul 2015 09:34:45 +0200 ubuntu-make (0.8.2) wily; urgency=medium * Fix Visual Studio Code support due to new upstream archive layout and web page content. * Add support for 32 bits installation of VSC as now supported upstream. * Refresh and adapt large and medium tests to reflect those changes. -- Didier Roche Wed, 10 Jun 2015 09:41:49 +0200 ubuntu-make (0.8.1) wily; urgency=medium * Match Android NDK with new download URL. * Adapt medium test accordingly. * Fix one failing Android large test. -- Didier Roche Mon, 08 Jun 2015 08:59:30 +0200 ubuntu-make (0.8) wily; urgency=medium * Fix icon name that changed in Android Studio 1.2. Thanks Mark Trolley for this contribution! * Add tests to ensure that we are checking icon file name for android frameworks as well. * Rewrite the access in tests for icons and executables to read directly from the optional installed desktop file. Keep a way to override it for frameworks without desktop file. * Ensure we can remove deprecated frameworks. They only appear in shell completion and --help only if you had them installed. Prevent any reinstallation but only get a removal option. * Addition of a full non interactive installation mode. * Add tests for all those new features and fix some previous failing tests. -- Didier Roche Thu, 07 May 2015 11:13:09 +0200 ubuntu-make (0.7) vivid; urgency=medium * Add Visual Studio Code support (under the "web" category) * Fix an error message printing for the eclipse framework if the server doesn't return a success code -- Didier Roche Thu, 30 Apr 2015 13:06:50 +0200 ubuntu-make (0.6.2) vivid; urgency=medium * New translations: - Greek, Indonesian * Updated translations: - German, Spanish, French -- Didier Roche Thu, 02 Apr 2015 09:56:30 +0200 ubuntu-make (0.6.1) vivid; urgency=medium * Set dart-editor as the command to install the editor and adapt the tests to this * Fix some strings not marked for translations * Print help for category with no default framework * Fix get binary depends with empty starting line in debian/control * Add missing tests deps in debian/tests/control -- Didier Roche Thu, 12 Mar 2015 08:14:02 +0100 ubuntu-make (0.6) vivid; urgency=medium * New IDEs support and various cleanups by Anton Antonov: - rubymine - pycharm educational - pycharm professional - webstorm - phpstorm * All of those covered by medium and large tests * Add zsh support + tests (thanks Anton Antonov again) * Various small code enhancements -- Didier Roche Wed, 18 Feb 2015 09:47:08 +0100 ubuntu-make (0.5) vivid; urgency=medium * Add Idea Ultimate support, thanks to Tin Tvrtković. * Add Android NDK support. * Add Dartlang support. * Add Firefox Developer Edition support. * Get new ftp download support as Intellij downloads can redirect to ftp download based on location. Thank to Tin Tvrtković. * Refresh de and es translations. Thanks to all contributors! * Rationalize what is up for translations and refresh i18n templates for new strings. * Fix some is_installed() detection. * Workaround a glib issue when some Unity launcher icon doesn't appear. * Some tests enhancements, cleanups and fixes. -- Didier Roche Thu, 12 Feb 2015 10:48:20 +0100 ubuntu-make (0.4.1) vivid; urgency=medium * Fix for Intellij IDEA download page, thanks to Tin Tvrtković. * Add jayatana dependency for ides based on intellij so that even older releases than vivid get appmenu support. * Some misc test and docker container fixes. -- Didier Roche Thu, 22 Jan 2015 09:00:45 +0100 ubuntu-make (0.4) vivid; urgency=medium * Add go support from the golang google compiler * Add a game category with stencyl support * Refactor and add some tests for those -- Didier Roche Tue, 06 Jan 2015 10:49:58 +0100 ubuntu-make (0.3) vivid; urgency=medium * New release featuring intellij IDEA and Pycharm support (from jetbrain) in their community edition. Thanks to Tin Tvrtković for this work. They both are covered by new tests. * Add dependency on beautifulsoup for easier html parsing by Tin Tvrtković. * Ensure we download Android Studio over https. * Miscellaneous medium tests fixes. -- Didier Roche Tue, 16 Dec 2014 09:33:21 +0100 ubuntu-make (0.2) vivid; urgency=medium * Releasing under new name: ubuntu-make. Handle transition by shipping a temporary binary under the older name (udtc). New command is umake. Note as well that the new framework environment variable is UMAKE_FRAMEWORKS. * Provide compatibility binary (udtc) for now in the transitional package. Also move previous configuration file location to the new one. * Update Standards-Version * Fix Android Studio installation, now that it reached 1.0 milestone. * Removing Android Eclipse (adt) from Ubuntu Make: upstream doesn't provide any bundle anymore as this tools is deprecated in favor of Android Studio. -- Didier Roche Tue, 09 Dec 2014 08:23:33 +0100 ubuntu-developer-tools-center (0.1.1-0ubuntu1) vivid; urgency=medium * Bug-fix release as Google changed their android-studio checksum from md5sum to sha1sum. Implementing sha1sum largely thanks to Tin Tvrtković work! * Adapt tests + new tests for sha1sum. * Note that the new Android Studio doesn't ship the sdk with it anymore. You need to download it manually and set the path to it. Will try to get in touch with the android studio developer team for this. -- Didier Roche Tue, 04 Nov 2014 09:55:41 +0100 ubuntu-developer-tools-center (0.1-0ubuntu1) vivid; urgency=medium * Add eclipse support as a standalone IDE. Usage is: udtc ide eclipse. Thanks to Tin Tvrtković for his excellent work and tests implementation. * Add android adt support (through eclipse). Usage is: udtc android eclipse-adt. Added tests for it as well * adb and other android tools are now added to user path while installing an android framework * Support removal of framework. If you installed a framework and want to remove it, just use: udtc android android-studio --remove * Numerous typo fixes thanks to Igor Vuk * Enable loading of local framework. They are controlled by UDTC_FRAMEWORKS env variable which can point to any path containing local frameworks * Support reinstallation in different folder than the origin one, cleaning the original directory. * DownloadCenter now support redirections. Thanks Tin Tvrtković for this work * Add support for decompressing zip files in Decompressor * New and refresh translations: de, en_AU, en_CA, en_GB, es, eu, fr, hr, it, pl, ru, te, zh_CN, zh_HK. Thanks to all translators for their hard work! * Improve i18n support * Protect against mistyping with multiple frameworks * Framework support refactoring to avoid code duplication * Tests fixes and refactoring for better scalability * Fix logging support during test runs * Reshape docker files to have fewer layers * Don't raise any Exception for unexpected CLI args -- Didier Roche Wed, 29 Oct 2014 10:21:01 +0100 ubuntu-developer-tools-center (0.0.5) utopic; urgency=medium * Addition for the test jenkins server: - Add helper to display binary depends - Output xml tests and coverage report - Add xunit artefacts support in runtests * Some tests enhancement for working in the daily jenkins environment: - Change installing in conflict package prediction. - Give some time for the container in medium tests to start - Remove full install timeout logic. Instead, have a timeout if there is no new stdout/progress report change for a while. This ensure less flakyness in case of really slow network. - Remove on output testing first INFO message detection as it's a false positive. * No output by default when running tests: - Coverage tests doesn't print any stdout or logging info unless a tests is failing. - Debug profile is using the debug logging configuraiton as well. - Don't rely on importing tests/__init__.py to define logging format for nose. - Ensure subprocess (medium/large tests) set the same logging level as well. - Add a stdout hanlder in subprocess as well while testing (using the correct profile and be able to detect warning/errors) * debian/rules: - no need for --no-config for running tests anymore * Misc cleanups: - some refactoring of runtests - remove unusued imports - removed unused profile options - update documentation for the new logging profiles change. * Have pep8 tests passing on system version as well. * Add Spanish, Basque and Chinese (Hong Kong) translations. Thanks to all translators! -- Didier Roche Tue, 09 Sep 2014 16:48:12 +0200 ubuntu-developer-tools-center (0.0.4.1) utopic; urgency=medium * GSettings:schema has been deprecated and glib shows a warning about it. Fix the deprecation by switching to schema-id which is supported in 14.04. -- Didier Roche Mon, 01 Sep 2014 17:14:06 +0200 ubuntu-developer-tools-center (0.0.4) utopic; urgency=medium * Enhance some tests by adding more info in case of failure and decouple some concerns. * Fix medium tests in using server name back as sbuild supports it again. * Refreshed certificates which expired and document how to get longer ones. * First trial to get medium tests running as autopkgtests, but disabled for now (Docker permission error inside the autopkg chroot) * Refactor i18n support with dropping babel and automatically run the commands when setuptools is building. * Add fr and zh_CN translations. -- Didier Roche Thu, 28 Aug 2014 11:03:09 +0200 ubuntu-developer-tools-center (0.0.3) utopic; urgency=medium * Fix coverage reports by importing tested modules only when needed and when overriding "packages" and "__files__", by reloading the module * Some cleanups (removed unused imports) * Add allow-stderr for adt tests: as nose-cov print some debug output at start which makes adt failing then. As we control, stderr and warnings during tests, disable this check. -- Didier Roche Thu, 28 Aug 2014 08:12:31 +0200 ubuntu-developer-tools-center (0.0.2.2) utopic; urgency=medium * debian/control: - add XS-Testsuite as some uploads may happen from trusty -- Didier Roche Wed, 27 Aug 2014 15:24:18 +0200 ubuntu-developer-tools-center (0.0.2.1) utopic; urgency=medium * Rebuild to run autopkgtests * Fix some pep8 issues on utopic and enable them during package build -- Didier Roche Wed, 27 Aug 2014 15:00:29 +0200 ubuntu-developer-tools-center (0.0.2) utopic; urgency=medium * Adapt one test as we disabled the android eclipse framework (not ready yet) -- Didier Roche Mon, 11 Aug 2014 17:44:12 +0200 ubuntu-developer-tools-center (0.0.1) utopic; urgency=medium * Initial release, supporting android-studio -- Didier Roche Fri, 01 Aug 2014 09:37:20 +0200 ubuntu-make-16.02.1/debian/rules0000775000000000000000000000056512656574623013336 0ustar #!/usr/bin/make -f #DH_VERBOSE=1 %: dh $@ --with python3 --buildsystem=pybuild --fail-missing override_dh_auto_test: ./runtests pep8 small override_dh_installman: help2man -n "Deploy and setup developers environment easily on ubuntu" -o debian/umake.1 bin/umake sed -i s/+unknown//g debian/umake.1 dh_installman override_dh_clean: rm -f debian/umake.1 dh_clean ubuntu-make-16.02.1/debian/control0000664000000000000000000000346512656574623013663 0ustar Source: ubuntu-make Section: devel Priority: optional Build-Depends: debhelper (>= 9), dh-python, gettext, python3, python3-apt, python3-argcomplete, python3-bs4, python3-gi, python3-gnupg, python3-setuptools, python3-nose, python3-nose-cov, python3-nose-json, python3-pep8, python3-pexpect, python3-progressbar, python3-yaml, python3-requests, python3-xdg, dbus-x11, fakeroot, help2man, Maintainer: Didier Roche Standards-Version: 3.9.6 X-Python3-Version: >= 3.4 XS-Testsuite: autopkgtest Package: ubuntu-make Architecture: all Depends: ${misc:Depends}, ${python3:Depends}, python3-apt, python3-argcomplete, python3-bs4, python3-gi, python3-gnupg, python3-progressbar, python3-yaml, python3-requests, python3-xdg, Description: setup your development environment on ubuntu easily Ubuntu Make provides a set of functionality to setup, maintain and personalize your developer environment easily. It will handle all dependencies, even those which aren't in Ubuntu itself, and install latest versions of the desired and recommended tools. . For now, you can configure a complete android studio environment. Package: ubuntu-developer-tools-center Architecture: all Section: oldlibs Priority: extra Depends: ubuntu-make, ${misc:Depends}, ${python3:Depends} Description: transitional dummy package This is a transitional dummy package only providing previous udtc binary instead of umake. It can safely be removed. ubuntu-make-16.02.1/debian/ubuntu-developer-tools-center.postinst0000664000000000000000000000032712656574623022000 0ustar #!/bin/sh set -e case "$1" in configure) rm -f /etc/bash_completion.d/udtc ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac #DEBHELPER# exit 0 ubuntu-make-16.02.1/debian/ubuntu-make.postrm0000664000000000000000000000042612656574623015755 0ustar #!/bin/sh set -e case "$1" in purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) rm -f /etc/bash_completion.d/umake ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 1 ;; esac #DEBHELPER# exit 0 ubuntu-make-16.02.1/debian/tests/0000775000000000000000000000000012656574623013412 5ustar ubuntu-make-16.02.1/debian/tests/medium0000664000000000000000000000025212656574623014614 0ustar #!/bin/bash # Author: Didier Roche set -e . `dirname $0`/utils # skip tests if not requested skip_if_no_in_list run_tests medium publish_results ubuntu-make-16.02.1/debian/tests/collect-coverage0000664000000000000000000000061312656574623016553 0ustar #!/bin/bash # collect and generate global coverage report # Author: Didier Roche set -e . `dirname $0`/utils # combine the reports cd $coverage_dir python3-coverage combine python3-coverage html -d html-coverage python3-coverage xml # archive the results cp .coverage ${ADT_ARTIFACTS} cp -a *coverage* ${ADT_ARTIFACTS} # print on stdout as well python3-coverage report ubuntu-make-16.02.1/debian/tests/setup-testbed0000664000000000000000000000644712656574623016140 0ustar #!/bin/bash # setup an ubuntu-desktop machine with autologin and dependencies # Author: Didier Roche set -e . `dirname $0`/utils if [ -n "$ADT_REBOOT_MARK" ]; then exit 0 fi export DEBIAN_FRONTEND=noninteractive # configure docker sudo -n addgroup $(whoami) docker # the config file isn't a pam file (shouldn't have export) when used from the # service file under systemd if [ -d /run/systemd/system/ ]; then grep proxy /etc/environment | sudo -n tee -a /etc/default/docker else # this is sourced for sysv init scripts sed -n '/proxy/ { s/^/export /; p}' /etc/environment | sudo -n tee -a /etc/default/docker fi # ensure we have a cgroup controller installed (systemd for wily and on, cgroup-lite for trusty) if ! `dpkg -l systemd-sysv 1>/dev/null 2>&1`; then sudo -n apt --no-install-recommends install -y cgroup-lite fi # workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=808203 sudo -n rm -f /etc/dpkg/dpkg.cfg.d/pkg-config-hook-config # enable xserver dummy driver sudo -n apt --no-install-recommends install -y xserver-xorg-video-dummy cat <> ~/.ssh/authorized_keys # install ubuntu-make if we are running system tests, otherwise install only deps from debian/control if [ "$(is_package_test)" = "true" ]; then PACKAGES="ubuntu-make" else PACKAGES=$(tests/daily_runs/get_binary_depends ubuntu-make) fi sudo -n -E apt install -y $PACKAGES # store ubuntu make version and packages config_dir="$ADT_ARTIFACTS/config" mkdir -p $config_dir # discover target: package/branch, origin if [ "$(is_package_test)" = "true" ]; then # clean the source package to ensure we don't have duplicated files after # build for sloccount debian/rules clean type="system" origin="$(apt-cache policy ubuntu-make | sed -n '/\*\*\*/ {n;p}' | cut -d' ' -f 10)" [ -z "$origin" ] && origin="Local package" version="$(umake --version)'" else type="branch" upstream_short="$(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD))" IFS=/ read repo branch <<< $upstream_short repo_url=$(git config --get remote.${repo}.url) origin="${repo_url} $branch" version="$(bin/umake --version)'" fi cat << EOF | tee "$config_dir/version" { 'target': { 'type': '$type', 'origin': '$origin', 'version': '$version', }, 'date': { 'timestamp': '$(date +%s)', 'utc': '$(date -u)' }, 'arch': '$(arch)' } EOF dpkg -l > "$config_dir/packages_list" echo -e "\nStats:" sloccount * | head -n -17 | tail -17 | tee "$config_dir/stats" # remove umake directory for coverage reporting on real used files if [ "$type" = "system" ]; then rm -r umake/ fi # compile local python file under current user to avoid some root-owned compile # file like for local server python3 -m compileall . sudo -n /tmp/autopkgtest-reboot ready ubuntu-make-16.02.1/debian/tests/pep80000664000000000000000000000025012656574623014206 0ustar #!/bin/bash # Author: Didier Roche set -e . `dirname $0`/utils # skip tests if not requested skip_if_no_in_list run_tests pep8 publish_results ubuntu-make-16.02.1/debian/tests/custom0000664000000000000000000000036112656574623014647 0ustar #!/bin/bash # Author: Didier Roche set -e . `dirname $0`/utils # skip tests if not requested skip_if_no_in_list # require compiz to run as we might right large tests wait_for_compiz run_tests $TESTS publish_results ubuntu-make-16.02.1/debian/tests/large0000664000000000000000000000032212656574623014424 0ustar #!/bin/bash # Author: Didier Roche set -e . `dirname $0`/utils # skip tests if not requested skip_if_no_in_list # require compiz to run wait_for_compiz run_tests large publish_results ubuntu-make-16.02.1/debian/tests/control0000664000000000000000000000075512656574623015024 0ustar # Setup an ubuntu-desktop install which can logout and login Tests: setup-testbed, pep8, small, medium, large, custom, collect-coverage, Depends: @builddeps@, ubuntu-desktop, git, docker.io, sloccount, libjs-jquery, libjs-jquery-hotkeys, libjs-jquery-isonscreen, libjs-jquery-tablesorter, Restrictions: rw-build-tree, isolation-machine, allow-stderr, ubuntu-make-16.02.1/debian/tests/small0000664000000000000000000000025212656574623014444 0ustar #!/bin/bash # Author: Didier Roche set -e . `dirname $0`/utils # skip tests if not requested. skip_if_no_in_list run_tests small publish_results ubuntu-make-16.02.1/debian/tests/utils0000664000000000000000000000562312656574623014503 0ustar #!/bin/bash # Author: Didier Roche coverage_dir=/tmp/global-coverage # publish test results for given test run. Keep a secondary coverage copy (as the first one is cleaned) for collect step function publish_results { test_type=$(basename $0) output_dir="$ADT_ARTIFACTS/$test_type" mkdir -p $output_dir mv nosetests.* ${output_dir} mv .coverage ${output_dir} mv *coverage* ${output_dir} mv *.log ${output_dir} mkdir -p $coverage_dir cp ${output_dir}/.coverage ${coverage_dir}/.coverage.${test_type} } # this function need to be run in ubuntu make directory" function is_package_test { if [ -d ".git" ]; then echo "false" return fi echo "true" } # add --system if we run from a package dir function add_runtests_opts { if [ "$(is_package_test)" = true ]; then echo "--system" return fi } # skip current test if not "all" or in the list of $TESTS # if the test variable is empty, we still want to run some tests as per of package testing function skip_if_no_in_list { # tests to run if nothing was provided [ -z "$TESTS" ] && TESTS="small" test_type=$(basename $0) re=\\btests[\./] # we are in the custom type test flavor if [[ "$test_type" = "custom" ]]; then if [[ "$TESTS" =~ $re ]]; then return else echo "No specific mentioned in \$TESTS; skipping test" exit 0 fi fi # if we run only some tests of the current type, (tests..), disable all and this category if [[ "$TESTS" =~ $re ]]; then echo "Specific tests required, skipping general ones." exit 0 fi retype=\\b${test_type}\\b reall=\\ball\\b if [[ "$TESTS" =~ $retype ]] || [[ "$TESTS" =~ $reall ]]; then return fi echo "$test_type isn't mentioned in \$TESTS; skipping test" exit 0 } # we need to run in a ssh subshell to get a real terminal connexion so that ssh can returns when subprocess are killed function run_tests { ssh -o StrictHostKeyChecking=no -t -t 127.0.0.1 "cd $PWD; DISPLAY=:0 dbus-launch ./runtests --publish --coverage $(add_runtests_opts) $@" } # wait for compiz to start, exit 1 after a timeout if not running. function wait_for_compiz { timeout=100 while [ ! `pgrep -c compiz` -gt 0 ]; do if [ $timeout -le 0 ]; then echo "compiz didn't start" echo "------------- /var/log/lightdm/x-0.log -------------" sudo -n cat /var/log/lightdm/x-0.log || true echo "------------- /var/log/lightdm/.lightdm.log -------------" sudo -n cat /var/log/lightdm/lightdm.log || true echo "------------- ~/.xsession-errors -------------" cat ~/.xsession-errors || true exit 1 fi timeout=$((timeout - 5)) sleep 5 echo "waiting for compiz to start... (${timeout}s left)" done } ubuntu-make-16.02.1/debian/copyright0000664000000000000000000000166512656574623014213 0ustar Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: Ubuntu Make Source: https://github.com/ubuntu/ubuntu-make Files: * Copyright: (C) 2014 Canonical License: GPL-3 This program 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; version 3 of the License. . This program 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 this package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA . The full text of the GPL is distributed in /usr/share/common-licenses/GPL-3 on Debian systems. ubuntu-make-16.02.1/debian/ubuntu-developer-tools-center.install0000664000000000000000000000001512656574623021555 0ustar usr/bin/udtc ubuntu-make-16.02.1/debian/ubuntu-make.install0000664000000000000000000000010412656574623016070 0ustar usr/share/zsh/vendor-completions/ usr/bin/umake usr/lib/ usr/share/ ubuntu-make-16.02.1/debian/compat0000664000000000000000000000000212656574623013446 0ustar 9 ubuntu-make-16.02.1/debian/gbp.conf0000664000000000000000000000010612656574623013664 0ustar [buildpackage] export-dir=../build-area/ export=INDEX ignore-new=True ubuntu-make-16.02.1/requirements.txt0000664000000000000000000000030012656574623014303 0ustar # runtime requirements -e bzr+lp:python-apt/@0.9.3.5#egg=apt argcomplete beautifulsoup4 progressbar pyyaml requests pyxdg python-gnupg # test tools nose nose-cov nose-json pep8 pexpect>=4.0
    By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2015, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo