def xtermTitleReset(): global default_xterm_title if default_xterm_title is None: prompt_command = os.environ.get('PROMPT_COMMAND') if prompt_command == "": default_xterm_title = "" elif prompt_command is not None: if dotitles and \ 'TERM' in os.environ and \ _legal_terms_re.match(os.environ['TERM']) is not None and \ sys.__stderr__.isatty(): from portage.process import find_binary, spawn shell = os.environ.get("SHELL") if not shell or not os.access(shell, os.EX_OK): shell = find_binary("sh") if shell: spawn([shell, "-c", prompt_command], env=os.environ, fd_pipes={ 0: portage._get_stdin().fileno(), 1: sys.__stderr__.fileno(), 2: sys.__stderr__.fileno() }) else: os.system(prompt_command) return else: pwd = os.environ.get('PWD','') home = os.environ.get('HOME', '') if home != '' and pwd.startswith(home): pwd = '~' + pwd[len(home):] default_xterm_title = '\x1b]0;%s@%s:%s\x07' % ( os.environ.get('LOGNAME', ''), os.environ.get('HOSTNAME', '').split('.', 1)[0], pwd) xtermTitle(default_xterm_title, raw=True)
def testReadTransport(self): """ Test asyncio.create_subprocess_exec(stdout=subprocess.PIPE) which requires an AbstractEventLoop.connect_read_pipe implementation (and a ReadTransport implementation for it to return). """ if sys.version_info.major < 3: self.skipTest('ReadTransport not implemented for python2') args_tuple = (b'hello', b'world') echo_binary = find_binary("echo") self.assertNotEqual(echo_binary, None) echo_binary = echo_binary.encode() def test(loop): with open(os.devnull, 'rb', 0) as devnull: proc = loop.run_until_complete( create_subprocess_exec( echo_binary, *args_tuple, stdin=devnull, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, loop=loop)) self.assertEqual( tuple(loop.run_until_complete(proc.stdout.read()).split()), args_tuple) self.assertEqual(loop.run_until_complete(proc.wait()), os.EX_OK) self._run_test(test)
def testWriteTransport(self): """ Test asyncio.create_subprocess_exec(stdin=subprocess.PIPE) which requires an AbstractEventLoop.connect_write_pipe implementation (and a WriteTransport implementation for it to return). """ if sys.version_info.major < 3: self.skipTest('WriteTransport not implemented for python2') stdin_data = b'hello world' cat_binary = find_binary("cat") self.assertNotEqual(cat_binary, None) cat_binary = cat_binary.encode() def test(loop): proc = loop.run_until_complete( create_subprocess_exec( cat_binary, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, loop=loop)) # This buffers data when necessary to avoid blocking. proc.stdin.write(stdin_data) # Any buffered data is written asynchronously after the # close method is called. proc.stdin.close() self.assertEqual( loop.run_until_complete(proc.stdout.read()), stdin_data) self.assertEqual(loop.run_until_complete(proc.wait()), os.EX_OK) self._run_test(test)
def repoman_getstatusoutput(cmd): """ Implements an interface similar to getstatusoutput(), but with customized unicode handling (see bug #310789) and without the shell. """ args = portage.util.shlex_split(cmd) if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \ not os.path.isabs(args[0]): # Python 3.1 _execvp throws TypeError for non-absolute executable # path passed as bytes (see http://bugs.python.org/issue8513). fullname = find_binary(args[0]) if fullname is None: raise portage.exception.CommandNotFound(args[0]) args[0] = fullname encoding = _encodings['fs'] args = [ _unicode_encode(x, encoding=encoding, errors='strict') for x in args] proc = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = portage._unicode_decode( proc.communicate()[0], encoding=encoding, errors='strict') if output and output[-1] == "\n": # getstatusoutput strips one newline output = output[:-1] return (proc.wait(), output)
def _must_skip(self): xmllint = find_binary("xmllint") if not xmllint: return "xmllint not found" try: __import__("xml.etree.ElementTree") __import__("xml.parsers.expat").parsers.expat.ExpatError except (AttributeError, ImportError): return "python is missing xml support"
def _check_capable(self): if self.options.mode == "manifest": return self.binary = find_binary('xmllint') if not self.binary: print(red("!!! xmllint not found. Can't check metadata.xml.\n")) else: if not fetch_metadata_dtd(self.metadata_dtd, self.repoman_settings): sys.exit(1) # this can be problematic if xmllint changes their output self._is_capable = True
def testCommand(self): input = set(test_cps) command = find_binary("bash") command += " -c '" for a in input: command += " echo -e \"%s\" ; " % a command += "'" s = CommandOutputSet(command) atoms = s.getAtoms() self.assertEqual(atoms, input)
def gpgsign(filename, repoman_settings, options): gpgcmd = repoman_settings.get("PORTAGE_GPG_SIGNING_COMMAND") if gpgcmd in [None, '']: raise MissingParameter("PORTAGE_GPG_SIGNING_COMMAND is unset!" " Is make.globals missing?") if "${PORTAGE_GPG_KEY}" in gpgcmd and \ "PORTAGE_GPG_KEY" not in repoman_settings: raise MissingParameter("PORTAGE_GPG_KEY is unset!") if "${PORTAGE_GPG_DIR}" in gpgcmd: if "PORTAGE_GPG_DIR" not in repoman_settings: repoman_settings["PORTAGE_GPG_DIR"] = \ os.path.expanduser("~/.gnupg") logging.info( "Automatically setting PORTAGE_GPG_DIR to '%s'" % repoman_settings["PORTAGE_GPG_DIR"]) else: repoman_settings["PORTAGE_GPG_DIR"] = \ os.path.expanduser(repoman_settings["PORTAGE_GPG_DIR"]) if not os.access(repoman_settings["PORTAGE_GPG_DIR"], os.X_OK): raise portage.exception.InvalidLocation( "Unable to access directory: PORTAGE_GPG_DIR='%s'" % repoman_settings["PORTAGE_GPG_DIR"]) gpgvars = {"FILE": filename} for k in ("PORTAGE_GPG_DIR", "PORTAGE_GPG_KEY"): v = repoman_settings.get(k) if v is not None: gpgvars[k] = v gpgcmd = portage.util.varexpand(gpgcmd, mydict=gpgvars) if options.pretend: print("(" + gpgcmd + ")") else: # Encode unicode manually for bug #310789. gpgcmd = portage.util.shlex_split(gpgcmd) if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \ not os.path.isabs(gpgcmd[0]): # Python 3.1 _execvp throws TypeError for non-absolute executable # path passed as bytes (see http://bugs.python.org/issue8513). fullname = find_binary(gpgcmd[0]) if fullname is None: raise portage.exception.CommandNotFound(gpgcmd[0]) gpgcmd[0] = fullname gpgcmd = [ _unicode_encode(arg, encoding=_encodings['fs'], errors='strict') for arg in gpgcmd] rValue = subprocess.call(gpgcmd) if rValue == os.EX_OK: os.rename(filename + ".asc", filename) else: raise portage.exception.PortageException( "!!! gpg exited with '" + str(rValue) + "' status")
def __init__(self, cmd): args = portage.util.shlex_split(cmd) if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and not os.path.isabs(args[0]): # Python 3.1 _execvp throws TypeError for non-absolute executable # path passed as bytes (see http://bugs.python.org/issue8513). fullname = find_binary(args[0]) if fullname is None: raise portage.exception.CommandNotFound(args[0]) args[0] = fullname encoding = _encodings["fs"] args = [_unicode_encode(x, encoding=encoding, errors="strict") for x in args] proc = subprocess.Popen(args, stdout=subprocess.PIPE) object.__setattr__(self, "_proc", proc) object.__setattr__(self, "_stdout", codecs.getreader(encoding)(proc.stdout, "strict"))
def validate_cmd_var(v): """ Validate an evironment variable value to see if it contains an executable command as the first token. returns (valid, token_list) where 'valid' is boolean and 'token_list' is the (possibly empty) list of tokens split by shlex. """ invalid = False v_split = shlex_split(v) if not v_split: invalid = True elif os.path.isabs(v_split[0]): invalid = not os.access(v_split[0], os.EX_OK) elif find_binary(v_split[0]) is None: invalid = True return (not invalid, v_split)
def editor_is_executable(editor): """ Given an EDITOR string, validate that it refers to an executable. This uses shlex_split() to split the first component and do a PATH lookup if necessary. @param editor: An EDITOR value from the environment. @type: string @rtype: bool @return: True if an executable is found, False otherwise. """ editor_split = util.shlex_split(editor) if not editor_split: return False filename = editor_split[0] if not os.path.isabs(filename): return find_binary(filename) is not None return os.access(filename, os.X_OK) and os.path.isfile(filename)
def testCat(self): stdin_data = b'hello world' cat_binary = find_binary("cat") self.assertNotEqual(cat_binary, None) cat_binary = cat_binary.encode() def test(loop): proc = loop.run_until_complete( create_subprocess_exec(cat_binary, stdin=subprocess.PIPE, stdout=subprocess.PIPE, loop=loop)) out, err = loop.run_until_complete(proc.communicate(input=stdin_data)) self.assertEqual(loop.run_until_complete(proc.wait()), os.EX_OK) self.assertEqual(out, stdin_data) self._run_test(test)
def testEcho(self): args_tuple = (b'hello', b'world') echo_binary = find_binary("echo") self.assertNotEqual(echo_binary, None) echo_binary = echo_binary.encode() def test(loop): @coroutine def test_coroutine(loop=None): proc = (yield create_subprocess_exec(echo_binary, *args_tuple, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, loop=loop)) out, err = (yield proc.communicate()) self.assertEqual(tuple(out.split()), args_tuple) self.assertEqual(proc.returncode, os.EX_OK) proc = (yield create_subprocess_exec( 'bash', '-c', 'echo foo; echo bar 1>&2;', stdout=subprocess.PIPE, stderr=subprocess.PIPE, loop=loop)) out, err = (yield proc.communicate()) self.assertEqual(out, b'foo\n') self.assertEqual(err, b'bar\n') self.assertEqual(proc.returncode, os.EX_OK) proc = (yield create_subprocess_exec( 'bash', '-c', 'echo foo; echo bar 1>&2;', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, loop=loop)) out, err = (yield proc.communicate()) self.assertEqual(out, b'foo\nbar\n') self.assertEqual(err, None) self.assertEqual(proc.returncode, os.EX_OK) coroutine_return('success') self.assertEqual('success', loop.run_until_complete(test_coroutine(loop=loop))) self._run_test(test)
def testChildWatcher(self): true_binary = find_binary("true") self.assertNotEqual(true_binary, None) initial_policy = asyncio.get_event_loop_policy() if not isinstance(initial_policy, DefaultEventLoopPolicy): asyncio.set_event_loop_policy(DefaultEventLoopPolicy()) loop = None try: try: asyncio.set_child_watcher(None) except NotImplementedError: pass else: self.assertTrue(False) args_tuple = ('hello', 'world') loop = asyncio._wrap_loop() future = loop.create_future() def callback(pid, returncode, *args): future.set_result((pid, returncode, args)) with asyncio.get_child_watcher() as watcher: pids = spawn([true_binary], returnpid=True) watcher.add_child_handler(pids[0], callback, *args_tuple) self.assertEqual( loop.run_until_complete(future), (pids[0], os.EX_OK, args_tuple)) finally: asyncio.set_event_loop_policy(initial_policy) if loop not in (None, global_event_loop()): loop.close() self.assertFalse(global_event_loop().is_closed())
def testSyncLocal(self): debug = False skip_reason = self._must_skip() if skip_reason: self.portage_skip = skip_reason self.assertFalse(True, skip_reason) return repos_conf = textwrap.dedent(""" [DEFAULT] %(default_keys)s [test_repo] location = %(EPREFIX)s/var/repositories/test_repo sync-type = %(sync-type)s sync-depth = %(sync-depth)s sync-uri = file://%(EPREFIX)s/var/repositories/test_repo_sync sync-rcu = %(sync-rcu)s sync-rcu-store-dir = %(EPREFIX)s/var/repositories/test_repo_rcu_storedir auto-sync = %(auto-sync)s %(repo_extra_keys)s """) profile = { "eapi": ("5", ), "package.use.stable.mask": ("dev-libs/A flag", ) } ebuilds = {"dev-libs/A-0": {}} user_config = {'make.conf': ('FEATURES="metadata-transfer"', )} playground = ResolverPlayground(ebuilds=ebuilds, profile=profile, user_config=user_config, debug=debug) settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] homedir = os.path.join(eroot, "home") distdir = os.path.join(eprefix, "distdir") repo = settings.repositories["test_repo"] metadata_dir = os.path.join(repo.location, "metadata") rcu_store_dir = os.path.join( eprefix, 'var/repositories/test_repo_rcu_storedir') cmds = {} for cmd in ("emerge", "emaint"): for bindir in (self.bindir, self.sbindir): path = os.path.join(bindir, cmd) if os.path.exists(path): cmds[cmd] = (portage._python_interpreter, "-b", "-Wd", path) break else: raise AssertionError('%s binary not found in %s or %s' % (cmd, self.bindir, self.sbindir)) git_binary = find_binary("git") git_cmd = (git_binary, ) committer_name = "Gentoo Dev" committer_email = "*****@*****.**" def repos_set_conf(sync_type, dflt_keys=None, xtra_keys=None, auto_sync="yes", sync_rcu=False, sync_depth=None): env["PORTAGE_REPOSITORIES"] = repos_conf % {\ "EPREFIX": eprefix, "sync-type": sync_type, "sync-depth": 0 if sync_depth is None else sync_depth, "sync-rcu": "yes" if sync_rcu else "no", "auto-sync": auto_sync, "default_keys": "" if dflt_keys is None else dflt_keys, "repo_extra_keys": "" if xtra_keys is None else xtra_keys} def alter_ebuild(): with open( os.path.join(repo.location + "_sync", "dev-libs", "A", "A-0.ebuild"), "a") as f: f.write("\n") bump_timestamp() def bump_timestamp(): bump_timestamp.timestamp += datetime.timedelta(seconds=1) with open( os.path.join(repo.location + '_sync', 'metadata', 'timestamp.chk'), 'w') as f: f.write( bump_timestamp.timestamp.strftime( '%s\n' % TIMESTAMP_FORMAT, )) bump_timestamp.timestamp = datetime.datetime.utcnow() bump_timestamp_cmds = ((homedir, bump_timestamp), ) sync_cmds = ( (homedir, cmds["emerge"] + ("--sync", )), (homedir, lambda: self.assertTrue( os.path.exists(os.path.join(repo.location, "dev-libs", "A")), "dev-libs/A expected, but missing")), (homedir, cmds["emaint"] + ("sync", "-A")), ) sync_cmds_auto_sync = ( (homedir, lambda: repos_set_conf("rsync", auto_sync="no")), (homedir, cmds["emerge"] + ("--sync", )), (homedir, lambda: self.assertFalse( os.path.exists(os.path.join(repo.location, "dev-libs", "A")), "dev-libs/A found, expected missing")), (homedir, lambda: repos_set_conf("rsync", auto_sync="yes")), ) rename_repo = ( (homedir, lambda: os.rename(repo.location, repo.location + "_sync")), ) rsync_opts_repos = ( (homedir, alter_ebuild), (homedir, lambda: repos_set_conf( "rsync", None, "sync-rsync-extra-opts = --backup --backup-dir=%s" % _shell_quote(repo.location + "_back"))), (homedir, cmds['emerge'] + ("--sync", )), (homedir, lambda: self.assertTrue(os.path.exists(repo.location + "_back"))), (homedir, lambda: shutil.rmtree(repo.location + "_back")), (homedir, lambda: repos_set_conf("rsync")), ) rsync_opts_repos_default = ( (homedir, alter_ebuild), (homedir, lambda: repos_set_conf( "rsync", "sync-rsync-extra-opts = --backup --backup-dir=%s" % _shell_quote(repo.location + "_back"))), (homedir, cmds['emerge'] + ("--sync", )), (homedir, lambda: self.assertTrue(os.path.exists(repo.location + "_back"))), (homedir, lambda: shutil.rmtree(repo.location + "_back")), (homedir, lambda: repos_set_conf("rsync")), ) rsync_opts_repos_default_ovr = ( (homedir, alter_ebuild), (homedir, lambda: repos_set_conf( "rsync", "sync-rsync-extra-opts = --backup --backup-dir=%s" % _shell_quote(repo.location + "_back_nowhere"), "sync-rsync-extra-opts = --backup --backup-dir=%s" % _shell_quote(repo.location + "_back"))), (homedir, cmds['emerge'] + ("--sync", )), (homedir, lambda: self.assertTrue(os.path.exists(repo.location + "_back"))), (homedir, lambda: shutil.rmtree(repo.location + "_back")), (homedir, lambda: repos_set_conf("rsync")), ) rsync_opts_repos_default_cancel = ( (homedir, alter_ebuild), (homedir, lambda: repos_set_conf( "rsync", "sync-rsync-extra-opts = --backup --backup-dir=%s" % _shell_quote(repo.location + "_back_nowhere" ), "sync-rsync-extra-opts = ")), (homedir, cmds['emerge'] + ("--sync", )), (homedir, lambda: self.assertFalse(os.path.exists(repo.location + "_back")) ), (homedir, lambda: repos_set_conf("rsync")), ) delete_repo_location = ( (homedir, lambda: shutil.rmtree(repo.user_location)), (homedir, lambda: os.mkdir(repo.user_location)), ) delete_rcu_store_dir = ((homedir, lambda: shutil.rmtree(rcu_store_dir)), ) revert_rcu_layout = ( (homedir, lambda: os.rename(repo.user_location, repo.user_location + '.bak') ), (homedir, lambda: os.rename(os.path.realpath(repo.user_location + '.bak'), repo.user_location)), (homedir, lambda: os.unlink(repo.user_location + '.bak')), (homedir, lambda: shutil.rmtree(repo.user_location + '_rcu_storedir')), ) upstream_git_commit = ( ( repo.location + "_sync", git_cmd + ('commit', '--allow-empty', '-m', 'test empty commit'), ), ( repo.location + "_sync", git_cmd + ('commit', '--allow-empty', '-m', 'test empty commit 2'), ), ) delete_sync_repo = ((homedir, lambda: shutil.rmtree(repo.location + "_sync")), ) git_repo_create = ( (repo.location, git_cmd + ( "config", "--global", "user.name", committer_name, )), (repo.location, git_cmd + ( "config", "--global", "user.email", committer_email, )), (repo.location, git_cmd + ("init-db", )), (repo.location, git_cmd + ("add", ".")), (repo.location, git_cmd + ("commit", "-a", "-m", "add whole repo")), ) sync_type_git = ((homedir, lambda: repos_set_conf("git")), ) sync_type_git_shallow = (( homedir, lambda: repos_set_conf("git", sync_depth=1)), ) sync_rsync_rcu = ((homedir, lambda: repos_set_conf("rsync", sync_rcu=True)), ) pythonpath = os.environ.get("PYTHONPATH") if pythonpath is not None and not pythonpath.strip(): pythonpath = None if pythonpath is not None and \ pythonpath.split(":")[0] == PORTAGE_PYM_PATH: pass else: if pythonpath is None: pythonpath = "" else: pythonpath = ":" + pythonpath pythonpath = PORTAGE_PYM_PATH + pythonpath env = { "PORTAGE_OVERRIDE_EPREFIX": eprefix, "DISTDIR": distdir, "GENTOO_COMMITTER_NAME": committer_name, "GENTOO_COMMITTER_EMAIL": committer_email, "HOME": homedir, "PATH": os.environ["PATH"], "PORTAGE_GRPNAME": os.environ["PORTAGE_GRPNAME"], "PORTAGE_USERNAME": os.environ["PORTAGE_USERNAME"], "PYTHONDONTWRITEBYTECODE": os.environ.get("PYTHONDONTWRITEBYTECODE", ""), "PYTHONPATH": pythonpath, } repos_set_conf("rsync") if os.environ.get("SANDBOX_ON") == "1": # avoid problems from nested sandbox instances env["FEATURES"] = "-sandbox -usersandbox" dirs = [homedir, metadata_dir] try: for d in dirs: ensure_dirs(d) timestamp_path = os.path.join(metadata_dir, 'timestamp.chk') with open(timestamp_path, 'w') as f: f.write( bump_timestamp.timestamp.strftime( '%s\n' % TIMESTAMP_FORMAT, )) if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for cwd, cmd in rename_repo + sync_cmds_auto_sync + sync_cmds + \ rsync_opts_repos + rsync_opts_repos_default + \ rsync_opts_repos_default_ovr + rsync_opts_repos_default_cancel + \ bump_timestamp_cmds + sync_rsync_rcu + sync_cmds + delete_rcu_store_dir + \ sync_cmds + revert_rcu_layout + \ delete_repo_location + sync_cmds + sync_cmds + \ bump_timestamp_cmds + sync_cmds + revert_rcu_layout + \ delete_sync_repo + git_repo_create + sync_type_git + \ rename_repo + sync_cmds + upstream_git_commit + sync_cmds + \ sync_type_git_shallow + upstream_git_commit + sync_cmds: if hasattr(cmd, '__call__'): cmd() continue abs_cwd = os.path.join(repo.location, cwd) proc = subprocess.Popen(cmd, cwd=abs_cwd, env=env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "%s failed in %s" % ( cmd, cwd, )) finally: playground.cleanup()
def _start(self): tar_options = "" if "xattr" in self.features: process = subprocess.Popen(["tar", "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) output = process.communicate()[0] if b"--xattrs" in output: tar_options = ["--xattrs", "--xattrs-include='*'"] for x in portage.util.shlex_split(self.env.get("PORTAGE_XATTR_EXCLUDE", "")): tar_options.append(portage._shell_quote("--xattrs-exclude=%s" % x)) tar_options = " ".join(tar_options) decomp = _compressors.get(compression_probe(self.pkg_path)) if decomp is not None: decomp_cmd = decomp.get("decompress") else: decomp_cmd = None if decomp_cmd is None: self.scheduler.output("!!! %s\n" % _("File compression header unrecognized: %s") % self.pkg_path, log_path=self.logfile, background=self.background, level=logging.ERROR) self.returncode = 1 self._async_wait() return try: decompression_binary = shlex_split(varexpand(decomp_cmd, mydict=self.env))[0] except IndexError: decompression_binary = "" if find_binary(decompression_binary) is None: # Try alternative command if it exists if _compressors.get(compression_probe(self.pkg_path)).get("decompress_alt"): decomp_cmd = _compressors.get( compression_probe(self.pkg_path)).get("decompress_alt") try: decompression_binary = shlex_split(varexpand(decomp_cmd, mydict=self.env))[0] except IndexError: decompression_binary = "" if find_binary(decompression_binary) is None: missing_package = _compressors.get(compression_probe(self.pkg_path)).get("package") self.scheduler.output("!!! %s\n" % _("File compression unsupported %s.\n Command was: %s.\n Maybe missing package: %s") % (self.pkg_path, varexpand(decomp_cmd, mydict=self.env), missing_package), log_path=self.logfile, background=self.background, level=logging.ERROR) self.returncode = 1 self._async_wait() return pkg_xpak = portage.xpak.tbz2(self.pkg_path) pkg_xpak.scan() # SIGPIPE handling (128 + SIGPIPE) should be compatible with # assert_sigpipe_ok() that's used by the ebuild unpack() helper. self.args = [self._shell_binary, "-c", ("cmd0=(head -c %d -- %s) cmd1=(%s) cmd2=(tar -xp %s -C %s -f -); " + \ '"${cmd0[@]}" | "${cmd1[@]}" | "${cmd2[@]}"; ' + \ "p=(${PIPESTATUS[@]}) ; for i in {0..2}; do " + \ "if [[ ${p[$i]} != 0 && ${p[$i]} != %d ]] ; then " + \ "echo command $(eval \"echo \\\"'\\${cmd$i[*]}'\\\"\") " + \ "failed with status ${p[$i]} ; exit ${p[$i]} ; fi ; done; " + \ "if [ ${p[$i]} != 0 ] ; then " + \ "echo command $(eval \"echo \\\"'\\${cmd$i[*]}'\\\"\") " + \ "failed with status ${p[$i]} ; exit ${p[$i]} ; fi ; " + \ "exit 0 ;") % \ (pkg_xpak.filestat.st_size - pkg_xpak.xpaksize, portage._shell_quote(self.pkg_path), decomp_cmd, tar_options, portage._shell_quote(self.image_dir), 128 + signal.SIGPIPE)] SpawnProcess._start(self)
def testSyncLocal(self): debug = False skip_reason = self._must_skip() if skip_reason: self.portage_skip = skip_reason self.assertFalse(True, skip_reason) return repos_conf = textwrap.dedent(""" [DEFAULT] %(default_keys)s [test_repo] location = %(EPREFIX)s/var/repositories/test_repo sync-type = %(sync-type)s sync-uri = file://%(EPREFIX)s/var/repositories/test_repo_sync auto-sync = %(auto-sync)s %(repo_extra_keys)s """) profile = { "eapi": ("5",), "package.use.stable.mask": ("dev-libs/A flag",) } ebuilds = { "dev-libs/A-0": {} } user_config = { 'make.conf': ('FEATURES="metadata-transfer"',) } playground = ResolverPlayground(ebuilds=ebuilds, profile=profile, user_config=user_config, debug=debug) settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] homedir = os.path.join(eroot, "home") distdir = os.path.join(eprefix, "distdir") repo = settings.repositories["test_repo"] metadata_dir = os.path.join(repo.location, "metadata") cmds = {} for cmd in ("emerge", "emaint"): path = os.path.join(self.bindir, cmd) assert os.path.exists(path) cmds[cmd] = (portage._python_interpreter, "-b", "-Wd", path) git_binary = find_binary("git") git_cmd = (git_binary,) committer_name = "Gentoo Dev" committer_email = "*****@*****.**" def repos_set_conf(sync_type, dflt_keys=None, xtra_keys=None, auto_sync="yes"): env["PORTAGE_REPOSITORIES"] = repos_conf % {\ "EPREFIX": eprefix, "sync-type": sync_type, "auto-sync": auto_sync, "default_keys": "" if dflt_keys is None else dflt_keys, "repo_extra_keys": "" if xtra_keys is None else xtra_keys} def alter_ebuild(): with open(os.path.join(repo.location + "_sync", "dev-libs", "A", "A-0.ebuild"), "a") as f: f.write("\n") os.unlink(os.path.join(metadata_dir, 'timestamp.chk')) sync_cmds = ( (homedir, cmds["emerge"] + ("--sync",)), (homedir, lambda: self.assertTrue(os.path.exists( os.path.join(repo.location, "dev-libs", "A") ), "dev-libs/A expected, but missing")), (homedir, cmds["emaint"] + ("sync", "-A")), ) sync_cmds_auto_sync = ( (homedir, lambda: repos_set_conf("rsync", auto_sync="no")), (homedir, cmds["emerge"] + ("--sync",)), (homedir, lambda: self.assertFalse(os.path.exists( os.path.join(repo.location, "dev-libs", "A") ), "dev-libs/A found, expected missing")), (homedir, lambda: repos_set_conf("rsync", auto_sync="yes")), ) rename_repo = ( (homedir, lambda: os.rename(repo.location, repo.location + "_sync")), ) rsync_opts_repos = ( (homedir, alter_ebuild), (homedir, lambda: repos_set_conf("rsync", None, "sync-rsync-extra-opts = --backup --backup-dir=%s" % _shell_quote(repo.location + "_back"))), (homedir, cmds['emerge'] + ("--sync",)), (homedir, lambda: self.assertTrue(os.path.exists( repo.location + "_back"))), (homedir, lambda: shutil.rmtree(repo.location + "_back")), (homedir, lambda: repos_set_conf("rsync")), ) rsync_opts_repos_default = ( (homedir, alter_ebuild), (homedir, lambda: repos_set_conf("rsync", "sync-rsync-extra-opts = --backup --backup-dir=%s" % _shell_quote(repo.location+"_back"))), (homedir, cmds['emerge'] + ("--sync",)), (homedir, lambda: self.assertTrue(os.path.exists(repo.location + "_back"))), (homedir, lambda: shutil.rmtree(repo.location + "_back")), (homedir, lambda: repos_set_conf("rsync")), ) rsync_opts_repos_default_ovr = ( (homedir, alter_ebuild), (homedir, lambda: repos_set_conf("rsync", "sync-rsync-extra-opts = --backup --backup-dir=%s" % _shell_quote(repo.location + "_back_nowhere"), "sync-rsync-extra-opts = --backup --backup-dir=%s" % _shell_quote(repo.location + "_back"))), (homedir, cmds['emerge'] + ("--sync",)), (homedir, lambda: self.assertTrue(os.path.exists(repo.location + "_back"))), (homedir, lambda: shutil.rmtree(repo.location + "_back")), (homedir, lambda: repos_set_conf("rsync")), ) rsync_opts_repos_default_cancel = ( (homedir, alter_ebuild), (homedir, lambda: repos_set_conf("rsync", "sync-rsync-extra-opts = --backup --backup-dir=%s" % _shell_quote(repo.location + "_back_nowhere"), "sync-rsync-extra-opts = ")), (homedir, cmds['emerge'] + ("--sync",)), (homedir, lambda: self.assertFalse(os.path.exists(repo.location + "_back"))), (homedir, lambda: repos_set_conf("rsync")), ) delete_sync_repo = ( (homedir, lambda: shutil.rmtree( repo.location + "_sync")), ) git_repo_create = ( (repo.location, git_cmd + ("config", "--global", "user.name", committer_name,)), (repo.location, git_cmd + ("config", "--global", "user.email", committer_email,)), (repo.location, git_cmd + ("init-db",)), (repo.location, git_cmd + ("add", ".")), (repo.location, git_cmd + ("commit", "-a", "-m", "add whole repo")), ) sync_type_git = ( (homedir, lambda: repos_set_conf("git")), ) pythonpath = os.environ.get("PYTHONPATH") if pythonpath is not None and not pythonpath.strip(): pythonpath = None if pythonpath is not None and \ pythonpath.split(":")[0] == PORTAGE_PYM_PATH: pass else: if pythonpath is None: pythonpath = "" else: pythonpath = ":" + pythonpath pythonpath = PORTAGE_PYM_PATH + pythonpath env = { "PORTAGE_OVERRIDE_EPREFIX" : eprefix, "DISTDIR" : distdir, "GENTOO_COMMITTER_NAME" : committer_name, "GENTOO_COMMITTER_EMAIL" : committer_email, "HOME" : homedir, "PATH" : os.environ["PATH"], "PORTAGE_GRPNAME" : os.environ["PORTAGE_GRPNAME"], "PORTAGE_USERNAME" : os.environ["PORTAGE_USERNAME"], "PYTHONDONTWRITEBYTECODE" : os.environ.get("PYTHONDONTWRITEBYTECODE", ""), "PYTHONPATH" : pythonpath, } repos_set_conf("rsync") if os.environ.get("SANDBOX_ON") == "1": # avoid problems from nested sandbox instances env["FEATURES"] = "-sandbox -usersandbox" dirs = [homedir, metadata_dir] try: for d in dirs: ensure_dirs(d) timestamp_path = os.path.join(metadata_dir, 'timestamp.chk') with open(timestamp_path, 'w') as f: f.write(time.strftime('%s\n' % TIMESTAMP_FORMAT, time.gmtime())) if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for cwd, cmd in rename_repo + sync_cmds_auto_sync + sync_cmds + \ rsync_opts_repos + rsync_opts_repos_default + \ rsync_opts_repos_default_ovr + rsync_opts_repos_default_cancel + \ delete_sync_repo + git_repo_create + sync_type_git + \ rename_repo + sync_cmds: if hasattr(cmd, '__call__'): cmd() continue abs_cwd = os.path.join(repo.location, cwd) proc = subprocess.Popen(cmd, cwd=abs_cwd, env=env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "%s failed in %s" % (cmd, cwd,)) finally: playground.cleanup()
def testConfigProtect(self): """ Demonstrates many different scenarios. For example: * regular file replaces regular file * regular file replaces symlink * regular file replaces directory * symlink replaces symlink * symlink replaces regular file * symlink replaces directory * directory replaces regular file * directory replaces symlink """ debug = False content_A_1 = """ S="${WORKDIR}" src_install() { insinto /etc/A keepdir /etc/A/dir_a keepdir /etc/A/symlink_replaces_dir keepdir /etc/A/regular_replaces_dir echo regular_a_1 > "${T}"/regular_a doins "${T}"/regular_a echo regular_b_1 > "${T}"/regular_b doins "${T}"/regular_b dosym regular_a /etc/A/regular_replaces_symlink dosym regular_b /etc/A/symlink_replaces_symlink echo regular_replaces_regular_1 > \ "${T}"/regular_replaces_regular doins "${T}"/regular_replaces_regular echo symlink_replaces_regular > \ "${T}"/symlink_replaces_regular doins "${T}"/symlink_replaces_regular } """ content_A_2 = """ S="${WORKDIR}" src_install() { insinto /etc/A keepdir /etc/A/dir_a dosym dir_a /etc/A/symlink_replaces_dir echo regular_replaces_dir > "${T}"/regular_replaces_dir doins "${T}"/regular_replaces_dir echo regular_a_2 > "${T}"/regular_a doins "${T}"/regular_a echo regular_b_2 > "${T}"/regular_b doins "${T}"/regular_b echo regular_replaces_symlink > \ "${T}"/regular_replaces_symlink doins "${T}"/regular_replaces_symlink dosym regular_b /etc/A/symlink_replaces_symlink echo regular_replaces_regular_2 > \ "${T}"/regular_replaces_regular doins "${T}"/regular_replaces_regular dosym regular_a /etc/A/symlink_replaces_regular } """ ebuilds = { "dev-libs/A-1": { "EAPI" : "5", "IUSE" : "+flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "MISC_CONTENT": content_A_1, }, "dev-libs/A-2": { "EAPI" : "5", "IUSE" : "+flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "MISC_CONTENT": content_A_2, }, } playground = ResolverPlayground( ebuilds=ebuilds, debug=debug) settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] var_cache_edb = os.path.join(eprefix, "var", "cache", "edb") portage_python = portage._python_interpreter dispatch_conf_cmd = (portage_python, "-b", "-Wd", os.path.join(self.sbindir, "dispatch-conf")) emerge_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "emerge")) etc_update_cmd = (BASH_BINARY, os.path.join(self.sbindir, "etc-update")) etc_update_auto = etc_update_cmd + ("--automode", "-5",) config_protect = "/etc" def modify_files(dir_path): for name in os.listdir(dir_path): path = os.path.join(dir_path, name) st = os.lstat(path) if stat.S_ISREG(st.st_mode): with io.open(path, mode='a', encoding=_encodings["stdio"]) as f: f.write("modified at %d\n" % time.time()) elif stat.S_ISLNK(st.st_mode): old_dest = os.readlink(path) os.unlink(path) os.symlink(old_dest + " modified at %d" % time.time(), path) def updated_config_files(count): self.assertEqual(count, sum(len(x[1]) for x in find_updated_config_files(eroot, shlex_split(config_protect)))) test_commands = ( etc_update_cmd, dispatch_conf_cmd, emerge_cmd + ("-1", "=dev-libs/A-1"), partial(updated_config_files, 0), emerge_cmd + ("-1", "=dev-libs/A-2"), partial(updated_config_files, 2), etc_update_auto, partial(updated_config_files, 0), emerge_cmd + ("-1", "=dev-libs/A-2"), partial(updated_config_files, 0), # Test bug #523684, where a file renamed or removed by the # admin forces replacement files to be merged with config # protection. partial(shutil.rmtree, os.path.join(eprefix, "etc", "A")), emerge_cmd + ("-1", "=dev-libs/A-2"), partial(updated_config_files, 8), etc_update_auto, partial(updated_config_files, 0), # Modify some config files, and verify that it triggers # config protection. partial(modify_files, os.path.join(eroot, "etc", "A")), emerge_cmd + ("-1", "=dev-libs/A-2"), partial(updated_config_files, 6), etc_update_auto, partial(updated_config_files, 0), # Modify some config files, downgrade to A-1, and verify # that config protection works properly when the file # types are changing. partial(modify_files, os.path.join(eroot, "etc", "A")), emerge_cmd + ("-1", "--noconfmem", "=dev-libs/A-1"), partial(updated_config_files, 6), etc_update_auto, partial(updated_config_files, 0), ) distdir = playground.distdir fake_bin = os.path.join(eprefix, "bin") portage_tmpdir = os.path.join(eprefix, "var", "tmp", "portage") path = os.environ.get("PATH") if path is not None and not path.strip(): path = None if path is None: path = "" else: path = ":" + path path = fake_bin + path pythonpath = os.environ.get("PYTHONPATH") if pythonpath is not None and not pythonpath.strip(): pythonpath = None if pythonpath is not None and \ pythonpath.split(":")[0] == PORTAGE_PYM_PATH: pass else: if pythonpath is None: pythonpath = "" else: pythonpath = ":" + pythonpath pythonpath = PORTAGE_PYM_PATH + pythonpath env = { "PORTAGE_OVERRIDE_EPREFIX" : eprefix, "CLEAN_DELAY" : "0", "CONFIG_PROTECT": config_protect, "DISTDIR" : distdir, "EMERGE_DEFAULT_OPTS": "-v", "EMERGE_WARNING_DELAY" : "0", "INFODIR" : "", "INFOPATH" : "", "PATH" : path, "PORTAGE_INST_GID" : str(portage.data.portage_gid), "PORTAGE_INST_UID" : str(portage.data.portage_uid), "PORTAGE_PYTHON" : portage_python, "PORTAGE_REPOSITORIES" : settings.repositories.config_string(), "PORTAGE_TMPDIR" : portage_tmpdir, "PYTHONPATH" : pythonpath, "__PORTAGE_TEST_PATH_OVERRIDE" : fake_bin, } if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: env["__PORTAGE_TEST_HARDLINK_LOCKS"] = \ os.environ["__PORTAGE_TEST_HARDLINK_LOCKS"] dirs = [distdir, fake_bin, portage_tmpdir, var_cache_edb] etc_symlinks = ("dispatch-conf.conf", "etc-update.conf") # Override things that may be unavailable, or may have portability # issues when running tests in exotic environments. # prepstrip - bug #447810 (bash read builtin EINTR problem) true_symlinks = ["prepstrip", "scanelf"] true_binary = find_binary("true") self.assertEqual(true_binary is None, False, "true command not found") try: for d in dirs: ensure_dirs(d) for x in true_symlinks: os.symlink(true_binary, os.path.join(fake_bin, x)) for x in etc_symlinks: os.symlink(os.path.join(self.cnf_etc_path, x), os.path.join(eprefix, "etc", x)) with open(os.path.join(var_cache_edb, "counter"), 'wb') as f: f.write(b"100") if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for args in test_commands: if hasattr(args, '__call__'): args() continue if isinstance(args[0], dict): local_env = env.copy() local_env.update(args[0]) args = args[1:] else: local_env = env proc = subprocess.Popen(args, env=local_env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "emerge failed with args %s" % (args,)) finally: playground.cleanup()
def _async_test_simple(self, playground, metadata_xml_files, loop=None): debug = playground.debug settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] trees = playground.trees portdb = trees[eroot]["porttree"].dbapi test_repo_location = settings.repositories["test_repo"].location var_cache_edb = os.path.join(eprefix, "var", "cache", "edb") cachedir = os.path.join(var_cache_edb, "dep") cachedir_pregen = os.path.join(test_repo_location, "metadata", "md5-cache") portage_python = portage._python_interpreter dispatch_conf_cmd = (portage_python, "-b", "-Wd", os.path.join(self.sbindir, "dispatch-conf")) ebuild_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "ebuild")) egencache_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "egencache"), "--repo", "test_repo", "--repositories-configuration", settings.repositories.config_string()) emerge_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "emerge")) emaint_cmd = (portage_python, "-b", "-Wd", os.path.join(self.sbindir, "emaint")) env_update_cmd = (portage_python, "-b", "-Wd", os.path.join(self.sbindir, "env-update")) etc_update_cmd = (BASH_BINARY, os.path.join(self.sbindir, "etc-update")) fixpackages_cmd = (portage_python, "-b", "-Wd", os.path.join(self.sbindir, "fixpackages")) portageq_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "portageq")) quickpkg_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "quickpkg")) regenworld_cmd = (portage_python, "-b", "-Wd", os.path.join(self.sbindir, "regenworld")) rm_binary = find_binary("rm") self.assertEqual(rm_binary is None, False, "rm command not found") rm_cmd = (rm_binary, ) egencache_extra_args = [] if self._have_python_xml(): egencache_extra_args.append("--update-use-local-desc") test_ebuild = portdb.findname("dev-libs/A-1") self.assertFalse(test_ebuild is None) cross_prefix = os.path.join(eprefix, "cross_prefix") cross_root = os.path.join(eprefix, "cross_root") cross_eroot = os.path.join(cross_root, eprefix.lstrip(os.sep)) binhost_dir = os.path.join(eprefix, "binhost") binhost_address = '127.0.0.1' binhost_remote_path = '/binhost' binhost_server = AsyncHTTPServer( binhost_address, BinhostContentMap(binhost_remote_path, binhost_dir), loop).__enter__() binhost_uri = 'http://{address}:{port}{path}'.format( address=binhost_address, port=binhost_server.server_port, path=binhost_remote_path) test_commands = ( emerge_cmd + ("--usepkgonly", "--root", cross_root, "--quickpkg-direct=y", "dev-libs/A"), env_update_cmd, portageq_cmd + ("envvar", "-v", "CONFIG_PROTECT", "EROOT", "PORTAGE_CONFIGROOT", "PORTAGE_TMPDIR", "USERLAND"), etc_update_cmd, dispatch_conf_cmd, emerge_cmd + ("--version",), emerge_cmd + ("--info",), emerge_cmd + ("--info", "--verbose"), emerge_cmd + ("--list-sets",), emerge_cmd + ("--check-news",), rm_cmd + ("-rf", cachedir), rm_cmd + ("-rf", cachedir_pregen), emerge_cmd + ("--regen",), rm_cmd + ("-rf", cachedir), ({"FEATURES" : "metadata-transfer"},) + \ emerge_cmd + ("--regen",), rm_cmd + ("-rf", cachedir), ({"FEATURES" : "metadata-transfer"},) + \ emerge_cmd + ("--regen",), rm_cmd + ("-rf", cachedir), egencache_cmd + ("--update",) + tuple(egencache_extra_args), ({"FEATURES" : "metadata-transfer"},) + \ emerge_cmd + ("--metadata",), rm_cmd + ("-rf", cachedir), ({"FEATURES" : "metadata-transfer"},) + \ emerge_cmd + ("--metadata",), emerge_cmd + ("--metadata",), rm_cmd + ("-rf", cachedir), emerge_cmd + ("--oneshot", "virtual/foo"), lambda: self.assertFalse(os.path.exists( os.path.join(pkgdir, "virtual", "foo-0.tbz2"))), ({"FEATURES" : "unmerge-backup"},) + \ emerge_cmd + ("--unmerge", "virtual/foo"), lambda: self.assertTrue(os.path.exists( os.path.join(pkgdir, "virtual", "foo-0.tbz2"))), emerge_cmd + ("--pretend", "dev-libs/A"), ebuild_cmd + (test_ebuild, "manifest", "clean", "package", "merge"), emerge_cmd + ("--pretend", "--tree", "--complete-graph", "dev-libs/A"), emerge_cmd + ("-p", "dev-libs/B"), emerge_cmd + ("-p", "--newrepo", "dev-libs/B"), emerge_cmd + ("-B", "dev-libs/B",), emerge_cmd + ("--oneshot", "--usepkg", "dev-libs/B",), # trigger clean prior to pkg_pretend as in bug #390711 ebuild_cmd + (test_ebuild, "unpack"), emerge_cmd + ("--oneshot", "dev-libs/A",), emerge_cmd + ("--noreplace", "dev-libs/A",), emerge_cmd + ("--config", "dev-libs/A",), emerge_cmd + ("--info", "dev-libs/A", "dev-libs/B"), emerge_cmd + ("--pretend", "--depclean", "--verbose", "dev-libs/B"), emerge_cmd + ("--pretend", "--depclean",), emerge_cmd + ("--depclean",), quickpkg_cmd + ("--include-config", "y", "dev-libs/A",), # Test bug #523684, where a file renamed or removed by the # admin forces replacement files to be merged with config # protection. lambda: self.assertEqual(0, len(list(find_updated_config_files(eroot, shlex_split(settings["CONFIG_PROTECT"]))))), lambda: os.unlink(os.path.join(eprefix, "etc", "A-0")), emerge_cmd + ("--usepkgonly", "dev-libs/A"), lambda: self.assertEqual(1, len(list(find_updated_config_files(eroot, shlex_split(settings["CONFIG_PROTECT"]))))), emaint_cmd + ("--check", "all"), emaint_cmd + ("--fix", "all"), fixpackages_cmd, regenworld_cmd, portageq_cmd + ("match", eroot, "dev-libs/A"), portageq_cmd + ("best_visible", eroot, "dev-libs/A"), portageq_cmd + ("best_visible", eroot, "binary", "dev-libs/A"), portageq_cmd + ("contents", eroot, "dev-libs/A-1"), portageq_cmd + ("metadata", eroot, "ebuild", "dev-libs/A-1", "EAPI", "IUSE", "RDEPEND"), portageq_cmd + ("metadata", eroot, "binary", "dev-libs/A-1", "EAPI", "USE", "RDEPEND"), portageq_cmd + ("metadata", eroot, "installed", "dev-libs/A-1", "EAPI", "USE", "RDEPEND"), portageq_cmd + ("owners", eroot, eroot + "usr"), emerge_cmd + ("-p", eroot + "usr"), emerge_cmd + ("-p", "--unmerge", "-q", eroot + "usr"), emerge_cmd + ("--unmerge", "--quiet", "dev-libs/A"), emerge_cmd + ("-C", "--quiet", "dev-libs/B"), # If EMERGE_DEFAULT_OPTS contains --autounmask=n, then --autounmask # must be specified with --autounmask-continue. ({"EMERGE_DEFAULT_OPTS" : "--autounmask=n"},) + \ emerge_cmd + ("--autounmask", "--autounmask-continue", "dev-libs/C",), # Verify that the above --autounmask-continue command caused # USE=flag to be applied correctly to dev-libs/D. portageq_cmd + ("match", eroot, "dev-libs/D[flag]"), # Test cross-prefix usage, including chpathtool for binpkgs. # EAPI 7 ({"EPREFIX" : cross_prefix},) + \ emerge_cmd + ("dev-libs/C",), ({"EPREFIX" : cross_prefix},) + \ portageq_cmd + ("has_version", cross_prefix, "dev-libs/C"), ({"EPREFIX" : cross_prefix},) + \ portageq_cmd + ("has_version", cross_prefix, "dev-libs/D"), ({"ROOT": cross_root},) + emerge_cmd + ("dev-libs/D",), portageq_cmd + ("has_version", cross_eroot, "dev-libs/D"), # EAPI 5 ({"EPREFIX" : cross_prefix},) + \ emerge_cmd + ("--usepkgonly", "dev-libs/A"), ({"EPREFIX" : cross_prefix},) + \ portageq_cmd + ("has_version", cross_prefix, "dev-libs/A"), ({"EPREFIX" : cross_prefix},) + \ portageq_cmd + ("has_version", cross_prefix, "dev-libs/B"), ({"EPREFIX" : cross_prefix},) + \ emerge_cmd + ("-C", "--quiet", "dev-libs/B"), ({"EPREFIX" : cross_prefix},) + \ emerge_cmd + ("-C", "--quiet", "dev-libs/A"), ({"EPREFIX" : cross_prefix},) + \ emerge_cmd + ("dev-libs/A",), ({"EPREFIX" : cross_prefix},) + \ portageq_cmd + ("has_version", cross_prefix, "dev-libs/A"), ({"EPREFIX" : cross_prefix},) + \ portageq_cmd + ("has_version", cross_prefix, "dev-libs/B"), # Test ROOT support ({"ROOT": cross_root},) + emerge_cmd + ("dev-libs/B",), portageq_cmd + ("has_version", cross_eroot, "dev-libs/B"), ) # Test binhost support if FETCHCOMMAND is available. binrepos_conf_file = os.path.join(os.sep, eprefix, BINREPOS_CONF_FILE) with open(binrepos_conf_file, 'wt') as f: f.write('[test-binhost]\n') f.write('sync-uri = {}\n'.format(binhost_uri)) fetchcommand = portage.util.shlex_split( playground.settings['FETCHCOMMAND']) fetch_bin = portage.process.find_binary(fetchcommand[0]) if fetch_bin is not None: test_commands = test_commands + ( lambda: os.rename(pkgdir, binhost_dir), emerge_cmd + ("-e", "--getbinpkgonly", "dev-libs/A"), lambda: shutil.rmtree(pkgdir), lambda: os.rename(binhost_dir, pkgdir), # Remove binrepos.conf and test PORTAGE_BINHOST. lambda: os.unlink(binrepos_conf_file), lambda: os.rename(pkgdir, binhost_dir), ({"PORTAGE_BINHOST": binhost_uri},) + \ emerge_cmd + ("-fe", "--getbinpkgonly", "dev-libs/A"), lambda: shutil.rmtree(pkgdir), lambda: os.rename(binhost_dir, pkgdir), ) distdir = playground.distdir pkgdir = playground.pkgdir fake_bin = os.path.join(eprefix, "bin") portage_tmpdir = os.path.join(eprefix, "var", "tmp", "portage") profile_path = settings.profile_path user_config_dir = os.path.join(os.sep, eprefix, USER_CONFIG_PATH) path = os.environ.get("PATH") if path is not None and not path.strip(): path = None if path is None: path = "" else: path = ":" + path path = fake_bin + path pythonpath = os.environ.get("PYTHONPATH") if pythonpath is not None and not pythonpath.strip(): pythonpath = None if pythonpath is not None and \ pythonpath.split(":")[0] == PORTAGE_PYM_PATH: pass else: if pythonpath is None: pythonpath = "" else: pythonpath = ":" + pythonpath pythonpath = PORTAGE_PYM_PATH + pythonpath env = { "PORTAGE_OVERRIDE_EPREFIX": eprefix, "CLEAN_DELAY": "0", "DISTDIR": distdir, "EMERGE_WARNING_DELAY": "0", "INFODIR": "", "INFOPATH": "", "PATH": path, "PKGDIR": pkgdir, "PORTAGE_INST_GID": str(portage.data.portage_gid), "PORTAGE_INST_UID": str(portage.data.portage_uid), "PORTAGE_PYTHON": portage_python, "PORTAGE_REPOSITORIES": settings.repositories.config_string(), "PORTAGE_TMPDIR": portage_tmpdir, "PORTAGE_LOGDIR": portage_tmpdir, "PYTHONDONTWRITEBYTECODE": os.environ.get("PYTHONDONTWRITEBYTECODE", ""), "PYTHONPATH": pythonpath, "__PORTAGE_TEST_PATH_OVERRIDE": fake_bin, } if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: env["__PORTAGE_TEST_HARDLINK_LOCKS"] = \ os.environ["__PORTAGE_TEST_HARDLINK_LOCKS"] updates_dir = os.path.join(test_repo_location, "profiles", "updates") dirs = [ cachedir, cachedir_pregen, cross_eroot, cross_prefix, distdir, fake_bin, portage_tmpdir, updates_dir, user_config_dir, var_cache_edb ] etc_symlinks = ("dispatch-conf.conf", "etc-update.conf") # Override things that may be unavailable, or may have portability # issues when running tests in exotic environments. # prepstrip - bug #447810 (bash read builtin EINTR problem) true_symlinks = ["find", "prepstrip", "sed", "scanelf"] true_binary = find_binary("true") self.assertEqual(true_binary is None, False, "true command not found") try: for d in dirs: ensure_dirs(d) for x in true_symlinks: os.symlink(true_binary, os.path.join(fake_bin, x)) for x in etc_symlinks: os.symlink(os.path.join(self.cnf_etc_path, x), os.path.join(eprefix, "etc", x)) with open(os.path.join(var_cache_edb, "counter"), 'wb') as f: f.write(b"100") # non-empty system set keeps --depclean quiet with open(os.path.join(profile_path, "packages"), 'w') as f: f.write("*dev-libs/token-system-pkg") for cp, xml_data in metadata_xml_files: with open(os.path.join(test_repo_location, cp, "metadata.xml"), 'w') as f: f.write(playground.metadata_xml_template % xml_data) with open(os.path.join(updates_dir, "1Q-2010"), 'w') as f: f.write(""" slotmove =app-doc/pms-3 2 3 move dev-util/git dev-vcs/git """) if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for args in test_commands: if hasattr(args, '__call__'): args() continue if isinstance(args[0], dict): local_env = env.copy() local_env.update(args[0]) args = args[1:] else: local_env = env proc = yield asyncio.create_subprocess_exec(*args, env=local_env, stderr=None, stdout=stdout, loop=loop) if debug: yield proc.wait() else: output, _err = yield proc.communicate() yield proc.wait() if proc.returncode != os.EX_OK: portage.writemsg(output) self.assertEqual(os.EX_OK, proc.returncode, "emerge failed with args %s" % (args, )) finally: binhost_server.__exit__(None, None, None) playground.cleanup()
def testBlockerFileCollision(self): debug = False install_something = """ S="${WORKDIR}" src_install() { einfo "installing something..." insinto /usr/lib echo "${PN}" > "${T}/file-collision" doins "${T}/file-collision" } """ ebuilds = { "dev-libs/A-1" : { "EAPI": "6", "MISC_CONTENT": install_something, "RDEPEND": "!dev-libs/B", }, "dev-libs/B-1" : { "EAPI": "6", "MISC_CONTENT": install_something, "RDEPEND": "!dev-libs/A", }, } playground = ResolverPlayground(ebuilds=ebuilds, debug=debug) settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] var_cache_edb = os.path.join(eprefix, "var", "cache", "edb") user_config_dir = os.path.join(eprefix, USER_CONFIG_PATH) portage_python = portage._python_interpreter emerge_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "emerge")) file_collision = os.path.join(eroot, 'usr/lib/file-collision') test_commands = ( emerge_cmd + ("--oneshot", "dev-libs/A",), (lambda: portage.util.grablines(file_collision) == ["A\n"],), emerge_cmd + ("--oneshot", "dev-libs/B",), (lambda: portage.util.grablines(file_collision) == ["B\n"],), emerge_cmd + ("--oneshot", "dev-libs/A",), (lambda: portage.util.grablines(file_collision) == ["A\n"],), ({"FEATURES":"parallel-install"},) + emerge_cmd + ("--oneshot", "dev-libs/B",), (lambda: portage.util.grablines(file_collision) == ["B\n"],), ({"FEATURES":"parallel-install"},) + emerge_cmd + ("-Cq", "dev-libs/B",), (lambda: not os.path.exists(file_collision),), ) fake_bin = os.path.join(eprefix, "bin") portage_tmpdir = os.path.join(eprefix, "var", "tmp", "portage") profile_path = settings.profile_path path = os.environ.get("PATH") if path is not None and not path.strip(): path = None if path is None: path = "" else: path = ":" + path path = fake_bin + path pythonpath = os.environ.get("PYTHONPATH") if pythonpath is not None and not pythonpath.strip(): pythonpath = None if pythonpath is not None and \ pythonpath.split(":")[0] == PORTAGE_PYM_PATH: pass else: if pythonpath is None: pythonpath = "" else: pythonpath = ":" + pythonpath pythonpath = PORTAGE_PYM_PATH + pythonpath env = { "PORTAGE_OVERRIDE_EPREFIX" : eprefix, "PATH" : path, "PORTAGE_PYTHON" : portage_python, "PORTAGE_REPOSITORIES" : settings.repositories.config_string(), "PYTHONDONTWRITEBYTECODE" : os.environ.get("PYTHONDONTWRITEBYTECODE", ""), "PYTHONPATH" : pythonpath, } if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: env["__PORTAGE_TEST_HARDLINK_LOCKS"] = \ os.environ["__PORTAGE_TEST_HARDLINK_LOCKS"] dirs = [playground.distdir, fake_bin, portage_tmpdir, user_config_dir, var_cache_edb] true_symlinks = ["chown", "chgrp"] true_binary = find_binary("true") self.assertEqual(true_binary is None, False, "true command not found") try: for d in dirs: ensure_dirs(d) for x in true_symlinks: os.symlink(true_binary, os.path.join(fake_bin, x)) with open(os.path.join(var_cache_edb, "counter"), 'wb') as f: f.write(b"100") # non-empty system set keeps --unmerge quiet with open(os.path.join(profile_path, "packages"), 'w') as f: f.write("*dev-libs/token-system-pkg") if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for i, args in enumerate(test_commands): if hasattr(args[0], '__call__'): self.assertTrue(args[0](), "callable at index %s failed" % (i,)) continue if isinstance(args[0], dict): local_env = env.copy() local_env.update(args[0]) args = args[1:] else: local_env = env proc = subprocess.Popen(args, env=local_env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "emerge failed with args %s" % (args,)) finally: playground.debug = False playground.cleanup()
def testSlotAbiEmerge(self): debug = False ebuilds = { "dev-libs/glib-1.2.10" : { "SLOT": "1" }, "dev-libs/glib-2.30.2" : { "EAPI": "4-slot-abi", "SLOT": "2/2.30" }, "dev-libs/glib-2.32.3" : { "EAPI": "4-slot-abi", "SLOT": "2/2.32" }, "dev-libs/dbus-glib-0.98" : { "EAPI": "4-slot-abi", "DEPEND": "dev-libs/glib:2=", "RDEPEND": "dev-libs/glib:2=" }, } installed = { "dev-libs/glib-1.2.10" : { "EAPI": "4-slot-abi", "SLOT": "1" }, "dev-libs/glib-2.30.2" : { "EAPI": "4-slot-abi", "SLOT": "2/2.30" }, "dev-libs/dbus-glib-0.98" : { "EAPI": "4-slot-abi", "DEPEND": "dev-libs/glib:2/2.30=", "RDEPEND": "dev-libs/glib:2/2.30=" }, } world = ["dev-libs/glib:1", "dev-libs/dbus-glib"] playground = ResolverPlayground(ebuilds=ebuilds, installed=installed, world=world, debug=debug) settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] trees = playground.trees portdb = trees[eroot]["porttree"].dbapi vardb = trees[eroot]["vartree"].dbapi var_cache_edb = os.path.join(eprefix, "var", "cache", "edb") user_config_dir = os.path.join(eprefix, USER_CONFIG_PATH) package_mask_path = os.path.join(user_config_dir, "package.mask") portage_python = portage._python_interpreter ebuild_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "ebuild")) emerge_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "emerge")) test_ebuild = portdb.findname("dev-libs/dbus-glib-0.98") self.assertFalse(test_ebuild is None) test_commands = ( emerge_cmd + ("--oneshot", "dev-libs/glib",), (lambda: "dev-libs/glib:2/2.32=" in vardb.aux_get("dev-libs/dbus-glib-0.98", ["RDEPEND"])[0],), (BASH_BINARY, "-c", "echo %s >> %s" % tuple(map(portage._shell_quote, (">=dev-libs/glib-2.32", package_mask_path,)))), emerge_cmd + ("--oneshot", "dev-libs/glib",), (lambda: "dev-libs/glib:2/2.30=" in vardb.aux_get("dev-libs/dbus-glib-0.98", ["RDEPEND"])[0],), ) distdir = playground.distdir pkgdir = playground.pkgdir fake_bin = os.path.join(eprefix, "bin") portage_tmpdir = os.path.join(eprefix, "var", "tmp", "portage") profile_path = settings.profile_path path = os.environ.get("PATH") if path is not None and not path.strip(): path = None if path is None: path = "" else: path = ":" + path path = fake_bin + path pythonpath = os.environ.get("PYTHONPATH") if pythonpath is not None and not pythonpath.strip(): pythonpath = None if pythonpath is not None and \ pythonpath.split(":")[0] == PORTAGE_PYM_PATH: pass else: if pythonpath is None: pythonpath = "" else: pythonpath = ":" + pythonpath pythonpath = PORTAGE_PYM_PATH + pythonpath env = { "PORTAGE_OVERRIDE_EPREFIX" : eprefix, "PATH" : path, "PORTAGE_PYTHON" : portage_python, "PORTAGE_REPOSITORIES" : settings.repositories.config_string(), "PYTHONPATH" : pythonpath, } if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: env["__PORTAGE_TEST_HARDLINK_LOCKS"] = \ os.environ["__PORTAGE_TEST_HARDLINK_LOCKS"] dirs = [distdir, fake_bin, portage_tmpdir, user_config_dir, var_cache_edb] true_symlinks = ["chown", "chgrp"] true_binary = find_binary("true") self.assertEqual(true_binary is None, False, "true command not found") try: for d in dirs: ensure_dirs(d) for x in true_symlinks: os.symlink(true_binary, os.path.join(fake_bin, x)) with open(os.path.join(var_cache_edb, "counter"), 'wb') as f: f.write(b"100") # non-empty system set keeps --depclean quiet with open(os.path.join(profile_path, "packages"), 'w') as f: f.write("*dev-libs/token-system-pkg") if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for i, args in enumerate(test_commands): if hasattr(args[0], '__call__'): self.assertTrue(args[0](), "callable at index %s failed" % (i,)) continue proc = subprocess.Popen(args, env=env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "emerge failed with args %s" % (args,)) finally: playground.cleanup()
def testSimple(self): debug = False skip_reason = self._must_skip() if skip_reason: self.portage_skip = skip_reason self.assertFalse(True, skip_reason) return copyright_header = """# Copyright 1999-%s Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ """ % time.gmtime().tm_year repo_configs = { "test_repo": { "layout.conf": ( "update-changelog = true", ), } } profiles = ( ("x86", "default/linux/x86/test_profile", "stable"), ) ebuilds = { "dev-libs/A-1": { "COPYRIGHT_HEADER" : copyright_header, "DESCRIPTION" : "Desc goes here", "EAPI" : "4", "HOMEPAGE" : "http://example.com", "IUSE" : "flag", "KEYWORDS": "~x86", "LICENSE": "GPL-2", "RDEPEND": "flag? ( dev-libs/B[flag] )", }, "dev-libs/B-1": { "COPYRIGHT_HEADER" : copyright_header, "DESCRIPTION" : "Desc goes here", "EAPI" : "4", "HOMEPAGE" : "http://example.com", "IUSE" : "flag", "KEYWORDS": "~x86", "LICENSE": "GPL-2", }, } licenses = ["GPL-2"] arch_list = ["x86"] metadata_dtd = os.path.join(PORTAGE_BASE_PATH, "cnf/metadata.dtd") metadata_xml_files = ( ( "dev-libs/A", { "herd" : "base-system", "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>", }, ), ( "dev-libs/B", { "herd" : "no-herd", "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>", }, ), ) use_desc = ( ("flag", "Description of how USE='flag' affects packages"), ) playground = ResolverPlayground(ebuilds=ebuilds, repo_configs=repo_configs, debug=debug) settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] portdb = playground.trees[playground.eroot]["porttree"].dbapi homedir = os.path.join(eroot, "home") distdir = os.path.join(eprefix, "distdir") portdir = settings["PORTDIR"] profiles_dir = os.path.join(portdir, "profiles") license_dir = os.path.join(portdir, "licenses") repoman_cmd = (portage._python_interpreter, "-Wd", os.path.join(PORTAGE_BIN_PATH, "repoman")) git_binary = find_binary("git") git_cmd = (git_binary,) cp_binary = find_binary("cp") self.assertEqual(cp_binary is None, False, "cp command not found") cp_cmd = (cp_binary,) test_ebuild = portdb.findname("dev-libs/A-1") self.assertFalse(test_ebuild is None) committer_name = "Gentoo Dev" committer_email = "*****@*****.**" git_test = ( ("", repoman_cmd + ("manifest",)), ("", git_cmd + ("config", "--global", "user.name", committer_name,)), ("", git_cmd + ("config", "--global", "user.email", committer_email,)), ("", git_cmd + ("init-db",)), ("", git_cmd + ("add", ".")), ("", git_cmd + ("commit", "-a", "-m", "add whole repo")), ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "2.ebuild")), ("", git_cmd + ("add", test_ebuild[:-8] + "2.ebuild")), ("", repoman_cmd + ("commit", "-m", "bump to version 2")), ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "3.ebuild")), ("", git_cmd + ("add", test_ebuild[:-8] + "3.ebuild")), ("dev-libs", repoman_cmd + ("commit", "-m", "bump to version 3")), ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "4.ebuild")), ("", git_cmd + ("add", test_ebuild[:-8] + "4.ebuild")), ("dev-libs/A", repoman_cmd + ("commit", "-m", "bump to version 4")), ) pythonpath = os.environ.get("PYTHONPATH") if pythonpath is not None and not pythonpath.strip(): pythonpath = None if pythonpath is not None and \ pythonpath.split(":")[0] == PORTAGE_PYM_PATH: pass else: if pythonpath is None: pythonpath = "" else: pythonpath = ":" + pythonpath pythonpath = PORTAGE_PYM_PATH + pythonpath env = { "PORTAGE_OVERRIDE_EPREFIX" : eprefix, "DISTDIR" : distdir, "GENTOO_COMMITTER_NAME" : committer_name, "GENTOO_COMMITTER_EMAIL" : committer_email, "HOME" : homedir, "PATH" : os.environ["PATH"], "PORTAGE_GRPNAME" : os.environ["PORTAGE_GRPNAME"], "PORTAGE_USERNAME" : os.environ["PORTAGE_USERNAME"], "PORTDIR" : portdir, "PYTHONPATH" : pythonpath, } if os.environ.get("SANDBOX_ON") == "1": # avoid problems from nested sandbox instances env["FEATURES"] = "-sandbox" dirs = [homedir, license_dir, profiles_dir, distdir] try: for d in dirs: ensure_dirs(d) with open(os.path.join(portdir, "skel.ChangeLog"), 'w') as f: f.write(copyright_header) with open(os.path.join(profiles_dir, "profiles.desc"), 'w') as f: for x in profiles: f.write("%s %s %s\n" % x) for x in licenses: open(os.path.join(license_dir, x), 'wb').close() with open(os.path.join(profiles_dir, "arch.list"), 'w') as f: for x in arch_list: f.write("%s\n" % x) with open(os.path.join(profiles_dir, "use.desc"), 'w') as f: for k, v in use_desc: f.write("%s - %s\n" % (k, v)) for cp, xml_data in metadata_xml_files: with open(os.path.join(portdir, cp, "metadata.xml"), 'w') as f: f.write(playground.metadata_xml_template % xml_data) # Use a symlink to portdir, in order to trigger bugs # involving canonical vs. non-canonical paths. portdir_symlink = os.path.join(eroot, "portdir_symlink") os.symlink(portdir, portdir_symlink) # repoman checks metadata.dtd for recent CTIME, so copy the file in # order to ensure that the CTIME is current shutil.copyfile(metadata_dtd, os.path.join(distdir, "metadata.dtd")) if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for cwd in ("", "dev-libs", "dev-libs/A", "dev-libs/B"): abs_cwd = os.path.join(portdir_symlink, cwd) proc = subprocess.Popen([portage._python_interpreter, "-Wd", os.path.join(PORTAGE_BIN_PATH, "repoman"), "full"], cwd=abs_cwd, env=env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "repoman failed in %s" % (cwd,)) if git_binary is not None: for cwd, cmd in git_test: abs_cwd = os.path.join(portdir_symlink, cwd) proc = subprocess.Popen(cmd, cwd=abs_cwd, env=env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "%s failed in %s" % (cmd, cwd,)) finally: playground.cleanup()
def testSlotAbiEmerge(self): debug = False ebuilds = { "dev-libs/glib-1.2.10": { "SLOT": "1" }, "dev-libs/glib-2.30.2": { "EAPI": "4-slot-abi", "SLOT": "2/2.30" }, "dev-libs/glib-2.32.3": { "EAPI": "4-slot-abi", "SLOT": "2/2.32" }, "dev-libs/dbus-glib-0.98": { "EAPI": "4-slot-abi", "DEPEND": "dev-libs/glib:2=", "RDEPEND": "dev-libs/glib:2=" }, } installed = { "dev-libs/glib-1.2.10": { "EAPI": "4-slot-abi", "SLOT": "1" }, "dev-libs/glib-2.30.2": { "EAPI": "4-slot-abi", "SLOT": "2/2.30" }, "dev-libs/dbus-glib-0.98": { "EAPI": "4-slot-abi", "DEPEND": "dev-libs/glib:2/2.30=", "RDEPEND": "dev-libs/glib:2/2.30=" }, } world = ["dev-libs/glib:1", "dev-libs/dbus-glib"] playground = ResolverPlayground(ebuilds=ebuilds, installed=installed, world=world, debug=debug) settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] trees = playground.trees portdb = trees[eroot]["porttree"].dbapi vardb = trees[eroot]["vartree"].dbapi var_cache_edb = os.path.join(eprefix, "var", "cache", "edb") user_config_dir = os.path.join(eprefix, USER_CONFIG_PATH) package_mask_path = os.path.join(user_config_dir, "package.mask") portage_python = portage._python_interpreter ebuild_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "ebuild")) emerge_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "emerge")) test_ebuild = portdb.findname("dev-libs/dbus-glib-0.98") self.assertFalse(test_ebuild is None) test_commands = ( emerge_cmd + ( "--oneshot", "dev-libs/glib", ), (lambda: "dev-libs/glib:2/2.32=" in vardb.aux_get( "dev-libs/dbus-glib-0.98", ["RDEPEND"])[0], ), (BASH_BINARY, "-c", "echo %s >> %s" % tuple( map(portage._shell_quote, ( ">=dev-libs/glib-2.32", package_mask_path, )))), emerge_cmd + ( "--oneshot", "dev-libs/glib", ), (lambda: "dev-libs/glib:2/2.30=" in vardb.aux_get( "dev-libs/dbus-glib-0.98", ["RDEPEND"])[0], ), ) distdir = playground.distdir pkgdir = playground.pkgdir fake_bin = os.path.join(eprefix, "bin") portage_tmpdir = os.path.join(eprefix, "var", "tmp", "portage") profile_path = settings.profile_path path = os.environ.get("PATH") if path is not None and not path.strip(): path = None if path is None: path = "" else: path = ":" + path path = fake_bin + path pythonpath = os.environ.get("PYTHONPATH") if pythonpath is not None and not pythonpath.strip(): pythonpath = None if pythonpath is not None and \ pythonpath.split(":")[0] == PORTAGE_PYM_PATH: pass else: if pythonpath is None: pythonpath = "" else: pythonpath = ":" + pythonpath pythonpath = PORTAGE_PYM_PATH + pythonpath env = { "PORTAGE_OVERRIDE_EPREFIX": eprefix, "PATH": path, "PORTAGE_PYTHON": portage_python, "PORTAGE_REPOSITORIES": settings.repositories.config_string(), "PYTHONPATH": pythonpath, } if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: env["__PORTAGE_TEST_HARDLINK_LOCKS"] = \ os.environ["__PORTAGE_TEST_HARDLINK_LOCKS"] dirs = [ distdir, fake_bin, portage_tmpdir, user_config_dir, var_cache_edb ] true_symlinks = ["chown", "chgrp"] true_binary = find_binary("true") self.assertEqual(true_binary is None, False, "true command not found") try: for d in dirs: ensure_dirs(d) for x in true_symlinks: os.symlink(true_binary, os.path.join(fake_bin, x)) with open(os.path.join(var_cache_edb, "counter"), 'wb') as f: f.write(b"100") # non-empty system set keeps --depclean quiet with open(os.path.join(profile_path, "packages"), 'w') as f: f.write("*dev-libs/token-system-pkg") if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for i, args in enumerate(test_commands): if hasattr(args[0], '__call__'): self.assertTrue(args[0](), "callable at index %s failed" % (i, )) continue proc = subprocess.Popen(args, env=env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "emerge failed with args %s" % (args, )) finally: playground.cleanup()
def _start(self): tar_options = "" if "xattr" in self.features: process = subprocess.Popen(["tar", "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) output = process.communicate()[0] if b"--xattrs" in output: tar_options = ["--xattrs", "--xattrs-include='*'"] for x in portage.util.shlex_split(self.env.get("PORTAGE_XATTR_EXCLUDE", "")): tar_options.append(portage._shell_quote("--xattrs-exclude=%s" % x)) tar_options = " ".join(tar_options) decomp = _compressors.get(compression_probe(self.pkg_path)) if decomp is not None: decomp_cmd = decomp.get("decompress") elif tarfile.is_tarfile(portage._unicode_encode(self.pkg_path, encoding=portage._encodings['fs'], errors='strict')): decomp_cmd = 'cat' decomp = { 'compress': 'cat', 'package': 'sys-apps/coreutils', } else: decomp_cmd = None if decomp_cmd is None: self.scheduler.output("!!! %s\n" % _("File compression header unrecognized: %s") % self.pkg_path, log_path=self.logfile, background=self.background, level=logging.ERROR) self.returncode = 1 self._async_wait() return try: decompression_binary = shlex_split(varexpand(decomp_cmd, mydict=self.env))[0] except IndexError: decompression_binary = "" if find_binary(decompression_binary) is None: # Try alternative command if it exists if decomp.get("decompress_alt"): decomp_cmd = decomp.get("decompress_alt") try: decompression_binary = shlex_split(varexpand(decomp_cmd, mydict=self.env))[0] except IndexError: decompression_binary = "" if find_binary(decompression_binary) is None: missing_package = decomp.get("package") self.scheduler.output("!!! %s\n" % _("File compression unsupported %s.\n Command was: %s.\n Maybe missing package: %s") % (self.pkg_path, varexpand(decomp_cmd, mydict=self.env), missing_package), log_path=self.logfile, background=self.background, level=logging.ERROR) self.returncode = 1 self._async_wait() return pkg_xpak = portage.xpak.tbz2(self.pkg_path) pkg_xpak.scan() # SIGPIPE handling (128 + SIGPIPE) should be compatible with # assert_sigpipe_ok() that's used by the ebuild unpack() helper. self.args = [self._shell_binary, "-c", ("cmd0=(head -c %d -- %s) cmd1=(%s) cmd2=(tar -xp %s -C %s -f -); " + \ '"${cmd0[@]}" | "${cmd1[@]}" | "${cmd2[@]}"; ' + \ "p=(${PIPESTATUS[@]}) ; for i in {0..2}; do " + \ "if [[ ${p[$i]} != 0 && ${p[$i]} != %d ]] ; then " + \ "echo command $(eval \"echo \\\"'\\${cmd$i[*]}'\\\"\") " + \ "failed with status ${p[$i]} ; exit ${p[$i]} ; fi ; done; " + \ "if [ ${p[$i]} != 0 ] ; then " + \ "echo command $(eval \"echo \\\"'\\${cmd$i[*]}'\\\"\") " + \ "failed with status ${p[$i]} ; exit ${p[$i]} ; fi ; " + \ "exit 0 ;") % \ (pkg_xpak.filestat.st_size - pkg_xpak.xpaksize, portage._shell_quote(self.pkg_path), decomp_cmd, tar_options, portage._shell_quote(self.image_dir), 128 + signal.SIGPIPE)] SpawnProcess._start(self)
def testSimple(self): debug = False install_something = """ S="${WORKDIR}" pkg_pretend() { einfo "called pkg_pretend for $CATEGORY/$PF" } src_install() { einfo "installing something..." insinto /usr/lib/${P} echo "blah blah blah" > "${T}"/regular-file doins "${T}"/regular-file dosym regular-file /usr/lib/${P}/symlink || die # Test code for bug #381629, using a copyright symbol encoded with latin-1. # We use $(printf "\\xa9") rather than $'\\xa9', since printf apparently # works in any case, while $'\\xa9' transforms to \\xef\\xbf\\xbd under # some conditions. TODO: Find out why it transforms to \\xef\\xbf\\xbd when # running tests for Python 3.2 (even though it's bash that is ultimately # responsible for performing the transformation). local latin_1_dir=/usr/lib/${P}/latin-1-$(printf "\\xa9")-directory insinto "${latin_1_dir}" echo "blah blah blah" > "${T}"/latin-1-$(printf "\\xa9")-regular-file || die doins "${T}"/latin-1-$(printf "\\xa9")-regular-file dosym latin-1-$(printf "\\xa9")-regular-file ${latin_1_dir}/latin-1-$(printf "\\xa9")-symlink || die } pkg_config() { einfo "called pkg_config for $CATEGORY/$PF" } pkg_info() { einfo "called pkg_info for $CATEGORY/$PF" } pkg_preinst() { einfo "called pkg_preinst for $CATEGORY/$PF" # Test that has_version and best_version work correctly with # prefix (involves internal ROOT -> EROOT calculation in order # to support ROOT override via the environment with EAPIs 3 # and later which support prefix). if has_version $CATEGORY/$PN:$SLOT ; then einfo "has_version detects an installed instance of $CATEGORY/$PN:$SLOT" einfo "best_version reports that the installed instance is $(best_version $CATEGORY/$PN:$SLOT)" else einfo "has_version does not detect an installed instance of $CATEGORY/$PN:$SLOT" fi } """ ebuilds = { "dev-libs/A-1": { "EAPI" : "4", "IUSE" : "+flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "MISC_CONTENT": install_something, "RDEPEND": "flag? ( dev-libs/B[flag] )", }, "dev-libs/B-1": { "EAPI" : "4", "IUSE" : "+flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "MISC_CONTENT": install_something, }, "virtual/foo-0": { "EAPI" : "4", "KEYWORDS": "x86", "LICENSE": "GPL-2", }, } installed = { "dev-libs/A-1": { "EAPI" : "4", "IUSE" : "+flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "RDEPEND": "flag? ( dev-libs/B[flag] )", "USE": "flag", }, "dev-libs/B-1": { "EAPI" : "4", "IUSE" : "+flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "USE": "flag", }, "dev-libs/depclean-me-1": { "EAPI" : "4", "IUSE" : "", "KEYWORDS": "x86", "LICENSE": "GPL-2", "USE": "", }, "app-misc/depclean-me-1": { "EAPI" : "4", "IUSE" : "", "KEYWORDS": "x86", "LICENSE": "GPL-2", "RDEPEND": "dev-libs/depclean-me", "USE": "", }, } metadata_xml_files = ( ( "dev-libs/A", { "herd" : "base-system", "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>", }, ), ( "dev-libs/B", { "herd" : "no-herd", "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>", }, ), ) playground = ResolverPlayground( ebuilds=ebuilds, installed=installed, debug=debug) settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] trees = playground.trees portdb = trees[eroot]["porttree"].dbapi portdir = settings["PORTDIR"] var_cache_edb = os.path.join(eprefix, "var", "cache", "edb") cachedir = os.path.join(var_cache_edb, "dep") cachedir_pregen = os.path.join(portdir, "metadata", "cache") portage_python = portage._python_interpreter ebuild_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "ebuild")) egencache_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "egencache")) emerge_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "emerge")) emaint_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "emaint")) env_update_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "env-update")) fixpackages_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "fixpackages")) portageq_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "portageq")) quickpkg_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "quickpkg")) regenworld_cmd = (portage_python, "-Wd", os.path.join(PORTAGE_BIN_PATH, "regenworld")) rm_binary = find_binary("rm") self.assertEqual(rm_binary is None, False, "rm command not found") rm_cmd = (rm_binary,) egencache_extra_args = [] if self._have_python_xml(): egencache_extra_args.append("--update-use-local-desc") test_ebuild = portdb.findname("dev-libs/A-1") self.assertFalse(test_ebuild is None) test_commands = ( env_update_cmd, emerge_cmd + ("--version",), emerge_cmd + ("--info",), emerge_cmd + ("--info", "--verbose"), emerge_cmd + ("--list-sets",), emerge_cmd + ("--check-news",), rm_cmd + ("-rf", cachedir), rm_cmd + ("-rf", cachedir_pregen), emerge_cmd + ("--regen",), rm_cmd + ("-rf", cachedir), ({"FEATURES" : "metadata-transfer"},) + \ emerge_cmd + ("--regen",), rm_cmd + ("-rf", cachedir), ({"FEATURES" : "metadata-transfer parse-eapi-ebuild-head"},) + \ emerge_cmd + ("--regen",), rm_cmd + ("-rf", cachedir), egencache_cmd + ("--update",) + tuple(egencache_extra_args), ({"FEATURES" : "metadata-transfer"},) + \ emerge_cmd + ("--metadata",), rm_cmd + ("-rf", cachedir), ({"FEATURES" : "metadata-transfer"},) + \ emerge_cmd + ("--metadata",), emerge_cmd + ("--metadata",), rm_cmd + ("-rf", cachedir), emerge_cmd + ("--oneshot", "virtual/foo"), emerge_cmd + ("--pretend", "dev-libs/A"), ebuild_cmd + (test_ebuild, "manifest", "clean", "package", "merge"), emerge_cmd + ("--pretend", "--tree", "--complete-graph", "dev-libs/A"), emerge_cmd + ("-p", "dev-libs/B"), emerge_cmd + ("-B", "dev-libs/B",), emerge_cmd + ("--oneshot", "--usepkg", "dev-libs/B",), # trigger clean prior to pkg_pretend as in bug #390711 ebuild_cmd + (test_ebuild, "unpack"), emerge_cmd + ("--oneshot", "dev-libs/A",), emerge_cmd + ("--noreplace", "dev-libs/A",), emerge_cmd + ("--config", "dev-libs/A",), emerge_cmd + ("--info", "dev-libs/A", "dev-libs/B"), emerge_cmd + ("--pretend", "--depclean", "--verbose", "dev-libs/B"), emerge_cmd + ("--pretend", "--depclean",), emerge_cmd + ("--depclean",), quickpkg_cmd + ("dev-libs/A",), emerge_cmd + ("--usepkgonly", "dev-libs/A"), emaint_cmd + ("--check", "all"), emaint_cmd + ("--fix", "all"), fixpackages_cmd, regenworld_cmd, portageq_cmd + ("match", eroot, "dev-libs/A"), portageq_cmd + ("best_visible", eroot, "dev-libs/A"), portageq_cmd + ("best_visible", eroot, "binary", "dev-libs/A"), portageq_cmd + ("contents", eroot, "dev-libs/A-1"), portageq_cmd + ("metadata", eroot, "ebuild", "dev-libs/A-1", "EAPI", "IUSE", "RDEPEND"), portageq_cmd + ("metadata", eroot, "binary", "dev-libs/A-1", "EAPI", "USE", "RDEPEND"), portageq_cmd + ("metadata", eroot, "installed", "dev-libs/A-1", "EAPI", "USE", "RDEPEND"), portageq_cmd + ("owners", eroot, eroot + "usr"), emerge_cmd + ("-p", eroot + "usr"), emerge_cmd + ("-p", "--unmerge", "-q", eroot + "usr"), emerge_cmd + ("--unmerge", "--quiet", "dev-libs/A"), emerge_cmd + ("-C", "--quiet", "dev-libs/B"), ) distdir = os.path.join(eprefix, "distdir") pkgdir = os.path.join(eprefix, "pkgdir") fake_bin = os.path.join(eprefix, "bin") portage_tmpdir = os.path.join(eprefix, "var", "tmp", "portage") profile_path = settings.profile_path user_config_dir = os.path.join(os.sep, eprefix, USER_CONFIG_PATH) features = [] if not portage.process.sandbox_capable or \ os.environ.get("SANDBOX_ON") == "1": features.append("-sandbox") # Since egencache ignores settings from the calling environment, # configure it via make.conf. make_conf = ( "FEATURES=\"%s\"\n" % (" ".join(features),), "PORTDIR=\"%s\"\n" % (portdir,), "PORTAGE_GRPNAME=\"%s\"\n" % (os.environ["PORTAGE_GRPNAME"],), "PORTAGE_USERNAME=\"%s\"\n" % (os.environ["PORTAGE_USERNAME"],), ) path = os.environ.get("PATH") if path is not None and not path.strip(): path = None if path is None: path = "" else: path = ":" + path path = fake_bin + path pythonpath = os.environ.get("PYTHONPATH") if pythonpath is not None and not pythonpath.strip(): pythonpath = None if pythonpath is not None and \ pythonpath.split(":")[0] == PORTAGE_PYM_PATH: pass else: if pythonpath is None: pythonpath = "" else: pythonpath = ":" + pythonpath pythonpath = PORTAGE_PYM_PATH + pythonpath env = { "PORTAGE_OVERRIDE_EPREFIX" : eprefix, "CLEAN_DELAY" : "0", "DISTDIR" : distdir, "EMERGE_WARNING_DELAY" : "0", "INFODIR" : "", "INFOPATH" : "", "PATH" : path, "PKGDIR" : pkgdir, "PORTAGE_INST_GID" : str(portage.data.portage_gid), "PORTAGE_INST_UID" : str(portage.data.portage_uid), "PORTAGE_PYTHON" : portage_python, "PORTAGE_TMPDIR" : portage_tmpdir, "PYTHONPATH" : pythonpath, } if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: env["__PORTAGE_TEST_HARDLINK_LOCKS"] = \ os.environ["__PORTAGE_TEST_HARDLINK_LOCKS"] updates_dir = os.path.join(portdir, "profiles", "updates") dirs = [cachedir, cachedir_pregen, distdir, fake_bin, portage_tmpdir, updates_dir, user_config_dir, var_cache_edb] true_symlinks = ["chown", "chgrp"] true_binary = find_binary("true") self.assertEqual(true_binary is None, False, "true command not found") try: for d in dirs: ensure_dirs(d) with open(os.path.join(user_config_dir, "make.conf"), 'w') as f: for line in make_conf: f.write(line) for x in true_symlinks: os.symlink(true_binary, os.path.join(fake_bin, x)) with open(os.path.join(var_cache_edb, "counter"), 'wb') as f: f.write(b"100") # non-empty system set keeps --depclean quiet with open(os.path.join(profile_path, "packages"), 'w') as f: f.write("*dev-libs/token-system-pkg") for cp, xml_data in metadata_xml_files: with open(os.path.join(portdir, cp, "metadata.xml"), 'w') as f: f.write(playground.metadata_xml_template % xml_data) with open(os.path.join(updates_dir, "1Q-2010"), 'w') as f: f.write(""" slotmove =app-doc/pms-3 2 3 move dev-util/git dev-vcs/git """) if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for args in test_commands: if isinstance(args[0], dict): local_env = env.copy() local_env.update(args[0]) args = args[1:] else: local_env = env proc = subprocess.Popen(args, env=local_env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "emerge failed with args %s" % (args,)) finally: playground.cleanup()
def _must_skip(self): if find_binary("rsync") is None: return "rsync: command not found" if find_binary("git") is None: return "git: command not found"
def __init__(self, ebuilds={}, binpkgs={}, installed={}, profile={}, repo_configs={}, \ user_config={}, sets={}, world=[], world_sets=[], distfiles={}, eprefix=None, targetroot=False, debug=False): """ ebuilds: cpv -> metadata mapping simulating available ebuilds. installed: cpv -> metadata mapping simulating installed packages. If a metadata key is missing, it gets a default value. profile: settings defined by the profile. """ self.debug = debug if eprefix is None: self.eprefix = normalize_path(tempfile.mkdtemp()) # EPREFIX/bin is used by fake true_binaries. Real binaries goes into EPREFIX/usr/bin eubin = os.path.join(self.eprefix, "usr", "bin") ensure_dirs(eubin) essential_binaries = ( "awk", "basename", "bzip2", "cat", "chgrp", "chmod", "chown", "cp", "egrep", "env", "find", "grep", "head", "install", "ln", "mkdir", "mktemp", "mv", "readlink", "rm", "sed", "sort", "tar", "tr", "uname", "uniq", "xargs", ) # Exclude internal wrappers from PATH lookup. orig_path = os.environ['PATH'] included_paths = [] for path in orig_path.split(':'): if path and not fnmatch.fnmatch(path, '*/portage/*/ebuild-helpers*'): included_paths.append(path) try: os.environ['PATH'] = ':'.join(included_paths) for x in essential_binaries: path = find_binary(x) if path is None: raise portage.exception.CommandNotFound(x) os.symlink(path, os.path.join(eubin, x)) finally: os.environ['PATH'] = orig_path else: self.eprefix = normalize_path(eprefix) # Tests may override portage.const.EPREFIX in order to # simulate a prefix installation. It's reasonable to do # this because tests should be self-contained such that # the "real" value of portage.const.EPREFIX is entirely # irrelevant (see bug #492932). portage.const.EPREFIX = self.eprefix.rstrip(os.sep) self.eroot = self.eprefix + os.sep if targetroot: self.target_root = os.path.join(self.eroot, 'target_root') else: self.target_root = os.sep self.distdir = os.path.join(self.eroot, "var", "portage", "distfiles") self.pkgdir = os.path.join(self.eprefix, "pkgdir") self.vdbdir = os.path.join(self.eroot, "var/db/pkg") os.makedirs(self.vdbdir) if not debug: portage.util.noiselimit = -2 self._repositories = {} #Make sure the main repo is always created self._get_repo_dir("test_repo") self._create_distfiles(distfiles) self._create_ebuilds(ebuilds) self._create_binpkgs(binpkgs) self._create_installed(installed) self._create_profile(ebuilds, installed, profile, repo_configs, user_config, sets) self._create_world(world, world_sets) self.settings, self.trees = self._load_config() self._create_ebuild_manifests(ebuilds) portage.util.noiselimit = 0
def _env_update(makelinks, target_root, prev_mtimes, contents, env, writemsg_level): if writemsg_level is None: writemsg_level = portage.util.writemsg_level if target_root is None: target_root = portage.settings["ROOT"] if prev_mtimes is None: prev_mtimes = portage.mtimedb["ldpath"] if env is None: settings = portage.settings else: settings = env eprefix = settings.get("EPREFIX", "") eprefix_lstrip = eprefix.lstrip(os.sep) eroot = (normalize_path(os.path.join(target_root, eprefix_lstrip)).rstrip( os.sep) + os.sep) envd_dir = os.path.join(eroot, "etc", "env.d") ensure_dirs(envd_dir, mode=0o755) fns = listdir(envd_dir, EmptyOnError=1) fns.sort() templist = [] for x in fns: if len(x) < 3: continue if not x[0].isdigit() or not x[1].isdigit(): continue if x.startswith(".") or x.endswith("~") or x.endswith(".bak"): continue templist.append(x) fns = templist del templist space_separated = set(["CONFIG_PROTECT", "CONFIG_PROTECT_MASK"]) colon_separated = set([ "ADA_INCLUDE_PATH", "ADA_OBJECTS_PATH", "CLASSPATH", "INFODIR", "INFOPATH", "KDEDIRS", "LDPATH", "MANPATH", "PATH", "PKG_CONFIG_PATH", "PRELINK_PATH", "PRELINK_PATH_MASK", "PYTHONPATH", "ROOTPATH", ]) config_list = [] for x in fns: file_path = os.path.join(envd_dir, x) try: myconfig = getconfig(file_path, expand=False) except ParseError as e: writemsg("!!! '%s'\n" % str(e), noiselevel=-1) del e continue if myconfig is None: # broken symlink or file removed by a concurrent process writemsg("!!! File Not Found: '%s'\n" % file_path, noiselevel=-1) continue config_list.append(myconfig) if "SPACE_SEPARATED" in myconfig: space_separated.update(myconfig["SPACE_SEPARATED"].split()) del myconfig["SPACE_SEPARATED"] if "COLON_SEPARATED" in myconfig: colon_separated.update(myconfig["COLON_SEPARATED"].split()) del myconfig["COLON_SEPARATED"] env = {} specials = {} for var in space_separated: mylist = [] for myconfig in config_list: if var in myconfig: for item in myconfig[var].split(): if item and not item in mylist: mylist.append(item) del myconfig[var] # prepare for env.update(myconfig) if mylist: env[var] = " ".join(mylist) specials[var] = mylist for var in colon_separated: mylist = [] for myconfig in config_list: if var in myconfig: for item in myconfig[var].split(":"): if item and not item in mylist: mylist.append(item) del myconfig[var] # prepare for env.update(myconfig) if mylist: env[var] = ":".join(mylist) specials[var] = mylist for myconfig in config_list: """Cumulative variables have already been deleted from myconfig so that they won't be overwritten by this dict.update call.""" env.update(myconfig) ldsoconf_path = os.path.join(eroot, "etc", "ld.so.conf") try: myld = io.open( _unicode_encode(ldsoconf_path, encoding=_encodings["fs"], errors="strict"), mode="r", encoding=_encodings["content"], errors="replace", ) myldlines = myld.readlines() myld.close() oldld = [] for x in myldlines: # each line has at least one char (a newline) if x[:1] == "#": continue oldld.append(x[:-1]) except (IOError, OSError) as e: if e.errno != errno.ENOENT: raise oldld = None newld = specials["LDPATH"] if oldld != newld: # ld.so.conf needs updating and ldconfig needs to be run myfd = atomic_ofstream(ldsoconf_path) myfd.write( "# ld.so.conf autogenerated by env-update; make all changes to\n") myfd.write("# contents of /etc/env.d directory\n") for x in specials["LDPATH"]: myfd.write(x + "\n") myfd.close() potential_lib_dirs = set() for lib_dir_glob in ("usr/lib*", "lib*"): x = os.path.join(eroot, lib_dir_glob) for y in glob.glob( _unicode_encode(x, encoding=_encodings["fs"], errors="strict")): try: y = _unicode_decode(y, encoding=_encodings["fs"], errors="strict") except UnicodeDecodeError: continue if os.path.basename(y) != "libexec": potential_lib_dirs.add(y[len(eroot):]) # Update prelink.conf if we are prelink-enabled if prelink_capable: prelink_d = os.path.join(eroot, "etc", "prelink.conf.d") ensure_dirs(prelink_d) newprelink = atomic_ofstream(os.path.join(prelink_d, "portage.conf")) newprelink.write( "# prelink.conf autogenerated by env-update; make all changes to\n" ) newprelink.write("# contents of /etc/env.d directory\n") for x in sorted(potential_lib_dirs) + ["bin", "sbin"]: newprelink.write("-l /%s\n" % (x, )) prelink_paths = set() prelink_paths |= set(specials.get("LDPATH", [])) prelink_paths |= set(specials.get("PATH", [])) prelink_paths |= set(specials.get("PRELINK_PATH", [])) prelink_path_mask = specials.get("PRELINK_PATH_MASK", []) for x in prelink_paths: if not x: continue if x[-1:] != "/": x += "/" plmasked = 0 for y in prelink_path_mask: if not y: continue if y[-1] != "/": y += "/" if y == x[0:len(y)]: plmasked = 1 break if not plmasked: newprelink.write("-h %s\n" % (x, )) for x in prelink_path_mask: newprelink.write("-b %s\n" % (x, )) newprelink.close() # Migration code path. If /etc/prelink.conf was generated by us, then # point it to the new stuff until the prelink package re-installs. prelink_conf = os.path.join(eroot, "etc", "prelink.conf") try: with open( _unicode_encode(prelink_conf, encoding=_encodings["fs"], errors="strict"), "rb", ) as f: if (f.readline( ) == b"# prelink.conf autogenerated by env-update; make all changes to\n" ): f = atomic_ofstream(prelink_conf) f.write("-c /etc/prelink.conf.d/*.conf\n") f.close() except IOError as e: if e.errno != errno.ENOENT: raise current_time = int(time.time()) mtime_changed = False lib_dirs = set() for lib_dir in set(specials["LDPATH"]) | potential_lib_dirs: x = os.path.join(eroot, lib_dir.lstrip(os.sep)) try: newldpathtime = os.stat(x)[stat.ST_MTIME] lib_dirs.add(normalize_path(x)) except OSError as oe: if oe.errno == errno.ENOENT: try: del prev_mtimes[x] except KeyError: pass # ignore this path because it doesn't exist continue raise if newldpathtime == current_time: # Reset mtime to avoid the potential ambiguity of times that # differ by less than 1 second. newldpathtime -= 1 os.utime(x, (newldpathtime, newldpathtime)) prev_mtimes[x] = newldpathtime mtime_changed = True elif x in prev_mtimes: if prev_mtimes[x] == newldpathtime: pass else: prev_mtimes[x] = newldpathtime mtime_changed = True else: prev_mtimes[x] = newldpathtime mtime_changed = True if makelinks and not mtime_changed and contents is not None: libdir_contents_changed = False for mypath, mydata in contents.items(): if mydata[0] not in ("obj", "sym"): continue head, tail = os.path.split(mypath) if head in lib_dirs: libdir_contents_changed = True break if not libdir_contents_changed: makelinks = False if ("CHOST" in settings and "CBUILD" in settings and settings["CHOST"] != settings["CBUILD"]): ldconfig = find_binary("%s-ldconfig" % settings["CHOST"]) else: ldconfig = os.path.join(eroot, "sbin", "ldconfig") if ldconfig is None: pass elif not (os.access(ldconfig, os.X_OK) and os.path.isfile(ldconfig)): ldconfig = None # Only run ldconfig as needed if makelinks and ldconfig: # ldconfig has very different behaviour between FreeBSD and Linux if ostype == "Linux" or ostype.lower().endswith("gnu"): # We can't update links if we haven't cleaned other versions first, as # an older package installed ON TOP of a newer version will cause ldconfig # to overwrite the symlinks we just made. -X means no links. After 'clean' # we can safely create links. writemsg_level( _(">>> Regenerating %setc/ld.so.cache...\n") % (target_root, )) os.system("cd / ; %s -X -r '%s'" % (ldconfig, target_root)) elif ostype in ("FreeBSD", "DragonFly"): writemsg_level( _(">>> Regenerating %svar/run/ld-elf.so.hints...\n") % target_root) os.system(("cd / ; %s -elf -i " + "-f '%svar/run/ld-elf.so.hints' '%setc/ld.so.conf'") % (ldconfig, target_root, target_root)) del specials["LDPATH"] notice = "# THIS FILE IS AUTOMATICALLY GENERATED BY env-update.\n" notice += "# DO NOT EDIT THIS FILE." penvnotice = notice + " CHANGES TO STARTUP PROFILES\n" cenvnotice = penvnotice[:] penvnotice += "# GO INTO /etc/profile NOT /etc/profile.env\n\n" cenvnotice += "# GO INTO /etc/csh.cshrc NOT /etc/csh.env\n\n" # create /etc/profile.env for bash support profile_env_path = os.path.join(eroot, "etc", "profile.env") with atomic_ofstream(profile_env_path) as outfile: outfile.write(penvnotice) env_keys = [x for x in env if x != "LDPATH"] env_keys.sort() for k in env_keys: v = env[k] if v.startswith("$") and not v.startswith("${"): outfile.write("export %s=$'%s'\n" % (k, v[1:])) else: outfile.write("export %s='%s'\n" % (k, v)) # Create the systemd user environment configuration file # /etc/environment.d/10-gentoo-env.conf with the # environment configuration from /etc/env.d. systemd_environment_dir = os.path.join(eroot, "etc", "environment.d") os.makedirs(systemd_environment_dir, exist_ok=True) systemd_gentoo_env_path = os.path.join(systemd_environment_dir, "10-gentoo-env.conf") with atomic_ofstream(systemd_gentoo_env_path) as systemd_gentoo_env: senvnotice = notice + "\n\n" systemd_gentoo_env.write(senvnotice) for env_key in env_keys: # Skip PATH since this makes it impossible to use # "systemctl --user import-environment PATH". if env_key == "PATH": continue env_key_value = env[env_key] # Skip variables with the empty string # as value. Those sometimes appear in # profile.env (e.g. "export GCC_SPECS=''"), # but are invalid in systemd's syntax. if not env_key_value: continue # Transform into systemd environment.d # conf syntax, basically shell variable # assignment (without "export "). line = f"{env_key}={env_key_value}\n" systemd_gentoo_env.write(line) # create /etc/csh.env for (t)csh support outfile = atomic_ofstream(os.path.join(eroot, "etc", "csh.env")) outfile.write(cenvnotice) for x in env_keys: outfile.write("setenv %s '%s'\n" % (x, env[x])) outfile.close()
def changelogs(self, myupdates, mymanifests, myremoved, mychanged, myautoadd, mynew, changelog_msg): broken_changelog_manifests = [] if self.options.echangelog in ('y', 'force'): logging.info("checking for unmodified ChangeLog files") committer_name = utilities.get_committer_name(env=self.repoman_settings) for x in sorted(vcs_files_to_cps( chain(myupdates, mymanifests, myremoved), self.scanner.repolevel, self.scanner.reposplit, self.scanner.categories)): catdir, pkgdir = x.split("/") checkdir = self.repo_settings.repodir + "/" + x checkdir_relative = "" if self.scanner.repolevel < 3: checkdir_relative = os.path.join(pkgdir, checkdir_relative) if self.scanner.repolevel < 2: checkdir_relative = os.path.join(catdir, checkdir_relative) checkdir_relative = os.path.join(".", checkdir_relative) changelog_path = os.path.join(checkdir_relative, "ChangeLog") changelog_modified = changelog_path in self.scanner.changed.changelogs if changelog_modified and self.options.echangelog != 'force': continue # get changes for this package cdrlen = len(checkdir_relative) check_relative = lambda e: e.startswith(checkdir_relative) split_relative = lambda e: e[cdrlen:] clnew = list(map(split_relative, filter(check_relative, mynew))) clremoved = list(map(split_relative, filter(check_relative, myremoved))) clchanged = list(map(split_relative, filter(check_relative, mychanged))) # Skip ChangeLog generation if only the Manifest was modified, # as discussed in bug #398009. nontrivial_cl_files = set() nontrivial_cl_files.update(clnew, clremoved, clchanged) nontrivial_cl_files.difference_update(['Manifest']) if not nontrivial_cl_files and self.options.echangelog != 'force': continue new_changelog = utilities.UpdateChangeLog( checkdir_relative, committer_name, changelog_msg, os.path.join(self.repo_settings.repodir, 'skel.ChangeLog'), catdir, pkgdir, new=clnew, removed=clremoved, changed=clchanged, pretend=self.options.pretend) if new_changelog is None: writemsg_level( "!!! Updating the ChangeLog failed\n", level=logging.ERROR, noiselevel=-1) sys.exit(1) # if the ChangeLog was just created, add it to vcs if new_changelog: myautoadd.append(changelog_path) # myautoadd is appended to myupdates below else: myupdates.append(changelog_path) if self.options.ask and not self.options.pretend: # regenerate Manifest for modified ChangeLog (bug #420735) self.repoman_settings["O"] = checkdir digestgen(mysettings=self.repoman_settings, myportdb=self.repo_settings.portdb) else: broken_changelog_manifests.append(x) if myautoadd: print(">>> Auto-Adding missing Manifest/ChangeLog file(s)...") add_cmd = [self.vcs_settings.vcs, "add"] add_cmd += myautoadd if self.options.pretend: portage.writemsg_stdout( "(%s)\n" % " ".join(add_cmd), noiselevel=-1) else: if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \ not os.path.isabs(add_cmd[0]): # Python 3.1 _execvp throws TypeError for non-absolute executable # path passed as bytes (see http://bugs.python.org/issue8513). fullname = find_binary(add_cmd[0]) if fullname is None: raise portage.exception.CommandNotFound(add_cmd[0]) add_cmd[0] = fullname add_cmd = [_unicode_encode(arg) for arg in add_cmd] retcode = subprocess.call(add_cmd) if retcode != os.EX_OK: logging.error( "Exiting on %s error code: %s\n" % (self.vcs_settings.vcs, retcode)) sys.exit(retcode) myupdates += myautoadd return myupdates, broken_changelog_manifests
def testSimple(self): debug = False skip_reason = self._must_skip() if skip_reason: self.portage_skip = skip_reason self.assertFalse(True, skip_reason) return copyright_header = """# Copyright 1999-%s Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ """ % time.gmtime().tm_year repo_configs = { "test_repo": { "layout.conf": ( "update-changelog = true", ), } } profiles = ( ("x86", "default/linux/x86/test_profile", "stable"), ("x86", "default/linux/x86/test_dev", "dev"), ("x86", "default/linux/x86/test_exp", "exp"), ) profile = { "eapi": ("5",), "package.use.stable.mask": ("dev-libs/A flag",) } ebuilds = { "dev-libs/A-0": { "COPYRIGHT_HEADER" : copyright_header, "DESCRIPTION" : "Desc goes here", "EAPI" : "5", "HOMEPAGE" : "https://example.com", "IUSE" : "flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "RDEPEND": "flag? ( dev-libs/B[flag] )", }, "dev-libs/A-1": { "COPYRIGHT_HEADER" : copyright_header, "DESCRIPTION" : "Desc goes here", "EAPI" : "4", "HOMEPAGE" : "https://example.com", "IUSE" : "flag", "KEYWORDS": "~x86", "LICENSE": "GPL-2", "RDEPEND": "flag? ( dev-libs/B[flag] )", }, "dev-libs/B-1": { "COPYRIGHT_HEADER" : copyright_header, "DESCRIPTION" : "Desc goes here", "EAPI" : "4", "HOMEPAGE" : "https://example.com", "IUSE" : "flag", "KEYWORDS": "~x86", "LICENSE": "GPL-2", }, "dev-libs/C-0": { "COPYRIGHT_HEADER" : copyright_header, "DESCRIPTION" : "Desc goes here", "EAPI" : "4", "HOMEPAGE" : "https://example.com", "IUSE" : "flag", # must be unstable, since dev-libs/A[flag] is stable masked "KEYWORDS": "~x86", "LICENSE": "GPL-2", "RDEPEND": "flag? ( dev-libs/A[flag] )", }, } licenses = ["GPL-2"] arch_list = ["x86"] metadata_xsd = os.path.join(REPOMAN_BASE_PATH, "cnf/metadata.xsd") metadata_xml_files = ( ( "dev-libs/A", { "flags" : "<flag name='flag' restrict='>=dev-libs/A-0'>Description of how USE='flag' affects this package</flag>", }, ), ( "dev-libs/B", { "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>", }, ), ( "dev-libs/C", { "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>", }, ), ) use_desc = ( ("flag", "Description of how USE='flag' affects packages"), ) playground = ResolverPlayground(ebuilds=ebuilds, profile=profile, repo_configs=repo_configs, debug=debug) settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] portdb = playground.trees[playground.eroot]["porttree"].dbapi homedir = os.path.join(eroot, "home") distdir = os.path.join(eprefix, "distdir") test_repo_location = settings.repositories["test_repo"].location profiles_dir = os.path.join(test_repo_location, "profiles") license_dir = os.path.join(test_repo_location, "licenses") repoman_cmd = (portage._python_interpreter, "-b", "-Wd", os.path.join(self.bindir, "repoman")) git_binary = find_binary("git") git_cmd = (git_binary,) cp_binary = find_binary("cp") self.assertEqual(cp_binary is None, False, "cp command not found") cp_cmd = (cp_binary,) test_ebuild = portdb.findname("dev-libs/A-1") self.assertFalse(test_ebuild is None) committer_name = "Gentoo Dev" committer_email = "*****@*****.**" git_test = ( ("", repoman_cmd + ("manifest",)), ("", git_cmd + ("config", "--global", "user.name", committer_name,)), ("", git_cmd + ("config", "--global", "user.email", committer_email,)), ("", git_cmd + ("init-db",)), ("", git_cmd + ("add", ".")), ("", git_cmd + ("commit", "-a", "-m", "add whole repo")), ("", repoman_cmd + ("full", "-d")), ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "2.ebuild")), ("", git_cmd + ("add", test_ebuild[:-8] + "2.ebuild")), ("", repoman_cmd + ("commit", "-m", "cat/pkg: bump to version 2")), ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "3.ebuild")), ("", git_cmd + ("add", test_ebuild[:-8] + "3.ebuild")), ("dev-libs", repoman_cmd + ("commit", "-m", "cat/pkg: bump to version 3")), ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "4.ebuild")), ("", git_cmd + ("add", test_ebuild[:-8] + "4.ebuild")), ("dev-libs/A", repoman_cmd + ("commit", "-m", "cat/pkg: bump to version 4")), ) env = { "PORTAGE_OVERRIDE_EPREFIX" : eprefix, "DISTDIR" : distdir, "GENTOO_COMMITTER_NAME" : committer_name, "GENTOO_COMMITTER_EMAIL" : committer_email, "HOME" : homedir, "PATH" : os.environ["PATH"], "PORTAGE_GRPNAME" : os.environ["PORTAGE_GRPNAME"], "PORTAGE_USERNAME" : os.environ["PORTAGE_USERNAME"], "PORTAGE_REPOSITORIES" : settings.repositories.config_string(), "PYTHONDONTWRITEBYTECODE" : os.environ.get("PYTHONDONTWRITEBYTECODE", ""), } if os.environ.get("SANDBOX_ON") == "1": # avoid problems from nested sandbox instances env["FEATURES"] = "-sandbox -usersandbox" dirs = [homedir, license_dir, profiles_dir, distdir] try: for d in dirs: ensure_dirs(d) with open(os.path.join(test_repo_location, "skel.ChangeLog"), 'w') as f: f.write(copyright_header) with open(os.path.join(profiles_dir, "profiles.desc"), 'w') as f: for x in profiles: f.write("%s %s %s\n" % x) # ResolverPlayground only created the first profile, # so create the remaining ones. for x in profiles[1:]: sub_profile_dir = os.path.join(profiles_dir, x[1]) ensure_dirs(sub_profile_dir) for config_file, lines in profile.items(): file_name = os.path.join(sub_profile_dir, config_file) with open(file_name, "w") as f: for line in lines: f.write("%s\n" % line) for x in licenses: open(os.path.join(license_dir, x), 'wb').close() with open(os.path.join(profiles_dir, "arch.list"), 'w') as f: for x in arch_list: f.write("%s\n" % x) with open(os.path.join(profiles_dir, "use.desc"), 'w') as f: for k, v in use_desc: f.write("%s - %s\n" % (k, v)) for cp, xml_data in metadata_xml_files: with open(os.path.join(test_repo_location, cp, "metadata.xml"), 'w') as f: f.write(playground.metadata_xml_template % xml_data) # Use a symlink to test_repo, in order to trigger bugs # involving canonical vs. non-canonical paths. test_repo_symlink = os.path.join(eroot, "test_repo_symlink") os.symlink(test_repo_location, test_repo_symlink) metadata_xsd_dest = os.path.join(test_repo_location, 'metadata/xml-schema/metadata.xsd') os.makedirs(os.path.dirname(metadata_xsd_dest)) os.symlink(metadata_xsd, metadata_xsd_dest) if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for cwd in ("", "dev-libs", "dev-libs/A", "dev-libs/B"): abs_cwd = os.path.join(test_repo_symlink, cwd) proc = subprocess.Popen(repoman_cmd + ("full",), cwd=abs_cwd, env=env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "repoman failed in %s" % (cwd,)) if git_binary is not None: for cwd, cmd in git_test: abs_cwd = os.path.join(test_repo_symlink, cwd) proc = subprocess.Popen(cmd, cwd=abs_cwd, env=env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "%s failed in %s" % (cmd, cwd,)) finally: playground.cleanup()
def testSimple(self): debug = False install_something = """ S="${WORKDIR}" pkg_pretend() { einfo "called pkg_pretend for $CATEGORY/$PF" } src_install() { einfo "installing something..." insinto /usr/lib/${P} echo "blah blah blah" > "${T}"/regular-file doins "${T}"/regular-file dosym regular-file /usr/lib/${P}/symlink || die # Test CONFIG_PROTECT insinto /etc newins "${T}"/regular-file ${PN}-${SLOT%/*} # Test code for bug #381629, using a copyright symbol encoded with latin-1. # We use $(printf "\\xa9") rather than $'\\xa9', since printf apparently # works in any case, while $'\\xa9' transforms to \\xef\\xbf\\xbd under # some conditions. TODO: Find out why it transforms to \\xef\\xbf\\xbd when # running tests for Python 3.2 (even though it's bash that is ultimately # responsible for performing the transformation). local latin_1_dir=/usr/lib/${P}/latin-1-$(printf "\\xa9")-directory insinto "${latin_1_dir}" echo "blah blah blah" > "${T}"/latin-1-$(printf "\\xa9")-regular-file || die doins "${T}"/latin-1-$(printf "\\xa9")-regular-file dosym latin-1-$(printf "\\xa9")-regular-file ${latin_1_dir}/latin-1-$(printf "\\xa9")-symlink || die } pkg_config() { einfo "called pkg_config for $CATEGORY/$PF" } pkg_info() { einfo "called pkg_info for $CATEGORY/$PF" } pkg_preinst() { einfo "called pkg_preinst for $CATEGORY/$PF" # Test that has_version and best_version work correctly with # prefix (involves internal ROOT -> EROOT calculation in order # to support ROOT override via the environment with EAPIs 3 # and later which support prefix). if has_version $CATEGORY/$PN:$SLOT ; then einfo "has_version detects an installed instance of $CATEGORY/$PN:$SLOT" einfo "best_version reports that the installed instance is $(best_version $CATEGORY/$PN:$SLOT)" else einfo "has_version does not detect an installed instance of $CATEGORY/$PN:$SLOT" fi if [[ ${EPREFIX} != ${PORTAGE_OVERRIDE_EPREFIX} ]] ; then if has_version --host-root $CATEGORY/$PN:$SLOT ; then einfo "has_version --host-root detects an installed instance of $CATEGORY/$PN:$SLOT" einfo "best_version --host-root reports that the installed instance is $(best_version $CATEGORY/$PN:$SLOT)" else einfo "has_version --host-root does not detect an installed instance of $CATEGORY/$PN:$SLOT" fi fi } """ ebuilds = { "dev-libs/A-1": { "EAPI" : "5", "IUSE" : "+flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "MISC_CONTENT": install_something, "RDEPEND": "flag? ( dev-libs/B[flag] )", }, "dev-libs/B-1": { "EAPI" : "5", "IUSE" : "+flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "MISC_CONTENT": install_something, }, "dev-libs/C-1": { "EAPI" : "6", "KEYWORDS": "~x86", "RDEPEND": "dev-libs/D[flag]", }, "dev-libs/D-1": { "EAPI" : "6", "KEYWORDS": "~x86", "IUSE" : "flag", }, "virtual/foo-0": { "EAPI" : "5", "KEYWORDS": "x86", "LICENSE": "GPL-2", }, } installed = { "dev-libs/A-1": { "EAPI" : "5", "IUSE" : "+flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "RDEPEND": "flag? ( dev-libs/B[flag] )", "USE": "flag", }, "dev-libs/B-1": { "EAPI" : "5", "IUSE" : "+flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "USE": "flag", }, "dev-libs/depclean-me-1": { "EAPI" : "5", "IUSE" : "", "KEYWORDS": "x86", "LICENSE": "GPL-2", "USE": "", }, "app-misc/depclean-me-1": { "EAPI" : "5", "IUSE" : "", "KEYWORDS": "x86", "LICENSE": "GPL-2", "RDEPEND": "dev-libs/depclean-me", "USE": "", }, } metadata_xml_files = ( ( "dev-libs/A", { "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>", }, ), ( "dev-libs/B", { "flags" : "<flag name='flag'>Description of how USE='flag' affects this package</flag>", }, ), ) playground = ResolverPlayground( ebuilds=ebuilds, installed=installed, debug=debug) settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] trees = playground.trees portdb = trees[eroot]["porttree"].dbapi test_repo_location = settings.repositories["test_repo"].location var_cache_edb = os.path.join(eprefix, "var", "cache", "edb") cachedir = os.path.join(var_cache_edb, "dep") cachedir_pregen = os.path.join(test_repo_location, "metadata", "md5-cache") portage_python = portage._python_interpreter dispatch_conf_cmd = (portage_python, "-b", "-Wd", os.path.join(self.sbindir, "dispatch-conf")) ebuild_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "ebuild")) egencache_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "egencache"), "--repo", "test_repo", "--repositories-configuration", settings.repositories.config_string()) emerge_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "emerge")) emaint_cmd = (portage_python, "-b", "-Wd", os.path.join(self.sbindir, "emaint")) env_update_cmd = (portage_python, "-b", "-Wd", os.path.join(self.sbindir, "env-update")) etc_update_cmd = (BASH_BINARY, os.path.join(self.sbindir, "etc-update")) fixpackages_cmd = (portage_python, "-b", "-Wd", os.path.join(self.sbindir, "fixpackages")) portageq_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "portageq")) quickpkg_cmd = (portage_python, "-b", "-Wd", os.path.join(self.bindir, "quickpkg")) regenworld_cmd = (portage_python, "-b", "-Wd", os.path.join(self.sbindir, "regenworld")) rm_binary = find_binary("rm") self.assertEqual(rm_binary is None, False, "rm command not found") rm_cmd = (rm_binary,) egencache_extra_args = [] if self._have_python_xml(): egencache_extra_args.append("--update-use-local-desc") test_ebuild = portdb.findname("dev-libs/A-1") self.assertFalse(test_ebuild is None) cross_prefix = os.path.join(eprefix, "cross_prefix") cross_root = os.path.join(eprefix, "cross_root") cross_eroot = os.path.join(cross_root, eprefix.lstrip(os.sep)) test_commands = ( env_update_cmd, portageq_cmd + ("envvar", "-v", "CONFIG_PROTECT", "EROOT", "PORTAGE_CONFIGROOT", "PORTAGE_TMPDIR", "USERLAND"), etc_update_cmd, dispatch_conf_cmd, emerge_cmd + ("--version",), emerge_cmd + ("--info",), emerge_cmd + ("--info", "--verbose"), emerge_cmd + ("--list-sets",), emerge_cmd + ("--check-news",), rm_cmd + ("-rf", cachedir), rm_cmd + ("-rf", cachedir_pregen), emerge_cmd + ("--regen",), rm_cmd + ("-rf", cachedir), ({"FEATURES" : "metadata-transfer"},) + \ emerge_cmd + ("--regen",), rm_cmd + ("-rf", cachedir), ({"FEATURES" : "metadata-transfer"},) + \ emerge_cmd + ("--regen",), rm_cmd + ("-rf", cachedir), egencache_cmd + ("--update",) + tuple(egencache_extra_args), ({"FEATURES" : "metadata-transfer"},) + \ emerge_cmd + ("--metadata",), rm_cmd + ("-rf", cachedir), ({"FEATURES" : "metadata-transfer"},) + \ emerge_cmd + ("--metadata",), emerge_cmd + ("--metadata",), rm_cmd + ("-rf", cachedir), emerge_cmd + ("--oneshot", "virtual/foo"), lambda: self.assertFalse(os.path.exists( os.path.join(pkgdir, "virtual", "foo-0.tbz2"))), ({"FEATURES" : "unmerge-backup"},) + \ emerge_cmd + ("--unmerge", "virtual/foo"), lambda: self.assertTrue(os.path.exists( os.path.join(pkgdir, "virtual", "foo-0.tbz2"))), emerge_cmd + ("--pretend", "dev-libs/A"), ebuild_cmd + (test_ebuild, "manifest", "clean", "package", "merge"), emerge_cmd + ("--pretend", "--tree", "--complete-graph", "dev-libs/A"), emerge_cmd + ("-p", "dev-libs/B"), emerge_cmd + ("-p", "--newrepo", "dev-libs/B"), emerge_cmd + ("-B", "dev-libs/B",), emerge_cmd + ("--oneshot", "--usepkg", "dev-libs/B",), # trigger clean prior to pkg_pretend as in bug #390711 ebuild_cmd + (test_ebuild, "unpack"), emerge_cmd + ("--oneshot", "dev-libs/A",), emerge_cmd + ("--noreplace", "dev-libs/A",), emerge_cmd + ("--config", "dev-libs/A",), emerge_cmd + ("--info", "dev-libs/A", "dev-libs/B"), emerge_cmd + ("--pretend", "--depclean", "--verbose", "dev-libs/B"), emerge_cmd + ("--pretend", "--depclean",), emerge_cmd + ("--depclean",), quickpkg_cmd + ("--include-config", "y", "dev-libs/A",), # Test bug #523684, where a file renamed or removed by the # admin forces replacement files to be merged with config # protection. lambda: self.assertEqual(0, len(list(find_updated_config_files(eroot, shlex_split(settings["CONFIG_PROTECT"]))))), lambda: os.unlink(os.path.join(eprefix, "etc", "A-0")), emerge_cmd + ("--usepkgonly", "dev-libs/A"), lambda: self.assertEqual(1, len(list(find_updated_config_files(eroot, shlex_split(settings["CONFIG_PROTECT"]))))), emaint_cmd + ("--check", "all"), emaint_cmd + ("--fix", "all"), fixpackages_cmd, regenworld_cmd, portageq_cmd + ("match", eroot, "dev-libs/A"), portageq_cmd + ("best_visible", eroot, "dev-libs/A"), portageq_cmd + ("best_visible", eroot, "binary", "dev-libs/A"), portageq_cmd + ("contents", eroot, "dev-libs/A-1"), portageq_cmd + ("metadata", eroot, "ebuild", "dev-libs/A-1", "EAPI", "IUSE", "RDEPEND"), portageq_cmd + ("metadata", eroot, "binary", "dev-libs/A-1", "EAPI", "USE", "RDEPEND"), portageq_cmd + ("metadata", eroot, "installed", "dev-libs/A-1", "EAPI", "USE", "RDEPEND"), portageq_cmd + ("owners", eroot, eroot + "usr"), emerge_cmd + ("-p", eroot + "usr"), emerge_cmd + ("-p", "--unmerge", "-q", eroot + "usr"), emerge_cmd + ("--unmerge", "--quiet", "dev-libs/A"), emerge_cmd + ("-C", "--quiet", "dev-libs/B"), emerge_cmd + ("--autounmask-continue", "dev-libs/C",), # Verify that the above --autounmask-continue command caused # USE=flag to be applied correctly to dev-libs/D. portageq_cmd + ("match", eroot, "dev-libs/D[flag]"), # Test cross-prefix usage, including chpathtool for binpkgs. ({"EPREFIX" : cross_prefix},) + \ emerge_cmd + ("--usepkgonly", "dev-libs/A"), ({"EPREFIX" : cross_prefix},) + \ portageq_cmd + ("has_version", cross_prefix, "dev-libs/A"), ({"EPREFIX" : cross_prefix},) + \ portageq_cmd + ("has_version", cross_prefix, "dev-libs/B"), ({"EPREFIX" : cross_prefix},) + \ emerge_cmd + ("-C", "--quiet", "dev-libs/B"), ({"EPREFIX" : cross_prefix},) + \ emerge_cmd + ("-C", "--quiet", "dev-libs/A"), ({"EPREFIX" : cross_prefix},) + \ emerge_cmd + ("dev-libs/A",), ({"EPREFIX" : cross_prefix},) + \ portageq_cmd + ("has_version", cross_prefix, "dev-libs/A"), ({"EPREFIX" : cross_prefix},) + \ portageq_cmd + ("has_version", cross_prefix, "dev-libs/B"), # Test ROOT support ({"ROOT": cross_root},) + emerge_cmd + ("dev-libs/B",), portageq_cmd + ("has_version", cross_eroot, "dev-libs/B"), ) distdir = playground.distdir pkgdir = playground.pkgdir fake_bin = os.path.join(eprefix, "bin") portage_tmpdir = os.path.join(eprefix, "var", "tmp", "portage") profile_path = settings.profile_path user_config_dir = os.path.join(os.sep, eprefix, USER_CONFIG_PATH) path = os.environ.get("PATH") if path is not None and not path.strip(): path = None if path is None: path = "" else: path = ":" + path path = fake_bin + path pythonpath = os.environ.get("PYTHONPATH") if pythonpath is not None and not pythonpath.strip(): pythonpath = None if pythonpath is not None and \ pythonpath.split(":")[0] == PORTAGE_PYM_PATH: pass else: if pythonpath is None: pythonpath = "" else: pythonpath = ":" + pythonpath pythonpath = PORTAGE_PYM_PATH + pythonpath env = { "PORTAGE_OVERRIDE_EPREFIX" : eprefix, "CLEAN_DELAY" : "0", "DISTDIR" : distdir, "EMERGE_WARNING_DELAY" : "0", "INFODIR" : "", "INFOPATH" : "", "PATH" : path, "PKGDIR" : pkgdir, "PORTAGE_INST_GID" : str(portage.data.portage_gid), "PORTAGE_INST_UID" : str(portage.data.portage_uid), "PORTAGE_PYTHON" : portage_python, "PORTAGE_REPOSITORIES" : settings.repositories.config_string(), "PORTAGE_TMPDIR" : portage_tmpdir, "PYTHONDONTWRITEBYTECODE" : os.environ.get("PYTHONDONTWRITEBYTECODE", ""), "PYTHONPATH" : pythonpath, "__PORTAGE_TEST_PATH_OVERRIDE" : fake_bin, } if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: env["__PORTAGE_TEST_HARDLINK_LOCKS"] = \ os.environ["__PORTAGE_TEST_HARDLINK_LOCKS"] updates_dir = os.path.join(test_repo_location, "profiles", "updates") dirs = [cachedir, cachedir_pregen, cross_eroot, cross_prefix, distdir, fake_bin, portage_tmpdir, updates_dir, user_config_dir, var_cache_edb] etc_symlinks = ("dispatch-conf.conf", "etc-update.conf") # Override things that may be unavailable, or may have portability # issues when running tests in exotic environments. # prepstrip - bug #447810 (bash read builtin EINTR problem) true_symlinks = ["find", "prepstrip", "sed", "scanelf"] true_binary = find_binary("true") self.assertEqual(true_binary is None, False, "true command not found") try: for d in dirs: ensure_dirs(d) for x in true_symlinks: os.symlink(true_binary, os.path.join(fake_bin, x)) for x in etc_symlinks: os.symlink(os.path.join(self.cnf_etc_path, x), os.path.join(eprefix, "etc", x)) with open(os.path.join(var_cache_edb, "counter"), 'wb') as f: f.write(b"100") # non-empty system set keeps --depclean quiet with open(os.path.join(profile_path, "packages"), 'w') as f: f.write("*dev-libs/token-system-pkg") for cp, xml_data in metadata_xml_files: with open(os.path.join(test_repo_location, cp, "metadata.xml"), 'w') as f: f.write(playground.metadata_xml_template % xml_data) with open(os.path.join(updates_dir, "1Q-2010"), 'w') as f: f.write(""" slotmove =app-doc/pms-3 2 3 move dev-util/git dev-vcs/git """) if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for args in test_commands: if hasattr(args, '__call__'): args() continue if isinstance(args[0], dict): local_env = env.copy() local_env.update(args[0]) args = args[1:] else: local_env = env proc = subprocess.Popen(args, env=local_env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "emerge failed with args %s" % (args,)) finally: playground.cleanup()
def _start(self): tar_options = "" if "xattr" in self.features: process = subprocess.Popen(["tar", "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) output = process.communicate()[0] if b"--xattrs" in output: tar_options = ["--xattrs", "--xattrs-include='*'"] for x in portage.util.shlex_split(self.env.get("PORTAGE_XATTR_EXCLUDE", "")): tar_options.append(portage._shell_quote("--xattrs-exclude=%s" % x)) tar_options = " ".join(tar_options) decomp = _compressors.get(compression_probe(self.pkg_path)) if decomp is not None: decomp_cmd = decomp.get("decompress") else: decomp_cmd = None if decomp_cmd is None: self.scheduler.output("!!! %s\n" % _("File compression header unrecognized: %s") % self.pkg_path, log_path=self.logfile, background=self.background, level=logging.ERROR) self.returncode = 1 self._async_wait() return try: decompression_binary = shlex_split(varexpand(decomp_cmd, mydict=self.env))[0] except IndexError: decompression_binary = "" if find_binary(decompression_binary) is None: # Try alternative command if it exists if _compressors.get(compression_probe(self.pkg_path)).get("decompress_alt"): decomp_cmd = _compressors.get( compression_probe(self.pkg_path)).get("decompress_alt") try: decompression_binary = shlex_split(varexpand(decomp_cmd, mydict=self.env))[0] except IndexError: decompression_binary = "" if find_binary(decompression_binary) is None: missing_package = _compressors.get(compression_probe(self.pkg_path)).get("package") self.scheduler.output("!!! %s\n" % _("File compression unsupported %s.\n Command was: %s.\n Maybe missing package: %s") % (self.pkg_path, varexpand(decomp_cmd, mydict=self.env), missing_package), log_path=self.logfile, background=self.background, level=logging.ERROR) self.returncode = 1 self._async_wait() return # Add -q to decomp_cmd opts, in order to avoid "trailing garbage # after EOF ignored" warning messages due to xpak trailer. # SIGPIPE handling (128 + SIGPIPE) should be compatible with # assert_sigpipe_ok() that's used by the ebuild unpack() helper. self.args = [self._shell_binary, "-c", ("%s -cq -- %s | tar -xp %s -C %s -f - ; " + \ "p=(${PIPESTATUS[@]}) ; " + \ "if [[ ${p[0]} != 0 && ${p[0]} != %d ]] ; then " % (128 + signal.SIGPIPE) + \ "echo bzip2 failed with status ${p[0]} ; exit ${p[0]} ; fi ; " + \ "if [ ${p[1]} != 0 ] ; then " + \ "echo tar failed with status ${p[1]} ; exit ${p[1]} ; fi ; " + \ "exit 0 ;") % \ (decomp_cmd, portage._shell_quote(self.pkg_path), tar_options, portage._shell_quote(self.image_dir))] SpawnProcess._start(self)
def _env_update(makelinks, target_root, prev_mtimes, contents, env, writemsg_level): if writemsg_level is None: writemsg_level = portage.util.writemsg_level if target_root is None: target_root = portage.settings["ROOT"] if prev_mtimes is None: prev_mtimes = portage.mtimedb["ldpath"] if env is None: settings = portage.settings else: settings = env eprefix = settings.get("EPREFIX", "") eprefix_lstrip = eprefix.lstrip(os.sep) envd_dir = os.path.join(target_root, eprefix_lstrip, "etc", "env.d") ensure_dirs(envd_dir, mode=0o755) fns = listdir(envd_dir, EmptyOnError=1) fns.sort() templist = [] for x in fns: if len(x) < 3: continue if not x[0].isdigit() or not x[1].isdigit(): continue if x.startswith(".") or x.endswith("~") or x.endswith(".bak"): continue templist.append(x) fns = templist del templist space_separated = set(["CONFIG_PROTECT", "CONFIG_PROTECT_MASK"]) colon_separated = set(["ADA_INCLUDE_PATH", "ADA_OBJECTS_PATH", "CLASSPATH", "INFODIR", "INFOPATH", "KDEDIRS", "LDPATH", "MANPATH", "PATH", "PKG_CONFIG_PATH", "PRELINK_PATH", "PRELINK_PATH_MASK", "PYTHONPATH", "ROOTPATH"]) config_list = [] for x in fns: file_path = os.path.join(envd_dir, x) try: myconfig = getconfig(file_path, expand=False) except ParseError as e: writemsg("!!! '%s'\n" % str(e), noiselevel=-1) del e continue if myconfig is None: # broken symlink or file removed by a concurrent process writemsg("!!! File Not Found: '%s'\n" % file_path, noiselevel=-1) continue config_list.append(myconfig) if "SPACE_SEPARATED" in myconfig: space_separated.update(myconfig["SPACE_SEPARATED"].split()) del myconfig["SPACE_SEPARATED"] if "COLON_SEPARATED" in myconfig: colon_separated.update(myconfig["COLON_SEPARATED"].split()) del myconfig["COLON_SEPARATED"] env = {} specials = {} for var in space_separated: mylist = [] for myconfig in config_list: if var in myconfig: for item in myconfig[var].split(): if item and not item in mylist: mylist.append(item) del myconfig[var] # prepare for env.update(myconfig) if mylist: env[var] = " ".join(mylist) specials[var] = mylist for var in colon_separated: mylist = [] for myconfig in config_list: if var in myconfig: for item in myconfig[var].split(":"): if item and not item in mylist: mylist.append(item) del myconfig[var] # prepare for env.update(myconfig) if mylist: env[var] = ":".join(mylist) specials[var] = mylist for myconfig in config_list: """Cumulative variables have already been deleted from myconfig so that they won't be overwritten by this dict.update call.""" env.update(myconfig) ldsoconf_path = os.path.join( target_root, eprefix_lstrip, "etc", "ld.so.conf") try: myld = io.open(_unicode_encode(ldsoconf_path, encoding=_encodings['fs'], errors='strict'), mode='r', encoding=_encodings['content'], errors='replace') myldlines=myld.readlines() myld.close() oldld=[] for x in myldlines: #each line has at least one char (a newline) if x[:1] == "#": continue oldld.append(x[:-1]) except (IOError, OSError) as e: if e.errno != errno.ENOENT: raise oldld = None newld = specials["LDPATH"] if (oldld != newld): #ld.so.conf needs updating and ldconfig needs to be run myfd = atomic_ofstream(ldsoconf_path) myfd.write("# ld.so.conf autogenerated by env-update; make all changes to\n") myfd.write("# contents of /etc/env.d directory\n") for x in specials["LDPATH"]: myfd.write(x + "\n") myfd.close() # Update prelink.conf if we are prelink-enabled if prelink_capable: newprelink = atomic_ofstream(os.path.join( target_root, eprefix_lstrip, "etc", "prelink.conf")) newprelink.write("# prelink.conf autogenerated by env-update; make all changes to\n") newprelink.write("# contents of /etc/env.d directory\n") for x in ["/bin","/sbin","/usr/bin","/usr/sbin","/lib","/usr/lib"]: newprelink.write("-l %s\n" % (x,)); prelink_paths = [] prelink_paths += specials.get("LDPATH", []) prelink_paths += specials.get("PATH", []) prelink_paths += specials.get("PRELINK_PATH", []) prelink_path_mask = specials.get("PRELINK_PATH_MASK", []) for x in prelink_paths: if not x: continue if x[-1:] != '/': x += "/" plmasked = 0 for y in prelink_path_mask: if not y: continue if y[-1] != '/': y += "/" if y == x[0:len(y)]: plmasked = 1 break if not plmasked: newprelink.write("-h %s\n" % (x,)) for x in prelink_path_mask: newprelink.write("-b %s\n" % (x,)) newprelink.close() current_time = long(time.time()) mtime_changed = False lib_dirs = set() for lib_dir in set(specials["LDPATH"] + \ ['usr/lib','usr/lib64','usr/lib32','lib','lib64','lib32']): x = os.path.join(target_root, eprefix_lstrip, lib_dir.lstrip(os.sep)) try: newldpathtime = os.stat(x)[stat.ST_MTIME] lib_dirs.add(normalize_path(x)) except OSError as oe: if oe.errno == errno.ENOENT: try: del prev_mtimes[x] except KeyError: pass # ignore this path because it doesn't exist continue raise if newldpathtime == current_time: # Reset mtime to avoid the potential ambiguity of times that # differ by less than 1 second. newldpathtime -= 1 os.utime(x, (newldpathtime, newldpathtime)) prev_mtimes[x] = newldpathtime mtime_changed = True elif x in prev_mtimes: if prev_mtimes[x] == newldpathtime: pass else: prev_mtimes[x] = newldpathtime mtime_changed = True else: prev_mtimes[x] = newldpathtime mtime_changed = True if makelinks and \ not mtime_changed and \ contents is not None: libdir_contents_changed = False for mypath, mydata in contents.items(): if mydata[0] not in ("obj", "sym"): continue head, tail = os.path.split(mypath) if head in lib_dirs: libdir_contents_changed = True break if not libdir_contents_changed: makelinks = False ldconfig = "/sbin/ldconfig" if "CHOST" in settings and "CBUILD" in settings and \ settings["CHOST"] != settings["CBUILD"]: ldconfig = find_binary("%s-ldconfig" % settings["CHOST"]) # Only run ldconfig as needed if makelinks and ldconfig and not eprefix: # ldconfig has very different behaviour between FreeBSD and Linux if ostype == "Linux" or ostype.lower().endswith("gnu"): # We can't update links if we haven't cleaned other versions first, as # an older package installed ON TOP of a newer version will cause ldconfig # to overwrite the symlinks we just made. -X means no links. After 'clean' # we can safely create links. writemsg_level(_(">>> Regenerating %setc/ld.so.cache...\n") % \ (target_root,)) os.system("cd / ; %s -X -r '%s'" % (ldconfig, target_root)) elif ostype in ("FreeBSD","DragonFly"): writemsg_level(_(">>> Regenerating %svar/run/ld-elf.so.hints...\n") % \ target_root) os.system(("cd / ; %s -elf -i " + \ "-f '%svar/run/ld-elf.so.hints' '%setc/ld.so.conf'") % \ (ldconfig, target_root, target_root)) del specials["LDPATH"] penvnotice = "# THIS FILE IS AUTOMATICALLY GENERATED BY env-update.\n" penvnotice += "# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES\n" cenvnotice = penvnotice[:] penvnotice += "# GO INTO /etc/profile NOT /etc/profile.env\n\n" cenvnotice += "# GO INTO /etc/csh.cshrc NOT /etc/csh.env\n\n" #create /etc/profile.env for bash support outfile = atomic_ofstream(os.path.join( target_root, eprefix_lstrip, "etc", "profile.env")) outfile.write(penvnotice) env_keys = [ x for x in env if x != "LDPATH" ] env_keys.sort() for k in env_keys: v = env[k] if v.startswith('$') and not v.startswith('${'): outfile.write("export %s=$'%s'\n" % (k, v[1:])) else: outfile.write("export %s='%s'\n" % (k, v)) outfile.close() #create /etc/csh.env for (t)csh support outfile = atomic_ofstream(os.path.join( target_root, eprefix_lstrip, "etc", "csh.env")) outfile.write(cenvnotice) for x in env_keys: outfile.write("setenv %s '%s'\n" % (x, env[x])) outfile.close()
def testSimple(self): debug = False skip_reason = self._must_skip() if skip_reason: self.portage_skip = skip_reason self.assertFalse(True, skip_reason) return copyright_header = """# Copyright 1999-%s Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ """ % time.gmtime().tm_year repo_configs = { "test_repo": { "layout.conf": ("update-changelog = true", ), } } profiles = ( ("x86", "default/linux/x86/test_profile", "stable"), ("x86", "default/linux/x86/test_dev", "dev"), ("x86", "default/linux/x86/test_exp", "exp"), ) profile = { "eapi": ("5", ), "package.use.stable.mask": ("dev-libs/A flag", ) } ebuilds = { "dev-libs/A-0": { "COPYRIGHT_HEADER": copyright_header, "DESCRIPTION": "Desc goes here", "EAPI": "5", "HOMEPAGE": "http://example.com", "IUSE": "flag", "KEYWORDS": "x86", "LICENSE": "GPL-2", "RDEPEND": "flag? ( dev-libs/B[flag] )", }, "dev-libs/A-1": { "COPYRIGHT_HEADER": copyright_header, "DESCRIPTION": "Desc goes here", "EAPI": "4", "HOMEPAGE": "http://example.com", "IUSE": "flag", "KEYWORDS": "~x86", "LICENSE": "GPL-2", "RDEPEND": "flag? ( dev-libs/B[flag] )", }, "dev-libs/B-1": { "COPYRIGHT_HEADER": copyright_header, "DESCRIPTION": "Desc goes here", "EAPI": "4", "HOMEPAGE": "http://example.com", "IUSE": "flag", "KEYWORDS": "~x86", "LICENSE": "GPL-2", }, "dev-libs/C-0": { "COPYRIGHT_HEADER": copyright_header, "DESCRIPTION": "Desc goes here", "EAPI": "4", "HOMEPAGE": "http://example.com", "IUSE": "flag", # must be unstable, since dev-libs/A[flag] is stable masked "KEYWORDS": "~x86", "LICENSE": "GPL-2", "RDEPEND": "flag? ( dev-libs/A[flag] )", }, } licenses = ["GPL-2"] arch_list = ["x86"] metadata_dtd = os.path.join(PORTAGE_BASE_PATH, "cnf/metadata.dtd") metadata_xml_files = ( ( "dev-libs/A", { "herd": "base-system", "flags": "<flag name='flag' restrict='>=dev-libs/A-0'>Description of how USE='flag' affects this package</flag>", }, ), ( "dev-libs/B", { "herd": "no-herd", "flags": "<flag name='flag'>Description of how USE='flag' affects this package</flag>", }, ), ( "dev-libs/C", { "herd": "no-herd", "flags": "<flag name='flag'>Description of how USE='flag' affects this package</flag>", }, ), ) use_desc = (("flag", "Description of how USE='flag' affects packages"), ) playground = ResolverPlayground(ebuilds=ebuilds, profile=profile, repo_configs=repo_configs, debug=debug) settings = playground.settings eprefix = settings["EPREFIX"] eroot = settings["EROOT"] portdb = playground.trees[playground.eroot]["porttree"].dbapi homedir = os.path.join(eroot, "home") distdir = os.path.join(eprefix, "distdir") test_repo_location = settings.repositories["test_repo"].location profiles_dir = os.path.join(test_repo_location, "profiles") license_dir = os.path.join(test_repo_location, "licenses") repoman_cmd = (portage._python_interpreter, "-Wd", os.path.join(PORTAGE_BIN_PATH, "repoman")) git_binary = find_binary("git") git_cmd = (git_binary, ) cp_binary = find_binary("cp") self.assertEqual(cp_binary is None, False, "cp command not found") cp_cmd = (cp_binary, ) test_ebuild = portdb.findname("dev-libs/A-1") self.assertFalse(test_ebuild is None) committer_name = "Gentoo Dev" committer_email = "*****@*****.**" git_test = ( ("", repoman_cmd + ("manifest", )), ("", git_cmd + ( "config", "--global", "user.name", committer_name, )), ("", git_cmd + ( "config", "--global", "user.email", committer_email, )), ("", git_cmd + ("init-db", )), ("", git_cmd + ("add", ".")), ("", git_cmd + ("commit", "-a", "-m", "add whole repo")), ("", repoman_cmd + ("full", "-d")), ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "2.ebuild")), ("", git_cmd + ("add", test_ebuild[:-8] + "2.ebuild")), ("", repoman_cmd + ("commit", "-m", "bump to version 2")), ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "3.ebuild")), ("", git_cmd + ("add", test_ebuild[:-8] + "3.ebuild")), ("dev-libs", repoman_cmd + ("commit", "-m", "bump to version 3")), ("", cp_cmd + (test_ebuild, test_ebuild[:-8] + "4.ebuild")), ("", git_cmd + ("add", test_ebuild[:-8] + "4.ebuild")), ("dev-libs/A", repoman_cmd + ("commit", "-m", "bump to version 4")), ) pythonpath = os.environ.get("PYTHONPATH") if pythonpath is not None and not pythonpath.strip(): pythonpath = None if pythonpath is not None and \ pythonpath.split(":")[0] == PORTAGE_PYM_PATH: pass else: if pythonpath is None: pythonpath = "" else: pythonpath = ":" + pythonpath pythonpath = PORTAGE_PYM_PATH + pythonpath env = { "PORTAGE_OVERRIDE_EPREFIX": eprefix, "DISTDIR": distdir, "GENTOO_COMMITTER_NAME": committer_name, "GENTOO_COMMITTER_EMAIL": committer_email, "HOME": homedir, "PATH": os.environ["PATH"], "PORTAGE_GRPNAME": os.environ["PORTAGE_GRPNAME"], "PORTAGE_USERNAME": os.environ["PORTAGE_USERNAME"], "PORTAGE_REPOSITORIES": settings.repositories.config_string(), "PYTHONPATH": pythonpath, } if os.environ.get("SANDBOX_ON") == "1": # avoid problems from nested sandbox instances env["FEATURES"] = "-sandbox -usersandbox" dirs = [homedir, license_dir, profiles_dir, distdir] try: for d in dirs: ensure_dirs(d) with open(os.path.join(test_repo_location, "skel.ChangeLog"), 'w') as f: f.write(copyright_header) with open(os.path.join(profiles_dir, "profiles.desc"), 'w') as f: for x in profiles: f.write("%s %s %s\n" % x) # ResolverPlayground only created the first profile, # so create the remaining ones. for x in profiles[1:]: sub_profile_dir = os.path.join(profiles_dir, x[1]) ensure_dirs(sub_profile_dir) for config_file, lines in profile.items(): file_name = os.path.join(sub_profile_dir, config_file) with open(file_name, "w") as f: for line in lines: f.write("%s\n" % line) for x in licenses: open(os.path.join(license_dir, x), 'wb').close() with open(os.path.join(profiles_dir, "arch.list"), 'w') as f: for x in arch_list: f.write("%s\n" % x) with open(os.path.join(profiles_dir, "use.desc"), 'w') as f: for k, v in use_desc: f.write("%s - %s\n" % (k, v)) for cp, xml_data in metadata_xml_files: with open(os.path.join(test_repo_location, cp, "metadata.xml"), 'w') as f: f.write(playground.metadata_xml_template % xml_data) # Use a symlink to test_repo, in order to trigger bugs # involving canonical vs. non-canonical paths. test_repo_symlink = os.path.join(eroot, "test_repo_symlink") os.symlink(test_repo_location, test_repo_symlink) # repoman checks metadata.dtd for recent CTIME, so copy the file in # order to ensure that the CTIME is current shutil.copyfile(metadata_dtd, os.path.join(distdir, "metadata.dtd")) if debug: # The subprocess inherits both stdout and stderr, for # debugging purposes. stdout = None else: # The subprocess inherits stderr so that any warnings # triggered by python -Wd will be visible. stdout = subprocess.PIPE for cwd in ("", "dev-libs", "dev-libs/A", "dev-libs/B"): abs_cwd = os.path.join(test_repo_symlink, cwd) proc = subprocess.Popen([ portage._python_interpreter, "-Wd", os.path.join(PORTAGE_BIN_PATH, "repoman"), "full" ], cwd=abs_cwd, env=env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "repoman failed in %s" % (cwd, )) if git_binary is not None: for cwd, cmd in git_test: abs_cwd = os.path.join(test_repo_symlink, cwd) proc = subprocess.Popen(cmd, cwd=abs_cwd, env=env, stdout=stdout) if debug: proc.wait() else: output = proc.stdout.readlines() proc.wait() proc.stdout.close() if proc.returncode != os.EX_OK: for line in output: sys.stderr.write(_unicode_decode(line)) self.assertEqual(os.EX_OK, proc.returncode, "%s failed in %s" % ( cmd, cwd, )) finally: playground.cleanup()