// NAME // clean - Clean all generated files // // DESCRIPTION // Clean all generated files and paths. // // OPTIONS // --backup, -b // clean all backup files (*~, #*) // --verbose, -v // run in verbose mode func TaskClean(t *tasking.T) { var paths []string paths = append( paths, ARMBinaryPath, "pkg", filepath.Join("bin", ProjectName), filepath.Join(AndroidPath, "bin"), filepath.Join(AndroidPath, "gen"), filepath.Join(AndroidPath, "libs"), filepath.Join(AndroidPath, "obj"), ) // Actually remove files using rm for _, path := range paths { err := rm_rf(t, path) if err != nil { t.Error(err) } } if t.Flags.Bool("backup") { err := t.Exec(`sh -c`, `"find ./ -name '*~' -print0 | xargs -0 rm -f"`) if err != nil { t.Error(err) } } if t.Failed() { t.Fatalf("%-20s %s\n", status(t.Failed()), "Clean all generated files and paths.") } t.Logf("%-20s %s\n", status(t.Failed()), "Clean all generated files and paths.") }
// NAME // deploy - Deploy the application // // DESCRIPTION // Build and deploy the application on the device via ant. // // OPTIONS // --verbose, -v // run in verbose mode func TaskDeploy(t *tasking.T) { deployAndroid(t) if t.Failed() { t.Fatalf("%-20s %s\n", status(t.Failed()), "Build and deploy the application on the device via ant.") } t.Logf("%-20s %s\n", status(t.Failed()), "Build and deploy the application on the device via ant.") }
// NAME // clean - Clean all generated files // // DESCRIPTION // Clean all generated files and paths. // func TaskClean(t *tasking.T) { var paths []string paths = append( paths, ARMBinaryPath, "pkg", filepath.Join("bin"), filepath.Join(AndroidPath, "bin"), filepath.Join(AndroidPath, "gen"), filepath.Join(AndroidPath, "libs"), filepath.Join(AndroidPath, "obj"), ) // Actually remove files using rm for _, path := range paths { err := rm_rf(t, path) if err != nil { t.Error(err) } } if t.Failed() { t.Fatalf("%-20s %s\n", status(t.Failed()), "Clean all generated files and paths.") } t.Logf("%-20s %s\n", status(t.Failed()), "Clean all generated files and paths.") }
// NAME // specgen - generates Go code from the UPnP specification files. // // DESCRIPTION // The specification is available for download from: // // OPTIONS // -s, --specs_dir=<spec directory> // Path to the specification storage directory. This is used to find (and download if not present) the specification ZIP files. Defaults to 'specs' // -o, --out_dir=<output directory> // Path to the output directory. This is is where the DCP source files will be placed. Should normally correspond to the directory for github.com/huin/goupnp/dcps. Defaults to '../dcps' // --nogofmt // Disable passing the output through gofmt. Do this if debugging code output problems and needing to see the generated code prior to being passed through gofmt. func TaskSpecgen(t *tasking.T) { specsDir := fallbackStrValue("specs", t.Flags.String("specs_dir"), t.Flags.String("s")) if err := os.MkdirAll(specsDir, os.ModePerm); err != nil { t.Fatalf("Could not create specs-dir %q: %v\n", specsDir, err) } outDir := fallbackStrValue("../dcps", t.Flags.String("out_dir"), t.Flags.String("o")) useGofmt := !t.Flags.Bool("nogofmt") NEXT_DCP: for _, d := range dcpMetadata { specFilename := filepath.Join(specsDir, d.Name+".zip") err := acquireFile(specFilename, d.XMLSpecURL) if err != nil { t.Logf("Could not acquire spec for %s, skipping: %v\n", d.Name, err) continue NEXT_DCP } dcp := newDCP(d) if err := dcp.processZipFile(specFilename); err != nil { log.Printf("Error processing spec for %s in file %q: %v", d.Name, specFilename, err) continue NEXT_DCP } for i, hack := range d.Hacks { if err := hack(dcp); err != nil { log.Printf("Error with Hack[%d] for %s: %v", i, d.Name, err) continue NEXT_DCP } } dcp.writePackage(outDir, useGofmt) if err := dcp.writePackage(outDir, useGofmt); err != nil { log.Printf("Error writing package %q: %v", dcp.Metadata.Name, err) continue NEXT_DCP } } }
// NAME // cross-compile - cross-compiles gh for current platform. // // DESCRIPTION // Cross-compiles gh for current platform. Build artifacts will be in target/VERSION func TaskCrossCompile(t *tasking.T) { t.Logf("Cross-compiling gh for %s...\n", runtime.GOOS) t.Logf("GOPATH=%s\n", os.Getenv("GOPATH")) err := t.Exec("goxc", "-wd=.", "-os="+runtime.GOOS, "-c="+runtime.GOOS) if err != nil { t.Fatalf("Can't cross-compile gh: %s\n", err) } }
// NAME // say-hello - Say hello to current user // // DESCRIPTION // Print out hello to current user // // OPTIONS // --verbose, -v // run in verbose mode func TaskSayHello(t *tasking.T) { user, _ := user.Current() if t.Flags.Bool("v") || t.Flags.Bool("verbose") { t.Logf("Hello %s, the time now is %s\n", user.Name, time.Now()) } else { t.Logf("Hello %s\n", user.Name) } }
// NAME // init - Initialize a new Mandala application // // DESCRIPTION // Initialize a new Mandala application based on application.json // func TaskInit(t *tasking.T) { var err error // read application.json app, err := readJSON(jsonPath) if err != nil { t.Error(err) } var paths []string // execute templates and copy the files err = filepath.Walk( "templates", func(path string, info os.FileInfo, err error) error { if !info.IsDir() { paths = append(paths, path) } return nil }, ) if err != nil { t.Error(err) } for _, path := range paths { var dstPath string splits := strings.Split(path, "/") if len(splits) > 1 { dstPath = filepath.Join(splits[1:]...) } else { dstPath = filepath.Base(path) } if err = copyFile(path, dstPath, app); err != nil { t.Error(err) } } // Rename paths accordly to app.LibName if err = os.Rename("_task.go", strings.ToLower(app.LibName)+"_task.go"); err != nil { t.Error(err) } if err = os.Rename("src/_app", filepath.Join("src", strings.ToLower(app.LibName))); err != nil { t.Error(err) } if err = os.Rename("test/src/_app", filepath.Join("test/src/", strings.ToLower(app.TestLibName))); err != nil { t.Error(err) } if t.Failed() { t.Fatalf("%-20s %s\n", status(t.Failed()), "Initialize a new Mandala application") } t.Logf("%-20s %s\n", status(t.Failed()), "Initialize a new Mandala application") }
// NAME // build - Build the application // // DESCRIPTION // Build the application for the given platforms. // // OPTIONS // --flags=<FLAGS> // pass FLAGS to the compiler // --verbose, -v // run in verbose mode func TaskBuild(t *tasking.T) { for _, platform := range t.Args { buildFun[platform](t) } if t.Failed() { t.Fatalf("%-20s %s\n", status(t.Failed()), "Build the application for the given platforms.") } t.Logf("%-20s %s\n", status(t.Failed()), "Build the application for the given platforms.") }
// NAME // test - Run the tests // // DESCRIPTION // Build and run the tests on the given platform returning output using logcat. // // OPTIONS // --flags=<FLAGS> // pass the given flags to the executable // --verbose, -v // run in verbose mode func TaskTest(t *tasking.T) { TaskBuild(t) if f, ok := runFun[t.Args[0]]; ok { f(t) } if t.Failed() { t.Fatalf("%-20s %s\n", status(t.Failed()), "Run the example on the given platforms.") } t.Logf("%-20s %s\n", status(t.Failed()), "Run the example on the given platforms.") }
// NAME // test - Run black-box tests // // DESCRIPTION // Build and run the application on the given platforms. // // OPTIONS // --flags=<FLAGS> // pass the flags to the executable // --logcat=Mandala:* stdout:* stderr:* *:S // show logcat output (android only) // --verbose, -v // run in verbose mode func TaskTest(t *tasking.T) { TaskBuild(t) for _, platform := range t.Args { runFun[platform](t) } if t.Failed() { t.Fatalf("%-20s %s\n", status(t.Failed()), "Run the application on the given platforms.") } t.Logf("%-20s %s\n", status(t.Failed()), "Run the application on the given platforms.") }
// NAME // release - Build the application in 'release mode' // // DESCRIPTION // Build the application for Android in 'release mode'. // // OPTIONS // --flags=<FLAGS> // pass FLAGS to the compiler // --verbose, -v // run in verbose mode func TaskRelease(t *tasking.T) { // Build app in 'release mode' buildAndroid(t, true) // Sign and 'zipalign' app signAndroid(t) // Check task if t.Failed() { t.Fatalf("%-20s %s\n", status(t.Failed()), "Release the application for Android.") } t.Logf("%-20s %s\n", status(t.Failed()), "Release the application for Android.") }
// NAME // build - Build the tests // // DESCRIPTION // Build the tests for the given platforms (xorg/android). // // OPTIONS // --buildflags= // pass the given flags to the compiler // --verbose, -v // run in verbose mode func TaskBuild(t *tasking.T) { if len(t.Args) == 0 { t.Error("At least a platform name must be specified!") } if f, ok := buildFun[t.Args[0]]; ok { f(t) } if t.Failed() { t.Fatalf("%-20s %s\n", status(t.Failed()), "Build the tests for the given platforms.") } t.Logf("%-20s %s\n", status(t.Failed()), "Build the tests for the given platforms.") }
// NAME // install-deps - install dependencies with go get // // DESCRIPTION // Install dependencies with go get. func TaskInstallDeps(t *tasking.T) { deps := []string{ "github.com/laher/goxc", } for _, dep := range deps { t.Logf("Installing %s\n", dep) err := t.Exec("go get", dep) if err != nil { t.Fatalf("Can't download dependency %s", err) } } }
// NAME // build - Build the application // // DESCRIPTION // Build the application for the given platforms. // // OPTIONS // --flags=<FLAGS> // pass FLAGS to the compiler // --verbose, -v // run in verbose mode func TaskBuild(t *tasking.T) { if len(t.Args) < 1 { t.Error("You must specify a build platform!") } else { for _, platform := range t.Args { buildFun[platform](t) } } if t.Failed() { t.Fatalf("%-20s %s\n", status(t.Failed()), "Build the application for the given platforms.") } t.Logf("%-20s %s\n", status(t.Failed()), "Build the application for the given platforms.") }
// NAME // say-hello - Say hello to current user // // DESCRIPTION // Print out hello to current user // // OPTIONS // -n, --name="NAME" // say hello to an user with the given NAME // -v, --verbose // run in verbose mode func TaskSayHello(t *tasking.T) { username := t.Flags.String("name") if username == "" { user, _ := user.Current() username = user.Name } if t.Flags.Bool("verbose") { t.Logf("Hello %s, the time now is %s\n", username, time.Now()) } else { t.Logf("Hello %s\n", username) } }
// NAME // package - cross compile gh and package it // // DESCRIPTION // Cross compile gh and package it into PWD/target func TaskPackage(t *tasking.T) { gopath, err := ioutil.TempDir("", "gh-build") os.Setenv("GOPATH", gopath) t.Logf("GOPATH=%s\n", gopath) path := fmt.Sprintf("%s%c%s", filepath.Join(gopath, "bin"), os.PathListSeparator, os.Getenv("PATH")) os.Setenv("PATH", path) t.Logf("PATH=%s\n", path) t.Logf("Packaging for %s...\n", runtime.GOOS) t.Log("Installing dependencies...") TaskInstallDeps(t) pwd, err := os.Getwd() if err != nil { t.Fatal(err) } ghPath := filepath.Join(gopath, "src", "github.com", "jingweno", "gh") t.Logf("Copying source from %s to %s\n", pwd, ghPath) err = copyDir(pwd, ghPath) if err != nil { t.Fatal(err) } err = os.Chdir(ghPath) if err != nil { t.Fatal(err) } t.Log("Cross-compiling...") godepPath := filepath.Join(ghPath, "Godeps", "_workspace") gopath = fmt.Sprintf("%s%c%s", gopath, os.PathListSeparator, godepPath) os.Setenv("GOPATH", gopath) TaskCrossCompile(t) source := filepath.Join(ghPath, "target") target := filepath.Join(pwd, "target") t.Logf("Copying build artifacts from %s to %s...\n", source, target) err = mkdirAll(target) if err != nil { t.Fatal(err) } err = copyBuildArtifacts(source, target) if err != nil { t.Fatal(err) } }
// Cross-compiles gh for current operating system. // // Cross-compiles gh for current operating system. The build artifacts will be in target/VERSION func TaskCrossCompile(t *tasking.T) { t.Log("Updating goxc...") err := t.Exec("go get -u github.com/laher/goxc") if err != nil { t.Errorf("Can't update goxc: %s\n", err) return } t.Logf("Cross-compiling gh for %s...\n", runtime.GOOS) err = t.Exec("goxc", "-wd=.", "-os="+runtime.GOOS, "-c="+runtime.GOOS) if err != nil { t.Errorf("Can't cross-compile gh: %s\n", err) return } }
// NAME // gh-user - Get URL for a given GitHub user login // // DESCRIPTION // Given a GitHub user login, call the GitHub API to get this user and print out the user page URL. // // For example // // $ gotask git-hub-user jingweno // // OPTIONS // --verbose, -v // run in verbose mode func TaskGitHubUser(t *tasking.T) { if len(t.Args) == 0 { t.Error("No GitHub user login is provided!") return } login := t.Args[0] data, err := fetchGitHubUser(login) if err != nil { t.Error(err) return } url, ok := data["html_url"] if !ok { t.Errorf("No URL found for user login %s\n", login) return } t.Logf("The URL for user %s is %s\n", login, url) }
// Cross-compiles gh for all supported platforms. // // Cross-compiles gh for all supported platforms. The build artifacts // will be in target/VERSION. This only works on darwin with Vagrant setup. func TaskCrossCompileAll(t *tasking.T) { t.Log("Removing build target...") err := os.RemoveAll("target") if err != nil { t.Errorf("Can't remove build target: %s\n", err) return } // for current t.Logf("Compiling for %s...\n", runtime.GOOS) TaskCrossCompile(t) if t.Failed() { return } // for linux t.Log("Compiling for linux...") err = t.Exec("vagrant ssh -c 'cd ~/src/github.com/jingweno/gh && git pull origin master && gotask cross-compile'") if err != nil { t.Errorf("Can't compile on linux: %s\n", err) return } }
// NAME // specgen - generates Go code from the UPnP specification files. // // DESCRIPTION // The specification is available for download from: // // OPTIONS // -s, --spec_filename=<upnpresources.zip> // Path to the specification file, available from http://upnp.org/resources/upnpresources.zip // -o, --out_dir=<output directory> // Path to the output directory. This is is where the DCP source files will be placed. Should normally correspond to the directory for github.com/huin/goupnp/dcps // --nogofmt // Disable passing the output through gofmt. Do this if debugging code output problems and needing to see the generated code prior to being passed through gofmt. func TaskSpecgen(t *tasking.T) { specFilename := t.Flags.String("spec-filename") if specFilename == "" { specFilename = t.Flags.String("s") } if specFilename == "" { t.Fatal("--spec_filename is required") } outDir := t.Flags.String("out-dir") if outDir == "" { outDir = t.Flags.String("o") } if outDir == "" { log.Fatal("--out_dir is required") } useGofmt := !t.Flags.Bool("nogofmt") specArchive, err := openZipfile(specFilename) if err != nil { t.Fatalf("Error opening spec file: %v", err) } defer specArchive.Close() dcpCol := newDcpsCollection() for _, f := range globFiles("standardizeddcps/*/*.zip", specArchive.Reader) { dirName := strings.TrimPrefix(f.Name, "standardizeddcps/") slashIndex := strings.Index(dirName, "/") if slashIndex == -1 { // Should not happen. t.Logf("Could not find / in %q", dirName) return } dirName = dirName[:slashIndex] dcp := dcpCol.dcpForDir(dirName) if dcp == nil { t.Logf("No alias defined for directory %q: skipping %s\n", dirName, f.Name) continue } else { t.Logf("Alias found for directory %q: processing %s\n", dirName, f.Name) } dcp.processZipFile(f) } for _, dcp := range dcpCol.dcpByAlias { if err := dcp.writePackage(outDir, useGofmt); err != nil { log.Printf("Error writing package %q: %v", dcp.Metadata.Name, err) } } }
// NAME // deploy - Run platform-specific deployment routine // // DESCRIPTION // Embeds resources, compiles binary, copies related libs and plugins, etc... // Distribution-ready application package will be the result of this task. // Supported platforms are: darwin, linux, windows. // // OPTIONS // --verbose, -v // Enable some logging // --dmg // Create an installable dmg (darwin only) func TaskDeploy(t *tasking.T) { deploy, ok := deployers[runtime.GOOS] if !ok { t.Fatal("deploy: platform unsupported:", runtime.GOOS) } verbose = t.Flags.Bool("verbose") // prepare output path path := fmt.Sprintf("%s/%s", outDir, runtime.GOOS) if err := os.RemoveAll(path); err != nil { t.Fatal(err) } if err := os.MkdirAll(path, 0755); err != nil { t.Fatal(err) } // gather info pkgInfo, err := getPkgInfo() if err != nil { t.Fatal(err) } qtInfo, err := getQtInfo() if err != nil { t.Fatal(err) } // read deploy profile buf, err := ioutil.ReadFile(deployProfileSrc) if err != nil { t.Fatal(err) } var profile deployProfile err = yaml.Unmarshal(buf, &profile) if err != nil { t.Fatalf("deploy: profile: %v\n", err) } else if verbose { t.Log("deploy: profile loaded") } cfg := config{ PkgInfo: pkgInfo, QtInfo: qtInfo, Path: path, Profile: profile, } if t.Flags.Bool("verbose") { t.Log("deploy: package name:", pkgInfo.Name) t.Logf("deploy: qt base: %s (%s)\n", qtInfo.BasePath, qtInfo.Version) } // embed resources if verbose { t.Log("deploy: embedding resources") } if err := exec.Command("rice", "embed-go").Run(); err != nil { t.Fatalf("deploy: rice: %v", err) } // run deployment if err := deploy(&cfg, t); err != nil { if err := os.RemoveAll(path); err != nil { t.Fatal(err) } t.Fatal(err) } // clean leftovers if err := exec.Command("rice", "clean").Run(); err != nil { t.Fatalf("clean: rice: %v", err) } }