@@ -3,28 +3,11 @@ package main
33import (
44 "fmt"
55 "os"
6- "path/filepath"
7- "strings"
8- "time"
96
10- "github.com/nauticalab/devenv-engine/internal/config"
11- "github.com/nauticalab/devenv-engine/internal/templates"
7+ "github.com/nauticalab/devenv-engine/internal/cli"
128 "github.com/spf13/cobra"
139)
1410
15- // DeveloperJob represents work to be done for one developer
16- type DeveloperJob struct {
17- Name string
18- }
19-
20- // ProcessingResult represents the outcome of processing one developer
21- type ProcessingResult struct {
22- Developer string
23- Success bool
24- Error error
25- Duration time.Duration
26- }
27-
2811var (
2912 // Command-specific flags for generate
3013 outputDir string
@@ -55,16 +38,20 @@ Examples:
5538 os .Exit (1 )
5639 }
5740
58- // Execute the logic (placeholder for now)
41+ opts := cli.GenerateOptions {
42+ OutputDir : outputDir ,
43+ ConfigDir : configDir ,
44+ DryRun : dryRun ,
45+ Verbose : verbose ,
46+ }
47+
48+ // Execute the logic
5949 if allDevs {
6050 fmt .Println ("Generating manifests for all developers..." )
61- if verbose {
62- fmt .Printf ("Output directory: %s\n " , outputDir )
63- }
64- generateAllDevelopersWithProgress ()
51+ cli .GenerateRunAll (opts )
6552 } else {
6653 developerName := args [0 ]
67- generateSingleDeveloper (developerName )
54+ cli . GenerateRunSingle (developerName , opts )
6855 }
6956 },
7057}
@@ -77,276 +64,3 @@ func init() {
7764 generateCmd .Flags ().BoolVar (& allDevs , "all-developers" , false , "Generate manifests for all developers" )
7865
7966}
80-
81- func generateAllDevelopersWithProgress () {
82- // Step 1: Load global config once
83- globalConfig , err := config .LoadGlobalConfig (configDir )
84- if err != nil {
85- fmt .Fprintf (os .Stderr , "Error loading global config in %s: %v\n " , configDir , err )
86- os .Exit (1 )
87- }
88-
89- if verbose {
90- fmt .Printf ("Generating system manifests in %s\n " , outputDir )
91- }
92-
93- // Step 2: Generate system manifests once
94- if ! dryRun {
95- if err := generateSystemManifests (globalConfig , outputDir ); err != nil {
96- fmt .Fprintf (os .Stderr , "Error generating system manifests: %v\n " , err )
97- os .Exit (1 )
98- }
99- }
100-
101- // Step 3: Discover all developers
102- developers , err := findAllDevelopers (configDir )
103- if err != nil {
104- fmt .Fprintf (os .Stderr , "Error discovering developers: %v\n " , err )
105- os .Exit (1 )
106- }
107-
108- if len (developers ) == 0 {
109- fmt .Printf ("No developers found in %s\n " , configDir )
110- return
111- }
112-
113- fmt .Printf ("Found %d developers to process.\n " , len (developers ))
114-
115- // Step 4: Set up channels for worker communication
116- const numWorkers = 4
117- jobs := make (chan DeveloperJob , len (developers ))
118- results := make (chan ProcessingResult , len (developers ))
119-
120- // Step 5: Start worker goroutines
121- for i := 0 ; i < numWorkers ; i ++ {
122- go developerWorker (jobs , results , globalConfig )
123- }
124-
125- // Step 6: Send all jobs to workers
126- for _ , dev := range developers {
127- jobs <- DeveloperJob {Name : dev }
128- }
129- close (jobs )
130-
131- // Step 7: Collect results
132- var successCount , failureCount int
133- var failures []ProcessingResult
134-
135- for i := 0 ; i < len (developers ); i ++ {
136- result := <- results
137- if result .Success {
138- successCount ++
139- fmt .Printf ("[%d/%d] ✅ %s (%.1fs)\n " ,
140- i + 1 , len (developers ), result .Developer , result .Duration .Seconds ())
141- } else {
142- failureCount ++
143- failures = append (failures , result )
144- fmt .Printf ("[%d/%d] ❌ %s (%.1fs): %v\n " ,
145- i + 1 , len (developers ), result .Developer , result .Duration .Seconds (), result .Error )
146- }
147- }
148-
149- // Step 8: Print final summary
150- fmt .Printf ("\n 🎉 Batch processing complete!\n " )
151- fmt .Printf ("✅ Successful: %d\n " , successCount )
152- if failureCount > 0 {
153- fmt .Printf ("❌ Failed: %d\n " , failureCount )
154- }
155-
156- if failureCount > 0 {
157- fmt .Printf ("\n Failures:\n " )
158- for _ , failure := range failures {
159- fmt .Printf (" - %s: %v\n " , failure .Developer , failure .Error )
160- }
161- os .Exit (1 ) // Exit with error if any failures
162- }
163- }
164-
165- func developerWorker (jobs <- chan DeveloperJob , results chan <- ProcessingResult , globalConfig * config.BaseConfig ) {
166- for job := range jobs {
167- startTime := time .Now ()
168- err := processSingleDeveloperForBatchWithError (job .Name , globalConfig )
169-
170- results <- ProcessingResult {
171- Developer : job .Name ,
172- Success : err == nil ,
173- Error : err ,
174- Duration : time .Since (startTime ),
175- }
176- }
177- }
178-
179- // processSingleDeveloperForBatchWithError processes a single developer for batch mode
180- func processSingleDeveloperForBatchWithError (developerName string , globalConfig * config.BaseConfig ) error {
181- if verbose {
182- fmt .Printf ("Processing developer: %s\n " , developerName )
183- }
184-
185- cfg , err := config .LoadDeveloperConfigWithBaseConfig (configDir , developerName , globalConfig )
186- if err != nil {
187- return fmt .Errorf ("failed to load config: %w" , err )
188- }
189-
190- // Create user-specific output directory
191- userOutputDir := filepath .Join (outputDir , developerName )
192-
193- if ! dryRun {
194- if err := generateDeveloperManifests (cfg , userOutputDir ); err != nil {
195- return fmt .Errorf ("failed to generate manifests: %w" , err )
196- }
197- }
198-
199- return nil
200- }
201-
202- func findAllDevelopers (configDir string ) ([]string , error ) {
203- var developers []string
204-
205- entries , err := os .ReadDir (configDir )
206- if err != nil {
207- return nil , fmt .Errorf ("failed to read config directory: %w" , err )
208- }
209-
210- for _ , entry := range entries {
211- if entry .IsDir () {
212- // Check to make sure devenv-config.yaml exists in this directory
213- configPath := filepath .Join (configDir , entry .Name (), "devenv-config.yaml" )
214- if _ , err := os .Stat (configPath ); err == nil {
215- developers = append (developers , entry .Name ())
216- }
217- }
218- }
219-
220- return developers , nil
221- }
222-
223- // generateSingleDeveloper handles generation for a single developer
224- func generateSingleDeveloper (developerName string ) {
225- fmt .Printf ("Generating manifests for developer: %s\n " , developerName )
226-
227- if verbose {
228- fmt .Printf ("Output directory: %s\n " , outputDir )
229- fmt .Printf ("Config directory: %s\n " , configDir )
230- fmt .Printf ("Dry run mode: %t\n " , dryRun )
231- }
232-
233- userOutputDir := filepath .Join (outputDir , developerName )
234-
235- globalConfig , err := config .LoadGlobalConfig (configDir )
236- if err != nil {
237- fmt .Fprintf (os .Stderr , "Error loading global config in %s: %v\n " , configDir , err )
238- os .Exit (1 )
239- }
240-
241- if err := generateSystemManifests (globalConfig , outputDir ); err != nil {
242- fmt .Fprintf (os .Stderr , "Error generating system manifests: %v\n " , err )
243- os .Exit (1 )
244- }
245-
246- cfg , err := config .LoadDeveloperConfigWithBaseConfig (configDir , developerName , globalConfig )
247- if err != nil {
248- fmt .Fprintf (os .Stderr , "Error loading config for developer %s: %v\n " , developerName , err )
249- os .Exit (1 )
250- }
251-
252- fmt .Printf ("✅ Successfully loaded configuration for developer: %s\n " , cfg .Name )
253-
254- if verbose {
255- printConfigSummary (cfg )
256- }
257-
258- if ! dryRun {
259- if err := generateDeveloperManifests (cfg , userOutputDir ); err != nil {
260- fmt .Fprintf (os .Stderr , "Error generating manifests: %v\n " , err )
261- os .Exit (1 )
262- }
263- } else {
264- fmt .Printf ("🔍 Dry run - would generate manifests to: %s\n " , userOutputDir )
265- }
266- }
267-
268- func generateSystemManifests (cfg * config.BaseConfig , outputDir string ) error {
269- // Create template renderer
270- renderer := templates .NewSystemRenderer (outputDir )
271-
272- // Render all main templates
273- if err := renderer .RenderAll (cfg ); err != nil {
274- return fmt .Errorf ("failed to render templates: %w" , err )
275- }
276-
277- fmt .Printf ("🎉 Successfully generated system manifests\n " )
278-
279- return nil
280- }
281-
282- // generateDeveloperManifests creates Kubernetes manifests for a developer
283- func generateDeveloperManifests (cfg * config.DevEnvConfig , outputDir string ) error {
284- // Create template renderer
285- renderer := templates .NewDevRenderer (outputDir )
286-
287- // Render all main templates
288- if err := renderer .RenderAll (cfg ); err != nil {
289- return fmt .Errorf ("failed to render templates: %w" , err )
290- }
291-
292- fmt .Printf ("🎉 Successfully generated manifests for %s\n " , cfg .Name )
293-
294- return nil
295- }
296-
297- // Helper function to print config summary
298- func printConfigSummary (cfg * config.DevEnvConfig ) {
299- fmt .Printf ("\n Configuration Summary:\n " )
300- fmt .Printf (" Name: %s\n " , cfg .Name )
301-
302- sshKeys , _ := cfg .GetSSHKeys ()
303- fmt .Printf (" SSH Keys: %d configured\n " , len (sshKeys ))
304-
305- if cfg .SSHPort != 0 {
306- fmt .Printf (" SSH Port: %d\n " , cfg .SSHPort )
307- }
308-
309- if cfg .Git .Name != "" {
310- fmt .Printf (" Git: %s <%s>\n " , cfg .Git .Name , cfg .Git .Email )
311- }
312-
313- cpuStr := cfg .CPU () // e.g., "4000m" or "0"
314- memStr := cfg .Memory () // e.g., "16Gi" or ""
315-
316- hasCPU := cpuStr != "0"
317- hasMem := memStr != ""
318-
319- if hasCPU || hasMem {
320- var parts []string
321- if hasCPU {
322- parts = append (parts , fmt .Sprintf ("CPU=%s" , cpuStr ))
323- }
324- if hasMem {
325- parts = append (parts , fmt .Sprintf ("Memory=%s" , memStr ))
326- }
327- fmt .Printf (" Resources: %s\n " , strings .Join (parts , ", " ))
328- }
329-
330- if len (cfg .Volumes ) > 0 {
331- fmt .Printf (" Volumes: %d configured\n " , len (cfg .Volumes ))
332- }
333-
334- fmt .Printf (" Developer Config Dir: %s\n " , cfg .GetDeveloperDir ())
335- }
336-
337- // Helper function to format CPU value for display
338- func formatCPU (cpu any ) string {
339- if cpu == nil {
340- return "default"
341- }
342- switch v := cpu .(type ) {
343- case string :
344- return v
345- case int :
346- return fmt .Sprintf ("%d" , v )
347- case float64 :
348- return fmt .Sprintf ("%.0f" , v )
349- default :
350- return fmt .Sprintf ("%v" , v ) // Fallback
351- }
352- }
0 commit comments