~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to misc/dist/bindist.go

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2014-11-18 15:12:26 UTC
  • mfrom: (14.2.12 vivid-proposed)
  • Revision ID: package-import@ubuntu.com-20141118151226-zug7vn93mn3dtiz3
Tags: 2:1.3.2-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - Support co-installability with gccgo-go tool:
    - d/rules,golang-go.install: Rename bin/go -> bin/golang-go
    - d/golang-go.{postinst,prerm}: Install/remove /usr/bin/go using
      alternatives.
  - d/copyright: Amendments for full compiliance with copyright format.
  - d/control: Demote golang-go.tools to Suggests to support Ubuntu MIR.
  - dropped patches (now upstream):
    - d/p/issue27650045_40001_50001.diff
    - d/p/issue28050043_60001_70001.diff
    - d/p/issue54790044_100001_110001.diff

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2012 The Go Authors. All rights reserved.
2
 
// Use of this source code is governed by a BSD-style
3
 
// license that can be found in the LICENSE file.
4
 
 
5
 
// This is a tool for packaging binary releases.
6
 
// It supports FreeBSD, Linux, NetBSD, OpenBSD, OS X, and Windows.
7
 
package main
8
 
 
9
 
import (
10
 
        "archive/tar"
11
 
        "archive/zip"
12
 
        "bufio"
13
 
        "bytes"
14
 
        "compress/gzip"
15
 
        "encoding/base64"
16
 
        "flag"
17
 
        "fmt"
18
 
        "io"
19
 
        "io/ioutil"
20
 
        "log"
21
 
        "mime/multipart"
22
 
        "net/http"
23
 
        "os"
24
 
        "os/exec"
25
 
        "path"
26
 
        "path/filepath"
27
 
        "regexp"
28
 
        "runtime"
29
 
        "strings"
30
 
)
31
 
 
32
 
var (
33
 
        tag             = flag.String("tag", "release", "mercurial tag to check out")
34
 
        toolTag         = flag.String("tool", defaultToolTag, "go.tools tag to check out")
35
 
        repo            = flag.String("repo", "https://code.google.com/p/go", "repo URL")
36
 
        verbose         = flag.Bool("v", false, "verbose output")
37
 
        upload          = flag.Bool("upload", true, "upload resulting files to Google Code")
38
 
        wxsFile         = flag.String("wxs", "", "path to custom installer.wxs")
39
 
        addLabel        = flag.String("label", "", "additional label to apply to file when uploading")
40
 
        includeRace     = flag.Bool("race", true, "build race detector packages")
41
 
        versionOverride = flag.String("version", "", "override version name")
42
 
        staticToolchain = flag.Bool("static", true, "try to build statically linked toolchain (only supported on ELF targets)")
43
 
 
44
 
        username, password string // for Google Code upload
45
 
)
46
 
 
47
 
const (
48
 
        uploadURL      = "https://go.googlecode.com/files"
49
 
        blogPath       = "code.google.com/p/go.blog"
50
 
        toolPath       = "code.google.com/p/go.tools"
51
 
        tourPath       = "code.google.com/p/go-tour"
52
 
        defaultToolTag = "release-branch.go1.2"
53
 
)
54
 
 
55
 
// Import paths for tool commands.
56
 
// These must be the command that cmd/go knows to install to $GOROOT/bin
57
 
// or $GOROOT/pkg/tool.
58
 
var toolPaths = []string{
59
 
        "code.google.com/p/go.tools/cmd/cover",
60
 
        "code.google.com/p/go.tools/cmd/godoc",
61
 
        "code.google.com/p/go.tools/cmd/vet",
62
 
}
63
 
 
64
 
var preBuildCleanFiles = []string{
65
 
        "lib/codereview",
66
 
        "misc/dashboard/godashboard",
67
 
        "src/cmd/cov",
68
 
        "src/cmd/prof",
69
 
        "src/pkg/exp",
70
 
        "src/pkg/old",
71
 
}
72
 
 
73
 
var cleanFiles = []string{
74
 
        ".hg",
75
 
        ".hgtags",
76
 
        ".hgignore",
77
 
        "VERSION.cache",
78
 
}
79
 
 
80
 
var sourceCleanFiles = []string{
81
 
        "bin",
82
 
        "pkg",
83
 
}
84
 
 
85
 
var tourPackages = []string{
86
 
        "pic",
87
 
        "tree",
88
 
        "wc",
89
 
}
90
 
 
91
 
var tourContent = []string{
92
 
        "content",
93
 
        "js",
94
 
        "solutions",
95
 
        "static",
96
 
        "template",
97
 
}
98
 
 
99
 
var blogContent = []string{
100
 
        "content",
101
 
        "template",
102
 
}
103
 
 
104
 
// The os-arches that support the race toolchain.
105
 
var raceAvailable = []string{
106
 
        "darwin-amd64",
107
 
        "linux-amd64",
108
 
        "windows-amd64",
109
 
}
110
 
 
111
 
// The OSes that support building statically linked toolchain
112
 
// Only ELF platforms are supported.
113
 
var staticLinkAvailable = []string{
114
 
        "linux",
115
 
        "freebsd",
116
 
        "openbsd",
117
 
        "netbsd",
118
 
}
119
 
 
120
 
var fileRe = regexp.MustCompile(
121
 
        `^(go[a-z0-9-.]+)\.(src|([a-z0-9]+)-([a-z0-9]+)(?:-([a-z0-9.]))?)\.`)
122
 
 
123
 
func main() {
124
 
        flag.Usage = func() {
125
 
                fmt.Fprintf(os.Stderr, "usage: %s [flags] targets...\n", os.Args[0])
126
 
                flag.PrintDefaults()
127
 
                os.Exit(2)
128
 
        }
129
 
        flag.Parse()
130
 
        if flag.NArg() == 0 {
131
 
                flag.Usage()
132
 
        }
133
 
        if runtime.GOOS == "windows" {
134
 
                checkWindowsDeps()
135
 
        }
136
 
 
137
 
        if *upload {
138
 
                if err := readCredentials(); err != nil {
139
 
                        log.Println("readCredentials:", err)
140
 
                }
141
 
        }
142
 
        for _, targ := range flag.Args() {
143
 
                var b Build
144
 
                if m := fileRe.FindStringSubmatch(targ); m != nil {
145
 
                        // targ is a file name; upload it to googlecode.
146
 
                        version := m[1]
147
 
                        if m[2] == "src" {
148
 
                                b.Source = true
149
 
                        } else {
150
 
                                b.OS = m[3]
151
 
                                b.Arch = m[4]
152
 
                                b.Label = m[5]
153
 
                        }
154
 
                        if !*upload {
155
 
                                log.Printf("%s: -upload=false, skipping", targ)
156
 
                                continue
157
 
                        }
158
 
                        if err := b.Upload(version, targ); err != nil {
159
 
                                log.Printf("%s: %v", targ, err)
160
 
                        }
161
 
                        continue
162
 
                }
163
 
                if targ == "source" {
164
 
                        b.Source = true
165
 
                } else {
166
 
                        p := strings.SplitN(targ, "-", 3)
167
 
                        if len(p) < 2 {
168
 
                                log.Println("Ignoring unrecognized target:", targ)
169
 
                                continue
170
 
                        }
171
 
                        b.OS = p[0]
172
 
                        b.Arch = p[1]
173
 
                        if len(p) >= 3 {
174
 
                                b.Label = p[2]
175
 
                        }
176
 
                        if *includeRace {
177
 
                                for _, t := range raceAvailable {
178
 
                                        if t == targ || strings.HasPrefix(targ, t+"-") {
179
 
                                                b.Race = true
180
 
                                        }
181
 
                                }
182
 
                        }
183
 
                        if *staticToolchain {
184
 
                                for _, os := range staticLinkAvailable {
185
 
                                        if b.OS == os {
186
 
                                                b.static = true
187
 
                                        }
188
 
                                }
189
 
                        }
190
 
                }
191
 
                if err := b.Do(); err != nil {
192
 
                        log.Printf("%s: %v", targ, err)
193
 
                }
194
 
        }
195
 
}
196
 
 
197
 
type Build struct {
198
 
        Source bool // if true, OS and Arch must be empty
199
 
        Race   bool // build race toolchain
200
 
        OS     string
201
 
        Arch   string
202
 
        Label  string
203
 
        root   string
204
 
        gopath string
205
 
        static bool // if true, build statically linked toolchain
206
 
}
207
 
 
208
 
func (b *Build) Do() error {
209
 
        work, err := ioutil.TempDir("", "bindist")
210
 
        if err != nil {
211
 
                return err
212
 
        }
213
 
        defer os.RemoveAll(work)
214
 
        b.root = filepath.Join(work, "go")
215
 
        b.gopath = work
216
 
 
217
 
        // Clone Go distribution and update to tag.
218
 
        _, err = b.hgCmd(work, "clone", *repo, b.root)
219
 
        if err != nil {
220
 
                return err
221
 
        }
222
 
        _, err = b.hgCmd(b.root, "update", *tag)
223
 
        if err != nil {
224
 
                return err
225
 
        }
226
 
 
227
 
        // Remove exp and old packages.
228
 
        if err := b.clean(preBuildCleanFiles); err != nil {
229
 
                return err
230
 
        }
231
 
 
232
 
        src := filepath.Join(b.root, "src")
233
 
        if b.Source {
234
 
                if runtime.GOOS == "windows" {
235
 
                        log.Print("Warning: running make.bash on Windows; source builds are intended to be run on a Unix machine")
236
 
                }
237
 
                // Build dist tool only.
238
 
                _, err = b.run(src, "bash", "make.bash", "--dist-tool")
239
 
        } else {
240
 
                // Build.
241
 
                if b.OS == "windows" {
242
 
                        _, err = b.run(src, "cmd", "/C", "make.bat")
243
 
                } else {
244
 
                        _, err = b.run(src, "bash", "make.bash")
245
 
                }
246
 
                if b.Race {
247
 
                        if err != nil {
248
 
                                return err
249
 
                        }
250
 
                        goCmd := filepath.Join(b.root, "bin", "go")
251
 
                        if b.OS == "windows" {
252
 
                                goCmd += ".exe"
253
 
                        }
254
 
                        _, err = b.run(src, goCmd, "install", "-race", "std")
255
 
                        if err != nil {
256
 
                                return err
257
 
                        }
258
 
                        // Re-install std without -race, so that we're not left
259
 
                        // with a slower, race-enabled cmd/go, etc.
260
 
                        _, err = b.run(src, goCmd, "install", "-a", "std")
261
 
                        // Re-building go command leaves old versions of go.exe as go.exe~ on windows.
262
 
                        // See (*builder).copyFile in $GOROOT/src/cmd/go/build.go for details.
263
 
                        // Remove it manually.
264
 
                        if b.OS == "windows" {
265
 
                                os.Remove(goCmd + "~")
266
 
                        }
267
 
                }
268
 
                if err != nil {
269
 
                        return err
270
 
                }
271
 
                err = b.tools()
272
 
                if err != nil {
273
 
                        return err
274
 
                }
275
 
                err = b.blog()
276
 
                if err != nil {
277
 
                        return err
278
 
                }
279
 
                err = b.tour()
280
 
        }
281
 
        if err != nil {
282
 
                return err
283
 
        }
284
 
 
285
 
        // Get version strings.
286
 
        var (
287
 
                version     string // "weekly.2012-03-04"
288
 
                fullVersion []byte // "weekly.2012-03-04 9353aa1efdf3"
289
 
        )
290
 
        pat := filepath.Join(b.root, "pkg/tool/*/dist*") // trailing * for .exe
291
 
        m, err := filepath.Glob(pat)
292
 
        if err != nil {
293
 
                return err
294
 
        }
295
 
        if len(m) == 0 {
296
 
                return fmt.Errorf("couldn't find dist in %q", pat)
297
 
        }
298
 
        fullVersion, err = b.run("", m[0], "version")
299
 
        if err != nil {
300
 
                return err
301
 
        }
302
 
        fullVersion = bytes.TrimSpace(fullVersion)
303
 
        v := bytes.SplitN(fullVersion, []byte(" "), 2)
304
 
        version = string(v[0])
305
 
        if *versionOverride != "" {
306
 
                version = *versionOverride
307
 
        }
308
 
 
309
 
        // Write VERSION file.
310
 
        err = ioutil.WriteFile(filepath.Join(b.root, "VERSION"), fullVersion, 0644)
311
 
        if err != nil {
312
 
                return err
313
 
        }
314
 
 
315
 
        // Clean goroot.
316
 
        if err := b.clean(cleanFiles); err != nil {
317
 
                return err
318
 
        }
319
 
        if b.Source {
320
 
                if err := b.clean(sourceCleanFiles); err != nil {
321
 
                        return err
322
 
                }
323
 
        }
324
 
 
325
 
        // Create packages.
326
 
        base := fmt.Sprintf("%s.%s-%s", version, b.OS, b.Arch)
327
 
        if b.Label != "" {
328
 
                base += "-" + b.Label
329
 
        }
330
 
        if !strings.HasPrefix(base, "go") {
331
 
                base = "go." + base
332
 
        }
333
 
        var targs []string
334
 
        switch b.OS {
335
 
        case "linux", "freebsd", "netbsd", "":
336
 
                // build tarball
337
 
                targ := base
338
 
                if b.Source {
339
 
                        targ = fmt.Sprintf("%s.src", version)
340
 
                        if !strings.HasPrefix(targ, "go") {
341
 
                                targ = "go." + targ
342
 
                        }
343
 
                }
344
 
                targ += ".tar.gz"
345
 
                err = makeTar(targ, work)
346
 
                targs = append(targs, targ)
347
 
        case "darwin":
348
 
                // build tarball
349
 
                targ := base + ".tar.gz"
350
 
                err = makeTar(targ, work)
351
 
                targs = append(targs, targ)
352
 
 
353
 
                // build pkg
354
 
                // arrange work so it's laid out as the dest filesystem
355
 
                etc := filepath.Join(b.root, "misc/dist/darwin/etc")
356
 
                _, err = b.run(work, "cp", "-r", etc, ".")
357
 
                if err != nil {
358
 
                        return err
359
 
                }
360
 
                localDir := filepath.Join(work, "usr/local")
361
 
                err = os.MkdirAll(localDir, 0755)
362
 
                if err != nil {
363
 
                        return err
364
 
                }
365
 
                _, err = b.run(work, "mv", "go", localDir)
366
 
                if err != nil {
367
 
                        return err
368
 
                }
369
 
                // build package
370
 
                pkgdest, err := ioutil.TempDir("", "pkgdest")
371
 
                if err != nil {
372
 
                        return err
373
 
                }
374
 
                defer os.RemoveAll(pkgdest)
375
 
                dist := filepath.Join(runtime.GOROOT(), "misc/dist")
376
 
                _, err = b.run("", "pkgbuild",
377
 
                        "--identifier", "com.googlecode.go",
378
 
                        "--version", version,
379
 
                        "--scripts", filepath.Join(dist, "darwin/scripts"),
380
 
                        "--root", work,
381
 
                        filepath.Join(pkgdest, "com.googlecode.go.pkg"))
382
 
                if err != nil {
383
 
                        return err
384
 
                }
385
 
                targ = base + ".pkg"
386
 
                _, err = b.run("", "productbuild",
387
 
                        "--distribution", filepath.Join(dist, "darwin/Distribution"),
388
 
                        "--resources", filepath.Join(dist, "darwin/Resources"),
389
 
                        "--package-path", pkgdest,
390
 
                        targ)
391
 
                if err != nil {
392
 
                        return err
393
 
                }
394
 
                targs = append(targs, targ)
395
 
        case "windows":
396
 
                // Create ZIP file.
397
 
                zip := filepath.Join(work, base+".zip")
398
 
                err = makeZip(zip, work)
399
 
                // Copy zip to target file.
400
 
                targ := base + ".zip"
401
 
                err = cp(targ, zip)
402
 
                if err != nil {
403
 
                        return err
404
 
                }
405
 
                targs = append(targs, targ)
406
 
 
407
 
                // Create MSI installer.
408
 
                win := filepath.Join(b.root, "misc/dist/windows")
409
 
                installer := filepath.Join(win, "installer.wxs")
410
 
                if *wxsFile != "" {
411
 
                        installer = *wxsFile
412
 
                }
413
 
                appfiles := filepath.Join(work, "AppFiles.wxs")
414
 
                msi := filepath.Join(work, "installer.msi")
415
 
                // Gather files.
416
 
                _, err = b.run(work, "heat", "dir", "go",
417
 
                        "-nologo",
418
 
                        "-gg", "-g1", "-srd", "-sfrag",
419
 
                        "-cg", "AppFiles",
420
 
                        "-template", "fragment",
421
 
                        "-dr", "INSTALLDIR",
422
 
                        "-var", "var.SourceDir",
423
 
                        "-out", appfiles)
424
 
                if err != nil {
425
 
                        return err
426
 
                }
427
 
                // Build package.
428
 
                _, err = b.run(work, "candle",
429
 
                        "-nologo",
430
 
                        "-dVersion="+version,
431
 
                        "-dArch="+b.Arch,
432
 
                        "-dSourceDir=go",
433
 
                        installer, appfiles)
434
 
                if err != nil {
435
 
                        return err
436
 
                }
437
 
                appfiles = filepath.Join(work, "AppFiles.wixobj")
438
 
                installer = filepath.Join(work, "installer.wixobj")
439
 
                _, err = b.run(win, "light",
440
 
                        "-nologo",
441
 
                        "-ext", "WixUIExtension",
442
 
                        "-ext", "WixUtilExtension",
443
 
                        installer, appfiles,
444
 
                        "-o", msi)
445
 
                if err != nil {
446
 
                        return err
447
 
                }
448
 
                // Copy installer to target file.
449
 
                targ = base + ".msi"
450
 
                err = cp(targ, msi)
451
 
                targs = append(targs, targ)
452
 
        }
453
 
        if err == nil && *upload {
454
 
                for _, targ := range targs {
455
 
                        err = b.Upload(version, targ)
456
 
                        if err != nil {
457
 
                                return err
458
 
                        }
459
 
                }
460
 
        }
461
 
        return err
462
 
}
463
 
 
464
 
func (b *Build) tools() error {
465
 
        defer b.cleanGopath()
466
 
 
467
 
        // Fetch the tool packages (without building/installing).
468
 
        args := append([]string{"get", "-d"}, toolPaths...)
469
 
        _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), args...)
470
 
        if err != nil {
471
 
                return err
472
 
        }
473
 
 
474
 
        // Update the repo to the revision specified by -tool.
475
 
        repoPath := filepath.Join(b.gopath, "src", filepath.FromSlash(toolPath))
476
 
        _, err = b.run(repoPath, "hg", "update", *toolTag)
477
 
        if err != nil {
478
 
                return err
479
 
        }
480
 
 
481
 
        // Install tools.
482
 
        args = append([]string{"install"}, toolPaths...)
483
 
        _, err = b.run(b.gopath, filepath.Join(b.root, "bin", "go"), args...)
484
 
        if err != nil {
485
 
                return err
486
 
        }
487
 
 
488
 
        // Copy doc.go from go.tools/cmd/$CMD to $GOROOT/src/cmd/$CMD
489
 
        // while rewriting "package main" to "package documentation".
490
 
        for _, p := range toolPaths {
491
 
                d, err := ioutil.ReadFile(filepath.Join(b.gopath, "src",
492
 
                        filepath.FromSlash(p), "doc.go"))
493
 
                if err != nil {
494
 
                        return err
495
 
                }
496
 
                d = bytes.Replace(d, []byte("\npackage main\n"),
497
 
                        []byte("\npackage documentation\n"), 1)
498
 
                cmdDir := filepath.Join(b.root, "src", "cmd", path.Base(p))
499
 
                if err := os.MkdirAll(cmdDir, 0755); err != nil {
500
 
                        return err
501
 
                }
502
 
                docGo := filepath.Join(cmdDir, "doc.go")
503
 
                if err := ioutil.WriteFile(docGo, d, 0644); err != nil {
504
 
                        return err
505
 
                }
506
 
        }
507
 
 
508
 
        return nil
509
 
}
510
 
 
511
 
func (b *Build) blog() error {
512
 
        defer b.cleanGopath()
513
 
 
514
 
        // Fetch the blog repository.
515
 
        _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), "get", "-d", blogPath+"/blog")
516
 
        if err != nil {
517
 
                return err
518
 
        }
519
 
 
520
 
        // Copy blog content to $GOROOT/blog.
521
 
        blogSrc := filepath.Join(b.gopath, "src", filepath.FromSlash(blogPath))
522
 
        contentDir := filepath.Join(b.root, "blog")
523
 
        return cpAllDir(contentDir, blogSrc, blogContent...)
524
 
}
525
 
 
526
 
func (b *Build) tour() error {
527
 
        defer b.cleanGopath()
528
 
 
529
 
        // go get the gotour package.
530
 
        _, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), "get", tourPath+"/gotour")
531
 
        if err != nil {
532
 
                return err
533
 
        }
534
 
 
535
 
        // Copy all the tour content to $GOROOT/misc/tour.
536
 
        importPath := filepath.FromSlash(tourPath)
537
 
        tourSrc := filepath.Join(b.gopath, "src", importPath)
538
 
        contentDir := filepath.Join(b.root, "misc", "tour")
539
 
        if err = cpAllDir(contentDir, tourSrc, tourContent...); err != nil {
540
 
                return err
541
 
        }
542
 
 
543
 
        // Copy the tour source code so it's accessible with $GOPATH pointing to $GOROOT/misc/tour.
544
 
        if err = cpAllDir(filepath.Join(contentDir, "src", importPath), tourSrc, tourPackages...); err != nil {
545
 
                return err
546
 
        }
547
 
 
548
 
        // Copy gotour binary to tool directory as "tour"; invoked as "go tool tour".
549
 
        return cp(
550
 
                filepath.Join(b.root, "pkg", "tool", b.OS+"_"+b.Arch, "tour"+ext()),
551
 
                filepath.Join(b.gopath, "bin", "gotour"+ext()),
552
 
        )
553
 
}
554
 
 
555
 
func (b *Build) cleanGopath() {
556
 
        for _, d := range []string{"bin", "pkg", "src"} {
557
 
                os.RemoveAll(filepath.Join(b.gopath, d))
558
 
        }
559
 
}
560
 
 
561
 
func ext() string {
562
 
        if runtime.GOOS == "windows" {
563
 
                return ".exe"
564
 
        }
565
 
        return ""
566
 
}
567
 
 
568
 
func (b *Build) hgCmd(dir string, args ...string) ([]byte, error) {
569
 
        return b.run(dir, "hg", append([]string{"--config", "extensions.codereview=!"}, args...)...)
570
 
}
571
 
 
572
 
func (b *Build) run(dir, name string, args ...string) ([]byte, error) {
573
 
        buf := new(bytes.Buffer)
574
 
        absName, err := lookPath(name)
575
 
        if err != nil {
576
 
                return nil, err
577
 
        }
578
 
        cmd := exec.Command(absName, args...)
579
 
        var output io.Writer = buf
580
 
        if *verbose {
581
 
                log.Printf("Running %q %q", absName, args)
582
 
                output = io.MultiWriter(buf, os.Stdout)
583
 
        }
584
 
        cmd.Stdout = output
585
 
        cmd.Stderr = output
586
 
        cmd.Dir = dir
587
 
        cmd.Env = b.env()
588
 
        if err := cmd.Run(); err != nil {
589
 
                fmt.Fprintf(os.Stderr, "%s", buf.Bytes())
590
 
                return nil, fmt.Errorf("%s %s: %v", name, strings.Join(args, " "), err)
591
 
        }
592
 
        return buf.Bytes(), nil
593
 
}
594
 
 
595
 
var cleanEnv = []string{
596
 
        "GOARCH",
597
 
        "GOBIN",
598
 
        "GOHOSTARCH",
599
 
        "GOHOSTOS",
600
 
        "GOOS",
601
 
        "GOROOT",
602
 
        "GOROOT_FINAL",
603
 
        "GOPATH",
604
 
}
605
 
 
606
 
func (b *Build) env() []string {
607
 
        env := os.Environ()
608
 
        for i := 0; i < len(env); i++ {
609
 
                for _, c := range cleanEnv {
610
 
                        if strings.HasPrefix(env[i], c+"=") {
611
 
                                env = append(env[:i], env[i+1:]...)
612
 
                        }
613
 
                }
614
 
        }
615
 
        final := "/usr/local/go"
616
 
        if b.OS == "windows" {
617
 
                final = `c:\go`
618
 
        }
619
 
        env = append(env,
620
 
                "GOARCH="+b.Arch,
621
 
                "GOHOSTARCH="+b.Arch,
622
 
                "GOHOSTOS="+b.OS,
623
 
                "GOOS="+b.OS,
624
 
                "GOROOT="+b.root,
625
 
                "GOROOT_FINAL="+final,
626
 
                "GOPATH="+b.gopath,
627
 
        )
628
 
        if b.static {
629
 
                env = append(env, "GO_DISTFLAGS=-s")
630
 
        }
631
 
        return env
632
 
}
633
 
 
634
 
func (b *Build) Upload(version string, filename string) error {
635
 
        // Prepare upload metadata.
636
 
        var labels []string
637
 
        os_, arch := b.OS, b.Arch
638
 
        switch b.Arch {
639
 
        case "386":
640
 
                arch = "x86 32-bit"
641
 
        case "amd64":
642
 
                arch = "x86 64-bit"
643
 
        }
644
 
        if arch != "" {
645
 
                labels = append(labels, "Arch-"+b.Arch)
646
 
        }
647
 
        var opsys, ftype string // labels
648
 
        switch b.OS {
649
 
        case "linux":
650
 
                os_ = "Linux"
651
 
                opsys = "Linux"
652
 
        case "freebsd":
653
 
                os_ = "FreeBSD"
654
 
                opsys = "FreeBSD"
655
 
        case "darwin":
656
 
                os_ = "Mac OS X"
657
 
                opsys = "OSX"
658
 
        case "netbsd":
659
 
                os_ = "NetBSD"
660
 
                opsys = "NetBSD"
661
 
        case "windows":
662
 
                os_ = "Windows"
663
 
                opsys = "Windows"
664
 
        }
665
 
        summary := fmt.Sprintf("%s %s (%s)", version, os_, arch)
666
 
        switch {
667
 
        case strings.HasSuffix(filename, ".msi"):
668
 
                ftype = "Installer"
669
 
                summary += " MSI installer"
670
 
        case strings.HasSuffix(filename, ".pkg"):
671
 
                ftype = "Installer"
672
 
                summary += " PKG installer"
673
 
        case strings.HasSuffix(filename, ".zip"):
674
 
                ftype = "Archive"
675
 
                summary += " ZIP archive"
676
 
        case strings.HasSuffix(filename, ".tar.gz"):
677
 
                ftype = "Archive"
678
 
                summary += " tarball"
679
 
        }
680
 
        if b.Source {
681
 
                ftype = "Source"
682
 
                summary = fmt.Sprintf("%s (source only)", version)
683
 
        }
684
 
        if opsys != "" {
685
 
                labels = append(labels, "OpSys-"+opsys)
686
 
        }
687
 
        if ftype != "" {
688
 
                labels = append(labels, "Type-"+ftype)
689
 
        }
690
 
        if b.Label != "" {
691
 
                labels = append(labels, b.Label)
692
 
        }
693
 
        if *addLabel != "" {
694
 
                labels = append(labels, *addLabel)
695
 
        }
696
 
        // Put "Go" prefix on summary when it doesn't already begin with "go".
697
 
        if !strings.HasPrefix(strings.ToLower(summary), "go") {
698
 
                summary = "Go " + summary
699
 
        }
700
 
 
701
 
        // Open file to upload.
702
 
        f, err := os.Open(filename)
703
 
        if err != nil {
704
 
                return err
705
 
        }
706
 
        defer f.Close()
707
 
 
708
 
        // Prepare multipart payload.
709
 
        body := new(bytes.Buffer)
710
 
        w := multipart.NewWriter(body)
711
 
        if err := w.WriteField("summary", summary); err != nil {
712
 
                return err
713
 
        }
714
 
        for _, l := range labels {
715
 
                if err := w.WriteField("label", l); err != nil {
716
 
                        return err
717
 
                }
718
 
        }
719
 
        fw, err := w.CreateFormFile("filename", filename)
720
 
        if err != nil {
721
 
                return err
722
 
        }
723
 
        if _, err = io.Copy(fw, f); err != nil {
724
 
                return err
725
 
        }
726
 
        if err := w.Close(); err != nil {
727
 
                return err
728
 
        }
729
 
 
730
 
        // Send the file to Google Code.
731
 
        req, err := http.NewRequest("POST", uploadURL, body)
732
 
        if err != nil {
733
 
                return err
734
 
        }
735
 
        token := fmt.Sprintf("%s:%s", username, password)
736
 
        token = base64.StdEncoding.EncodeToString([]byte(token))
737
 
        req.Header.Set("Authorization", "Basic "+token)
738
 
        req.Header.Set("Content-type", w.FormDataContentType())
739
 
 
740
 
        resp, err := http.DefaultTransport.RoundTrip(req)
741
 
        if err != nil {
742
 
                return err
743
 
        }
744
 
        if resp.StatusCode/100 != 2 {
745
 
                fmt.Fprintln(os.Stderr, "upload failed")
746
 
                defer resp.Body.Close()
747
 
                io.Copy(os.Stderr, resp.Body)
748
 
                return fmt.Errorf("upload: %s", resp.Status)
749
 
        }
750
 
        return nil
751
 
}
752
 
 
753
 
func (b *Build) clean(files []string) error {
754
 
        for _, name := range files {
755
 
                err := os.RemoveAll(filepath.Join(b.root, name))
756
 
                if err != nil {
757
 
                        return err
758
 
                }
759
 
        }
760
 
        return nil
761
 
}
762
 
 
763
 
func exists(path string) bool {
764
 
        _, err := os.Stat(path)
765
 
        return err == nil
766
 
}
767
 
 
768
 
func readCredentials() error {
769
 
        name := os.Getenv("HOME")
770
 
        if runtime.GOOS == "windows" {
771
 
                name = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
772
 
        }
773
 
        name = filepath.Join(name, ".gobuildkey")
774
 
        f, err := os.Open(name)
775
 
        if err != nil {
776
 
                return err
777
 
        }
778
 
        defer f.Close()
779
 
        r := bufio.NewReader(f)
780
 
        for i := 0; i < 3; i++ {
781
 
                b, _, err := r.ReadLine()
782
 
                if err != nil {
783
 
                        return err
784
 
                }
785
 
                b = bytes.TrimSpace(b)
786
 
                switch i {
787
 
                case 1:
788
 
                        username = string(b)
789
 
                case 2:
790
 
                        password = string(b)
791
 
                }
792
 
        }
793
 
        return nil
794
 
}
795
 
 
796
 
func cp(dst, src string) error {
797
 
        sf, err := os.Open(src)
798
 
        if err != nil {
799
 
                return err
800
 
        }
801
 
        defer sf.Close()
802
 
        fi, err := sf.Stat()
803
 
        if err != nil {
804
 
                return err
805
 
        }
806
 
        df, err := os.Create(dst)
807
 
        if err != nil {
808
 
                return err
809
 
        }
810
 
        defer df.Close()
811
 
        // Windows doesn't currently implement Fchmod
812
 
        if runtime.GOOS != "windows" {
813
 
                if err := df.Chmod(fi.Mode()); err != nil {
814
 
                        return err
815
 
                }
816
 
        }
817
 
        _, err = io.Copy(df, sf)
818
 
        return err
819
 
}
820
 
 
821
 
func cpDir(dst, src string) error {
822
 
        walk := func(srcPath string, info os.FileInfo, err error) error {
823
 
                if err != nil {
824
 
                        return err
825
 
                }
826
 
                dstPath := filepath.Join(dst, srcPath[len(src):])
827
 
                if info.IsDir() {
828
 
                        return os.MkdirAll(dstPath, 0755)
829
 
                }
830
 
                return cp(dstPath, srcPath)
831
 
        }
832
 
        return filepath.Walk(src, walk)
833
 
}
834
 
 
835
 
func cpAllDir(dst, basePath string, dirs ...string) error {
836
 
        for _, dir := range dirs {
837
 
                if err := cpDir(filepath.Join(dst, dir), filepath.Join(basePath, dir)); err != nil {
838
 
                        return err
839
 
                }
840
 
        }
841
 
        return nil
842
 
}
843
 
 
844
 
func makeTar(targ, workdir string) error {
845
 
        f, err := os.Create(targ)
846
 
        if err != nil {
847
 
                return err
848
 
        }
849
 
        zout := gzip.NewWriter(f)
850
 
        tw := tar.NewWriter(zout)
851
 
 
852
 
        err = filepath.Walk(workdir, func(path string, fi os.FileInfo, err error) error {
853
 
                if !strings.HasPrefix(path, workdir) {
854
 
                        log.Panicf("walked filename %q doesn't begin with workdir %q", path, workdir)
855
 
                }
856
 
                name := path[len(workdir):]
857
 
 
858
 
                // Chop of any leading / from filename, leftover from removing workdir.
859
 
                if strings.HasPrefix(name, "/") {
860
 
                        name = name[1:]
861
 
                }
862
 
                // Don't include things outside of the go subdirectory (for instance,
863
 
                // the zip file that we're currently writing here.)
864
 
                if !strings.HasPrefix(name, "go/") {
865
 
                        return nil
866
 
                }
867
 
                if *verbose {
868
 
                        log.Printf("adding to tar: %s", name)
869
 
                }
870
 
                target, _ := os.Readlink(path)
871
 
                hdr, err := tar.FileInfoHeader(fi, target)
872
 
                if err != nil {
873
 
                        return err
874
 
                }
875
 
                hdr.Name = name
876
 
                hdr.Uname = "root"
877
 
                hdr.Gname = "root"
878
 
                hdr.Uid = 0
879
 
                hdr.Gid = 0
880
 
 
881
 
                // Force permissions to 0755 for executables, 0644 for everything else.
882
 
                if fi.Mode().Perm()&0111 != 0 {
883
 
                        hdr.Mode = hdr.Mode&^0777 | 0755
884
 
                } else {
885
 
                        hdr.Mode = hdr.Mode&^0777 | 0644
886
 
                }
887
 
 
888
 
                err = tw.WriteHeader(hdr)
889
 
                if err != nil {
890
 
                        return fmt.Errorf("Error writing file %q: %v", name, err)
891
 
                }
892
 
                if fi.IsDir() {
893
 
                        return nil
894
 
                }
895
 
                r, err := os.Open(path)
896
 
                if err != nil {
897
 
                        return err
898
 
                }
899
 
                defer r.Close()
900
 
                _, err = io.Copy(tw, r)
901
 
                return err
902
 
        })
903
 
        if err != nil {
904
 
                return err
905
 
        }
906
 
        if err := tw.Close(); err != nil {
907
 
                return err
908
 
        }
909
 
        if err := zout.Close(); err != nil {
910
 
                return err
911
 
        }
912
 
        return f.Close()
913
 
}
914
 
 
915
 
func makeZip(targ, workdir string) error {
916
 
        f, err := os.Create(targ)
917
 
        if err != nil {
918
 
                return err
919
 
        }
920
 
        zw := zip.NewWriter(f)
921
 
 
922
 
        err = filepath.Walk(workdir, func(path string, fi os.FileInfo, err error) error {
923
 
                if !strings.HasPrefix(path, workdir) {
924
 
                        log.Panicf("walked filename %q doesn't begin with workdir %q", path, workdir)
925
 
                }
926
 
                name := path[len(workdir):]
927
 
 
928
 
                // Convert to Unix-style named paths, as that's the
929
 
                // type of zip file that archive/zip creates.
930
 
                name = strings.Replace(name, "\\", "/", -1)
931
 
                // Chop of any leading / from filename, leftover from removing workdir.
932
 
                if strings.HasPrefix(name, "/") {
933
 
                        name = name[1:]
934
 
                }
935
 
                // Don't include things outside of the go subdirectory (for instance,
936
 
                // the zip file that we're currently writing here.)
937
 
                if !strings.HasPrefix(name, "go/") {
938
 
                        return nil
939
 
                }
940
 
                if *verbose {
941
 
                        log.Printf("adding to zip: %s", name)
942
 
                }
943
 
                fh, err := zip.FileInfoHeader(fi)
944
 
                if err != nil {
945
 
                        return err
946
 
                }
947
 
                fh.Name = name
948
 
                fh.Method = zip.Deflate
949
 
                if fi.IsDir() {
950
 
                        fh.Name += "/"        // append trailing slash
951
 
                        fh.Method = zip.Store // no need to deflate 0 byte files
952
 
                }
953
 
                w, err := zw.CreateHeader(fh)
954
 
                if err != nil {
955
 
                        return err
956
 
                }
957
 
                if fi.IsDir() {
958
 
                        return nil
959
 
                }
960
 
                r, err := os.Open(path)
961
 
                if err != nil {
962
 
                        return err
963
 
                }
964
 
                defer r.Close()
965
 
                _, err = io.Copy(w, r)
966
 
                return err
967
 
        })
968
 
        if err != nil {
969
 
                return err
970
 
        }
971
 
        if err := zw.Close(); err != nil {
972
 
                return err
973
 
        }
974
 
        return f.Close()
975
 
}
976
 
 
977
 
type tool struct {
978
 
        name       string
979
 
        commonDirs []string
980
 
}
981
 
 
982
 
var wixTool = tool{
983
 
        "http://wix.sourceforge.net/, version 3.5",
984
 
        []string{`C:\Program Files\Windows Installer XML v3.5\bin`,
985
 
                `C:\Program Files (x86)\Windows Installer XML v3.5\bin`},
986
 
}
987
 
 
988
 
var hgTool = tool{
989
 
        "http://mercurial.selenic.com/wiki/WindowsInstall",
990
 
        []string{`C:\Program Files\Mercurial`,
991
 
                `C:\Program Files (x86)\Mercurial`,
992
 
        },
993
 
}
994
 
 
995
 
var gccTool = tool{
996
 
        "Mingw gcc; http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/",
997
 
        []string{`C:\Mingw\bin`},
998
 
}
999
 
 
1000
 
var windowsDeps = map[string]tool{
1001
 
        "gcc":    gccTool,
1002
 
        "heat":   wixTool,
1003
 
        "candle": wixTool,
1004
 
        "light":  wixTool,
1005
 
        "cmd":    {"Windows cmd.exe", nil},
1006
 
        "hg":     hgTool,
1007
 
}
1008
 
 
1009
 
func checkWindowsDeps() {
1010
 
        for prog, help := range windowsDeps {
1011
 
                absPath, err := lookPath(prog)
1012
 
                if err != nil {
1013
 
                        log.Fatalf("Failed to find necessary binary %q in path or common locations; %s", prog, help)
1014
 
                }
1015
 
                if *verbose {
1016
 
                        log.Printf("found windows dep %s at %s", prog, absPath)
1017
 
                }
1018
 
        }
1019
 
}
1020
 
 
1021
 
func lookPath(prog string) (absPath string, err error) {
1022
 
        absPath, err = exec.LookPath(prog)
1023
 
        if err == nil {
1024
 
                return
1025
 
        }
1026
 
        t, ok := windowsDeps[prog]
1027
 
        if !ok {
1028
 
                return
1029
 
        }
1030
 
        for _, dir := range t.commonDirs {
1031
 
                for _, ext := range []string{"exe", "bat"} {
1032
 
                        absPath = filepath.Join(dir, prog+"."+ext)
1033
 
                        if _, err1 := os.Stat(absPath); err1 == nil {
1034
 
                                err = nil
1035
 
                                os.Setenv("PATH", os.Getenv("PATH")+";"+dir)
1036
 
                                return
1037
 
                        }
1038
 
                }
1039
 
        }
1040
 
        return
1041
 
}