mirror of https://gitlab.com/basile.b/dexed.git
handle dependency operators, close #231
This commit is contained in:
parent
7ff81260ea
commit
d3c495d605
|
@ -6,7 +6,7 @@ interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, fpjson, jsonparser, jsonscanner, process, strutils,
|
Classes, SysUtils, fpjson, jsonparser, jsonscanner, process, strutils,
|
||||||
LazFileUtils, RegExpr,
|
LazFileUtils, RegExpr, fgl,
|
||||||
ce_common, ce_interfaces, ce_observer, ce_dialogs, ce_processes,
|
ce_common, ce_interfaces, ce_observer, ce_dialogs, ce_processes,
|
||||||
ce_writableComponent, ce_compilers, ce_semver, ce_stringrange;
|
ce_writableComponent, ce_compilers, ce_semver, ce_stringrange;
|
||||||
|
|
||||||
|
@ -22,11 +22,20 @@ type
|
||||||
|
|
||||||
PDubLocalPackage = ^TDubLocalPackage;
|
PDubLocalPackage = ^TDubLocalPackage;
|
||||||
|
|
||||||
TDubLocalPackage = record
|
TSemVerList = specialize TFPGList<PSemVer>;
|
||||||
name : string;
|
|
||||||
versions: array of TSemVer;
|
TDubLocalPackage = class
|
||||||
|
strict private
|
||||||
|
fName : string;
|
||||||
|
fVersions: TSemVerList;
|
||||||
|
public
|
||||||
|
constructor create;
|
||||||
|
destructor destroy; override;
|
||||||
procedure addVersion(const value: string);
|
procedure addVersion(const value: string);
|
||||||
function findVersion(constref value: TSemVer): boolean;
|
function findVersion(constref value: TSemVer): PSemVer;
|
||||||
|
function highestInInterval(constref lo, hi: TSemVer): PSemVer;
|
||||||
|
function highest: PSemVer;
|
||||||
|
property name: string read fName write fName;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TDubLocalPackages = class
|
TDubLocalPackages = class
|
||||||
|
@ -34,8 +43,11 @@ type
|
||||||
fRoot: string;
|
fRoot: string;
|
||||||
fLocalPackages: array of TDubLocalPackage;
|
fLocalPackages: array of TDubLocalPackage;
|
||||||
public
|
public
|
||||||
|
destructor destroy; override;
|
||||||
procedure update;
|
procedure update;
|
||||||
function find(const name: string; out package: PDubLocalPackage): boolean;
|
function find(const name: string; out package: PDubLocalPackage): boolean; overload;
|
||||||
|
function find(const name, op: string; constref opVer: TSemVer;
|
||||||
|
out package: PDubLocalPackage): PSemver; overload;
|
||||||
function fetch(constref version: TSemVer): PDubLocalPackage;
|
function fetch(constref version: TSemVer): PDubLocalPackage;
|
||||||
function getPackageePath(package: PDubLocalPackage): string;
|
function getPackageePath(package: PDubLocalPackage): string;
|
||||||
end;
|
end;
|
||||||
|
@ -212,35 +224,86 @@ const
|
||||||
DubDefaultConfigName = '(default config)';
|
DubDefaultConfigName = '(default config)';
|
||||||
|
|
||||||
{$REGION TDubLocalPackages -----------------------------------------------------}
|
{$REGION TDubLocalPackages -----------------------------------------------------}
|
||||||
procedure TDubLocalPackage.addVersion(const value: string);
|
constructor TDubLocalPackage.create;
|
||||||
var
|
|
||||||
v: TSemVer;
|
|
||||||
i: integer;
|
|
||||||
begin
|
begin
|
||||||
if value = 'vmaster' then
|
fVersions := TSemVerList.create;
|
||||||
v.init('v0.0.0-master')
|
|
||||||
else try
|
|
||||||
v.init(value);
|
|
||||||
except
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
for i:= 0 to high(versions) do
|
|
||||||
begin
|
|
||||||
if versions[i] = v then
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
setLength(versions, length(versions) + 1);
|
|
||||||
versions[high(versions)] := v;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDubLocalPackage.findVersion(constref value: TSemVer): boolean;
|
destructor TDubLocalPackage.destroy;
|
||||||
var
|
var
|
||||||
i: integer;
|
i: integer;
|
||||||
begin
|
begin
|
||||||
result := false;
|
for i := 0 to fVersions.Count-1 do
|
||||||
for i:= 0 to high(versions) do
|
dispose(fVersions.Items[i]);
|
||||||
if versions[i] = value then
|
fVersions.Free;
|
||||||
exit(true);
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDubLocalPackage.addVersion(const value: string);
|
||||||
|
var
|
||||||
|
v: PSemVer;
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
v := new(PSemVer);
|
||||||
|
if value = 'vmaster' then
|
||||||
|
v^.init('v0.0.0-master')
|
||||||
|
else try
|
||||||
|
v^.init(value);
|
||||||
|
except
|
||||||
|
dispose(v);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
for i := 0 to fVersions.Count-1 do
|
||||||
|
begin
|
||||||
|
if fVersions[i]^ = v^ then
|
||||||
|
exit;
|
||||||
|
if (i < fVersions.Count-1) and (fVersions[i+1]^ > v^) and (fVersions[i]^ < v^ ) then
|
||||||
|
begin
|
||||||
|
fVersions.Insert(i, v);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
fVersions.Add(v);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDubLocalPackage.highest: PSemVer;
|
||||||
|
begin
|
||||||
|
result := fVersions.Last;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDubLocalPackage.highestInInterval(constref lo, hi: TSemVer): PSemVer;
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
result := nil;
|
||||||
|
for i := 0 to fVersions.Count-1 do
|
||||||
|
begin
|
||||||
|
if fVersions[i]^ < lo then
|
||||||
|
continue;
|
||||||
|
if fVersions[i]^ < hi then
|
||||||
|
result := fVersions[i];
|
||||||
|
if (fVersions[i]^ > hi) then
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDubLocalPackage.findVersion(constref value: TSemVer): PSemVer;
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
result := nil;
|
||||||
|
for i:= 0 to fVersions.Count-1 do
|
||||||
|
if fVersions.Items[i]^ = value then
|
||||||
|
exit(fVersions.Items[i]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TDubLocalPackages.destroy;
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
for i:= 0 to high(fLocalPackages) do
|
||||||
|
fLocalPackages[i].Free;
|
||||||
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDubLocalPackages.update;
|
procedure TDubLocalPackages.update;
|
||||||
|
@ -291,6 +354,7 @@ begin
|
||||||
if not find(n, d) then
|
if not find(n, d) then
|
||||||
begin
|
begin
|
||||||
setLength(fLocalPackages, length(fLocalPackages) + 1);
|
setLength(fLocalPackages, length(fLocalPackages) + 1);
|
||||||
|
fLocalPackages[high(fLocalPackages)] := TDubLocalPackage.create;
|
||||||
d := @fLocalPackages[high(fLocalPackages)];
|
d := @fLocalPackages[high(fLocalPackages)];
|
||||||
d^.name := n;
|
d^.name := n;
|
||||||
end;
|
end;
|
||||||
|
@ -318,6 +382,54 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDubLocalPackages.find(const name, op: string; constref opVer: TSemVer;
|
||||||
|
out package: PDubLocalPackage): PSemVer;
|
||||||
|
var
|
||||||
|
hi: TSemVer;
|
||||||
|
begin
|
||||||
|
result := nil;
|
||||||
|
if op = '=' then
|
||||||
|
begin
|
||||||
|
if find(name, package) then
|
||||||
|
result := package^.findVersion(opVer);
|
||||||
|
end
|
||||||
|
else if op = '>=' then
|
||||||
|
begin
|
||||||
|
if find(name, package) then
|
||||||
|
begin
|
||||||
|
result := package^.highest;
|
||||||
|
if result^ < opVer then
|
||||||
|
result := nil;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else if op = '>' then
|
||||||
|
begin
|
||||||
|
if find(name, package) then
|
||||||
|
begin
|
||||||
|
result := package^.highest;
|
||||||
|
if (result^ < opVer) or (result^ = opVer) then
|
||||||
|
result := nil;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else if op = '~>' then
|
||||||
|
begin
|
||||||
|
if find(name, package) then
|
||||||
|
begin
|
||||||
|
hi := opVer;
|
||||||
|
hi.minor := hi.minor + 1;
|
||||||
|
hi.patch := 0;
|
||||||
|
hi.additional :='';
|
||||||
|
result := package^.highestInInterval(opVer, hi);
|
||||||
|
result := result;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if find(name, package) then
|
||||||
|
result := package^.highest;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TDubLocalPackages.fetch(constref version: TSemVer): PDubLocalPackage;
|
function TDubLocalPackages.fetch(constref version: TSemVer): PDubLocalPackage;
|
||||||
begin
|
begin
|
||||||
result := nil;
|
result := nil;
|
||||||
|
@ -325,9 +437,8 @@ end;
|
||||||
|
|
||||||
function TDubLocalPackages.getPackageePath(package: PDubLocalPackage): string;
|
function TDubLocalPackages.getPackageePath(package: PDubLocalPackage): string;
|
||||||
begin
|
begin
|
||||||
result := fRoot + package^.name;
|
result := fRoot + package^.Name;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{$ENDREGION}
|
{$ENDREGION}
|
||||||
|
|
||||||
{$REGION Options ---------------------------------------------------------------}
|
{$REGION Options ---------------------------------------------------------------}
|
||||||
|
@ -1173,6 +1284,7 @@ procedure TCEDubProject.updateImportPathsFromJson;
|
||||||
z: string;
|
z: string;
|
||||||
r: TStringRange = (ptr: nil; pos: 0; len: 0);
|
r: TStringRange = (ptr: nil; pos: 0; len: 0);
|
||||||
q: TSemVer;
|
q: TSemVer;
|
||||||
|
u: PSemVer;
|
||||||
i: integer;
|
i: integer;
|
||||||
begin
|
begin
|
||||||
if obj.findObject('dependencies', deps) then
|
if obj.findObject('dependencies', deps) then
|
||||||
|
@ -1201,10 +1313,10 @@ procedure TCEDubProject.updateImportPathsFromJson;
|
||||||
else
|
else
|
||||||
q.init('v' + p);
|
q.init('v' + p);
|
||||||
|
|
||||||
if fLocalPackages.find(n, pck) and
|
u := fLocalPackages.find(n, o, q, pck);
|
||||||
pck^.findVersion(q) then
|
if assigned(u) then
|
||||||
begin
|
begin
|
||||||
p := s + '-' + p + DirectorySeparator + n + DirectorySeparator;
|
p := s + '-' + u^.asString + DirectorySeparator + n + DirectorySeparator;
|
||||||
if (p + 'source').dirExists then
|
if (p + 'source').dirExists then
|
||||||
fImportPaths.Add(p + 'source')
|
fImportPaths.Add(p + 'source')
|
||||||
else if (p + 'src').dirExists then
|
else if (p + 'src').dirExists then
|
||||||
|
|
|
@ -31,14 +31,17 @@ type
|
||||||
// Indicates wether the version is a release candidate ("v1.0.0-rc", "v1.0.0-rc.1").
|
// Indicates wether the version is a release candidate ("v1.0.0-rc", "v1.0.0-rc.1").
|
||||||
function isRc: boolean;
|
function isRc: boolean;
|
||||||
|
|
||||||
|
// Rebuild and Returns the SemVer string.
|
||||||
|
function asString: string;
|
||||||
|
|
||||||
// The major version.
|
// The major version.
|
||||||
property major: word read fMajor;
|
property major: word read fMajor write fMajor;
|
||||||
// The minor version.
|
// The minor version.
|
||||||
property minor: word read fMinor;
|
property minor: word read fMinor write fMinor;
|
||||||
// The patch.
|
// The patch.
|
||||||
property patch: word read fPatch;
|
property patch: word read fPatch write fPatch;
|
||||||
// The additional labels.
|
// The additional labels.
|
||||||
property additional: string read fAdditional;
|
property additional: string read fAdditional write fAdditional;
|
||||||
// Indicates if the init has succeeded.
|
// Indicates if the init has succeeded.
|
||||||
property valid: boolean read fValid;
|
property valid: boolean read fValid;
|
||||||
end;
|
end;
|
||||||
|
@ -46,6 +49,7 @@ type
|
||||||
PSemVer = ^TSemVer;
|
PSemVer = ^TSemVer;
|
||||||
|
|
||||||
operator > (constref lhs, rhs: TSemVer): boolean;
|
operator > (constref lhs, rhs: TSemVer): boolean;
|
||||||
|
operator < (constref lhs, rhs: TSemVer): boolean;
|
||||||
operator = (constref lhs, rhs: TSemVer): boolean;
|
operator = (constref lhs, rhs: TSemVer): boolean;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
@ -56,12 +60,18 @@ var v1, v2: TSemVer;
|
||||||
|
|
||||||
procedure TSemVer.init(const text: string; throw: boolean = true);
|
procedure TSemVer.init(const text: string; throw: boolean = true);
|
||||||
|
|
||||||
procedure error(const message: string);
|
procedure resetFields();
|
||||||
begin
|
begin
|
||||||
fMajor := 0;
|
fMajor := 0;
|
||||||
fMinor := 0;
|
fMinor := 0;
|
||||||
fPatch := 0;
|
fPatch := 0;
|
||||||
fAdditional := '';
|
fAdditional := '';
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure error(const message: string);
|
||||||
|
begin
|
||||||
|
resetFields();
|
||||||
|
fAdditional := '';
|
||||||
fValid := false;
|
fValid := false;
|
||||||
raise Exception.Create(message);
|
raise Exception.Create(message);
|
||||||
end;
|
end;
|
||||||
|
@ -69,6 +79,7 @@ procedure TSemVer.init(const text: string; throw: boolean = true);
|
||||||
var
|
var
|
||||||
r: TStringRange = (ptr:nil; pos:0; len: 0);
|
r: TStringRange = (ptr:nil; pos:0; len: 0);
|
||||||
begin
|
begin
|
||||||
|
resetFields();
|
||||||
if throw and (text.length < 6) then
|
if throw and (text.length < 6) then
|
||||||
error('Invalid semVer format, at least 6 characters expected');
|
error('Invalid semVer format, at least 6 characters expected');
|
||||||
r.init(text);
|
r.init(text);
|
||||||
|
@ -107,6 +118,13 @@ begin
|
||||||
result := (additional = 'rc') or (additional.StartsWith('rc.'));
|
result := (additional = 'rc') or (additional.StartsWith('rc.'));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TSemVer.asString: string;
|
||||||
|
begin
|
||||||
|
result := format('%d.%d.%d', [fMajor, fMinor, fPatch]);
|
||||||
|
if fAdditional <> '' then
|
||||||
|
result += '-' + fAdditional;
|
||||||
|
end;
|
||||||
|
|
||||||
operator > (constref lhs, rhs: TSemVer): boolean;
|
operator > (constref lhs, rhs: TSemVer): boolean;
|
||||||
begin
|
begin
|
||||||
result := (lhs.major > rhs.major) or
|
result := (lhs.major > rhs.major) or
|
||||||
|
@ -117,6 +135,11 @@ begin
|
||||||
and (lhs.patch = rhs.patch) and (lhs.additional > rhs.additional));
|
and (lhs.patch = rhs.patch) and (lhs.additional > rhs.additional));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
operator < (constref lhs, rhs: TSemVer): boolean;
|
||||||
|
begin
|
||||||
|
result := rhs > lhs;
|
||||||
|
end;
|
||||||
|
|
||||||
operator = (constref lhs, rhs: TSemVer): boolean;
|
operator = (constref lhs, rhs: TSemVer): boolean;
|
||||||
begin
|
begin
|
||||||
result := (lhs.major = rhs.major) and (lhs.minor = rhs.minor)
|
result := (lhs.major = rhs.major) and (lhs.minor = rhs.minor)
|
||||||
|
@ -133,24 +156,29 @@ begin
|
||||||
v1.init('v2.0.0');
|
v1.init('v2.0.0');
|
||||||
v2.init('v1.0.0');
|
v2.init('v1.0.0');
|
||||||
assert(v1 > v2);
|
assert(v1 > v2);
|
||||||
|
assert(v2 < v1);
|
||||||
|
|
||||||
v1.init('v1.1.0');
|
v1.init('v1.1.0');
|
||||||
v2.init('v1.0.0');
|
v2.init('v1.0.0');
|
||||||
assert(v1 > v2);
|
assert(v1 > v2);
|
||||||
|
assert(v2 < v1);
|
||||||
|
|
||||||
v1.init('v1.1.1');
|
v1.init('v1.1.1');
|
||||||
v2.init('v1.1.0');
|
v2.init('v1.1.0');
|
||||||
assert(v1 > v2);
|
assert(v1 > v2);
|
||||||
|
assert(v2 < v1);
|
||||||
|
|
||||||
v1.init('v1.1.1');
|
v1.init('v1.1.1');
|
||||||
v2.init('v1.0.1');
|
v2.init('v1.0.1');
|
||||||
assert(v1 > v2);
|
assert(v1 > v2);
|
||||||
|
assert(v2 < v1);
|
||||||
|
|
||||||
v1.init('v1.1.1-alpha.2');
|
v1.init('v1.1.1-alpha.2');
|
||||||
v2.init('v1.1.1-alpha.1');
|
v2.init('v1.1.1-alpha.1');
|
||||||
assert(v1 > v2);
|
assert(v1 > v2);
|
||||||
assert(v1.isAlpha);
|
assert(v1.isAlpha);
|
||||||
assert(v2.isAlpha);
|
assert(v2.isAlpha);
|
||||||
|
assert(v2.asString = '1.1.1-alpha.1');
|
||||||
|
|
||||||
v1.init('v1.1.1-beta.1');
|
v1.init('v1.1.1-beta.1');
|
||||||
v2.init('v1.1.1-alpha.8');
|
v2.init('v1.1.1-alpha.8');
|
||||||
|
@ -167,6 +195,7 @@ begin
|
||||||
assert(v2.major = 1);
|
assert(v2.major = 1);
|
||||||
assert(v2.minor = 22);
|
assert(v2.minor = 22);
|
||||||
assert(v2.patch = 33);
|
assert(v2.patch = 33);
|
||||||
|
assert(v2.asString = '1.22.33');
|
||||||
|
|
||||||
v1.init('v0.0.2060');
|
v1.init('v0.0.2060');
|
||||||
assert(v1.major = 0);
|
assert(v1.major = 0);
|
||||||
|
|
Loading…
Reference in New Issue