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