Skip to content

Commit 9baf951

Browse files
Merge pull request #8 from stackroost/dev
enhance logger output
2 parents 7460b35 + 7e9c484 commit 9baf951

7 files changed

Lines changed: 143 additions & 64 deletions

File tree

cmd/root.go

Lines changed: 98 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/spf13/cobra"
1010
"stackroost/config"
1111
"stackroost/internal"
12+
"stackroost/internal/logger"
1213
)
1314

1415
var rootCmd = &cobra.Command{
@@ -23,6 +24,8 @@ var createDomainCmd = &cobra.Command{
2324
Use: "create-domain",
2425
Short: "Create a web server configuration for a domain",
2526
Run: func(cmd *cobra.Command, args []string) {
27+
logger.Info("Starting create-domain command execution")
28+
2629
domain, _ := cmd.Flags().GetString("name")
2730
port, _ := cmd.Flags().GetString("port")
2831
serverType, _ := cmd.Flags().GetString("server")
@@ -31,14 +34,18 @@ var createDomainCmd = &cobra.Command{
3134
createDir, _ := cmd.Flags().GetBool("useridr")
3235

3336
if internal.IsNilOrEmpty(domain) {
34-
fmt.Println("Error: --name flag is required and cannot be empty")
37+
logger.Error("Domain name is required and cannot be empty")
3538
os.Exit(1)
3639
}
40+
3741
if internal.IsNilOrEmpty(port) {
42+
logger.Info("No port specified, defaulting to 80")
3843
port = "80"
3944
}
45+
4046
username := strings.Split(domain, ".")[0]
41-
47+
logger.Debug(fmt.Sprintf("Extracted username: %s from domain: %s", username, domain))
48+
4249
ext := ".conf"
4350
var configPath string
4451

@@ -49,142 +56,138 @@ var createDomainCmd = &cobra.Command{
4956
configPath = filepath.Join("/etc/caddy/sites-available", domain+ext)
5057
case "apache":
5158
configPath = filepath.Join("/etc/apache2/sites-available", domain+ext)
52-
default:
53-
fmt.Println("Error: Unsupported server type. Supported types are: apache, nginx, caddy")
59+
default:
60+
logger.Error(fmt.Sprintf("Unsupported server type: %s. Supported types are: apache, nginx, caddy", serverType))
61+
os.Exit(1)
5462
}
5563

5664
if _, err := os.Stat(configPath); err == nil {
57-
fmt.Printf(" Configuration for '%s' already exists at %s\n", domain, configPath)
58-
fmt.Println(" Aborting to prevent overwriting existing configuration.")
65+
logger.Error(fmt.Sprintf("Configuration for '%s' already exists at %s", domain, configPath))
5966
os.Exit(1)
6067
}
6168

62-
fmt.Println(" Starting setup for domain:", domain)
69+
logger.Info(fmt.Sprintf("Initiating setup for domain: %s with server type: %s", domain, serverType))
6370

64-
// Shell user creation
6571
if shellUser {
6672
if internal.IsNilOrEmpty(password) {
67-
fmt.Println(" Error: --pass is required when --shelluser is true")
73+
logger.Error("Password is required when shelluser is enabled")
6874
os.Exit(1)
6975
}
7076

71-
fmt.Println("🔧 Creating system user:", username)
77+
logger.Info(fmt.Sprintf("Creating system user: %s", username))
7278

7379
userAddCmd := fmt.Sprintf("id -u %s || useradd -m -s /bin/bash %s", username, username)
7480
setPassCmd := fmt.Sprintf("echo '%s:%s' | chpasswd", username, password)
7581

7682
if err := internal.RunCommand("sudo", "bash", "-c", userAddCmd); err != nil {
77-
fmt.Printf(" Failed to create user: %v\n", err)
83+
logger.Error(fmt.Sprintf("Failed to create user %s: %v", username, err))
7884
os.Exit(1)
7985
}
8086

8187
if err := internal.RunCommand("sudo", "bash", "-c", setPassCmd); err != nil {
82-
fmt.Printf(" Failed to set password: %v\n", err)
88+
logger.Error(fmt.Sprintf("Failed to set password for user %s: %v", username, err))
8389
os.Exit(1)
8490
}
8591

86-
fmt.Printf(" User '%s' created with shell access\n", username)
92+
logger.Success(fmt.Sprintf("User '%s' created with shell access", username))
8793
}
8894

89-
// Create user directory
9095
if createDir {
91-
fmt.Println(" Creating public_html directory for user...")
96+
logger.Info("Creating public_html directory for user")
9297

9398
publicHtmlPath := fmt.Sprintf("/home/%s/public_html", username)
9499
if err := os.MkdirAll(publicHtmlPath, 0755); err != nil {
95-
fmt.Printf(" Failed to create directory: %v\n", err)
100+
logger.Error(fmt.Sprintf("Failed to create directory %s: %v", publicHtmlPath, err))
96101
os.Exit(1)
97102
}
98103

99104
if err := internal.RunCommand("sudo", "chown", "-R", fmt.Sprintf("%s:%s", username, username), fmt.Sprintf("/home/%s", username)); err != nil {
100-
fmt.Printf(" Failed to assign ownership: %v\n", err)
105+
logger.Error(fmt.Sprintf("Failed to assign ownership for %s: %v", username, err))
101106
os.Exit(1)
102107
}
103108

104-
fmt.Printf(" Directory '%s' created and owned by '%s'\n", publicHtmlPath, username)
109+
logger.Success(fmt.Sprintf("Directory '%s' created and owned by '%s'", publicHtmlPath, username))
105110
}
106111

107-
fmt.Println(" Generating Apache configuration...")
112+
logger.Info(fmt.Sprintf("Generating %s configuration", serverType))
108113

109114
configGen, err := config.NewWebServerConfig(serverType)
110115
if err != nil {
111-
fmt.Printf(" Error: %v\n", err)
116+
logger.Error(fmt.Sprintf("Failed to create config generator: %v", err))
112117
os.Exit(1)
113118
}
114119

115-
// Use extracted username in DocumentRoot
116120
configContent, err := configGen.Generate(domain, port, username)
117121
if err != nil {
118-
fmt.Printf(" Error generating config: %v\n", err)
122+
logger.Error(fmt.Sprintf("Failed to generate config for %s: %v", domain, err))
119123
os.Exit(1)
120124
}
121125

122126
if err := writeConfigFile(domain, configContent, configGen.GetFileExtension()); err != nil {
123-
fmt.Printf(" Error writing config file: %v\n", err)
127+
logger.Error(fmt.Sprintf("Failed to write config file: %v", err))
124128
os.Exit(1)
125129
}
126130

127-
fmt.Println(" Configuration file created.")
131+
logger.Success("Configuration file created")
128132

129133
filename := fmt.Sprintf("%s%s", domain, configGen.GetFileExtension())
130134

131135
switch serverType {
132136
case "apache":
133-
fmt.Println(" Enabling site with a2ensite...")
137+
logger.Info("Enabling site with a2ensite")
134138
if err := internal.RunCommand("sudo", "a2ensite", filename); err != nil {
135-
fmt.Printf(" Failed to enable site: %v\n", err)
139+
logger.Error(fmt.Sprintf("Failed to enable site %s: %v", filename, err))
136140
os.Exit(1)
137141
}
138142

139-
fmt.Println("Reloading Apache server...")
143+
logger.Info("Reloading Apache server")
140144
if err := internal.RunCommand("sudo", "systemctl", "reload", "apache2"); err != nil {
141-
fmt.Printf(" Failed to reload apache: %v\n", err)
145+
logger.Error(fmt.Sprintf("Failed to reload Apache: %v", err))
142146
os.Exit(1)
143147
}
144148

145149
case "nginx":
146150
sitePath := filepath.Join("/etc/nginx/sites-available", filename)
147151
linkPath := filepath.Join("/etc/nginx/sites-enabled", filename)
148-
fmt.Println(" Enabling Nginx site...")
152+
logger.Info("Enabling Nginx site")
149153
if _, err := os.Stat(linkPath); os.IsNotExist(err) {
150154
if err := internal.RunCommand("sudo", "ln", "-s", sitePath, linkPath); err != nil {
151-
fmt.Printf(" Failed to enable nginx site: %v\n", err)
155+
logger.Error(fmt.Sprintf("Failed to enable Nginx site %s: %v", filename, err))
152156
os.Exit(1)
153157
}
154158
}
155159

156-
fmt.Println("Reloading Nginx server...")
160+
logger.Info("Reloading Nginx server")
157161
if err := internal.RunCommand("sudo", "systemctl", "reload", "nginx"); err != nil {
158-
fmt.Printf(" Failed to reload nginx: %v\n", err)
162+
logger.Error(fmt.Sprintf("Failed to reload Nginx: %v", err))
159163
os.Exit(1)
160164
}
161165

162166
case "caddy":
163167
sitePath := filepath.Join("/etc/caddy/sites-available", filename)
164168
linkPath := filepath.Join("/etc/caddy/sites-enabled", filename)
165-
fmt.Println(" Enabling Caddy site...")
166-
169+
logger.Info("Enabling Caddy site")
167170
if _, err := os.Stat(linkPath); os.IsNotExist(err) {
168171
if err := internal.RunCommand("sudo", "ln", "-s", sitePath, linkPath); err != nil {
169-
fmt.Printf(" Failed to enable caddy site: %v\n", err)
172+
logger.Error(fmt.Sprintf("Failed to enable Caddy site %s: %v", filename, err))
170173
os.Exit(1)
171174
}
172175
}
173-
}
174176

175-
fmt.Println("Reloading Caddy server...")
176-
if err := internal.RunCommand("sudo", "systemctl", "reload", "caddy"); err != nil {
177-
fmt.Printf(" Failed to reload caddy: %v\n", err)
178-
os.Exit(1)
177+
logger.Info("Reloading Caddy server")
178+
if err := internal.RunCommand("sudo", "systemctl", "reload", "caddy"); err != nil {
179+
logger.Error(fmt.Sprintf("Failed to reload Caddy: %v", err))
180+
os.Exit(1)
181+
}
179182
}
180183

181-
fmt.Printf("🎉 %s configuration created and enabled for %s on port %s\n", serverType, domain, port)
184+
logger.Success(fmt.Sprintf("%s configuration created and enabled for %s on port %s", serverType, domain, port))
182185
},
183186
}
184187

185188
func init() {
186189
rootCmd.AddCommand(createDomainCmd)
187-
createDomainCmd.Flags().StringP("name", "n", "", "Domain name for the configuration (e.g., mahesh.spark.dev)")
190+
createDomainCmd.Flags().StringP("name", "n", "", "Domain name for the configuration (e.g., example.com)")
188191
createDomainCmd.Flags().Bool("shelluser", false, "Create a shell user for the domain")
189192
createDomainCmd.Flags().String("pass", "", "Password for the shell user")
190193
createDomainCmd.Flags().Bool("useridr", false, "Create user directory /home/<user>/public_html")
@@ -195,42 +198,83 @@ func init() {
195198

196199
func Execute() {
197200
if err := rootCmd.Execute(); err != nil {
201+
logger.Error(fmt.Sprintf("Command execution failed: %v", err))
198202
fmt.Println("Error:", err)
199203
os.Exit(1)
200204
}
201205
}
202206

203207
func printWelcome() {
204-
fmt.Println("Welcome to StackRoost CLI!")
205-
fmt.Println("Your terminal assistant for managing Linux servers.")
208+
reset := "\033[0m"
209+
bold := "\033[1m"
210+
gray := "\033[38;2;180;180;180m"
211+
212+
title := "WELCOME TO STACKROOST CLI"
213+
subTitle := "Smart Linux Server Manager"
214+
215+
startR, startG, startB := 135, 206, 235
216+
endR, endG, endB := 255, 0, 0
217+
218+
length := len(title)
219+
220+
fmt.Println()
221+
fmt.Print(bold)
222+
223+
for i, ch := range title {
224+
t := float64(i) / float64(length-1)
225+
r := int(float64(startR)*(1-t) + float64(endR)*t)
226+
g := int(float64(startG)*(1-t) + float64(endG)*t)
227+
b := int(float64(startB)*(1-t) + float64(endB)*t)
228+
fmt.Printf("\033[38;2;%d;%d;%dm%c", r, g, b, ch)
229+
}
230+
231+
fmt.Println(reset)
232+
fmt.Println()
233+
234+
fmt.Printf("%s\033[38;2;135;206;235m%s%s\n\n", bold, subTitle, reset)
235+
236+
fmt.Println(gray + "Welcome to StackRoost — your powerful CLI for managing Linux domains," + reset)
237+
fmt.Println(gray + "creating shell users, and configuring Apache · Nginx · Caddy effortlessly." + reset)
238+
fmt.Println()
239+
240+
fmt.Printf("%s\033[38;2;200;200;200mtry: %sstackroost --help%s\n\n", bold, reset, reset)
206241
}
207242

208243
func writeConfigFile(domain, content, extension string) error {
209-
var outputDir string
244+
logger.Info(fmt.Sprintf("Writing configuration file for %s", domain))
245+
246+
var configPath string
210247
if extension == ".conf" {
211248
if strings.HasPrefix(content, "server") {
212-
outputDir = "/etc/nginx/sites-available"
249+
configPath = "/etc/nginx/sites-available"
250+
logger.Debug("Detected nginx configuration")
213251
} else if strings.Contains(content, "php_fastcgi") {
214-
outputDir = "/etc/caddy/sites-available"
252+
configPath = "/etc/caddy/sites-available"
253+
logger.Debug("Detected caddy configuration")
215254
} else {
216-
outputDir = "/etc/apache2/sites-available"
255+
configPath = "/etc/apache2/sites-available"
256+
logger.Debug("Detected apache configuration")
217257
}
218258
}
219259

220-
if err := os.MkdirAll(outputDir, 0755); err != nil {
221-
return fmt.Errorf("failed to create output directory: %v", err)
260+
if err := os.MkdirAll(configPath, 0755); err != nil {
261+
logger.Error(fmt.Sprintf("Failed to create output directory %s: %v", configPath, err))
262+
return err
222263
}
223264

224265
filename := fmt.Sprintf("%s%s", domain, extension)
225-
outputPath := filepath.Join(outputDir, filename)
266+
outputPath := filepath.Join(configPath, filename)
226267

227268
if _, err := os.Stat(outputPath); err == nil {
228-
return fmt.Errorf("configuration for '%s' already exists at %s", domain, outputPath)
269+
logger.Error(fmt.Sprintf("Configuration already exists at %s for domain %s", outputPath, domain))
270+
return fmt.Errorf("configuration exists")
229271
}
230272

231273
if err := os.WriteFile(outputPath, []byte(content), 0644); err != nil {
232-
return fmt.Errorf("failed to write config file: %v", err)
274+
logger.Error(fmt.Sprintf("Failed to write config file %s: %v", outputPath, err))
275+
return err
233276
}
234277

278+
logger.Success(fmt.Sprintf("Configuration file written to %s", outputPath))
235279
return nil
236-
}
280+
}

config/apache/apache.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ package apache
22

33
import "fmt"
44

5-
// ApacheConfig implements the WebServerConfig interface for Apache
65
type ApacheConfig struct{}
76

8-
// Generate creates an Apache virtual host configuration
97
func (a *ApacheConfig) Generate(domain, port, username string) (string, error) {
108
vhostTemplate := `<VirtualHost *:%s>
119
ServerName %s
@@ -23,8 +21,6 @@ func (a *ApacheConfig) Generate(domain, port, username string) (string, error) {
2321
return fmt.Sprintf(vhostTemplate, port, domain, domain, username, domain, domain, username), nil
2422
}
2523

26-
27-
// GetFileExtension returns the file extension for Apache config files
2824
func (a *ApacheConfig) GetFileExtension() string {
2925
return ".conf"
3026
}

config/caddy/caddy.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package caddy
22

33
import "fmt"
44

5-
// CaddyConfig implements WebServerConfig for Caddy
65
type CaddyConfig struct{}
76

87
func (c *CaddyConfig) Generate(domain, port, username string) (string, error) {

config/config.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ import (
77
"stackroost/config/caddy"
88
)
99

10-
// WebServerConfig defines the interface for generating web server configurations
1110
type WebServerConfig interface {
1211
Generate(domain, port, username string) (string, error)
1312
GetFileExtension() string
1413
}
1514

16-
// NewWebServerConfig creates a new configuration generator based on the server type
1715
func NewWebServerConfig(serverType string) (WebServerConfig, error) {
1816
switch serverType {
1917
case "apache":

config/nginx/nginx.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package nginx
22

33
import "fmt"
44

5-
// NginxConfig implements WebServerConfig for Nginx
65
type NginxConfig struct{}
76

87
func (n *NginxConfig) Generate(domain, port, username string) (string, error) {

0 commit comments

Comments
 (0)