summaryrefslogtreecommitdiff
path: root/src/cmd/gobuild/util.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-04-16 00:18:11 -0700
committerRuss Cox <rsc@golang.org>2009-04-16 00:18:11 -0700
commit5a1a92a0559e505bf7a8b50a56d9f28d4b3da765 (patch)
tree6c0830724548ef4a33f0aff8bd2262bd3abc5d79 /src/cmd/gobuild/util.go
parent5eda790c67ef577f56e3347bb3589f4de21c7c0a (diff)
downloadgolang-5a1a92a0559e505bf7a8b50a56d9f28d4b3da765.tar.gz
rewrite gobuild in go.
R=r DELTA=1305 (704 added, 590 deleted, 11 changed) OCL=27546 CL=27548
Diffstat (limited to 'src/cmd/gobuild/util.go')
-rw-r--r--src/cmd/gobuild/util.go244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/cmd/gobuild/util.go b/src/cmd/gobuild/util.go
new file mode 100644
index 000000000..022417289
--- /dev/null
+++ b/src/cmd/gobuild/util.go
@@ -0,0 +1,244 @@
+// Copyright 2009 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.
+
+
+package gobuild
+
+import (
+ "ast";
+ "exec";
+ "fmt";
+ "os";
+ "parser";
+ "path";
+ "sort";
+ "strconv";
+ "strings";
+)
+
+var (
+ theChar string;
+ goarch string;
+ goos string;
+ bin = make(map[string] string);
+)
+
+var theChars = map[string] string {
+ "amd64": "6",
+ "386": "8",
+ "arm": "5"
+}
+
+func fatal(args ...) {
+ fmt.Fprintf(os.Stderr, "gobuild: %s\n", fmt.Sprint(args));
+ sys.Exit(1);
+}
+
+func init() {
+ var err *os.Error;
+ goarch, err = os.Getenv("GOARCH");
+ goos, err = os.Getenv("GOOS");
+
+ var ok bool;
+ theChar, ok = theChars[goarch];
+ if !ok {
+ fatal("unknown $GOARCH: ", goarch);
+ }
+
+ var binaries = []string{
+ theChar + "g",
+ theChar + "c",
+ theChar + "a",
+ "6ar", // sic
+ };
+
+ for i, v := range binaries {
+ var s string;
+ if s, err = exec.LookPath(v); err != nil {
+ fatal("cannot find binary ", v);
+ }
+ bin[v] = s;
+ }
+}
+
+func PushString(v *[]string, p string) {
+ n := len(v);
+ if n >= cap(v) {
+ m := 2*n + 10;
+ a := make([]string, n, m);
+ for i := range *v {
+ a[i] = v[i];
+ }
+ *v = a;
+ }
+ *v = v[0:n+1];
+ v[n] = p;
+}
+
+
+func run(argv []string, display bool) (ok bool) {
+ argv0 := bin[argv[0]];
+ output := exec.DevNull;
+ if display {
+ output = exec.PassThrough;
+ }
+ p, err1 := exec.Run(argv0, argv, os.Environ(), exec.DevNull, output, output);
+ if err1 != nil {
+ return false;
+ }
+ w, err2 := p.Wait(0);
+ if err2 != nil {
+ return false;
+ }
+ return w.Exited() && w.ExitStatus() == 0;
+}
+
+func Build(cmd []string, file string, display bool) (ok bool) {
+ if display {
+ fmt.Fprint(os.Stderr, "$ ");
+ for i, s := range cmd {
+ fmt.Fprint(os.Stderr, s[i], " ");
+ }
+ fmt.Fprint(os.Stderr, file, "\n");
+ }
+
+ var argv []string;
+ for i, c := range cmd {
+ PushString(&argv, c);
+ }
+ PushString(&argv, file);
+ return run(argv, display);
+}
+
+func Archive(pkg string, files []string) {
+ argv := []string{ "6ar", "grc", pkg };
+ for i, file := range files {
+ PushString(&argv, file);
+ }
+ if !run(argv, true) {
+ fatal("archive failed");
+ }
+}
+
+func Compiler(file string) []string {
+ switch {
+ case strings.HasSuffix(file, ".go"):
+ return []string{ theChar + "g" };
+ case strings.HasSuffix(file, ".c"):
+ return []string{ theChar + "c", "-FVw" };
+ case strings.HasSuffix(file, ".s"):
+ return []string{ theChar + "a" };
+ }
+ fatal("don't know how to compile ", file);
+ return nil;
+}
+
+func Object(file, suffix string) string {
+ ext := path.Ext(file);
+ return file[0:len(file)-len(ext)] + "." + suffix;
+}
+
+// Dollarstring returns s with literal goarch/goos values
+// replaced by $lGOARCHr where l and r are the specified delimeters.
+func dollarString(s, l, r string) string {
+ out := "";
+ j := 0; // index of last byte in s copied to out.
+ for i := 0; i < len(s); {
+ switch {
+ case i+len(goarch) <= len(s) && s[i:i+len(goarch)] == goarch:
+ out += s[j:i];
+ out += "$" + l + "GOARCH" + r;
+ i += len(goarch);
+ j = i;
+ case i+len(goos) <= len(s) && s[i:i+len(goos)] == goos:
+ out += s[j:i];
+ out += "$" + l + "GOOS" + r;
+ i += len(goos);
+ j = i;
+ default:
+ i++;
+ }
+ }
+ out += s[j:len(s)];
+ return out;
+}
+
+// dollarString wrappers.
+// Print ShellString(s) or MakeString(s) depending on
+// the context in which the result will be interpreted.
+type ShellString string;
+func (s ShellString) String() string {
+ return dollarString(s, "{", "}");
+}
+
+type MakeString string;
+func (s MakeString) String() string {
+ return dollarString(s, "(", ")");
+}
+
+// TODO(rsc): parse.Parse should return an os.Error.
+var ParseError = os.NewError("parse errors");
+
+// TODO(rsc): Should this be in the AST library?
+func LitString(p []*ast.StringLit) (string, *os.Error) {
+ s := "";
+ for i, lit := range p {
+ t, err := strconv.Unquote(string(lit.Value));
+ if err != nil {
+ return "", err;
+ }
+ s += t;
+ }
+ return s, nil;
+}
+
+func PackageImports(file string) (pkg string, imports []string, err1 *os.Error) {
+ f, err := os.Open(file, os.O_RDONLY, 0);
+ if err != nil {
+ return "", nil, err
+ }
+
+ prog, ok := parser.Parse(f, nil, parser.ImportsOnly);
+ if !ok {
+ return "", nil, ParseError;
+ }
+
+ // Normally one must consult the types of decl and spec,
+ // but we told the parser to return imports only,
+ // so assume it did.
+ var imp []string;
+ for _, decl := range prog.Decls {
+ for _, spec := range decl.(*ast.GenDecl).Specs {
+ str, err := LitString(spec.(*ast.ImportSpec).Path);
+ if err != nil {
+ return "", nil, ParseError; // ParseError is better than os.EINVAL
+ }
+ PushString(&imp, str);
+ }
+ }
+
+ // TODO(rsc): should be prog.Package.Value
+ return prog.Name.Value, imp, nil;
+}
+
+func SourceFiles(dir string) ([]string, *os.Error) {
+ f, err := os.Open(dir, os.O_RDONLY, 0);
+ if err != nil {
+ return nil, err;
+ }
+ names, err1 := f.Readdirnames(-1);
+ f.Close();
+ out := make([]string, 0, len(names));
+ for i, name := range names {
+ if strings.HasSuffix(name, ".go")
+ || strings.HasSuffix(name, ".c")
+ || strings.HasSuffix(name, ".s") {
+ n := len(out);
+ out = out[0:n+1];
+ out[n] = name;
+ }
+ }
+ sort.SortStrings(out);
+ return out, nil;
+}