diff options
Diffstat (limited to 'misc')
-rw-r--r-- | misc/cgo/gmp/gmp.go | 5 | ||||
-rw-r--r-- | misc/chrome/gophertool/README.txt | 8 | ||||
-rw-r--r-- | misc/chrome/gophertool/background.html | 24 | ||||
-rw-r--r-- | misc/chrome/gophertool/gopher.js | 34 | ||||
-rw-r--r-- | misc/chrome/gophertool/gopher.png | bin | 0 -> 5588 bytes | |||
-rw-r--r-- | misc/chrome/gophertool/manifest.json | 17 | ||||
-rw-r--r-- | misc/chrome/gophertool/popup.html | 54 | ||||
-rw-r--r-- | misc/dashboard/builder/exec.go | 59 | ||||
-rw-r--r-- | misc/dashboard/builder/main.go | 44 | ||||
-rw-r--r-- | misc/dashboard/godashboard/app.yaml | 2 | ||||
-rw-r--r-- | misc/dashboard/godashboard/gobuild.py | 91 | ||||
-rwxr-xr-x | misc/dashboard/googlecode_upload.py | 2 | ||||
-rw-r--r-- | misc/emacs/go-mode.el | 2 | ||||
-rw-r--r-- | misc/godoc/README | 22 | ||||
-rw-r--r-- | misc/godoc/app.yaml | 12 | ||||
-rw-r--r-- | misc/godoc/init.go | 35 | ||||
-rw-r--r-- | misc/goplay/goplay.go | 28 | ||||
-rw-r--r-- | misc/vim/ftplugin/go/fmt.vim | 2 |
18 files changed, 368 insertions, 73 deletions
diff --git a/misc/cgo/gmp/gmp.go b/misc/cgo/gmp/gmp.go index f7bbe9c51..7faa71b69 100644 --- a/misc/cgo/gmp/gmp.go +++ b/misc/cgo/gmp/gmp.go @@ -86,9 +86,8 @@ explicitly in Go to pointers to arrays, as they do (implicitly) in C. Garbage collection is the big problem. It is fine for the Go world to have pointers into the C world and to free those pointers when they -are no longer needed. To help, the garbage collector calls an -object's destroy() method prior to collecting it. C pointers can be -wrapped by Go objects with appropriate destroy methods. +are no longer needed. To help, the Go code can define Go objects +holding the C pointers and use runtime.SetFinalizer on those Go objects. It is much more difficult for the C world to have pointers into the Go world, because the Go garbage collector is unaware of the memory diff --git a/misc/chrome/gophertool/README.txt b/misc/chrome/gophertool/README.txt new file mode 100644 index 000000000..a7c0b4b26 --- /dev/null +++ b/misc/chrome/gophertool/README.txt @@ -0,0 +1,8 @@ +To install: + +1) chrome://extensions/ +2) click "[+] Developer Mode" in top right +3) "Load unpacked extension..." +4) pick $GOROOT/misc/chrome/gophertool + +Done. It'll now auto-reload from source. diff --git a/misc/chrome/gophertool/background.html b/misc/chrome/gophertool/background.html new file mode 100644 index 000000000..058c18142 --- /dev/null +++ b/misc/chrome/gophertool/background.html @@ -0,0 +1,24 @@ +<html> +<!-- + Copyright 2011 The Go Authors. All rights reserved. + Use of this source code is governed by a BSD-style + license that can be found in the LICENSE file. +--> +<head> +<script src="gopher.js"></script> +<script> + +chrome.omnibox.onInputEntered.addListener(function(t) { + var url = urlForInput(t); + if (url) { + chrome.tabs.getSelected(null, function(tab) { + if (!tab) return; + chrome.tabs.update(tab.id, { "url": url, "selected": true }); + }); + } +}); + +</script> +</head> +</html> + diff --git a/misc/chrome/gophertool/gopher.js b/misc/chrome/gophertool/gopher.js new file mode 100644 index 000000000..847c1c70d --- /dev/null +++ b/misc/chrome/gophertool/gopher.js @@ -0,0 +1,34 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +var numericRE = /^\d+$/; +var commitRE = /^(?:\d+:)?([0-9a-f]{6,20})$/; // e.g "8486:ab29d2698a47" or "ab29d2698a47" +var pkgRE = /^[a-z0-9_\/]+$/; + +function urlForInput(t) { + if (!t) { + return null; + } + + if (numericRE.test(t)) { + if (t < 1000000) { + return "http://code.google.com/p/go/issues/detail?id=" + t; + } + return "http://codereview.appspot.com/" + t + "/"; + } + + var match = commitRE.exec(t); + if (match) { + return "http://code.google.com/p/go/source/detail?r=" + match[1]; + } + + if (pkgRE.test(t)) { + // TODO: make this smarter, using a list of packages + substring matches. + // Get the list from godoc itself in JSON format? + // TODO: prefer localhost:6060 to golang.org if localhost:6060 is responding. + return "http://golang.org/pkg/" + t; + } + + return null; +} diff --git a/misc/chrome/gophertool/gopher.png b/misc/chrome/gophertool/gopher.png Binary files differnew file mode 100644 index 000000000..0d1abb741 --- /dev/null +++ b/misc/chrome/gophertool/gopher.png diff --git a/misc/chrome/gophertool/manifest.json b/misc/chrome/gophertool/manifest.json new file mode 100644 index 000000000..3a2540a86 --- /dev/null +++ b/misc/chrome/gophertool/manifest.json @@ -0,0 +1,17 @@ +{ + "name": "Hacking Gopher", + "version": "1.0", + "description": "Go Hacking utility", + "background_page": "background.html", + "browser_action": { + "default_icon": "gopher.png", + "popup": "popup.html" + }, + "omnibox": { "keyword": "golang" }, + "icons": { + "16": "gopher.png" + }, + "permissions": [ + "tabs" + ] +} diff --git a/misc/chrome/gophertool/popup.html b/misc/chrome/gophertool/popup.html new file mode 100644 index 000000000..ebbc71f3a --- /dev/null +++ b/misc/chrome/gophertool/popup.html @@ -0,0 +1,54 @@ +<html> +<!-- + Copyright 2011 The Go Authors. All rights reserved. + Use of this source code is governed by a BSD-style + license that can be found in the LICENSE file. +--> +<head> +<script src="gopher.js"></script> +<script> + +function focusinput() { + document.getElementById("inputbox").focus(); +} + +function navigate() { + var box = document.getElementById("inputbox"); + box.focus(); + + var t = box.value; + if (t == "") { + return false; + } + + var success = function(url) { + console.log("matched " + t + " to: " + url) + box.value = ""; + openURL(url); + return false; // cancel form submission + }; + + var url = urlForInput(t); + if (url) { + return success(url); + } + + console.log("no match for text: " + t) + return false; +} + +function openURL(url) { + chrome.tabs.create({ "url": url }) +} + +</script> +</head> +<body onload="focusinput()" style='margin: 0.5em; font-family: sans;'> +<small><a href="#" onclick="openURL('http://code.google.com/p/go/issues/list')">issue</a>, +<a href="#" onclick="openURL('http://codereview.appspot.com/')">codereview</a>, +<a href="#" onclick="openURL('http://code.google.com/p/go/source/list')">commit</a>, or +<a href="#" onclick="openURL('http://golang.org/pkg/')">pkg</a> id/name:</small> +<form style='margin: 0' onsubmit="return navigate();"><nobr><input id="inputbox" size=10 /><input type="submit" value="go" /></nobr></form> +<small>Also: <a href="#" onclick="openURL('http://godashboard.appspot.com/')">buildbots</small> +</body> +</html> diff --git a/misc/dashboard/builder/exec.go b/misc/dashboard/builder/exec.go index 988d216ce..0db509136 100644 --- a/misc/dashboard/builder/exec.go +++ b/misc/dashboard/builder/exec.go @@ -18,16 +18,12 @@ func run(envv []string, dir string, argv ...string) os.Error { if *verbose { log.Println("run", argv) } - bin, err := lookPath(argv[0]) - if err != nil { - return err - } - p, err := exec.Run(bin, argv, envv, dir, - exec.DevNull, exec.DevNull, exec.PassThrough) - if err != nil { - return err - } - return p.Close() + argv = useBash(argv) + cmd := exec.Command(argv[0], argv[1:]...) + cmd.Dir = dir + cmd.Env = envv + cmd.Stderr = os.Stderr + return cmd.Run() } // runLog runs a process and returns the combined stdout/stderr, @@ -36,16 +32,8 @@ func runLog(envv []string, logfile, dir string, argv ...string) (output string, if *verbose { log.Println("runLog", argv) } - bin, err := lookPath(argv[0]) - if err != nil { - return - } - p, err := exec.Run(bin, argv, envv, dir, - exec.DevNull, exec.Pipe, exec.MergeWithStdout) - if err != nil { - return - } - defer p.Close() + argv = useBash(argv) + b := new(bytes.Buffer) var w io.Writer = b if logfile != "" { @@ -56,21 +44,30 @@ func runLog(envv []string, logfile, dir string, argv ...string) (output string, defer f.Close() w = io.MultiWriter(f, b) } - _, err = io.Copy(w, p.Stdout) - if err != nil { - return - } - wait, err := p.Wait(0) + + cmd := exec.Command(argv[0], argv[1:]...) + cmd.Dir = dir + cmd.Env = envv + cmd.Stdout = w + cmd.Stderr = w + + err = cmd.Run() + output = b.String() if err != nil { + if ws, ok := err.(*os.Waitmsg); ok { + exitStatus = ws.ExitStatus() + } return } - return b.String(), wait.WaitStatus.ExitStatus(), nil + return } -// lookPath looks for cmd in $PATH if cmd does not begin with / or ./ or ../. -func lookPath(cmd string) (string, os.Error) { - if strings.HasPrefix(cmd, "/") || strings.HasPrefix(cmd, "./") || strings.HasPrefix(cmd, "../") { - return cmd, nil +// useBash prefixes a list of args with 'bash' if the first argument +// is a bash script. +func useBash(argv []string) []string { + // TODO(brainman): choose a more reliable heuristic here. + if strings.HasSuffix(argv[0], ".bash") { + argv = append([]string{"bash"}, argv...) } - return exec.LookPath(cmd) + return argv } diff --git a/misc/dashboard/builder/main.go b/misc/dashboard/builder/main.go index c1536abb2..5ba5c11c3 100644 --- a/misc/dashboard/builder/main.go +++ b/misc/dashboard/builder/main.go @@ -12,6 +12,7 @@ import ( "os" "path" "regexp" + "runtime" "strconv" "strings" "time" @@ -347,6 +348,9 @@ func (b *Builder) buildHash(hash string) (err os.Error) { // envv returns an environment for build/bench execution func (b *Builder) envv() []string { + if runtime.GOOS == "windows" { + return b.envvWindows() + } e := []string{ "GOOS=" + b.goos, "GOARCH=" + b.goarch, @@ -358,6 +362,42 @@ func (b *Builder) envv() []string { return e } +// windows version of envv +func (b *Builder) envvWindows() []string { + start := map[string]string{ + "GOOS": b.goos, + "GOARCH": b.goarch, + "GOROOT_FINAL": "/c/go", + } + for _, name := range extraEnv { + start[name] = os.Getenv(name) + } + skip := map[string]bool{ + "GOBIN": true, + "GOROOT": true, + "INCLUDE": true, + "LIB": true, + } + var e []string + for name, v := range start { + e = append(e, name+"="+v) + skip[name] = true + } + for _, kv := range os.Environ() { + s := strings.Split(kv, "=", 2) + name := strings.ToUpper(s[0]) + switch { + case name == "": + // variables, like "=C:=C:\", just copy them + e = append(e, kv) + case !skip[name]: + e = append(e, kv) + skip[name] = true + } + } + return e +} + func isDirectory(name string) bool { s, err := os.Stat(name) return err == nil && s.IsDirectory() @@ -455,7 +495,7 @@ func commitPoll(key string) { // Pass 1. Fill in parents and add new log entries to logsByHash. // Empty parent means take parent from next log entry. - // Non-empty parent has form 1234:hashhashhash; we weant full hash. + // Non-empty parent has form 1234:hashhashhash; we want full hash. for i := range logs { l := &logs[i] log.Printf("hg log: %s < %s\n", l.Hash, l.Parent) @@ -516,7 +556,7 @@ func addCommit(hash, key string) bool { // Create commit. if err := postCommit(key, l); err != nil { - log.Printf("faield to add %s to dashboard: %v", err) + log.Printf("failed to add %s to dashboard: %v", key, err) return false } return true diff --git a/misc/dashboard/godashboard/app.yaml b/misc/dashboard/godashboard/app.yaml index 455da57f0..4fd05f259 100644 --- a/misc/dashboard/godashboard/app.yaml +++ b/misc/dashboard/godashboard/app.yaml @@ -1,5 +1,5 @@ application: godashboard -version: 6 +version: 7 runtime: python api_version: 1 diff --git a/misc/dashboard/godashboard/gobuild.py b/misc/dashboard/godashboard/gobuild.py index baddb0e9b..ee700c73b 100644 --- a/misc/dashboard/godashboard/gobuild.py +++ b/misc/dashboard/godashboard/gobuild.py @@ -12,15 +12,12 @@ from google.appengine.ext import db from google.appengine.ext import webapp from google.appengine.ext.webapp import template from google.appengine.ext.webapp.util import run_wsgi_app -import binascii import datetime import hashlib import hmac import logging import os import re -import struct -import time import bz2 # local imports @@ -346,16 +343,98 @@ class Build(webapp.RequestHandler): key = 'todo-%s' % builder memcache.delete(key) - # TODO: Send mail for build breakage. + c = getBrokenCommit(node, builder) + if c is not None and not c.fail_notification_sent: + notifyBroken(c, builder) self.response.set_status(200) -def failed(c, builder): + +def getBrokenCommit(node, builder): + """ + getBrokenCommit returns a Commit that breaks the build. + The Commit will be either the one specified by node or the one after. + """ + + # Squelch mail if already fixed. + head = firstResult(builder) + if broken(head, builder) == False: + return + + # Get current node and node before, after. + cur = nodeByHash(node) + if cur is None: + return + before = nodeBefore(cur) + after = nodeAfter(cur) + + if broken(before, builder) == False and broken(cur, builder): + return cur + if broken(cur, builder) == False and broken(after, builder): + return after + + return + +def firstResult(builder): + q = Commit.all().order('-__key__').limit(20) + for c in q: + for i, b in enumerate(c.builds): + p = b.split('`', 1) + if p[0] == builder: + return c + return None + +def nodeBefore(c): + return nodeByHash(c.parentnode) + +def nodeAfter(c): + return Commit.all().filter('parenthash', c.node).get() + +def notifyBroken(c, builder): + def send(): + n = Commit.get_by_key_name('%08x-%s' % (c.num, c.node)) + if n.fail_notification_sent: + return False + n.fail_notification_sent = True + return n.put() + if not db.run_in_transaction(send): + return + + subject = const.mail_fail_subject % (builder, c.desc.split('\n')[0]) + path = os.path.join(os.path.dirname(__file__), 'fail-notify.txt') + body = template.render(path, { + "builder": builder, + "node": c.node, + "user": c.user, + "desc": c.desc, + "loghash": logHash(c, builder) + }) + mail.send_mail( + sender=const.mail_from, + to=const.mail_fail_to, + subject=subject, + body=body + ) + +def logHash(c, builder): + for i, b in enumerate(c.builds): + p = b.split('`', 1) + if p[0] == builder: + return p[1] + return "" + +def broken(c, builder): + """ + broken returns True if commit c breaks the build for the specified builder, + False if it is a good build, and None if no results exist for this builder. + """ + if c is None: + return None for i, b in enumerate(c.builds): p = b.split('`', 1) if p[0] == builder: return len(p[1]) > 0 - return False + return None def node(num): q = Commit.all() diff --git a/misc/dashboard/googlecode_upload.py b/misc/dashboard/googlecode_upload.py index 3b1d432ff..e87db884a 100755 --- a/misc/dashboard/googlecode_upload.py +++ b/misc/dashboard/googlecode_upload.py @@ -70,7 +70,7 @@ def upload(file, project_name, user_name, password, summary, labels=None): Returns: a tuple: http_status: 201 if the upload succeeded, something else if an - error occured. + error occurred. http_reason: The human-readable string associated with http_status file_url: If the upload succeeded, the URL of the file on Google Code, None otherwise. diff --git a/misc/emacs/go-mode.el b/misc/emacs/go-mode.el index 532f464ed..03f0a2a8b 100644 --- a/misc/emacs/go-mode.el +++ b/misc/emacs/go-mode.el @@ -523,7 +523,7 @@ Replace the current buffer on success; display errors on failure." (erase-buffer) (insert-buffer-substring outbuf) (goto-char (min old-point (point-max))) - (if old-mark (set-mark (min old-mark (point-max)))) + (if old-mark (push-mark (min old-mark (point-max)) t)) (kill-buffer errbuf)) ;; gofmt failed: display the errors diff --git a/misc/godoc/README b/misc/godoc/README new file mode 100644 index 000000000..3c8d830e4 --- /dev/null +++ b/misc/godoc/README @@ -0,0 +1,22 @@ +Instructions to get an initial godoc running on a local app engine emulator +--------------------------------------------------------------------------- + +To run godoc under the app engine emulator, create a ("goroot") godoc +directory that contains the app.yaml file, the doc and lib directories +from the Go distribution, as well as a godoc directory with the godoc +sources from src/cmd/godoc. In the godoc source directory, replace +main.go with init.go. The directory structure should look as follows: + +godoc // "goroot" directory + app.yaml // app engine control file + doc // goroot/doc directory + favicon.ico + godoc // contains godoc sources + godoc.go // unchanged godoc file + init.go // this file instead of godoc/main.go + ... // remaining godoc files + lib // goroot/lib directory + +Run app engine emulator locally: dev_appserver.py -a <hostname> godoc +where godoc is the top-level "goroot" directory. The godoc home page +is then served at: <hostname>:8080 . diff --git a/misc/godoc/app.yaml b/misc/godoc/app.yaml new file mode 100644 index 000000000..f8b46db31 --- /dev/null +++ b/misc/godoc/app.yaml @@ -0,0 +1,12 @@ +# Copyright 2011 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +application: godoc +version: 1 +runtime: go +api_version: 1 + +handlers: +- url: /.* + script: _go_app diff --git a/misc/godoc/init.go b/misc/godoc/init.go new file mode 100644 index 000000000..0fd0bd542 --- /dev/null +++ b/misc/godoc/init.go @@ -0,0 +1,35 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file replaces main.go when running godoc under the app engine emulator. +// See the README file for instructions. + +package main + +import ( + "http" + "log" + "os" + "path/filepath" +) + +func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) { + contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path! + w.WriteHeader(http.StatusNotFound) + servePage(w, "File "+relpath, "", "", contents) +} + +func init() { + // set goroot + cwd, err := os.Getwd() + if err != nil { + log.Fatalf("cwd: %s", err) + } + log.Printf("cwd = %s", cwd) + *goroot = filepath.Clean(cwd) + + initHandlers() + readTemplates() + registerPublicHandlers(http.DefaultServeMux) +} diff --git a/misc/goplay/goplay.go b/misc/goplay/goplay.go index f3e2ff565..f1dc1bca5 100644 --- a/misc/goplay/goplay.go +++ b/misc/goplay/goplay.go @@ -5,7 +5,6 @@ package main import ( - "bytes" "exec" "flag" "http" @@ -140,32 +139,7 @@ func error(w http.ResponseWriter, out []byte, err os.Error) { // run executes the specified command and returns its output and an error. func run(cmd ...string) ([]byte, os.Error) { - // find the specified binary - bin, err := exec.LookPath(cmd[0]) - if err != nil { - // report binary as well as the error - return nil, os.NewError(cmd[0] + ": " + err.String()) - } - - // run the binary and read its combined stdout and stderr into a buffer - p, err := exec.Run(bin, cmd, os.Environ(), "", exec.DevNull, exec.Pipe, exec.MergeWithStdout) - if err != nil { - return nil, err - } - var buf bytes.Buffer - io.Copy(&buf, p.Stdout) - w, err := p.Wait(0) - p.Close() - if err != nil { - return nil, err - } - - // set the error return value if the program had a non-zero exit status - if !w.Exited() || w.ExitStatus() != 0 { - err = os.ErrorString("running " + cmd[0] + ": " + w.String()) - } - - return buf.Bytes(), err + return exec.Command(cmd[0], cmd[1:]...).CombinedOutput() } var frontPage, output *template.Template // HTML templates diff --git a/misc/vim/ftplugin/go/fmt.vim b/misc/vim/ftplugin/go/fmt.vim index 18a2156f5..a299dfcee 100644 --- a/misc/vim/ftplugin/go/fmt.vim +++ b/misc/vim/ftplugin/go/fmt.vim @@ -13,7 +13,7 @@ " replacing the buffer with stderr output. " -command! Fmt call s:GoFormat() +command! -buffer Fmt call s:GoFormat() function! s:GoFormat() let view = winsaveview() |