Introduce a pre-release version component
* The version string pattern is now: <major>[.<minor>[.<micro>]][-<pre>][-<release>] * Introduce B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE package attribute. * Add "preRelease" field to BPackageVersionData. * Add "preRelease" property to BPackageVersion and packagefs's Version. * Adjust package reader and writer code accordingly.
This commit is contained in:
parent
934980dcb1
commit
8f314372a8
@ -16,7 +16,7 @@ enum BPackageInfoAttributeID {
|
||||
B_PACKAGE_INFO_VENDOR, // e.g. "Haiku Project"
|
||||
B_PACKAGE_INFO_PACKAGER, // e-mail address preferred
|
||||
B_PACKAGE_INFO_ARCHITECTURE,
|
||||
B_PACKAGE_INFO_VERSION, // <major>[.<minor>[.<micro>]]
|
||||
B_PACKAGE_INFO_VERSION, // <major>[.<minor>[.<micro>]][-<pre>]-<release>
|
||||
B_PACKAGE_INFO_COPYRIGHTS, // list
|
||||
B_PACKAGE_INFO_LICENSES, // list
|
||||
B_PACKAGE_INFO_PROVIDES, // list of resolvables this package provides,
|
||||
|
@ -25,20 +25,22 @@ public:
|
||||
const BPackageVersionData& data);
|
||||
BPackageVersion(const BString& major,
|
||||
const BString& minor, const BString& micro,
|
||||
uint8 release);
|
||||
const BString& preRelease, uint8 release);
|
||||
|
||||
status_t InitCheck() const;
|
||||
|
||||
const BString& Major() const;
|
||||
const BString& Minor() const;
|
||||
const BString& Micro() const;
|
||||
const BString& PreRelease() const;
|
||||
// "alpha3", "beta2", "rc1" or "" if final
|
||||
uint8 Release() const;
|
||||
|
||||
BString ToString() const;
|
||||
|
||||
void SetTo(const BString& major,
|
||||
const BString& minor, const BString& micro,
|
||||
uint8 release);
|
||||
const BString& preRelease, uint8 release);
|
||||
void Clear();
|
||||
|
||||
int Compare(const BPackageVersion& other) const;
|
||||
@ -49,6 +51,7 @@ private:
|
||||
BString fMajor;
|
||||
BString fMinor;
|
||||
BString fMicro;
|
||||
BString fPreRelease;
|
||||
uint8 fRelease;
|
||||
};
|
||||
|
||||
|
@ -110,6 +110,7 @@ enum BHPKGAttributeID {
|
||||
B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES = 37,
|
||||
B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR = 38,
|
||||
B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM = 39,
|
||||
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE = 40,
|
||||
//
|
||||
B_HPKG_ATTRIBUTE_ID_ENUM_COUNT,
|
||||
};
|
||||
|
@ -23,6 +23,7 @@ struct BPackageVersionData {
|
||||
const char* major;
|
||||
const char* minor;
|
||||
const char* micro;
|
||||
const char* preRelease;
|
||||
uint8 release;
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <new>
|
||||
|
||||
#include <NaturalCompare.h>
|
||||
@ -37,6 +38,7 @@ Version::Version()
|
||||
fMajor(NULL),
|
||||
fMinor(NULL),
|
||||
fMicro(NULL),
|
||||
fPreRelease(NULL),
|
||||
fRelease(0)
|
||||
{
|
||||
}
|
||||
@ -47,12 +49,13 @@ Version::~Version()
|
||||
free(fMajor);
|
||||
free(fMinor);
|
||||
free(fMicro);
|
||||
free(fPreRelease);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Version::Init(const char* major, const char* minor, const char* micro,
|
||||
uint8 release)
|
||||
const char* preRelease, uint8 release)
|
||||
{
|
||||
if (major != NULL) {
|
||||
fMajor = strdup(major);
|
||||
@ -72,6 +75,12 @@ Version::Init(const char* major, const char* minor, const char* micro,
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (preRelease != NULL) {
|
||||
fPreRelease = strdup(preRelease);
|
||||
if (fPreRelease == NULL)
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
fRelease = release;
|
||||
|
||||
return B_OK;
|
||||
@ -80,13 +89,13 @@ Version::Init(const char* major, const char* minor, const char* micro,
|
||||
|
||||
/*static*/ status_t
|
||||
Version::Create(const char* major, const char* minor, const char* micro,
|
||||
uint8 release, Version*& _version)
|
||||
const char* preRelease, uint8 release, Version*& _version)
|
||||
{
|
||||
Version* version = new(std::nothrow) Version;
|
||||
if (version == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t error = version->Init(major, minor, micro, release);
|
||||
status_t error = version->Init(major, minor, micro, preRelease, release);
|
||||
if (error != B_OK) {
|
||||
delete version;
|
||||
return error;
|
||||
@ -112,6 +121,21 @@ Version::Compare(const Version& other) const
|
||||
if (cmp != 0)
|
||||
return cmp;
|
||||
|
||||
// The pre-version works differently: The empty string is greater than any
|
||||
// non-empty string (e.g. "R1" is newer than "R1-rc2"). So we catch the
|
||||
// empty string cases first.
|
||||
if (fPreRelease == NULL) {
|
||||
if (other.fPreRelease != NULL)
|
||||
return 1;
|
||||
} else if (other.fPreRelease == NULL) {
|
||||
return -1;
|
||||
} else {
|
||||
// both are non-null -- compare normally
|
||||
cmp = BPrivate::NaturalCompare(fPreRelease, other.fPreRelease);
|
||||
if (cmp != 0)
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return (int)fRelease - other.fRelease;
|
||||
}
|
||||
|
||||
@ -147,8 +171,8 @@ Version::ToString(char* buffer, size_t bufferSize) const
|
||||
{
|
||||
// We need to normalize the version string somewhat. If a subpart is given,
|
||||
// make sure that also the superparts are defined, using a placeholder. This
|
||||
// avoids clashes, e.g. if one version defines only major and one only
|
||||
// micro.
|
||||
// avoids clashes, e.g. if one version defines major and minor and one only
|
||||
// major and micro.
|
||||
const char* major = fMajor;
|
||||
const char* minor = fMinor;
|
||||
const char* micro = fMicro;
|
||||
@ -158,16 +182,28 @@ Version::ToString(char* buffer, size_t bufferSize) const
|
||||
if (minor != NULL && major == NULL)
|
||||
major = kVersionPartPlaceholder;
|
||||
|
||||
if (micro != NULL) {
|
||||
return snprintf(buffer, bufferSize, "%s.%s.%s-%u", major, minor, micro,
|
||||
fRelease);
|
||||
size_t size = strlcpy(buffer, major, bufferSize);
|
||||
|
||||
if (minor != NULL) {
|
||||
size_t offset = std::min(bufferSize, size);
|
||||
size += snprintf(buffer + offset, bufferSize - offset, ".%s", minor);
|
||||
}
|
||||
|
||||
if (minor != NULL)
|
||||
return snprintf(buffer, bufferSize, "%s.%s-%u", major, minor, fRelease);
|
||||
if (micro != NULL) {
|
||||
size_t offset = std::min(bufferSize, size);
|
||||
size += snprintf(buffer + offset, bufferSize - offset, ".%s", micro);
|
||||
}
|
||||
|
||||
if (major != NULL)
|
||||
return snprintf(buffer, bufferSize, "%s-%u", major, fRelease);
|
||||
if (fPreRelease != NULL) {
|
||||
size_t offset = std::min(bufferSize, size);
|
||||
size += snprintf(buffer + offset, bufferSize - offset, "-%s",
|
||||
fPreRelease);
|
||||
}
|
||||
|
||||
return snprintf(buffer, bufferSize, "%u", fRelease);
|
||||
if (fRelease != 0) {
|
||||
size_t offset = std::min(bufferSize, size);
|
||||
size += snprintf(buffer + offset, bufferSize - offset, "-%u", fRelease);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
@ -19,11 +19,12 @@ public:
|
||||
~Version();
|
||||
|
||||
status_t Init(const char* major, const char* minor,
|
||||
const char* micro, uint8 release);
|
||||
const char* micro, const char* preRelease,
|
||||
uint8 release);
|
||||
|
||||
static status_t Create(const char* major, const char* minor,
|
||||
const char* micro, uint8 release,
|
||||
Version*& _version);
|
||||
const char* micro, const char* preRelease,
|
||||
uint8 release, Version*& _version);
|
||||
|
||||
int Compare(const Version& other) const;
|
||||
bool Compare(BPackageResolvableOperator op,
|
||||
@ -37,6 +38,7 @@ private:
|
||||
char* fMajor;
|
||||
char* fMinor;
|
||||
char* fMicro;
|
||||
char* fPreRelease;
|
||||
uint8 fRelease;
|
||||
};
|
||||
|
||||
|
@ -294,7 +294,7 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
|
||||
Version* version;
|
||||
status_t error = Version::Create(value.version.major,
|
||||
value.version.minor, value.version.micro,
|
||||
value.version.release, version);
|
||||
value.version.preRelease, value.version.release, version);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
@ -312,7 +312,7 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
|
||||
= value.resolvable.version;
|
||||
status_t error = Version::Create(versionInfo.major,
|
||||
versionInfo.minor, versionInfo.micro,
|
||||
versionInfo.release, version);
|
||||
versionInfo.preRelease, versionInfo.release, version);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
@ -354,7 +354,7 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
|
||||
= value.resolvableExpression.version;
|
||||
status_t error = Version::Create(versionInfo.major,
|
||||
versionInfo.minor, versionInfo.micro,
|
||||
versionInfo.release, version);
|
||||
versionInfo.preRelease, versionInfo.release, version);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
|
@ -253,6 +253,8 @@ private:
|
||||
printf(".%s", version.minor);
|
||||
if (version.micro != NULL && version.micro[0] != '\0')
|
||||
printf(".%s", version.micro);
|
||||
if (version.preRelease != NULL && version.preRelease[0] != '\0')
|
||||
printf("-%s", version.preRelease);
|
||||
if (version.release > 0)
|
||||
printf("-%d", version.release);
|
||||
}
|
||||
|
@ -226,6 +226,8 @@ private:
|
||||
printf(".%s", version.minor);
|
||||
if (version.micro != NULL && version.micro[0] != '\0')
|
||||
printf(".%s", version.micro);
|
||||
if (version.preRelease != NULL && version.preRelease[0] != '\0')
|
||||
printf("-%s", version.preRelease);
|
||||
if (version.release > 0)
|
||||
printf("-%d", version.release);
|
||||
}
|
||||
|
@ -349,23 +349,43 @@ BPackageInfo::Parser::_ParseVersionValue(BPackageVersion* value,
|
||||
if (word.type != TOKEN_WORD)
|
||||
throw ParseError("expected word (a version)", word.pos);
|
||||
|
||||
// get the release number
|
||||
uint8 release = 0;
|
||||
int32 lastDashPos = word.text.FindLast('-');
|
||||
if (lastDashPos < 0) {
|
||||
if (!releaseIsOptional) {
|
||||
throw ParseError("expected release number (-<number> suffix)",
|
||||
if (lastDashPos >= 0) {
|
||||
// Might be either the release number or, if that is optional, a
|
||||
// pre-release. The former always is a number, the latter starts with a
|
||||
// non-digit.
|
||||
if (isdigit(word.text[lastDashPos + 1])) {
|
||||
int number = atoi(word.text.String() + lastDashPos + 1);
|
||||
if (number <= 0 || number > 99) {
|
||||
throw ParseError("release number must be from 1-99",
|
||||
word.pos + word.text.Length());
|
||||
}
|
||||
release = number;
|
||||
word.text.Truncate(lastDashPos);
|
||||
lastDashPos = word.text.FindLast('-');
|
||||
}
|
||||
}
|
||||
|
||||
if (release == 0 && !releaseIsOptional) {
|
||||
throw ParseError("expected release number (-<number> suffix)",
|
||||
word.pos + word.text.Length());
|
||||
}
|
||||
|
||||
// get the pre-release string
|
||||
BString preRelease;
|
||||
if (lastDashPos >= 0) {
|
||||
if (isdigit(word.text[lastDashPos + 1])) {
|
||||
throw ParseError("pre-release number must not start with a digit",
|
||||
word.pos + word.text.Length());
|
||||
}
|
||||
} else {
|
||||
int number = atoi(word.text.String() + lastDashPos + 1);
|
||||
if (number <= 0 || number > 99) {
|
||||
throw ParseError("release number must be from 1-99",
|
||||
word.pos + word.text.Length());
|
||||
}
|
||||
release = number;
|
||||
|
||||
word.text.CopyInto(preRelease, lastDashPos + 1, word.text.Length());
|
||||
word.text.Truncate(lastDashPos);
|
||||
}
|
||||
|
||||
// get major, minor, and micro strings
|
||||
BString major;
|
||||
BString minor;
|
||||
BString micro;
|
||||
@ -387,7 +407,7 @@ BPackageInfo::Parser::_ParseVersionValue(BPackageVersion* value,
|
||||
}
|
||||
}
|
||||
|
||||
value->SetTo(major, minor, micro, release);
|
||||
value->SetTo(major, minor, micro, preRelease, release);
|
||||
}
|
||||
|
||||
|
||||
|
@ -29,17 +29,19 @@ BPackageVersion::BPackageVersion(const BPackageVersionData& data)
|
||||
fMajor(data.major),
|
||||
fMinor(data.minor),
|
||||
fMicro(data.micro),
|
||||
fPreRelease(data.preRelease),
|
||||
fRelease(data.release)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BPackageVersion::BPackageVersion(const BString& major, const BString& minor,
|
||||
const BString& micro, uint8 release)
|
||||
const BString& micro, const BString& preRelease, uint8 release)
|
||||
:
|
||||
fMajor(major),
|
||||
fMinor(minor),
|
||||
fMicro(micro),
|
||||
fPreRelease(preRelease),
|
||||
fRelease(release)
|
||||
{
|
||||
}
|
||||
@ -73,6 +75,13 @@ BPackageVersion::Micro() const
|
||||
}
|
||||
|
||||
|
||||
const BString&
|
||||
BPackageVersion::PreRelease() const
|
||||
{
|
||||
return fPreRelease;
|
||||
}
|
||||
|
||||
|
||||
uint8
|
||||
BPackageVersion::Release() const
|
||||
{
|
||||
@ -83,17 +92,32 @@ BPackageVersion::Release() const
|
||||
int
|
||||
BPackageVersion::Compare(const BPackageVersion& other) const
|
||||
{
|
||||
int majorDiff = NaturalCompare(fMajor.String(), other.fMajor.String());
|
||||
if (majorDiff != 0)
|
||||
return majorDiff;
|
||||
int diff = NaturalCompare(fMajor.String(), other.fMajor.String());
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
|
||||
int minorDiff = NaturalCompare(fMinor.String(), other.fMinor.String());
|
||||
if (minorDiff != 0)
|
||||
return minorDiff;
|
||||
diff = NaturalCompare(fMinor.String(), other.fMinor.String());
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
|
||||
int microDiff = NaturalCompare(fMicro.String(), other.fMicro.String());
|
||||
if (microDiff != 0)
|
||||
return microDiff;
|
||||
diff = NaturalCompare(fMicro.String(), other.fMicro.String());
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
|
||||
// The pre-version works differently: The empty string is greater than any
|
||||
// non-empty string (e.g. "R1" is newer than "R1-rc2"). So we catch the
|
||||
// empty string cases first.
|
||||
if (fPreRelease.IsEmpty()) {
|
||||
if (!other.fPreRelease.IsEmpty())
|
||||
return 1;
|
||||
} else if (other.fPreRelease.IsEmpty()) {
|
||||
return -1;
|
||||
} else {
|
||||
// both are non-null -- compare normally
|
||||
diff = NaturalCompare(fPreRelease.String(), other.fPreRelease.String());
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
}
|
||||
|
||||
return (int)fRelease - (int)other.fRelease;
|
||||
}
|
||||
@ -110,6 +134,9 @@ BPackageVersion::ToString() const
|
||||
string << '.' << fMicro;
|
||||
}
|
||||
|
||||
if (!fPreRelease.IsEmpty())
|
||||
string << '-' << fPreRelease;
|
||||
|
||||
if (fRelease > 0)
|
||||
string << '-' << fRelease;
|
||||
|
||||
@ -119,11 +146,12 @@ BPackageVersion::ToString() const
|
||||
|
||||
void
|
||||
BPackageVersion::SetTo(const BString& major, const BString& minor,
|
||||
const BString& micro, uint8 release)
|
||||
const BString& micro, const BString& preRelease, uint8 release)
|
||||
{
|
||||
fMajor = major;
|
||||
fMinor = minor;
|
||||
fMicro = micro;
|
||||
fPreRelease = preRelease;
|
||||
fRelease = release;
|
||||
}
|
||||
|
||||
@ -134,6 +162,7 @@ BPackageVersion::Clear()
|
||||
fMajor.Truncate(0);
|
||||
fMinor.Truncate(0);
|
||||
fMicro.Truncate(0);
|
||||
fPreRelease.Truncate(0);
|
||||
fRelease = 0;
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,7 @@ static const char* kAttributeNames[B_HPKG_ATTRIBUTE_ID_ENUM_COUNT + 1] = {
|
||||
"package:replaces",
|
||||
"package:resolvable.operator",
|
||||
"package:checksum",
|
||||
"package:version.prerelease",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
@ -127,6 +127,10 @@ ReaderImplBase::PackageVersionAttributeHandler::HandleAttribute(
|
||||
fPackageVersionData.micro = value.string;
|
||||
break;
|
||||
|
||||
case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE:
|
||||
fPackageVersionData.preRelease = value.string;
|
||||
break;
|
||||
|
||||
case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_RELEASE:
|
||||
fPackageVersionData.release = value.unsignedInt;
|
||||
break;
|
||||
|
@ -523,6 +523,16 @@ WriterImplBase::RegisterPackageVersion(PackageAttributeList& attributeList,
|
||||
}
|
||||
}
|
||||
|
||||
if (!version.PreRelease().IsEmpty()) {
|
||||
PackageAttribute* preRelease = new PackageAttribute(
|
||||
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE,
|
||||
B_HPKG_ATTRIBUTE_TYPE_STRING,
|
||||
B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
|
||||
preRelease->string
|
||||
= fPackageStringCache.Get(version.PreRelease().String());
|
||||
versionMajor->children.Add(preRelease);
|
||||
}
|
||||
|
||||
if (version.Release() != 0) {
|
||||
PackageAttribute* versionRelease = new PackageAttribute(
|
||||
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_RELEASE,
|
||||
|
Loading…
Reference in New Issue
Block a user