Commit fc2480da authored by Andrew Gerrand's avatar Andrew Gerrand

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
parent d56c8132
......@@ -17,7 +17,6 @@ Flags and default settings:
-clean=false clean the package directory before installing
-dashboard=true tally public packages on godashboard.appspot.com
-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
-u=false update already-downloaded packages
-v=false verbose operation
......
......@@ -149,9 +149,9 @@ type vcsMatch struct {
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.
func findHostedRepo(pkg string) (*vcsMatch, os.Error) {
func findPublicRepo(pkg string) (*vcsMatch, os.Error) {
for _, v := range vcsList {
for _, host := range v.defaultHosts {
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.
func download(pkg, srcDir string) (dashReport bool, err os.Error) {
func download(pkg, srcDir string) (public bool, err os.Error) {
if strings.Contains(pkg, "..") {
err = os.NewError("invalid path (contains ..)")
return
}
m, err := findHostedRepo(pkg)
m, err := findPublicRepo(pkg)
if err != nil {
return
}
if m != nil {
dashReport = true // only report public code hosting sites
public = true
} else {
m, err = findAnyRepo(pkg)
if err != nil {
......@@ -236,13 +236,7 @@ func download(pkg, srcDir string) (dashReport bool, err os.Error) {
err = os.NewError("cannot download: " + pkg)
return
}
installed, err := m.checkoutRepo(srcDir, m.prefix, m.repo)
if err != nil {
return
}
if !installed {
dashReport = false
}
err = m.checkoutRepo(srcDir, m.prefix, m.repo)
return
}
......@@ -267,41 +261,36 @@ func (v *vcs) updateRepo(dst string) os.Error {
// exists and -u was specified on the command line)
// the repository at tag/branch "release". If there is no
// 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))
dir, err := os.Stat(filepath.Join(dst, vcs.metadir))
if err == nil && !dir.IsDirectory() {
err = os.NewError("not a directory: " + dst)
return
return os.NewError("not a directory: " + dst)
}
if err != nil {
parent, _ := filepath.Split(dst)
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 {
return
}
if err = vcs.updateRepo(dst); err != nil {
return
return err
}
installed = true
} else if *update {
return vcs.updateRepo(dst)
}
if *update {
// Retrieve new revisions from the remote branch, if the VCS
// supports this operation independently (e.g. svn doesn't)
if vcs.pull != "" {
if vcs.pullForceFlag != "" {
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 {
return
return err
}
}
// Update to release or latest revision
if err = vcs.updateRepo(dst); err != nil {
return
}
return vcs.updateRepo(dst)
}
return
return nil
}
......@@ -25,18 +25,18 @@ func usage() {
os.Exit(2)
}
const logfile = "goinstall.log"
var (
fset = token.NewFileSet()
argv0 = os.Args[0]
errors = false
parents = make(map[string]string)
visit = make(map[string]status)
logfile = filepath.Join(runtime.GOROOT(), "goinstall.log")
installedPkgs = make(map[string]bool)
installedPkgs = make(map[string]map[string]bool)
allpkg = flag.Bool("a", false, "install all previously installed packages")
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")
doInstall = flag.Bool("install", true, "build and install")
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)
os.Exit(1)
}
readPackageList()
// special case - "unsafe" is already installed
visit["unsafe"] = done
args := flag.Args()
if *allpkg || *logPkgs {
readPackageList()
}
if *allpkg {
if len(args) != 0 {
usage() // -a and package list both provided
}
// install all packages that were ever installed
if len(installedPkgs) == 0 {
fmt.Fprintf(os.Stderr, "%s: no installed packages\n", argv0)
os.Exit(1)
n := 0
for _, pkgs := range installedPkgs {
for pkg := range pkgs {
args = append(args, pkg)
n++
}
}
args = make([]string, len(installedPkgs), len(installedPkgs))
i := 0
for pkg := range installedPkgs {
args[i] = pkg
i++
if n == 0 {
logf("no installed packages\n")
os.Exit(1)
}
}
if len(args) == 0 {
......@@ -127,27 +126,40 @@ func printDeps(pkg string) {
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() {
pkglistdata, _ := ioutil.ReadFile(logfile)
pkglist := strings.Fields(string(pkglistdata))
for _, pkg := range pkglist {
installedPkgs[pkg] = true
for _, t := range build.Path {
installedPkgs[t.Path] = make(map[string]bool)
name := filepath.Join(t.Path, logfile)
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
func logPackage(pkg string) {
if installedPkgs[pkg] {
return
// logPackage logs the named package as installed in the goinstall.log file
// in the given tree if the package is not already in that file.
func logPackage(pkg string, tree *build.Tree) (logged bool) {
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 {
fmt.Fprintf(os.Stderr, "%s: %s\n", argv0, err)
return
logf("%s\n", err)
return false
}
fmt.Fprintf(fout, "%s\n", pkg)
fout.Close()
return true
}
// install installs the package named by path, which is needed by parent.
......@@ -181,11 +193,10 @@ func install(pkg, parent string) {
return
}
// Download remote packages if not found or forced with -u flag.
remote := isRemote(pkg)
dashReport := false
remote, public := isRemote(pkg), false
if remote && (err == build.ErrNotFound || (err == nil && *update)) {
printf("%s: download\n", pkg)
dashReport, err = download(pkg, tree.SrcDir())
public, err = download(pkg, tree.SrcDir())
}
if err != nil {
errorf("%s: %v\n", pkg, err)
......@@ -244,14 +255,17 @@ func install(pkg, parent string) {
}
}
}
if dashReport {
maybeReportToDashboard(pkg)
}
if remote {
// mark package as installed in $GOROOT/goinstall.log
logPackage(pkg)
// 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
}
// Is this a standard package path? strings container/vector etc.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment