diff --git a/.gitignore b/.gitignore index 257ef31d6..06c90e05e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ /.idea /.fleet /.vscode/*.log +/answer_build*/ +/answer.build.yaml /cmd/answer/*.sh /cmd/answer/answer /cmd/answer/uploads/* diff --git a/answer.build.yaml.example b/answer.build.yaml.example new file mode 100644 index 000000000..5ecc9a7da --- /dev/null +++ b/answer.build.yaml.example @@ -0,0 +1,14 @@ +# use buildDir or buildAbsDir +buildDir: "../answer-builds/build" +buildAbsDir: "" +# default new_answer +outputPath: "new_answer" +# default the github repository +answerModule: "" +plugins: + - "github.com/apache/answer-plugins/connector-basic@latest" + - "github.com/apache/answer-plugins/reviewer-basic@latest" + - "github.com/apache/answer-plugins/captcha-basic@latest" + - "github.com/apache/answer-plugins/quick-links@latest" +# whether if you want to reserve buildDir, default is delete it +reserveBuild: false diff --git a/cmd/command.go b/cmd/command.go index ca01aa80b..e47b2ac24 100644 --- a/cmd/command.go +++ b/cmd/command.go @@ -23,7 +23,6 @@ import ( "context" "fmt" "os" - "strings" "github.com/apache/answer/internal/base/conf" "github.com/apache/answer/internal/base/path" @@ -40,6 +39,8 @@ var ( dataDirPath string // dumpDataPath dump data path dumpDataPath string + // build config path, if exists, ignore other build args + buildConfigPath string // place to build new answer buildDir string // plugins needed to build in answer application @@ -68,6 +69,8 @@ func init() { dumpCmd.Flags().StringVarP(&dumpDataPath, "path", "p", "./", "dump data path, eg: -p ./dump/data/") + buildCmd.Flags().StringVarP(&buildConfigPath, "config", "c", "", "build config path, if exists, ignore other build args") + buildCmd.Flags().StringSliceVarP(&buildWithPlugins, "with", "w", []string{}, "plugins needed to build") buildCmd.Flags().StringVarP(&buildOutput, "output", "o", "", "build output path") @@ -222,8 +225,7 @@ To run answer, use: Short: "Build Answer with plugins", Long: `Build a new Answer with plugins that you need`, Run: func(_ *cobra.Command, _ []string) { - fmt.Printf("try to build a new answer with plugins:\n%s\n", strings.Join(buildWithPlugins, "\n")) - err := cli.BuildNewAnswer(buildDir, buildOutput, buildWithPlugins, cli.OriginalAnswerInfo{ + err := cli.BuildNewAnswer(buildConfigPath, buildDir, buildOutput, buildWithPlugins, cli.OriginalAnswerInfo{ Version: Version, Revision: Revision, Time: Time, diff --git a/internal/cli/build.go b/internal/cli/build.go index efc876e31..23bc494f1 100644 --- a/internal/cli/build.go +++ b/internal/cli/build.go @@ -34,6 +34,7 @@ import ( "github.com/Masterminds/semver/v3" "github.com/apache/answer/pkg/dir" "github.com/apache/answer/pkg/writer" + "github.com/segmentfault/pacman/contrib/conf/viper" "github.com/segmentfault/pacman/log" "gopkg.in/yaml.v3" ) @@ -76,6 +77,7 @@ type buildingMaterial struct { outputPath string tmpDir string originalAnswerInfo OriginalAnswerInfo + reserveBuild bool } type OriginalAnswerInfo struct { @@ -93,23 +95,74 @@ type pluginInfo struct { Version string } -func newAnswerBuilder(buildDir, outputPath string, plugins []string, originalAnswerInfo OriginalAnswerInfo) *answerBuilder { +type BuildConfig struct { + BuildDir string `json:"buildDir" mapstructure:"buildDir" yaml:"buildDir"` + BuildAbsDir string `json:"buildAbsDir" mapstructure:"buildAbsDir" yaml:"buildAbsDir"` + OutputPath string `json:"outputPath" mapstructure:"outputPath" yaml:"outputPath"` + Plugins []string `json:"plugins" mapstructure:"plugins" yaml:"plugins"` + AnswerModule string `json:"answerModule" mapstructure:"answerModule" yaml:"answerModule"` + ReserveBuild bool `json:"reserveBuild" mapstructure:"reserveBuild" yaml:"reserveBuild"` +} + +func newAnswerBuilder(buildConfigPath, buildDir, outputPath string, plugins []string, originalAnswerInfo OriginalAnswerInfo) (*answerBuilder, error) { material := &buildingMaterial{originalAnswerInfo: originalAnswerInfo} parentDir, _ := filepath.Abs(".") - if buildDir != "" { - material.tmpDir = filepath.Join(parentDir, buildDir) + if buildConfigPath == "" { + fmt.Printf("try to build a new answer with plugins:\n%s\n", strings.Join(plugins, "\n")) + + if buildDir != "" { + material.tmpDir = filepath.Join(parentDir, buildDir) + } else { + material.tmpDir, _ = os.MkdirTemp(parentDir, "answer_build") + } + if len(outputPath) == 0 { + outputPath = filepath.Join(parentDir, "new_answer") + } + material.outputPath, _ = filepath.Abs(outputPath) + material.plugins = formatPlugins(plugins) + material.answerModuleReplacement = os.Getenv("ANSWER_MODULE") } else { - material.tmpDir, _ = os.MkdirTemp(parentDir, "answer_build") - } - if len(outputPath) == 0 { - outputPath = filepath.Join(parentDir, "new_answer") + config, err := viper.NewWithPath(buildConfigPath) + if err != nil { + return nil, err + } + var c BuildConfig + if err = config.Parse(&c); err != nil { + return nil, err + } + + fmt.Printf("try to build a new answer with plugins:\n%s\n", strings.Join(c.Plugins, "\n")) + + isBuildDirTemp := false + if strings.TrimSpace(c.BuildAbsDir) != "" { + material.tmpDir = strings.TrimSpace(c.BuildAbsDir) + } else if strings.TrimSpace(c.BuildDir) != "" { + material.tmpDir = filepath.Join(parentDir, strings.TrimSpace(c.BuildDir)) + } else { + isBuildDirTemp = true + material.tmpDir, _ = os.MkdirTemp(parentDir, "answer_build") + } + if !isBuildDirTemp && c.ReserveBuild { + dirPath := filepath.Dir(material.tmpDir) + _ = os.MkdirAll(dirPath, os.ModePerm) + material.tmpDir, _ = os.MkdirTemp(dirPath, filepath.Base(material.tmpDir)) + } + if len(c.OutputPath) == 0 { + material.outputPath = filepath.Join(parentDir, "new_answer") + } else { + material.outputPath = strings.TrimSpace(c.OutputPath) + } + material.plugins = formatPlugins(c.Plugins) + if c.AnswerModule != "" { + material.answerModuleReplacement, _ = filepath.Abs(c.AnswerModule) + } else { + material.answerModuleReplacement = os.Getenv("ANSWER_MODULE") + } + material.reserveBuild = c.ReserveBuild } - material.outputPath, _ = filepath.Abs(outputPath) - material.plugins = formatPlugins(plugins) - material.answerModuleReplacement = os.Getenv("ANSWER_MODULE") return &answerBuilder{ buildingMaterial: material, - } + }, nil } func (a *answerBuilder) DoTask(task func(b *buildingMaterial) error) { @@ -120,8 +173,11 @@ func (a *answerBuilder) DoTask(task func(b *buildingMaterial) error) { } // BuildNewAnswer builds a new answer with specified plugins -func BuildNewAnswer(buildDir, outputPath string, plugins []string, originalAnswerInfo OriginalAnswerInfo) (err error) { - builder := newAnswerBuilder(buildDir, outputPath, plugins, originalAnswerInfo) +func BuildNewAnswer(buildConfigPath, buildDir, outputPath string, plugins []string, originalAnswerInfo OriginalAnswerInfo) (err error) { + builder, err := newAnswerBuilder(buildConfigPath, buildDir, outputPath, plugins, originalAnswerInfo) + if err != nil { + return err + } builder.DoTask(createMainGoFile) builder.DoTask(downloadGoModFile) builder.DoTask(movePluginToVendor) @@ -507,6 +563,11 @@ func buildBinary(b *buildingMaterial) (err error) { // cleanByproduct delete tmp dir func cleanByproduct(b *buildingMaterial) (err error) { + if b.reserveBuild { + fmt.Printf("sikp clean build temp dir\n") + return nil + } + fmt.Printf("remove build temp dir\n") return os.RemoveAll(b.tmpDir) }