mirror of
https://github.com/TECHNOFAB11/powerproto.git
synced 2025-12-12 08:00:04 +01:00
init
Signed-off-by: storyicon <yuanchao@bilibili.com>
This commit is contained in:
commit
9aac714c32
47 changed files with 5480 additions and 0 deletions
60
cmd/powerproto/main.go
Normal file
60
cmd/powerproto/main.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
cmdbuild "github.com/storyicon/powerproto/cmd/powerproto/subcommands/build"
|
||||
cmdenv "github.com/storyicon/powerproto/cmd/powerproto/subcommands/env"
|
||||
cmdinit "github.com/storyicon/powerproto/cmd/powerproto/subcommands/init"
|
||||
cmdtidy "github.com/storyicon/powerproto/cmd/powerproto/subcommands/tidy"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// Version is set via build flag -ldflags -X main.Version
|
||||
var (
|
||||
Version string
|
||||
Branch string
|
||||
Revision string
|
||||
BuildDate string
|
||||
)
|
||||
|
||||
var log = logger.NewDefault("command")
|
||||
|
||||
// GetRootCommand is used to get root command
|
||||
func GetRootCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "[powerproto]",
|
||||
Version: fmt.Sprintf("%s, branch: %s, revision: %s, buildDate: %s", Version, Branch, Revision, BuildDate),
|
||||
Short: "powerproto is used to build proto files and version control of protoc and related plug-ins",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
_ = cmd.Help()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
cmdRoot := GetRootCommand()
|
||||
cmdRoot.AddCommand(
|
||||
cmdbuild.CommandBuild(log),
|
||||
cmdinit.CommandInit(log),
|
||||
cmdtidy.CommandTidy(log),
|
||||
cmdenv.CommandEnv(log),
|
||||
)
|
||||
cmdRoot.Execute()
|
||||
}
|
||||
117
cmd/powerproto/subcommands/build/command.go
Normal file
117
cmd/powerproto/subcommands/build/command.go
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/bootstraps"
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
const description = `
|
||||
Examples:
|
||||
compile specific proto file
|
||||
powerproto build [proto file]
|
||||
|
||||
compile the proto file in the folder, excluding sub folders:
|
||||
powerproto build [dir]
|
||||
|
||||
compile all proto files in the folder recursively, including sub folders:
|
||||
powerproto build -r [dir]
|
||||
|
||||
compile proto files and execute the post actions/shells:
|
||||
powerproto build -r -a [dir]
|
||||
`
|
||||
|
||||
// compile proto files
|
||||
// powerproto build -r .
|
||||
// powerproto build .
|
||||
// powerproto build xxxxx.proto
|
||||
func CommandBuild(log logger.Logger) *cobra.Command {
|
||||
var recursive bool
|
||||
// todo: this feature is still under development
|
||||
var dryRun bool
|
||||
var postScriptEnabled bool
|
||||
cmd := &cobra.Command{
|
||||
Use: "build [dir|proto file]",
|
||||
Short: "compile proto files",
|
||||
Long: strings.TrimSpace(description),
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ctx := cmd.Context()
|
||||
if dryRun {
|
||||
ctx = command.WithDryRun(ctx)
|
||||
}
|
||||
if !postScriptEnabled {
|
||||
ctx = command.WithDisableAction(ctx)
|
||||
}
|
||||
|
||||
target, err := filepath.Abs(args[0])
|
||||
if err != nil {
|
||||
log.LogFatal(nil, "failed to abs target path: %s", err)
|
||||
}
|
||||
fileInfo, err := os.Stat(target)
|
||||
if err != nil {
|
||||
log.LogFatal(map[string]interface{}{
|
||||
"target": target,
|
||||
}, "failed to stat target: %s", err)
|
||||
}
|
||||
|
||||
var targets []string
|
||||
if fileInfo.IsDir() {
|
||||
log.LogInfo(nil, "search proto files...")
|
||||
if recursive {
|
||||
targets, err = util.GetFilesWithExtRecursively(target, ".proto")
|
||||
if err != nil {
|
||||
log.LogFatal(nil, "failed to walk directory: %s", err)
|
||||
}
|
||||
} else {
|
||||
targets, err = util.GetFilesWithExt(target, ".proto")
|
||||
if err != nil {
|
||||
log.LogFatal(nil, "failed to walk directory: %s", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
targets = append(targets, target)
|
||||
}
|
||||
|
||||
if len(targets) == 0 {
|
||||
log.LogWarn(nil, "no file to compile")
|
||||
return
|
||||
}
|
||||
if err := bootstraps.StepTidyConfig(ctx, targets); err != nil {
|
||||
log.LogFatal(nil, "failed to tidy config: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := bootstraps.Compile(ctx, targets); err != nil {
|
||||
log.LogFatal(nil, "failed to compile: %+v", err)
|
||||
}
|
||||
|
||||
log.LogInfo(nil, "succeed! you are ready to go :)")
|
||||
},
|
||||
}
|
||||
flags := cmd.PersistentFlags()
|
||||
flags.BoolVarP(&recursive, "recursive", "r", recursive, "whether to recursively traverse all child folders")
|
||||
flags.BoolVarP(&postScriptEnabled, "postScriptEnabled", "p", postScriptEnabled, "when this flag is attached, it will allow the execution of postActions and postShell")
|
||||
return cmd
|
||||
}
|
||||
57
cmd/powerproto/subcommands/env/command.go
vendored
Normal file
57
cmd/powerproto/subcommands/env/command.go
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package env
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/consts"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// Print environment variables related to program operation
|
||||
func CommandEnv(log logger.Logger) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "env",
|
||||
Short: "list the environments and binary files",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
log.LogInfo(nil, "[ENVIRONMENT]")
|
||||
for _, key := range []string{
|
||||
consts.EnvHomeDir,
|
||||
"HTTP_PROXY",
|
||||
"HTTPS_PROXY",
|
||||
"GOPROXY",
|
||||
} {
|
||||
log.LogInfo(nil, "%s=%s", key, os.Getenv(key))
|
||||
}
|
||||
|
||||
log.LogInfo(nil, "[BIN]")
|
||||
for _, key := range []string {
|
||||
"go",
|
||||
"git",
|
||||
} {
|
||||
path, err := exec.LookPath(key)
|
||||
if err != nil {
|
||||
log.LogError(nil, "failed to find: %s", key)
|
||||
continue
|
||||
}
|
||||
log.LogInfo(nil, "%s=%s", key, path)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
114
cmd/powerproto/subcommands/init/command.go
Normal file
114
cmd/powerproto/subcommands/init/command.go
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/configs"
|
||||
"github.com/storyicon/powerproto/pkg/consts"
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// UserPreference defines the model of user preference
|
||||
type UserPreference struct {
|
||||
Plugins []string `survey:"plugins"`
|
||||
}
|
||||
|
||||
// GetUserPreference is used to get user preference
|
||||
func GetUserPreference() (*UserPreference, error) {
|
||||
var preference UserPreference
|
||||
err := survey.Ask([]*survey.Question{
|
||||
{
|
||||
Name: "plugins",
|
||||
Prompt: &survey.MultiSelect{
|
||||
Message: "select plugins to use. Later, you can also manually add in the configuration file",
|
||||
Options: GetWellKnownPluginsOptionValues(),
|
||||
},
|
||||
},
|
||||
}, &preference)
|
||||
return &preference, err
|
||||
}
|
||||
|
||||
// GetDefaultConfig is used to get default config
|
||||
func GetDefaultConfig() *configs.Config {
|
||||
return &configs.Config{
|
||||
Scopes: []string{
|
||||
"./",
|
||||
},
|
||||
Protoc: "latest",
|
||||
Plugins: map[string]string{
|
||||
"protoc-gen-go": "google.golang.org/protobuf/cmd/protoc-gen-go@latest",
|
||||
"protoc-gen-go-grpc": "google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest",
|
||||
},
|
||||
Options: []string{
|
||||
"--go_out=.",
|
||||
"--go_opt=paths=source_relative",
|
||||
"--go-grpc_out=.",
|
||||
"--go-grpc_opt=paths=source_relative",
|
||||
},
|
||||
ImportPaths: []string{
|
||||
".",
|
||||
"$GOPATH",
|
||||
"$POWERPROTO_INCLUDE",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CommandInit is used to initialize the configuration
|
||||
// file in the current directory
|
||||
func CommandInit(log logger.Logger) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "init a config file in current directory",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
exists, err := util.IsFileExists(consts.ConfigFileName)
|
||||
if err != nil {
|
||||
log.LogError(nil, err.Error())
|
||||
return
|
||||
}
|
||||
if exists {
|
||||
log.LogInfo(nil, "config file already exists in this directory")
|
||||
return
|
||||
}
|
||||
|
||||
preference, err := GetUserPreference()
|
||||
if err != nil {
|
||||
log.LogError(nil, err.Error())
|
||||
return
|
||||
}
|
||||
config := GetDefaultConfig()
|
||||
if len(preference.Plugins) != 0 {
|
||||
var compileOptions []string
|
||||
plugins := map[string]string{}
|
||||
for _, val := range preference.Plugins {
|
||||
plugin, ok := GetPluginFromOptionsValue(val)
|
||||
if ok {
|
||||
plugins[plugin.Name] = plugin.Pkg
|
||||
compileOptions = append(compileOptions, plugin.Options...)
|
||||
}
|
||||
}
|
||||
config.Plugins = plugins
|
||||
config.Options = compileOptions
|
||||
}
|
||||
if err := configs.SaveConfigs(consts.ConfigFileName, config); err != nil {
|
||||
log.LogFatal(nil, "failed to save config: %s", err)
|
||||
}
|
||||
log.LogInfo(nil, "succeed! You can use `powerproto tidy` to tidy this config file")
|
||||
},
|
||||
}
|
||||
}
|
||||
95
cmd/powerproto/subcommands/init/plugins.go
Normal file
95
cmd/powerproto/subcommands/init/plugins.go
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Plugin defines the plugin options
|
||||
type Plugin struct {
|
||||
Name string
|
||||
Pkg string
|
||||
Options []string
|
||||
}
|
||||
|
||||
// String implements the standard string interface
|
||||
func (options *Plugin) String() string {
|
||||
return fmt.Sprintf("%s: %s", options.Name, options.Pkg)
|
||||
}
|
||||
|
||||
// GetWellKnownPlugins is used to get well known plugins
|
||||
func GetWellKnownPlugins() []*Plugin {
|
||||
return []*Plugin{
|
||||
{
|
||||
Name: "protoc-gen-go",
|
||||
Pkg: "google.golang.org/protobuf/cmd/protoc-gen-go@latest",
|
||||
Options: []string{
|
||||
"--go_out=.",
|
||||
"--go_opt=paths=source_relative",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "protoc-gen-go-grpc",
|
||||
Pkg: "google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest",
|
||||
Options: []string{
|
||||
"--go-grpc_out=.",
|
||||
"--go-grpc_opt=paths=source_relative",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "protoc-gen-grpc-gateway",
|
||||
Pkg: "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest",
|
||||
Options: []string{
|
||||
"--grpc-gateway_out=.",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "protoc-gen-deepcopy",
|
||||
Pkg: "istio.io/tools/cmd/protoc-gen-deepcopy@latest",
|
||||
Options: []string{
|
||||
"--deepcopy_out=source_relative:.",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "protoc-gen-go-json",
|
||||
Pkg: "github.com/mitchellh/protoc-gen-go-json@latest",
|
||||
Options: []string{
|
||||
"--go-json_out=.",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetPluginFromOptionsValue is used to get plugin by option value
|
||||
func GetPluginFromOptionsValue(val string) (*Plugin, bool) {
|
||||
plugins := GetWellKnownPlugins()
|
||||
for _, plugin := range plugins {
|
||||
if plugin.String() == val {
|
||||
return plugin, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// GetWellKnownPluginsOptionValues is used to get option values of well known plugins
|
||||
func GetWellKnownPluginsOptionValues() []string {
|
||||
plugins := GetWellKnownPlugins()
|
||||
packages := make([]string, 0, len(plugins))
|
||||
for _, plugin := range plugins {
|
||||
packages = append(packages, plugin.String())
|
||||
}
|
||||
return packages
|
||||
}
|
||||
108
cmd/powerproto/subcommands/tidy/command.go
Normal file
108
cmd/powerproto/subcommands/tidy/command.go
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tidy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/bootstraps"
|
||||
"github.com/storyicon/powerproto/pkg/component/pluginmanager"
|
||||
"github.com/storyicon/powerproto/pkg/configs"
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
"github.com/storyicon/powerproto/pkg/util/progressbar"
|
||||
)
|
||||
|
||||
func tidy(ctx context.Context,
|
||||
pluginManager pluginmanager.PluginManager,
|
||||
configFilePath string) error {
|
||||
progress := progressbar.GetProgressBar(1)
|
||||
progress.SetPrefix("tidy config")
|
||||
err := bootstraps.StepTidyConfigFile(ctx, pluginManager, progress, configFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
progress.Incr()
|
||||
progress.Wait()
|
||||
configItems, err := configs.LoadConfigItems(configFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := bootstraps.StepInstallProtoc(ctx, pluginManager, configItems); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := bootstraps.StepInstallPlugins(ctx, pluginManager, configItems); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// By default, clean the powerproto.yaml of the current directory and all parent directories
|
||||
// You can also explicitly specify the configuration file to clean up
|
||||
func CommandTidy(log logger.Logger) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "tidy [config file]",
|
||||
Short: "tidy the config file. It will replace the version number and install the protoc and proto plugins that declared in the config file",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var targets []string
|
||||
if len(args) != 0 {
|
||||
for _, arg := range args {
|
||||
dir, _ := filepath.Abs(arg)
|
||||
targets = append(targets, dir)
|
||||
}
|
||||
} else {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.LogFatal(nil, "failed to get current dir: %s", err)
|
||||
}
|
||||
targets = configs.ListConfigPaths(dir)
|
||||
}
|
||||
pluginManager, err := pluginmanager.NewPluginManager(pluginmanager.NewConfig(), log)
|
||||
if err != nil {
|
||||
log.LogFatal(nil, "failed to create plugin manager: %s", err)
|
||||
}
|
||||
configMap := map[string]struct{}{}
|
||||
for _, path := range targets {
|
||||
exists, err := util.IsFileExists(path)
|
||||
if err != nil {
|
||||
log.LogFatal(map[string]interface{}{
|
||||
"path": path,
|
||||
"err": err,
|
||||
}, "failed to tidy config")
|
||||
}
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
log.LogInfo(nil, "tidy %s", path)
|
||||
if err := tidy(cmd.Context(), pluginManager, path); err != nil {
|
||||
log.LogFatal(map[string]interface{}{
|
||||
"path": path,
|
||||
"err": err,
|
||||
}, "failed to tidy config")
|
||||
}
|
||||
configMap[path] = struct{}{}
|
||||
}
|
||||
log.LogInfo(nil, "these following config files were tidied:")
|
||||
for path := range configMap {
|
||||
log.LogInfo(nil, " %s", path)
|
||||
}
|
||||
log.LogInfo(nil, "\r\nsucceeded, you are ready to go :)")
|
||||
},
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue