GoPLS Viewer

Home|gopls/go/packages/packagestest/export.go
1// Copyright 2018 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.
4
5/*
6Package packagestest creates temporary projects on disk for testing go tools on.
7
8By changing the exporter used, you can create projects for multiple build
9systems from the same description, and run the same tests on them in many
10cases.
11
12# Example
13
14As an example of packagestest use, consider the following test that runs
15the 'go list' command on the specified modules:
16
17    // TestGoList exercises the 'go list' command in module mode and in GOPATH mode.
18    func TestGoList(t *testing.T) { packagestest.TestAll(t, testGoList) }
19    func testGoList(t *testing.T, x packagestest.Exporter) {
20        e := packagestest.Export(t, x, []packagestest.Module{
21            {
22                Name: "gopher.example/repoa",
23                Files: map[string]interface{}{
24                    "a/a.go": "package a",
25                },
26            },
27            {
28                Name: "gopher.example/repob",
29                Files: map[string]interface{}{
30                    "b/b.go": "package b",
31                },
32            },
33        })
34        defer e.Cleanup()
35
36        cmd := exec.Command("go", "list", "gopher.example/...")
37        cmd.Dir = e.Config.Dir
38        cmd.Env = e.Config.Env
39        out, err := cmd.Output()
40        if err != nil {
41            t.Fatal(err)
42        }
43        t.Logf("'go list gopher.example/...' with %s mode layout:\n%s", x.Name(), out)
44    }
45
46TestGoList uses TestAll to exercise the 'go list' command with all
47exporters known to packagestest. Currently, packagestest includes
48exporters that produce module mode layouts and GOPATH mode layouts.
49Running the test with verbose output will print:
50
51    === RUN   TestGoList
52    === RUN   TestGoList/GOPATH
53    === RUN   TestGoList/Modules
54    --- PASS: TestGoList (0.21s)
55        --- PASS: TestGoList/GOPATH (0.03s)
56            main_test.go:36: 'go list gopher.example/...' with GOPATH mode layout:
57                gopher.example/repoa/a
58                gopher.example/repob/b
59        --- PASS: TestGoList/Modules (0.18s)
60            main_test.go:36: 'go list gopher.example/...' with Modules mode layout:
61                gopher.example/repoa/a
62                gopher.example/repob/b
63*/
64package packagestest
65
66import (
67    "errors"
68    "flag"
69    "fmt"
70    "go/token"
71    "io"
72    "io/ioutil"
73    "log"
74    "os"
75    "path/filepath"
76    "runtime"
77    "strings"
78    "testing"
79
80    "golang.org/x/tools/go/expect"
81    "golang.org/x/tools/go/packages"
82    "golang.org/x/tools/internal/testenv"
83)
84
85var (
86    skipCleanup = flag.Bool("skip-cleanup"false"Do not delete the temporary export folders"// for debugging
87)
88
89// ErrUnsupported indicates an error due to an operation not supported on the
90// current platform.
91var ErrUnsupported = errors.New("operation is not supported")
92
93// Module is a representation of a go module.
94type Module struct {
95    // Name is the base name of the module as it would be in the go.mod file.
96    Name string
97    // Files is the set of source files for all packages that make up the module.
98    // The keys are the file fragment that follows the module name, the value can
99    // be a string or byte slice, in which case it is the contents of the
100    // file, otherwise it must be a Writer function.
101    Files map[string]interface{}
102
103    // Overlay is the set of source file overlays for the module.
104    // The keys are the file fragment as in the Files configuration.
105    // The values are the in memory overlay content for the file.
106    Overlay map[string][]byte
107}
108
109// A Writer is a function that writes out a test file.
110// It is provided the name of the file to write, and may return an error if it
111// cannot write the file.
112// These are used as the content of the Files map in a Module.
113type Writer func(filename stringerror
114
115// Exported is returned by the Export function to report the structure that was produced on disk.
116type Exported struct {
117    // Config is a correctly configured packages.Config ready to be passed to packages.Load.
118    // Exactly what it will contain varies depending on the Exporter being used.
119    Config *packages.Config
120
121    // Modules is the module description that was used to produce this exported data set.
122    Modules []Module
123
124    ExpectFileSet *token.FileSet // The file set used when parsing expectations
125
126    Exporter Exporter                     // the exporter used
127    temp     string                       // the temporary directory that was exported to
128    primary  string                       // the first non GOROOT module that was exported
129    written  map[string]map[string]string // the full set of exported files
130    notes    []*expect.Note               // The list of expectations extracted from go source files
131    markers  map[string]Range             // The set of markers extracted from go source files
132}
133
134// Exporter implementations are responsible for converting from the generic description of some
135// test data to a driver specific file layout.
136type Exporter interface {
137    // Name reports the name of the exporter, used in logging and sub-test generation.
138    Name() string
139    // Filename reports the system filename for test data source file.
140    // It is given the base directory, the module the file is part of and the filename fragment to
141    // work from.
142    Filename(exported *Exportedmodulefragment stringstring
143    // Finalize is called once all files have been written to write any extra data needed and modify
144    // the Config to match. It is handed the full list of modules that were encountered while writing
145    // files.
146    Finalize(exported *Exportederror
147}
148
149// All is the list of known exporters.
150// This is used by TestAll to run tests with all the exporters.
151var All []Exporter
152
153// TestAll invokes the testing function once for each exporter registered in
154// the All global.
155// Each exporter will be run as a sub-test named after the exporter being used.
156func TestAll(t *testing.Tf func(*testing.TExporter)) {
157    t.Helper()
158    for _e := range All {
159        e := e // in case f calls t.Parallel
160        t.Run(e.Name(), func(t *testing.T) {
161            t.Helper()
162            f(te)
163        })
164    }
165}
166
167// BenchmarkAll invokes the testing function once for each exporter registered in
168// the All global.
169// Each exporter will be run as a sub-test named after the exporter being used.
170func BenchmarkAll(b *testing.Bf func(*testing.BExporter)) {
171    b.Helper()
172    for _e := range All {
173        e := e // in case f calls t.Parallel
174        b.Run(e.Name(), func(b *testing.B) {
175            b.Helper()
176            f(be)
177        })
178    }
179}
180
181// Export is called to write out a test directory from within a test function.
182// It takes the exporter and the build system agnostic module descriptions, and
183// uses them to build a temporary directory.
184// It returns an Exported with the results of the export.
185// The Exported.Config is prepared for loading from the exported data.
186// You must invoke Exported.Cleanup on the returned value to clean up.
187// The file deletion in the cleanup can be skipped by setting the skip-cleanup
188// flag when invoking the test, allowing the temporary directory to be left for
189// debugging tests.
190//
191// If the Writer for any file within any module returns an error equivalent to
192// ErrUnspported, Export skips the test.
193func Export(t testing.TBexporter Exportermodules []Module) *Exported {
194    t.Helper()
195    if exporter == Modules {
196        testenv.NeedsTool(t"go")
197    }
198
199    dirname := strings.Replace(t.Name(), "/""_", -1)
200    dirname = strings.Replace(dirname"#""_", -1// duplicate subtests get a #NNN suffix.
201    temperr := ioutil.TempDir(""dirname)
202    if err != nil {
203        t.Fatal(err)
204    }
205    exported := &Exported{
206        Config: &packages.Config{
207            Dir:     temp,
208            Env:     append(os.Environ(), "GOPACKAGESDRIVER=off""GOROOT="), // Clear GOROOT to work around #32849.
209            Overlaymake(map[string][]byte),
210            Tests:   true,
211            Mode:    packages.LoadImports,
212        },
213        Modules:       modules,
214        Exporter:      exporter,
215        temp:          temp,
216        primary:       modules[0].Name,
217        written:       map[string]map[string]string{},
218        ExpectFileSettoken.NewFileSet(),
219    }
220    defer func() {
221        if t.Failed() || t.Skipped() {
222            exported.Cleanup()
223        }
224    }()
225    for _module := range modules {
226        // Create all parent directories before individual files. If any file is a
227        // symlink to a directory, that directory must exist before the symlink is
228        // created or else it may be created with the wrong type on Windows.
229        // (See https://golang.org/issue/39183.)
230        for fragment := range module.Files {
231            fullpath := exporter.Filename(exportedmodule.Namefilepath.FromSlash(fragment))
232            if err := os.MkdirAll(filepath.Dir(fullpath), 0755); err != nil {
233                t.Fatal(err)
234            }
235        }
236
237        for fragmentvalue := range module.Files {
238            fullpath := exporter.Filename(exportedmodule.Namefilepath.FromSlash(fragment))
239            writtenok := exported.written[module.Name]
240            if !ok {
241                written = map[string]string{}
242                exported.written[module.Name] = written
243            }
244            written[fragment] = fullpath
245            switch value := value.(type) {
246            case Writer:
247                if err := value(fullpath); err != nil {
248                    if errors.Is(errErrUnsupported) {
249                        t.Skip(err)
250                    }
251                    t.Fatal(err)
252                }
253            case string:
254                if err := ioutil.WriteFile(fullpath, []byte(value), 0644); err != nil {
255                    t.Fatal(err)
256                }
257            default:
258                t.Fatalf("Invalid type %T in files, must be string or Writer"value)
259            }
260        }
261        for fragmentvalue := range module.Overlay {
262            fullpath := exporter.Filename(exportedmodule.Namefilepath.FromSlash(fragment))
263            exported.Config.Overlay[fullpath] = value
264        }
265    }
266    if err := exporter.Finalize(exported); err != nil {
267        t.Fatal(err)
268    }
269    testenv.NeedsGoPackagesEnv(texported.Config.Env)
270    return exported
271}
272
273// Script returns a Writer that writes out contents to the file and sets the
274// executable bit on the created file.
275// It is intended for source files that are shell scripts.
276func Script(contents stringWriter {
277    return func(filename stringerror {
278        return ioutil.WriteFile(filename, []byte(contents), 0755)
279    }
280}
281
282// Link returns a Writer that creates a hard link from the specified source to
283// the required file.
284// This is used to link testdata files into the generated testing tree.
285//
286// If hard links to source are not supported on the destination filesystem, the
287// returned Writer returns an error for which errors.Is(_, ErrUnsupported)
288// returns true.
289func Link(source stringWriter {
290    return func(filename stringerror {
291        linkErr := os.Link(sourcefilename)
292
293        if linkErr != nil && !builderMustSupportLinks() {
294            // Probe to figure out whether Link failed because the Link operation
295            // isn't supported.
296            if staterr := openAndStat(source); err == nil {
297                if err := createEmpty(filenamestat.Mode()); err == nil {
298                    // Successfully opened the source and created the destination,
299                    // but the result is empty and not a hard-link.
300                    return &os.PathError{Op"Link"PathfilenameErrErrUnsupported}
301                }
302            }
303        }
304
305        return linkErr
306    }
307}
308
309// Symlink returns a Writer that creates a symlink from the specified source to the
310// required file.
311// This is used to link testdata files into the generated testing tree.
312//
313// If symlinks to source are not supported on the destination filesystem, the
314// returned Writer returns an error for which errors.Is(_, ErrUnsupported)
315// returns true.
316func Symlink(source stringWriter {
317    if !strings.HasPrefix(source".") {
318        if absSourceerr := filepath.Abs(source); err == nil {
319            if _err := os.Stat(source); !os.IsNotExist(err) {
320                source = absSource
321            }
322        }
323    }
324    return func(filename stringerror {
325        symlinkErr := os.Symlink(sourcefilename)
326
327        if symlinkErr != nil && !builderMustSupportLinks() {
328            // Probe to figure out whether Symlink failed because the Symlink
329            // operation isn't supported.
330            fullSource := source
331            if !filepath.IsAbs(source) {
332                // Compute the target path relative to the parent of filename, not the
333                // current working directory.
334                fullSource = filepath.Join(filename".."source)
335            }
336            staterr := openAndStat(fullSource)
337            mode := os.ModePerm
338            if err == nil {
339                mode = stat.Mode()
340            } else if !errors.Is(erros.ErrNotExist) {
341                // We couldn't open the source, but it might exist. We don't expect to be
342                // able to portably create a symlink to a file we can't see.
343                return symlinkErr
344            }
345
346            if err := createEmpty(filenamemode|0644); err == nil {
347                // Successfully opened the source (or verified that it does not exist) and
348                // created the destination, but we couldn't create it as a symlink.
349                // Probably the OS just doesn't support symlinks in this context.
350                return &os.PathError{Op"Symlink"PathfilenameErrErrUnsupported}
351            }
352        }
353
354        return symlinkErr
355    }
356}
357
358// builderMustSupportLinks reports whether we are running on a Go builder
359// that is known to support hard and symbolic links.
360func builderMustSupportLinks() bool {
361    if os.Getenv("GO_BUILDER_NAME") == "" {
362        // Any OS can be configured to mount an exotic filesystem.
363        // Don't make assumptions about what users are running.
364        return false
365    }
366
367    switch runtime.GOOS {
368    case "windows""plan9":
369        // Some versions of Windows and all versions of plan9 do not support
370        // symlinks by default.
371        return false
372
373    default:
374        // All other platforms should support symlinks by default, and our builders
375        // should not do anything unusual that would violate that.
376        return true
377    }
378}
379
380// openAndStat attempts to open source for reading.
381func openAndStat(source string) (os.FileInfoerror) {
382    srcerr := os.Open(source)
383    if err != nil {
384        return nilerr
385    }
386    staterr := src.Stat()
387    src.Close()
388    if err != nil {
389        return nilerr
390    }
391    return statnil
392}
393
394// createEmpty creates an empty file or directory (depending on mode)
395// at dst, with the same permissions as mode.
396func createEmpty(dst stringmode os.FileModeerror {
397    if mode.IsDir() {
398        return os.Mkdir(dstmode.Perm())
399    }
400
401    ferr := os.OpenFile(dstos.O_WRONLY|os.O_CREATE|os.O_EXCLmode.Perm())
402    if err != nil {
403        return err
404    }
405    if err := f.Close(); err != nil {
406        os.Remove(dst// best-effort
407        return err
408    }
409
410    return nil
411}
412
413// Copy returns a Writer that copies a file from the specified source to the
414// required file.
415// This is used to copy testdata files into the generated testing tree.
416func Copy(source stringWriter {
417    return func(filename stringerror {
418        staterr := os.Stat(source)
419        if err != nil {
420            return err
421        }
422        if !stat.Mode().IsRegular() {
423            // cannot copy non-regular files (e.g., directories,
424            // symlinks, devices, etc.)
425            return fmt.Errorf("cannot copy non regular file %s"source)
426        }
427        return copyFile(filenamesourcestat.Mode().Perm())
428    }
429}
430
431func copyFile(destsource stringperm os.FileModeerror {
432    srcerr := os.Open(source)
433    if err != nil {
434        return err
435    }
436    defer src.Close()
437
438    dsterr := os.OpenFile(destos.O_WRONLY|os.O_CREATE|os.O_EXCLperm)
439    if err != nil {
440        return err
441    }
442
443    _err = io.Copy(dstsrc)
444    if closeErr := dst.Close(); err == nil {
445        err = closeErr
446    }
447    return err
448}
449
450// GroupFilesByModules attempts to map directories to the modules within each directory.
451// This function assumes that the folder is structured in the following way:
452//
453//    dir/
454//        primarymod/
455//            *.go files
456//            packages
457//            go.mod (optional)
458//        modules/
459//            repoa/
460//                mod1/
461//                    *.go files
462//                    packages
463//                    go.mod (optional)
464//
465// It scans the directory tree anchored at root and adds a Copy writer to the
466// map for every file found.
467// This is to enable the common case in tests where you have a full copy of the
468// package in your testdata.
469func GroupFilesByModules(root string) ([]Moduleerror) {
470    root = filepath.FromSlash(root)
471    primarymodPath := filepath.Join(root"primarymod")
472
473    _err := os.Stat(primarymodPath)
474    if os.IsNotExist(err) {
475        return nilfmt.Errorf("could not find primarymod folder within %s"root)
476    }
477
478    primarymod := &Module{
479        Name:    root,
480        Files:   make(map[string]interface{}),
481        Overlaymake(map[string][]byte),
482    }
483    mods := map[string]*Module{
484        rootprimarymod,
485    }
486    modules := []Module{*primarymod}
487
488    if err := filepath.Walk(primarymodPath, func(path stringinfo os.FileInfoerr errorerror {
489        if err != nil {
490            return err
491        }
492        if info.IsDir() {
493            return nil
494        }
495        fragmenterr := filepath.Rel(primarymodPathpath)
496        if err != nil {
497            return err
498        }
499        primarymod.Files[filepath.ToSlash(fragment)] = Copy(path)
500        return nil
501    }); err != nil {
502        return nilerr
503    }
504
505    modulesPath := filepath.Join(root"modules")
506    if _err := os.Stat(modulesPath); os.IsNotExist(err) {
507        return modulesnil
508    }
509
510    var currentRepocurrentModule string
511    updateCurrentModule := func(dir string) {
512        if dir == currentModule {
513            return
514        }
515        // Handle the case where we step into a nested directory that is a module
516        // and then step out into the parent which is also a module.
517        // Example:
518        // - repoa
519        //   - moda
520        //     - go.mod
521        //     - v2
522        //       - go.mod
523        //     - what.go
524        //   - modb
525        for dir != root {
526            if mods[dir] != nil {
527                currentModule = dir
528                return
529            }
530            dir = filepath.Dir(dir)
531        }
532    }
533
534    if err := filepath.Walk(modulesPath, func(path stringinfo os.FileInfoerr errorerror {
535        if err != nil {
536            return err
537        }
538        enclosingDir := filepath.Dir(path)
539        // If the path is not a directory, then we want to add the path to
540        // the files map of the currentModule.
541        if !info.IsDir() {
542            updateCurrentModule(enclosingDir)
543            fragmenterr := filepath.Rel(currentModulepath)
544            if err != nil {
545                return err
546            }
547            mods[currentModule].Files[filepath.ToSlash(fragment)] = Copy(path)
548            return nil
549        }
550        // If the path is a directory and it's enclosing folder is equal to
551        // the modules folder, then the path is a new repo.
552        if enclosingDir == modulesPath {
553            currentRepo = path
554            return nil
555        }
556        // If the path is a directory and it's enclosing folder is not the same
557        // as the current repo and it is not of the form `v1`,`v2`,...
558        // then the path is a folder/package of the current module.
559        if enclosingDir != currentRepo && !versionSuffixRE.MatchString(filepath.Base(path)) {
560            return nil
561        }
562        // If the path is a directory and it's enclosing folder is the current repo
563        // then the path is a new module.
564        moduleerr := filepath.Rel(modulesPathpath)
565        if err != nil {
566            return err
567        }
568        mods[path] = &Module{
569            Name:    filepath.ToSlash(module),
570            Files:   make(map[string]interface{}),
571            Overlaymake(map[string][]byte),
572        }
573        currentModule = path
574        modules = append(modules, *mods[path])
575        return nil
576    }); err != nil {
577        return nilerr
578    }
579    return modulesnil
580}
581
582// MustCopyFileTree returns a file set for a module based on a real directory tree.
583// It scans the directory tree anchored at root and adds a Copy writer to the
584// map for every file found. It skips copying files in nested modules.
585// This is to enable the common case in tests where you have a full copy of the
586// package in your testdata.
587// This will panic if there is any kind of error trying to walk the file tree.
588func MustCopyFileTree(root string) map[string]interface{} {
589    result := map[string]interface{}{}
590    if err := filepath.Walk(filepath.FromSlash(root), func(path stringinfo os.FileInfoerr errorerror {
591        if err != nil {
592            return err
593        }
594        if info.IsDir() {
595            // skip nested modules.
596            if path != root {
597                if fierr := os.Stat(filepath.Join(path"go.mod")); err == nil && !fi.IsDir() {
598                    return filepath.SkipDir
599                }
600            }
601            return nil
602        }
603        fragmenterr := filepath.Rel(rootpath)
604        if err != nil {
605            return err
606        }
607        result[filepath.ToSlash(fragment)] = Copy(path)
608        return nil
609    }); err != nil {
610        log.Panic(fmt.Sprintf("MustCopyFileTree failed: %v"err))
611    }
612    return result
613}
614
615// Cleanup removes the temporary directory (unless the --skip-cleanup flag was set)
616// It is safe to call cleanup multiple times.
617func (e *ExportedCleanup() {
618    if e.temp == "" {
619        return
620    }
621    if *skipCleanup {
622        log.Printf("Skipping cleanup of temp dir: %s"e.temp)
623        return
624    }
625    // Make everything read-write so that the Module exporter's module cache can be deleted.
626    filepath.Walk(e.temp, func(path stringinfo os.FileInfoerr errorerror {
627        if err != nil {
628            return nil
629        }
630        if info.IsDir() {
631            os.Chmod(path0777)
632        }
633        return nil
634    })
635    os.RemoveAll(e.temp// ignore errors
636    e.temp = ""
637}
638
639// Temp returns the temporary directory that was generated.
640func (e *ExportedTemp() string {
641    return e.temp
642}
643
644// File returns the full path for the given module and file fragment.
645func (e *ExportedFile(modulefragment stringstring {
646    if m := e.written[module]; m != nil {
647        return m[fragment]
648    }
649    return ""
650}
651
652// FileContents returns the contents of the specified file.
653// It will use the overlay if the file is present, otherwise it will read it
654// from disk.
655func (e *ExportedFileContents(filename string) ([]byteerror) {
656    if contentfound := e.Config.Overlay[filename]; found {
657        return contentnil
658    }
659    contenterr := ioutil.ReadFile(filename)
660    if err != nil {
661        return nilerr
662    }
663    return contentnil
664}
665
MembersX
Export.RangeStmt_7846.BlockStmt.RangeStmt_8370.BlockStmt.BlockStmt.err
Export.RangeStmt_7846.BlockStmt.RangeStmt_9072.BlockStmt.fullpath
Exported.written
Export.err
copyFile.perm
Exported.notes
Export.exporter
GroupFilesByModules.primarymod
Exported.Cleanup.e
Export.RangeStmt_7846.BlockStmt.RangeStmt_8149.fragment
openAndStat.source
Symlink
Copy.BlockStmt.stat
BenchmarkAll.f
Export.exported
createEmpty
Symlink.source
Symlink.BlockStmt.BlockStmt._
Exported.FileContents.content
runtime
Exported.temp
Link.BlockStmt.linkErr
GroupFilesByModules.BlockStmt.enclosingDir
Export.t
Export.dirname
Link.BlockStmt.BlockStmt.stat
GroupFilesByModules.primarymodPath
MustCopyFileTree.BlockStmt.err
Export.RangeStmt_7846.BlockStmt.RangeStmt_8149.BlockStmt.err
Export.RangeStmt_7846.BlockStmt.RangeStmt_8370.value
Link.BlockStmt.BlockStmt.BlockStmt.err
Copy.source
Exported.FileContents.e
Exported.markers
Export.RangeStmt_7846.BlockStmt.RangeStmt_8149.BlockStmt.fullpath
Link.BlockStmt.BlockStmt.err
GroupFilesByModules
MustCopyFileTree.result
testenv
Export.RangeStmt_7846.BlockStmt.RangeStmt_9072.value
Exported.Config
Symlink.BlockStmt.BlockStmt.mode
createEmpty.dst
Copy.BlockStmt.err
TestAll.f
Symlink.BlockStmt.err
Export.RangeStmt_7846.BlockStmt.RangeStmt_8370.fragment
builderMustSupportLinks
GroupFilesByModules.root
Exported.FileContents.err
errors
Writer
Export.modules
copyFile.dest
Exported.File.fragment
Exported.FileContents
Exported.ExpectFileSet
TestAll.RangeStmt_5688.e
copyFile.src
Module
openAndStat.src
GroupFilesByModules.modules
Export.temp
GroupFilesByModules._
GroupFilesByModules.BlockStmt.module
MustCopyFileTree.BlockStmt.fragment
TestAll.RangeStmt_5688.BlockStmt.e
Copy
copyFile.closeErr
MustCopyFileTree.BlockStmt.BlockStmt.BlockStmt.fi
Exported.Temp.e
log
Symlink.BlockStmt.BlockStmt.stat
GroupFilesByModules.BlockStmt.fragment
Module.Name
TestAll.t
GroupFilesByModules.BlockStmt.BlockStmt.fragment
Script.contents
Symlink.BlockStmt.BlockStmt.fullSource
BenchmarkAll.RangeStmt_6084.BlockStmt.e
Export.RangeStmt_7846.BlockStmt.RangeStmt_8370.BlockStmt.fullpath
copyFile.source
GroupFilesByModules.modulesPath
Exported.Modules
Exported.Exporter
BenchmarkAll
openAndStat.stat
Exported.File.module
GroupFilesByModules.currentModule
createEmpty.f
copyFile.dst
Export.RangeStmt_7846.module
GroupFilesByModules.mods
MustCopyFileTree.err
MustCopyFileTree.BlockStmt.BlockStmt.BlockStmt.err
flag
Module.Files
GroupFilesByModules.BlockStmt.BlockStmt.err
Exported.FileContents.filename
io
openAndStat
GroupFilesByModules.currentRepo
MustCopyFileTree
Exported.Temp
Exported.File.e
Exported.File
Export.RangeStmt_7846.BlockStmt.RangeStmt_9072.fragment
Script
GroupFilesByModules.BlockStmt.err
Exported.primary
createEmpty.err
copyFile.err
GroupFilesByModules.err
Exported
Symlink.BlockStmt.absSource
Export
Symlink.BlockStmt.symlinkErr
createEmpty.mode
copyFile
TestAll
BenchmarkAll.b
Link
openAndStat.err
Exporter
BenchmarkAll.RangeStmt_6084.e
Link.source
Symlink.BlockStmt.BlockStmt.err
MustCopyFileTree.root
Exported.Cleanup
Module.Overlay
All
Members
X