NAME
Java::Maven::Artifact::Version - a perl module for comparing Artifact versions exactly like Maven does.
VERSION
Version 1.000001
see "MAVEN VERSION COMPATIBILITY".
SYNOPSIS
Note that this documentation is intended as a reference to the module.
use Java::Maven::Artifact::Version qw/version_compare version_parse/;
my $y = version_compare('1-alpha', '1-beta'); # $y = -1
my $x = version_compare('1.0', '1-0.alpha'); # $x = 0
my $z = version_parse('1-1.2-alpha'); # $z = '(1,(1,2,alpha))'
my @l = version_parse('1-1.2-alpha'); # @l = (1,[1,2,'alpha'])
DESCRIPTION
Apache Maven has a peculiar way to compare Artifact versions. The aim of this module is to exactly reproduce this way in hope that it could be usefull to someone that wants to write utils like SCM hooks. It may quickly ensure an Artifact version respect a grow order without to have to install Java and Maven on the system in charge of this checking.
The official Apache document that describes it is here http://docs.codehaus.org/display/MAVEN/Versioning. But don't blindly believe everything. Take the red pill, and I show you how deep the rabbit-hole goes. Because there is a gap between the truth coded in org.apache.maven.artifact.versioning.ComparableVersion.java
that can be found here and that Maven official document.
Lucky for you this module cares about the real comparison differences hard coded in ComparableVersion
and reproduces it.
see "FAQ" for details.
SUBROUTINES
version_compare
By default version_compare
compares a version string to another one exactly like Maven does.
See http://docs.codehaus.org/display/MAVEN/Versioning for general comparison description, and "DESCRIPTION" for more details about mechanisms not described in that official Maven doc but occur during Maven Artifact versions comparison in Java.
This function will return :
0
if versions compared are equal1
if version is greater than version that is compared to-1
if version is lower than version that is compared to
$v = version_compare('1.0', '1.1'); # $v = -1
version_compare
can go further. You can set max_depth
to stop comparison before the whole version comparison has processed.
Suppose you have to code SCM hook which enforce that pushed artifact source must always begin by the same two version items and new version must be greater than the old one.
my ($old, $new) = ('1.1.12', '1.1.13');
my $common = version_compare($old, $new, 2); # returns 0 here
die "you did not respect the version policy" if $common;
die "you must increment artifact version" if version_compare($old, $new) >= 0;
Note that max_depth
cares about sub listitems
.
$v = '1-1.0.sp; # normalized to (1,(1,0,'sp'))
$o = '1-1-SNAPSHOT'; # normalized to (1,(1,'SNAPSHOT'))
$x = version_compare($v, $o, 3); # will compare '0' to 'SNAPSHOT' and will return 1
Of course understand that this computation is done after normalization.
$x = version_compare('1-1.0-1-ga-0-1.2', '1-1.0-1-ga-0-1.3', 4); #only last item will be ignored during this comparison
# ^ ^ ^ ^ ^ ^ ^ ^
Note that set negative max_depth
will always return 0, because no comparison will be done at all
$x = version_compare(1, 2, -1); # $x = 0
version_parse
will return normalized version representation (see "Normalization").
In scalar context, it will return string representation :
$s = version_parse('1.0-final-1'); # $s = '(1,(,1))'
You would have the same string if you had call org.apache.maven.artifact.versioning.ComparableVersion.ListItem.toString()
private method of org.apache.maven.artifact.versioning.ComparableVersion.java
on the main ListItem
.
In list context, it will return the data structure representation :
@l = version_parse('1.0-final-1'); # [1,['',1]]
FAQ
What are differences between actual Maven comparison algo and that described in the official Maven doc ?
zero appending on blank separator
zero ('0
') will be appended on each blank separator char (dot '.' or dash '-') During parsing if separator char is encountered and it was not preceded by stringitem
or listitem
, zero char ('0
') is automatically appended. Then version that begins with separator is automatically prefixed by zero.
'-1
' will be internally moved to '0-1
'.
'1....1
' will be internally moved to '1.0.0.0.1
'.
The dash separator "-"
The dash separator "-" will create listitem
only if it is preceeded by an integeritem
and it is followed by digit.
Then when they say 1-alpha10-SNAPSHOT => [1,["alpha",10,["SNAPSHOT"]]]
understand that it's wrong.
1-alpha10-SNAPSHOT
is internally represented by [1,"alpha",10,"SNAPSHOT"]
. Which has a fully different comparison behavior because no sub listitem
is created.
Please note that "zero appending on blank separator" has been done after listitem
splitting.
Then understand that '-1--1
' will NOT be internally represented by '(0,(1,(0,(1))
', but by '(0,1,0,1)
'.
Normalization
Normalization is one of the most important part of version comparison but it is not described at all in the official Maven document. So what is normalization ? It's kind of reducing version components function. Its aim is to shoot useless version components in artifact version. To simplify it, understand that 1.0
must be internally represented by 1
during comparison. But normalization appends in specific times during artifact version parsing.
It appends:
- 1. each time a dash '
-
' separator is preceded by digit but before any alias substitution (except when any of these digits is a zero appended, becauselistitem
splitting is done before 'zero appending'). - 2. at the end of each parsed
listitem
, then after all alias substitution
And normalization process current parsed listitem
from current position when normalization is called, back to the beginning of this current listitem
.
Each encountered nullitem
will be shot until a non nullitem
is encountered or until the begining of this listitem
is reached if all its items are nullitems
. In this last case precisely, the empty listitem
will be shot except if it is the main one.
Then understand that :
1.0.alpha.0
becomes(1,0,alpha)
#because when mainlistitem
parsing has ended, normalization has been called. Last item was 0, 0 is thenullitem
ofintegeritem
, then it has been shooted. Next last item wasalpha
that is notnullitem
then normalization process stopped.1.0-final-1
becomes(1,,1)
#because a dash has been encoutered during parsing. Then normalization has been called because it was preceded by a digit and last item in the currentlistitem
is 0. Then it has been shot.final
has been substituted by''
but when next normalization has been called, at the end of the parsing, the last item was notnullitem
, then normalization did not meet''
.0.0.ga
becomes()
# because 'ga' has been substituted by''
and whenlistitem
has been normalized at the end, all items wherenullitem
sfinal-0.1 becomes
(,0,1) # because normalization has not been called after first dash because it was not been preceded by digit.
If you told me WTF ?, I would answer I am not responsible of drug consumption...
In org.apache.maven.artifact.versioning.ComparableVersion.java
, the representation of normalized version is only displayable with the call of org.apache.maven.artifact.versioning.ComparableVersion.ListItem.toString()
private method on the main ListItem
.
Comma ",
" is used as items separator, and enclosing braces are used to represent ListItem
.
For example: in Java world org.apache.maven.artifact.versioning.ComparableVersion.ListItem.toString()
on "1-0.1"
gives "(1,(0,1))"
.
"version_parse" function reproduces this algo for the whole set Java::Maven::Artifact::Version
.
$v = version_parse('1-0.1'); # $v = '(1,(O,1))'
listitem and nullitem comparison
It is not very clear in the official Maven doc.
Comparing listitem
with nullitem
will just compare first item
of the listitem
with nullitem
.
MAVEN VERSION COMPATIBILITY
This version is fully compatible with the org.apache.maven.artifact.versioning.ComparableVersion.java
algo of org.apache.maven:maven-artifact
embedded with :
Maven 3.2.3
Maven 3.2.2
All Test::More tests are also available with Java Junit tests to ensure comparison results are similars.
See "SOURCE" if you want to check them.
I will do my best to check the Maven compatibility on each Maven new release.
AUTHOR
Thomas Cazali, <pandragon at cpan.org>
SOURCE
The source code repository for Java::Maven::Artifact::Version
can be found at https://github.com/apendragon/Java-Maven-Artifact-Version/
BUGS
Please report any bugs or feature requests to https://github.com/apendragon/Java-Maven-Artifact-Version/issues.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc Java::Maven::Artifact::Version
You can also look for information at:
https://github.com/apendragon/Java-Maven-Artifact-Version/wiki
github repository issues tracker (report bugs here)
https://github.com/apendragon/Java-Maven-Artifact-Version/issues
AnnoCPAN: Annotated CPAN documentation
CPAN Ratings
Search CPAN
LICENSE AND COPYRIGHT
Copyright 2014 Thomas Cazali.
This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:
http://www.perlfoundation.org/artistic_license_2_0
Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.
If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.
This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.
This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.
Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.