diff --git a/cmd/main.go b/cmd/main.go index 66081b9..ef7396c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -16,17 +16,34 @@ package main import ( _ "time/tzdata" + "github.com/spf13/cobra" + + "github.com/opentreehole/backend/cmd/migrate" "github.com/opentreehole/backend/cmd/wire" _ "github.com/opentreehole/backend/internal/docs" ) +var rootCmd = &cobra.Command{ + Use: "opentreehole_backend", + Run: func(cmd *cobra.Command, args []string) { + server, cleanup, err := wire.NewApp() + if err != nil { + panic(err) + } + + defer cleanup() + server.Run() + }, +} + +func init() { + rootCmd.AddCommand(migrate.Cmd) +} + //go:generate wire gen ./wire func main() { - server, cleanup, err := wire.NewApp() + err := rootCmd.Execute() if err != nil { panic(err) } - - defer cleanup() - server.Run() } diff --git a/cmd/migrate_danke_v3/main.go b/cmd/migrate/danke_v3.go similarity index 95% rename from cmd/migrate_danke_v3/main.go rename to cmd/migrate/danke_v3.go index d53f9b5..5dec2cb 100644 --- a/cmd/migrate_danke_v3/main.go +++ b/cmd/migrate/danke_v3.go @@ -1,7 +1,4 @@ -//! 迁移旧版本蛋壳到新版本 -//! `review`.`history` -> `review_history` - -package main +package migrate import ( "time" @@ -52,7 +49,7 @@ type ReviewOld struct { Downvoters []int `json:"downvoters" gorm:"serializer:json"` } -func main() { +func DankeV3() { conf := config.NewConfig() logger, cancel := log.NewLogger(conf) defer cancel() @@ -62,8 +59,10 @@ func main() { reviews []*ReviewOld err error ) + logger.Info("migrate danke v3") err = db.Transaction(func(tx *gorm.DB) error { + logger.Info("migrate danke v3: get reviews") err = db.Table("review").FindInBatches(&reviews, 1000, func(tx *gorm.DB, batch int) error { // update History var ( @@ -138,14 +137,14 @@ func main() { } // update course.review_count - err = db.Exec(`update course set review_count = (select count(*) from review where review.course_id = course.id) where true`).Error + err = tx.Exec(`update course set review_count = (select count(*) from review where review.course_id = course.id) where true`).Error if err != nil { return err } // update review.upvote_count and review.downvote_count // extract review.rank_* from review.rank - err = db.Exec(`update review + err = tx.Exec(`update review set upvote_count = (select count(*) from review_vote where review_vote.review_id = review.id and review_vote.data = 1), downvote_count = (select count(*) from review_vote where review_vote.review_id = review.id and review_vote.data = -1), rank_overall = JSON_EXTRACT(review.rank, '$.overall'), diff --git a/cmd/migrate/main.go b/cmd/migrate/main.go new file mode 100644 index 0000000..d62e4a3 --- /dev/null +++ b/cmd/migrate/main.go @@ -0,0 +1,27 @@ +//! 迁移旧版本蛋壳到新版本 +//! `review`.`history` -> `review_history` + +package migrate + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +var Cmd = &cobra.Command{ + Use: "migrate", + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return fmt.Errorf("no migration specified") + } + + switch args[0] { + case "danke_v3": + DankeV3() + default: + return fmt.Errorf("unknown migration %s", args[0]) + } + return nil + }, +} diff --git a/data/data.go b/data/data.go index ee88dcc..275336b 100644 --- a/data/data.go +++ b/data/data.go @@ -6,7 +6,6 @@ import ( "os" "github.com/goccy/go-json" - "github.com/rs/zerolog/log" ) //go:embed names.json @@ -23,13 +22,11 @@ var NamesMapping map[string]string func init() { NamesMappingData, err := os.ReadFile(`data/names_mapping.json`) if err != nil { - log.Err(err).Msg("could not load names_mapping.json") return } err = json.Unmarshal(NamesMappingData, &NamesMapping) if err != nil { - log.Err(err).Msg("could not unmarshal names_mapping.json") return } } diff --git a/go.mod b/go.mod index b58e435..f93c49a 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/jinzhu/copier v0.4.0 github.com/redis/go-redis/v9 v9.2.0 github.com/rs/zerolog v1.30.0 + github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.4 github.com/swaggo/swag v1.16.2 @@ -54,6 +55,7 @@ require ( github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/uuid v1.3.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgx/v5 v5.3.1 // indirect diff --git a/go.sum b/go.sum index b8b7380..519e400 100644 --- a/go.sum +++ b/go.sum @@ -68,6 +68,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA= github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= @@ -206,6 +207,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hetiansu5/urlquery v1.2.7 h1:jn0h+9pIRqUziSPnRdK/gJK8S5TCnk+HZZx5fRHf8K0= github.com/hetiansu5/urlquery v1.2.7/go.mod h1:wFpZdTHRdwt7mk0EM/DdZEWtEN4xf8HJoH/BLXm/PG0= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= @@ -318,10 +321,13 @@ github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/internal/config/config.go b/internal/config/config.go index c34b170..1c783c1 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -15,31 +15,31 @@ import ( ) type EnvConfig struct { - Mode string `env:"MODE" default:"dev" validate:"oneof=dev production test bench"` + Mode string `env:"MODE"` - LogLevel string `env:"LOG_LEVEL" default:"debug" validate:"oneof=debug info warn error dpanic panic fatal"` + LogLevel string `env:"LOG_LEVEL" ` - Port int `env:"PORT" default:"8000"` + Port int `env:"PORT" ` - DBType string `env:"DB_TYPE" default:"sqlite" validate:"oneof=mysql sqlite postgres memory"` + DBType string `env:"DB_TYPE"` - DBDSN string `env:"DB_DSN" default:"data/sqlite.db"` + DBDSN string `env:"DB_DSN"` - CacheType string `env:"CACHE_TYPE" default:"memory" validate:"oneof=redis memory"` + CacheType string `env:"CACHE_TYPE" ` - CacheUrl string `env:"CACHE_URL" default:"redis:6379"` + CacheUrl string `env:"CACHE_URL" ` - SearchEngineType string `env:"SEARCH_ENGINE_TYPE" default:"elasticsearch" validate:"oneof=elasticsearch meilisearch"` + SearchEngineType string `env:"SEARCH_ENGINE_TYPE" ` - SearchEngineUrl string `env:"SEARCH_ENGINE_URL" default:"http://elasticsearch:9200"` + SearchEngineUrl string `env:"SEARCH_ENGINE_URL" ` - ModulesAuth bool `env:"MODULES_AUTH" default:"false"` + ModulesAuth bool `env:"MODULES_AUTH" ` - ModulesNotification bool `env:"MODULES_NOTIFICATION" default:"false"` + ModulesNotification bool `env:"MODULES_NOTIFICATION"` - ModulesTreehole bool `env:"MODULES_TREEHOLE" default:"false"` + ModulesTreehole bool `env:"MODULES_TREEHOLE"` - ModulesCurriculumBoard bool `env:"MODULES_CURRICULUM_BOARD" default:"false"` + ModulesCurriculumBoard bool `env:"MODULES_CURRICULUM_BOARD"` } type Config struct { @@ -357,17 +357,55 @@ func (config *Config) WriteIntoFile(name string) { } func CopyEnvConfigToConfig(envConfig *EnvConfig, config *Config) { - config.Mode = envConfig.Mode - config.LogLevel = envConfig.LogLevel - config.Port = envConfig.Port - config.DB.Type = envConfig.DBType - config.DB.DSN = envConfig.DBDSN - config.Cache.Type = envConfig.CacheType - config.Cache.Url = envConfig.CacheUrl - config.SearchEngine.Type = envConfig.SearchEngineType - config.SearchEngine.Url = envConfig.SearchEngineUrl - config.Modules.Auth = envConfig.ModulesAuth - config.Modules.Notification = envConfig.ModulesNotification - config.Modules.Treehole = envConfig.ModulesTreehole - config.Modules.CurriculumBoard = envConfig.ModulesCurriculumBoard + if envConfig.Mode != "" { + config.Mode = envConfig.Mode + } + + if envConfig.LogLevel != "" { + config.LogLevel = envConfig.LogLevel + } + + if envConfig.Port != 0 { + config.Port = envConfig.Port + } + + if envConfig.DBType != "" { + config.DB.Type = envConfig.DBType + } + + if envConfig.DBDSN != "" { + config.DB.DSN = envConfig.DBDSN + } + + if envConfig.CacheType != "" { + config.Cache.Type = envConfig.CacheType + } + + if envConfig.CacheUrl != "" { + config.Cache.Url = envConfig.CacheUrl + } + + if envConfig.SearchEngineType != "" { + config.SearchEngine.Type = envConfig.SearchEngineType + } + + if envConfig.SearchEngineUrl != "" { + config.SearchEngine.Url = envConfig.SearchEngineUrl + } + + if envConfig.ModulesAuth { + config.Modules.Auth = envConfig.ModulesAuth + } + + if envConfig.ModulesNotification { + config.Modules.Notification = envConfig.ModulesNotification + } + + if envConfig.ModulesTreehole { + config.Modules.Treehole = envConfig.ModulesTreehole + } + + if envConfig.ModulesCurriculumBoard { + config.Modules.CurriculumBoard = envConfig.ModulesCurriculumBoard + } }