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:
parent
d56c8132e8
commit
fc2480da3c
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user