예제 #1
0
	def entries_matching_range(self, from_ver=None, to_ver=None):
		"""Return entries whose header versions are within a range of versions.

		@type from_ver: str
		@param from_ver: valid Gentoo version
		@type to_ver: str
		@param to_ver: valid Gentoo version
		@rtype: list
		@return: entries between from_ver and to_ver
		@raise errors.GentoolkitFatalError: if neither vers are set
		@raise errors.GentoolkitInvalidVersion: if either ver is invalid
		"""
		result = []

		# Make sure we have at least one version set
		if not (from_ver or to_ver):
			raise errors.GentoolkitFatalError(
				"Need to specifiy 'from_ver' or 'to_ver'"
			)

		# Create a VersionMatch instance out of from_ver
		from_restriction = None
		if from_ver:
			try:
				from_ver_rev = CPV("null-%s" % from_ver)
			except errors.GentoolkitInvalidCPV:
				raise errors.GentoolkitInvalidVersion(from_ver)
			from_restriction = VersionMatch(from_ver_rev, op='>=')

		# Create a VersionMatch instance out of to_ver
		to_restriction = None
		if to_ver:
			try:
				to_ver_rev = CPV("null-%s" % to_ver)
			except errors.GentoolkitInvalidCPV:
				raise errors.GentoolkitInvalidVersion(to_ver)
			to_restriction = VersionMatch(to_ver_rev, op='<=')

		# Add entry to result if version ranges intersect it
		for entry_set in self.indexed_entries:
			i, entry = entry_set
			if from_restriction and not from_restriction.match(i):
				continue
			if to_restriction and not to_restriction.match(i):
				# TODO: is it safe to break here?
				continue
			result.append(entry)

		return result
예제 #2
0
    def _index_changelog(self):
        """Use the output of L{self._split_changelog} to create an index list
		of L{gentoolkit.versionmatch.VersionMatch} objects.

		@rtype: list
		@return: tuples containing a VersionMatch instance for the release
			version of each entry header as the first item and the entire entry
			as the second item
		@raise ValueError: if self.invalid_entry_is_fatal is True and we hit an
			invalid entry
		"""

        result = []
        for entry in self.entries:
            # Extract the package name from the entry header, ex:
            # *xterm-242 (07 Mar 2009) => xterm-242
            pkg_name = entry.split(' ', 1)[0].lstrip('*')
            if not pkg_name.strip():
                continue
            try:
                entry_ver = CPV(pkg_name, validate=True)
            except errors.GentoolkitInvalidCPV:
                if self.invalid_entry_is_fatal:
                    raise ValueError(entry_ver)
                continue

            result.append((VersionMatch(entry_ver, op='='), entry))

        return result
예제 #3
0
    def intersects(self, other):
        """Check if a passed in package atom "intersects" this atom.

		Lifted from pkgcore.

		Two atoms "intersect" if a package can be constructed that
		matches both:
		  - if you query for just "dev-lang/python" it "intersects" both
			"dev-lang/python" and ">=dev-lang/python-2.4"
		  - if you query for "=dev-lang/python-2.4" it "intersects"
			">=dev-lang/python-2.4" and "dev-lang/python" but not
			"<dev-lang/python-2.3"

		@type other: L{gentoolkit.atom.Atom} or
			L{gentoolkit.versionmatch.VersionMatch}
		@param other: other package to compare
		@see: L{pkgcore.ebuild.atom}
		"""
        # Our "cp" (cat/pkg) must match exactly:
        if self.cp != other.cp:
            # Check to see if one is name only:
            # We don't bother checking if self.category is None: it can't be
            # because we're an Atom subclass and that would be invalid.
            return (not other.category and self.name == other.name)

        # Slot dep only matters if we both have one. If we do they
        # must be identical:
        this_slot = getattr(self, 'slot', None)
        that_slot = getattr(other, 'slot', None)
        if (this_slot is not None and that_slot is not None
                and this_slot != that_slot):
            return False

        if (self.repo is not None and other.repo is not None
                and self.repo != other.repo):
            return False

        # Use deps are similar: if one of us forces a flag on and the
        # other forces it off we do not intersect. If only one of us
        # cares about a flag it is irrelevant.

        # Skip the (very common) case of one of us not having use deps:
        this_use = getattr(self, 'use', None)
        that_use = getattr(other, 'use', None)
        if this_use and that_use:
            # Set of flags we do not have in common:
            flags = set(this_use.tokens) ^ set(that_use.tokens)
            for flag in flags:
                # If this is unset and we also have the set version we fail:
                if flag[0] == '-' and flag[1:] in flags:
                    return False

        # Remaining thing to check is version restrictions. Get the
        # ones we can check without actual version comparisons out of
        # the way first.

        # If one of us is unversioned we intersect:
        if not self.operator or not other.operator:
            return True

        # If we are both "unbounded" in the same direction we intersect:
        if (('<' in self.operator and '<' in other.operator)
                or ('>' in self.operator and '>' in other.operator)):
            return True

        # If one of us is an exact match we intersect if the other matches it:
        if self.operator == '=':
            if other.operator == '=*':
                return self.fullversion.startswith(other.fullversion)
            return VersionMatch(other, op=other.operator).match(self)
        if other.operator == '=':
            if self.operator == '=*':
                return other.fullversion.startswith(self.fullversion)
            return VersionMatch(self, op=self.operator).match(other)

        # If we are both ~ matches we match if we are identical:
        if self.operator == other.operator == '~':
            return (self.version == other.version
                    and self.revision == other.revision)

        # If we are both glob matches we match if one of us matches the other.
        if self.operator == other.operator == '=*':
            return (self.fullversion.startswith(other.fullversion)
                    or other.fullversion.startswith(self.fullversion))

        # If one of us is a glob match and the other a ~ we match if the glob
        # matches the ~ (ignoring a revision on the glob):
        if self.operator == '=*' and other.operator == '~':
            return other.fullversion.startswith(self.version)
        if other.operator == '=*' and self.operator == '~':
            return self.fullversion.startswith(other.version)

        # If we get here at least one of us is a <, <=, > or >=:
        if self.operator in ('<', '<=', '>', '>='):
            ranged, ranged.operator = self, self.operator
        else:
            ranged, ranged.operator = other, other.operator
            other, other.operator = self, self.operator

        if '<' in other.operator or '>' in other.operator:
            # We are both ranged, and in the opposite "direction" (or
            # we would have matched above). We intersect if we both
            # match the other's endpoint (just checking one endpoint
            # is not enough, it would give a false positive on <=2 vs >2)
            return (VersionMatch(other, op=other.operator).match(ranged)
                    and VersionMatch(ranged, op=ranged.operator).match(other))

        if other.operator == '~':
            # Other definitely matches its own version. If ranged also
            # does we're done:
            if VersionMatch(ranged, op=ranged.operator).match(other):
                return True
            # The only other case where we intersect is if ranged is a
            # > or >= on other's version and a nonzero revision. In
            # that case other will match ranged. Be careful not to
            # give a false positive for ~2 vs <2 here:
            return (ranged.operator in ('>', '>=')
                    and VersionMatch(other, op=other.operator).match(ranged))

        if other.operator == '=*':
            # a glob match definitely matches its own version, so if
            # ranged does too we're done:
            if VersionMatch(ranged, op=ranged.operator).match(other):
                return True
            if '<' in ranged.operator:
                # If other.revision is not defined then other does not
                # match anything smaller than its own fullversion:
                if other.revision:
                    return False

                # If other.revision is defined then we can always
                # construct a package smaller than other.fullversion by
                # tagging e.g. an _alpha1 on.
                return ranged.fullversion.startswith(other.version)
            else:
                # Remaining cases where this intersects: there is a
                # package greater than ranged.fullversion and
                # other.fullversion that they both match.
                return ranged.fullversion.startswith(other.version)

        # Handled all possible ops.
        raise NotImplementedError(
            'Someone added an operator without adding it to intersects')