diff --git a/src/unix/vpkEnv.Mod b/src/unix/vpkEnv.Mod index a8864b7..2f2753e 100644 --- a/src/unix/vpkEnv.Mod +++ b/src/unix/vpkEnv.Mod @@ -19,31 +19,111 @@ BEGIN END getGraphName; PROCEDURE createIfNotThere*(VAR fileName: ARRAY OF CHAR); +VAR + workName: ARRAY 512 OF CHAR; + len: INTEGER; BEGIN - IF ~UnixFS.ExistsByName(fileName) THEN - IF ~UnixFS.mkDir(fileName) THEN - Out.String("failed to create directory "); Out.String(fileName); Out.Ln; HALT(1); - END; - END; + COPY(fileName, workName); + (* Remove trailing slash for directory creation *) + len := Strings.Length(workName); + IF (len > 1) & (workName[len - 1] = '/') THEN + workName[len - 1] := 0X; + END; + + IF ~UnixFS.ExistsByName(workName) THEN + IF ~UnixFS.mkDir(workName) THEN + Out.String("failed to create directory "); Out.String(workName); Out.Ln; HALT(1); + END; + END; END createIfNotThere; -PROCEDURE getSrcRelPath*(VAR depName, domain, path0: ARRAY OF CHAR): strTypes.pstring; +(* Create directories recursively like mkdir -p *) +PROCEDURE mkDirRecursive*(VAR fullPath: ARRAY OF CHAR); +VAR + currentPath: ARRAY 512 OF CHAR; + component: ARRAY 128 OF CHAR; + pos, nextPos: INTEGER; + i: INTEGER; +BEGIN + (* + Out.String(">>> mkDirRecursive called with: '"); Out.String(fullPath); Out.String("'"); Out.Ln; + *) + + COPY("", currentPath); + pos := 0; + + (* Handle absolute paths starting with / *) + IF (Strings.Length(fullPath) > 0) & (fullPath[0] = '/') THEN + COPY("/", currentPath); + pos := 1; + END; + + WHILE pos < Strings.Length(fullPath) DO + (* Find next '/' or end of string *) + nextPos := pos; + WHILE (nextPos < Strings.Length(fullPath)) & (fullPath[nextPos] # '/') DO + INC(nextPos); + END; + + (* Extract component *) + IF nextPos > pos THEN + i := 0; + WHILE (pos < nextPos) & (i < LEN(component) - 1) DO + component[i] := fullPath[pos]; + INC(i); INC(pos); + END; + component[i] := 0X; + + (* Append component to current path *) + IF Strings.Length(currentPath) > 0 THEN + IF currentPath[Strings.Length(currentPath) - 1] # '/' THEN + Strings.Append("/", currentPath); + END; + END; + Strings.Append(component, currentPath); + + (* + Out.String(">>> Creating directory: '"); Out.String(currentPath); Out.String("'"); Out.Ln; + *) + + (* Create directory if it doesn't exist - createIfNotThere handles trailing slashes *) + createIfNotThere(currentPath); + END; + + (* Skip the '/' *) + IF (pos < Strings.Length(fullPath)) & (fullPath[pos] = '/') THEN + INC(pos); + END; + END; + + (* + Out.String(">>> mkDirRecursive completed"); Out.Ln; + *) +END mkDirRecursive; + +PROCEDURE getSrcRelPath*(VAR depName, repoPath, path0: ARRAY OF CHAR): strTypes.pstring; VAR p: strTypes.pstring; len: INTEGER; BEGIN - len := 12 + Strings.Length(depName) + Strings.Length(path0) + Strings.Length(domain); - (* 5 chars are ../, /, /, plus a couple of chars *) + (* + Out.String("@@@ getSrcRelPath called with:"); Out.Ln; + Out.String("@@@ depName: '"); Out.String(depName); Out.String("'"); Out.Ln; + Out.String("@@@ repoPath: '"); Out.String(repoPath); Out.String("'"); Out.Ln; + Out.String("@@@ path0: '"); Out.String(path0); Out.String("'"); Out.Ln; + *) + len := 16 + Strings.Length(path0) + Strings.Length(repoPath); NEW(p, len); - COPY("../", p^); + COPY("", p^); (* Start with empty string instead of "../" *) Strings.Append(vpkSettings.vpkDepDir, p^); Strings.Append("/", p^); - Strings.Append(domain, p^); - Strings.Append("/", p^); - Strings.Append(depName, p^); + Strings.Append(repoPath, p^); Strings.Append("/", p^); Strings.Append(path0, p^); + (* + Out.String("@@@ result: '"); Out.String(p^); Out.String("'"); Out.Ln; + *) RETURN p; END getSrcRelPath; @@ -89,42 +169,82 @@ BEGIN RETURN builddir END mkdefBldDir; -PROCEDURE mkdefPkgDirPath*(VAR domain, name, path: ARRAY OF CHAR); +PROCEDURE mkdefPkgDirPath*(VAR repoPath, name, path: ARRAY OF CHAR); VAR home: ARRAY 128 OF CHAR; + finalPath: ARRAY 512 OF CHAR; BEGIN getHome(home); - COPY(home, path); - Strings.Append("/", path); - Strings.Append(vpkSettings.vpkPkgDir, path); - createIfNotThere(path); - Strings.Append("/", path); - Strings.Append(vpkSettings.vpkDepDir, path); - createIfNotThere(path); - Strings.Append("/", path); - Strings.Append(domain, path); - createIfNotThere(path); - Strings.Append("/", path); - Strings.Append(name, path); - createIfNotThere(path); + + (* Build: //deps/// *) + COPY(home, finalPath); + Strings.Append("/", finalPath); + Strings.Append(vpkSettings.vpkPkgDir, finalPath); + Strings.Append("/", finalPath); + Strings.Append(vpkSettings.vpkDepDir, finalPath); + Strings.Append("/", finalPath); + Strings.Append(repoPath, finalPath); + Strings.Append("/", finalPath); + Strings.Append(name, finalPath); + + (* Create all directories recursively *) + mkDirRecursive(finalPath); + + (* Return the path with trailing slash *) + COPY(finalPath, path); Strings.Append("/", path); END mkdefPkgDirPath; -PROCEDURE mkPkgDirPath*(VAR domain, name, path: ARRAY OF CHAR); +PROCEDURE mkPkgDirPath*(VAR repoPath, name, path: ARRAY OF CHAR); +VAR + finalPath: ARRAY 512 OF CHAR; + len: INTEGER; BEGIN - Strings.Append("/", path); - createIfNotThere(path); - Strings.Append(vpkSettings.vpkDepDir, path); - Strings.Append("/", path); - createIfNotThere(path); - Strings.Append(domain, path); - createIfNotThere(path); - Strings.Append("/", path); - Strings.Append(name, path); - createIfNotThere(path); - Strings.Append("/", path); -END mkPkgDirPath; + (* + Out.String("=== DEBUG mkPkgDirPath START ==="); Out.Ln; + Out.String("Input path: '"); Out.String(path); Out.String("'"); Out.Ln; + Out.String("Input repoPath: '"); Out.String(repoPath); Out.String("'"); Out.Ln; + Out.String("Input name: '"); Out.String(name); Out.String("'"); Out.Ln; + *) + (* Start with clean path *) + COPY(path, finalPath); + + (* Remove trailing slashes *) + len := Strings.Length(finalPath); + WHILE (len > 1) & (finalPath[len - 1] = '/') DO + finalPath[len - 1] := 0X; + DEC(len); + END; + (* + Out.String("After removing trailing slashes: '"); Out.String(finalPath); Out.String("'"); Out.Ln; + *) + + (* Add /deps *) + Strings.Append("/", finalPath); + Strings.Append(vpkSettings.vpkDepDir, finalPath); + (* + Out.String("After adding deps: '"); Out.String(finalPath); Out.String("'"); Out.Ln; + *) + + (* Add / - this already contains the package name! *) + Strings.Append("/", finalPath); + Strings.Append(repoPath, finalPath); + (* + Out.String("After adding repoPath: '"); Out.String(finalPath); Out.String("'"); Out.Ln; + *) + + (* Create directories *) + mkDirRecursive(finalPath); + + (* Return with trailing slash *) + COPY(finalPath, path); + Strings.Append("/", path); + (* + Out.String("Final output path: '"); Out.String(path); Out.String("'"); Out.Ln; + Out.String("=== DEBUG mkPkgDirPath END ==="); Out.Ln; + *) +END mkPkgDirPath; PROCEDURE mkCmd*(VAR p0, p1: ARRAY OF CHAR): strTypes.pstring; VAR diff --git a/src/unix/vpkGit.Mod b/src/unix/vpkGit.Mod index 7fec876..9b3666b 100644 --- a/src/unix/vpkGit.Mod +++ b/src/unix/vpkGit.Mod @@ -4,28 +4,38 @@ IMPORT Out, Strings, Platform, vpkEnv; PROCEDURE pull*(VAR url : ARRAY OF CHAR; VAR dst : ARRAY OF CHAR; VAR branch: ARRAY OF CHAR); VAR i : INTEGER; cmd : ARRAY 2048 OF CHAR; + cleanDst: ARRAY 512 OF CHAR; BEGIN - cmd := "git init "; - Strings.Append(dst, cmd); - i:=Platform.System(cmd); - (*cmd := "git -C "; - Strings.Append(dst, cmd); - Strings.Append(" remote add origin ", cmd); + (* Clean destination path - remove trailing slash *) + COPY(dst, cleanDst); + IF (Strings.Length(cleanDst) > 1) & (cleanDst[Strings.Length(cleanDst) - 1] = '/') THEN + cleanDst[Strings.Length(cleanDst) - 1] := 0X; + END; + + Out.String("*** GIT: Cloning to: '"); Out.String(cleanDst); Out.String("'"); Out.Ln; + + (* Remove directory if it exists to avoid conflicts *) + cmd := "rm -rf "; + Strings.Append(cleanDst, cmd); + i := Platform.System(cmd); + + (* Use git clone directly - much simpler *) + cmd := "git clone "; Strings.Append(url, cmd); - i:=Platform.System(cmd);*) - cmd := ""; - cmd := "git -C "; - Strings.Append(dst, cmd); - Strings.Append(" pull ", cmd); - Strings.Append(url, cmd); - Out.String("branch: '"); Out.String(branch); Out.String("'."); Out.Ln; IF branch # "" THEN - Out.String("adding branch to commandline"); Out.Ln; - Strings.Append(" ", cmd); + Strings.Append(" --branch ", cmd); Strings.Append(branch, cmd); END; - Out.String("fetch command: '"); Out.String(cmd); Out.Char("'"); Out.Ln; + Strings.Append(" ", cmd); + Strings.Append(cleanDst, cmd); + + Out.String("*** GIT: Executing: '"); Out.String(cmd); Out.String("'"); Out.Ln; i := Platform.System(cmd); + IF i # 0 THEN + Out.String("*** GIT: Command failed with exit code: "); Out.Int(i, 0); Out.Ln; + ELSE + Out.String("*** GIT: Clone successful"); Out.Ln; + END; END pull; PROCEDURE syncTree*(url, branch: ARRAY OF CHAR); diff --git a/src/vipak.Mod b/src/vipak.Mod index 69c8673..d4a4d6d 100644 --- a/src/vipak.Mod +++ b/src/vipak.Mod @@ -11,7 +11,7 @@ END msgnopkg; PROCEDURE main; VAR - deps, sync, fetch, ask, local, init, withDeps: BOOLEAN; + deps, sync, fetch, ask, local, init: BOOLEAN; package, prefix, pkgTree, localFile: ARRAY 128 OF CHAR; options: opts.Options; @@ -86,7 +86,7 @@ BEGIN opts.setOptName(opt, "-l"); opts.setOptLName(opt, "--local"); opts.setOptHasVal(opt, FALSE); - opts.setOptDesc(opt, "build local project from vipak.json file"); + opts.setOptDesc(opt, "build local project from vipak.json file (includes dependencies)"); opts.setOptRequired(opt, FALSE); options.add(options, opt); @@ -98,14 +98,6 @@ BEGIN opts.setOptRequired(opt, FALSE); options.add(options, opt); - opt := opts.createOpt(); - opts.setOptName(opt, "-w"); - opts.setOptLName(opt, "--with-deps"); - opts.setOptHasVal(opt, FALSE); - opts.setOptDesc(opt, "also build dependencies when building local project"); - opts.setOptRequired(opt, FALSE); - options.add(options, opt); - foptions := opts.populateOptions(options); IF opts.reqsSatisfied(options, foptions) THEN Out.String("required options provided"); Out.Ln; @@ -118,7 +110,7 @@ BEGIN COPY("", package); COPY("", prefix); COPY("", pkgTree); COPY("vipak.json", localFile); deps := FALSE; sync := FALSE; fetch := FALSE; ask := FALSE; - local := FALSE; init := FALSE; withDeps := FALSE; + local := FALSE; init := FALSE; fopt := opts.createOpt(); fopt := opts.findOpt("-d", foptions); @@ -144,10 +136,6 @@ BEGIN fopt := opts.findOpt("-i", foptions); IF fopt # NIL THEN init := TRUE END; - fopt := opts.createOpt(); - fopt := opts.findOpt("-w", foptions); - IF fopt # NIL THEN withDeps := TRUE END; - opts.valOfOpt("-p", foptions, package); opts.valOfOpt("-P", foptions, prefix); IF prefix = "" THEN @@ -166,7 +154,7 @@ BEGIN vpkLocalBuilder.init ELSIF local THEN Out.String("Building local project from: "); Out.String(localFile); Out.Ln; - vpkLocalBuilder.buildLocal(localFile, withDeps) + vpkLocalBuilder.buildLocal(localFile) ELSIF sync THEN vpkSyncer.sync ELSE @@ -187,4 +175,4 @@ END main; BEGIN main -END vipak. \ No newline at end of file +END vipak. diff --git a/src/vpkHttp.Mod b/src/vpkHttp.Mod index 49bbced..ca3ce7c 100644 --- a/src/vpkHttp.Mod +++ b/src/vpkHttp.Mod @@ -8,6 +8,7 @@ VAR h: http.Client; answer: strTypes.pstring; domain, path: ARRAY 128 OF CHAR; port: ARRAY 8 OF CHAR; + repoPath: ARRAY 256 OF CHAR; (* Added for full repository path *) filename: ARRAY 64 OF CHAR; i, j: LONGINT; node: List.Node; @@ -25,12 +26,19 @@ BEGIN IF node^.obj(vpkdepTree.File) # NIL THEN Out.String("getting "); Out.String(node^.obj(vpkdepTree.File)^.URI); Out.Ln; + (* Extract domain for connection *) vpkTools.extractDomainFromUrl(node^.obj(vpkdepTree.File)^.URI, domain); Out.String("connecting to "); Out.String(domain); Out.Ln; + + (* Extract full repository path for directory structure *) + vpkTools.extractRepoPathFromUrl(node^.obj(vpkdepTree.File)^.URI, repoPath); + Out.String("repo path: "); Out.String(repoPath); Out.Ln; + vpkTools.extractPathFromUrl(node^.obj(vpkdepTree.File)^.URI, path); vpkTools.extractFilenameFromUrl(node^.obj(vpkdepTree.File)^.URI, filename); - vpkEnv.mkPkgDirPath(domain, dep^.name^, dst); + (* Use full repository path instead of just domain *) + vpkEnv.mkPkgDirPath(repoPath, dep^.name^, dst); j := Platform.Chdir(dst); @@ -65,4 +73,4 @@ BEGIN END fetchFiles; -END vpkHttp. +END vpkHttp. \ No newline at end of file diff --git a/src/vpkHttps.Mod b/src/vpkHttps.Mod index aafcde9..7bf77fc 100644 --- a/src/vpkHttps.Mod +++ b/src/vpkHttps.Mod @@ -8,12 +8,14 @@ VAR h: https.TLSClient; answer: strTypes.pstring; domain, path: ARRAY 128 OF CHAR; port: ARRAY 8 OF CHAR; + repoPath: ARRAY 256 OF CHAR; (* Added for full repository path *) filename: ARRAY 64 OF CHAR; i, j: LONGINT; node: List.Node; bool, continueFetching: BOOLEAN; initialDst: ARRAY 512 OF CHAR; BEGIN + Out.String("*** HTTPS: fetchFiles called"); Out.Ln; COPY(dst, initialDst); COPY("443", port); i := 0; @@ -25,12 +27,19 @@ BEGIN IF node^.obj(vpkdepTree.File) # NIL THEN Out.String("getting "); Out.String(node^.obj(vpkdepTree.File)^.URI); Out.Ln; + (* Extract domain for connection *) vpkTools.extractDomainFromUrl(node^.obj(vpkdepTree.File)^.URI, domain); Out.String("connecting to "); Out.String(domain); Out.Ln; + + (* Extract full repository path for directory structure *) + vpkTools.extractRepoPathFromUrl(node^.obj(vpkdepTree.File)^.URI, repoPath); + Out.String("repo path: "); Out.String(repoPath); Out.Ln; + vpkTools.extractPathFromUrl(node^.obj(vpkdepTree.File)^.URI, path); vpkTools.extractFilenameFromUrl(node^.obj(vpkdepTree.File)^.URI, filename); - vpkEnv.mkPkgDirPath(domain, dep^.name^, dst); + (* Use full repository path - DO NOT add package name again *) + vpkEnv.mkPkgDirPath(repoPath, dep^.name^, dst); j := Platform.Chdir(dst); diff --git a/src/vpkInstaller.Mod b/src/vpkInstaller.Mod index 9f8652f..6b6ada9 100644 --- a/src/vpkInstaller.Mod +++ b/src/vpkInstaller.Mod @@ -47,14 +47,23 @@ VAR depTree: vpkdepTree.TdepTree; dep: vpkdepTree.Tdep; i: LONGINT; + builddir: StringList.pstring; BEGIN + (* Create build directory path *) + IF prefix # "" THEN + builddir := vpkEnv.mkBldDir(prefix) + ELSE + builddir := vpkEnv.mkdefBldDir(); + END; + depTree := resolve(package); IF a THEN ask END; i := 0; REPEAT dep := vpkdepTree.Get(depTree, i); vpkJsonDepRetriever.getURIandType(dep); - vpkSyncer.fetch(dep, prefix); + (* Pass build directory instead of prefix *) + vpkSyncer.fetch(dep, builddir^); INC(i) UNTIL i = depTree.Count; END fetch; @@ -69,7 +78,7 @@ VAR b: BOOLEAN; builddir, cmd, srcPath: StringList.pstring; res: INTEGER; - domain: ARRAY 256 OF CHAR; + repoPath: ARRAY 256 OF CHAR; (* Changed from domain to repoPath *) node: List.Node; BEGIN IF prefix # "" THEN @@ -83,12 +92,13 @@ BEGIN REPEAT dep := vpkdepTree.Get(depTree, i); vpkJsonDepRetriever.getURIandType(dep); - vpkSyncer.fetch(dep, prefix); + (* Pass build directory instead of prefix *) + vpkSyncer.fetch(dep, builddir^); b := FALSE; b := vpkJsonDepRetriever.getBuildInfo(dep, keys, values); IF b THEN Out.String("Build info found for the package: "); Out.String(dep.name^); Out.Ln; - + (* Ensure keys and values are not NIL *) IF keys = NIL THEN Out.String("Error: keys list is NIL."); Out.Ln; @@ -98,17 +108,18 @@ BEGIN Out.String("Error: values list is NIL."); Out.Ln; HALT(10); END; - + Out.String("keys.Count = "); Out.Int(keys.Count, 0); Out.Ln; Out.String("values.Count = "); Out.Int(values.Count, 0); Out.Ln; j := 0; REPEAT Out.String("Processing build step "); Out.Int(j, 0); Out.Ln; IF dep^.rmt IS vpkdepTree.RemoteGit THEN - vpkTools.extractDomainFromUrl(dep^.rmt.URI, domain); + (* Use extractRepoPathFromUrl instead of extractDomainFromUrl *) + vpkTools.extractRepoPathFromUrl(dep^.rmt.URI, repoPath); ELSIF dep^.rmt IS vpkdepTree.RemoteHttps THEN node := dep^.rmt(vpkdepTree.RemoteHttps)^.Files.Get(dep^.rmt(vpkdepTree.RemoteHttps)^.Files, j); - vpkTools.extractDomainFromUrl(node^.obj(vpkdepTree.File)^.URI, domain) + vpkTools.extractRepoPathFromUrl(node^.obj(vpkdepTree.File)^.URI, repoPath) ELSE Out.String("WARNING: building for neither git nor https sources not supported yet"); Out.Ln; END; @@ -120,7 +131,8 @@ BEGIN v := values.GetString(values, j); Out.String("Got key: "); Out.String(k^); Out.Ln; Out.String("Got value: "); Out.String(v^); Out.Ln; - srcPath := vpkEnv.getSrcRelPath(dep.name^, domain, v^); + (* Use repoPath instead of domain, and deps/ prefix to reflect new structure *) + srcPath := vpkEnv.getSrcRelPath(dep.name^, repoPath, v^); cmd := vpkEnv.mkCmd(k^, srcPath^); Out.String("Command: "); Out.String(cmd^); Out.Ln; Out.String("Building in "); Out.String(builddir^); Out.Ln; diff --git a/src/vpkLocalBuilder.Mod b/src/vpkLocalBuilder.Mod index 8ae4f37..c987013 100644 --- a/src/vpkLocalBuilder.Mod +++ b/src/vpkLocalBuilder.Mod @@ -2,7 +2,7 @@ MODULE vpkLocalBuilder; IMPORT Files, Out, Strings, Platform, In, Json, StringList, strUtils, vpkStorage, vpkSettings, vpkdepTree, vpkInstaller, vpkEnv, vpkJsonDepRetriever, - UnixFS; + vpkResolver, vpkSyncer, vpkDot, vpkTools, UnixFS; CONST DefaultProjectFile = "vipak.json"; @@ -45,7 +45,7 @@ BEGIN COPY("src/", filename); Strings.Append(projectName, filename); Strings.Append(".Mod", filename); - + (* Create template module content *) COPY("MODULE ", content); Strings.Append(projectName, content); @@ -96,7 +96,7 @@ VAR BEGIN (* Use a simple default project name *) COPY("myproject", projectName); - + (* Create default JSON content *) COPY('{', content); Strings.Append(eol, content); @@ -265,12 +265,117 @@ BEGIN RETURN TRUE; END createBuildDir; -PROCEDURE buildDependencies(VAR projectFile: ARRAY OF CHAR); +PROCEDURE resolveLocal(VAR projectFile: ARRAY OF CHAR): vpkdepTree.TdepTree; +VAR + localDep: vpkdepTree.Tdep; + depsList: StringList.TStringList; + depName: StringList.pstring; + combinedTree, subTree: vpkdepTree.TdepTree; + currentDep: vpkdepTree.Tdep; + i, j: LONGINT; + found: BOOLEAN; + graphName: ARRAY 32 OF CHAR; + lst: StringList.TStringList; + localName: ARRAY 16 OF CHAR; BEGIN - (* For now, skip dependency building in local mode *) - (* This can be implemented later when the infrastructure is ready *) - Out.String("Dependency building for local projects not yet implemented."); Out.Ln; - Out.String("Please build dependencies manually using 'vipak -p '"); Out.Ln; + Out.Ln; Out.String("resolving dependencies for local project..."); Out.Ln; + + (* Set the local project file for dependency reading *) + vpkJsonDepRetriever.setLocalProjectFile(projectFile); + + (* Create a dummy dependency object to read dependencies from local file *) + COPY("local-project", localName); + localDep := vpkdepTree.CreateDep(localName); + + (* Create combined dependency tree *) + combinedTree := vpkdepTree.Create(); + + (* Get direct dependencies from the local project file *) + IF vpkJsonDepRetriever.getDepsFromFile(localDep, depsList) > 0 THEN + Out.String("Found "); Out.Int(depsList.Count, 0); Out.String(" direct dependencies"); Out.Ln; + + (* Resolve each dependency using normal tree-based resolution *) + i := 0; + REPEAT + depName := depsList.GetString(depsList, i); + IF depName # NIL THEN + Out.String("Resolving: "); Out.String(depName^); Out.Ln; + + (* Use normal vpkResolver.resolve for this dependency (it's in the tree) *) + subTree := vpkResolver.resolve(depName^, vpkJsonDepRetriever.getDeps); + + (* Merge this subtree into combined tree (avoiding duplicates) *) + j := 0; + REPEAT + currentDep := vpkdepTree.Get(subTree, j); + IF currentDep # NIL THEN + (* Check if this dependency is already in combined tree *) + found := (combinedTree.GetByName(combinedTree, currentDep.name^) # NIL); + IF ~found THEN + vpkdepTree.AddCopy(combinedTree, currentDep); + END; + END; + INC(j); + UNTIL j = subTree.Count; + END; + INC(i); + UNTIL i = depsList.Count; + + Out.String(" done! (:"); Out.Ln; Out.Ln; + + (* Show dependency graph like normal vipak *) + vpkEnv.getGraphName(graphName); + lst := vpkDot.tree2dot(combinedTree); + Out.String("dependency graph:"); Out.Ln; + Out.String("-----------------"); Out.Ln; + StringList.DumpOut(lst); + lst.Dump(lst, graphName); + Out.String("-----------------"); Out.Ln; + Out.String("(use 'dot -Tpng deps.dot > deps.png' to get the graph image)"); Out.Ln; Out.Ln; + Out.String("dependencies will be installed in the following order:"); Out.Ln; + i := 0; + REPEAT + currentDep := vpkdepTree.Get(combinedTree, i); + IF currentDep # NIL THEN + Out.String(currentDep.name^); Out.Ln; + END; + INC(i); + UNTIL i = combinedTree.Count; + ELSE + Out.String("No dependencies found in project file."); Out.Ln; + END; + + RETURN combinedTree; +END resolveLocal; + +PROCEDURE buildDependencies(VAR projectFile: ARRAY OF CHAR); +VAR + depTree: vpkdepTree.TdepTree; + currentDep: vpkdepTree.Tdep; + i: LONGINT; + buildDir: ARRAY 128 OF CHAR; +BEGIN + (* Resolve all dependencies for local project *) + depTree := resolveLocal(projectFile); + + IF depTree.Count > 0 THEN + (* Fetch all resolved dependencies *) + COPY("./", buildDir); + Strings.Append(DefaultBuildDir, buildDir); + + i := 0; + REPEAT + currentDep := vpkdepTree.Get(depTree, i); + IF currentDep # NIL THEN + Out.String("Fetching: "); Out.String(currentDep.name^); Out.Ln; + vpkJsonDepRetriever.getURIandType(currentDep); + vpkSyncer.fetch(currentDep, buildDir); + END; + INC(i); + UNTIL i = depTree.Count; + + Out.String("All dependencies fetched successfully!"); Out.Ln; + END; END buildDependencies; PROCEDURE buildProject(VAR projectFile: ARRAY OF CHAR; info: ProjectInfo): BOOLEAN; @@ -285,13 +390,13 @@ VAR BEGIN (* Create a dummy dependency object for build info extraction *) dep := vpkdepTree.CreateDep(info.name); - + (* Get build information using the procedure from vpkJsonDepRetriever *) b := vpkJsonDepRetriever.getBuildInfoFromFile(dep, keys, values, projectFile); - + IF b & (keys # NIL) & (values # NIL) THEN Out.String("Building project: "); Out.String(info.name); Out.Ln; - + (* Change to build directory *) COPY(DefaultBuildDir, buildDirVar); res := Platform.Chdir(buildDirVar); @@ -299,18 +404,18 @@ BEGIN Out.String("Failed to change to build directory"); Out.Ln; RETURN FALSE; END; - + (* Execute build commands *) i := 0; REPEAT k := keys.GetString(keys, i); v := values.GetString(values, i); - + (* Create command: copy from parent directory if needed *) COPY(k^, cmd); Strings.Append(" ../", cmd); Strings.Append(v^, cmd); - + Out.String("Executing: "); Out.String(cmd); Out.Ln; res := Platform.System(cmd); IF res # 0 THEN @@ -321,7 +426,7 @@ BEGIN END; INC(i); UNTIL i = keys.Count; - + (* Restore original directory *) COPY("..", buildDirVar); res := Platform.Chdir(buildDirVar); @@ -333,7 +438,7 @@ BEGIN END; END buildProject; -PROCEDURE buildLocal*(VAR projectFile: ARRAY OF CHAR; withDeps: BOOLEAN); +PROCEDURE buildLocal*(VAR projectFile: ARRAY OF CHAR); VAR info: ProjectInfo; b: BOOLEAN; @@ -344,27 +449,27 @@ BEGIN Out.String("Create one with 'vipak --init'"); Out.Ln; HALT(1); END; - + (* Parse project file *) b := parseProjectFile(projectFile, info); IF ~b THEN Out.String("Failed to parse project file: "); Out.String(projectFile); Out.Ln; HALT(1); END; - - Out.String("Building project: "); Out.String(info.name); + + Out.String("Building project: "); Out.String(info.name); Out.String(" v"); Out.String(info.version); Out.Ln; - + (* Create build directory *) IF ~createBuildDir() THEN HALT(1); END; - - (* Build dependencies if requested and available *) - IF withDeps & info.hasDeps THEN + + (* Build dependencies if available - default behavior for local projects *) + IF info.hasDeps THEN buildDependencies(projectFile); END; - + (* Build the project itself *) IF info.hasBuild THEN b := buildProject(projectFile, info); @@ -386,11 +491,11 @@ BEGIN Out.String("Project file already exists: "); Out.String(projectFile); Out.Ln; HALT(1); END; - + COPY("myproject", projectName); createDefaultProject(projectFile); createTemplateModule(projectName); - + Out.Ln; Out.String("Project initialized! You can now:"); Out.Ln; Out.String(" 1. Edit src/"); Out.String(projectName); Out.String(".Mod with your code"); Out.Ln; @@ -400,4 +505,4 @@ END init; BEGIN eol[0] := 0AX; eol[1] := 0X; (* Unix line ending *) -END vpkLocalBuilder. \ No newline at end of file +END vpkLocalBuilder. diff --git a/src/vpkSyncer.Mod b/src/vpkSyncer.Mod index 181694b..dd63f1a 100644 --- a/src/vpkSyncer.Mod +++ b/src/vpkSyncer.Mod @@ -24,10 +24,14 @@ BEGIN END sync; PROCEDURE fetch*(VAR dep: vpkdepTree.Tdep; dst: ARRAY OF CHAR); -VAR domain: ARRAY 64 OF CHAR; +VAR repoPath: ARRAY 256 OF CHAR; + workingDst: ARRAY 512 OF CHAR; (* Local copy to modify *) BEGIN - Out.String("Starting fetch process..."); Out.Ln; - Out.String("Destination: "); Out.String(dst); Out.Ln; + Out.String("*** SYNCER: Starting fetch process..."); Out.Ln; + Out.String("*** SYNCER: Input destination: '"); Out.String(dst); Out.String("'"); Out.Ln; + COPY(dst, workingDst); (* Make a local copy to modify *) + Out.String("*** SYNCER: Working destination: '"); Out.String(workingDst); Out.String("'"); Out.Ln; + IF dep = NIL THEN Out.String("Dependency is NIL"); Out.Ln; HALT(1); @@ -37,33 +41,42 @@ BEGIN HALT(5); ELSE IF dep^.rmt IS vpkdepTree.RemoteGit THEN - Out.String("Remote type is Git"); Out.Ln; - vpkTools.extractDomainFromUrl(dep^.rmt^.URI, domain); - Out.String("Extracted domain: "); Out.String(domain); Out.Ln; - (* dst is changed by mkdefPkgDirPath and mkPkgdirPath *) - IF dst = "" THEN - vpkEnv.mkdefPkgDirPath(domain, dep^.name^, dst); + Out.String("*** SYNCER: Remote type is Git"); Out.Ln; + Out.String("*** SYNCER: Package name is: '"); Out.String(dep^.name^); Out.String("'"); Out.Ln; + Out.String("*** SYNCER: Remote URI is: '"); Out.String(dep^.rmt^.URI); Out.String("'"); Out.Ln; + + vpkTools.extractRepoPathFromUrl(dep^.rmt^.URI, repoPath); + Out.String("*** SYNCER: Extracted repo path: '"); Out.String(repoPath); Out.String("'"); Out.Ln; + + Out.String("*** SYNCER: About to call mkPkgDirPath with:"); Out.Ln; + Out.String("*** repoPath = '"); Out.String(repoPath); Out.String("'"); Out.Ln; + Out.String("*** name = '"); Out.String(dep^.name^); Out.String("'"); Out.Ln; + Out.String("*** workingDst = '"); Out.String(workingDst); Out.String("'"); Out.Ln; + + (* Build the proper destination path *) + IF Strings.Length(workingDst) = 0 THEN + vpkEnv.mkdefPkgDirPath(repoPath, dep^.name^, workingDst); ELSE - vpkEnv.mkPkgDirPath(domain, dep^.name^, dst); + vpkEnv.mkPkgDirPath(repoPath, dep^.name^, workingDst); END; - Out.String("Final destination path: "); Out.String(dst); Out.Ln; - Out.String("Fetching repository..."); Out.Ln; - vpkGit.fetchRepo(dep^.rmt^.URI, dst, dep^.rmt(vpkdepTree.RemoteGit).branch); + + Out.String("*** SYNCER: After mkPkgDirPath, workingDst = '"); Out.String(workingDst); Out.String("'"); Out.Ln; + Out.String("*** SYNCER: About to call git with destination: '"); Out.String(workingDst); Out.String("'"); Out.Ln; + + vpkGit.fetchRepo(dep^.rmt^.URI, workingDst, dep^.rmt(vpkdepTree.RemoteGit).branch); ELSIF dep^.rmt IS vpkdepTree.RemoteHttps THEN Out.String("Remote type is HTTPS"); Out.Ln; - (* full dst will be determined in vpkHttps.fetchFiles for each file *) - vpkHttps.fetchFiles(dep, dst); + vpkHttps.fetchFiles(dep, workingDst); ELSIF dep^.rmt IS vpkdepTree.RemoteHttp THEN Out.String("Remote type is HTTP"); Out.Ln; - (* full dst will be determined in vpkHttps.fetchFiles for each file *) - vpkHttp.fetchFiles(dep, dst); + vpkHttp.fetchFiles(dep, workingDst); ELSE Out.String("TODO: neither git nor https url"); Out.Ln; Out.String("not handled"); Out.Ln; END; END; - Out.String("Fetch process completed."); Out.Ln; + Out.String("*** SYNCER: Fetch process completed."); Out.Ln; END fetch; END vpkSyncer. diff --git a/src/vpkTools.Mod b/src/vpkTools.Mod index b13787b..7c90355 100644 --- a/src/vpkTools.Mod +++ b/src/vpkTools.Mod @@ -1,5 +1,5 @@ MODULE vpkTools; -IMPORT Strings, strUtils; +IMPORT Strings, strUtils, Out; PROCEDURE extractDomainFromUrl*(VAR url: ARRAY OF CHAR; VAR domain: ARRAY OF CHAR); @@ -78,5 +78,63 @@ BEGIN END; END extractFilenameFromUrl; +PROCEDURE extractRepoPathFromUrl*(VAR url: ARRAY OF CHAR; VAR repoPath: ARRAY OF CHAR); +(* Extracts full repository path from URL like: + https://github.com/norayr/strutils -> github.com/norayr/strutils + https://codeberg.org/user/project -> codeberg.org/user/project +*) +VAR + start, i, j: INTEGER; + found: BOOLEAN; +BEGIN + Out.String("@@@ extractRepoPathFromUrl input: '"); Out.String(url); Out.String("'"); Out.Ln; + + start := 0; + found := FALSE; + repoPath[0] := 0X; (* Initialize to empty string *) + + (* Find the "://" pattern to skip protocol *) + WHILE (start < LEN(url) - 2) & (url[start] # 0X) & ~found DO + IF (url[start] = ':') & (url[start+1] = '/') & (url[start+2] = '/') THEN + found := TRUE; + start := start + 3; (* Skip "://" *) + ELSE + INC(start); + END; + END; + + Out.String("@@@ After skipping protocol, start="); Out.Int(start, 0); Out.Ln; + + IF ~found THEN + (* No protocol found, assume the whole URL is the path *) + COPY(url, repoPath); + Out.String("@@@ No protocol found, using whole URL: '"); Out.String(repoPath); Out.String("'"); Out.Ln; + RETURN; + END; + + (* Find end of URL (exclude .git suffix if present) *) + i := start; + WHILE (i < LEN(url)) & (url[i] # 0X) DO + INC(i); + END; + + Out.String("@@@ End of URL at position: "); Out.Int(i, 0); Out.Ln; + + (* Remove .git suffix if present *) + IF (i >= 4) & (url[i-4] = '.') & (url[i-3] = 'g') & (url[i-2] = 'i') & (url[i-1] = 't') THEN + i := i - 4; + Out.String("@@@ Removed .git suffix, new end: "); Out.Int(i, 0); Out.Ln; + END; + + (* Copy domain + path *) + j := 0; + WHILE (start < i) & (j < LEN(repoPath) - 1) DO + repoPath[j] := url[start]; + INC(j); INC(start); + END; + repoPath[j] := 0X; + + Out.String("@@@ extractRepoPathFromUrl output: '"); Out.String(repoPath); Out.String("'"); Out.Ln; +END extractRepoPathFromUrl; END vpkTools.