Exemple #1
0
    def _testAsynchronousLock(self):
        scheduler = global_event_loop()
        tempdir = tempfile.mkdtemp()
        try:
            path = os.path.join(tempdir, 'lock_me')
            for force_async in (True, False):
                for force_dummy in ((False, ) if dummy_threading is None else
                                    (True, False)):
                    async_lock = AsynchronousLock(path=path,
                                                  scheduler=scheduler,
                                                  _force_async=force_async,
                                                  _force_thread=True,
                                                  _force_dummy=force_dummy)
                    scheduler.run_until_complete(async_lock.async_start())
                    self.assertEqual(async_lock.wait(), os.EX_OK)
                    self.assertEqual(async_lock.returncode, os.EX_OK)
                    scheduler.run_until_complete(async_lock.async_unlock())

                async_lock = AsynchronousLock(path=path,
                                              scheduler=scheduler,
                                              _force_async=force_async,
                                              _force_process=True)
                scheduler.run_until_complete(async_lock.async_start())
                self.assertEqual(async_lock.wait(), os.EX_OK)
                self.assertEqual(async_lock.returncode, os.EX_OK)
                scheduler.run_until_complete(async_lock.async_unlock())
        finally:
            shutil.rmtree(tempdir)
Exemple #2
0
    def async_lock(self):
        """
		This raises an AlreadyLocked exception if lock() is called
		while a lock is already held. In order to avoid this, call
		unlock() or check whether the "locked" attribute is True
		or False before calling lock().
		"""
        if self._lock_obj is not None:
            raise self.AlreadyLocked((self._lock_obj, ))

        result = self.scheduler.create_future()

        def acquired_lock(async_lock):
            if async_lock.wait() == os.EX_OK:
                self.locked = True
                result.set_result(None)
            else:
                result.set_exception(
                    AssertionError(
                        "AsynchronousLock failed with returncode %s" %
                        (async_lock.returncode, )))

        self._lock_obj = AsynchronousLock(path=self.pkg_path,
                                          scheduler=self.scheduler)
        self._lock_obj.addExitListener(acquired_lock)
        self._lock_obj.start()
        return result
Exemple #3
0
    def _testAsynchronousLockWaitKill(self):
        scheduler = global_event_loop()
        tempdir = tempfile.mkdtemp()
        try:
            path = os.path.join(tempdir, 'lock_me')
            lock1 = AsynchronousLock(path=path, scheduler=scheduler)
            scheduler.run_until_complete(lock1.async_start())
            self.assertEqual(lock1.wait(), os.EX_OK)
            self.assertEqual(lock1.returncode, os.EX_OK)
            lock2 = AsynchronousLock(path=path,
                                     scheduler=scheduler,
                                     _force_async=True,
                                     _force_process=True)
            scheduler.run_until_complete(lock2.async_start())
            # lock2 should be waiting for lock1 to release
            self.assertEqual(lock2.poll(), None)
            self.assertEqual(lock2.returncode, None)

            # Kill lock2's process and then check wait() and
            # returncode results. This is intended to simulate
            # a SIGINT sent via the controlling tty.
            self.assertEqual(lock2._imp is not None, True)
            self.assertEqual(lock2._imp._proc is not None, True)
            self.assertEqual(lock2._imp._proc.pid is not None, True)
            lock2._imp._kill_test = True
            os.kill(lock2._imp._proc.pid, signal.SIGTERM)
            self.assertEqual(lock2.wait() == os.EX_OK, False)
            self.assertEqual(lock2.returncode == os.EX_OK, False)
            self.assertEqual(lock2.returncode is None, False)
            scheduler.run_until_complete(lock1.async_unlock())
        finally:
            shutil.rmtree(tempdir)
Exemple #4
0
    def _start_lock(self):
        if (self.phase in self._locked_phases
                and "ebuild-locks" in self.settings.features):
            eroot = self.settings["EROOT"]
            lock_path = os.path.join(eroot, portage.VDB_PATH + "-ebuild")
            if os.access(os.path.dirname(lock_path), os.W_OK):
                self._ebuild_lock = AsynchronousLock(path=lock_path,
                                                     scheduler=self.scheduler)
                self._start_task(self._ebuild_lock, self._lock_exit)
                return

        self._start_ebuild()
    def async_unlock(self):
        """
		Release the lock asynchronously. Release notification is available
		via the add_done_callback method of the returned Future instance.

		@returns: Future, result is None
		"""
        if self._lock_obj is not None:
            yield self._lock_obj.async_unlock()

            self._lock_obj = None
            self.locked = False
            self.settings.pop('PORTAGE_BUILDDIR_LOCKED', None)
            catdir_lock = AsynchronousLock(path=self._catdir,
                                           scheduler=self.scheduler)
            try:
                yield catdir_lock.async_start()
                yield catdir_lock.async_wait()
            except asyncio.CancelledError:
                if catdir_lock.poll() is None:
                    catdir_lock.cancel()
                raise

            if catdir_lock.returncode == os.EX_OK:
                try:
                    os.rmdir(self._catdir)
                except OSError:
                    pass
                yield catdir_lock.async_unlock()
Exemple #6
0
	def async_lock(self):
		"""
		This raises an AlreadyLocked exception if lock() is called
		while a lock is already held. In order to avoid this, call
		unlock() or check whether the "locked" attribute is True
		or False before calling lock().
		"""
		if self._lock_obj is not None:
			raise self.AlreadyLocked((self._lock_obj,))

		result = self.scheduler.create_future()

		def acquired_lock(async_lock):
			if async_lock.wait() == os.EX_OK:
				self.locked = True
				result.set_result(None)
			else:
				result.set_exception(AssertionError(
					"AsynchronousLock failed with returncode %s"
					% (async_lock.returncode,)))

		self._lock_obj = AsynchronousLock(path=self.pkg_path,
			scheduler=self.scheduler)
		self._lock_obj.addExitListener(acquired_lock)
		self._lock_obj.start()
		return result
Exemple #7
0
    def _start_lock(self):
        if self.phase in self._locked_phases and "ebuild-locks" in self.settings.features:
            eroot = self.settings["EROOT"]
            lock_path = os.path.join(eroot, portage.VDB_PATH + "-ebuild")
            if os.access(os.path.dirname(lock_path), os.W_OK):
                self._ebuild_lock = AsynchronousLock(path=lock_path, scheduler=self.scheduler)
                self._start_task(self._ebuild_lock, self._lock_exit)
                return

        self._start_ebuild()
Exemple #8
0
    def lock(self):
        """
		This raises an AlreadyLocked exception if lock() is called
		while a lock is already held. In order to avoid this, call
		unlock() or check whether the "locked" attribute is True
		or False before calling lock().
		"""
        if self._lock_obj is not None:
            raise self.AlreadyLocked((self._lock_obj, ))

        async_lock = AsynchronousLock(path=self.pkg_path,
                                      scheduler=self.scheduler)
        async_lock.start()

        if async_lock.wait() != os.EX_OK:
            # TODO: Use CompositeTask for better handling, like in EbuildPhase.
            raise AssertionError("AsynchronousLock failed with returncode %s" \
             % (async_lock.returncode,))

        self._lock_obj = async_lock
        self.locked = True
Exemple #9
0
	def lock(self):
		"""
		This raises an AlreadyLocked exception if lock() is called
		while a lock is already held. In order to avoid this, call
		unlock() or check whether the "locked" attribute is True
		or False before calling lock().
		"""
		if self._lock_obj is not None:
			raise self.AlreadyLocked((self._lock_obj,))

		async_lock = AsynchronousLock(path=self.pkg_path,
			scheduler=self.scheduler)
		async_lock.start()

		if async_lock.wait() != os.EX_OK:
			# TODO: Use CompositeTask for better handling, like in EbuildPhase.
			raise AssertionError("AsynchronousLock failed with returncode %s" \
				% (async_lock.returncode,))

		self._lock_obj = async_lock
		self.locked = True
Exemple #10
0
 def builddir_unlocked(future):
     if future.exception() is not None:
         result.set_exception(future.exception())
     else:
         self._lock_obj = None
         self.locked = False
         self.settings.pop('PORTAGE_BUILDDIR_LOCKED', None)
         catdir_lock = AsynchronousLock(path=self._catdir,
                                        scheduler=self.scheduler)
         catdir_lock.addExitListener(catdir_locked)
         catdir_lock.start()
	def unlock(self):
		if self._lock_obj is None:
			return

		self._lock_obj.unlock()
		self._lock_obj = None
		self.locked = False
		self.settings.pop('PORTAGE_BUILDDIR_LOCKED', None)
		catdir_lock = AsynchronousLock(path=self._catdir, scheduler=self.scheduler)
		catdir_lock.start()
		if catdir_lock.wait() == os.EX_OK:
			try:
				os.rmdir(self._catdir)
			except OSError:
				pass
			finally:
				catdir_lock.unlock()
Exemple #12
0
    def unlock(self):
        if self._lock_obj is None:
            return

        self._lock_obj.unlock()
        self._lock_obj = None
        self.locked = False
        self.settings.pop('PORTAGE_BUILDIR_LOCKED', None)
        catdir_lock = AsynchronousLock(path=self._catdir,
                                       scheduler=self.scheduler)
        catdir_lock.start()
        if catdir_lock.wait() == os.EX_OK:
            try:
                os.rmdir(self._catdir)
            except OSError as e:
                if e.errno not in (errno.ENOENT, errno.ENOTEMPTY, errno.EEXIST,
                                   errno.EPERM):
                    raise
            finally:
                catdir_lock.unlock()
	def unlock(self):
		if self._lock_obj is None:
			return

		self._lock_obj.unlock()
		self._lock_obj = None
		self.locked = False
		self.settings.pop('PORTAGE_BUILDIR_LOCKED', None)
		catdir_lock = AsynchronousLock(path=self._catdir, scheduler=self.scheduler)
		catdir_lock.start()
		if catdir_lock.wait() == os.EX_OK:
			try:
				os.rmdir(self._catdir)
			except OSError as e:
				if e.errno not in (errno.ENOENT,
					errno.ENOTEMPTY, errno.EEXIST, errno.EPERM):
					raise
			finally:
				catdir_lock.unlock()
Exemple #14
0
class _BinpkgFetcherProcess(SpawnProcess):

    __slots__ = ("pkg", "pretend", "locked", "pkg_path", "_lock_obj")

    def _start(self):
        pkg = self.pkg
        pretend = self.pretend
        bintree = pkg.root_config.trees["bintree"]
        settings = bintree.settings
        pkg_path = self.pkg_path

        exists = os.path.exists(pkg_path)
        resume = exists and os.path.basename(pkg_path) in bintree.invalids
        if not (pretend or resume):
            # Remove existing file or broken symlink.
            try:
                os.unlink(pkg_path)
            except OSError:
                pass

        # urljoin doesn't work correctly with
        # unrecognized protocols like sftp
        fetchcommand = None
        resumecommand = None
        if bintree._remote_has_index:
            remote_metadata = bintree._remotepkgs[bintree.dbapi._instance_key(
                pkg.cpv)]
            rel_uri = remote_metadata.get("PATH")
            if not rel_uri:
                rel_uri = pkg.cpv + ".tbz2"
            remote_base_uri = remote_metadata["BASE_URI"]
            uri = remote_base_uri.rstrip("/") + "/" + rel_uri.lstrip("/")
            fetchcommand = remote_metadata.get('FETCHCOMMAND')
            resumecommand = remote_metadata.get('RESUMECOMMAND')
        else:
            uri = settings["PORTAGE_BINHOST"].rstrip("/") + \
             "/" + pkg.pf + ".tbz2"

        if pretend:
            portage.writemsg_stdout("\n%s\n" % uri, noiselevel=-1)
            self.returncode = os.EX_OK
            self._async_wait()
            return

        fcmd = None
        if resume:
            fcmd = resumecommand
        else:
            fcmd = fetchcommand
        if fcmd is None:
            protocol = urllib_parse_urlparse(uri)[0]
            fcmd_prefix = "FETCHCOMMAND"
            if resume:
                fcmd_prefix = "RESUMECOMMAND"
            fcmd = settings.get(fcmd_prefix + "_" + protocol.upper())
            if not fcmd:
                fcmd = settings.get(fcmd_prefix)

        fcmd_vars = {
            "DISTDIR": os.path.dirname(pkg_path),
            "URI": uri,
            "FILE": os.path.basename(pkg_path)
        }

        for k in ("PORTAGE_SSH_OPTS", ):
            v = settings.get(k)
            if v is not None:
                fcmd_vars[k] = v

        fetch_env = dict(settings.items())
        fetch_args = [portage.util.varexpand(x, mydict=fcmd_vars) \
         for x in portage.util.shlex_split(fcmd)]

        if self.fd_pipes is None:
            self.fd_pipes = {}
        fd_pipes = self.fd_pipes

        # Redirect all output to stdout since some fetchers like
        # wget pollute stderr (if portage detects a problem then it
        # can send it's own message to stderr).
        fd_pipes.setdefault(0, portage._get_stdin().fileno())
        fd_pipes.setdefault(1, sys.__stdout__.fileno())
        fd_pipes.setdefault(2, sys.__stdout__.fileno())

        self.args = fetch_args
        self.env = fetch_env
        if settings.selinux_enabled():
            self._selinux_type = settings["PORTAGE_FETCH_T"]
        self.log_filter_file = settings.get('PORTAGE_LOG_FILTER_FILE_CMD')
        SpawnProcess._start(self)

    def _pipe(self, fd_pipes):
        """When appropriate, use a pty so that fetcher progress bars,
		like wget has, will work properly."""
        if self.background or not sys.__stdout__.isatty():
            # When the output only goes to a log file,
            # there's no point in creating a pty.
            return os.pipe()
        stdout_pipe = None
        if not self.background:
            stdout_pipe = fd_pipes.get(1)
        got_pty, master_fd, slave_fd = \
         _create_pty_or_pipe(copy_term_size=stdout_pipe)
        return (master_fd, slave_fd)

    def sync_timestamp(self):
        # If possible, update the mtime to match the remote package if
        # the fetcher didn't already do it automatically.
        bintree = self.pkg.root_config.trees["bintree"]
        if bintree._remote_has_index:
            remote_mtime = bintree._remotepkgs[bintree.dbapi._instance_key(
                self.pkg.cpv)].get("_mtime_")
            if remote_mtime is not None:
                try:
                    remote_mtime = int(remote_mtime)
                except ValueError:
                    pass
                else:
                    try:
                        local_mtime = os.stat(self.pkg_path)[stat.ST_MTIME]
                    except OSError:
                        pass
                    else:
                        if remote_mtime != local_mtime:
                            try:
                                os.utime(self.pkg_path,
                                         (remote_mtime, remote_mtime))
                            except OSError:
                                pass

    def async_lock(self):
        """
		This raises an AlreadyLocked exception if lock() is called
		while a lock is already held. In order to avoid this, call
		unlock() or check whether the "locked" attribute is True
		or False before calling lock().
		"""
        if self._lock_obj is not None:
            raise self.AlreadyLocked((self._lock_obj, ))

        result = self.scheduler.create_future()

        def acquired_lock(async_lock):
            if async_lock.wait() == os.EX_OK:
                self.locked = True
                result.set_result(None)
            else:
                result.set_exception(
                    AssertionError(
                        "AsynchronousLock failed with returncode %s" %
                        (async_lock.returncode, )))

        self._lock_obj = AsynchronousLock(path=self.pkg_path,
                                          scheduler=self.scheduler)
        self._lock_obj.addExitListener(acquired_lock)
        self._lock_obj.start()
        return result

    class AlreadyLocked(portage.exception.PortageException):
        pass

    def async_unlock(self):
        if self._lock_obj is None:
            raise AssertionError('already unlocked')
        result = self._lock_obj.async_unlock()
        self._lock_obj = None
        self.locked = False
        return result
Exemple #15
0
class _BinpkgFetcherProcess(SpawnProcess):

	__slots__ = ("pkg", "pretend", "locked", "pkg_path", "_lock_obj")

	def _start(self):
		pkg = self.pkg
		pretend = self.pretend
		bintree = pkg.root_config.trees["bintree"]
		settings = bintree.settings
		pkg_path = self.pkg_path

		exists = os.path.exists(pkg_path)
		resume = exists and os.path.basename(pkg_path) in bintree.invalids
		if not (pretend or resume):
			# Remove existing file or broken symlink.
			try:
				os.unlink(pkg_path)
			except OSError:
				pass

		# urljoin doesn't work correctly with
		# unrecognized protocols like sftp
		if bintree._remote_has_index:
			instance_key = bintree.dbapi._instance_key(pkg.cpv)
			rel_uri = bintree._remotepkgs[instance_key].get("PATH")
			if not rel_uri:
				rel_uri = pkg.cpv + ".tbz2"
			remote_base_uri = bintree._remotepkgs[
				instance_key]["BASE_URI"]
			uri = remote_base_uri.rstrip("/") + "/" + rel_uri.lstrip("/")
		else:
			uri = settings["PORTAGE_BINHOST"].rstrip("/") + \
				"/" + pkg.pf + ".tbz2"

		if pretend:
			portage.writemsg_stdout("\n%s\n" % uri, noiselevel=-1)
			self.returncode = os.EX_OK
			self._async_wait()
			return

		protocol = urllib_parse_urlparse(uri)[0]
		fcmd_prefix = "FETCHCOMMAND"
		if resume:
			fcmd_prefix = "RESUMECOMMAND"
		fcmd = settings.get(fcmd_prefix + "_" + protocol.upper())
		if not fcmd:
			fcmd = settings.get(fcmd_prefix)

		fcmd_vars = {
			"DISTDIR" : os.path.dirname(pkg_path),
			"URI"     : uri,
			"FILE"    : os.path.basename(pkg_path)
		}

		for k in ("PORTAGE_SSH_OPTS",):
			v = settings.get(k)
			if v is not None:
				fcmd_vars[k] = v

		fetch_env = dict(settings.items())
		fetch_args = [portage.util.varexpand(x, mydict=fcmd_vars) \
			for x in portage.util.shlex_split(fcmd)]

		if self.fd_pipes is None:
			self.fd_pipes = {}
		fd_pipes = self.fd_pipes

		# Redirect all output to stdout since some fetchers like
		# wget pollute stderr (if portage detects a problem then it
		# can send it's own message to stderr).
		fd_pipes.setdefault(0, portage._get_stdin().fileno())
		fd_pipes.setdefault(1, sys.__stdout__.fileno())
		fd_pipes.setdefault(2, sys.__stdout__.fileno())

		self.args = fetch_args
		self.env = fetch_env
		if settings.selinux_enabled():
			self._selinux_type = settings["PORTAGE_FETCH_T"]
		SpawnProcess._start(self)

	def _pipe(self, fd_pipes):
		"""When appropriate, use a pty so that fetcher progress bars,
		like wget has, will work properly."""
		if self.background or not sys.__stdout__.isatty():
			# When the output only goes to a log file,
			# there's no point in creating a pty.
			return os.pipe()
		stdout_pipe = None
		if not self.background:
			stdout_pipe = fd_pipes.get(1)
		got_pty, master_fd, slave_fd = \
			_create_pty_or_pipe(copy_term_size=stdout_pipe)
		return (master_fd, slave_fd)

	def sync_timestamp(self):
			# If possible, update the mtime to match the remote package if
			# the fetcher didn't already do it automatically.
			bintree = self.pkg.root_config.trees["bintree"]
			if bintree._remote_has_index:
				remote_mtime = bintree._remotepkgs[
					bintree.dbapi._instance_key(
					self.pkg.cpv)].get("_mtime_")
				if remote_mtime is not None:
					try:
						remote_mtime = long(remote_mtime)
					except ValueError:
						pass
					else:
						try:
							local_mtime = os.stat(self.pkg_path)[stat.ST_MTIME]
						except OSError:
							pass
						else:
							if remote_mtime != local_mtime:
								try:
									os.utime(self.pkg_path,
										(remote_mtime, remote_mtime))
								except OSError:
									pass

	def async_lock(self):
		"""
		This raises an AlreadyLocked exception if lock() is called
		while a lock is already held. In order to avoid this, call
		unlock() or check whether the "locked" attribute is True
		or False before calling lock().
		"""
		if self._lock_obj is not None:
			raise self.AlreadyLocked((self._lock_obj,))

		result = self.scheduler.create_future()

		def acquired_lock(async_lock):
			if async_lock.wait() == os.EX_OK:
				self.locked = True
				result.set_result(None)
			else:
				result.set_exception(AssertionError(
					"AsynchronousLock failed with returncode %s"
					% (async_lock.returncode,)))

		self._lock_obj = AsynchronousLock(path=self.pkg_path,
			scheduler=self.scheduler)
		self._lock_obj.addExitListener(acquired_lock)
		self._lock_obj.start()
		return result

	class AlreadyLocked(portage.exception.PortageException):
		pass

	def async_unlock(self):
		if self._lock_obj is None:
			raise AssertionError('already unlocked')
		result = self._lock_obj.async_unlock()
		self._lock_obj = None
		self.locked = False
		return result
Exemple #16
0
    def async_lock(self):
        """
		Acquire the lock asynchronously. Notification is available
		via the add_done_callback method of the returned Future instance.

		This raises an AlreadyLocked exception if async_lock() is called
		while a lock is already held. In order to avoid this, call
		async_unlock() or check whether the "locked" attribute is True
		or False before calling async_lock().

		@returns: Future, result is None
		"""
        if self._lock_obj is not None:
            raise self.AlreadyLocked((self._lock_obj, ))

        dir_path = self.settings.get('PORTAGE_BUILDDIR')
        if not dir_path:
            raise AssertionError('PORTAGE_BUILDDIR is unset')
        catdir = os.path.dirname(dir_path)
        self._catdir = catdir

        try:
            portage.util.ensure_dirs(os.path.dirname(catdir),
                                     gid=portage.portage_gid,
                                     mode=0o70,
                                     mask=0)
        except PortageException:
            if not os.path.isdir(os.path.dirname(catdir)):
                raise

        catdir_lock = AsynchronousLock(path=catdir, scheduler=self.scheduler)
        builddir_lock = AsynchronousLock(path=dir_path,
                                         scheduler=self.scheduler)
        try:
            yield catdir_lock.async_start()
            yield catdir_lock.async_wait()

            self._assert_lock(catdir_lock)

            try:
                portage.util.ensure_dirs(catdir,
                                         gid=portage.portage_gid,
                                         mode=0o70,
                                         mask=0)
            except PortageException:
                if not os.path.isdir(catdir):
                    raise

            yield builddir_lock.async_start()
            yield builddir_lock.async_wait()
        except asyncio.CancelledError:
            if catdir_lock.poll() is None:
                catdir_lock.cancel()
            if builddir_lock.poll() is None:
                builddir_lock.cancel()
            raise

        try:
            self._assert_lock(builddir_lock)
        except AssertionError:
            yield catdir_lock.async_unlock()
            raise

        self._lock_obj = builddir_lock
        self.locked = True
        self.settings['PORTAGE_BUILDDIR_LOCKED'] = '1'
        yield catdir_lock.async_unlock()
Exemple #17
0
class EbuildPhase(CompositeTask):

    __slots__ = ("actionmap", "fd_pipes", "phase", "settings") + \
     ("_ebuild_lock",)

    # FEATURES displayed prior to setup phase
    _features_display = ("ccache", "compressdebug", "distcc", "distcc-pump",
                         "fakeroot", "installsources", "keeptemp", "keepwork",
                         "nostrip", "preserve-libs", "sandbox", "selinux",
                         "sesandbox", "splitdebug", "suidctl", "test",
                         "userpriv", "usersandbox")

    # Locked phases
    _locked_phases = ("setup", "preinst", "postinst", "prerm", "postrm")

    def _start(self):

        need_builddir = self.phase not in EbuildProcess._phases_without_builddir

        if need_builddir:
            phase_completed_file = os.path.join(
                self.settings['PORTAGE_BUILDDIR'],
                ".%sed" % self.phase.rstrip('e'))
            if not os.path.exists(phase_completed_file):
                # If the phase is really going to run then we want
                # to eliminate any stale elog messages that may
                # exist from a previous run.
                try:
                    os.unlink(
                        os.path.join(self.settings['T'], 'logging',
                                     self.phase))
                except OSError:
                    pass

        if self.phase in ('nofetch', 'pretend', 'setup'):

            use = self.settings.get('PORTAGE_BUILT_USE')
            if use is None:
                use = self.settings['PORTAGE_USE']

            maint_str = ""
            upstr_str = ""
            metadata_xml_path = os.path.join(
                os.path.dirname(self.settings['EBUILD']), "metadata.xml")
            if MetaDataXML is not None and os.path.isfile(metadata_xml_path):
                herds_path = os.path.join(self.settings['PORTDIR'],
                                          'metadata/herds.xml')
                try:
                    metadata_xml = MetaDataXML(metadata_xml_path, herds_path)
                    maint_str = metadata_xml.format_maintainer_string()
                    upstr_str = metadata_xml.format_upstream_string()
                except SyntaxError:
                    maint_str = "<invalid metadata.xml>"

            msg = []
            msg.append("Package:    %s" % self.settings.mycpv)
            if self.settings.get('PORTAGE_REPO_NAME'):
                msg.append("Repository: %s" %
                           self.settings['PORTAGE_REPO_NAME'])
            if maint_str:
                msg.append("Maintainer: %s" % maint_str)
            if upstr_str:
                msg.append("Upstream:   %s" % upstr_str)

            msg.append("USE:        %s" % use)
            relevant_features = []
            enabled_features = self.settings.features
            for x in self._features_display:
                if x in enabled_features:
                    relevant_features.append(x)
            if relevant_features:
                msg.append("FEATURES:   %s" % " ".join(relevant_features))

            # Force background=True for this header since it's intended
            # for the log and it doesn't necessarily need to be visible
            # elsewhere.
            self._elog('einfo', msg, background=True)

        if self.phase == 'package':
            if 'PORTAGE_BINPKG_TMPFILE' not in self.settings:
                self.settings['PORTAGE_BINPKG_TMPFILE'] = \
                 os.path.join(self.settings['PKGDIR'],
                 self.settings['CATEGORY'], self.settings['PF']) + '.tbz2'

        if self.phase in ("pretend", "prerm"):
            env_extractor = BinpkgEnvExtractor(background=self.background,
                                               scheduler=self.scheduler,
                                               settings=self.settings)
            if env_extractor.saved_env_exists():
                self._start_task(env_extractor, self._env_extractor_exit)
                return
            # If the environment.bz2 doesn't exist, then ebuild.sh will
            # source the ebuild as a fallback.

        self._start_lock()

    def _env_extractor_exit(self, env_extractor):
        if self._default_exit(env_extractor) != os.EX_OK:
            self.wait()
            return

        self._start_lock()

    def _start_lock(self):
        if (self.phase in self._locked_phases
                and "ebuild-locks" in self.settings.features):
            eroot = self.settings["EROOT"]
            lock_path = os.path.join(eroot, portage.VDB_PATH + "-ebuild")
            if os.access(os.path.dirname(lock_path), os.W_OK):
                self._ebuild_lock = AsynchronousLock(path=lock_path,
                                                     scheduler=self.scheduler)
                self._start_task(self._ebuild_lock, self._lock_exit)
                return

        self._start_ebuild()

    def _lock_exit(self, ebuild_lock):
        if self._default_exit(ebuild_lock) != os.EX_OK:
            self.wait()
            return
        self._start_ebuild()

    def _get_log_path(self):
        # Don't open the log file during the clean phase since the
        # open file can result in an nfs lock on $T/build.log which
        # prevents the clean phase from removing $T.
        logfile = None
        if self.phase not in ("clean", "cleanrm") and \
         self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
            logfile = self.settings.get("PORTAGE_LOG_FILE")
        return logfile

    def _start_ebuild(self):

        fd_pipes = self.fd_pipes
        if fd_pipes is None:
            if not self.background and self.phase == 'nofetch':
                # All the pkg_nofetch output goes to stderr since
                # it's considered to be an error message.
                fd_pipes = {1: sys.__stderr__.fileno()}

        ebuild_process = EbuildProcess(actionmap=self.actionmap,
                                       background=self.background,
                                       fd_pipes=fd_pipes,
                                       logfile=self._get_log_path(),
                                       phase=self.phase,
                                       scheduler=self.scheduler,
                                       settings=self.settings)

        self._start_task(ebuild_process, self._ebuild_exit)

    def _ebuild_exit(self, ebuild_process):

        if self._ebuild_lock is not None:
            self._ebuild_lock.unlock()
            self._ebuild_lock = None

        fail = False
        if self._default_exit(ebuild_process) != os.EX_OK:
            if self.phase == "test" and \
             "test-fail-continue" in self.settings.features:
                # mark test phase as complete (bug #452030)
                try:
                    open(
                        _unicode_encode(os.path.join(
                            self.settings["PORTAGE_BUILDDIR"], ".tested"),
                                        encoding=_encodings['fs'],
                                        errors='strict'), 'wb').close()
                except OSError:
                    pass
            else:
                fail = True

        if not fail:
            self.returncode = None

        logfile = self._get_log_path()

        if self.phase == "install":
            out = io.StringIO()
            _check_build_log(self.settings, out=out)
            msg = out.getvalue()
            self.scheduler.output(msg, log_path=logfile)

        if fail:
            self._die_hooks()
            return

        settings = self.settings
        _post_phase_userpriv_perms(settings)

        if self.phase == "unpack":
            # Bump WORKDIR timestamp, in case tar gave it a timestamp
            # that will interfere with distfiles / WORKDIR timestamp
            # comparisons as reported in bug #332217. Also, fix
            # ownership since tar can change that too.
            os.utime(settings["WORKDIR"], None)
            _prepare_workdir(settings)
        elif self.phase == "install":
            out = io.StringIO()
            _post_src_install_write_metadata(settings)
            _post_src_install_uid_fix(settings, out)
            msg = out.getvalue()
            if msg:
                self.scheduler.output(msg, log_path=logfile)
        elif self.phase == "preinst":
            _preinst_bsdflags(settings)
        elif self.phase == "postinst":
            _postinst_bsdflags(settings)

        post_phase_cmds = _post_phase_cmds.get(self.phase)
        if post_phase_cmds is not None:
            if logfile is not None and self.phase in ("install", ):
                # Log to a temporary file, since the code we are running
                # reads PORTAGE_LOG_FILE for QA checks, and we want to
                # avoid annoying "gzip: unexpected end of file" messages
                # when FEATURES=compress-build-logs is enabled.
                fd, logfile = tempfile.mkstemp()
                os.close(fd)
            post_phase = MiscFunctionsProcess(background=self.background,
                                              commands=post_phase_cmds,
                                              fd_pipes=self.fd_pipes,
                                              logfile=logfile,
                                              phase=self.phase,
                                              scheduler=self.scheduler,
                                              settings=settings)
            self._start_task(post_phase, self._post_phase_exit)
            return

        # this point is not reachable if there was a failure and
        # we returned for die_hooks above, so returncode must
        # indicate success (especially if ebuild_process.returncode
        # is unsuccessful and test-fail-continue came into play)
        self.returncode = os.EX_OK
        self._current_task = None
        self.wait()

    def _post_phase_exit(self, post_phase):

        self._assert_current(post_phase)

        log_path = None
        if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
            log_path = self.settings.get("PORTAGE_LOG_FILE")

        if post_phase.logfile is not None and \
         post_phase.logfile != log_path:
            # We were logging to a temp file (see above), so append
            # temp file to main log and remove temp file.
            self._append_temp_log(post_phase.logfile, log_path)

        if self._final_exit(post_phase) != os.EX_OK:
            writemsg("!!! post %s failed; exiting.\n" % self.phase,
                     noiselevel=-1)
            self._die_hooks()
            return

        if self.phase == "install":
            out = io.StringIO()
            _post_src_install_soname_symlinks(self.settings, out)
            msg = out.getvalue()
            if msg:
                self.scheduler.output(msg, log_path=log_path)

        self._current_task = None
        self.wait()
        return

    def _append_temp_log(self, temp_log, log_path):

        temp_file = open(
            _unicode_encode(temp_log,
                            encoding=_encodings['fs'],
                            errors='strict'), 'rb')

        log_file, log_file_real = self._open_log(log_path)

        for line in temp_file:
            log_file.write(line)

        temp_file.close()
        log_file.close()
        if log_file_real is not log_file:
            log_file_real.close()
        os.unlink(temp_log)

    def _open_log(self, log_path):

        f = open(_unicode_encode(log_path,
                                 encoding=_encodings['fs'],
                                 errors='strict'),
                 mode='ab')
        f_real = f

        if log_path.endswith('.gz'):
            f = gzip.GzipFile(filename='', mode='ab', fileobj=f)

        return (f, f_real)

    def _die_hooks(self):
        self.returncode = None
        phase = 'die_hooks'
        die_hooks = MiscFunctionsProcess(background=self.background,
                                         commands=[phase],
                                         phase=phase,
                                         logfile=self._get_log_path(),
                                         fd_pipes=self.fd_pipes,
                                         scheduler=self.scheduler,
                                         settings=self.settings)
        self._start_task(die_hooks, self._die_hooks_exit)

    def _die_hooks_exit(self, die_hooks):
        if self.phase != 'clean' and \
         'noclean' not in self.settings.features and \
         'fail-clean' in self.settings.features:
            self._default_exit(die_hooks)
            self._fail_clean()
            return
        self._final_exit(die_hooks)
        self.returncode = 1
        self.wait()

    def _fail_clean(self):
        self.returncode = None
        portage.elog.elog_process(self.settings.mycpv, self.settings)
        phase = "clean"
        clean_phase = EbuildPhase(background=self.background,
                                  fd_pipes=self.fd_pipes,
                                  phase=phase,
                                  scheduler=self.scheduler,
                                  settings=self.settings)
        self._start_task(clean_phase, self._fail_clean_exit)
        return

    def _fail_clean_exit(self, clean_phase):
        self._final_exit(clean_phase)
        self.returncode = 1
        self.wait()

    def _elog(self, elog_funcname, lines, background=None):
        if background is None:
            background = self.background
        out = io.StringIO()
        phase = self.phase
        elog_func = getattr(elog_messages, elog_funcname)
        global_havecolor = portage.output.havecolor
        try:
            portage.output.havecolor = \
             self.settings.get('NOCOLOR', 'false').lower() in ('no', 'false')
            for line in lines:
                elog_func(line, phase=phase, key=self.settings.mycpv, out=out)
        finally:
            portage.output.havecolor = global_havecolor
        msg = out.getvalue()
        if msg:
            log_path = None
            if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
                log_path = self.settings.get("PORTAGE_LOG_FILE")
            self.scheduler.output(msg,
                                  log_path=log_path,
                                  background=background)
Exemple #18
0
    def async_lock(self):
        """
		Acquire the lock asynchronously. Notification is available
		via the add_done_callback method of the returned Future instance.

		This raises an AlreadyLocked exception if async_lock() is called
		while a lock is already held. In order to avoid this, call
		async_unlock() or check whether the "locked" attribute is True
		or False before calling async_lock().

		@returns: Future, result is None
		"""
        if self._lock_obj is not None:
            raise self.AlreadyLocked((self._lock_obj, ))

        dir_path = self.settings.get('PORTAGE_BUILDDIR')
        if not dir_path:
            raise AssertionError('PORTAGE_BUILDDIR is unset')
        catdir = os.path.dirname(dir_path)
        self._catdir = catdir
        catdir_lock = AsynchronousLock(path=catdir, scheduler=self.scheduler)
        builddir_lock = AsynchronousLock(path=dir_path,
                                         scheduler=self.scheduler)
        result = self.scheduler.create_future()

        def catdir_locked(catdir_lock):
            try:
                self._assert_lock(catdir_lock)
            except AssertionError as e:
                result.set_exception(e)
                return

            try:
                portage.util.ensure_dirs(catdir,
                                         gid=portage.portage_gid,
                                         mode=0o70,
                                         mask=0)
            except PortageException as e:
                if not os.path.isdir(catdir):
                    result.set_exception(e)
                    return

            builddir_lock.addExitListener(builddir_locked)
            builddir_lock.start()

        def builddir_locked(builddir_lock):
            try:
                self._assert_lock(builddir_lock)
            except AssertionError as e:
                catdir_lock.async_unlock.add_done_callback(
                    functools.partial(catdir_unlocked, exception=e))
                return

            self._lock_obj = builddir_lock
            self.locked = True
            self.settings['PORTAGE_BUILDDIR_LOCKED'] = '1'
            catdir_lock.async_unlock().add_done_callback(catdir_unlocked)

        def catdir_unlocked(future, exception=None):
            if not (exception is None and future.exception() is None):
                result.set_exception(exception or future.exception())
            else:
                result.set_result(None)

        try:
            portage.util.ensure_dirs(os.path.dirname(catdir),
                                     gid=portage.portage_gid,
                                     mode=0o70,
                                     mask=0)
        except PortageException:
            if not os.path.isdir(os.path.dirname(catdir)):
                raise

        catdir_lock.addExitListener(catdir_locked)
        catdir_lock.start()
        return result
Exemple #19
0
class EbuildPhase(CompositeTask):

	__slots__ = ("actionmap", "fd_pipes", "phase", "settings") + \
		("_ebuild_lock",)

	# FEATURES displayed prior to setup phase
	_features_display = (
		"ccache", "compressdebug", "distcc", "distcc-pump", "fakeroot",
		"installsources", "keeptemp", "keepwork", "network-sandbox",
		"network-sandbox-proxy", "nostrip", "preserve-libs", "sandbox",
		"selinux", "sesandbox", "splitdebug", "suidctl", "test",
		"userpriv", "usersandbox"
	)

	# Locked phases
	_locked_phases = ("setup", "preinst", "postinst", "prerm", "postrm")

	def _start(self):

		need_builddir = self.phase not in EbuildProcess._phases_without_builddir

		if need_builddir:
			phase_completed_file = os.path.join(
				self.settings['PORTAGE_BUILDDIR'],
				".%sed" % self.phase.rstrip('e'))
			if not os.path.exists(phase_completed_file):
				# If the phase is really going to run then we want
				# to eliminate any stale elog messages that may
				# exist from a previous run.
				try:
					os.unlink(os.path.join(self.settings['T'],
						'logging', self.phase))
				except OSError:
					pass

		if self.phase in ('nofetch', 'pretend', 'setup'):

			use = self.settings.get('PORTAGE_BUILT_USE')
			if use is None:
				use = self.settings['PORTAGE_USE']

			maint_str = ""
			upstr_str = ""
			metadata_xml_path = os.path.join(os.path.dirname(self.settings['EBUILD']), "metadata.xml")
			if MetaDataXML is not None and os.path.isfile(metadata_xml_path):
				herds_path = os.path.join(self.settings['PORTDIR'],
					'metadata/herds.xml')
				try:
					metadata_xml = MetaDataXML(metadata_xml_path, herds_path)
					maint_str = metadata_xml.format_maintainer_string()
					upstr_str = metadata_xml.format_upstream_string()
				except SyntaxError:
					maint_str = "<invalid metadata.xml>"

			msg = []
			msg.append("Package:    %s" % self.settings.mycpv)
			if self.settings.get('PORTAGE_REPO_NAME'):
				msg.append("Repository: %s" % self.settings['PORTAGE_REPO_NAME'])
			if maint_str:
				msg.append("Maintainer: %s" % maint_str)
			if upstr_str:
				msg.append("Upstream:   %s" % upstr_str)

			msg.append("USE:        %s" % use)
			relevant_features = []
			enabled_features = self.settings.features
			for x in self._features_display:
				if x in enabled_features:
					relevant_features.append(x)
			if relevant_features:
				msg.append("FEATURES:   %s" % " ".join(relevant_features))

			# Force background=True for this header since it's intended
			# for the log and it doesn't necessarily need to be visible
			# elsewhere.
			self._elog('einfo', msg, background=True)

		if self.phase == 'package':
			if 'PORTAGE_BINPKG_TMPFILE' not in self.settings:
				self.settings['PORTAGE_BINPKG_TMPFILE'] = \
					os.path.join(self.settings['PKGDIR'],
					self.settings['CATEGORY'], self.settings['PF']) + '.tbz2'

		if self.phase in ("pretend", "prerm"):
			env_extractor = BinpkgEnvExtractor(background=self.background,
				scheduler=self.scheduler, settings=self.settings)
			if env_extractor.saved_env_exists():
				self._start_task(env_extractor, self._env_extractor_exit)
				return
			# If the environment.bz2 doesn't exist, then ebuild.sh will
			# source the ebuild as a fallback.

		self._start_lock()

	def _env_extractor_exit(self, env_extractor):
		if self._default_exit(env_extractor) != os.EX_OK:
			self.wait()
			return

		self._start_lock()

	def _start_lock(self):
		if (self.phase in self._locked_phases and
			"ebuild-locks" in self.settings.features):
			eroot = self.settings["EROOT"]
			lock_path = os.path.join(eroot, portage.VDB_PATH + "-ebuild")
			if os.access(os.path.dirname(lock_path), os.W_OK):
				self._ebuild_lock = AsynchronousLock(path=lock_path,
					scheduler=self.scheduler)
				self._start_task(self._ebuild_lock, self._lock_exit)
				return

		self._start_ebuild()

	def _lock_exit(self, ebuild_lock):
		if self._default_exit(ebuild_lock) != os.EX_OK:
			self.wait()
			return
		self._start_ebuild()

	def _get_log_path(self):
		# Don't open the log file during the clean phase since the
		# open file can result in an nfs lock on $T/build.log which
		# prevents the clean phase from removing $T.
		logfile = None
		if self.phase not in ("clean", "cleanrm") and \
			self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
			logfile = self.settings.get("PORTAGE_LOG_FILE")
		return logfile

	def _start_ebuild(self):
		if self.phase == "package":
			self._start_task(PackagePhase(actionmap=self.actionmap,
				background=self.background, fd_pipes=self.fd_pipes,
				logfile=self._get_log_path(), scheduler=self.scheduler,
				settings=self.settings), self._ebuild_exit)
			return

		if self.phase == "unpack":
			alist = self.settings.configdict["pkg"].get("A", "").split()
			_prepare_fake_distdir(self.settings, alist)
			_prepare_fake_filesdir(self.settings)

		fd_pipes = self.fd_pipes
		if fd_pipes is None:
			if not self.background and self.phase == 'nofetch':
				# All the pkg_nofetch output goes to stderr since
				# it's considered to be an error message.
				fd_pipes = {1 : sys.__stderr__.fileno()}

		ebuild_process = EbuildProcess(actionmap=self.actionmap,
			background=self.background, fd_pipes=fd_pipes,
			logfile=self._get_log_path(), phase=self.phase,
			scheduler=self.scheduler, settings=self.settings)

		self._start_task(ebuild_process, self._ebuild_exit)

	def _ebuild_exit(self, ebuild_process):

		if self._ebuild_lock is not None:
			self._ebuild_lock.unlock()
			self._ebuild_lock = None

		fail = False
		if self._default_exit(ebuild_process) != os.EX_OK:
			if self.phase == "test" and \
				"test-fail-continue" in self.settings.features:
				# mark test phase as complete (bug #452030)
				try:
					open(_unicode_encode(os.path.join(
						self.settings["PORTAGE_BUILDDIR"], ".tested"),
						encoding=_encodings['fs'], errors='strict'),
						'wb').close()
				except OSError:
					pass
			else:
				fail = True

		if not fail:
			self.returncode = None

		logfile = self._get_log_path()

		if self.phase == "install":
			out = io.StringIO()
			_check_build_log(self.settings, out=out)
			msg = out.getvalue()
			self.scheduler.output(msg, log_path=logfile)

		if fail:
			self._die_hooks()
			return

		settings = self.settings
		_post_phase_userpriv_perms(settings)

		if self.phase == "unpack":
			# Bump WORKDIR timestamp, in case tar gave it a timestamp
			# that will interfere with distfiles / WORKDIR timestamp
			# comparisons as reported in bug #332217. Also, fix
			# ownership since tar can change that too.
			os.utime(settings["WORKDIR"], None)
			_prepare_workdir(settings)
		elif self.phase == "install":
			out = io.StringIO()
			_post_src_install_write_metadata(settings)
			_post_src_install_uid_fix(settings, out)
			msg = out.getvalue()
			if msg:
				self.scheduler.output(msg, log_path=logfile)
		elif self.phase == "preinst":
			_preinst_bsdflags(settings)
		elif self.phase == "postinst":
			_postinst_bsdflags(settings)

		post_phase_cmds = _post_phase_cmds.get(self.phase)
		if post_phase_cmds is not None:
			if logfile is not None and self.phase in ("install",):
				# Log to a temporary file, since the code we are running
				# reads PORTAGE_LOG_FILE for QA checks, and we want to
				# avoid annoying "gzip: unexpected end of file" messages
				# when FEATURES=compress-build-logs is enabled.
				fd, logfile = tempfile.mkstemp()
				os.close(fd)
			post_phase = MiscFunctionsProcess(background=self.background,
				commands=post_phase_cmds, fd_pipes=self.fd_pipes,
				logfile=logfile, phase=self.phase, scheduler=self.scheduler,
				settings=settings)
			self._start_task(post_phase, self._post_phase_exit)
			return

		# this point is not reachable if there was a failure and
		# we returned for die_hooks above, so returncode must
		# indicate success (especially if ebuild_process.returncode
		# is unsuccessful and test-fail-continue came into play)
		self.returncode = os.EX_OK
		self._current_task = None
		self.wait()

	def _post_phase_exit(self, post_phase):

		self._assert_current(post_phase)

		log_path = None
		if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
			log_path = self.settings.get("PORTAGE_LOG_FILE")

		if post_phase.logfile is not None and \
			post_phase.logfile != log_path:
			# We were logging to a temp file (see above), so append
			# temp file to main log and remove temp file.
			self._append_temp_log(post_phase.logfile, log_path)

		if self._final_exit(post_phase) != os.EX_OK:
			writemsg("!!! post %s failed; exiting.\n" % self.phase,
				noiselevel=-1)
			self._die_hooks()
			return

		if self.phase == "install":
			out = io.StringIO()
			_post_src_install_soname_symlinks(self.settings, out)
			msg = out.getvalue()
			if msg:
				self.scheduler.output(msg, log_path=log_path)

		self._current_task = None
		self.wait()
		return

	def _append_temp_log(self, temp_log, log_path):

		temp_file = open(_unicode_encode(temp_log,
			encoding=_encodings['fs'], errors='strict'), 'rb')

		log_file, log_file_real = self._open_log(log_path)

		for line in temp_file:
			log_file.write(line)

		temp_file.close()
		log_file.close()
		if log_file_real is not log_file:
			log_file_real.close()
		os.unlink(temp_log)

	def _open_log(self, log_path):

		f = open(_unicode_encode(log_path,
			encoding=_encodings['fs'], errors='strict'),
			mode='ab')
		f_real = f

		if log_path.endswith('.gz'):
			f =  gzip.GzipFile(filename='', mode='ab', fileobj=f)

		return (f, f_real)

	def _die_hooks(self):
		self.returncode = None
		phase = 'die_hooks'
		die_hooks = MiscFunctionsProcess(background=self.background,
			commands=[phase], phase=phase, logfile=self._get_log_path(),
			fd_pipes=self.fd_pipes, scheduler=self.scheduler,
			settings=self.settings)
		self._start_task(die_hooks, self._die_hooks_exit)

	def _die_hooks_exit(self, die_hooks):
		if self.phase != 'clean' and \
			'noclean' not in self.settings.features and \
			'fail-clean' in self.settings.features:
			self._default_exit(die_hooks)
			self._fail_clean()
			return
		self._final_exit(die_hooks)
		self.returncode = 1
		self.wait()

	def _fail_clean(self):
		self.returncode = None
		portage.elog.elog_process(self.settings.mycpv, self.settings)
		phase = "clean"
		clean_phase = EbuildPhase(background=self.background,
			fd_pipes=self.fd_pipes, phase=phase, scheduler=self.scheduler,
			settings=self.settings)
		self._start_task(clean_phase, self._fail_clean_exit)
		return

	def _fail_clean_exit(self, clean_phase):
		self._final_exit(clean_phase)
		self.returncode = 1
		self.wait()

	def _elog(self, elog_funcname, lines, background=None):
		if background is None:
			background = self.background
		out = io.StringIO()
		phase = self.phase
		elog_func = getattr(elog_messages, elog_funcname)
		global_havecolor = portage.output.havecolor
		try:
			portage.output.havecolor = \
				self.settings.get('NOCOLOR', 'false').lower() in ('no', 'false')
			for line in lines:
				elog_func(line, phase=phase, key=self.settings.mycpv, out=out)
		finally:
			portage.output.havecolor = global_havecolor
		msg = out.getvalue()
		if msg:
			log_path = None
			if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
				log_path = self.settings.get("PORTAGE_LOG_FILE")
			self.scheduler.output(msg, log_path=log_path,
				background=background)
Exemple #20
0
    def _testAsynchronousLock(self):
        scheduler = global_event_loop()
        tempdir = tempfile.mkdtemp()
        try:
            path = os.path.join(tempdir, 'lock_me')
            for force_async, async_unlock in itertools.product((True, False),
                                                               repeat=2):
                for force_dummy in (True, False):
                    async_lock = AsynchronousLock(path=path,
                                                  scheduler=scheduler,
                                                  _force_async=force_async,
                                                  _force_thread=True,
                                                  _force_dummy=force_dummy)
                    async_lock.start()
                    self.assertEqual(async_lock.wait(), os.EX_OK)
                    self.assertEqual(async_lock.returncode, os.EX_OK)
                    if async_unlock:
                        scheduler.run_until_complete(async_lock.async_unlock())
                    else:
                        async_lock.unlock()

                async_lock = AsynchronousLock(path=path,
                                              scheduler=scheduler,
                                              _force_async=force_async,
                                              _force_process=True)
                async_lock.start()
                self.assertEqual(async_lock.wait(), os.EX_OK)
                self.assertEqual(async_lock.returncode, os.EX_OK)
                if async_unlock:
                    scheduler.run_until_complete(async_lock.async_unlock())
                else:
                    async_lock.unlock()
        finally:
            shutil.rmtree(tempdir)
Exemple #21
0
    def lock(self):
        """
		This raises an AlreadyLocked exception if lock() is called
		while a lock is already held. In order to avoid this, call
		unlock() or check whether the "locked" attribute is True
		or False before calling lock().
		"""
        if self._lock_obj is not None:
            raise self.AlreadyLocked((self._lock_obj, ))

        dir_path = self.settings.get('PORTAGE_BUILDDIR')
        if not dir_path:
            raise AssertionError('PORTAGE_BUILDDIR is unset')
        catdir = os.path.dirname(dir_path)
        self._catdir = catdir

        try:
            portage.util.ensure_dirs(os.path.dirname(catdir),
                                     gid=portage.portage_gid,
                                     mode=0o70,
                                     mask=0)
        except PortageException:
            if not os.path.isdir(os.path.dirname(catdir)):
                raise
        catdir_lock = AsynchronousLock(path=catdir, scheduler=self.scheduler)
        catdir_lock.start()
        catdir_lock.wait()
        self._assert_lock(catdir_lock)

        try:
            try:
                portage.util.ensure_dirs(catdir,
                                         gid=portage.portage_gid,
                                         mode=0o70,
                                         mask=0)
            except PortageException:
                if not os.path.isdir(catdir):
                    raise
            builddir_lock = AsynchronousLock(path=dir_path,
                                             scheduler=self.scheduler)
            builddir_lock.start()
            builddir_lock.wait()
            self._assert_lock(builddir_lock)
            self._lock_obj = builddir_lock
            self.settings['PORTAGE_BUILDIR_LOCKED'] = '1'
        finally:
            self.locked = self._lock_obj is not None
            catdir_lock.unlock()
	def testAsynchronousLock(self):
		scheduler = PollScheduler().sched_iface
		tempdir = tempfile.mkdtemp()
		try:
			path = os.path.join(tempdir, 'lock_me')
			for force_async in (True, False):
				for force_dummy in (True, False):
					async_lock = AsynchronousLock(path=path,
						scheduler=scheduler, _force_async=force_async,
						_force_thread=True,
						_force_dummy=force_dummy)
					async_lock.start()
					self.assertEqual(async_lock.wait(), os.EX_OK)
					self.assertEqual(async_lock.returncode, os.EX_OK)
					async_lock.unlock()

				async_lock = AsynchronousLock(path=path,
					scheduler=scheduler, _force_async=force_async,
					_force_process=True)
				async_lock.start()
				self.assertEqual(async_lock.wait(), os.EX_OK)
				self.assertEqual(async_lock.returncode, os.EX_OK)
				async_lock.unlock()

		finally:
			shutil.rmtree(tempdir)
Exemple #23
0
    def _testAsynchronousLock(self):
        scheduler = PollScheduler().sched_iface
        tempdir = tempfile.mkdtemp()
        try:
            path = os.path.join(tempdir, 'lock_me')
            for force_async in (True, False):
                for force_dummy in (True, False):
                    async_lock = AsynchronousLock(path=path,
                                                  scheduler=scheduler,
                                                  _force_async=force_async,
                                                  _force_thread=True,
                                                  _force_dummy=force_dummy)
                    async_lock.start()
                    self.assertEqual(async_lock.wait(), os.EX_OK)
                    self.assertEqual(async_lock.returncode, os.EX_OK)
                    async_lock.unlock()

                async_lock = AsynchronousLock(path=path,
                                              scheduler=scheduler,
                                              _force_async=force_async,
                                              _force_process=True)
                async_lock.start()
                self.assertEqual(async_lock.wait(), os.EX_OK)
                self.assertEqual(async_lock.returncode, os.EX_OK)
                async_lock.unlock()

        finally:
            shutil.rmtree(tempdir)
	def _testAsynchronousLock(self):
		scheduler = global_event_loop()
		tempdir = tempfile.mkdtemp()
		try:
			path = os.path.join(tempdir, 'lock_me')
			for force_async, async_unlock in itertools.product(
				(True, False), repeat=2):
				for force_dummy in (True, False):
					async_lock = AsynchronousLock(path=path,
						scheduler=scheduler, _force_async=force_async,
						_force_thread=True,
						_force_dummy=force_dummy)
					async_lock.start()
					self.assertEqual(async_lock.wait(), os.EX_OK)
					self.assertEqual(async_lock.returncode, os.EX_OK)
					if async_unlock:
						scheduler.run_until_complete(async_lock.async_unlock())
					else:
						async_lock.unlock()

				async_lock = AsynchronousLock(path=path,
					scheduler=scheduler, _force_async=force_async,
					_force_process=True)
				async_lock.start()
				self.assertEqual(async_lock.wait(), os.EX_OK)
				self.assertEqual(async_lock.returncode, os.EX_OK)
				if async_unlock:
					scheduler.run_until_complete(async_lock.async_unlock())
				else:
					async_lock.unlock()
		finally:
			shutil.rmtree(tempdir)
Exemple #25
0
    def _testAsynchronousLockWait(self):
        scheduler = global_event_loop()
        tempdir = tempfile.mkdtemp()
        try:
            path = os.path.join(tempdir, 'lock_me')
            lock1 = AsynchronousLock(path=path, scheduler=scheduler)
            lock1.start()
            self.assertEqual(lock1.wait(), os.EX_OK)
            self.assertEqual(lock1.returncode, os.EX_OK)

            # lock2 requires _force_async=True since the portage.locks
            # module is not designed to work as intended here if the
            # same process tries to lock the same file more than
            # one time concurrently.
            lock2 = AsynchronousLock(path=path,
                                     scheduler=scheduler,
                                     _force_async=True,
                                     _force_process=True)
            lock2.start()
            # lock2 should be waiting for lock1 to release
            self.assertEqual(lock2.poll(), None)
            self.assertEqual(lock2.returncode, None)

            lock1.unlock()
            self.assertEqual(lock2.wait(), os.EX_OK)
            self.assertEqual(lock2.returncode, os.EX_OK)
            lock2.unlock()
        finally:
            shutil.rmtree(tempdir)
	def _testAsynchronousLockWaitCancel(self):
		scheduler = global_event_loop()
		tempdir = tempfile.mkdtemp()
		try:
			path = os.path.join(tempdir, 'lock_me')
			lock1 = AsynchronousLock(path=path, scheduler=scheduler)
			lock1.start()
			self.assertEqual(lock1.wait(), os.EX_OK)
			self.assertEqual(lock1.returncode, os.EX_OK)
			lock2 = AsynchronousLock(path=path, scheduler=scheduler,
				_force_async=True, _force_process=True)
			lock2.start()
			# lock2 should be waiting for lock1 to release
			self.assertEqual(lock2.poll(), None)
			self.assertEqual(lock2.returncode, None)

			# Cancel lock2 and then check wait() and returncode results.
			lock2.cancel()
			self.assertEqual(lock2.wait() == os.EX_OK, False)
			self.assertEqual(lock2.returncode == os.EX_OK, False)
			self.assertEqual(lock2.returncode is None, False)
			lock1.unlock()
		finally:
			shutil.rmtree(tempdir)
	def _testAsynchronousLockWaitKill(self):
		scheduler = global_event_loop()
		tempdir = tempfile.mkdtemp()
		try:
			path = os.path.join(tempdir, 'lock_me')
			lock1 = AsynchronousLock(path=path, scheduler=scheduler)
			lock1.start()
			self.assertEqual(lock1.wait(), os.EX_OK)
			self.assertEqual(lock1.returncode, os.EX_OK)
			lock2 = AsynchronousLock(path=path, scheduler=scheduler,
				_force_async=True, _force_process=True)
			lock2.start()
			# lock2 should be waiting for lock1 to release
			self.assertEqual(lock2.poll(), None)
			self.assertEqual(lock2.returncode, None)

			# Kill lock2's process and then check wait() and
			# returncode results. This is intended to simulate
			# a SIGINT sent via the controlling tty.
			self.assertEqual(lock2._imp is not None, True)
			self.assertEqual(lock2._imp._proc is not None, True)
			self.assertEqual(lock2._imp._proc.pid is not None, True)
			lock2._imp._kill_test = True
			os.kill(lock2._imp._proc.pid, signal.SIGTERM)
			self.assertEqual(lock2.wait() == os.EX_OK, False)
			self.assertEqual(lock2.returncode == os.EX_OK, False)
			self.assertEqual(lock2.returncode is None, False)
			lock1.unlock()
		finally:
			shutil.rmtree(tempdir)
Exemple #28
0
    def _testAsynchronousLockWaitCancel(self):
        scheduler = global_event_loop()
        tempdir = tempfile.mkdtemp()
        try:
            path = os.path.join(tempdir, 'lock_me')
            lock1 = AsynchronousLock(path=path, scheduler=scheduler)
            lock1.start()
            self.assertEqual(lock1.wait(), os.EX_OK)
            self.assertEqual(lock1.returncode, os.EX_OK)
            lock2 = AsynchronousLock(path=path,
                                     scheduler=scheduler,
                                     _force_async=True,
                                     _force_process=True)
            lock2.start()
            # lock2 should be waiting for lock1 to release
            self.assertEqual(lock2.poll(), None)
            self.assertEqual(lock2.returncode, None)

            # Cancel lock2 and then check wait() and returncode results.
            lock2.cancel()
            self.assertEqual(lock2.wait() == os.EX_OK, False)
            self.assertEqual(lock2.returncode == os.EX_OK, False)
            self.assertEqual(lock2.returncode is None, False)
            lock1.unlock()
        finally:
            shutil.rmtree(tempdir)
	def _testAsynchronousLockWait(self):
		scheduler = global_event_loop()
		tempdir = tempfile.mkdtemp()
		try:
			path = os.path.join(tempdir, 'lock_me')
			lock1 = AsynchronousLock(path=path, scheduler=scheduler)
			lock1.start()
			self.assertEqual(lock1.wait(), os.EX_OK)
			self.assertEqual(lock1.returncode, os.EX_OK)

			# lock2 requires _force_async=True since the portage.locks
			# module is not designed to work as intended here if the
			# same process tries to lock the same file more than
			# one time concurrently.
			lock2 = AsynchronousLock(path=path, scheduler=scheduler,
				_force_async=True, _force_process=True)
			lock2.start()
			# lock2 should be waiting for lock1 to release
			self.assertEqual(lock2.poll(), None)
			self.assertEqual(lock2.returncode, None)

			lock1.unlock()
			self.assertEqual(lock2.wait(), os.EX_OK)
			self.assertEqual(lock2.returncode, os.EX_OK)
			lock2.unlock()
		finally:
			shutil.rmtree(tempdir)
	def lock(self):
		"""
		This raises an AlreadyLocked exception if lock() is called
		while a lock is already held. In order to avoid this, call
		unlock() or check whether the "locked" attribute is True
		or False before calling lock().
		"""
		if self._lock_obj is not None:
			raise self.AlreadyLocked((self._lock_obj,))

		dir_path = self.settings.get('PORTAGE_BUILDDIR')
		if not dir_path:
			raise AssertionError('PORTAGE_BUILDDIR is unset')
		catdir = os.path.dirname(dir_path)
		self._catdir = catdir

		try:
			portage.util.ensure_dirs(os.path.dirname(catdir),
				gid=portage.portage_gid,
				mode=0o70, mask=0)
		except PortageException:
			if not os.path.isdir(os.path.dirname(catdir)):
				raise
		catdir_lock = AsynchronousLock(path=catdir, scheduler=self.scheduler)
		catdir_lock.start()
		catdir_lock.wait()
		self._assert_lock(catdir_lock)

		try:
			try:
				portage.util.ensure_dirs(catdir,
					gid=portage.portage_gid,
					mode=0o70, mask=0)
			except PortageException:
				if not os.path.isdir(catdir):
					raise
			builddir_lock = AsynchronousLock(path=dir_path,
				scheduler=self.scheduler)
			builddir_lock.start()
			builddir_lock.wait()
			self._assert_lock(builddir_lock)
			self._lock_obj = builddir_lock
			self.settings['PORTAGE_BUILDIR_LOCKED'] = '1'
		finally:
			self.locked = self._lock_obj is not None
			catdir_lock.unlock()