This package provides functions for comparing version strings.
Similar functionality is available in Emacs; see version<
and related
functions defined in subr.el
.
I created this package for the benefit of the Emacsmirror, around the
time package.el
was also created. Emacs already provided version
comparison functions but package.el
did not use them initially.
Shortly after it was merged into Emacs, it started using them.
Neither the implementation in Emacs nor the one in early package.el
,
satisfied the requirements of the Emacsmirror, which had to deal with
all the crazy version strings found in the wild. Nowadays, version
strings tend to be less crazy. Because Emacs and thus package.el
,
does not support them, many package maintainers adjusted, which is
a good thing.
But back in the days, I had to write this package to cope. It is
based on the implementation initially used by package.el
.
The main difference is that this package also supports “post-releases”, not just “pre-releases”.
;; "1-alpha" is a "preview" of what will eventually be released as "1".
(version< "1-alpha" "1") => t
(vcomp< "1-alpha" "1") => t
;; "1" has already been released and this is a snaphot of a commit that follows that release.
(version< "1" "1-p20230407") => error
(vcomp< "1" "1-p20230407") => t
I intend to port that feature to Emacs’ implementation, so that the
could be used by MELPA, GNU-devel ELPA and NonGNU-devel ELPA. Vcomp
only supports -p
as a prefix for post-releases. I would have liked
to also support, e.g., -git
and -snapshot
, but since Emacs already
(ab)uses them as pre-releases, that won’t work. -dev
and -elpa
are still available though.
There are other difference. In some cases this package is more flexible, in other cases Emacs’ implementation is. I don’t think Emacs’ implementation should be changed.
- Vcomp supports only one post-release part.
1-alpha-beta
, for example, is not valid. - Vcomp does however support an additional
-rN
part. - Vcomp supports an additional alphabetic version part, while
version-to-list
produces the same result for1.1
and1A
. (version= "1" "1.0")
but by default(vcomp< "1" "1.0")
.
What is a valid version string, is defined jointly by the regular
expression stored in variable vcomp--regexp
and the function
vcomp--intern
, and best explained with an example.
Function vcomp--intern
converts a string to the internal format as
follows:
0.11a_rc3-r1 => ((0 11) (97 103 3 1))
0.11 => (0 11) valid separators are ._-
a => 97 either 0 or the ascii code of the lower
case letter (A is equal to a)
_rc => 103 100 alpha
101 beta
102 pre
103 rc
104 --
105 p
_ is optional, - is also valid
3 => 3 if missing 0 is used
-r1 => 1 there are no variations of -rN
A less crazy version string would be converted like this:
1.0.3 => ((1 0 3) (0 104 0 0))
The internal format is only intended for … internal use, but if you are wondering why a flat list does not do, here is one example:
1.97 => (1 97)
1a => (1 97)
There are other ways of dealing with this and similar problems. E.g.,
the built-in functions treat 1
and 1.0
as equal, and only support
pre-releases of sorts but not patches (-pN
) like this library does.
Functions vcomp-compare
and vcomp--compare-interned
can be used
to compare two versions using any predicate that can compare
integers.
When comparing two versions whose numeric parts have different
lengths, vcomp--compare-interned
fills in -1
.
1.0 => ((1 0) ...) => ((1 0 -1) ...)
1.0.0 => ((1 0 0) ...) => ((1 0 0) ...)
So 1.0.0
is greater than 1.0
, and 1.0
is greater than 1
. If
you don’t want that, set vcomp--fill-number
to 0
.
This filling has to happen in vcomp--compare-interned
, because we
don’t know the length of the other versions, when vcomp--intern
is
called.
Function vcomp-normalize
can be used to normalize a version string.
0-11A-Alpha0-r1 => 0.11a_alpha-r1
2.3d-BETA5 => 2.3d_beta5