3
3
// license that can be found in the LICENSE file.
5
5
// This is a tool for packaging binary releases.
6
// It supports FreeBSD, Linux, OS X, and Windows.
6
// It supports FreeBSD, Linux, NetBSD, OS X, and Windows.
33
tag = flag.String("tag", "weekly", "mercurial tag to check out")
34
repo = flag.String("repo", "https://code.google.com/p/go", "repo URL")
35
verbose = flag.Bool("v", false, "verbose output")
36
upload = flag.Bool("upload", true, "upload resulting files to Google Code")
37
wxsFile = flag.String("wxs", "", "path to custom installer.wxs")
38
addLabel = flag.String("label", "", "additional label to apply to file when uploading")
32
tag = flag.String("tag", "release", "mercurial tag to check out")
33
repo = flag.String("repo", "https://code.google.com/p/go", "repo URL")
34
tourPath = flag.String("tour", "code.google.com/p/go-tour", "Go tour repo import path")
35
verbose = flag.Bool("v", false, "verbose output")
36
upload = flag.Bool("upload", true, "upload resulting files to Google Code")
37
wxsFile = flag.String("wxs", "", "path to custom installer.wxs")
38
addLabel = flag.String("label", "", "additional label to apply to file when uploading")
39
includeRace = flag.Bool("race", true, "build race detector packages")
40
versionOverride = flag.String("version", "", "override version name")
40
42
username, password string // for Google Code upload
44
packageMaker = "/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker"
45
uploadURL = "https://go.googlecode.com/files"
46
uploadURL = "https://go.googlecode.com/files"
48
49
var preBuildCleanFiles = []string{
69
var fileRe = regexp.MustCompile(`^go\.([a-z0-9-.]+)\.(src|([a-z0-9]+)-([a-z0-9]+))\.`)
70
var tourPackages = []string{
76
var tourContent = []string{
85
// The os-arches that support the race toolchain.
86
var raceAvailable = []string{
92
var fileRe = regexp.MustCompile(`^(go[a-z0-9-.]+)\.(src|([a-z0-9]+)-([a-z0-9]+))\.`)
72
95
flag.Usage = func() {
139
171
defer os.RemoveAll(work)
140
172
b.root = filepath.Join(work, "go")
142
175
// Clone Go distribution and update to tag.
143
176
_, err = b.run(work, "hg", "clone", "-q", *repo, b.root)
169
202
_, err = b.run(src, "bash", "make.bash")
208
goCmd := filepath.Join(b.root, "bin", "go")
209
if b.OS == "windows" {
212
_, err = b.run(src, goCmd, "install", "-race", "std")
216
// Re-install std without -race, so that we're not left
217
// with a slower, race-enabled cmd/go, cmd/godoc, etc.
218
_, err = b.run(src, goCmd, "install", "-a", "std")
193
246
fullVersion = bytes.TrimSpace(fullVersion)
194
247
v := bytes.SplitN(fullVersion, []byte(" "), 2)
195
248
version = string(v[0])
249
if *versionOverride != "" {
250
version = *versionOverride
197
253
// Write VERSION file.
198
254
err = ioutil.WriteFile(filepath.Join(b.root, "VERSION"), fullVersion, 0644)
213
269
// Create packages.
214
base := fmt.Sprintf("go.%s.%s-%s", version, b.OS, b.Arch)
270
base := fmt.Sprintf("%s.%s-%s", version, b.OS, b.Arch)
271
if !strings.HasPrefix(base, "go") {
215
274
var targs []string
217
case "linux", "freebsd", "":
276
case "linux", "freebsd", "netbsd", "":
221
targ = fmt.Sprintf("go.%s.src", version)
280
targ = fmt.Sprintf("%s.src", version)
281
if !strings.HasPrefix(targ, "go") {
223
285
targ += ".tar.gz"
224
286
err = makeTar(targ, work)
225
287
targs = append(targs, targ)
290
targ := base + ".tar.gz"
291
err = makeTar(targ, work)
292
targs = append(targs, targ)
227
295
// arrange work so it's laid out as the dest filesystem
228
296
etc := filepath.Join(b.root, "misc/dist/darwin/etc")
229
297
_, err = b.run(work, "cp", "-r", etc, ".")
233
301
localDir := filepath.Join(work, "usr/local")
234
err = os.MkdirAll(localDir, 0744)
302
err = os.MkdirAll(localDir, 0755)
245
pm = "/Developer" + pm
247
return errors.New("couldn't find PackageMaker")
311
pkgdest, err := ioutil.TempDir("", "pkgdest")
250
targ := base + ".pkg"
251
scripts := filepath.Join(work, "usr/local/go/misc/dist/darwin/scripts")
252
_, err = b.run("", pm, "-v",
255
"--scripts", scripts,
256
"--id", "com.googlecode.go",
315
defer os.RemoveAll(pkgdest)
316
dist := filepath.Join(runtime.GOROOT(), "misc/dist")
317
_, err = b.run("", "pkgbuild",
318
"--identifier", "com.googlecode.go",
258
319
"--version", "1.0",
320
"--scripts", filepath.Join(dist, "darwin/scripts"),
322
filepath.Join(pkgdest, "com.googlecode.go.pkg"))
327
_, err = b.run("", "productbuild",
328
"--distribution", filepath.Join(dist, "darwin/Distribution"),
329
"--resources", filepath.Join(dist, "darwin/Resources"),
330
"--package-path", pkgdest,
260
335
targs = append(targs, targ)
262
337
// Create ZIP file.
405
func (b *Build) tour() error {
406
// go get the gotour package.
407
_, err := b.run(b.gopath, filepath.Join(b.root, "bin", "go"), "get", *tourPath+"/gotour")
412
// Copy all the tour content to $GOROOT/misc/tour.
413
importPath := filepath.FromSlash(*tourPath)
414
tourSrc := filepath.Join(b.gopath, "src", importPath)
415
contentDir := filepath.Join(b.root, "misc", "tour")
416
if err = cpAllDir(contentDir, tourSrc, tourContent...); err != nil {
420
// Copy the tour source code so it's accessible with $GOPATH pointing to $GOROOT/misc/tour.
421
if err = cpAllDir(filepath.Join(contentDir, "src", importPath), tourSrc, tourPackages...); err != nil {
425
// Copy gotour binary to tool directory as "tour"; invoked as "go tool tour".
427
if runtime.GOOS == "windows" {
431
filepath.Join(b.root, "pkg", "tool", b.OS+"_"+b.Arch, "tour"+ext),
432
filepath.Join(b.gopath, "bin", "gotour"+ext),
330
436
func (b *Build) run(dir, name string, args ...string) ([]byte, error) {
331
437
buf := new(bytes.Buffer)
332
438
absName, err := lookPath(name)
390
498
os_, arch := b.OS, b.Arch
398
506
labels = append(labels, "Arch-"+b.Arch)
508
var opsys, ftype string // labels
403
labels = append(labels, "Type-Archive", "OpSys-Linux")
406
labels = append(labels, "Type-Archive", "OpSys-FreeBSD")
409
labels = append(labels, "Type-Installer", "OpSys-OSX")
412
labels = append(labels, "OpSys-Windows")
414
526
summary := fmt.Sprintf("%s %s (%s)", version, os_, arch)
415
if b.OS == "windows" {
417
case strings.HasSuffix(filename, ".msi"):
418
labels = append(labels, "Type-Installer")
419
summary += " MSI installer"
420
case strings.HasSuffix(filename, ".zip"):
421
labels = append(labels, "Type-Archive")
422
summary += " ZIP archive"
528
case strings.HasSuffix(filename, ".msi"):
530
summary += " MSI installer"
531
case strings.HasSuffix(filename, ".pkg"):
533
summary += " PKG installer"
534
case strings.HasSuffix(filename, ".zip"):
536
summary += " ZIP archive"
537
case strings.HasSuffix(filename, ".tar.gz"):
539
summary += " tarball"
426
labels = append(labels, "Type-Source")
427
543
summary = fmt.Sprintf("%s (source only)", version)
546
labels = append(labels, "OpSys-"+opsys)
549
labels = append(labels, "Type-"+ftype)
429
551
if *addLabel != "" {
430
552
labels = append(labels, *addLabel)
538
664
df, err := os.Create(dst)
669
// Windows doesn't currently implement Fchmod
670
if runtime.GOOS != "windows" {
671
if err := df.Chmod(fi.Mode()); err != nil {
543
675
_, err = io.Copy(df, sf)
679
func cpDir(dst, src string) error {
680
walk := func(srcPath string, info os.FileInfo, err error) error {
684
dstPath := filepath.Join(dst, srcPath[len(src):])
686
return os.MkdirAll(dstPath, 0755)
688
return cp(dstPath, srcPath)
690
return filepath.Walk(src, walk)
693
func cpAllDir(dst, basePath string, dirs ...string) error {
694
for _, dir := range dirs {
695
if err := cpDir(filepath.Join(dst, dir), filepath.Join(basePath, dir)); err != nil {
547
702
func makeTar(targ, workdir string) error {
548
703
f, err := os.Create(targ)
552
707
zout := gzip.NewWriter(f)
553
708
tw := tar.NewWriter(zout)
555
filepath.Walk(workdir, filepath.WalkFunc(func(path string, fi os.FileInfo, err error) error {
710
err = filepath.Walk(workdir, func(path string, fi os.FileInfo, err error) error {
556
711
if !strings.HasPrefix(path, workdir) {
557
712
log.Panicf("walked filename %q doesn't begin with workdir %q", path, workdir)
571
726
log.Printf("adding to tar: %s", name)
576
hdr, err := tarFileInfoHeader(fi, path)
728
target, _ := os.Readlink(path)
729
hdr, err := tar.FileInfoHeader(fi, target)
620
778
zw := zip.NewWriter(f)
622
filepath.Walk(workdir, filepath.WalkFunc(func(path string, fi os.FileInfo, err error) error {
780
err = filepath.Walk(workdir, func(path string, fi os.FileInfo, err error) error {
626
781
if !strings.HasPrefix(path, workdir) {
627
782
log.Panicf("walked filename %q doesn't begin with workdir %q", path, workdir)
737
// sysStat, if non-nil, populates h from system-dependent fields of fi.
738
var sysStat func(fi os.FileInfo, h *tar.Header) error
740
// Mode constants from the tar spec.
751
// tarFileInfoHeader creates a partially-populated Header from an os.FileInfo.
752
// The filename parameter is used only in the case of symlinks, to call os.Readlink.
753
// If fi is a symlink but filename is empty, an error is returned.
754
func tarFileInfoHeader(fi os.FileInfo, filename string) (*tar.Header, error) {
757
ModTime: fi.ModTime(),
758
Mode: int64(fi.Mode().Perm()), // or'd with c_IS* constants later
761
case fi.Mode()&os.ModeType == 0:
763
h.Typeflag = tar.TypeReg
766
h.Typeflag = tar.TypeDir
768
case fi.Mode()&os.ModeSymlink != 0:
769
h.Typeflag = tar.TypeSymlink
772
return h, fmt.Errorf("archive/tar: unable to populate Header.Linkname of symlinks")
774
targ, err := os.Readlink(filename)
779
case fi.Mode()&os.ModeDevice != 0:
780
if fi.Mode()&os.ModeCharDevice != 0 {
782
h.Typeflag = tar.TypeChar
785
h.Typeflag = tar.TypeBlock
787
case fi.Mode()&os.ModeSocket != 0:
790
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fi.Mode())
793
return h, sysStat(fi, h)