func (pw *ProjectWatcher) updateConfig() { loggers.Info("Reloading the project.toml file ...") var newConfig ProjectConfig if _, err := toml.DecodeFile("project.toml", &newConfig); err != nil { loggers.Error("We found the project.toml has changed, but it contains some error, will omit it.") loggers.Error("TOML Error: %v", err) fmt.Println() loggers.Info("Waiting for the file changes ...") } else { loggers.Succ("Loaded the new project.toml, will update all the dependencies ...") rootConfig.Lock() rootConfig.Package = newConfig.Package rootConfig.Assets = newConfig.Assets rootConfig.Distribution = newConfig.Distribution rootConfig.Unlock() if err := updateGolangDeps(); err != nil { loggers.Error("Failed to load project Go dependencies, %v", err) return } if err := updateAssetsDeps(); err != nil { loggers.Error("Failed to load project assets dependencies, %v", err) return } pw.addTask(kTaskBuildImages, "") pw.addTask(kTaskBuildStyles, "") pw.addTask(kTaskBuildJavaScripts, "") pw.addTask(kTaskGenAssetsMapping, "") pw.addTask(kTaskBuildBinary, "") pw.addTask(kTaskBinaryRestart, "") } }
func updateGolangDeps() error { rootConfig.RLock() defer rootConfig.RUnlock() if rootConfig.Package == nil || len(rootConfig.Package.Dependencies) == 0 { return nil } fmt.Println() loggers.Info("Start to loading Go dependencies...") if hasGetColangDeps() { loggers.Info("Has Loaded Go package dependencies") return nil } params := []string{"get", ""} for _, dep := range rootConfig.Package.Dependencies { params[len(params)-1] = dep loggers.Info("Loading Go package dependency: %v", dep) getCmd := exec.Command("go", params...) getCmd.Stdout = os.Stdout getCmd.Stderr = os.Stderr getCmd.Env = mergeEnv(nil) if err := getCmd.Run(); err != nil { loggers.Error("Error when run go get: go %v, %v", params, err) return err } } loggers.Succ("Loaded Go package dependencies: \n\t%v", strings.Join(rootConfig.Package.Dependencies, "\n\t")) return nil }
func (il _ImageLibrary) Build(isProduction bool) error { folderName := fmt.Sprintf("assets/images/%s", il.entry) if exist, err := il.checkFile(folderName, false); !exist { return err } targetFolder := fmt.Sprintf("public/images/%s", il.entry) if err := ResetDir(targetFolder, true); err != nil { return err } // copy the single image files if imageItems, err := il.getImages(folderName); err != nil { return err } else { for _, imgItem := range imageItems { target := fmt.Sprintf("public/images/%s/%s", il.entry, imgItem.name) if err := il.copyFile(target, imgItem.fullpath); err != nil { return err } target = il.addFingerPrint(targetFolder, imgItem.name) loggers.Succ("[ImageLibrary][%s] Saved images: %s", il.entry, target) } } // check if we have sprite folders under assets return il.buildSprites(il.entry, isProduction) }
func (d _GoPkgMappingDumper) Dump(mapping *AssetsMapping) error { pkgName, targetPath := d.GetPkgPath() mapping.PkgName = pkgName sort.Sort(mapping) if file, err := os.Create(targetPath); err != nil { return fmt.Errorf("Cannot create the assets mapping go file, %+v", err) } else { defer file.Close() if err := tmAssetsMapping.Execute(file, mapping); err != nil { return fmt.Errorf("Cannot generate assets mapping file, %+v", err) } } var out bytes.Buffer cmd := exec.Command("gofmt", "-w", targetPath) cmd.Stderr = &out if err := cmd.Run(); err != nil { loggers.Error("[AssetMapping] failed to gofmt source code, %v", out.String()) return err } loggers.Succ("[AssetMappings] Saved asssets mapping go file: %q", targetPath) return nil }
func (s _Sprite) save(spriteImg image.Image, items []_ImageItem, fullWidth, fullHeight int) error { targetFolder := fmt.Sprintf("public/images/%s", s.entry) target := path.Join(targetFolder, s.name+".png") if file, err := os.Create(target); err != nil { return fmt.Errorf("Cannot create sprite file %s, %v", target, err) } else { defer file.Close() if err := png.Encode(file, spriteImg); err != nil { return nil } target = s.addFingerPrint(targetFolder, s.name+".png") loggers.Succ("[Sprite][%s] Saved sprite image: %s", s.entry, target) // generate the stylus file stylus := "assets/stylesheets/sprites" if err := os.MkdirAll(stylus, os.ModePerm|os.ModeDir); err != nil { return fmt.Errorf("Cannot mkdir %s, %v", stylus, err) } stylus = fmt.Sprintf("assets/stylesheets/sprites/%s_%s.styl", s.entry, s.name) if stylusFile, err := os.Create(stylus); err != nil { return fmt.Errorf("Cannot create the stylus file for sprite %s, %v", stylus, err) } else { defer stylusFile.Close() spriteEntry := SpriteEntry{ Entry: s.entry, Name: s.name, Url: fmt.Sprintf("%s/images/%s/%s", s.config.UrlPrefix, s.entry, filepath.Base(target)), Sprites: make([]SpriteImage, len(items)), Width: fullWidth / s.pixelRatio, Height: fullHeight / s.pixelRatio, } lastHeight := 0 for i, image := range items { name := image.name name = name[:len(name)-len(filepath.Ext(name))] width, height := image.Bounds().Dx(), image.Bounds().Dy() if width%s.pixelRatio != 0 || height%s.pixelRatio != 0 { loggers.Warn("You have images cannot be adjusted by the pixel ratio, %s, bounds=%v, pixelRatio=%d", image.fullpath, image.Bounds(), s.pixelRatio) } spriteEntry.Sprites[i] = SpriteImage{ Name: fmt.Sprintf("%s-%s", s.name, name), X: 0, Y: -1 * lastHeight, Width: width / s.pixelRatio, Height: height / s.pixelRatio, } lastHeight += (height + s.pixelRatio) / s.pixelRatio } if err := tmSprites.Execute(stylusFile, spriteEntry); err != nil { return fmt.Errorf("Cannot generate stylus for sprites %s, %v", spriteEntry, err) } } } return nil }
func (app *AppShell) buildPackage() error { name, version := rootConfig.Package.Name, rootConfig.Package.Version pkgName := fmt.Sprintf("%s-%s", name, version) srcFolders := append([]string{"public"}, rootConfig.Distribution.PackExtras...) goOs, goArch := runtime.GOOS, runtime.GOARCH targets := append(rootConfig.Distribution.CrossTargets, [2]string{goOs, goArch}) visited := make(map[string]struct{}) for _, target := range targets { buildTarget := fmt.Sprintf("%s_%s", target[0], target[1]) if _, ok := visited[buildTarget]; ok { continue } visited[buildTarget] = struct{}{} srcFolders = append(srcFolders, app.binaryName(name, version, target[0], target[1])) } if zipFile, err := os.Create(pkgName + ".zip"); err != nil { return fmt.Errorf("Cannot create the zip file[%q], %v", pkgName, err) } else { defer zipFile.Close() zw := zip.NewWriter(zipFile) defer zw.Close() for _, srcFolder := range srcFolders { err := filepath.Walk(srcFolder, func(fn string, info os.FileInfo, err error) error { if err == nil && !info.IsDir() { zipSrcName := path.Join(pkgName, fn) fileHeader, err := zip.FileInfoHeader(info) if err != nil { return err } fileHeader.Name = zipSrcName zipSrcFile, err := zw.CreateHeader(fileHeader) if err != nil { return err } srcFile, err := os.Open(fn) if err != nil { return err } io.Copy(zipSrcFile, srcFile) srcFile.Close() loggers.Debug("Archiving %s", zipSrcName) } return nil }) if err != nil { return fmt.Errorf("Cannot walk the files when creating the zip file, %v", err) } } } loggers.Succ("Finish packing the deploy package in %s.zip", pkgName) return nil }
func (css _StyleSheet) Build(isProduction bool) error { filename := fmt.Sprintf("assets/stylesheets/%s.styl", css.entry) isStylus := true if exist, _ := css.checkFile(filename, true); !exist { filename = fmt.Sprintf("assets/stylesheets/%s.css", css.entry) if exist, err := css.checkFile(filename, true); !exist { return err } else { isStylus = false } } target := fmt.Sprintf("public/stylesheets/%s.css", css.entry) // * Maybe it's a template using images, styles assets links // TODO // * Maybe we need to call stylus preprocess if isStylus { params := []string{"--use", "nib", filename, "--out", "public/stylesheets"} if isProduction { params = append(params, "--compress") } else { params = append(params, "--sourcemap-inline") } params = append(params, "--include-css") // add asset plugin to change original file path to the finger printed one if css.config.AssetsMappingJson != "" { params = append(params, "--use", getStylusPluginPath()) } cmd := exec.Command("./node_modules/stylus/bin/stylus", params...) loggers.Debug("[CSS][%s] Building asset: %s, %v", css.entry, filename, cmd.Args) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout cmd.Env = css.getEnv(isProduction) if err := cmd.Run(); err != nil { loggers.Error("[CSS][%s] Error when building asset %v, %v", css.entry, cmd.Args, err) return err } } else { if err := css.copyFile(target, filename); err != nil { return err } } // * generate the hash, clear old bundle, move to target target = css.addFingerPrint("public/stylesheets", css.entry+".css") loggers.Succ("[CSS][%s] Saved assset: %s", css.entry, target) return nil }
func (app *AppShell) start() error { app.command = exec.Command("./"+app.binName, app.args...) app.command.Stdout = os.Stdout app.command.Stderr = os.Stderr app.command.Env = mergeEnv(nil) if err := app.command.Start(); err != nil { return err } loggers.Succ("App is starting, %v", app.command.Args) fmt.Println() go app.command.Wait() time.Sleep(500 * time.Millisecond) return nil }
func (app *AppShell) distExtraCommand() error { extraCmd := rootConfig.Distribution.ExtraCmd if extraCmd == nil || len(extraCmd) == 0 { return nil } cmd := exec.Command(extraCmd[0], extraCmd[1:]...) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout if err := cmd.Run(); err != nil { loggers.Error("Error when running distribution extra command, %v, %s", extraCmd, err) return err } loggers.Succ("Run extra command succ: %v", cmd.Args) return nil }
func (app *AppShell) binaryTest(module string) error { return nil // close the test first, will reconsider this if module == "" { module = "./..." } testCmd := exec.Command("go", "test", "-v", module) testCmd.Stderr = os.Stderr testCmd.Stdout = os.Stdout testCmd.Env = mergeEnv(nil) if err := testCmd.Run(); err != nil { loggers.Error("Error when testing go modules[%s], %v", module, err) return err } loggers.Succ("Module[%s] Test passed: %v", module, testCmd.Args) return nil }
func (app *AppShell) buildBinary(params ...string) error { goOs, goArch := runtime.GOOS, runtime.GOARCH if len(params) == 2 && (goOs != params[0] || goArch != params[1]) { goOs, goArch = params[0], params[1] } rootConfig.RLock() builder := rootConfig.Package.Builder binName := app.binaryName(rootConfig.Package.Name, rootConfig.Package.Version, goOs, goArch) var buildOpts []string if app.isProduction { buildOpts = make([]string, len(rootConfig.Distribution.BuildOpts)) copy(buildOpts, rootConfig.Distribution.BuildOpts) } else { buildOpts = make([]string, len(rootConfig.Package.BuildOpts)) copy(buildOpts, rootConfig.Package.BuildOpts) } rootConfig.RUnlock() cmdName := "go" flags := make([]string, 0, 3+len(buildOpts)) if builder != "" { flags = append(flags, "go") cmdName = builder } flags = append(flags, "build") flags = append(flags, buildOpts...) flags = append(flags, []string{"-o", binName}...) buildCmd := exec.Command(cmdName, flags...) buildCmd.Stderr = os.Stderr buildCmd.Stdout = os.Stdout buildCmd.Env = mergeEnv(map[string]string{ "GOOS": goOs, "GOARCH": goArch, }) loggers.Debug("Running build: %v", buildCmd.Args) start := time.Now() if err := buildCmd.Run(); err != nil { loggers.Error("Building failed") return err } app.binName = binName duration := float64(time.Since(start).Nanoseconds()) / 1e6 loggers.Succ("Got binary built %s, takes=%.3fms", binName, duration) return nil }
func (d _JsonMappingDumper) Dump(mapping *AssetsMapping) error { srcMap := make(map[string]string) for _, m := range mapping.Mappings { srcMap[m.Src] = m.Target } if data, err := json.MarshalIndent(srcMap, "", " "); err != nil { return fmt.Errorf("Cannot encoding the assets into json, %s", err) } else { if err := ioutil.WriteFile(d.jsonFile, data, 0644); err != nil { loggers.Error("[AsssetMapping] failed to write json mapping file, %s", err) return err } } loggers.Succ("[AssetMappings] Saved asssets mapping json file: %q", d.jsonFile) return nil }
func updateAssetsDeps() error { rootConfig.RLock() defer rootConfig.RUnlock() if rootConfig.Assets == nil || len(rootConfig.Assets.Dependencies) == 0 { return nil } fmt.Println() loggers.Info("Start to loading assets dependencies...") checkParams := []string{"list", "--depth", "0", ""} params := []string{"install", ""} deps := make([]string, len(rootConfig.Assets.Dependencies), len(rootConfig.Assets.Dependencies)+1) copy(deps, rootConfig.Assets.Dependencies) // add all dev deps for xxxify deps = append(deps, "browserify", "coffeeify", "envify", "uglifyify", "babelify", "babel-preset-es2015", "babel-preset-react", "nib", "stylus") for _, dep := range deps { checkParams[len(checkParams)-1] = dep listCmd := exec.Command("npm", checkParams...) listCmd.Env = mergeEnv(nil) if err := listCmd.Run(); err == nil { // the module has been installed loggers.Info("Checked npm module: %v", dep) continue } params[len(params)-1] = dep loggers.Info("Loading npm module: %v", dep) installCmd := exec.Command("npm", params...) installCmd.Stdout = os.Stdout installCmd.Stderr = os.Stderr installCmd.Env = mergeEnv(nil) if err := installCmd.Run(); err != nil { loggers.Error("Error when run npm install: npm %v, %v", params, err) return err } } loggers.Succ("Loaded assets dependencies: \n\t%v", strings.Join(deps, "\n\t")) return nil }
func (app *AppShell) binaryTest(module string) error { return nil // close the test first, will reconsider this if module == "" { module = "./..." } builder := rootConfig.Package.Builder cmdName := "go" flags := make([]string, 0) if builder != "" { cmdName = builder flags = append(flags, "go") } flags = append(flags, "test", "-v", module) testCmd := exec.Command(cmdName, flags...) testCmd.Stderr = os.Stderr testCmd.Stdout = os.Stdout testCmd.Env = mergeEnv(nil) if err := testCmd.Run(); err != nil { loggers.Error("Error when testing go modules[%s], %v", module, err) return err } loggers.Succ("Module[%s] Test passed: %v", module, testCmd.Args) return nil }
func (js _JavaScript) Build(isProduction bool) error { if os.Getenv("NODE_ENV") == "production" { isProduction = true } assetEntry, ok := js.config.getAssetEntry(js.entry) if !ok { return nil } target := fmt.Sprintf("public/javascripts/%s.js", js.entry) filename := fmt.Sprintf("assets/javascripts/%s.js", js.entry) isCoffee := false if exist, _ := js.checkFile(filename, true); !exist { filename = fmt.Sprintf("assets/javascripts/%s.coffee", js.entry) if exist, err := js.checkFile(filename, true); !exist { return err } isCoffee = true } // * Maybe it's a template using images, styles assets links // TODO // * run browserify params := []string{filename} for _, require := range assetEntry.Requires { params = append(params, "--require", require) } for _, external := range assetEntry.Externals { if anEntry, ok := js.config.getAssetEntry(external); ok { for _, require := range anEntry.Requires { params = append(params, "--external", require) } } } for _, opt := range assetEntry.BundleOpts { params = append(params, opt) } if isCoffee { params = append(params, "--transform", "coffeeify") } else { params = append(params, "--transform", "[", "babelify", "--presets", "[", "es2015", "react", "]", "]") } params = append(params, "--transform", "envify") if isProduction { params = append(params, "-g", "uglifyify") } else { params = append(params, "--debug") } params = append(params, "--outfile", target) cmd := exec.Command("./node_modules/browserify/bin/cmd.js", params...) loggers.Debug("[JavaScript][%s] Building asset: %s, %v", js.entry, filename, cmd.Args) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout cmd.Env = js.getEnv(isProduction) if err := cmd.Run(); err != nil { loggers.Error("[JavaScript][%s] Error when building asset %v, %v", js.entry, cmd.Args, err) return err } // * generate the hash, clear old bundle, move to target target = js.addFingerPrint("public/javascripts", js.entry+".js") loggers.Succ("[JavaScript][%s] Saved assset: %s", js.entry, target) return nil }
func (js _JavaScript) Build(isProduction bool) error { if os.Getenv("NODE_ENV") == "production" { isProduction = true } assetEntry, ok := js.config.getAssetEntry(js.entry) if !ok { return nil } suffixJs, suffixCoffee, originDir, targetDir := ".js", ".coffee", "assets/javascripts", "public/javascripts" filename, outfile := path.Join(originDir, js.entry+suffixJs), path.Join(targetDir, js.entry+suffixJs) isCoffee := false if exist, _ := js.checkFile(filename, true); !exist { filename = path.Join(originDir, js.entry+suffixCoffee) if exist, err := js.checkFile(filename, true); !exist { return err } isCoffee = true } // * generate the hash, just loaded if not change outTarget := js.traverEntryFingerPrint(originDir, targetDir, js.entry, filename, suffixJs) mapping := js._Asset.getJsonAssetsMapping() if targetName, ok := mapping[outfile[len("public/"):]]; ok { if targetName == outTarget[len("public/"):] { loggers.Succ("[JavaScript][%s] Loaded assset: %s", js.entry, outTarget) return nil } } // * Maybe it's a template using images, styles assets links // TODO // * run browserify params := []string{filename} for _, require := range assetEntry.Requires { params = append(params, "--require", require) } for _, external := range assetEntry.Externals { if anEntry, ok := js.config.getAssetEntry(external); ok { for _, require := range anEntry.Requires { params = append(params, "--external", require) } } } for _, opt := range assetEntry.BundleOpts { params = append(params, opt) } if isCoffee { params = append(params, "--transform", "coffeeify") } else { params = append(params, "--transform", "[", "babelify", "--presets", "[", "es2015", "react", "]", "]") } params = append(params, "--transform", "envify") if isProduction { params = append(params, "-g", "uglifyify") } else { params = append(params, "--debug") } params = append(params, "--outfile", outfile) cmd := exec.Command("./node_modules/browserify/bin/cmd.js", params...) loggers.Debug("[JavaScript][%s] Building asset: %s, %v", js.entry, filename, cmd.Args) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout cmd.Env = js.getEnv(isProduction) if err := cmd.Run(); err != nil { loggers.Error("[JavaScript][%s] Error when building asset %v, %v", js.entry, cmd.Args, err) return err } //clear old bundle, move to target js._Asset.removeOldFile(targetDir, js.entry+suffixJs) if err := os.Rename(outfile, outTarget); err != nil { loggers.Error("rename file error, %v", err) } // target = js.addFingerPrint("public/javascripts", js.entry+".js") loggers.Succ("[JavaScript][%s] Saved assset: %s", js.entry, outTarget) return nil }