diff --git a/cmd/llar/internal/install.go b/cmd/llar/internal/install.go index 4370da0e..ee6da7e4 100644 --- a/cmd/llar/internal/install.go +++ b/cmd/llar/internal/install.go @@ -142,7 +142,7 @@ func install(ctx context.Context, progress io.Writer, serviceURL, arg string, ma matrixStr := matrix.Combinations()[0] var rootResult moduleOutputResult - deps := make([]module.Version, 0, len(messages)-1) + deps := make([]moduleOutputDep, 0, len(messages)-1) for _, message := range messages { parsed, err := url.Parse(message.ID) if err != nil { @@ -184,7 +184,7 @@ func install(ctx context.Context, progress io.Writer, serviceURL, arg string, ma OutputDir: installDir, } } else { - deps = append(deps, mod) + deps = append(deps, moduleOutputDep{Module: mod, OutputDir: installDir}) } } rootResult.Deps = deps diff --git a/cmd/llar/internal/install_test.go b/cmd/llar/internal/install_test.go index 69acb840..48eb13d2 100644 --- a/cmd/llar/internal/install_test.go +++ b/cmd/llar/internal/install_test.go @@ -140,6 +140,10 @@ func TestInstallCommand(t *testing.T) { if result.Path != "test/root" || result.Version != "v1.0.0" { t.Fatalf("result = %+v, want test/root@v1.0.0", result) } + installDir := filepath.Join(workspaceDir, "test/root@v1.0.0-testarch-testos|ON") + if result.Dir != installDir { + t.Fatalf("result dir = %q, want %q", result.Dir, installDir) + } if _, err := os.Stat(output); err != nil { t.Fatalf("output artifact: %v", err) } @@ -156,7 +160,6 @@ func TestInstallCommand(t *testing.T) { if archiveInfo.Metadata != "-I"+filepath.Join(extracted, "include")+" -lroot" { t.Fatalf("archive metadata = %+v", archiveInfo) } - installDir := filepath.Join(workspaceDir, "test/root@v1.0.0-testarch-testos|ON") assertInstallFile(t, filepath.Join(installDir, "include", "root.h"), "root") directoryOutput := filepath.Join(t.TempDir(), "root-out") @@ -312,7 +315,12 @@ func TestInstallDownloadsRootAndDependencies(t *testing.T) { if result.Module != (module.Version{Path: "test/root", Version: "v1.0.0"}) { t.Fatalf("result module = %+v", result.Module) } - if len(result.Deps) != 1 || result.Deps[0] != (module.Version{Path: "test/dep", Version: "v1.2.3"}) { + depDir := filepath.Join(workspaceDir, fmt.Sprintf("test/dep@v1.2.3-%s", matrixStr)) + rootDir := filepath.Join(workspaceDir, fmt.Sprintf("test/root@v1.0.0-%s", matrixStr)) + if result.OutputDir != rootDir { + t.Fatalf("result output dir = %q, want %q", result.OutputDir, rootDir) + } + if len(result.Deps) != 1 || result.Deps[0].Module != (module.Version{Path: "test/dep", Version: "v1.2.3"}) || result.Deps[0].OutputDir != depDir { t.Fatalf("result deps = %+v", result.Deps) } if result.Metadata != "-I"+filepath.Join(result.OutputDir, "include")+" -lroot" { @@ -325,8 +333,6 @@ func TestInstallDownloadsRootAndDependencies(t *testing.T) { t.Fatalf("llard artifact requests = %d, want one", artifactRequests) } - depDir := filepath.Join(workspaceDir, fmt.Sprintf("test/dep@v1.2.3-%s", matrixStr)) - rootDir := filepath.Join(workspaceDir, fmt.Sprintf("test/root@v1.0.0-%s", matrixStr)) assertInstallFile(t, filepath.Join(depDir, "lib", "libdep.a"), "dep") assertInstallFile(t, filepath.Join(rootDir, "include", "root.h"), "root") assertInstallCache(t, workspaceDir, "test/dep", "v1.2.3", matrixStr, "-L"+filepath.Join(depDir, "lib")+" -ldep") @@ -355,9 +361,12 @@ func TestInstallDownloadsRootAndDependencies(t *testing.T) { if err := json.Unmarshal(jsonOutput.Bytes(), &jsonResult); err != nil { t.Fatal(err) } - if jsonResult.Path != "test/root" || jsonResult.Version != "v1.0.0" || len(jsonResult.Deps) != 1 { + if jsonResult.Path != "test/root" || jsonResult.Version != "v1.0.0" || jsonResult.Dir != rootDir || len(jsonResult.Deps) != 1 { t.Fatalf("JSON result = %+v", jsonResult) } + if jsonResult.Deps[0].Path != "test/dep" || jsonResult.Deps[0].Version != "v1.2.3" || jsonResult.Deps[0].Dir != depDir { + t.Fatalf("JSON dependency = %+v", jsonResult.Deps[0]) + } } @@ -420,7 +429,7 @@ func TestInstallSkipsCachedArtifacts(t *testing.T) { if result.Module != (module.Version{Path: "test/root", Version: "v1.0.0"}) { t.Fatalf("result module = %+v", result.Module) } - if len(result.Deps) != 1 || result.Deps[0] != (module.Version{Path: "test/dep", Version: "v1.2.3"}) { + if len(result.Deps) != 1 || result.Deps[0].Module != (module.Version{Path: "test/dep", Version: "v1.2.3"}) || result.Deps[0].OutputDir != depDir { t.Fatalf("result deps = %+v", result.Deps) } if result.Metadata != "-I"+filepath.Join(result.OutputDir, "include")+" -lroot" { diff --git a/cmd/llar/internal/make.go b/cmd/llar/internal/make.go index c16f343e..cee26203 100644 --- a/cmd/llar/internal/make.go +++ b/cmd/llar/internal/make.go @@ -171,9 +171,35 @@ func buildModule(ctx context.Context, store repo.Store, modPath, version string, if len(results) > 0 { main := results[len(results)-1] + deps := artifactDeps(mods) + mainPath, err := module.EscapePath(mods[0].Path) + if err != nil { + return err + } + mainSuffix := fmt.Sprintf("%s@%s-%s", mainPath, mods[0].Version, matrixStr) + mainDir := filepath.Clean(main.OutputDir) + if !strings.HasSuffix(mainDir, mainSuffix) { + return fmt.Errorf("unexpected build output directory %q for %s@%s", mainDir, mods[0].Path, mods[0].Version) + } + workspaceDir := strings.TrimSuffix(mainDir, mainSuffix) + workspaceDir = strings.TrimSuffix(workspaceDir, string(filepath.Separator)) + outputDeps := make([]moduleOutputDep, 0, len(deps)) + for _, dep := range deps { + depPath, err := module.EscapePath(dep.Path) + if err != nil { + return err + } + outputDeps = append(outputDeps, moduleOutputDep{ + Module: dep, + OutputDir: filepath.Join( + workspaceDir, + fmt.Sprintf("%s@%s-%s", depPath, dep.Version, matrixStr), + ), + }) + } result := moduleOutputResult{ Module: module.Version{Path: mods[0].Path, Version: mods[0].Version}, - Deps: artifactDeps(mods), + Deps: outputDeps, Metadata: main.Metadata, OutputDir: main.OutputDir, } diff --git a/cmd/llar/internal/make_test.go b/cmd/llar/internal/make_test.go index 8b330cb1..5aa3ae7c 100644 --- a/cmd/llar/internal/make_test.go +++ b/cmd/llar/internal/make_test.go @@ -688,9 +688,11 @@ func TestMakeLocal_JSONOutput(t *testing.T) { var got struct { Path string `json:"path"` Version string `json:"version"` + Dir string `json:"dir"` Deps []struct { Path string `json:"path"` Version string `json:"version"` + Dir string `json:"dir"` } `json:"deps"` Metadata string `json:"metadata"` } @@ -703,6 +705,10 @@ func TestMakeLocal_JSONOutput(t *testing.T) { if got.Version != "1.0.0" { t.Fatalf("version = %q, want %q", got.Version, "1.0.0") } + rootDir := filepath.Join(workspaceDir, fmt.Sprintf("test/jsonroot@1.0.0-%s", matrixStr)) + if got.Dir != rootDir { + t.Fatalf("dir = %q, want %q", got.Dir, rootDir) + } if got.Metadata != "-ljsonroot" { t.Fatalf("metadata = %q, want %q", got.Metadata, "-ljsonroot") } @@ -712,6 +718,10 @@ func TestMakeLocal_JSONOutput(t *testing.T) { if got.Deps[0].Path != "test/jsondep" || got.Deps[0].Version != "1.2.3" { t.Fatalf("deps[0] = %+v, want test/jsondep@1.2.3", got.Deps[0]) } + depDir := filepath.Join(workspaceDir, fmt.Sprintf("test/jsondep@1.2.3-%s", matrixStr)) + if got.Deps[0].Dir != depDir { + t.Fatalf("deps[0].dir = %q, want %q", got.Deps[0].Dir, depDir) + } } func TestMakeLocal_VerboseWritesBuildOutputToStderr(t *testing.T) { diff --git a/cmd/llar/internal/module_output.go b/cmd/llar/internal/module_output.go index 876593cb..890f14f8 100644 --- a/cmd/llar/internal/module_output.go +++ b/cmd/llar/internal/module_output.go @@ -15,18 +15,25 @@ import ( type moduleJSONDep struct { Path string `json:"path"` Version string `json:"version"` + Dir string `json:"dir"` } type moduleJSONResult struct { Path string `json:"path"` Version string `json:"version"` + Dir string `json:"dir"` Deps []moduleJSONDep `json:"deps,omitempty"` Metadata string `json:"metadata"` } +type moduleOutputDep struct { + Module module.Version + OutputDir string +} + type moduleOutputResult struct { Module module.Version - Deps []module.Version + Deps []moduleOutputDep Metadata string OutputDir string } @@ -42,11 +49,16 @@ func writeModuleResult(output io.Writer, result moduleOutputResult, jsonOutput b deps := make([]moduleJSONDep, 0, len(result.Deps)) for _, dep := range result.Deps { - deps = append(deps, moduleJSONDep{Path: dep.Path, Version: dep.Version}) + deps = append(deps, moduleJSONDep{ + Path: dep.Module.Path, + Version: dep.Module.Version, + Dir: dep.OutputDir, + }) } return json.NewEncoder(output).Encode(moduleJSONResult{ Path: result.Module.Path, Version: result.Module.Version, + Dir: result.OutputDir, Deps: deps, Metadata: result.Metadata, }) @@ -71,7 +83,11 @@ func writeModuleOutput(result moduleOutputResult, dest string) error { if !strings.HasSuffix(dest, ".zip") && !strings.HasSuffix(dest, ".tar.gz") { return os.CopyFS(dest, os.DirFS(result.OutputDir)) } - body, err := metadata.Encode(metadata.Info{Metadata: result.Metadata, Deps: result.Deps}, result.OutputDir) + deps := make([]module.Version, 0, len(result.Deps)) + for _, dep := range result.Deps { + deps = append(deps, dep.Module) + } + body, err := metadata.Encode(metadata.Info{Metadata: result.Metadata, Deps: deps}, result.OutputDir) if err != nil { return err }