// loadPackage scans directory named by arg, // which is either an import path or a file system path // (if the latter, must be rooted or begin with . or ..), // and returns a *Package describing the package // found in that directory. func loadPackage(arg string, stk *importStack) *Package { stk.push(arg) defer stk.pop() // Check package cache. if p := packageCache[arg]; p != nil { return reusePackage(p, stk) } // Find basic information about package path. t, importPath, err := build.FindTree(arg) dir := "" // Maybe it is a standard command. if err != nil && strings.HasPrefix(arg, "cmd/") { goroot := build.Path[0] p := filepath.Join(goroot.Path, "src", arg) if st, err1 := os.Stat(p); err1 == nil && st.IsDir() { t = goroot importPath = arg dir = p err = nil } } // Maybe it is a path to a standard command. if err != nil && (filepath.IsAbs(arg) || isLocalPath(arg)) { arg, _ := filepath.Abs(arg) goroot := build.Path[0] cmd := filepath.Join(goroot.Path, "src", "cmd") + string(filepath.Separator) if st, err1 := os.Stat(arg); err1 == nil && st.IsDir() && strings.HasPrefix(arg, cmd) { t = goroot importPath = filepath.FromSlash(arg[len(cmd):]) dir = arg err = nil } } if err != nil { p := &Package{ ImportPath: arg, Error: &PackageError{ ImportStack: stk.copy(), Err: err.Error(), }, Incomplete: true, } packageCache[arg] = p return p } if dir == "" { dir = filepath.Join(t.SrcDir(), filepath.FromSlash(importPath)) } // Maybe we know the package by its directory. if p := packageCache[dir]; p != nil { packageCache[importPath] = p return reusePackage(p, stk) } return scanPackage(&buildContext, t, arg, importPath, dir, stk) }
func TestTool(t *testing.T) { if e := Remotize(Value2Spec("github.com/josvazg/remotize/tool", new(ToolTester))); e != nil { t.Fatal(e) } dir, e := build.ScanDir(".", false) if e != nil { t.Fatal(e) } dir.GoFiles = append(dir.GoFiles, "tool_test.go") //fmt.Println("dir", dir) tree, pkg, e := build.FindTree(".") if e != nil { t.Fatal(e) } //fmt.Println("tree", tree, "pkg", pkg) script, e := build.Build(tree, pkg, dir) if e != nil { t.Fatal(e) } //fmt.Println("script", script) e = script.Run() if e != nil { t.Fatal(e) } }
func main() { flag.Parse() // source of unique numbers go func() { for i := 0; ; i++ { uniq <- i } }() // set archChar var err os.Error archChar, err = build.ArchChar(runtime.GOARCH) if err != nil { log.Fatal(err) } // find and serve the go tour files t, _, err := build.FindTree(basePkg) if err != nil { log.Fatalf("Couldn't find tour files: %v", err) } root := filepath.Join(t.SrcDir(), basePkg) root := basePkg log.Println("Serving content from", root) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/favicon.ico" || r.URL.Path == "/" { fn := filepath.Join(root, "static", r.URL.Path[1:]) http.ServeFile(w, r, fn) return } http.Error(w, "not found", 404) }) http.Handle("/static/", http.FileServer(http.Dir(root))) http.HandleFunc("/kill", kill) // set include path for ld and gc pkgDir = t.PkgDir() if !strings.HasPrefix(*httpListen, "127.0.0.1") && !strings.HasPrefix(*httpListen, "localhost") { log.Print(localhostWarning) } log.Printf("Serving at http://%s/", *httpListen) log.Fatal(http.ListenAndServe(*httpListen, nil)) }
// show godoc of current package func document(pkg string) { // Don't allow trailing '/' if strings.HasSuffix(pkg, "/") { errorf("%s should not have trailing '/'\n", pkg) return } // Check whether package is local or remote. // If remote, download or update it. tree, pkg, err := build.FindTree(pkg) var dir, baseDir string // Download remote packages if not found or forced with -u flag. remote := isRemote(pkg) if !remote { dir = filepath.Join(tree.SrcDir(), filepath.FromSlash(pkg)) } else { baseDir, _ = ioutil.TempDir("", "godocr") _, err = download(pkg, baseDir) if err != nil { errorf("%s: problem downloading: %s\n", pkg, err) return } dir = filepath.Join(baseDir, filepath.FromSlash(pkg)) } // Run godoc either in the standard library or in the checked // out repo. out, err := runGodoc(dir) if err != nil { errorf("%s: godoc: %s\n", pkg, err) } else { fmt.Print(string(out)) } // only clean up after ourselves if we've downloaded a remote // directory if remote { err = os.RemoveAll(baseDir) if err != nil { errorf("%s: couldn't clean up after ourselves: %s\n", pkg, err) } } }
// findPkg returns the filename and package id for an import path. // If no file was found, an empty filename is returned. func findPkg(path string) (filename, id string) { if len(path) == 0 { return } id = path var noext string switch path[0] { default: // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x" tree, pkg, err := build.FindTree(path) if err != nil { return } noext = filepath.Join(tree.PkgDir(), pkg) case '.': // "./x" -> "/this/directory/x.ext", "/this/directory/x" cwd, err := os.Getwd() if err != nil { return } noext = filepath.Join(cwd, path) id = noext case '/': // "/x" -> "/x.ext", "/x" noext = path } // try extensions for _, ext := range pkgExts { filename = noext + ext if f, err := os.Stat(filename); err == nil && !f.IsDir() { return } } filename = "" // not found return }
func main() { flag.Parse() var pkgs []string if flag.NArg() > 0 { pkgs = flag.Args() } else { stds, err := exec.Command("go", "list", "std").Output() if err != nil { log.Fatal(err) } pkgs = strings.Fields(string(stds)) } tree, _, err := build.FindTree("os") // some known package if err != nil { log.Fatalf("failed to find tree: %v", err) } var featureCtx = make(map[string]map[string]bool) // feature -> context name -> true for _, context := range contexts { w := NewWalker() w.context = context w.tree = tree for _, pkg := range pkgs { w.wantedPkg[pkg] = true } for _, pkg := range pkgs { if strings.HasPrefix(pkg, "cmd/") || strings.HasPrefix(pkg, "exp/") || strings.HasPrefix(pkg, "old/") { continue } if !tree.HasSrc(pkg) { log.Fatalf("no source in tree for package %q", pkg) } w.WalkPackage(pkg) } ctxName := contextName(context) for _, f := range w.Features() { if featureCtx[f] == nil { featureCtx[f] = make(map[string]bool) } featureCtx[f][ctxName] = true } } var features []string for f, cmap := range featureCtx { if len(cmap) == len(contexts) { features = append(features, f) continue } comma := strings.Index(f, ",") for cname := range cmap { f2 := fmt.Sprintf("%s (%s)%s", f[:comma], cname, f[comma:]) features = append(features, f2) } } sort.Strings(features) bw := bufio.NewWriter(os.Stdout) defer bw.Flush() if *checkFile != "" { bs, err := ioutil.ReadFile(*checkFile) if err != nil { log.Fatalf("Error reading file %s: %v", *checkFile, err) } v1 := strings.Split(string(bs), "\n") sort.Strings(v1) v2 := features take := func(sl *[]string) string { s := (*sl)[0] *sl = (*sl)[1:] return s } for len(v1) > 0 || len(v2) > 0 { switch { case len(v2) == 0 || v1[0] < v2[0]: fmt.Fprintf(bw, "-%s\n", take(&v1)) case len(v1) == 0 || v1[0] > v2[0]: fmt.Fprintf(bw, "+%s\n", take(&v2)) default: take(&v1) take(&v2) } } } else { for _, f := range features { fmt.Fprintf(bw, "%s\n", f) } } }
func main() { flag.Usage = usage flag.Parse() // Check usage: either server and no args, or command line and args if (*httpAddr != "") != (flag.NArg() == 0) { usage() } if *tabwidth < 0 { log.Fatalf("negative tabwidth %d", *tabwidth) } // Determine file system to use. // TODO(gri) - fs and fsHttp should really be the same. Try to unify. // - fsHttp doesn't need to be set up in command-line mode, // same is true for the http handlers in initHandlers. if *zipfile == "" { // use file system of underlying OS *goroot = filepath.Clean(*goroot) // normalize path separator fs = OS fsHttp = http.Dir(*goroot) } else { // use file system specified via .zip file (path separator must be '/') rc, err := zip.OpenReader(*zipfile) if err != nil { log.Fatalf("%s: %s\n", *zipfile, err) } *goroot = path.Join("/", *goroot) // fsHttp paths are relative to '/' fs = NewZipFS(rc) fsHttp = NewHttpZipFS(rc, *goroot) } readTemplates() initHandlers() if *httpAddr != "" { // HTTP server mode. var handler http.Handler = http.DefaultServeMux if *verbose { log.Printf("Go Documentation Server") log.Printf("version = %s", runtime.Version()) log.Printf("address = %s", *httpAddr) log.Printf("goroot = %s", *goroot) log.Printf("tabwidth = %d", *tabwidth) switch { case !*indexEnabled: log.Print("search index disabled") case *maxResults > 0: log.Printf("full text index enabled (maxresults = %d)", *maxResults) default: log.Print("identifier search index enabled") } if !fsMap.IsEmpty() { log.Print("user-defined mapping:") fsMap.Fprint(os.Stderr) } handler = loggingHandler(handler) } registerPublicHandlers(http.DefaultServeMux) if *syncCmd != "" { http.Handle("/debug/sync", http.HandlerFunc(dosync)) } // Initialize default directory tree with corresponding timestamp. // (Do it in a goroutine so that launch is quick.) go initFSTree() // Initialize directory trees for user-defined file systems (-path flag). initDirTrees() // Start sync goroutine, if enabled. if *syncCmd != "" && *syncMin > 0 { syncDelay.set(*syncMin) // initial sync delay go func() { for { dosync(nil, nil) delay, _ := syncDelay.get() if *verbose { log.Printf("next sync in %dmin", delay.(int)) } time.Sleep(int64(delay.(int)) * 60e9) } }() } // Start indexing goroutine. if *indexEnabled { go indexer() } // Start http server. if err := http.ListenAndServe(*httpAddr, handler); err != nil { log.Fatalf("ListenAndServe %s: %v", *httpAddr, err) } return } // Command line mode. if *html { packageText = packageHTML searchText = packageHTML } if *query { // Command-line queries. for i := 0; i < flag.NArg(); i++ { res, err := remoteSearch(flag.Arg(i)) if err != nil { log.Fatalf("remoteSearch: %s", err) } io.Copy(os.Stdout, res.Body) } return } // determine paths path := flag.Arg(0) if len(path) > 0 && path[0] == '.' { // assume cwd; don't assume -goroot cwd, _ := os.Getwd() // ignore errors path = filepath.Join(cwd, path) } relpath := path abspath := path if t, pkg, err := build.FindTree(path); err == nil { relpath = pkg abspath = filepath.Join(t.SrcDir(), pkg) } else if !filepath.IsAbs(path) { abspath = absolutePath(path, pkgHandler.fsRoot) } else { relpath = relativeURL(path) } var mode PageInfoMode if *srcMode { // only filter exports if we don't have explicit command-line filter arguments if flag.NArg() == 1 { mode |= exportsOnly } } else { mode = exportsOnly | genDoc } // TODO(gri): Provide a mechanism (flag?) to select a package // if there are multiple packages in a directory. info := pkgHandler.getPageInfo(abspath, relpath, "", mode) if info.IsEmpty() { // try again, this time assume it's a command if !filepath.IsAbs(path) { abspath = absolutePath(path, cmdHandler.fsRoot) } cmdInfo := cmdHandler.getPageInfo(abspath, relpath, "", mode) // only use the cmdInfo if it actually contains a result // (don't hide errors reported from looking up a package) if !cmdInfo.IsEmpty() { info = cmdInfo } } if info.Err != nil { log.Fatalf("%v", info.Err) } // If we have more than one argument, use the remaining arguments for filtering if flag.NArg() > 1 { args := flag.Args()[1:] rx := makeRx(args) if rx == nil { log.Fatalf("illegal regular expression from %v", args) } filter := func(s string) bool { return rx.MatchString(s) } switch { case info.PAst != nil: ast.FilterFile(info.PAst, filter) // Special case: Don't use templates for printing // so we only get the filtered declarations without // package clause or extra whitespace. for i, d := range info.PAst.Decls { if i > 0 { fmt.Println() } if *html { var buf bytes.Buffer writeNode(&buf, info.FSet, d) FormatText(os.Stdout, buf.Bytes(), -1, true, "", nil) } else { writeNode(os.Stdout, info.FSet, d) } fmt.Println() } return case info.PDoc != nil: info.PDoc.Filter(filter) } } if err := packageText.Execute(os.Stdout, info); err != nil { log.Printf("packageText.Execute: %s", err) } }
// install installs the package named by path, which is needed by parent. func install(pkg, parent string) { // Make sure we're not already trying to install pkg. switch visit[pkg] { case done: return case visiting: fmt.Fprintf(os.Stderr, "%s: package dependency cycle\n", argv0) printDeps(parent) fmt.Fprintf(os.Stderr, "\t%s\n", pkg) os.Exit(2) } parents[pkg] = parent visit[pkg] = visiting defer func() { visit[pkg] = done }() // Don't allow trailing '/' if _, f := filepath.Split(pkg); f == "" { errorf("%s should not have trailing '/'\n", pkg) return } // Check whether package is local or remote. // If remote, download or update it. tree, pkg, err := build.FindTree(pkg) // Don't build the standard library. if err == nil && tree.Goroot && isStandardPath(pkg) { if parent == "" { errorf("%s: can not goinstall the standard library\n", pkg) } else { printf("%s: skipping standard library\n", pkg) } return } // Download remote packages if not found or forced with -u flag. remote, public := isRemote(pkg), false if remote { if err == build.ErrNotFound || (err == nil && *update) { // Download remote package. printf("%s: download\n", pkg) public, err = download(pkg, tree.SrcDir()) } else { // Test if this is a public repository // (for reporting to dashboard). m, _ := findPublicRepo(pkg) public = m != nil } } if err != nil { terrorf(tree, "%s: %v\n", pkg, err) return } dir := filepath.Join(tree.SrcDir(), pkg) // Install prerequisites. dirInfo, err := build.ScanDir(dir, parent == "") if err != nil { terrorf(tree, "%s: %v\n", pkg, err) return } if len(dirInfo.GoFiles)+len(dirInfo.CgoFiles) == 0 { terrorf(tree, "%s: package has no files\n", pkg) return } for _, p := range dirInfo.Imports { if p != "C" { install(p, pkg) } } if errors { return } // Install this package. if *useMake { err := domake(dir, pkg, tree, dirInfo.IsCommand()) if err != nil { terrorf(tree, "%s: install: %v\n", pkg, err) return } } else { script, err := build.Build(tree, pkg, dirInfo) if err != nil { terrorf(tree, "%s: install: %v\n", pkg, err) return } if *nuke { printf("%s: nuke\n", pkg) script.Nuke() } else if *clean { printf("%s: clean\n", pkg) script.Clean() } if *doInstall { if script.Stale() { printf("%s: install\n", pkg) if err := script.Run(); err != nil { terrorf(tree, "%s: install: %v\n", pkg, err) return } } else { printf("%s: up-to-date\n", pkg) } } } if remote { // mark package as installed in goinstall.log logged := logPackage(pkg, tree) // report installation to the dashboard if this is the first // install from a public repository. if logged && public { maybeReportToDashboard(pkg) } } }
// loadPackage scans directory named by arg, // which is either an import path or a file system path // (if the latter, must be rooted or begin with . or ..), // and returns a *Package describing the package // found in that directory. func loadPackage(arg string, stk *importStack) *Package { stk.push(arg) defer stk.pop() // Check package cache. if p := packageCache[arg]; p != nil { return reusePackage(p, stk) } // Find basic information about package path. isCmd := false t, importPath, err := build.FindTree(arg) dir := "" // Maybe it is a standard command. if err != nil && strings.HasPrefix(arg, "cmd/") { goroot := build.Path[0] p := filepath.Join(goroot.Path, "src", arg) if st, err1 := os.Stat(p); err1 == nil && st.IsDir() { t = goroot importPath = arg dir = p err = nil isCmd = true } } // Maybe it is a path to a standard command. if err != nil && (filepath.IsAbs(arg) || isLocalPath(arg)) { arg, _ := filepath.Abs(arg) goroot := build.Path[0] cmd := filepath.Join(goroot.Path, "src", "cmd") + string(filepath.Separator) if st, err1 := os.Stat(arg); err1 == nil && st.IsDir() && strings.HasPrefix(arg, cmd) { t = goroot importPath = filepath.FromSlash(arg[len(cmd):]) dir = arg err = nil isCmd = true } } if err != nil { p := &Package{ ImportPath: arg, Error: &PackageError{ ImportStack: stk.copy(), Err: err.Error(), }, Incomplete: true, } packageCache[arg] = p return p } if dir == "" { dir = filepath.Join(t.SrcDir(), filepath.FromSlash(importPath)) } // Maybe we know the package by its directory. p := packageCache[dir] if p != nil { packageCache[importPath] = p p = reusePackage(p, stk) } else { p = scanPackage(&buildContext, t, arg, importPath, dir, stk, false) } // If we loaded the files from the Go root's cmd/ tree, // it must be a command (package main). if isCmd && p.Error == nil && p.Name != "main" { p.Error = &PackageError{ ImportStack: stk.copy(), Err: fmt.Sprintf("expected package main in %q; found package %s", dir, p.Name), } } return p }
func main() { flag.Parse() var pkgs []string if flag.NArg() > 0 { pkgs = flag.Args() } else { stds, err := exec.Command("go", "list", "std").Output() if err != nil { log.Fatal(err) } pkgs = strings.Fields(string(stds)) } w := NewWalker() tree, _, err := build.FindTree("os") // some known package if err != nil { log.Fatalf("failed to find tree: %v", err) } for _, pkg := range pkgs { if strings.HasPrefix(pkg, "cmd/") || strings.HasPrefix(pkg, "exp/") || strings.HasPrefix(pkg, "old/") { continue } if !tree.HasSrc(pkg) { log.Fatalf("no source in tree for package %q", pkg) } pkgSrcDir := filepath.Join(tree.SrcDir(), filepath.FromSlash(pkg)) w.WalkPackage(pkg, pkgSrcDir) } bw := bufio.NewWriter(os.Stdout) defer bw.Flush() if *checkFile != "" { bs, err := ioutil.ReadFile(*checkFile) if err != nil { log.Fatalf("Error reading file %s: %v", *checkFile, err) } v1 := strings.Split(string(bs), "\n") sort.Strings(v1) v2 := w.Features() take := func(sl *[]string) string { s := (*sl)[0] *sl = (*sl)[1:] return s } for len(v1) > 0 || len(v2) > 0 { switch { case len(v2) == 0 || v1[0] < v2[0]: fmt.Fprintf(bw, "-%s\n", take(&v1)) case len(v1) == 0 || v1[0] > v2[0]: fmt.Fprintf(bw, "+%s\n", take(&v2)) default: take(&v1) take(&v2) } } } else { for _, f := range w.Features() { fmt.Fprintf(bw, "%s\n", f) } } }
func main() { flag.Usage = usage flag.Parse() // Check usage: either server and no args, command line and args, or index creation mode if (*httpAddr != "") != (flag.NArg() == 0) && !*writeIndex { usage() } if *tabwidth < 0 { log.Fatalf("negative tabwidth %d", *tabwidth) } // Determine file system to use. // TODO(gri) - fs and fsHttp should really be the same. Try to unify. // - fsHttp doesn't need to be set up in command-line mode, // same is true for the http handlers in initHandlers. if *zipfile == "" { // use file system of underlying OS *goroot = filepath.Clean(*goroot) // normalize path separator fs = OS fsHttp = http.Dir(*goroot) } else { // use file system specified via .zip file (path separator must be '/') rc, err := zip.OpenReader(*zipfile) if err != nil { log.Fatalf("%s: %s\n", *zipfile, err) } defer rc.Close() // be nice (e.g., -writeIndex mode) *goroot = path.Join("/", *goroot) // fsHttp paths are relative to '/' fs = NewZipFS(rc) fsHttp = NewHttpZipFS(rc, *goroot) } readTemplates() initHandlers() if *writeIndex { // Write search index and exit. if *indexFiles == "" { log.Fatal("no index file specified") } log.Println("initialize file systems") *verbose = true // want to see what happens initFSTree() initDirTrees() *indexThrottle = 1 updateIndex() log.Println("writing index file", *indexFiles) f, err := os.Create(*indexFiles) if err != nil { log.Fatal(err) } index, _ := searchIndex.get() err = index.(*Index).Write(f) if err != nil { log.Fatal(err) } log.Println("done") return } if *httpAddr != "" { // HTTP server mode. var handler http.Handler = http.DefaultServeMux if *verbose { log.Printf("Go Documentation Server") log.Printf("version = %s", runtime.Version()) log.Printf("address = %s", *httpAddr) log.Printf("goroot = %s", *goroot) log.Printf("tabwidth = %d", *tabwidth) switch { case !*indexEnabled: log.Print("search index disabled") case *maxResults > 0: log.Printf("full text index enabled (maxresults = %d)", *maxResults) default: log.Print("identifier search index enabled") } if !fsMap.IsEmpty() { log.Print("user-defined mapping:") fsMap.Fprint(os.Stderr) } handler = loggingHandler(handler) } registerPublicHandlers(http.DefaultServeMux) if *syncCmd != "" { http.Handle("/debug/sync", http.HandlerFunc(dosync)) } // Initialize default directory tree with corresponding timestamp. // (Do it in a goroutine so that launch is quick.) go initFSTree() // Initialize directory trees for user-defined file systems (-path flag). initDirTrees() // Start sync goroutine, if enabled. if *syncCmd != "" && *syncMin > 0 { syncDelay.set(*syncMin) // initial sync delay go func() { for { dosync(nil, nil) delay, _ := syncDelay.get() dt := delay.(time.Duration) if *verbose { log.Printf("next sync in %s", dt) } time.Sleep(dt) } }() } // Immediately update metadata. updateMetadata() // Periodically refresh metadata. go refreshMetadataLoop() // Initialize search index. if *indexEnabled { go indexer() } // Start http server. if err := http.ListenAndServe(*httpAddr, handler); err != nil { log.Fatalf("ListenAndServe %s: %v", *httpAddr, err) } return } // Command line mode. if *html { packageText = packageHTML searchText = packageHTML } if *query { // Command-line queries. for i := 0; i < flag.NArg(); i++ { res, err := remoteSearch(flag.Arg(i)) if err != nil { log.Fatalf("remoteSearch: %s", err) } io.Copy(os.Stdout, res.Body) } return } // determine paths const cmdPrefix = "cmd/" path := flag.Arg(0) var forceCmd bool if strings.HasPrefix(path, ".") { // assume cwd; don't assume -goroot cwd, _ := os.Getwd() // ignore errors path = filepath.Join(cwd, path) } else if strings.HasPrefix(path, cmdPrefix) { path = path[len(cmdPrefix):] forceCmd = true } relpath := path abspath := path if t, pkg, err := build.FindTree(path); err == nil { relpath = pkg abspath = filepath.Join(t.SrcDir(), pkg) } else if !filepath.IsAbs(path) { abspath = absolutePath(path, pkgHandler.fsRoot) } else { relpath = relativeURL(path) } var mode PageInfoMode if relpath == builtinPkgPath { // the fake built-in package contains unexported identifiers mode = noFiltering } if *srcMode { // only filter exports if we don't have explicit command-line filter arguments if flag.NArg() > 1 { mode |= noFiltering } mode |= showSource } // TODO(gri): Provide a mechanism (flag?) to select a package // if there are multiple packages in a directory. // first, try as package unless forced as command var info PageInfo if !forceCmd { info = pkgHandler.getPageInfo(abspath, relpath, "", mode) } // second, try as command unless the path is absolute // (the go command invokes godoc w/ absolute paths; don't override) var cinfo PageInfo if !filepath.IsAbs(path) { abspath = absolutePath(path, cmdHandler.fsRoot) cinfo = cmdHandler.getPageInfo(abspath, relpath, "", mode) } // determine what to use if info.IsEmpty() { if !cinfo.IsEmpty() { // only cinfo exists - switch to cinfo info = cinfo } } else if !cinfo.IsEmpty() { // both info and cinfo exist - use cinfo if info // contains only subdirectory information if info.PAst == nil && info.PDoc == nil { info = cinfo } else { fmt.Printf("use 'godoc %s%s' for documentation on the %s command \n\n", cmdPrefix, relpath, relpath) } } if info.Err != nil { log.Fatalf("%v", info.Err) } // If we have more than one argument, use the remaining arguments for filtering if flag.NArg() > 1 { args := flag.Args()[1:] rx := makeRx(args) if rx == nil { log.Fatalf("illegal regular expression from %v", args) } filter := func(s string) bool { return rx.MatchString(s) } switch { case info.PAst != nil: ast.FilterFile(info.PAst, filter) // Special case: Don't use templates for printing // so we only get the filtered declarations without // package clause or extra whitespace. for i, d := range info.PAst.Decls { if i > 0 { fmt.Println() } if *html { var buf bytes.Buffer writeNode(&buf, info.FSet, d) FormatText(os.Stdout, buf.Bytes(), -1, true, "", nil) } else { writeNode(os.Stdout, info.FSet, d) } fmt.Println() } return case info.PDoc != nil: info.PDoc.Filter(filter) } } if err := packageText.Execute(os.Stdout, info); err != nil { log.Printf("packageText.Execute: %s", err) } }
// install installs the package named by path, which is needed by parent. func install(pkg, parent string) error { // Basic validation of import path string. if s := schemeRe.FindString(pkg); s != "" { return fmt.Errorf("%q used in import path, try %q\n", s, pkg[len(s):]) } if strings.HasSuffix(pkg, "/") { return fmt.Errorf("%q should not have trailing '/'\n", pkg) } // Make sure we're not already trying to install pkg. switch visit[pkg] { case done: return nil case visiting: fmt.Fprintf(os.Stderr, "%s: package dependency cycle\n", argv0) printDeps(parent) fmt.Fprintf(os.Stderr, "\t%s\n", pkg) os.Exit(2) } parents[pkg] = parent visit[pkg] = visiting defer func() { visit[pkg] = done }() // Check whether package is local or remote. // If remote, download or update it. tree, pkg, err := build.FindTree(pkg) // Don't build the standard library. if err == nil && tree.Goroot && isStandardPath(pkg) { if parent == "" { return &PackageError{pkg, errors.New("cannot goinstall the standard library")} } return nil } // Download remote packages if not found or forced with -u flag. remote, public := isRemote(pkg), false if remote { if err == build.ErrNotFound || (err == nil && *update) { // Download remote package. printf("%s: download\n", pkg) public, err = download(pkg, tree.SrcDir()) if err != nil { // only suggest -fix if the bad import was not on the command line if e, ok := err.(*errOldGoogleRepo); ok && parent != "" { err = fmt.Errorf("%v\nRun goinstall with -fix to gofix the code.", e) } return &DownloadError{pkg, tree.Goroot, err} } } else { // Test if this is a public repository // (for reporting to dashboard). repo, e := findPublicRepo(pkg) public = repo != nil err = e } } if err != nil { return &PackageError{pkg, err} } // Install the package and its dependencies. if err := installPackage(pkg, parent, tree, false); err != nil { return err } if remote { // mark package as installed in goinstall.log logged := logPackage(pkg, tree) // report installation to the dashboard if this is the first // install from a public repository. if logged && public { maybeReportToDashboard(pkg) } } return nil }