@@ -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
@@ -60,6 +61,8 @@ const (
6061
6162// InitCmd is a struct that defines a command call for "init"
6263type InitCmd struct {
64+ * flags.GlobalFlags
65+
6366 // Flags
6467 Reconfigure bool
6568 Dockerfile string
@@ -71,7 +74,8 @@ type InitCmd struct {
7174// NewInitCmd creates a new init command
7275func NewInitCmd (f factory.Factory ) * cobra.Command {
7376 cmd := & InitCmd {
74- log : f .GetLog (),
77+ log : f .GetLog (),
78+ GlobalFlags : globalFlags ,
7579 }
7680
7781 initCmd := & cobra.Command {
@@ -147,45 +151,31 @@ func (cmd *InitCmd) Run(f factory.Factory) error {
147151 // Print DevSpace logo
148152 log .PrintLogo ()
149153
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- }
154+ // Determine if we're initializing from scratch, or using docker-compose.yaml
155+ dockerComposePath , generateFromDockerCompose , err := cmd .shouldGenerateFromDockerCompose ()
156+ if err != nil {
157+ return err
158+ }
166159
167- generateFromDockerCompose = selectedDockerComposeOption == DockerComposeDevSpaceConfigOption
168- }
160+ if generateFromDockerCompose {
161+ err = cmd .initDockerCompose (f , dockerComposePath )
162+ } else {
163+ err = cmd .initDevspace (f , configLoader )
164+ }
169165
170- if generateFromDockerCompose {
171- composeLoader := compose.NewDockerComposeLoader(dockerComposePath)
172- if err != nil {
173- return err
174- }
166+ if err != nil {
167+ panic (err )
168+ }
175169
176- // Load config
177- config, err := composeLoader.Load(cmd.log)
178- if err != nil {
179- return err
180- }
170+ cmd .log .WriteString (logrus .InfoLevel , "\n " )
171+ cmd .log .Done ("Project successfully initialized" )
172+ cmd .log .Info ("Configuration saved in devspace.yaml - you can make adjustments as needed" )
173+ 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" ))
181174
182- // Save config
183- err = composeLoader.Save(config)
184- if err != nil {
185- return err
186- }
187- } else {*/
175+ return nil
176+ }
188177
178+ func (cmd * InitCmd ) initDevspace (f factory.Factory , configLoader loader.ConfigLoader ) error {
189179 // Create new dockerfile generator
190180 languageHandler , err := generator .NewLanguageHandler ("" , "" , cmd .log )
191181 if err != nil {
@@ -214,7 +204,7 @@ func (cmd *InitCmd) Run(f factory.Factory) error {
214204 var config * latest.Config
215205
216206 // create kubectl client
217- client , err := f .NewKubeClientFromContext (globalFlags . KubeContext , globalFlags .Namespace )
207+ client , err := f .NewKubeClientFromContext (cmd . GlobalFlags . KubeContext , cmd . GlobalFlags .Namespace )
218208 if err == nil {
219209 configInterface , err := configLoader .Load (context .TODO (), client , & loader.ConfigOptions {}, cmd .log )
220210 if err == nil {
@@ -476,8 +466,6 @@ create_deployments --all \ # 3. Deploy Helm charts and ma
476466 return err
477467 }
478468
479- /*}*/
480-
481469 // Save generated
482470 err = localCache .Save ()
483471 if err != nil {
@@ -491,6 +479,88 @@ create_deployments --all \ # 3. Deploy Helm charts and ma
491479 }
492480
493481 configPath := loader .ConfigPath ("" )
482+ err = annotateConfig (configPath )
483+ if err != nil {
484+ return err
485+ }
486+
487+ return nil
488+ }
489+
490+ func (cmd * InitCmd ) initDockerCompose (f factory.Factory , composePath string ) error {
491+ project , err := compose .LoadDockerComposeProject (composePath )
492+ if err != nil {
493+ return err
494+ }
495+
496+ projectName , _ , err := getProjectName ()
497+ if err != nil {
498+ return err
499+ }
500+
501+ project .Name = projectName
502+
503+ // Prompt user for entrypoints for each container with sync folders.
504+ for idx , service := range project .Services {
505+ localPaths := compose .GetServiceSyncPaths (project , service )
506+ noEntryPoint := len (service .Entrypoint ) == 0
507+ hasSyncEndpoints := len (localPaths ) > 0
508+
509+ if noEntryPoint && hasSyncEndpoints {
510+ entrypointStr , err := cmd .log .Question (& survey.QuestionOptions {
511+ Question : "How is this container started? (e.g. npm start, gradle run, go run main.go)" ,
512+ })
513+ if err != nil {
514+ return err
515+ }
516+
517+ entrypoint := strings .Split (entrypointStr , " " )
518+ project .Services [idx ].Entrypoint = entrypoint
519+ }
520+ }
521+
522+ // Generate DevSpace configuration
523+ composeManager := compose .NewComposeManager (project )
524+ err = composeManager .Load (cmd .log )
525+ if err != nil {
526+ return err
527+ }
528+
529+ // Save each configuration file
530+ for path , config := range composeManager .Configs () {
531+ localCache , err := localcache .NewCacheLoader ().Load (path )
532+ if err != nil {
533+ return err
534+ }
535+
536+ // Save config
537+ err = loader .Save (path , config )
538+ if err != nil {
539+ return err
540+ }
541+
542+ // Save generated
543+ err = localCache .Save ()
544+ if err != nil {
545+ return errors .Errorf ("Error saving generated file: %v" , err )
546+ }
547+
548+ // Add .devspace/ to .gitignore
549+ err = appendToIgnoreFile (gitIgnoreFile , devspaceFolderGitignore )
550+ if err != nil {
551+ cmd .log .Warn (err )
552+ }
553+
554+ err = annotateConfig (path )
555+ if err != nil {
556+ return err
557+ }
558+ }
559+
560+ return nil
561+ }
562+
563+ func annotateConfig (configPath string ) error {
494564 annotatedConfig , err := ioutil .ReadFile (configPath )
495565 if err != nil {
496566 panic (err )
@@ -541,74 +611,9 @@ create_deployments --all \ # 3. Deploy Helm charts and ma
541611 return err
542612 }
543613
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- }
575614 return nil
576615}
577616
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-
612617func (cmd * InitCmd ) addDevConfig (config * latest.Config , imageName , image string , port int , languageHandler * generator.LanguageHandler ) error {
613618 if config .Dev == nil {
614619 config .Dev = map [string ]* latest.DevPod {}
@@ -726,6 +731,7 @@ func (cmd *InitCmd) render(f factory.Factory, config *latest.Config) (string, er
726731 Silent : true ,
727732 ConfigPath : renderPath ,
728733 },
734+ Pipeline : "deploy" ,
729735 SkipPush : true ,
730736 SkipBuild : true ,
731737 Render : true ,
@@ -739,6 +745,87 @@ func (cmd *InitCmd) render(f factory.Factory, config *latest.Config) (string, er
739745 return writer .String (), nil
740746}
741747
748+ func (cmd * InitCmd ) shouldGenerateFromDockerCompose () (string , bool , error ) {
749+ dockerComposePath := compose .GetDockerComposePath ()
750+ if dockerComposePath != "" {
751+ selectedDockerComposeOption , err := cmd .log .Question (& survey.QuestionOptions {
752+ Question : "Docker Compose configuration detected. Do you want to create a DevSpace configuration based on Docker Compose?" ,
753+ DefaultValue : DockerComposeDevSpaceConfigOption ,
754+ Options : []string {
755+ DockerComposeDevSpaceConfigOption ,
756+ NewDevSpaceConfigOption ,
757+ },
758+ })
759+ if err != nil {
760+ return "" , false , err
761+ }
762+
763+ return dockerComposePath , selectedDockerComposeOption == DockerComposeDevSpaceConfigOption , nil
764+ }
765+ return "" , false , nil
766+ }
767+
768+ func appendToIgnoreFile (ignoreFile , content string ) error {
769+ // Check if ignoreFile exists
770+ _ , err := os .Stat (ignoreFile )
771+ if os .IsNotExist (err ) {
772+ _ = fsutil .WriteToFile ([]byte (content ), ignoreFile )
773+ } else {
774+ fileContent , err := ioutil .ReadFile (ignoreFile )
775+ if err != nil {
776+ return errors .Errorf ("Error reading file %s: %v" , ignoreFile , err )
777+ }
778+
779+ // append only if not found in file content
780+ if ! strings .Contains (string (fileContent ), content ) {
781+ file , err := os .OpenFile (ignoreFile , os .O_APPEND | os .O_WRONLY , 0600 )
782+ if err != nil {
783+ return errors .Errorf ("Error writing file %s: %v" , ignoreFile , err )
784+ }
785+
786+ defer file .Close ()
787+ if _ , err = file .WriteString (content ); err != nil {
788+ return errors .Errorf ("Error writing file %s: %v" , ignoreFile , err )
789+ }
790+ }
791+ }
792+ return nil
793+ }
794+
795+ func getProjectName () (string , string , error ) {
796+ projectName := ""
797+ projectNamespace := ""
798+ gitRemote , err := command .Output (context .TODO (), "" , "git" , "config" , "--get" , "remote.origin.url" )
799+ if err == nil {
800+ sep := "/"
801+ projectParts := strings .Split (string (regexp .MustCompile (`^.*?://[^/]+?/([^.]+)(\.git)?` ).ReplaceAll (gitRemote , []byte ("$1" ))), sep )
802+ partsLen := len (projectParts )
803+ if partsLen > 1 {
804+ projectNamespace = strings .Join (projectParts [0 :partsLen - 1 ], sep )
805+ projectName = projectParts [partsLen - 1 ]
806+ }
807+ }
808+
809+ if projectName == "" {
810+ absPath , err := filepath .Abs ("." )
811+ if err != nil {
812+ return "" , "" , err
813+ }
814+ projectName = filepath .Base (absPath )
815+ }
816+
817+ projectName = strings .ToLower (projectName )
818+ projectName = regexp .MustCompile ("[^a-zA-Z0-9- ]+" ).ReplaceAllString (projectName , "" )
819+ projectName = regexp .MustCompile ("[^a-zA-Z0-9-]+" ).ReplaceAllString (projectName , "-" )
820+ projectName = strings .Trim (projectName , "-" )
821+
822+ if ! SpaceNameValidationRegEx .MatchString (projectName ) || len (projectName ) > 42 {
823+ projectName = "devspace"
824+ }
825+
826+ return projectName , projectNamespace , nil
827+ }
828+
742829func parseImages (manifests string ) ([]string , error ) {
743830 images := []string {}
744831
0 commit comments