diff --git a/cmd/root.go b/cmd/root.go
index ceb4b5d..86e5d0d 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -1,26 +1,111 @@
package cmd
import (
- "fmt"
- "github.com/spf13/cobra"
+ "fmt"
+ "os"
+ "path/filepath"
+ "stackroost/config"
+ "stackroost/internal"
+ "github.com/spf13/cobra"
)
// rootCmd is the base command
var rootCmd = &cobra.Command{
- Use: "stackrooy",
- Short: "StackRooy CLI - manage your Linux servers with ease",
- Run: func(cmd *cobra.Command, args []string) {
- printWelcome()
- },
+ Use: "stackroost",
+ Short: "StackRoost CLI - manage your Linux servers with ease",
+ Run: func(cmd *cobra.Command, args []string) {
+ printWelcome()
+ },
+}
+
+// createDomainCmd is the command to create a web server configuration
+var createDomainCmd = &cobra.Command{
+ Use: "create-domain",
+ Short: "Create a web server configuration for a domain",
+ Run: func(cmd *cobra.Command, args []string) {
+ domain, _ := cmd.Flags().GetString("name")
+ port, _ := cmd.Flags().GetString("port")
+ serverType, _ := cmd.Flags().GetString("server")
+
+ if internal.IsNilOrEmpty(domain) {
+ fmt.Println("Error: --name flag is required and cannot be empty")
+ os.Exit(1)
+ }
+ if internal.IsNilOrEmpty(port) {
+ port = "80" // Default port
+ }
+
+ // Create web server configuration generator
+ configGen, err := config.NewWebServerConfig(serverType)
+ if err != nil {
+ fmt.Printf("Error: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Generate configuration
+ configContent, err := configGen.Generate(domain, port)
+ if err != nil {
+ fmt.Printf("Error generating config: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Write configuration to file
+ if err := writeConfigFile(domain, configContent, configGen.GetFileExtension()); err != nil {
+ fmt.Printf("Error writing config file: %v\n", err)
+ os.Exit(1)
+ }
+
+ filename := fmt.Sprintf("%s%s", domain, configGen.GetFileExtension())
+
+ // Enable site using a2ensite
+ if err := internal.RunCommand("sudo", "a2ensite", filename); err != nil {
+ fmt.Printf("Failed to enable site: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Reload apache to apply changes
+ if err := internal.RunCommand("sudo", "systemctl", "reload", "apache2"); err != nil {
+ fmt.Printf("Failed to reload apache: %v\n", err)
+ os.Exit(1)
+ }
+
+ fmt.Printf("%s configuration created and enabled for %s on port %s\n", serverType, domain, port)
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(createDomainCmd)
+ createDomainCmd.Flags().StringP("name", "n", "", "Domain name for the configuration (e.g., mahesh.spark.dev)")
+ createDomainCmd.Flags().StringP("port", "p", "80", "Port for the configuration (default: 80)")
+ createDomainCmd.Flags().StringP("server", "s", "apache", "Web server type (e.g., apache, nginx, caddy)")
+ createDomainCmd.MarkFlagRequired("name")
}
func Execute() {
- if err := rootCmd.Execute(); err != nil {
- fmt.Println("Error:", err)
- }
+ if err := rootCmd.Execute(); err != nil {
+ fmt.Println("Error:", err)
+ os.Exit(1)
+ }
}
func printWelcome() {
- fmt.Println("Welcome to StackRoot CLI!")
- fmt.Println("Your terminal assistant for managing Linux servers.")
+ fmt.Println("Welcome to StackRoost CLI!")
+ fmt.Println("Your terminal assistant for managing Linux servers.")
+}
+
+// writeConfigFile writes the configuration to a file
+func writeConfigFile(domain, content, extension string) error {
+ outputDir := "/etc/apache2/sites-available"
+ if err := os.MkdirAll(outputDir, 0755); err != nil {
+ return fmt.Errorf("failed to create output directory: %v", err)
+ }
+
+ filename := fmt.Sprintf("%s%s", domain, extension)
+ outputPath := filepath.Join(outputDir, filename)
+
+ if err := os.WriteFile(outputPath, []byte(content), 0644); err != nil {
+ return fmt.Errorf("failed to write config file: %v", err)
+ }
+
+ return nil
}
diff --git a/config/apache/apache.go b/config/apache/apache.go
new file mode 100644
index 0000000..69e9d4f
--- /dev/null
+++ b/config/apache/apache.go
@@ -0,0 +1,30 @@
+package apache
+
+import "fmt"
+
+// ApacheConfig implements the WebServerConfig interface for Apache
+type ApacheConfig struct{}
+
+// Generate creates an Apache virtual host configuration
+func (a *ApacheConfig) Generate(domain, port string) (string, error) {
+ vhostTemplate := `
+ ServerName %s
+ ServerAlias www.%s
+ DocumentRoot /var/www/%s
+ ErrorLog ${APACHE_LOG_DIR}/%s-error.log
+ CustomLog ${APACHE_LOG_DIR}/%s-access.log combined
+
+ Options Indexes FollowSymLinks
+ AllowOverride All
+ Require all granted
+
+`
+
+ config := fmt.Sprintf(vhostTemplate, port, domain, domain, domain, domain, domain, domain)
+ return config, nil
+}
+
+// GetFileExtension returns the file extension for Apache config files
+func (a *ApacheConfig) GetFileExtension() string {
+ return ".conf"
+}
\ No newline at end of file
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000..f819735
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,22 @@
+package config
+
+import (
+ "fmt"
+ "stackroost/config/apache"
+)
+
+// WebServerConfig defines the interface for generating web server configurations
+type WebServerConfig interface {
+ Generate(domain, port string) (string, error)
+ GetFileExtension() string
+}
+
+// NewWebServerConfig creates a new configuration generator based on the server type
+func NewWebServerConfig(serverType string) (WebServerConfig, error) {
+ switch serverType {
+ case "apache":
+ return &apache.ApacheConfig{}, nil
+ default:
+ return nil, fmt.Errorf("unsupported web server type: %s", serverType)
+ }
+}
\ No newline at end of file
diff --git a/internal/utils.go b/internal/utils.go
index 5de376f..bfcf731 100644
--- a/internal/utils.go
+++ b/internal/utils.go
@@ -1,5 +1,22 @@
package internal
+import (
+ "fmt"
+ "os/exec"
+)
+
+// RunCommand runs a shell command with args and returns error if any
+func RunCommand(name string, args ...string) error {
+ cmd := exec.Command(name, args...)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("command %s %v failed: %w", name, args, err)
+ }
+ return nil
+}
+
+// IsNilOrEmpty returns true if the string is empty or ""
func IsNilOrEmpty(s string) bool {
- return s == "" || s == ""
-}
\ No newline at end of file
+ return s == "" || s == ""
+}