Merge "jiri: Support installation of base profile on fnl"
diff --git a/profiles/util.go b/profiles/util.go
index 3e6e3ff..4be9a35 100644
--- a/profiles/util.go
+++ b/profiles/util.go
@@ -5,10 +5,12 @@
package profiles
import (
+ "archive/zip"
"bufio"
"bytes"
"flag"
"fmt"
+ "net/http"
"os"
"path/filepath"
"runtime"
@@ -253,7 +255,30 @@
return nil
}
+// Fetch downloads the specified url and saves it to dst.
+// TODO(nlacasse, cnicoloau): Move this to a package for profile-implementors
+// so it does not pollute the profile package namespace.
+func Fetch(ctx *tool.Context, dst, url string) error {
+ ctx.Run().Output([]string{"fetching " + url})
+ resp, err := http.Get(url)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("got non-200 status code while getting %v: %v", url, resp.StatusCode)
+ }
+ file, err := ctx.Run().Create(dst)
+ if err != nil {
+ return err
+ }
+ _, err = ctx.Run().Copy(file, resp.Body)
+ return err
+}
+
// GitCloneRepo clones a repo at a specific revision in outDir.
+// TODO(nlacasse, cnicoloau): Move this to a package for profile-implementors
+// so it does not pollute the profile package namespace.
func GitCloneRepo(ctx *tool.Context, remote, revision, outDir string, outDirPerm os.FileMode) (e error) {
cwd, err := os.Getwd()
if err != nil {
@@ -270,8 +295,45 @@
if err := ctx.Run().Chdir(outDir); err != nil {
return err
}
- if err := ctx.Git().Reset(revision); err != nil {
+ return ctx.Git().Reset(revision)
+}
+
+// Unzip unzips the file in srcFile and puts resulting files in directory dstDir.
+// TODO(nlacasse, cnicoloau): Move this to a package for profile-implementors
+// so it does not pollute the profile package namespace.
+func Unzip(ctx *tool.Context, srcFile, dstDir string) error {
+ r, err := zip.OpenReader(srcFile)
+ if err != nil {
return err
}
+ defer r.Close()
+
+ unzipFn := func(zFile *zip.File) error {
+ rc, err := zFile.Open()
+ if err != nil {
+ return err
+ }
+ defer rc.Close()
+
+ fileDst := filepath.Join(dstDir, zFile.Name)
+ if zFile.FileInfo().IsDir() {
+ return ctx.Run().MkdirAll(fileDst, zFile.Mode())
+ }
+ file, err := ctx.Run().OpenFile(fileDst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, zFile.Mode())
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+ _, err = ctx.Run().Copy(file, rc)
+ return err
+ }
+
+ ctx.Run().Output([]string{"unzipping " + srcFile})
+ for _, zFile := range r.File {
+ ctx.Run().Output([]string{"extracting " + zFile.Name})
+ if err := unzipFn(zFile); err != nil {
+ return err
+ }
+ }
return nil
}
diff --git a/runutil/wrapper.go b/runutil/wrapper.go
index 6a3a3f2..d4c63b3 100644
--- a/runutil/wrapper.go
+++ b/runutil/wrapper.go
@@ -4,12 +4,9 @@
package runutil
-// TODO(jsimsa): Write wrappers for additional functions from the Go
-// standard libraries "os" and "ioutil" that our tools use: Chmod(),
-// Create(), OpenFile(), ...
-
import (
"fmt"
+ "io"
"io/ioutil"
"os"
"os/exec"
@@ -57,6 +54,26 @@
return r.helper(func() error { return os.Chmod(dir, mode) }, fmt.Sprintf("chmod %v %q", mode, dir))
}
+// Create is a wrapper around os.Create that handles options such as "verbose"
+// or "dry run".
+func (r *Run) Create(name string) (f *os.File, err error) {
+ r.helper(func() error {
+ f, err = os.Create(name)
+ return err
+ }, fmt.Sprintf("create %q", name))
+ return
+}
+
+// Copy is a wrapper around io.Copy that handles options such as "verbose" or
+// "dry run".
+func (r *Run) Copy(dst *os.File, src io.Reader) (n int64, err error) {
+ r.helper(func() error {
+ n, err = io.Copy(dst, src)
+ return err
+ }, fmt.Sprintf("io.copy %q", dst.Name()))
+ return
+}
+
// MkdirAll is a wrapper around os.MkdirAll that handles options such
// as "verbose" or "dry run".
func (r *Run) MkdirAll(dir string, mode os.FileMode) error {
@@ -65,38 +82,42 @@
// Open is a wrapper around os.Open that handles options such as
// "verbose" or "dry run".
-func (r *Run) Open(name string) (*os.File, error) {
- var file *os.File
- var err error
+func (r *Run) Open(name string) (f *os.File, err error) {
r.helper(func() error {
- file, err = os.Open(name)
+ f, err = os.Open(name)
return err
}, fmt.Sprintf("open %q", name))
- return file, err
+ return
+}
+
+// OpenFile is a wrapper around os.OpenFile that handles options such as
+// "verbose" or "dry run".
+func (r *Run) OpenFile(name string, flag int, perm os.FileMode) (f *os.File, err error) {
+ r.helper(func() error {
+ f, err = os.OpenFile(name, flag, perm)
+ return err
+ }, fmt.Sprintf("open file %q", name))
+ return
}
// ReadDir is a wrapper around ioutil.ReadDir that handles options
// such as "verbose" or "dry run".
-func (r *Run) ReadDir(dirname string) ([]os.FileInfo, error) {
- var fileInfos []os.FileInfo
- var err error
+func (r *Run) ReadDir(dirname string) (fileInfos []os.FileInfo, err error) {
r.dryRun(func() error {
fileInfos, err = ioutil.ReadDir(dirname)
return err
}, fmt.Sprintf("ls %q", dirname))
- return fileInfos, err
+ return
}
// ReadFile is a wrapper around ioutil.ReadFile that handles options
// such as "verbose" or "dry run".
-func (r *Run) ReadFile(filename string) ([]byte, error) {
- var bytes []byte
- var err error
+func (r *Run) ReadFile(filename string) (bytes []byte, err error) {
r.dryRun(func() error {
bytes, err = ioutil.ReadFile(filename)
return err
}, fmt.Sprintf("read %q", filename))
- return bytes, err
+ return
}
// RemoveAll is a wrapper around os.RemoveAll that handles options
@@ -137,14 +158,12 @@
// Stat is a wrapper around os.Stat that handles options such as
// "verbose" or "dry run".
-func (r *Run) Stat(name string) (os.FileInfo, error) {
- var fileInfo os.FileInfo
- var err error
+func (r *Run) Stat(name string) (fileInfo os.FileInfo, err error) {
r.dryRun(func() error {
fileInfo, err = os.Stat(name)
return err
}, fmt.Sprintf("stat %q", name))
- return fileInfo, err
+ return
}
// IsDir is a wrapper around os.Stat that handles options such as
@@ -170,24 +189,34 @@
// TempDir is a wrapper around ioutil.TempDir that handles options
// such as "verbose" or "dry run".
-func (r *Run) TempDir(dir, prefix string) (string, error) {
- var err error
+func (r *Run) TempDir(dir, prefix string) (tmpDir string, err error) {
if dir == "" {
dir = os.Getenv("TMPDIR")
}
- tmpDir := fmt.Sprintf("%v%c%vXXXXXX", dir, os.PathSeparator, prefix)
- tmpDir = filepath.Clean(tmpDir)
+ tmpDir = filepath.Join(dir, prefix+"XXXXXX")
r.helper(func() error {
tmpDir, err = ioutil.TempDir(dir, prefix)
return err
}, fmt.Sprintf("mkdir -p %q", tmpDir))
- return tmpDir, err
+ return
+}
+
+// TempFile is a wrapper around ioutil.TempFile that handles options
+// such as "verbose" or "dry run".
+func (r *Run) TempFile(dir, prefix string) (f *os.File, err error) {
+ r.helper(func() error {
+ f, err = ioutil.TempFile(dir, prefix)
+ return err
+ }, fmt.Sprintf("open %q", f.Name()))
+ return
}
// WriteFile is a wrapper around ioutil.WriteFile that handles options
// such as "verbose" or "dry run".
func (r *Run) WriteFile(filename string, data []byte, perm os.FileMode) error {
- return r.helper(func() error { return ioutil.WriteFile(filename, data, perm) }, fmt.Sprintf("write %q", filename))
+ return r.helper(func() error {
+ return ioutil.WriteFile(filename, data, perm)
+ }, fmt.Sprintf("write %q", filename))
}
// DirectoryExists tests if a directory exists with appropriate logging.