From b99aed83c762247813b041d1469d639850530b9c Mon Sep 17 00:00:00 2001 From: Norayr Chilingarian Date: Mon, 6 Apr 2026 18:21:36 +0400 Subject: [PATCH] now works with new vipatsar with json files in subdirs. also version is taken from json file name, not from json field. --- src/vpkInstaller.Mod | 17 +- src/vpkJsonDepRetriever.Mod | 325 ++++++++++++++++++++++++------------ src/vpkLocalBuilder.Mod | 14 +- src/vpkResolver.Mod | 64 +++++-- src/vpkStorage.Mod | 219 ++++++++++++++++++++++-- src/vpkdepTree.Mod | 183 +++++++++++--------- 6 files changed, 592 insertions(+), 230 deletions(-) diff --git a/src/vpkInstaller.Mod b/src/vpkInstaller.Mod index 6b6ada9..1572ab5 100644 --- a/src/vpkInstaller.Mod +++ b/src/vpkInstaller.Mod @@ -1,5 +1,5 @@ MODULE vpkInstaller; -IMPORT In, Out, Platform, +IMPORT In, Out, Platform, Strings, List, StringList, vpkResolver, vpkdepTree, vpkDot, vpkEnv, vpkJsonDepRetriever,vpkSyncer, vpkTools, vpkSettings; @@ -76,9 +76,9 @@ VAR keys, values: StringList.TStringList; k, v: StringList.pstring; b: BOOLEAN; - builddir, cmd, srcPath: StringList.pstring; + builddir, cmd, srcPath, fullCmd: StringList.pstring; res: INTEGER; - repoPath: ARRAY 256 OF CHAR; (* Changed from domain to repoPath *) + repoPath: ARRAY 256 OF CHAR; node: List.Node; BEGIN IF prefix # "" THEN @@ -136,11 +136,12 @@ BEGIN cmd := vpkEnv.mkCmd(k^, srcPath^); Out.String("Command: "); Out.String(cmd^); Out.Ln; Out.String("Building in "); Out.String(builddir^); Out.Ln; - res := Platform.Chdir(builddir^); - IF res # 0 THEN - Out.String("Failed to change directory to "); Out.String(builddir^); Out.Ln; Out.String("This should never happen."); Out.Ln; HALT(66); - END; - res := Platform.System(cmd^); + NEW(fullCmd, Strings.Length(builddir^) + Strings.Length(cmd^) + 8); + COPY("cd ", fullCmd^); + Strings.Append(builddir^, fullCmd^); + Strings.Append(" && ", fullCmd^); + Strings.Append(cmd^, fullCmd^); + res := Platform.System(fullCmd^); IF res # 0 THEN Out.String("Failed to run build command"); Out.Ln END; INC(j) UNTIL j = keys.Count; diff --git a/src/vpkJsonDepRetriever.Mod b/src/vpkJsonDepRetriever.Mod index fbc724f..396c274 100644 --- a/src/vpkJsonDepRetriever.Mod +++ b/src/vpkJsonDepRetriever.Mod @@ -25,36 +25,70 @@ PROCEDURE getBuildInfo*(VAR d: vpkdepTree.Tdep; VAR k, v: StringList.TStringList VAR jsonstr, errstr: strUtils.pstring; tree, buildValue, command, file: Json.Value; - rootObj, buildStep: Json.Obj; + rootObj, buildStep, rootObjTmp, buildStepTmp: Json.Obj; buildArray: Json.Arr; - cm, fl, bl, cmLower, flLower: Json.jString; - b: BOOLEAN; + cm, fl, bl, cmLower, flLower, blLower: Json.jString; BEGIN k := NIL; v := NIL; - b := FALSE; jsonstr := NIL; - vpkStorage.json2pstring(d.name^, jsonstr); + vpkStorage.json2pstring(d.name^, d.version, jsonstr); IF jsonstr # NIL THEN NEW(errstr, ErrmessSize); - b := Json.Parse(tree, jsonstr^, errstr^); - IF b THEN + IF Json.Parse(tree, jsonstr^, errstr^) THEN IF tree IS Json.Obj THEN rootObj := tree(Json.Obj); - NEW(bl, Strings.Length(vpkSettings.bldType) + 1); (* +1 for 0X *) + NEW(bl, Strings.Length(vpkSettings.bldType) + 1); + NEW(blLower, Strings.Length(vpkSettings.bldType) + 1); COPY(vpkSettings.bldType, bl^); - IF Json.ObjSelect(buildValue, rootObj, bl) THEN - IF buildValue IS Json.Arr THEN - buildArray := buildValue(Json.Arr); - WHILE buildArray # NIL DO + COPY(vpkSettings.bldType, blLower^); + ToLower(blLower^); + + rootObjTmp := rootObj; + IF ~Json.ObjSelect(buildValue, rootObjTmp, bl) THEN + rootObjTmp := rootObj; + IF ~Json.ObjSelect(buildValue, rootObjTmp, blLower) THEN + Out.String("Build section not found."); Out.Ln; + RETURN FALSE + END; + END; + + IF buildValue IS Json.Arr THEN + buildArray := buildValue(Json.Arr); + WHILE buildArray # NIL DO + IF buildArray.value IS Json.Obj THEN buildStep := buildArray.value(Json.Obj); - NEW(cm, Strings.Length(vpkSettings.bldCommand) + 1); (* +1 for 0X *) - NEW(fl, Strings.Length(vpkSettings.bldFile) + 1); (* +1 for 0X *) + NEW(cm, Strings.Length(vpkSettings.bldCommand) + 1); + NEW(fl, Strings.Length(vpkSettings.bldFile) + 1); COPY(vpkSettings.bldCommand, cm^); COPY(vpkSettings.bldFile, fl^); - IF (d^.Type = vpkSettings.https) OR (d^.Type = vpkSettings.http) THEN - (* Handle HTTPS build steps *) - IF Json.ObjSelect(command, buildStep, cm) & Json.ObjSelect(file, buildStep, fl) THEN - IF (command IS Json.Str) & (file IS Json.Str) THEN + NEW(cmLower, Strings.Length(cm^) + 1); + NEW(flLower, Strings.Length(fl^) + 1); + COPY(cm^, cmLower^); + COPY(fl^, flLower^); + ToLower(cmLower^); + ToLower(flLower^); + + buildStepTmp := buildStep; + IF ~Json.ObjSelect(command, buildStepTmp, cm) THEN + buildStepTmp := buildStep; + IF ~Json.ObjSelect(command, buildStepTmp, cmLower) THEN + Out.String("Failed to select 'command' from build step"); Out.Ln; + ELSE + buildStepTmp := buildStep; + IF ~Json.ObjSelect(file, buildStepTmp, fl) THEN + buildStepTmp := buildStep; + IF ~Json.ObjSelect(file, buildStepTmp, flLower) THEN + Out.String("Failed to select 'file' from build step"); Out.Ln; + ELSIF (command IS Json.Str) & (file IS Json.Str) THEN + IF k = NIL THEN k := StringList.Create() END; + IF v = NIL THEN v := StringList.Create() END; + k.AppendString(k, command(Json.Str).str^); + v.AppendString(v, file(Json.Str).str^); + ELSE + Out.String("command and file must be strings"); Out.Ln; + HALT(5); + END; + ELSIF (command IS Json.Str) & (file IS Json.Str) THEN IF k = NIL THEN k := StringList.Create() END; IF v = NIL THEN v := StringList.Create() END; k.AppendString(k, command(Json.Str).str^); @@ -63,19 +97,14 @@ BEGIN Out.String("command and file must be strings"); Out.Ln; HALT(5); END; - ELSE - Out.String("Failed to select 'command' or 'file' from build step"); Out.Ln; END; - ELSIF d^.Type = vpkSettings.git THEN - (* Handle Git build steps *) - NEW(cmLower, Strings.Length(cm^) + 1); - NEW(flLower, Strings.Length(fl^) + 1); - COPY(cm^, cmLower^); - COPY(fl^, flLower^); - ToLower(cmLower^); - ToLower(flLower^); - IF Json.ObjSelect(command, buildStep, cmLower) & Json.ObjSelect(file, buildStep, flLower) THEN - IF (command IS Json.Str) & (file IS Json.Str) THEN + ELSE + buildStepTmp := buildStep; + IF ~Json.ObjSelect(file, buildStepTmp, fl) THEN + buildStepTmp := buildStep; + IF ~Json.ObjSelect(file, buildStepTmp, flLower) THEN + Out.String("Failed to select 'file' from build step"); Out.Ln; + ELSIF (command IS Json.Str) & (file IS Json.Str) THEN IF k = NIL THEN k := StringList.Create() END; IF v = NIL THEN v := StringList.Create() END; k.AppendString(k, command(Json.Str).str^); @@ -84,17 +113,21 @@ BEGIN Out.String("command and file must be strings"); Out.Ln; HALT(5); END; + ELSIF (command IS Json.Str) & (file IS Json.Str) THEN + IF k = NIL THEN k := StringList.Create() END; + IF v = NIL THEN v := StringList.Create() END; + k.AppendString(k, command(Json.Str).str^); + v.AppendString(v, file(Json.Str).str^); ELSE - Out.String("Failed to select 'command' or 'file' from build step"); Out.Ln; + Out.String("command and file must be strings"); Out.Ln; + HALT(5); END; END; - buildArray := buildArray.next; END; - ELSE - Out.String("Build section is not an array."); Out.Ln; + buildArray := buildArray.next; END; ELSE - Out.String("Build section not found."); Out.Ln; + Out.String("Build section is not an array."); Out.Ln; END; ELSE Out.String("JSON root is not an object."); Out.Ln; @@ -105,7 +138,7 @@ BEGIN ELSE Out.String("No JSON string provided."); Out.Ln; END; - RETURN b; + RETURN (k # NIL) & (v # NIL) & (k.Count > 0); END getBuildInfo; (*PROCEDURE fetchHttpsFiles(someObj: Json.Obj; VAR httpsRemote: vpkdepTree.RemoteHttps);*) @@ -227,7 +260,7 @@ VAR gitRemote: vpkdepTree.RemoteGit; BEGIN jsonstr := NIL; - vpkStorage.json2pstring(d.name^, jsonstr); + vpkStorage.json2pstring(d.name^, d.version, jsonstr); IF jsonstr # NIL THEN NEW(errstr, ErrmessSize); b := Json.Parse(tree, jsonstr^, errstr^); @@ -346,6 +379,7 @@ END getURIandType; PROCEDURE getDeps*(VAR d: vpkdepTree.Tdep; VAR depstrlist: StringList.TStringList): LONGINT; VAR jsonstr, errstr: strUtils.pstring; + keyLower, depKeyLower: strUtils.pstring; tree, depsValue, singleDep: Json.Value; rootObj, depObj: Json.Obj; depName, depVersion: Json.jString; @@ -353,7 +387,7 @@ VAR BEGIN depstrlist := NIL; jsonstr := NIL; - vpkStorage.json2pstring(d.name^, jsonstr); + vpkStorage.json2pstring(d.name^, d.version, jsonstr); IF jsonstr # NIL THEN NEW(errstr, ErrmessSize); IF Json.Parse(tree, jsonstr^, errstr^) THEN @@ -362,7 +396,16 @@ BEGIN (* searching for dependencies section *) foundDepSection := FALSE; REPEAT - IF rootObj.name^ = vpkSettings.depTypKey THEN + (*IF rootObj.name^ = vpkSettings.depTypKey THEN*) + NEW(keyLower, LEN(rootObj.name^) + 1); + COPY(rootObj.name^, keyLower^); + ToLower(keyLower^); + + NEW(depKeyLower, LEN(vpkSettings.depTypKey) + 1); + COPY(vpkSettings.depTypKey, depKeyLower^); + ToLower(depKeyLower^); + + IF keyLower^ = depKeyLower^ THEN foundDepSection := TRUE; END; IF ~foundDepSection THEN rootObj := rootObj.next END @@ -379,7 +422,19 @@ BEGIN depName := depObj.name; depVersion := depObj.value(Json.Str).str; IF depstrlist = NIL THEN depstrlist := StringList.Create() END; - depstrlist.AppendString(depstrlist, depName^); + IF depVersion # NIL THEN + IF depVersion^ # "" THEN + NEW(errstr, Strings.Length(depName^) + Strings.Length(depVersion^) + 2); + COPY(depName^, errstr^); + Strings.Append(":", errstr^); + Strings.Append(depVersion^, errstr^); + depstrlist.AppendString(depstrlist, errstr^); + ELSE + depstrlist.AppendString(depstrlist, depName^); + END; + ELSE + depstrlist.AppendString(depstrlist, depName^); + END; singleDep := depObj.next; (* Move to the next dependency *) END; END; (* End of inner WHILE loop for dependencies *) @@ -411,102 +466,109 @@ PROCEDURE getBuildInfoFromFile*(VAR d: vpkdepTree.Tdep; VAR k, v: StringList.TSt VAR jsonstr, errstr: strUtils.pstring; tree, buildValue, command, file: Json.Value; - rootObj, buildStep: Json.Obj; + rootObj, buildStep, rootObjTmp, buildStepTmp: Json.Obj; buildArray: Json.Arr; - cm, fl, bl: Json.jString; - b: BOOLEAN; + cm, fl, bl, cmLower, flLower, blLower: Json.jString; BEGIN k := NIL; v := NIL; - b := FALSE; jsonstr := NIL; - (* - Out.String("DEBUG: Reading file: "); Out.String(filename); Out.Ln; - *) - - (* Read from specified file instead of package tree *) vpkStorage.fileToString(filename, jsonstr); IF jsonstr # NIL THEN - (* - Out.String("DEBUG: JSON string loaded, length: "); Out.Int(LEN(jsonstr^), 0); Out.Ln; - *) NEW(errstr, ErrmessSize); - b := Json.Parse(tree, jsonstr^, errstr^); - IF b THEN - (* - Out.String("DEBUG: JSON parsed successfully"); Out.Ln; - *) + IF Json.Parse(tree, jsonstr^, errstr^) THEN IF tree IS Json.Obj THEN - (* - Out.String("DEBUG: Root is object"); Out.Ln; - *) rootObj := tree(Json.Obj); NEW(bl, Strings.Length(vpkSettings.bldType) + 1); + NEW(blLower, Strings.Length(vpkSettings.bldType) + 1); COPY(vpkSettings.bldType, bl^); - (* - Out.String("DEBUG: Looking for build key: "); Out.String(bl^); Out.Ln; - *) - IF Json.ObjSelect(buildValue, rootObj, bl) THEN - (* - Out.String("DEBUG: Found Build section"); Out.Ln; - *) - IF buildValue IS Json.Arr THEN - (* - Out.String("DEBUG: Build section is array"); Out.Ln; - *) - buildArray := buildValue(Json.Arr); - WHILE buildArray # NIL DO - (* - Out.String("DEBUG: Processing build array element"); Out.Ln; - *) - IF buildArray.value IS Json.Obj THEN - (* - Out.String("DEBUG: Build array element is object"); Out.Ln; - *) - buildStep := buildArray.value(Json.Obj); - NEW(cm, Strings.Length(vpkSettings.bldCommand) + 1); - NEW(fl, Strings.Length(vpkSettings.bldFile) + 1); - COPY(vpkSettings.bldCommand, cm^); - COPY(vpkSettings.bldFile, fl^); - (* - Out.String("DEBUG: Looking for command key: "); Out.String(cm^); Out.Ln; - Out.String("DEBUG: Looking for file key: "); Out.String(fl^); Out.Ln; - *) + COPY(vpkSettings.bldType, blLower^); + ToLower(blLower^); - (* Simple approach - just try to get command and file directly *) - IF Json.ObjSelect(command, buildStep, cm) & Json.ObjSelect(file, buildStep, fl) THEN - (* - Out.String("DEBUG: Found both command and file keys"); Out.Ln; - *) - IF (command IS Json.Str) & (file IS Json.Str) THEN - (* - Out.String("DEBUG: Both are strings"); Out.Ln; - *) + rootObjTmp := rootObj; + IF ~Json.ObjSelect(buildValue, rootObjTmp, bl) THEN + rootObjTmp := rootObj; + IF ~Json.ObjSelect(buildValue, rootObjTmp, blLower) THEN + Out.String("Build section not found."); Out.Ln; + RETURN FALSE + END; + END; + + IF buildValue IS Json.Arr THEN + buildArray := buildValue(Json.Arr); + WHILE buildArray # NIL DO + IF buildArray.value IS Json.Obj THEN + buildStep := buildArray.value(Json.Obj); + NEW(cm, Strings.Length(vpkSettings.bldCommand) + 1); + NEW(fl, Strings.Length(vpkSettings.bldFile) + 1); + NEW(cmLower, Strings.Length(vpkSettings.bldCommand) + 1); + NEW(flLower, Strings.Length(vpkSettings.bldFile) + 1); + COPY(vpkSettings.bldCommand, cm^); + COPY(vpkSettings.bldFile, fl^); + COPY(vpkSettings.bldCommand, cmLower^); + COPY(vpkSettings.bldFile, flLower^); + ToLower(cmLower^); + ToLower(flLower^); + + buildStepTmp := buildStep; + IF ~Json.ObjSelect(command, buildStepTmp, cm) THEN + buildStepTmp := buildStep; + IF ~Json.ObjSelect(command, buildStepTmp, cmLower) THEN + Out.String("DEBUG: Failed to select 'command' from build step"); Out.Ln; + ELSE + buildStepTmp := buildStep; + IF ~Json.ObjSelect(file, buildStepTmp, fl) THEN + buildStepTmp := buildStep; + IF ~Json.ObjSelect(file, buildStepTmp, flLower) THEN + Out.String("DEBUG: Failed to select 'file' from build step"); Out.Ln; + ELSIF (command IS Json.Str) & (file IS Json.Str) THEN + IF k = NIL THEN k := StringList.Create() END; + IF v = NIL THEN v := StringList.Create() END; + k.AppendString(k, command(Json.Str).str^); + v.AppendString(v, file(Json.Str).str^); + Out.String("Found build step: "); Out.String(command(Json.Str).str^); + Out.String(" "); Out.String(file(Json.Str).str^); Out.Ln; + END; + ELSIF (command IS Json.Str) & (file IS Json.Str) THEN IF k = NIL THEN k := StringList.Create() END; IF v = NIL THEN v := StringList.Create() END; k.AppendString(k, command(Json.Str).str^); v.AppendString(v, file(Json.Str).str^); Out.String("Found build step: "); Out.String(command(Json.Str).str^); Out.String(" "); Out.String(file(Json.Str).str^); Out.Ln; - ELSE - (* - Out.String("DEBUG: command and file must be strings"); Out.Ln; - *) END; - ELSE - Out.String("DEBUG: Failed to select 'command' or 'file' from build step"); Out.Ln; END; ELSE - Out.String("DEBUG: Build array element is not an object"); Out.Ln; + buildStepTmp := buildStep; + IF ~Json.ObjSelect(file, buildStepTmp, fl) THEN + buildStepTmp := buildStep; + IF ~Json.ObjSelect(file, buildStepTmp, flLower) THEN + Out.String("DEBUG: Failed to select 'file' from build step"); Out.Ln; + ELSIF (command IS Json.Str) & (file IS Json.Str) THEN + IF k = NIL THEN k := StringList.Create() END; + IF v = NIL THEN v := StringList.Create() END; + k.AppendString(k, command(Json.Str).str^); + v.AppendString(v, file(Json.Str).str^); + Out.String("Found build step: "); Out.String(command(Json.Str).str^); + Out.String(" "); Out.String(file(Json.Str).str^); Out.Ln; + END; + ELSIF (command IS Json.Str) & (file IS Json.Str) THEN + IF k = NIL THEN k := StringList.Create() END; + IF v = NIL THEN v := StringList.Create() END; + k.AppendString(k, command(Json.Str).str^); + v.AppendString(v, file(Json.Str).str^); + Out.String("Found build step: "); Out.String(command(Json.Str).str^); + Out.String(" "); Out.String(file(Json.Str).str^); Out.Ln; + END; END; - buildArray := buildArray.next; + ELSE + Out.String("DEBUG: Build array element is not an object"); Out.Ln; END; - ELSE - Out.String("Build section is not an array."); Out.Ln; + buildArray := buildArray.next; END; ELSE - Out.String("Build section not found."); Out.Ln; + Out.String("Build section is not an array."); Out.Ln; END; ELSE Out.String("JSON root is not an object."); Out.Ln; @@ -523,6 +585,8 @@ END getBuildInfoFromFile; PROCEDURE getDepsFromFile*(VAR d: vpkdepTree.Tdep; VAR depstrlist: StringList.TStringList): LONGINT; VAR jsonstr, errstr: strUtils.pstring; + keyLower, depKeyLower: strUtils.pstring; + depWithVersion: strUtils.pstring; tree, depsValue, singleDep: Json.Value; rootObj, depObj: Json.Obj; depName, depVersion: Json.jString; @@ -548,7 +612,16 @@ BEGIN (* searching for dependencies section *) foundDepSection := FALSE; REPEAT - IF rootObj.name^ = vpkSettings.depTypKey THEN + (*IF rootObj.name^ = vpkSettings.depTypKey THEN*) + NEW(keyLower, LEN(rootObj.name^) + 1); + COPY(rootObj.name^, keyLower^); + ToLower(keyLower^); + + NEW(depKeyLower, LEN(vpkSettings.depTypKey) + 1); + COPY(vpkSettings.depTypKey, depKeyLower^); + ToLower(depKeyLower^); + + IF keyLower^ = depKeyLower^ THEN foundDepSection := TRUE; END; IF ~foundDepSection THEN rootObj := rootObj.next END @@ -565,7 +638,37 @@ BEGIN depName := depObj.name; depVersion := depObj.value(Json.Str).str; IF depstrlist = NIL THEN depstrlist := StringList.Create() END; - depstrlist.AppendString(depstrlist, depName^); + IF depVersion # NIL THEN + IF depVersion^ # "" THEN + NEW(errstr, Strings.Length(depName^) + Strings.Length(depVersion^) + 2); + COPY(depName^, errstr^); + Strings.Append(":", errstr^); + Strings.Append(depVersion^, errstr^); + depstrlist.AppendString(depstrlist, errstr^); + ELSE + (*depstrlist.AppendString(depstrlist, depName^);*) + IF depVersion # NIL THEN + NEW(depWithVersion, LEN(depName^) + LEN(depVersion^) + 2); + COPY(depName^, depWithVersion^); + Strings.Append(":", depWithVersion^); + Strings.Append(depVersion^, depWithVersion^); + depstrlist.AppendString(depstrlist, depWithVersion^); + ELSE + depstrlist.AppendString(depstrlist, depName^); + END; + END; + ELSE + (*depstrlist.AppendString(depstrlist, depName^);*) + IF depVersion # NIL THEN + NEW(depWithVersion, LEN(depName^) + LEN(depVersion^) + 2); + COPY(depName^, depWithVersion^); + Strings.Append(":", depWithVersion^); + Strings.Append(depVersion^, depWithVersion^); + depstrlist.AppendString(depstrlist, depWithVersion^); + ELSE + depstrlist.AppendString(depstrlist, depName^); + END; + END; singleDep := depObj.next; (* Move to the next dependency *) END; END; (* End of inner WHILE loop for dependencies *) diff --git a/src/vpkLocalBuilder.Mod b/src/vpkLocalBuilder.Mod index 6129ce8..dee872b 100644 --- a/src/vpkLocalBuilder.Mod +++ b/src/vpkLocalBuilder.Mod @@ -108,8 +108,6 @@ BEGIN Strings.Append(eol, content); Strings.Append(' "License": "GPL-3",', content); Strings.Append(eol, content); - Strings.Append(' "Version": "0.1",', content); - Strings.Append(eol, content); Strings.Append(' "Remote": {', content); Strings.Append(eol, content); Strings.Append(' "type": "git",', content); @@ -167,10 +165,10 @@ END fileExists; PROCEDURE parseProjectFile(VAR filename: ARRAY OF CHAR; VAR info: ProjectInfo): BOOLEAN; VAR jsonstr, errstr: strUtils.pstring; - tree, packageValue, authorValue, licenseValue, versionValue: Json.Value; + tree, packageValue, authorValue, licenseValue: Json.Value; depsValue, buildValue: Json.Value; rootObj: Json.Obj; - packageKey, authorKey, licenseKey, versionKey: Json.jString; + packageKey, authorKey, licenseKey: Json.jString; depsKey, buildKey: Json.jString; b: BOOLEAN; BEGIN @@ -214,12 +212,8 @@ BEGIN END; END; - (* Parse Version *) - NEW(versionKey, 8); COPY("Version", versionKey^); - IF Json.ObjSelect(versionValue, rootObj, versionKey) THEN - IF versionValue IS Json.Str THEN - COPY(versionValue(Json.Str).str^, info.version); - END; + IF ~vpkStorage.versionFromPackageFileName(filename, info.version) THEN + COPY("", info.version); END; (* Check for Dependencies *) diff --git a/src/vpkResolver.Mod b/src/vpkResolver.Mod index d197043..8b185fa 100644 --- a/src/vpkResolver.Mod +++ b/src/vpkResolver.Mod @@ -1,5 +1,5 @@ MODULE vpkResolver; -IMPORT Out, StringList, vpkdepTree; +IMPORT Out, Strings, StringList, vpkdepTree; TYPE pstr = StringList.pstring; @@ -10,6 +10,34 @@ TYPE VAR rtvr: vpkdepTree.retriever; +PROCEDURE SplitDepSpec(VAR spec, depName, depVersion: ARRAY OF CHAR); +VAR + i, l: INTEGER; +BEGIN + COPY("", depName); + COPY("", depVersion); + l := Strings.Length(spec); + i := 0; + WHILE (i < l) & (spec[i] # ':') DO + depName[i] := spec[i]; + INC(i); + END; + depName[i] := 0X; + IF i < l THEN + INC(i); + WHILE i <= l DO + depVersion[i - (Strings.Length(depName) + 1)] := spec[i]; + INC(i); + END; + END; +END SplitDepSpec; + +PROCEDURE sameDep(VAR d1, d2: Tdep): BOOLEAN; +BEGIN + IF (d1 = NIL) OR (d2 = NIL) THEN RETURN FALSE END; + RETURN (d1.name^ = d2.name^) & (d1.version = d2.version); +END sameDep; + PROCEDURE treeContains(VAR d: Tdep; VAR depTree: TdepTree): BOOLEAN; VAR res: BOOLEAN; @@ -21,8 +49,7 @@ BEGIN REPEAT d2 := depTree.Get(depTree, i); IF d2 # NIL THEN - IF d = d2 THEN res := TRUE END; - (*IF d.name^ = d2.name^ THEN res := TRUE END *) + IF sameDep(d, d2) THEN res := TRUE END; END; INC(i) UNTIL res OR (i >= depTree.Count); @@ -40,15 +67,13 @@ BEGIN REPEAT d2 := depTree.Get(depTree, i); IF d2 # NIL THEN - IF d.name^ = d2.name^ THEN res := TRUE END; - (*IF d.name^ = d2.name^ THEN res := TRUE END *) + IF sameDep(d, d2) THEN res := TRUE END; END; INC(i) UNTIL res OR (i >= depTree.Count); RETURN res; END treeContainsByName; - PROCEDURE mkDepTree(VAR d: Tdep; VAR depTree, met: TdepTree); VAR depStrs: StringList.TStringList; @@ -57,6 +82,7 @@ VAR p: pstr; i: INTEGER; rtrvRes: LONGINT; + depName, depVersion: ARRAY 128 OF CHAR; BEGIN vpkdepTree.Add(met, d); IF d.RetrieveDeps = NIL THEN Out.String("dep retriever method not installed"); Out.Ln; HALT(1) END; @@ -69,23 +95,31 @@ BEGIN HALT(62); END; IF depStrs # NIL THEN - (*IF rtrvRes > 0 THEN*) - NEW (deps, depStrs.Count); + NEW(deps, depStrs.Count); i := 0; REPEAT p := depStrs.GetString(depStrs, i); IF p # NIL THEN + SplitDepSpec(p^, depName, depVersion); t := NIL; - t := met.GetByName(met, p^); + t := met.GetByNameVersion(met, depName, depVersion); IF t = NIL THEN - t := vpkdepTree.CreateDep(p^); + IF depVersion = "" THEN + t := vpkdepTree.CreateDep(depName) + ELSE + t := vpkdepTree.CreateDepVersioned(depName, depVersion) + END; t.InstallRetriever(t, rtvr); END; deps[i] := t; IF ~treeContainsByName(t, depTree) THEN IF treeContainsByName(t, met) THEN Out.Ln; Out.String("curcular dependency: "); - Out.String(d.name^); Out.String(" requires "); Out.String(t.name^); Out.Ln; + Out.String(d.name^); + IF d.version # "" THEN Out.String(":"); Out.String(d.version) END; + Out.String(" requires "); Out.String(t.name^); + IF t.version # "" THEN Out.String(":"); Out.String(t.version) END; + Out.Ln; Out.String("unable to continue."); Out.Ln; HALT(60) ELSE @@ -105,11 +139,17 @@ VAR depTree: TdepTree; met: TdepTree; dep: Tdep; + depName, depVersion: ARRAY 128 OF CHAR; BEGIN rtvr := r; depTree := vpkdepTree.Create(); met := vpkdepTree.Create(); (* for deps that we already met *) - dep := vpkdepTree.CreateDep(first); + SplitDepSpec(first, depName, depVersion); + IF depVersion = "" THEN + dep := vpkdepTree.CreateDep(depName) + ELSE + dep := vpkdepTree.CreateDepVersioned(depName, depVersion) + END; dep.InstallRetriever(dep, rtvr); mkDepTree(dep, depTree, met); RETURN depTree diff --git a/src/vpkStorage.Mod b/src/vpkStorage.Mod index eb63747..caac03c 100644 --- a/src/vpkStorage.Mod +++ b/src/vpkStorage.Mod @@ -1,6 +1,6 @@ MODULE vpkStorage; IMPORT Files, Out, Strings, -strUtils, vpkLogger, vpkEnv, UnixFS; + strUtils, vpkLogger, vpkEnv, UnixFS; PROCEDURE WriteString(VAR r : Files.Rider; str : ARRAY OF CHAR); BEGIN @@ -18,26 +18,25 @@ BEGIN IF f # NIL THEN Files.Set(r, f, 0); i := Files.Length(f); - NEW(returnString, i); + NEW(returnString, i + 1); j := 0; REPEAT Files.Read(r, returnString^[j]); INC(j); UNTIL r.eof OR (j >= i); + returnString^[j] := 0X; ELSE Out.String("file "); Out.String(fileName); Out.String(" not found"); Out.Ln; END; - END fileToString; PROCEDURE stringToFile*(VAR fileName, content: ARRAY OF CHAR): BOOLEAN; VAR f: Files.File; r: Files.Rider; - i: LONGINT; BEGIN f := Files.New(fileName); @@ -59,17 +58,213 @@ BEGIN RETURN TRUE; END stringToFile; -PROCEDURE json2pstring*(VAR json: ARRAY OF CHAR; VAR pstr: strUtils.pstring); +PROCEDURE EndsWith(s: ARRAY OF CHAR; suffix: ARRAY OF CHAR): BOOLEAN; VAR - fi: UnixFS.fileInfo; + ls, lf, i: INTEGER; +BEGIN + ls := Strings.Length(s); + lf := Strings.Length(suffix); + IF lf > ls THEN RETURN FALSE END; + i := 0; + WHILE i < lf DO + IF s[ls - lf + i] # suffix[i] THEN RETURN FALSE END; + INC(i) + END; + RETURN TRUE +END EndsWith; + +PROCEDURE StripSuffix(s: ARRAY OF CHAR; suffix: ARRAY OF CHAR; VAR out: ARRAY OF CHAR): BOOLEAN; +VAR + ls, lf, i: INTEGER; +BEGIN + COPY("", out); + ls := Strings.Length(s); + lf := Strings.Length(suffix); + IF lf > ls THEN RETURN FALSE END; + i := 0; + WHILE i < lf DO + IF s[ls - lf + i] # suffix[i] THEN RETURN FALSE END; + INC(i) + END; + i := 0; + WHILE i < ls - lf DO + out[i] := s[i]; + INC(i) + END; + out[i] := 0X; + RETURN TRUE +END StripSuffix; + +PROCEDURE BaseName(path: ARRAY OF CHAR; VAR base: ARRAY OF CHAR); +VAR + i, start, j: INTEGER; +BEGIN + start := 0; + i := 0; + WHILE path[i] # 0X DO + IF path[i] = "/" THEN start := i + 1 END; + INC(i) + END; + j := 0; + i := start; + WHILE path[i] # 0X DO + base[j] := path[i]; + INC(i); INC(j) + END; + base[j] := 0X +END BaseName; + +PROCEDURE DirName(path: ARRAY OF CHAR; VAR dir: ARRAY OF CHAR); +VAR + i, lastSlash: INTEGER; +BEGIN + lastSlash := -1; + i := 0; + WHILE path[i] # 0X DO + IF path[i] = "/" THEN lastSlash := i END; + INC(i) + END; + IF lastSlash < 0 THEN + COPY("", dir) + ELSE + i := 0; + WHILE i < lastSlash DO + dir[i] := path[i]; + INC(i) + END; + dir[i] := 0X + END +END DirName; + +PROCEDURE LastPathComponent(path: ARRAY OF CHAR; VAR comp: ARRAY OF CHAR); +VAR + dir: ARRAY 512 OF CHAR; +BEGIN + DirName(path, dir); + BaseName(dir, comp) +END LastPathComponent; + +PROCEDURE ParseNat(s: ARRAY OF CHAR; VAR pos: INTEGER): INTEGER; +VAR n: INTEGER; +BEGIN + n := 0; + WHILE (s[pos] >= "0") & (s[pos] <= "9") DO + n := n * 10 + (ORD(s[pos]) - ORD("0")); + INC(pos) + END; + RETURN n +END ParseNat; + +PROCEDURE CompareVersions*(a, b: ARRAY OF CHAR): INTEGER; +VAR + ia, ib, va, vb: INTEGER; +BEGIN + ia := 0; ib := 0; + WHILE (a[ia] # 0X) OR (b[ib] # 0X) DO + va := 0; vb := 0; + IF (a[ia] >= "0") & (a[ia] <= "9") THEN va := ParseNat(a, ia) END; + IF (b[ib] >= "0") & (b[ib] <= "9") THEN vb := ParseNat(b, ib) END; + + IF va < vb THEN RETURN -1 END; + IF va > vb THEN RETURN 1 END; + + IF a[ia] = "." THEN INC(ia) END; + IF b[ib] = "." THEN INC(ib) END; + END; + RETURN 0 +END CompareVersions; + +PROCEDURE versionFromPackageFileName*(path: ARRAY OF CHAR; VAR version: ARRAY OF CHAR): BOOLEAN; +VAR + base, stem, pkg, prefix: ARRAY 512 OF CHAR; + i, lp, ls: INTEGER; + jsonSuffix: ARRAY 16 OF CHAR; +BEGIN + COPY(".json", jsonSuffix); + COPY("", version); + BaseName(path, base); + IF ~StripSuffix(base, jsonSuffix, stem) THEN RETURN FALSE END; + LastPathComponent(path, pkg); + + COPY(pkg, prefix); + Strings.Append("-", prefix); + lp := Strings.Length(prefix); + ls := Strings.Length(stem); + IF ls < lp THEN RETURN FALSE END; + + i := 0; + WHILE i < lp DO + IF stem[i] # prefix[i] THEN RETURN FALSE END; + INC(i) + END; + + i := 0; + WHILE stem[lp + i] # 0X DO + version[i] := stem[lp + i]; + INC(i) + END; + version[i] := 0X; + RETURN version # "" +END versionFromPackageFileName; + +PROCEDURE findPackageJsonPath*(pkgName, reqVersion: ARRAY OF CHAR; VAR path: ARRAY OF CHAR): BOOLEAN; +VAR + dirPath, fullPath, currentVersion, bestVersion: ARRAY 512 OF CHAR; + lst: UnixFS.list; + i: INTEGER; + found: BOOLEAN; + emptyVersion, jsonSuffix: ARRAY 16 OF CHAR; +BEGIN + COPY("", path); + COPY("", bestVersion); + COPY("", emptyVersion); + COPY(".json", jsonSuffix); + found := FALSE; + + vpkEnv.getTreeDir(dirPath); + Strings.Append("/", dirPath); + Strings.Append(pkgName, dirPath); + + IF ~UnixFS.ExistsByName(dirPath) THEN RETURN FALSE END; + + UnixFS.ListDir(dirPath, lst); + IF lst = NIL THEN RETURN FALSE END; + + i := 0; + WHILE i < LEN(lst^) DO + IF (lst^[i].name # ".") & (lst^[i].name # "..") THEN + IF EndsWith(lst^[i].name, jsonSuffix) THEN + COPY(dirPath, fullPath); + Strings.Append("/", fullPath); + Strings.Append(lst^[i].name, fullPath); + IF versionFromPackageFileName(fullPath, currentVersion) THEN + IF reqVersion # emptyVersion THEN + IF currentVersion = reqVersion THEN + COPY(fullPath, path); + RETURN TRUE + END + ELSE + IF ~found OR (CompareVersions(bestVersion, currentVersion) < 0) THEN + COPY(currentVersion, bestVersion); + COPY(fullPath, path); + found := TRUE + END + END + END + END + END; + INC(i) + END; + RETURN found +END findPackageJsonPath; + +PROCEDURE json2pstring*(pkgName, reqVersion: ARRAY OF CHAR; VAR pstr: strUtils.pstring); +VAR + path: ARRAY 512 OF CHAR; BEGIN pstr := NIL; - vpkEnv.getTreeDir(fi.name); - Strings.Append("/", fi.name); - Strings.Append(json, fi.name); - Strings.Append(".json", fi.name); - IF UnixFS.Exists(fi) THEN - fileToString(fi.name, pstr); + IF findPackageJsonPath(pkgName, reqVersion, path) THEN + fileToString(path, pstr) END END json2pstring; diff --git a/src/vpkdepTree.Mod b/src/vpkdepTree.Mod index ba0388d..b4a13cd 100644 --- a/src/vpkdepTree.Mod +++ b/src/vpkdepTree.Mod @@ -3,8 +3,6 @@ IMPORT Out, Strings, strUtils, List, StringList, vpkSettings; - - TYPE pstring = strUtils.pstring; @@ -24,6 +22,7 @@ TYPE Add* : PROCEDURE (VAR l : TdepTree; VAR s : Tdep); Get* : PROCEDURE (VAR l : TdepTree; i : LONGINT): Tdep; GetByName* : PROCEDURE (VAR l : TdepTree; VAR name : ARRAY OF CHAR): Tdep; + GetByNameVersion* : PROCEDURE (VAR l : TdepTree; VAR name, version : ARRAY OF CHAR): Tdep; Empty* : PROCEDURE (VAR l : TdepTree) : BOOLEAN; Count* : LONGINT; END; @@ -63,6 +62,7 @@ TYPE TdepDesc* = RECORD prev-, next-: Tdep; name- : pstring; + version* : ARRAY 64 OF CHAR; deps- : Tdeps; Create* : PROCEDURE (VAR name: ARRAY OF CHAR): Tdep; AssignDeps* : PROCEDURE (VAR d: Tdep; VAR deps: Tdeps); @@ -71,7 +71,7 @@ TYPE Type* : LONGINT; (* from vpkSettings: http, https, gemini, git... *) rmt* : Remote; - END; + END; PROCEDURE AssignDeps*(VAR d: Tdep; VAR deps: Tdeps); BEGIN @@ -90,13 +90,25 @@ BEGIN NEW(dep); NEW(dep.name, Strings.Length(name) + 1); COPY(name, dep.name^); + COPY("", dep.version); dep.AssignDeps := AssignDeps; dep.InstallRetriever := InstallRetriever; dep.RetrieveDeps := NIL; dep.rmt := NIL; + dep.Type := 0; + dep.Create := CreateDep; RETURN dep END CreateDep; +PROCEDURE CreateDepVersioned*(VAR name, version: ARRAY OF CHAR): Tdep; +VAR + dep: Tdep; +BEGIN + dep := CreateDep(name); + COPY(version, dep.version); + RETURN dep +END CreateDepVersioned; + PROCEDURE list(VAR s : StringList.TStringList); VAR e : StringList.Node; i : INTEGER; @@ -106,7 +118,6 @@ BEGIN REPEAT e := s.Get(s, i); IF e # NIL THEN Out.String (e.obj(StringList.TString).str^); Out.Ln END; - (*Out.String (e.string); Out.Ln;*) INC(i); UNTIL i = s.Count - 1; END list; @@ -117,61 +128,73 @@ VAR BEGIN l := 0; REPEAT - Out.Int(l, 0); Out.String(": "); Out.String(deps[l].name^); Out.Ln; + Out.Int(l, 0); Out.String(": "); Out.String(deps[l].name^); + IF deps[l].version # "" THEN + Out.String(":"); Out.String(deps[l].version); + END; + Out.Ln; INC(l); UNTIL l = LEN(deps^) - 1; END listDeps; PROCEDURE Free*(VAR l : TdepTree); - BEGIN - l := NIL - END Free; +BEGIN + l := NIL +END Free; PROCEDURE Clear*(VAR l : TdepTree); - BEGIN - l.First := NIL; - l.Count := 0; - END Clear; +BEGIN + l.First := NIL; + l.Last := NIL; + l.Count := 0; +END Clear; -PROCEDURE Empty* (VAR l : TdepTree) : BOOLEAN; - BEGIN - RETURN l.First = NIL - END Empty; +PROCEDURE Empty*(VAR l : TdepTree) : BOOLEAN; +BEGIN + RETURN l.First = NIL +END Empty; -PROCEDURE Add* (VAR l : TdepTree; VAR d: Tdep); - BEGIN - IF l.First = NIL THEN - l.First := d; - ELSE - l.Last.next := d; - END; - l.Last := d; - l.Last.next := NIL; - INC(l.Count); - END Add; +PROCEDURE Add*(VAR l : TdepTree; VAR d: Tdep); +BEGIN + IF l.First = NIL THEN + l.First := d; + d.prev := NIL; + ELSE + l.Last.next := d; + d.prev := l.Last; + END; + l.Last := d; + l.Last.next := NIL; + INC(l.Count); +END Add; -PROCEDURE AddCopy* (VAR l : TdepTree; VAR d: Tdep); +PROCEDURE AddCopy*(VAR l : TdepTree; VAR d: Tdep); VAR new: Tdep; ln: INTEGER; - BEGIN - NEW(new); - new.prev := d.prev; new.next := d.next; - ln := Strings.Length(d.name^) + 1; NEW(new.name, ln); COPY(d.name^, new.name^); - new.deps := d.deps; - new.Create := d.Create; new.AssignDeps := d.AssignDeps; - new.RetrieveDeps := d.RetrieveDeps; - new.InstallRetriever := d.InstallRetriever; +BEGIN + NEW(new); + new.prev := d.prev; new.next := d.next; + ln := Strings.Length(d.name^) + 1; NEW(new.name, ln); COPY(d.name^, new.name^); + COPY(d.version, new.version); + new.deps := d.deps; + new.Create := d.Create; new.AssignDeps := d.AssignDeps; + new.RetrieveDeps := d.RetrieveDeps; + new.InstallRetriever := d.InstallRetriever; + new.Type := d.Type; + new.rmt := d.rmt; - IF l.First = NIL THEN - l.First := new; - ELSE - l.Last.next := new; - END; - l.Last := new; - l.Last.next := NIL; - INC(l.Count); - END AddCopy; + IF l.First = NIL THEN + l.First := new; + new.prev := NIL; + ELSE + l.Last.next := new; + new.prev := l.Last; + END; + l.Last := new; + l.Last.next := NIL; + INC(l.Count); +END AddCopy; PROCEDURE Get*(VAR l: TdepTree; inx: LONGINT): Tdep; VAR @@ -181,7 +204,6 @@ BEGIN d := NIL; i := 0; IF (inx < l.Count) & (inx >= 0) THEN - i := 0; d := l.First; WHILE i # inx DO IF d # NIL THEN d := d.next END; @@ -193,43 +215,50 @@ END Get; PROCEDURE GetByName*(VAR l: TdepTree; VAR name: ARRAY OF CHAR): Tdep; VAR - i: LONGINT; d: Tdep; - fnd: BOOLEAN; BEGIN - fnd := FALSE; - i := 0; d := l.First; - REPEAT - IF d # NIL THEN - IF d.name^ = name THEN - fnd := TRUE; - RETURN d; - ELSE - d := d.next - END + WHILE d # NIL DO + IF d.name^ = name THEN + RETURN d; END; - INC(i); -(* UNTIL fnd OR (i >= l.Count );*) - UNTIL fnd OR (d = NIL); - RETURN NIL; (* in case of this UNTIL it seems safe to RETURN d *) + d := d.next + END; + RETURN NIL; END GetByName; -PROCEDURE Create* () : TdepTree; - VAR l : TdepTree; - BEGIN - NEW(l); - l.First := NIL; - l.Last := NIL; - l.Count := 0; - l.Add := Add; - l.Get := Get; - l.GetByName := GetByName; - l.Clear := Clear; - l.Free := Free; - l.Empty := Empty; - RETURN(l); - END Create; +PROCEDURE GetByNameVersion*(VAR l: TdepTree; VAR name, version: ARRAY OF CHAR): Tdep; +VAR + d: Tdep; +BEGIN + d := l.First; + WHILE d # NIL DO + IF d.name^ = name THEN + IF (version = "") OR (d.version = version) THEN + RETURN d; + END; + END; + d := d.next + END; + RETURN NIL; +END GetByNameVersion; +PROCEDURE Create*() : TdepTree; +VAR l : TdepTree; +BEGIN + NEW(l); + l.First := NIL; + l.Last := NIL; + l.Count := 0; + l.Add := Add; + l.Get := Get; + l.GetByName := GetByName; + l.GetByNameVersion := GetByNameVersion; + l.Clear := Clear; + l.Free := Free; + l.Empty := Empty; + l.Create := Create; + RETURN l; +END Create; END vpkdepTree.