9
"launchpad.net/juju-core/version"
16
// archive writes the executable files found in the given directory in
17
// gzipped tar format to w. An error is returned if an entry inside dir
18
// is not a regular executable file.
19
func archive(w io.Writer, dir string) (err error) {
20
entries, err := ioutil.ReadDir(dir)
25
gzw := gzip.NewWriter(w)
26
defer closeErrorCheck(&err, gzw)
28
tarw := tar.NewWriter(gzw)
29
defer closeErrorCheck(&err, tarw)
31
for _, ent := range entries {
34
if isExecutable(ent) {
39
err := tarw.WriteHeader(h)
43
if err := copyFile(tarw, filepath.Join(dir, ent.Name())); err != nil {
50
// copyFile writes the contents of the given file to w.
51
func copyFile(w io.Writer, file string) error {
52
f, err := os.Open(file)
57
_, err = io.Copy(w, f)
61
// tarHeader returns a tar file header given the file's stat
63
func tarHeader(i os.FileInfo) *tar.Header {
65
Typeflag: tar.TypeReg,
68
Mode: int64(i.Mode() & 0777),
70
AccessTime: i.ModTime(),
71
ChangeTime: i.ModTime(),
77
// isExecutable returns whether the given info
78
// represents a regular file executable by (at least) the user.
79
func isExecutable(i os.FileInfo) bool {
80
return i.Mode()&(0100|os.ModeType) == 0100
83
// closeErrorCheck means that we can ensure that
84
// Close errors do not get lost even when we defer them,
85
func closeErrorCheck(errp *error, c io.Closer) {
92
func setenv(env []string, val string) []string {
93
prefix := val[0 : strings.Index(val, "=")+1]
94
for i, eval := range env {
95
if strings.HasPrefix(eval, prefix) {
100
return append(env, val)
103
// bundleTools bundles all the current juju tools in gzipped tar
104
// format to the given writer.
105
// If forceVersion is not nil, a FORCE-VERSION file is included in
106
// the tools bundle so it will lie about its current version number.
107
func bundleTools(w io.Writer, forceVersion *version.Number) (version.Binary, error) {
108
dir, err := ioutil.TempDir("", "juju-tools")
110
return version.Binary{}, err
112
defer os.RemoveAll(dir)
115
{"go", "install", "launchpad.net/juju-core/cmd/jujud"},
116
{"strip", dir + "/jujud"},
118
env := setenv(os.Environ(), "GOBIN="+dir)
119
for _, args := range cmds {
120
cmd := exec.Command(args[0], args[1:]...)
122
out, err := cmd.CombinedOutput()
124
return version.Binary{}, fmt.Errorf("build command %q failed: %v; %s", args[0], err, out)
127
if forceVersion != nil {
128
if err := ioutil.WriteFile(filepath.Join(dir, "FORCE-VERSION"), []byte(forceVersion.String()), 0666); err != nil {
129
return version.Binary{}, err
132
cmd := exec.Command(filepath.Join(dir, "jujud"), "version")
133
out, err := cmd.CombinedOutput()
135
return version.Binary{}, fmt.Errorf("cannot get version from %q: %v; %s", cmd.Args[0], err, out)
137
tvs := strings.TrimSpace(string(out))
138
tvers, err := version.ParseBinary(tvs)
140
return version.Binary{}, fmt.Errorf("invalid version %q printed by jujud", tvs)
142
err = archive(w, dir)
144
return version.Binary{}, err