Compare commits

...

4 Commits

Author SHA1 Message Date
oscar 9c56ec0d85 utils: refactor PrintMenu with tasker array 2022-09-21 17:43:56 +12:00
oscar a115970e7e utils: remove the config.go file 2022-09-21 17:43:21 +12:00
oscar 8463725b9c task: add tasks skeleton 2022-09-21 17:42:47 +12:00
oscar 2ab17147fb config: initialize and read config file 2022-09-21 17:00:10 +12:00
9 changed files with 258 additions and 63 deletions

View File

@ -0,0 +1,147 @@
package configs
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
)
const (
ConfigFileName string = ".devtool"
)
var (
ErrConfigNotInitialized error = errors.New("Config file is not initialized")
)
type Config struct {
// ProjectPath is where all git repositories will be downloaded to
ProjectPath string
// VolumePath is where all the persisitant data will be saved to
VolumePath string
//
LoginCredential LoginCredential
//
RepositoryConfig map[string]RepositoryConfig
}
// LoginCredential stores the user credential for API request
type LoginCredential struct {
Username string
Password string
Address string
}
type RepositoryConfig struct {
Name string
URL string
Directory string
Private bool
GitUsername string
GitPassword string
}
func GetConfig() (*Config, error) {
file, err := getConfigFile(ConfigFileName)
if err != nil {
if err == ErrConfigNotInitialized {
config, err := initializeConfig(file)
if err != nil {
return config, err
}
}
}
return getConfig(file)
}
func initializeConfig(w io.WriteCloser) (*Config, error) {
config := &Config{}
fmt.Printf("Set the project path: ")
fmt.Scanf("%s", &(config.ProjectPath))
fmt.Printf("Set the volume path: ")
fmt.Scanf("%s", &(config.VolumePath))
var loginCredential LoginCredential
fmt.Printf("Set login credential username(admin): ")
fmt.Scanf("%s", &(loginCredential.Username))
if loginCredential.Username == "" {
loginCredential.Username = "admin"
}
for {
fmt.Printf("Set login credential password(******): ")
fmt.Scanf("%s", &(loginCredential.Password))
if loginCredential.Password != "" {
break
}
fmt.Println("Login credential password must be provided")
}
fmt.Printf("Set login address(127.0.0.1): ")
fmt.Scanf("%s", &(loginCredential.Address))
if loginCredential.Address == "" {
loginCredential.Address = "http://127.0.0.1:9000/api/auth"
} else {
loginCredential.Address = fmt.Sprintf("http://%s:9000/api/auth", loginCredential.Address)
}
config.LoginCredential = loginCredential
// able to configure multiple project
// if utils.PromptConfirm("Do you want to configure the repository now?") {
// // configure repository
// }
bytes, err := json.Marshal(config)
if err != nil {
return nil, err
}
_, err = w.Write(bytes)
if err != nil {
return nil, err
}
return config, nil
}
func getConfig(f io.Reader) (*Config, error) {
config := &Config{}
bytes := make([]byte, 0)
_, err := f.Read(bytes)
if err != nil {
return nil, err
}
err = json.Unmarshal(bytes, &config)
if err != nil {
return nil, err
}
return config, nil
}
// getConfigFile get the config file handler
func getConfigFile(name string) (*os.File, error) {
_, err := os.Stat(name)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
//create file
file, err := os.Create(name)
if err != nil {
return nil, fmt.Errorf("fail to create config file: %w", err)
}
// first set up the git project path and volume path
// git credential
return file, err
} else {
return nil, err
}
}
return os.OpenFile(name, os.O_RDWR, 0644)
}

View File

@ -2,52 +2,40 @@ package main
import ( import (
"log" "log"
"ocl/portainer-devtool/repositories" "ocl/portainer-devtool/configs"
"ocl/portainer-devtool/tasks"
"ocl/portainer-devtool/utils" "ocl/portainer-devtool/utils"
"os"
)
const (
MENU_OPTION_EE_REPO int = iota + 1
MENU_OPTION_CE_REPO
MENU_OPTION_AGENT_REPO
MENU_OPTION_OTHERS
MENU_OPTION_QUIT
) )
func main() { func main() {
for { config, err := configs.GetConfig()
printMainMenu := func() {
utils.MenuPrint("Which repository or action do you want to operate:", `
1. Portainer EE Repository
2. Portainer CE Repository
3. Portainer Agent Repository
4. Others
5. Quit`)
}
option := utils.PromptMenu(printMainMenu)
var action repositories.Actioner
switch option {
case MENU_OPTION_EE_REPO:
action = repositories.NewPortainerEERepository()
case MENU_OPTION_CE_REPO:
case MENU_OPTION_AGENT_REPO:
case MENU_OPTION_OTHERS:
case MENU_OPTION_QUIT:
os.Exit(0)
}
err := action.Execute()
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
// Init tasks
taskItems := []tasks.Tasker{
tasks.NewGenerateJwtTokenTask(config),
}
for {
printMainMenu := func() {
utils.PrintMenu("Which repository of action do you want operate:", taskItems)
// utils.MenuPrint("Which repository or action do you want to operate:", `
// 1. Portainer EE Repository
// 2. Portainer CE Repository
// 3. Portainer Agent Repository
// 4. Others
// 5. Quit`)
}
utils.PromptMenu(printMainMenu)
} }
} }

View File

@ -0,0 +1,16 @@
package tasks
import "ocl/portainer-devtool/configs"
type BuildAllTask struct {
Config *configs.Config
}
func (task *BuildAllTask) Execute() error {
return nil
}
func (task *BuildAllTask) String() string {
return "Build all"
}

View File

@ -0,0 +1,15 @@
package tasks
import "ocl/portainer-devtool/configs"
type BuildBackendOnlyTask struct {
Config *configs.Config
}
func (task *BuildBackendOnlyTask) Execute() error {
return nil
}
func (task *BuildBackendOnlyTask) String() string {
return "Build backend only"
}

View File

@ -0,0 +1,21 @@
package tasks
import "ocl/portainer-devtool/configs"
type GenerateJwtTokenTask struct {
Config *configs.Config
}
func NewGenerateJwtTokenTask(cfg *configs.Config) *GenerateJwtTokenTask {
return &GenerateJwtTokenTask{
Config: cfg,
}
}
func (task *GenerateJwtTokenTask) Execute() error {
return nil
}
func (task *GenerateJwtTokenTask) String() string {
return "Generate JWT token"
}

View File

@ -0,0 +1,6 @@
package tasks
type Tasker interface {
Execute() error
String() string
}

View File

@ -1,24 +0,0 @@
package utils
import (
"errors"
"fmt"
"os"
)
func GetConfigFile(name string) (*os.File, error) {
_, err := os.Stat(name)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
//create file
file, err := os.Create(name)
if err != nil {
return nil, fmt.Errorf("fail to create config file: %w", err)
}
return file, err
} else {
return nil, err
}
}
return os.OpenFile(name, os.O_RDWR, 0644)
}

View File

@ -1,6 +1,9 @@
package utils package utils
import "fmt" import (
"fmt"
"ocl/portainer-devtool/tasks"
)
const ( const (
colorReset string = "\033[0m" colorReset string = "\033[0m"
@ -41,6 +44,20 @@ func InputPrint(message string) {
fmt.Println(colorYellow, message, colorReset) fmt.Println(colorYellow, message, colorReset)
} }
func PrintMenu(question string, tasks []tasks.Tasker) {
if question != "" {
InputPrint(fmt.Sprintf("[%s]", question))
}
menuContent := ""
for i, task := range tasks {
menuContent += fmt.Sprintf("%d. %s\n", i+1, task.String())
}
fmt.Println(colorCyan, menuContent, colorReset)
}
func MenuPrint(question, menu string) { func MenuPrint(question, menu string) {
if question != "" { if question != "" {
InputPrint(fmt.Sprintf("[%s]", question)) InputPrint(fmt.Sprintf("[%s]", question))

View File

@ -14,11 +14,20 @@ func PromptContinue() bool {
return false return false
} }
func PromptMenu(listMenu func()) int { func PromptConfirm(question string) bool {
ret := fmt.Sprintf("%s (y/n)?", question)
if ret == "y" || ret == "yes" {
return true
}
return false
}
func PromptMenu(listMenu func()) string {
listMenu() listMenu()
var option int var option string
fmt.Scanf("%d", &option) fmt.Scanf("%s", &option)
return option return option
} }