Hello, everyone. Following my earlier threads, I'd like to propose a first complete solution for new version restrictions for package dependencies. I honestly doubt it's going to be approved since it's a major change. Nevertheless, I think it's an interesting topic for consideration.
What is included: - conjunctive version ranges, - revision-free and revision-oriented comparisons, - full set of (blocker-free) logical operators. What isn't included: - disjunctive version ranges, - complete lower bound problem solution, - extensions for prefix matching, - some convenience shortcuts like Ruby's ~> op. Backwards compatibility [recommended] ===================================== For backwards compatibility, package dependency specifications using old-style restrictions will still be accepted. Those specifications will retain the old behavior, and have no new features. New package dependency syntax ============================= New-style package dependencies use the following syntax: <cat> "/" <pkg> [":" <slot>] ["[" <vers> "]"] ["[" <usedep> "]"] with <vers> now using the following sub-syntax: <op> <version> ["," <op> <version>...] The version restriction operator is removed from the front and all package dependency specifications start with the category and package name, followed by optional package slot. This can be followed by optional version restrictions and USE flag restrictions. The version constraints (if present) must *always* be placed inside square brackets, even for a single constraint. Each constraint starts with an operator followed by a version string. Multiple constraints are separated using "," character, and are conjunctive (AND-ed). The operators are not valid for beginning of a USE dependency string, therefore the version constraint can be clearly distinguished from USE contraints. The version and USE flag constraints are always disjoint. If both are present, they must be surrounded by separate pairs of brackets. Examples: dev-foo/bar:13[foo] # slot + USE dev-foo/bar[>=3] # single version constraint dev-foo/bar:4[>=4.11,<4.20] # slot + version range dev-foo/bar[>=3][foo] # version + USE Version restrictions ==================== Each version restriction consists of an operator followed by a version string. The following revision-free version comparison operators are provided: == exact version match, or prefix match (with *) != exact version non-match, or prefix non-match (with *) < version less than match <= version less or equal to match > version greater than match >= version greater or equal to match All those operators compare on versions ignoring the revision part. They must be followed by a valid version with no revision part. Additionally, the == and != operators can accept a version followed by * to indicate prefix match. The following revision-oriented version comparison operators are provided: === exact version+revision match !== exact version+revision non-match <== version+revision less or equal to match >== version+revision greater or equal to match Those operators include both version and revision in the comparison. They must be followed by a valid version with an optional revision part. No revision is equal to -r0. Prefix match is not allowed. Examples: [==1.3.3] version 1.3.3, any revision [>1.3.3] version >1.3.3 (e.g. 1.3.3.1 or 1.3.4...) [<=1.3.3] version <=1.3.3 (incl. any revision of 1.3.3) [===1.3.3] 1.3.3-r0 [>==1.3.3-r2] 1.3.3-r2 or newer [>=1.2,!=1.3.3] version >=1.2 but not 1.3.3 (any revision) [>=1.2,<1.4] version >=1.2 but <1.4 [==1.2*] any version starting with 1.2 prefix [>=1.2,<1.8,!=1.6*] version >=1.2 but <1.8, also excluding 1.6* Mapping from existing dependency syntax ======================================= It should be noted that whenever revision match is desired, one of *== operators need to be used. They do not include '<' or '>' variants, so the revision needs to be decreased or increased appropriately for <== or >==. The behavior of current '~' operator is now equal to '==', so the former is removed. =foo-1.2.3 ===1.2.3 =foo-1.2.3-r3 ===1.2.3-r3 =foo-1.2.3* ==1.2.3* ~foo-1.2.3 ==1.2.3 >foo-1.2.3 >==1.2.3-r1 >foo-1.2.3-r9999 >1.2.3 >=foo-1.2.3 >=1.2.3 or >==1.2.3 >=foo-1.2.3-r3 >==1.2.3-r3 <foo-1.2.3 <1.2.3 <foo-1.2.3-r4 <==1.2.3-r3 <=foo-1.2.3 <==1.2.3 <=foo-1.2.3-r3 <==1.2.3-r3 <=foo-1.2.3-r9999 <=1.2.3 Solutions to other problems =========================== The provided operators make it possible to quite conveniently express common types of dependencies. The remaining kinds can be constructed using conjunctive ranges combined with existing operators. In particular, for this specific reason the != and !== operators are provided. Disjunctive version ranges were considered needed rarely. If specific versions needs to be excluded from the base version range, the != and !== operators (optionally in the prefix matching mode) can be used to do so. [>=1.2,<1.6,!=1.4*,!=1.5*] While I agree that this is not perfect and can become quite verbose at times, the use cases for it are rather limited. Revision ranges can be easily constructed using version ranges: [>==1.3-r3,<==1.3-r7] Not that I see any real use for them. Pre-release version ranges can be achieved using the relatively safe _alpha_alpha or _p_p suffixes, or just predicting the upstream version use. The convenience Ruby ~> operator needs to be expanded to the verbose range: [>=1.3.4,<1.4] or [>=1.3.4,==1.3*] Rationale ========= The key goal behind this concept is to optimize for upstream version specifications, and provide the minimal reasonable, clear, symmetric set of tools needed to achieve the correct dependencies. The version syntax changes are necessary to be able to clearly express version ranges, and also to distinguish old and new operators. Furthermore, they increase the readability and usefulness of package dependency specifications. The square braces and ordering are based after Exherbo but can be changed if necessary. The "," separator for versions is copied from USE dependencies which are conjunctive as well. The disjunctive variant was not included since our research has shown that it is used very rarely (i.e. only once in the few base Exherbo repositories we've checked). Any more complex logic would only make the dependencies less readable for unlikely benefit. The default behavior for new operators is meant to accommodate the common necessity of expressing upstream version restrictions in ebuilds. Its major advantage is that all the operators behave symmetrically now (i.e. you don't have to add -r9999 to some of them to match upstream constraints). The additional ===, !==, >==, <== operators are provided to accommodate Gentoo-specific revision constraints, and distinguish them from plain upstream version constraints. No variant for '<' and '>' is provided since the resulting syntax would be colliding or confusing, and all possible revisions can be already expressed clearly using existing operators. Negations were added for the == and === equality operators to help constructing version ranges. They also provide major readability (and behavior) benefit over the current necessity of disallowing single versions via blockers. The prefix matching behavior was retained since it has its use cases. Furthermore, it becomes useful with conjunctive version ranger to disallow single versions matching a generic range. -- Best regards, Michał Górny <http://dev.gentoo.org/~mgorny/>
pgpU44w8AUMn4.pgp
Description: OpenPGP digital signature