First commit of golang CLI.
This commit is contained in:
180
wild-cli/cmd/wild/app/add.go
Normal file
180
wild-cli/cmd/wild/app/add.go
Normal file
@@ -0,0 +1,180 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/wild-cloud/wild-cli/internal/apps"
|
||||
"github.com/wild-cloud/wild-cli/internal/config"
|
||||
"github.com/wild-cloud/wild-cli/internal/environment"
|
||||
"github.com/wild-cloud/wild-cli/internal/output"
|
||||
)
|
||||
|
||||
func newAddCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "add <name>",
|
||||
Short: "Add an application to the project",
|
||||
Long: `Add an application to the project with configuration.
|
||||
|
||||
This copies the cached application template to your project's apps/
|
||||
directory and creates initial configuration.
|
||||
|
||||
Examples:
|
||||
wild app add nextcloud
|
||||
wild app add postgresql`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runAdd,
|
||||
}
|
||||
}
|
||||
|
||||
func runAdd(cmd *cobra.Command, args []string) error {
|
||||
appName := args[0]
|
||||
|
||||
output.Header("Adding Application")
|
||||
output.Info("App: " + appName)
|
||||
|
||||
// Initialize environment
|
||||
env := environment.New()
|
||||
if err := env.RequiresProject(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create catalog
|
||||
catalog := apps.NewCatalog(env.CacheDir())
|
||||
|
||||
// Check if app is cached
|
||||
if !catalog.IsAppCached(appName) {
|
||||
output.Warning("App '" + appName + "' is not cached locally")
|
||||
output.Info("Run 'wild app fetch " + appName + "' first")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if app already exists in project
|
||||
appDir := filepath.Join(env.AppsDir(), appName)
|
||||
if _, err := os.Stat(appDir); err == nil {
|
||||
output.Warning("App '" + appName + "' already exists in project")
|
||||
output.Info("App directory: " + appDir)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get app info
|
||||
app, err := catalog.FindApp(appName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting app info: %w", err)
|
||||
}
|
||||
|
||||
output.Info("Description: " + app.Description)
|
||||
output.Info("Version: " + app.Version)
|
||||
|
||||
// Check dependencies
|
||||
if len(app.Requires) > 0 {
|
||||
output.Info("Dependencies: " + fmt.Sprintf("%v", app.Requires))
|
||||
|
||||
// Check if dependencies are available
|
||||
for _, dep := range app.Requires {
|
||||
depDir := filepath.Join(env.AppsDir(), dep)
|
||||
if _, err := os.Stat(depDir); os.IsNotExist(err) {
|
||||
output.Warning("Dependency '" + dep + "' not found in project")
|
||||
output.Info("Consider adding it first: wild app add " + dep)
|
||||
} else {
|
||||
output.Success("Dependency '" + dep + "' found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy app template from cache to project
|
||||
cacheDir := filepath.Join(env.CacheDir(), "apps", appName)
|
||||
if err := copyDir(cacheDir, appDir); err != nil {
|
||||
return fmt.Errorf("copying app template: %w", err)
|
||||
}
|
||||
|
||||
// Create initial configuration in config.yaml
|
||||
if err := addAppConfig(env, appName, app); err != nil {
|
||||
output.Warning("Failed to add app configuration: " + err.Error())
|
||||
} else {
|
||||
output.Success("Added default configuration to config.yaml")
|
||||
}
|
||||
|
||||
output.Success("App '" + appName + "' added to project")
|
||||
output.Info("")
|
||||
output.Info("App directory: " + appDir)
|
||||
output.Info("Next steps:")
|
||||
output.Info(" wild config set apps." + appName + ".enabled true")
|
||||
output.Info(" wild app deploy " + appName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyDir recursively copies a directory
|
||||
func copyDir(src, dst string) error {
|
||||
entries, err := os.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(dst, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
srcPath := filepath.Join(src, entry.Name())
|
||||
dstPath := filepath.Join(dst, entry.Name())
|
||||
|
||||
if entry.IsDir() {
|
||||
if err := copyDir(srcPath, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := copyFile(srcPath, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyFile copies a single file
|
||||
func copyFile(src, dst string) error {
|
||||
data, err := os.ReadFile(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(dst, data, 0644)
|
||||
}
|
||||
|
||||
// addAppConfig adds default app configuration to config.yaml
|
||||
func addAppConfig(env *environment.Environment, appName string, app *apps.App) error {
|
||||
mgr := config.NewManager(env.ConfigPath(), env.SecretsPath())
|
||||
|
||||
// Create default app configuration
|
||||
appConfig := map[string]interface{}{
|
||||
"enabled": false,
|
||||
"image": appName + ":latest",
|
||||
}
|
||||
|
||||
// Add any default config from the app manifest
|
||||
if app.Config != nil {
|
||||
for key, value := range app.Config {
|
||||
appConfig[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to YAML and set in config
|
||||
configData, err := yaml.Marshal(appConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshaling config: %w", err)
|
||||
}
|
||||
|
||||
configPath := "apps." + appName
|
||||
if err := mgr.Set(configPath, string(configData)); err != nil {
|
||||
return fmt.Errorf("setting config: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user