Beispiel #1
0
func (app *AppShell) startRunner() {
	for task := range app.taskChan {
		switch task.taskType {
		case kTaskBuildImages:
			app.curError = app.buildImages(task.module)
		case kTaskBuildStyles:
			app.curError = app.buildStyles(task.module)
		case kTaskBuildJavaScripts:
			app.curError = app.buildJavaScripts(task.module)
		case kTaskGenAssetsMapping:
			app.curError = app.genAssetsMapping()
		case kTaskBinaryTest:
			app.curError = app.binaryTest(task.module)
		case kTaskBuildBinary:
			app.curError = app.buildBinary()
		case kTaskBinaryRestart:
			if app.curError == nil {
				if err := app.kill(); err != nil {
					loggers.Error("App cannot be killed, maybe you should restart the gobuildweb: %v", err)
				} else {
					if err := app.start(); err != nil {
						loggers.Error("App cannot be started, maybe you should restart the gobuildweb: %v", err)
					}
				}
			} else {
				loggers.Warn("You have errors with current assets and binary, please fix that ...")
			}
			fmt.Println()
			loggers.Info("Waiting for the file changes ...")
		}
	}
}
Beispiel #2
0
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, "")
	}
}
Beispiel #3
0
func commandDist(args []string) error {
	if err := updateGolangDeps(); err != nil {
		loggers.Error("Failed to load project #Golang dependencies, %v", err)
		return err
	}
	if err := updateAssetsDeps(); err != nil {
		loggers.Error("Failed to load project assets dependencies, %v", err)
		return err
	}

	return NewAppShell(args).Dist()
}
Beispiel #4
0
func (a _Asset) getJsonAssetsMapping() map[string]string {
	mapping := make(map[string]string)
	filename := a.config.AssetsMappingJson
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		loggers.Error(fmt.Sprintf("Cannot decoding the assets into json, %v", err))
	} else {
		err = json.Unmarshal(data, &mapping)
		if err != nil {
			loggers.Error(fmt.Sprintf("Cannot unmarshal the assets into json, %v", err))
		}
	}
	return mapping
}
Beispiel #5
0
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
}
Beispiel #6
0
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
}
Beispiel #7
0
func commandRun(args []string) error {
	if err := updateGolangDeps(); err != nil {
		loggers.Error("Failed to load project Go dependencies, %v", err)
		return err
	}
	if err := updateAssetsDeps(); err != nil {
		loggers.Error("Failed to load project assets dependencies, %v", err)
		return err
	}

	fmt.Println()
	if err := NewProjectWatcher().runAndWatch(".", args); err != nil {
		loggers.Error("Failed to start watching project changes, %v", err)
		return err
	}
	return nil
}
Beispiel #8
0
func (app *AppShell) Dist() error {
	app.isProduction = true
	fmt.Println()
	loggers.Info("Creating distribution package for %v-%v",
		rootConfig.Package.Name, rootConfig.Package.Version)

	var err error
	if err = app.buildImages(""); err != nil {
		loggers.Error("Error when building images, %v", err)
	} else if err = app.genAssetsMapping(); err != nil {
		loggers.Error("Error when generating assets mapping source code, %v", err)
	} else if err = app.buildStyles(""); err != nil {
		loggers.Error("Error when building stylesheets, %v", err)
	} else if err = app.clearJavaScriptsAssets(); err != nil {
		loggers.Error("Error when clear javascripts, %v", err)
	} else if err = app.buildJavaScripts(APP_SHELL_JS_TASK_INIT_ENTRY_KEY); err != nil {
		loggers.Error("Error when building javascripts, %v", err)
	} else if err = app.genAssetsMapping(); err != nil {
		loggers.Error("Error when generating assets mapping source code, %v", err)
	} else if err = app.binaryTest(""); err != nil {
		loggers.Error("You have failed test cases, %v", err)
	} else if err = app.distExtraCommand(); err != nil {
		loggers.Error("Error when running the distribution extra command, %v", err)
	} else if err == nil {
		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{}{}
			if err = app.buildBinary(target[:]...); err != nil {
				loggers.Error("Error when building binary for %v, %v", target, err)
			}
		}
	}
	if err == nil {
		err = app.buildPackage()
	}
	return err
}
Beispiel #9
0
func (pw *ProjectWatcher) maybeGoCodeChanged(fname string) {
	if strings.HasSuffix(fname, ".go") {
		goModule := path.Dir(fname)
		if pw.hasGoTests(goModule) {
			if moduleName, err := pw.goModuleName(goModule); err == nil {
				pw.addTask(kTaskBinaryTest, moduleName)
			} else {
				loggers.Error("Cannot get go module path name, %v", err)
			}
		}
		pw.addTask(kTaskBuildBinary, goModule)
		pw.addTask(kTaskBinaryRestart, "")
	}
}
Beispiel #10
0
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
}
Beispiel #11
0
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
}
Beispiel #12
0
//是否已经下载了go运行所需要的包,是否可以编译成功
func hasGetColangDeps() bool {
	cmd := exec.Command("go", "build")
	loggers.Info("Started to go build...")
	err := cmd.Start()
	if err != nil {
		loggers.Error("Failed to go build... %+v", err)
		return false
	}
	done := make(chan error, 1)
	go func() {
		done <- cmd.Wait()
	}()
	err = <-done
	if err != nil {
		loggers.Error("Failed to go build...%+v", err)
	} else {
		loggers.Info("Successed to go build...")
		cmd := exec.Command("rm", "zhiwang_web")
		cmd.Run()
		return true
	}

	return false
}
Beispiel #13
0
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
}
Beispiel #14
0
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
}
Beispiel #15
0
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
}
Beispiel #16
0
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
}
Beispiel #17
0
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
}
Beispiel #18
0
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
}
Beispiel #19
0
func (pw *ProjectWatcher) watchProject() {
	tick := time.Tick(800 * time.Millisecond)
	for {
		select {
		case event := <-pw.watcher.Events:
			if event.Name == "" ||
				pw.isIgnoredDir(event.Name) ||
				strings.HasSuffix(event.Name, ".swp") ||
				strings.HasSuffix(event.Name, ".DS_Store") {
				break
			}
			loggers.Debug("fsevents: %v", event)
			if event.Op&fsnotify.Create == fsnotify.Create || event.Op&fsnotify.Write == fsnotify.Write {
				if fi, err := os.Stat(event.Name); err == nil {
					if fi.IsDir() {
						if err := pw.watcher.Add(event.Name); err != nil {
							loggers.Error("Failed to add new directory into watching list[%v], %v",
								event.Name, err)
						} else {
							loggers.Debug("Watching %s", event.Name)
						}
					} else {
						if event.Name == "project.toml" {
							pw.updateConfig()
						}
						pw.maybeGoCodeChanged(event.Name)
						pw.maybeAssetsChanged(event.Name)
					}
				}
			} else if event.Op&fsnotify.Remove == fsnotify.Remove || event.Op&fsnotify.Rename == fsnotify.Rename {
				// maybe remove some dir
				if fi, err := os.Stat(event.Name); err == nil {
					if fi.IsDir() {
						if err := pw.watcher.Remove(event.Name); err != nil {
							loggers.Error("Failed to remove directory from watching list [%v], %v",
								event.Name, err)
						}
						// if the dir is under assets, we need to rebuild all the assets or sprites
						// else we take it as a go code directory
						// TODO
					} else {
						if event.Name == "project.toml" {
							panic("Please don't hurt the project.toml")
						}
						// maybe remove some source code
						// TODO
					}
				}
			}
		case err := <-pw.watcher.Errors:
			loggers.Error("Error: %v", err)
		case <-tick:
			pw.taskLock.Lock()
			if len(pw.tasks) > 0 {
				pw.app.executeTask(pw.tasks...)
				pw.tasks = make([]AppShellTask, 0)
			}
			pw.taskLock.Unlock()
		}
	}
}
Beispiel #20
0
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
}