@@ -11,6 +11,7 @@ import (
1111 "strconv"
1212 "strings"
1313
14+ "github.com/loft-sh/devspace/pkg/devspace/compose"
1415 "github.com/loft-sh/devspace/pkg/devspace/config/localcache"
1516 "github.com/sirupsen/logrus"
1617
@@ -147,45 +148,31 @@ func (cmd *InitCmd) Run(f factory.Factory) error {
147148 // Print DevSpace logo
148149 log .PrintLogo ()
149150
150- /*
151- generateFromDockerCompose := false
152- // TODO: Enable again
153- dockerComposePath := "" // compose.GetDockerComposePath()
154- if dockerComposePath != "" {
155- selectedDockerComposeOption, err := cmd.log.Question(&survey.QuestionOptions{
156- Question: "Docker Compose configuration detected. Do you want to create a DevSpace configuration based on Docker Compose?",
157- DefaultValue: DockerComposeDevSpaceConfigOption,
158- Options: []string{
159- DockerComposeDevSpaceConfigOption,
160- NewDevSpaceConfigOption,
161- },
162- })
163- if err != nil {
164- return err
165- }
151+ // Determine if we're initializing from scratch, or using docker-compose.yaml
152+ dockerComposePath , generateFromDockerCompose , err := cmd .shouldGenerateFromDockerCompose ()
153+ if err != nil {
154+ return err
155+ }
166156
167- generateFromDockerCompose = selectedDockerComposeOption == DockerComposeDevSpaceConfigOption
168- }
157+ if generateFromDockerCompose {
158+ err = cmd .initDockerCompose (f , dockerComposePath )
159+ } else {
160+ err = cmd .initDevspace (f , configLoader )
161+ }
169162
170- if generateFromDockerCompose {
171- composeLoader := compose.NewDockerComposeLoader(dockerComposePath)
172- if err != nil {
173- return err
174- }
163+ if err != nil {
164+ panic (err )
165+ }
175166
176- // Load config
177- config, err := composeLoader.Load(cmd.log)
178- if err != nil {
179- return err
180- }
167+ cmd .log .WriteString (logrus .InfoLevel , "\n " )
168+ cmd .log .Done ("Project successfully initialized" )
169+ cmd .log .Info ("Configuration saved in devspace.yaml - you can make adjustments as needed" )
170+ cmd .log .Infof ("\r \n You can now run:\n 1. %s - to pick which Kubernetes namespace to work in\n 2. %s - to start developing your project in Kubernetes\n \n Run `%s` or `%s` to see a list of available commands and flags\n " , ansi .Color ("devspace use namespace" , "blue+b" ), ansi .Color ("devspace dev" , "blue+b" ), ansi .Color ("devspace -h" , "blue+b" ), ansi .Color ("devspace [command] -h" , "blue+b" ))
181171
182- // Save config
183- err = composeLoader.Save(config)
184- if err != nil {
185- return err
186- }
187- } else {*/
172+ return nil
173+ }
188174
175+ func (cmd * InitCmd ) initDevspace (f factory.Factory , configLoader loader.ConfigLoader ) error {
189176 // Create new dockerfile generator
190177 languageHandler , err := generator .NewLanguageHandler ("" , "" , cmd .log )
191178 if err != nil {
@@ -476,8 +463,6 @@ create_deployments --all \ # 3. Deploy Helm charts and ma
476463 return err
477464 }
478465
479- /*}*/
480-
481466 // Save generated
482467 err = localCache .Save ()
483468 if err != nil {
@@ -491,6 +476,81 @@ create_deployments --all \ # 3. Deploy Helm charts and ma
491476 }
492477
493478 configPath := loader .ConfigPath ("" )
479+ err = annotateConfig (configPath )
480+ if err != nil {
481+ return err
482+ }
483+
484+ return nil
485+ }
486+
487+ func (cmd * InitCmd ) initDockerCompose (f factory.Factory , composePath string ) error {
488+ project , err := compose .LoadDockerComposeProject (composePath )
489+ if err != nil {
490+ return err
491+ }
492+
493+ // Prompt user for entrypoints for each container with sync folders.
494+ for idx , service := range project .Services {
495+ localPaths := compose .GetServiceSyncPaths (project , service )
496+ noEntryPoint := len (service .Entrypoint ) == 0
497+ hasSyncEndpoints := len (localPaths ) > 0
498+
499+ if noEntryPoint && hasSyncEndpoints {
500+ entrypointStr , err := cmd .log .Question (& survey.QuestionOptions {
501+ Question : "How is this container started? (e.g. npm start, gradle run, go run main.go)" ,
502+ })
503+ if err != nil {
504+ return err
505+ }
506+
507+ entrypoint := strings .Split (entrypointStr , " " )
508+ project .Services [idx ].Entrypoint = entrypoint
509+ }
510+ }
511+
512+ // Generate DevSpace configuration
513+ composeManager := compose .NewComposeManager (project )
514+ err = composeManager .Load (cmd .log )
515+ if err != nil {
516+ return err
517+ }
518+
519+ // Save each configuration file
520+ for path , config := range composeManager .Configs () {
521+ localCache , err := localcache .NewCacheLoader ().Load (path )
522+ if err != nil {
523+ return err
524+ }
525+
526+ // Save config
527+ err = loader .Save (path , config )
528+ if err != nil {
529+ return err
530+ }
531+
532+ // Save generated
533+ err = localCache .Save ()
534+ if err != nil {
535+ return errors .Errorf ("Error saving generated file: %v" , err )
536+ }
537+
538+ // Add .devspace/ to .gitignore
539+ err = appendToIgnoreFile (gitIgnoreFile , devspaceFolderGitignore )
540+ if err != nil {
541+ cmd .log .Warn (err )
542+ }
543+
544+ err = annotateConfig (path )
545+ if err != nil {
546+ return err
547+ }
548+ }
549+
550+ return nil
551+ }
552+
553+ func annotateConfig (configPath string ) error {
494554 annotatedConfig , err := ioutil .ReadFile (configPath )
495555 if err != nil {
496556 panic (err )
@@ -541,74 +601,9 @@ create_deployments --all \ # 3. Deploy Helm charts and ma
541601 return err
542602 }
543603
544- cmd .log .WriteString (logrus .InfoLevel , "\n " )
545- cmd .log .Done ("Project successfully initialized" )
546- cmd .log .Info ("Configuration saved in devspace.yaml - you can make adjustments as needed" )
547- cmd .log .Infof ("\r \n You can now run:\n 1. %s - to pick which Kubernetes namespace to work in\n 2. %s - to start developing your project in Kubernetes\n \n Run `%s` or `%s` to see a list of available commands and flags\n " , ansi .Color ("devspace use namespace" , "blue+b" ), ansi .Color ("devspace dev" , "blue+b" ), ansi .Color ("devspace -h" , "blue+b" ), ansi .Color ("devspace [command] -h" , "blue+b" ))
548- return nil
549- }
550-
551- func appendToIgnoreFile (ignoreFile , content string ) error {
552- // Check if ignoreFile exists
553- _ , err := os .Stat (ignoreFile )
554- if os .IsNotExist (err ) {
555- _ = fsutil .WriteToFile ([]byte (content ), ignoreFile )
556- } else {
557- fileContent , err := ioutil .ReadFile (ignoreFile )
558- if err != nil {
559- return errors .Errorf ("Error reading file %s: %v" , ignoreFile , err )
560- }
561-
562- // append only if not found in file content
563- if ! strings .Contains (string (fileContent ), content ) {
564- file , err := os .OpenFile (ignoreFile , os .O_APPEND | os .O_WRONLY , 0600 )
565- if err != nil {
566- return errors .Errorf ("Error writing file %s: %v" , ignoreFile , err )
567- }
568-
569- defer file .Close ()
570- if _ , err = file .WriteString (content ); err != nil {
571- return errors .Errorf ("Error writing file %s: %v" , ignoreFile , err )
572- }
573- }
574- }
575604 return nil
576605}
577606
578- func getProjectName () (string , string , error ) {
579- projectName := ""
580- projectNamespace := ""
581- gitRemote , err := command .Output (context .TODO (), "" , "git" , "config" , "--get" , "remote.origin.url" )
582- if err == nil {
583- sep := "/"
584- projectParts := strings .Split (string (regexp .MustCompile (`^.*?://[^/]+?/([^.]+)(\.git)?` ).ReplaceAll (gitRemote , []byte ("$1" ))), sep )
585- partsLen := len (projectParts )
586- if partsLen > 1 {
587- projectNamespace = strings .Join (projectParts [0 :partsLen - 1 ], sep )
588- projectName = projectParts [partsLen - 1 ]
589- }
590- }
591-
592- if projectName == "" {
593- absPath , err := filepath .Abs ("." )
594- if err != nil {
595- return "" , "" , err
596- }
597- projectName = filepath .Base (absPath )
598- }
599-
600- projectName = strings .ToLower (projectName )
601- projectName = regexp .MustCompile ("[^a-zA-Z0-9- ]+" ).ReplaceAllString (projectName , "" )
602- projectName = regexp .MustCompile ("[^a-zA-Z0-9-]+" ).ReplaceAllString (projectName , "-" )
603- projectName = strings .Trim (projectName , "-" )
604-
605- if ! SpaceNameValidationRegEx .MatchString (projectName ) || len (projectName ) > 42 {
606- projectName = "devspace"
607- }
608-
609- return projectName , projectNamespace , nil
610- }
611-
612607func (cmd * InitCmd ) addDevConfig (config * latest.Config , imageName , image string , port int , languageHandler * generator.LanguageHandler ) error {
613608 if config .Dev == nil {
614609 config .Dev = map [string ]* latest.DevPod {}
@@ -739,6 +734,87 @@ func (cmd *InitCmd) render(f factory.Factory, config *latest.Config) (string, er
739734 return writer .String (), nil
740735}
741736
737+ func (cmd * InitCmd ) shouldGenerateFromDockerCompose () (string , bool , error ) {
738+ dockerComposePath := compose .GetDockerComposePath ()
739+ if dockerComposePath != "" {
740+ selectedDockerComposeOption , err := cmd .log .Question (& survey.QuestionOptions {
741+ Question : "Docker Compose configuration detected. Do you want to create a DevSpace configuration based on Docker Compose?" ,
742+ DefaultValue : DockerComposeDevSpaceConfigOption ,
743+ Options : []string {
744+ DockerComposeDevSpaceConfigOption ,
745+ NewDevSpaceConfigOption ,
746+ },
747+ })
748+ if err != nil {
749+ return "" , false , err
750+ }
751+
752+ return dockerComposePath , selectedDockerComposeOption == DockerComposeDevSpaceConfigOption , nil
753+ }
754+ return "" , false , nil
755+ }
756+
757+ func appendToIgnoreFile (ignoreFile , content string ) error {
758+ // Check if ignoreFile exists
759+ _ , err := os .Stat (ignoreFile )
760+ if os .IsNotExist (err ) {
761+ _ = fsutil .WriteToFile ([]byte (content ), ignoreFile )
762+ } else {
763+ fileContent , err := ioutil .ReadFile (ignoreFile )
764+ if err != nil {
765+ return errors .Errorf ("Error reading file %s: %v" , ignoreFile , err )
766+ }
767+
768+ // append only if not found in file content
769+ if ! strings .Contains (string (fileContent ), content ) {
770+ file , err := os .OpenFile (ignoreFile , os .O_APPEND | os .O_WRONLY , 0600 )
771+ if err != nil {
772+ return errors .Errorf ("Error writing file %s: %v" , ignoreFile , err )
773+ }
774+
775+ defer file .Close ()
776+ if _ , err = file .WriteString (content ); err != nil {
777+ return errors .Errorf ("Error writing file %s: %v" , ignoreFile , err )
778+ }
779+ }
780+ }
781+ return nil
782+ }
783+
784+ func getProjectName () (string , string , error ) {
785+ projectName := ""
786+ projectNamespace := ""
787+ gitRemote , err := command .Output (context .TODO (), "" , "git" , "config" , "--get" , "remote.origin.url" )
788+ if err == nil {
789+ sep := "/"
790+ projectParts := strings .Split (string (regexp .MustCompile (`^.*?://[^/]+?/([^.]+)(\.git)?` ).ReplaceAll (gitRemote , []byte ("$1" ))), sep )
791+ partsLen := len (projectParts )
792+ if partsLen > 1 {
793+ projectNamespace = strings .Join (projectParts [0 :partsLen - 1 ], sep )
794+ projectName = projectParts [partsLen - 1 ]
795+ }
796+ }
797+
798+ if projectName == "" {
799+ absPath , err := filepath .Abs ("." )
800+ if err != nil {
801+ return "" , "" , err
802+ }
803+ projectName = filepath .Base (absPath )
804+ }
805+
806+ projectName = strings .ToLower (projectName )
807+ projectName = regexp .MustCompile ("[^a-zA-Z0-9- ]+" ).ReplaceAllString (projectName , "" )
808+ projectName = regexp .MustCompile ("[^a-zA-Z0-9-]+" ).ReplaceAllString (projectName , "-" )
809+ projectName = strings .Trim (projectName , "-" )
810+
811+ if ! SpaceNameValidationRegEx .MatchString (projectName ) || len (projectName ) > 42 {
812+ projectName = "devspace"
813+ }
814+
815+ return projectName , projectNamespace , nil
816+ }
817+
742818func parseImages (manifests string ) ([]string , error ) {
743819 images := []string {}
744820
0 commit comments