@@ -30,19 +30,22 @@ import (
3030 "os"
3131 "os/exec"
3232 "os/signal"
33- "path"
3433 "path/filepath"
3534 "regexp"
3635 "runtime"
37- "sort"
3836 "strings"
3937 "testing"
4038 "text/template"
4139
40+ "github.com/bazelbuild/rules_go/go/runfiles"
4241 "github.com/bazelbuild/rules_go/go/tools/bazel"
4342 "github.com/bazelbuild/rules_go/go/tools/internal/txtar"
4443)
4544
45+ // Set via x_defs.
46+ var goRootFile = ""
47+ var testedModuleName = ""
48+
4649const (
4750 // Standard Bazel exit codes.
4851 // A subset of codes in https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/util/ExitCode.java.
@@ -317,6 +320,30 @@ func setupWorkspace(args Args, files []string) (dir string, cleanup func() error
317320 }
318321 cleanups = append (cleanups , func () error { return os .RemoveAll (execDir ) })
319322
323+ // Copy or link the files for the tested repository.
324+ testedRepoDir := filepath .Join (execDir , "tested_repo" )
325+ for _ , f := range files {
326+ if ! strings .HasPrefix (f , "_main/" ) {
327+ return "" , cleanup , fmt .Errorf ("unexpected data file from a non-main repo: %s" , f )
328+ }
329+ srcPath , err := runfiles .Rlocation (f )
330+ if err != nil {
331+ return "" , cleanup , fmt .Errorf ("unknown runfile %s: %v" , f , err )
332+ }
333+ dstPath := filepath .Join (testedRepoDir , strings .TrimPrefix (f , "_main/" ))
334+ if err := copyOrLink (dstPath , srcPath ); err != nil {
335+ return "" , cleanup , fmt .Errorf ("copying %s to %s: %v" , srcPath , dstPath , err )
336+ }
337+ }
338+ testedRepoWorkspacePath := filepath .Join (testedRepoDir , "WORKSPACE" )
339+ testedModuleRepoName := testedModuleName
340+ if _ , err = os .Stat (testedRepoWorkspacePath ); err == nil {
341+ testedModuleRepoName , err = loadWorkspaceName (filepath .Join (testedRepoDir , "WORKSPACE" ))
342+ if err != nil {
343+ return "" , cleanup , fmt .Errorf ("loading workspace name: %v" , err )
344+ }
345+ }
346+
320347 // Create the workspace directory.
321348 mainDir := filepath .Join (execDir , "main" )
322349 if err := os .MkdirAll (mainDir , 0777 ); err != nil {
@@ -337,71 +364,11 @@ func setupWorkspace(args Args, files []string) (dir string, cleanup func() error
337364 return "" , cleanup , err
338365 }
339366
340- // Extract test files for the main workspace .
367+ // Extract test files for the main repository .
341368 if err := extractTxtar (mainDir , args .Main ); err != nil {
342369 return "" , cleanup , fmt .Errorf ("building main workspace: %v" , err )
343370 }
344371
345- // If some of the path arguments are missing an explicit workspace,
346- // read the workspace name from WORKSPACE. We need this to map arguments
347- // to runfiles in specific workspaces.
348- haveDefaultWorkspace := false
349- var defaultWorkspaceName string
350- for _ , argPath := range files {
351- workspace , _ , err := parseLocationArg (argPath )
352- if err == nil && workspace == "" {
353- haveDefaultWorkspace = true
354- cleanPath := path .Clean (argPath )
355- if cleanPath == "WORKSPACE" {
356- defaultWorkspaceName , err = loadWorkspaceName (cleanPath )
357- if err != nil {
358- return "" , cleanup , fmt .Errorf ("could not load default workspace name: %v" , err )
359- }
360- break
361- }
362- }
363- }
364- if haveDefaultWorkspace && defaultWorkspaceName == "" {
365- return "" , cleanup , fmt .Errorf ("found files from default workspace, but not WORKSPACE" )
366- }
367-
368- // Index runfiles by workspace and short path. We need this to determine
369- // destination paths when we copy or link files.
370- runfiles , err := bazel .ListRunfiles ()
371- if err != nil {
372- return "" , cleanup , err
373- }
374-
375- type runfileKey struct { workspace , short string }
376- runfileMap := make (map [runfileKey ]string )
377- for _ , rf := range runfiles {
378- runfileMap [runfileKey {rf .Workspace , rf .ShortPath }] = rf .Path
379- }
380-
381- // Copy or link file arguments from runfiles into fake workspace dirctories.
382- // Keep track of the workspace names we see, since we'll generate a WORKSPACE
383- // with local_repository rules later.
384- workspaceNames := make (map [string ]bool )
385- for _ , argPath := range files {
386- workspace , shortPath , err := parseLocationArg (argPath )
387- if err != nil {
388- return "" , cleanup , err
389- }
390- if workspace == "" {
391- workspace = defaultWorkspaceName
392- }
393- workspaceNames [workspace ] = true
394-
395- srcPath , ok := runfileMap [runfileKey {workspace , shortPath }]
396- if ! ok {
397- return "" , cleanup , fmt .Errorf ("unknown runfile: %s" , argPath )
398- }
399- dstPath := filepath .Join (execDir , workspace , shortPath )
400- if err := copyOrLink (dstPath , srcPath ); err != nil {
401- return "" , cleanup , err
402- }
403- }
404-
405372 // If there's no WORKSPACE file, create one.
406373 workspacePath := filepath .Join (mainDir , "WORKSPACE" )
407374 if _ , err = os .Stat (workspacePath ); os .IsNotExist (err ) {
@@ -415,25 +382,24 @@ func setupWorkspace(args Args, files []string) (dir string, cleanup func() error
415382 err = cerr
416383 }
417384 }()
418- info := workspaceTemplateInfo {
419- Prefix : args .WorkspacePrefix ,
420- Suffix : args .WorkspaceSuffix ,
421- Nogo : args .Nogo ,
422- NogoIncludes : args .NogoIncludes ,
423- NogoExcludes : args .NogoExcludes ,
385+ goRootFilePath , err := runfiles .Rlocation (goRootFile )
386+ if err != nil {
387+ return "" , cleanup , fmt .Errorf ("unknown runfile %s: %v" , goRootFile , err )
424388 }
425- for name := range workspaceNames {
426- info .WorkspaceNames = append (info .WorkspaceNames , name )
389+ // TODO: This is only necessary because of https://github.com/golang/go/issues/59924.
390+ goRootFileRealPath , err := filepath .EvalSymlinks (goRootFilePath )
391+ if err != nil {
392+ return "" , cleanup , fmt .Errorf ("unknown runfile %s: %v" , goRootFile , err )
427393 }
428- sort . Strings ( info . WorkspaceNames )
429- if outBaseDir != "" {
430- goSDKPath := filepath . Join ( outBaseDir , "external" , "go_sdk" )
431- rel , err := filepath . Rel ( mainDir , goSDKPath )
432- if err != nil {
433- return "" , cleanup , fmt . Errorf ( "could not find relative path from %q to %q for go_sdk" , mainDir , goSDKPath )
434- }
435- rel = filepath . ToSlash ( rel )
436- info . GoSDKPath = rel
394+ info := workspaceTemplateInfo {
395+ TestedModuleRepoName : testedModuleRepoName ,
396+ TestedModulePath : testedRepoDir ,
397+ Prefix : args . WorkspacePrefix ,
398+ Suffix : args . WorkspaceSuffix ,
399+ Nogo : args . Nogo ,
400+ NogoIncludes : args . NogoIncludes ,
401+ NogoExcludes : args . NogoExcludes ,
402+ GoSDKPath : filepath . Dir ( goRootFileRealPath ),
437403 }
438404 if err := defaultWorkspaceTpl .Execute (w , info ); err != nil {
439405 return "" , cleanup , err
@@ -456,14 +422,10 @@ func setupWorkspace(args Args, files []string) (dir string, cleanup func() error
456422 err = cerr
457423 }
458424 }()
459- rulesGoAbsPath := filepath .Join (execDir , "io_bazel_rules_go" )
460- rulesGoPath , err := filepath .Rel (mainDir , rulesGoAbsPath )
461- if err != nil {
462- return "" , cleanup , fmt .Errorf ("could not find relative path from %q to %q for io_bazel_rules_go" , mainDir , rulesGoAbsPath )
463- }
464- rulesGoPath = filepath .ToSlash (rulesGoPath )
465425 info := moduleFileTemplateInfo {
466- RulesGoPath : rulesGoPath ,
426+ TestedModuleName : testedModuleName ,
427+ TestedModuleRepoName : testedModuleRepoName ,
428+ TestedModulePath : testedRepoDir ,
467429 Suffix : args .ModuleFileSuffix ,
468430 }
469431 if err := defaultModuleBazelTpl .Execute (w , info ); err != nil {
@@ -489,33 +451,8 @@ func extractTxtar(dir, txt string) error {
489451 return nil
490452}
491453
492- func parseLocationArg (arg string ) (workspace , shortPath string , err error ) {
493- cleanPath := path .Clean (arg )
494- // Support both states of --legacy_external_runfiles.
495- if ! strings .HasPrefix (cleanPath , "../" ) && ! strings .HasPrefix (cleanPath , "external/" ) {
496- return "" , cleanPath , nil
497- }
498- var trimmedPath string
499- if strings .HasPrefix (cleanPath , "../" ) {
500- trimmedPath = cleanPath [len ("../" ):]
501- } else {
502- trimmedPath = cleanPath [len ("external/" ):]
503- }
504- i := strings .IndexByte (trimmedPath , '/' )
505- if i < 0 {
506- return "" , "" , fmt .Errorf ("unexpected file (missing / after ../): %s" , arg )
507- }
508- workspace = trimmedPath [:i ]
509- shortPath = trimmedPath [i + 1 :]
510- return workspace , shortPath , nil
511- }
512-
513454func loadWorkspaceName (workspacePath string ) (string , error ) {
514- runfilePath , err := bazel .Runfile (workspacePath )
515- if err == nil {
516- workspacePath = runfilePath
517- }
518- workspaceData , err := ioutil .ReadFile (workspacePath )
455+ workspaceData , err := os .ReadFile (workspacePath )
519456 if err != nil {
520457 return "" , err
521458 }
@@ -532,7 +469,8 @@ func loadWorkspaceName(workspacePath string) (string, error) {
532469}
533470
534471type workspaceTemplateInfo struct {
535- WorkspaceNames []string
472+ TestedModuleRepoName string
473+ TestedModulePath string
536474 GoSDKPath string
537475 Nogo string
538476 NogoIncludes []string
@@ -542,25 +480,17 @@ type workspaceTemplateInfo struct {
542480}
543481
544482var defaultWorkspaceTpl = template .Must (template .New ("" ).Parse (`
545- {{range .WorkspaceNames}}
546483local_repository(
547- name = "{{.}}",
548- path = "../ {{.}}",
484+ name = "{{.TestedModuleRepoName }}",
485+ path = "{{.TestedModulePath }}",
549486)
550- {{end}}
551487
552488{{.Prefix}}
553489
554- {{if not .GoSDKPath}}
555- load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains")
556-
557- go_rules_dependencies()
558-
559- go_register_toolchains(go_version = "host")
560- {{else}}
561- local_repository(
490+ new_local_repository(
562491 name = "local_go_sdk",
563492 path = "{{.GoSDKPath}}",
493+ build_file_content = "",
564494)
565495
566496load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains", "go_wrap_sdk", "go_register_nogo")
@@ -595,20 +525,22 @@ go_register_nogo(
595525 {{ end}}
596526)
597527{{end}}
598- {{end}}
599528{{.Suffix}}
600529` ))
601530
602531type moduleFileTemplateInfo struct {
603- RulesGoPath string
532+ TestedModuleName string
533+ TestedModuleRepoName string
534+ TestedModulePath string
604535 Suffix string
605536}
606537
538+ // TODO: Also reuse the current Go SDK as in the WORKSPACE file.
607539var defaultModuleBazelTpl = template .Must (template .New ("" ).Parse (`
608- bazel_dep(name = "rules_go ", version = "", repo_name = "io_bazel_rules_go ")
540+ bazel_dep(name = "{{.TestedModuleName}} ", repo_name = "{{.TestedModuleRepoName}} ")
609541local_path_override(
610- module_name = "rules_go ",
611- path = "{{.RulesGoPath }}",
542+ module_name = "{{.TestedModuleName}} ",
543+ path = "{{.TestedModulePath }}",
612544)
613545{{.Suffix}}
614546` ))
0 commit comments