1
// Copyright 2011 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
23
// A Package describes a single package found in a directory.
25
// Note: These fields are part of the go command's public API.
26
// See list.go. It is okay to add fields, but not to change or
27
// remove existing ones. Keep in sync with list.go
28
Dir string `json:",omitempty"` // directory containing package sources
29
ImportPath string `json:",omitempty"` // import path of package in dir
30
Name string `json:",omitempty"` // package name
31
Doc string `json:",omitempty"` // package documentation string
32
Target string `json:",omitempty"` // install path
33
Goroot bool `json:",omitempty"` // is this package found in the Go root?
34
Standard bool `json:",omitempty"` // is this package part of the standard Go library?
35
Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
36
Root string `json:",omitempty"` // Go root or Go path dir containing this package
37
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
40
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
41
CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
42
IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
43
CFiles []string `json:",omitempty"` // .c source files
44
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
45
HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
46
SFiles []string `json:",omitempty"` // .s source files
47
SwigFiles []string `json:",omitempty"` // .swig files
48
SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
49
SysoFiles []string `json:",omitempty"` // .syso system object files added to package
52
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
53
CgoCPPFLAGS []string `json:",omitempty"` // cgo: flags for C preprocessor
54
CgoCXXFLAGS []string `json:",omitempty"` // cgo: flags for C++ compiler
55
CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker
56
CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
58
// Dependency information
59
Imports []string `json:",omitempty"` // import paths used by this package
60
Deps []string `json:",omitempty"` // all (recursively) imported dependencies
63
Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
64
Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
65
DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
68
TestGoFiles []string `json:",omitempty"` // _test.go files in package
69
TestImports []string `json:",omitempty"` // imports from TestGoFiles
70
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
71
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
73
// Unexported fields are not part of the public API.
75
pkgdir string // overrides build.PkgDir
78
gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
80
allgofiles []string // gofiles + IgnoredGoFiles, absolute paths
81
target string // installed file for this package (may be executable)
82
fake bool // synthesized package
83
forceBuild bool // this package must be rebuilt
84
forceLibrary bool // this package is a library (even if named "main")
85
cmdline bool // defined by files listed on command line
86
local bool // imported via local path (./ or ../)
87
localPrefix string // interpret ./ and ../ imports relative to this prefix
88
exeName string // desired name for temporary executable
89
coverMode string // preprocess Go source files with the coverage tool in this mode
90
coverVars map[string]*CoverVar // variables created by coverage analysis
93
// CoverVar holds the name of the generated coverage variables targeting the named file.
94
type CoverVar struct {
95
File string // local file name
96
Var string // name of count struct
99
func (p *Package) copyBuild(pp *build.Package) {
103
p.ImportPath = pp.ImportPath
107
p.ConflictDir = pp.ConflictDir
110
p.Standard = p.Goroot && p.ImportPath != "" && !strings.Contains(p.ImportPath, ".")
111
p.GoFiles = pp.GoFiles
112
p.CgoFiles = pp.CgoFiles
113
p.IgnoredGoFiles = pp.IgnoredGoFiles
115
p.CXXFiles = pp.CXXFiles
118
p.SwigFiles = pp.SwigFiles
119
p.SwigCXXFiles = pp.SwigCXXFiles
120
p.SysoFiles = pp.SysoFiles
121
p.CgoCFLAGS = pp.CgoCFLAGS
122
p.CgoCPPFLAGS = pp.CgoCPPFLAGS
123
p.CgoCXXFLAGS = pp.CgoCXXFLAGS
124
p.CgoLDFLAGS = pp.CgoLDFLAGS
125
p.CgoPkgConfig = pp.CgoPkgConfig
126
p.Imports = pp.Imports
127
p.TestGoFiles = pp.TestGoFiles
128
p.TestImports = pp.TestImports
129
p.XTestGoFiles = pp.XTestGoFiles
130
p.XTestImports = pp.XTestImports
133
// A PackageError describes an error loading information about a package.
134
type PackageError struct {
135
ImportStack []string // shortest path from package named on command line to this one
136
Pos string // position of error
137
Err string // the error itself
138
isImportCycle bool // the error is an import cycle
141
func (p *PackageError) Error() string {
142
// Import cycles deserve special treatment.
144
return fmt.Sprintf("%s: %s\npackage %s\n", p.Pos, p.Err, strings.Join(p.ImportStack, "\n\timports "))
147
// Omit import stack. The full path to the file where the error
148
// is the most important thing.
149
return p.Pos + ": " + p.Err
151
if len(p.ImportStack) == 0 {
154
return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
157
// An importStack is a stack of import paths.
158
type importStack []string
160
func (s *importStack) push(p string) {
164
func (s *importStack) pop() {
165
*s = (*s)[0 : len(*s)-1]
168
func (s *importStack) copy() []string {
169
return append([]string{}, *s...)
172
// shorterThan returns true if sp is shorter than t.
173
// We use this to record the shortest import sequence
174
// that leads to a particular package.
175
func (sp *importStack) shorterThan(t []string) bool {
177
if len(s) != len(t) {
178
return len(s) < len(t)
180
// If they are the same length, settle ties using string ordering.
186
return false // they are equal
189
// packageCache is a lookup cache for loadPackage,
190
// so that if we look up a package multiple times
191
// we return the same pointer each time.
192
var packageCache = map[string]*Package{}
194
// reloadPackage is like loadPackage but makes sure
195
// not to use the package cache.
196
func reloadPackage(arg string, stk *importStack) *Package {
197
p := packageCache[arg]
199
delete(packageCache, p.Dir)
200
delete(packageCache, p.ImportPath)
202
return loadPackage(arg, stk)
205
// dirToImportPath returns the pseudo-import path we use for a package
206
// outside the Go path. It begins with _/ and then contains the full path
207
// to the directory. If the package lives in c:\home\gopher\my\pkg then
208
// the pseudo-import path is _/c_/home/gopher/my/pkg.
209
// Using a pseudo-import path like this makes the ./ imports no longer
210
// a special case, so that all the code to deal with ordinary imports works
212
func dirToImportPath(dir string) string {
213
return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir)))
216
func makeImportValid(r rune) rune {
217
// Should match Go spec, compilers, and ../../pkg/go/parser/parser.go:/isValidImport.
218
const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
219
if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
225
// loadImport scans the directory named by path, which must be an import path,
226
// but possibly a local import path (an absolute file system path or one beginning
227
// with ./ or ../). A local relative path is interpreted relative to srcDir.
228
// It returns a *Package describing the package found in that directory.
229
func loadImport(path string, srcDir string, stk *importStack, importPos []token.Position) *Package {
233
// Determine canonical identifier for this package.
234
// For a local import the identifier is the pseudo-import path
235
// we create from the full directory to the package.
236
// Otherwise it is the usual import path.
238
isLocal := build.IsLocalImport(path)
240
importPath = dirToImportPath(filepath.Join(srcDir, path))
242
if p := packageCache[importPath]; p != nil {
243
return reusePackage(p, stk)
248
p.ImportPath = importPath
249
packageCache[importPath] = p
252
// Import always returns bp != nil, even if an error occurs,
253
// in order to return partial information.
255
// TODO: After Go 1, decide when to pass build.AllowBinary here.
256
// See issue 3268 for mistakes to avoid.
257
bp, err := buildContext.Import(path, srcDir, 0)
258
bp.ImportPath = importPath
263
if p.Error != nil && len(importPos) > 0 {
265
pos.Filename = shortPath(pos.Filename)
266
p.Error.Pos = pos.String()
272
// reusePackage reuses package p to satisfy the import at the top
273
// of the import stack stk. If this use causes an import loop,
274
// reusePackage updates p's error information to record the loop.
275
func reusePackage(p *Package, stk *importStack) *Package {
276
// We use p.imports==nil to detect a package that
277
// is in the midst of its own loadPackage call
278
// (all the recursion below happens before p.imports gets set).
279
if p.imports == nil {
281
p.Error = &PackageError{
282
ImportStack: stk.copy(),
283
Err: "import cycle not allowed",
289
// Don't rewrite the import stack in the error if we have an import cycle.
290
// If we do, we'll lose the path that describes the cycle.
291
if p.Error != nil && !p.Error.isImportCycle && stk.shorterThan(p.Error.ImportStack) {
292
p.Error.ImportStack = stk.copy()
300
toRoot targetDir = iota // to bin dir inside package root (default)
301
toTool // GOROOT/pkg/tool
305
// goTools is a map of Go program import path to install target directory.
306
var goTools = map[string]targetDir{
311
"code.google.com/p/go.tools/cmd/cover": toTool,
312
"code.google.com/p/go.tools/cmd/godoc": toBin,
313
"code.google.com/p/go.tools/cmd/vet": toTool,
316
// expandScanner expands a scanner.List error into all the errors in the list.
317
// The default Error method only shows the first error.
318
func expandScanner(err error) error {
319
// Look for parser errors.
320
if err, ok := err.(scanner.ErrorList); ok {
321
// Prepare error with \n before each message.
322
// When printed in something like context: %v
323
// this will put the leading file positions each on
324
// its own line. It will also show all the errors
325
// instead of just the first, as err.Error does.
327
for _, e := range err {
328
e.Pos.Filename = shortPath(e.Pos.Filename)
329
buf.WriteString("\n")
330
buf.WriteString(e.Error())
332
return errors.New(buf.String())
337
var raceExclude = map[string]bool{
338
"runtime/race": true,
345
var cgoExclude = map[string]bool{
349
var cgoSyscallExclude = map[string]bool{
351
"runtime/race": true,
354
// load populates p using information from bp, err, which should
355
// be the result of calling build.Context.Import.
356
func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package {
359
// The localPrefix is the path we interpret ./ imports relative to.
360
// Synthesized main packages sometimes override this.
361
p.localPrefix = dirToImportPath(p.Dir)
365
err = expandScanner(err)
366
p.Error = &PackageError{
367
ImportStack: stk.copy(),
373
if p.Name == "main" {
374
_, elem := filepath.Split(p.Dir)
375
full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
376
if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {
377
// Install cross-compiled binaries to subdirectories of bin.
380
if p.build.BinDir != gobin && goTools[p.ImportPath] == toBin {
382
// This is from a subrepo but installs to $GOROOT/bin
383
// by default anyway (like godoc).
384
p.target = filepath.Join(gorootBin, elem)
385
} else if p.build.BinDir != "" {
386
// Install to GOBIN or bin of GOPATH entry.
387
p.target = filepath.Join(p.build.BinDir, elem)
389
if goTools[p.ImportPath] == toTool {
390
// This is for 'go tool'.
391
// Override all the usual logic and force it into the tool directory.
392
p.target = filepath.Join(gorootPkg, "tool", full)
394
if p.target != "" && buildContext.GOOS == "windows" {
398
// Local import turned into absolute path.
399
// No permanent install target.
402
p.target = p.build.PkgObj
405
importPaths := p.Imports
406
// Packages that use cgo import runtime/cgo implicitly.
407
// Packages that use cgo also import syscall implicitly,
409
// Exclude certain packages to avoid circular dependencies.
410
if len(p.CgoFiles) > 0 && (!p.Standard || !cgoExclude[p.ImportPath]) {
411
importPaths = append(importPaths, "runtime/cgo")
413
if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
414
importPaths = append(importPaths, "syscall")
416
// Everything depends on runtime, except runtime and unsafe.
417
if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
418
importPaths = append(importPaths, "runtime")
419
// When race detection enabled everything depends on runtime/race.
420
// Exclude certain packages to avoid circular dependencies.
421
if buildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
422
importPaths = append(importPaths, "runtime/race")
426
// Build list of full paths to all Go files in the package,
427
// for use by commands like go fmt.
428
p.gofiles = stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
429
for i := range p.gofiles {
430
p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i])
432
sort.Strings(p.gofiles)
434
p.sfiles = stringList(p.SFiles)
435
for i := range p.sfiles {
436
p.sfiles[i] = filepath.Join(p.Dir, p.sfiles[i])
438
sort.Strings(p.sfiles)
440
p.allgofiles = stringList(p.IgnoredGoFiles)
441
for i := range p.allgofiles {
442
p.allgofiles[i] = filepath.Join(p.Dir, p.allgofiles[i])
444
p.allgofiles = append(p.allgofiles, p.gofiles...)
445
sort.Strings(p.allgofiles)
447
// Check for case-insensitive collision of input files.
448
// To avoid problems on case-insensitive files, we reject any package
449
// where two different input files have equal names under a case-insensitive
451
f1, f2 := foldDup(stringList(
466
p.Error = &PackageError{
467
ImportStack: stk.copy(),
468
Err: fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2),
473
// Build list of imported packages and full dependency list.
474
imports := make([]*Package, 0, len(p.Imports))
475
deps := make(map[string]bool)
476
for i, path := range importPaths {
480
p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])
482
if !p.local && p.Error == nil {
483
p.Error = &PackageError{
484
ImportStack: stk.copy(),
485
Err: fmt.Sprintf("local import %q in non-local package", path),
487
pos := p.build.ImportPos[path]
489
p.Error.Pos = pos[0].String()
493
importPaths[i] = path
496
imports = append(imports, p1)
497
for _, dep := range p1.Deps {
506
p.Deps = make([]string, 0, len(deps))
507
for dep := range deps {
508
p.Deps = append(p.Deps, dep)
511
for _, dep := range p.Deps {
512
p1 := packageCache[dep]
514
panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
516
p.deps = append(p.deps, p1)
518
p.DepsErrors = append(p.DepsErrors, p1.Error)
522
// unsafe is a fake package.
523
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
528
// In the absence of errors lower in the dependency tree,
529
// check for case-insensitive collisions of import paths.
530
if len(p.DepsErrors) == 0 {
531
dep1, dep2 := foldDup(p.Deps)
533
p.Error = &PackageError{
534
ImportStack: stk.copy(),
535
Err: fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2),
544
// usesSwig reports whether the package needs to run SWIG.
545
func (p *Package) usesSwig() bool {
546
return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
549
// usesCgo reports whether the package needs to run cgo
550
func (p *Package) usesCgo() bool {
551
return len(p.CgoFiles) > 0
554
// swigSoname returns the name of the shared library we create for a
556
func (p *Package) swigSoname(file string) string {
557
return strings.Replace(p.ImportPath, "/", "-", -1) + "-" + strings.Replace(file, ".", "-", -1) + ".so"
560
// swigDir returns the name of the shared SWIG directory for a
562
func (p *Package) swigDir(ctxt *build.Context) string {
563
dir := p.build.PkgRoot
564
if ctxt.Compiler == "gccgo" {
565
dir = filepath.Join(dir, "gccgo_"+ctxt.GOOS+"_"+ctxt.GOARCH)
567
dir = filepath.Join(dir, ctxt.GOOS+"_"+ctxt.GOARCH)
569
return filepath.Join(dir, "swig")
572
// packageList returns the list of packages in the dag rooted at roots
573
// as visited in a depth-first post-order traversal.
574
func packageList(roots []*Package) []*Package {
575
seen := map[*Package]bool{}
577
var walk func(*Package)
578
walk = func(p *Package) {
583
for _, p1 := range p.imports {
588
for _, root := range roots {
594
// computeStale computes the Stale flag in the package dag that starts
595
// at the named pkgs (command-line arguments).
596
func computeStale(pkgs ...*Package) {
597
topRoot := map[string]bool{}
598
for _, p := range pkgs {
599
topRoot[p.Root] = true
602
for _, p := range packageList(pkgs) {
603
p.Stale = isStale(p, topRoot)
607
// isStale reports whether package p needs to be rebuilt.
608
func isStale(p *Package, topRoot map[string]bool) bool {
609
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
610
// fake, builtin package
617
// A package without Go sources means we only found
618
// the installed .a file. Since we don't know how to rebuild
619
// it, it can't be stale, even if -a is set. This enables binary-only
620
// distributions of Go packages, although such binaries are
621
// only useful with the specific version of the toolchain that
623
if len(p.gofiles) == 0 && !p.usesSwig() {
627
if buildA || p.target == "" || p.Stale {
631
// Package is stale if completely unbuilt.
633
if fi, err := os.Stat(p.target); err == nil {
640
olderThan := func(file string) bool {
641
fi, err := os.Stat(file)
642
return err != nil || fi.ModTime().After(built)
645
// Package is stale if a dependency is, or if a dependency is newer.
646
for _, p1 := range p.deps {
647
if p1.Stale || p1.target != "" && olderThan(p1.target) {
652
// As a courtesy to developers installing new versions of the compiler
653
// frequently, define that packages are stale if they are
654
// older than the compiler, and commands if they are older than
655
// the linker. This heuristic will not work if the binaries are
656
// back-dated, as some binary distributions may do, but it does handle
657
// a very common case.
659
// Assume code in $GOROOT is up to date, since it may not be writeable.
661
if p.Root != goroot {
662
if olderThan(buildToolchain.compiler()) {
665
if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
670
// Have installed copy, probably built using current compilers,
671
// and built after its imported packages. The only reason now
672
// that we'd have to rebuild it is if the sources were newer than
673
// the package. If a package p is not in the same tree as any
674
// package named on the command-line, assume it is up-to-date
675
// no matter what the modification times on the source files indicate.
676
// This avoids rebuilding $GOROOT packages when people are
677
// working outside the Go root, and it effectively makes each tree
678
// listed in $GOPATH a separate compilation world.
680
if p.Root != "" && !topRoot[p.Root] {
684
srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
685
for _, src := range srcs {
686
if olderThan(filepath.Join(p.Dir, src)) {
694
var cwd, _ = os.Getwd()
696
var cmdCache = map[string]*Package{}
698
// loadPackage is like loadImport but is used for command-line arguments,
699
// not for paths found in import statements. In addition to ordinary import paths,
700
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
701
// in the Go command directory, as well as paths to those directories.
702
func loadPackage(arg string, stk *importStack) *Package {
703
if build.IsLocalImport(arg) {
705
if !filepath.IsAbs(dir) {
706
if abs, err := filepath.Abs(dir); err == nil {
707
// interpret relative to current directory
711
if sub, ok := hasSubdir(gorootSrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
715
if strings.HasPrefix(arg, "cmd/") {
716
if p := cmdCache[arg]; p != nil {
722
if strings.Contains(arg[4:], "/") {
724
Error: &PackageError{
725
ImportStack: stk.copy(),
726
Err: fmt.Sprintf("invalid import path: cmd/... is reserved for Go commands"),
732
bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)
735
bp.BinDir = gorootBin
740
bp.SrcRoot = gorootSrc
744
if p.Error == nil && p.Name != "main" {
745
p.Error = &PackageError{
746
ImportStack: stk.copy(),
747
Err: fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
753
// Wasn't a command; must be a package.
754
// If it is a local import path but names a standard package,
755
// we treat it as if the user specified the standard package.
756
// This lets you run go test ./ioutil in package io and be
757
// referring to io/ioutil rather than a hypothetical import of
759
if build.IsLocalImport(arg) {
760
bp, _ := buildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
761
if bp.ImportPath != "" && bp.ImportPath != "." {
766
return loadImport(arg, cwd, stk, nil)
769
// packages returns the packages named by the
770
// command line arguments 'args'. If a named package
771
// cannot be loaded at all (for example, if the directory does not exist),
772
// then packages prints an error and does not include that
773
// package in the results. However, if errors occur trying
774
// to load dependencies of a named package, the named
775
// package is still returned, with p.Incomplete = true
776
// and details in p.DepsErrors.
777
func packages(args []string) []*Package {
779
for _, pkg := range packagesAndErrors(args) {
780
if pkg.Error != nil {
781
errorf("can't load package: %s", pkg.Error)
784
pkgs = append(pkgs, pkg)
789
// packagesAndErrors is like 'packages' but returns a
790
// *Package for every argument, even the ones that
791
// cannot be loaded at all.
792
// The packages that fail to load will have p.Error != nil.
793
func packagesAndErrors(args []string) []*Package {
794
if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
795
return []*Package{goFilesPackage(args)}
798
args = importPaths(args)
801
var set = make(map[string]bool)
803
for _, arg := range args {
805
pkgs = append(pkgs, loadPackage(arg, &stk))
809
computeStale(pkgs...)
814
// packagesForBuild is like 'packages' but fails if any of
815
// the packages or their dependencies have errors
816
// (cannot be built).
817
func packagesForBuild(args []string) []*Package {
818
pkgs := packagesAndErrors(args)
819
printed := map[*PackageError]bool{}
820
for _, pkg := range pkgs {
821
if pkg.Error != nil {
822
errorf("can't load package: %s", pkg.Error)
824
for _, err := range pkg.DepsErrors {
825
// Since these are errors in dependencies,
826
// the same error might show up multiple times,
827
// once in each package that depends on it.
828
// Only print each once.
839
// hasSubdir reports whether dir is a subdirectory of
840
// (possibly multiple levels below) root.
841
// If so, it sets rel to the path fragment that must be
842
// appended to root to reach dir.
843
func hasSubdir(root, dir string) (rel string, ok bool) {
844
if p, err := filepath.EvalSymlinks(root); err == nil {
847
if p, err := filepath.EvalSymlinks(dir); err == nil {
850
const sep = string(filepath.Separator)
851
root = filepath.Clean(root)
852
if !strings.HasSuffix(root, sep) {
855
dir = filepath.Clean(dir)
856
if !strings.HasPrefix(dir, root) {
859
return filepath.ToSlash(dir[len(root):]), true