1
0
mirror of https://github.com/golang/go synced 2024-11-25 06:57:58 -07:00

goinstall: write to goinstall.log in respective GOPATH

goinstall: report every newly installed package to the dashboard

This makes "goinstall -a" work on systems with GOROOTs that are
not user-writable, as is the case with Debian's Go packages.

This also makes goinstall.log the canonical list of installed
packages, in that only packages new to goinstall.log are reported to
the dashboard.

A side-effect is that writing to goinstall.log is now mandatory.
(A bug in the original implementation meant this was the case, anyway.)

The principal benefit of this change is that multiple packages from the
same repository can now be reported to the dashboard.  It is also less
likely for a user to report multiple installations of the same package
to the dashboard (they would need to remove the package from
goinstall.log first).

R=rsc, n13m3y3r
CC=golang-dev
https://golang.org/cl/4786041
This commit is contained in:
Andrew Gerrand 2011-07-24 13:43:08 +10:00
parent d56c8132e8
commit fc2480da3c
3 changed files with 66 additions and 64 deletions

View File

@ -17,7 +17,6 @@ Flags and default settings:
-clean=false clean the package directory before installing -clean=false clean the package directory before installing
-dashboard=true tally public packages on godashboard.appspot.com -dashboard=true tally public packages on godashboard.appspot.com
-install=true build and install the package and its dependencies -install=true build and install the package and its dependencies
-log=true log installed packages to $GOROOT/goinstall.log for use by -a
-nuke=false remove the target object and clean before installing -nuke=false remove the target object and clean before installing
-u=false update already-downloaded packages -u=false update already-downloaded packages
-v=false verbose operation -v=false verbose operation

View File

@ -149,9 +149,9 @@ type vcsMatch struct {
prefix, repo string prefix, repo string
} }
// findHostedRepo checks whether pkg is located at one of // findPublicRepo checks whether pkg is located at one of
// the supported code hosting sites and, if so, returns a match. // the supported code hosting sites and, if so, returns a match.
func findHostedRepo(pkg string) (*vcsMatch, os.Error) { func findPublicRepo(pkg string) (*vcsMatch, os.Error) {
for _, v := range vcsList { for _, v := range vcsList {
for _, host := range v.defaultHosts { for _, host := range v.defaultHosts {
if hm := host.pattern.FindStringSubmatch(pkg); hm != nil { if hm := host.pattern.FindStringSubmatch(pkg); hm != nil {
@ -215,17 +215,17 @@ func isRemote(pkg string) bool {
} }
// download checks out or updates pkg from the remote server. // download checks out or updates pkg from the remote server.
func download(pkg, srcDir string) (dashReport bool, err os.Error) { func download(pkg, srcDir string) (public bool, err os.Error) {
if strings.Contains(pkg, "..") { if strings.Contains(pkg, "..") {
err = os.NewError("invalid path (contains ..)") err = os.NewError("invalid path (contains ..)")
return return
} }
m, err := findHostedRepo(pkg) m, err := findPublicRepo(pkg)
if err != nil { if err != nil {
return return
} }
if m != nil { if m != nil {
dashReport = true // only report public code hosting sites public = true
} else { } else {
m, err = findAnyRepo(pkg) m, err = findAnyRepo(pkg)
if err != nil { if err != nil {
@ -236,13 +236,7 @@ func download(pkg, srcDir string) (dashReport bool, err os.Error) {
err = os.NewError("cannot download: " + pkg) err = os.NewError("cannot download: " + pkg)
return return
} }
installed, err := m.checkoutRepo(srcDir, m.prefix, m.repo) err = m.checkoutRepo(srcDir, m.prefix, m.repo)
if err != nil {
return
}
if !installed {
dashReport = false
}
return return
} }
@ -267,41 +261,36 @@ func (v *vcs) updateRepo(dst string) os.Error {
// exists and -u was specified on the command line) // exists and -u was specified on the command line)
// the repository at tag/branch "release". If there is no // the repository at tag/branch "release". If there is no
// such tag or branch, it falls back to the repository tip. // such tag or branch, it falls back to the repository tip.
func (vcs *vcs) checkoutRepo(srcDir, pkgprefix, repo string) (installed bool, err os.Error) { func (vcs *vcs) checkoutRepo(srcDir, pkgprefix, repo string) os.Error {
dst := filepath.Join(srcDir, filepath.FromSlash(pkgprefix)) dst := filepath.Join(srcDir, filepath.FromSlash(pkgprefix))
dir, err := os.Stat(filepath.Join(dst, vcs.metadir)) dir, err := os.Stat(filepath.Join(dst, vcs.metadir))
if err == nil && !dir.IsDirectory() { if err == nil && !dir.IsDirectory() {
err = os.NewError("not a directory: " + dst) return os.NewError("not a directory: " + dst)
return
} }
if err != nil { if err != nil {
parent, _ := filepath.Split(dst) parent, _ := filepath.Split(dst)
if err = os.MkdirAll(parent, 0777); err != nil { if err = os.MkdirAll(parent, 0777); err != nil {
return return err
} }
if err = run(string(filepath.Separator), nil, vcs.cmd, vcs.clone, repo, dst); err != nil { if err = run(string(filepath.Separator), nil, vcs.cmd, vcs.clone, repo, dst); err != nil {
return return err
} }
if err = vcs.updateRepo(dst); err != nil { return vcs.updateRepo(dst)
return }
} if *update {
installed = true
} else if *update {
// Retrieve new revisions from the remote branch, if the VCS // Retrieve new revisions from the remote branch, if the VCS
// supports this operation independently (e.g. svn doesn't) // supports this operation independently (e.g. svn doesn't)
if vcs.pull != "" { if vcs.pull != "" {
if vcs.pullForceFlag != "" { if vcs.pullForceFlag != "" {
if err = run(dst, nil, vcs.cmd, vcs.pull, vcs.pullForceFlag); err != nil { if err = run(dst, nil, vcs.cmd, vcs.pull, vcs.pullForceFlag); err != nil {
return return err
} }
} else if err = run(dst, nil, vcs.cmd, vcs.pull); err != nil { } else if err = run(dst, nil, vcs.cmd, vcs.pull); err != nil {
return return err
} }
} }
// Update to release or latest revision // Update to release or latest revision
if err = vcs.updateRepo(dst); err != nil { return vcs.updateRepo(dst)
return
}
} }
return return nil
} }

View File

@ -25,18 +25,18 @@ func usage() {
os.Exit(2) os.Exit(2)
} }
const logfile = "goinstall.log"
var ( var (
fset = token.NewFileSet() fset = token.NewFileSet()
argv0 = os.Args[0] argv0 = os.Args[0]
errors = false errors = false
parents = make(map[string]string) parents = make(map[string]string)
visit = make(map[string]status) visit = make(map[string]status)
logfile = filepath.Join(runtime.GOROOT(), "goinstall.log") installedPkgs = make(map[string]map[string]bool)
installedPkgs = make(map[string]bool)
allpkg = flag.Bool("a", false, "install all previously installed packages") allpkg = flag.Bool("a", false, "install all previously installed packages")
reportToDashboard = flag.Bool("dashboard", true, "report public packages at "+dashboardURL) reportToDashboard = flag.Bool("dashboard", true, "report public packages at "+dashboardURL)
logPkgs = flag.Bool("log", true, "log installed packages to $GOROOT/goinstall.log for use by -a")
update = flag.Bool("u", false, "update already-downloaded packages") update = flag.Bool("u", false, "update already-downloaded packages")
doInstall = flag.Bool("install", true, "build and install") doInstall = flag.Bool("install", true, "build and install")
clean = flag.Bool("clean", false, "clean the package directory before installing") clean = flag.Bool("clean", false, "clean the package directory before installing")
@ -76,28 +76,27 @@ func main() {
fmt.Fprintf(os.Stderr, "%s: no $GOROOT\n", argv0) fmt.Fprintf(os.Stderr, "%s: no $GOROOT\n", argv0)
os.Exit(1) os.Exit(1)
} }
readPackageList()
// special case - "unsafe" is already installed // special case - "unsafe" is already installed
visit["unsafe"] = done visit["unsafe"] = done
args := flag.Args() args := flag.Args()
if *allpkg || *logPkgs {
readPackageList()
}
if *allpkg { if *allpkg {
if len(args) != 0 { if len(args) != 0 {
usage() // -a and package list both provided usage() // -a and package list both provided
} }
// install all packages that were ever installed // install all packages that were ever installed
if len(installedPkgs) == 0 { n := 0
fmt.Fprintf(os.Stderr, "%s: no installed packages\n", argv0) for _, pkgs := range installedPkgs {
os.Exit(1) for pkg := range pkgs {
args = append(args, pkg)
n++
}
} }
args = make([]string, len(installedPkgs), len(installedPkgs)) if n == 0 {
i := 0 logf("no installed packages\n")
for pkg := range installedPkgs { os.Exit(1)
args[i] = pkg
i++
} }
} }
if len(args) == 0 { if len(args) == 0 {
@ -127,27 +126,40 @@ func printDeps(pkg string) {
fmt.Fprintf(os.Stderr, "\t%s ->\n", pkg) fmt.Fprintf(os.Stderr, "\t%s ->\n", pkg)
} }
// readPackageList reads the list of installed packages from goinstall.log // readPackageList reads the list of installed packages from the
// goinstall.log files in GOROOT and the GOPATHs and initalizes
// the installedPkgs variable.
func readPackageList() { func readPackageList() {
pkglistdata, _ := ioutil.ReadFile(logfile) for _, t := range build.Path {
pkglist := strings.Fields(string(pkglistdata)) installedPkgs[t.Path] = make(map[string]bool)
for _, pkg := range pkglist { name := filepath.Join(t.Path, logfile)
installedPkgs[pkg] = true pkglistdata, err := ioutil.ReadFile(name)
if err != nil {
printf("%s\n", err)
continue
}
pkglist := strings.Fields(string(pkglistdata))
for _, pkg := range pkglist {
installedPkgs[t.Path][pkg] = true
}
} }
} }
// logPackage logs the named package as installed in goinstall.log, if the package is not found in there // logPackage logs the named package as installed in the goinstall.log file
func logPackage(pkg string) { // in the given tree if the package is not already in that file.
if installedPkgs[pkg] { func logPackage(pkg string, tree *build.Tree) (logged bool) {
return if installedPkgs[tree.Path][pkg] {
return false
} }
fout, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) name := filepath.Join(tree.Path, logfile)
fout, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "%s: %s\n", argv0, err) logf("%s\n", err)
return return false
} }
fmt.Fprintf(fout, "%s\n", pkg) fmt.Fprintf(fout, "%s\n", pkg)
fout.Close() fout.Close()
return true
} }
// install installs the package named by path, which is needed by parent. // install installs the package named by path, which is needed by parent.
@ -181,11 +193,10 @@ func install(pkg, parent string) {
return return
} }
// Download remote packages if not found or forced with -u flag. // Download remote packages if not found or forced with -u flag.
remote := isRemote(pkg) remote, public := isRemote(pkg), false
dashReport := false
if remote && (err == build.ErrNotFound || (err == nil && *update)) { if remote && (err == build.ErrNotFound || (err == nil && *update)) {
printf("%s: download\n", pkg) printf("%s: download\n", pkg)
dashReport, err = download(pkg, tree.SrcDir()) public, err = download(pkg, tree.SrcDir())
} }
if err != nil { if err != nil {
errorf("%s: %v\n", pkg, err) errorf("%s: %v\n", pkg, err)
@ -244,14 +255,17 @@ func install(pkg, parent string) {
} }
} }
} }
if dashReport {
maybeReportToDashboard(pkg)
}
if remote { if remote {
// mark package as installed in $GOROOT/goinstall.log // mark package as installed in goinstall.log
logPackage(pkg) 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
} }
// Is this a standard package path? strings container/vector etc. // Is this a standard package path? strings container/vector etc.