// goxc function to archive a binary along with supporting files (e.g. README or LICENCE). func ArchiveBinariesAndResources(outDir, platName string, binPaths []string, appName string, resources []string, settings config.Settings, archiver Archiver, ending string, includeTopLevelDir bool) (zipFilename string, err error) { var zipName string if settings.PackageVersion != "" && settings.PackageVersion != core.PACKAGE_VERSION_DEFAULT { //0.1.6 using appname_version_platform. See issue 3 zipName = appName + "_" + settings.GetFullVersionName() + "_" + platName } else { zipName = appName + "_" + platName } zipFilename = filepath.Join(outDir, zipName+"."+ending) var zipDir string if includeTopLevelDir { zipDir = zipName } else { zipDir = "" } toArchive := []ArchiveItem{} for _, binPath := range binPaths { destFile := filepath.Base(binPath) if zipDir != "" { destFile = filepath.Join(zipDir, destFile) } toArchive = append(toArchive, ArchiveItemFromFileSystem(binPath, destFile)) } for _, resource := range resources { destFile := resource if zipDir != "" { destFile = filepath.Join(zipDir, destFile) } toArchive = append(toArchive, ArchiveItemFromFileSystem(resource, destFile)) } err = archiver(zipFilename, toArchive) return }
func archivePlat(goos, arch string, mainDirs []string, workingDirectory, outDestRoot string, settings *config.Settings, ending string, archiver archive.Archiver, includeTopLevelDir bool) error { resources := core.ParseIncludeResources(workingDirectory, settings.ResourcesInclude, settings.ResourcesExclude, !settings.IsQuiet()) //log.Printf("Resources: %v", resources) exes := []string{} for _, mainDir := range mainDirs { var exeName string if len(mainDirs) == 1 { exeName = settings.AppName } else { exeName = filepath.Base(mainDir) } binPath, err := core.GetAbsoluteBin(goos, arch, settings.AppName, exeName, workingDirectory, settings.GetFullVersionName(), settings.OutPath, settings.ArtifactsDest) if err != nil { return err } exes = append(exes, binPath) } outDir := filepath.Join(outDestRoot, settings.GetFullVersionName()) err := os.MkdirAll(outDir, 0777) if err != nil { return err } archivePath, err := archive.ArchiveBinariesAndResources(outDir, goos+"_"+arch, exes, settings.AppName, resources, *settings, archiver, ending, includeTopLevelDir) if err != nil { log.Printf("ZIP error: %s", err) return err } else { if !settings.IsQuiet() { log.Printf("Artifact(s) archived to %s", archivePath) } } return nil }
func getArmArchName(settings *config.Settings) string { armArchName := settings.GetTaskSettingString(TASK_PKG_BUILD, "armarch") if armArchName == "" { //derive it from GOARM version: goArm := settings.GetTaskSettingString(TASK_XC, "GOARM") if goArm == "5" { armArchName = "armel" } else { armArchName = "armhf" } } return armArchName }
func codesignPlat(goos, arch string, binPath string, settings *config.Settings) error { // settings.codesign only works on OS X for binaries generated for OS X. id := settings.GetTaskSettingString("codesign", "id") if id != "" && runtime.GOOS == platforms.DARWIN && goos == platforms.DARWIN { if err := signBinary(binPath, id); err != nil { log.Printf("codesign failed: %s", err) return err } else { log.Printf("Signed with ID: %q", id) return nil } } return nil }
// Build toolchain for a given target platform func buildToolchain(goos string, arch string, settings *config.Settings) error { goroot := settings.GoRoot scriptpath := core.GetMakeScriptPath(goroot) cmd := exec.Command(scriptpath) cmd.Dir = filepath.Join(goroot, "src") noClean := settings.GetTaskSettingBool(TASK_BUILD_TOOLCHAIN, "no-clean") if noClean { cmd.Args = append(cmd.Args, "--no-clean") } //0.8.5: no longer using cgoEnabled env := []string{"GOOS=" + goos, "GOARCH=" + arch} extraEnv := settings.GetTaskSettingStringSlice(TASK_BUILD_TOOLCHAIN, "extra-env") log.Printf("extra-env: %v", extraEnv) env = append(env, extraEnv...) if goos == platforms.LINUX && arch == platforms.ARM { // see http://dave.cheney.net/2012/09/08/an-introduction-to-cross-compilation-with-go //NOTE: I don't think it has any effect on fp goarm := settings.GetTaskSettingString(TASK_BUILD_TOOLCHAIN, "GOARM") if goarm != "" { env = append(env, "GOARM="+goarm) } } log.Printf("Setting env: %v", env) cmd.Env = append([]string{}, os.Environ()...) cmd.Env = append(cmd.Env, env...) if settings.IsVerbose() { log.Printf("'make' env: GOOS=%s GOARCH=%s GOROOT=%s", goos, arch, goroot) } log.Printf("Invoking '%v' from %s", executils.PrintableArgs(cmd.Args), cmd.Dir) executils.RedirectIO(cmd) err := cmd.Start() if err != nil { log.Printf("Build toolchain: Launch error: %s", err) return err } err = cmd.Wait() if err != nil { log.Printf("Build Toolchain: wait error: %s", err) return err } if settings.IsVerbose() { log.Printf("Complete") } return err }
func FillTaskSettingsDefaults(settings *config.Settings) { if len(settings.Tasks) == 0 { settings.Tasks = Aliases[TASKALIAS_DEFAULT] } if settings.TaskSettings == nil { settings.TaskSettings = make(map[string]map[string]interface{}) } //fill in per-task settings ... for _, t := range ListTasks() { if t.DefaultSettings != nil { if _, keyExists := settings.TaskSettings[t.Name]; !keyExists { settings.TaskSettings[t.Name] = t.DefaultSettings } else { //TODO go deeper still? for k, v := range t.DefaultSettings { taskSettings := settings.TaskSettings[t.Name] if _, keyExists = taskSettings[k]; !keyExists { taskSettings[k] = v } } } } } }
// invoke the go command via the os/exec package // 0.3.1 // v0.9 changed signature func InvokeGo(workingDirectory string, subCmd string, subCmdArgs []string, env []string, settings *config.Settings) error { fullVersionName := settings.GetFullVersionName() //var buildSettings config.BuildSettings buildSettings := settings.BuildSettings goRoot := settings.GoRoot if settings.IsVerbose() { log.Printf("build settings: %s", goRoot) } cmdPath := filepath.Join(goRoot, "bin", "go") args := []string{subCmd} //these features only apply to `go build` & `go install` if isBuildCommand(subCmd) { if buildSettings.Processors != nil { args = append(args, "-p", strconv.Itoa(*buildSettings.Processors)) } if buildSettings.Race != nil && *buildSettings.Race { args = append(args, "-race") } if buildSettings.Verbose != nil && *buildSettings.Verbose { args = append(args, "-v") } if buildSettings.PrintCommands != nil && *buildSettings.PrintCommands { args = append(args, "-x") } if buildSettings.CcFlags != nil && *buildSettings.CcFlags != "" { args = append(args, "-ccflags", *buildSettings.CcFlags) } if buildSettings.Compiler != nil && *buildSettings.Compiler != "" { args = append(args, "-compiler", *buildSettings.Compiler) } if buildSettings.GccGoFlags != nil && *buildSettings.GccGoFlags != "" { args = append(args, "-gccgoflags", *buildSettings.GccGoFlags) } if buildSettings.GcFlags != nil && *buildSettings.GcFlags != "" { args = append(args, "-gcflags", *buildSettings.GcFlags) } if buildSettings.InstallSuffix != nil && *buildSettings.InstallSuffix != "" { args = append(args, "-installsuffix", *buildSettings.InstallSuffix) } ldflags := "" if buildSettings.LdFlags != nil { ldflags = *buildSettings.LdFlags } if buildSettings.LdFlagsXVars != nil { //TODO! ldflags = ldflags + " " + buildFlags(buildInterpolationVars(*buildSettings.LdFlagsXVars, fullVersionName), "-X") } else { log.Printf("WARNING: LdFlagsXVars is nil. Not passing package version into compiler") } if ldflags != "" { args = append(args, "-ldflags", ldflags) } if buildSettings.Tags != nil && *buildSettings.Tags != "" { args = append(args, "-tags", *buildSettings.Tags) } if len(buildSettings.ExtraArgs) > 0 { args = append(args, buildSettings.ExtraArgs...) } } if settings.IsVerbose() { log.Printf("Env: %v", settings.Env) } if len(settings.Env) > 0 { vars := struct { PS string PLS string Env map[string]string }{ string(os.PathSeparator), string(os.PathListSeparator), map[string]string{}, } for _, val := range os.Environ() { k, v, err := splitEnvVar(val) if err != nil { //ignore invalid env vars from environment } else { vars.Env[k] = v } } for _, envTpl := range settings.Env { if settings.IsVerbose() { log.Printf("Processing env var %s", envTpl) } tpl, err := template.New("envItem").Parse(envTpl) if err != nil { return err } var dest bytes.Buffer err = tpl.Execute(&dest, vars) if err != nil { return err } executed := dest.String() if settings.IsVerbose() { if envTpl != executed { log.Printf("Setting env var (converted from %s to %s)", envTpl, executed) } else { log.Printf("Setting env var from config: %s", executed) } } env = append(env, dest.String()) //new address if necessary k, v, err := splitEnvVar(dest.String()) if err != nil { //fail on badly specified ENV vars return errors.New("Invalid env var defined by settings") } else { vars.Env[k] = v } } } args = append(args, subCmdArgs...) cmd, err := NewCmd(cmdPath, workingDirectory, args, env, settings.IsVerbose(), !settings.IsQuiet()) if err != nil { return err } if settings.IsVerbose() { log.Printf("invoking '%s %v' from '%s'", cmdPath, PrintableArgs(args), workingDirectory) } err = StartAndWait(cmd) if err != nil { log.Printf("'go' returned error: %s", err) return err } if settings.IsVerbose() { log.Printf("'go' completed successfully") } return nil }
// run all given tasks func RunTasks(workingDirectory string, destPlatforms []platforms.Platform, settings *config.Settings, maxProcessors int) error { if settings.IsVerbose() { log.Printf("Using Go root: %s", settings.GoRoot) log.Printf("looping through each platform") } appName := core.GetAppName(settings.AppName, workingDirectory) outDestRoot, err := core.GetOutDestRoot(appName, workingDirectory, settings.ArtifactsDest) if err != nil { return err } defer log.SetPrefix("[goxc] ") exclusions := ResolveAliases(settings.TasksExclude) appends := ResolveAliases(settings.TasksAppend) mains := ResolveAliases(settings.Tasks) all := ResolveAliases(settings.TasksPrepend) //log.Printf("prepending %v", all) all = append(all, mains...) all = append(all, appends...) //exclude by resolved task names (not by aliases) tasksToRun := []string{} for _, taskName := range all { if !core.ContainsString(exclusions, taskName) { tasksToRun = append(tasksToRun, taskName) } } //0.6 check all tasks are valid before continuing for _, taskName := range tasksToRun { if _, keyExists := allTasks[taskName]; !keyExists { if strings.HasPrefix(taskName, ".") { log.Printf("'%s' looks like a directory, not a task - specify 'working directory' with -wd option", taskName) } if e, _ := core.FileExists(taskName); e { log.Printf("'%s' looks like a directory, not a task - specify 'working directory' with -wd option", taskName) } if settings.IsVerbose() { log.Printf("Task '%s' does NOT exist!", taskName) } return errors.New("Task '" + taskName + "' does not exist") } } mainDirs := []string{} allPackages := []string{} if len(tasksToRun) == 1 && tasksToRun[0] == "toolchain" { log.Printf("Toolchain task only - not searching for main dirs") //mainDirs = []string{workingDirectory} } else { var err error excludes := core.ParseCommaGlobs(settings.MainDirsExclude) excludesSource := core.ParseCommaGlobs(settings.SourceDirsExclude) excludesSource = append(excludesSource, excludes...) allPackages, err = source.FindSourceDirs(workingDirectory, "", excludesSource, settings.IsVerbose()) if err != nil || len(allPackages) == 0 { log.Printf("Warning: could not establish list of source packages. Using working directory") allPackages = []string{workingDirectory} } mainDirs, err = source.FindMainDirs(workingDirectory, excludes, settings.IsVerbose()) if err != nil || len(mainDirs) == 0 { log.Printf("Warning: could not find any main dirs: %v", err) } else { if settings.IsVerbose() { log.Printf("Found 'main package' dirs (len %d): %v", len(mainDirs), mainDirs) } } } if settings.IsVerbose() { log.Printf("Running tasks: %v", tasksToRun) log.Printf("All packages: %v", allPackages) } for _, taskName := range tasksToRun { log.SetPrefix("[goxc:" + taskName + "] ") if settings.IsVerbose() { log.Printf("Running task %s with settings: %v", taskName, settings.TaskSettings[taskName]) } err := runTask(taskName, destPlatforms, allPackages, mainDirs, appName, workingDirectory, outDestRoot, settings, maxProcessors) if err != nil { // TODO: implement 'force' option. log.Printf("Stopping after '%s' failed with error '%v'", taskName, err) return err } else { if !settings.IsQuiet() { log.Printf("Task %s succeeded", taskName) } } } return nil }