diff --git a/internal/dockercompose/dockercompose.go b/internal/dockercompose/dockercompose.go index 99d8996..c130a12 100644 --- a/internal/dockercompose/dockercompose.go +++ b/internal/dockercompose/dockercompose.go @@ -7,7 +7,9 @@ import ( "github.com/fatih/color" DockermiTypes "github.com/mkhuda/dockermi/types" + "gopkg.in/yaml.v2" + // "github.com/goccy/go-yaml" ) // FindServices searches for docker-compose.yml files in the specified directory. @@ -41,14 +43,26 @@ func FindServices(root string, force bool) (DockermiTypes.ServiceScriptReturn, e } for serviceName, service := range composedFiles { - order, orderExists := service.Labels["dockermi.order"] - active, activeExists := service.Labels["dockermi.active"] + order, active := "", "" + orderExists, activeExists := false, false + + // Access the labels directly + if val, exists := service.Labels["dockermi.order"]; exists { + order, orderExists = val, true + } + if val, exists := service.Labels["dockermi.active"]; exists { + active, activeExists = val, true + } - includeService := true - if orderExists && activeExists && active == "true" { + // Determine if the service should be included + var includeService bool + + if force { + // If force is true, always include the service includeService = true - } else if !orderExists && !activeExists { - includeService = force || false + } else { + // Otherwise, check the order and active labels + includeService = (orderExists && activeExists && active == "true") } if includeService { @@ -57,6 +71,7 @@ func FindServices(root string, force bool) (DockermiTypes.ServiceScriptReturn, e ServiceName: serviceName, ComposeFile: path, }) + } else if activeExists { color.Yellow("Service '%s' is inactive (dockermi.active=false). Skipping...", serviceName) } else { @@ -112,7 +127,10 @@ func FindServicesWithKey(root string) (map[string][]DockermiTypes.ServiceScript, active, activeExists := service.Labels["dockermi.active"] key := service.Labels["dockermi.key"] // Check for dockermi.key - if orderExists && activeExists && active == "true" { + if key != "" && orderExists && activeExists && active == "true" { + if _, exists := groups[key]; !exists { + groups[key] = []DockermiTypes.ServiceScript{} + } groups[key] = append(groups[key], DockermiTypes.ServiceScript{ Order: order, ServiceName: serviceName, @@ -155,42 +173,74 @@ func ParseComposeFile(path string, withKey bool, force bool) (map[string]Dockerm return nil, err } - var composeFile DockermiTypes.DockerCompose + var composeFile map[string]interface{} err = yaml.Unmarshal(file, &composeFile) if err != nil { - // invalid docker-compose.yml file or yaml that can't be unmarshalled - // will not throw an error, just return an empty map return nil, nil } - // Convert the services to include their names and labels services := make(map[string]DockermiTypes.Service) - for name, service := range composeFile.Services { - labels := service.Labels - hasLabel := len(labels) != 0 - if force { - services[name] = DockermiTypes.Service{ - Name: name, - Labels: service.Labels, + + servicesData, exists := composeFile["services"] + if !exists { + return nil, nil + } + + if servicesData, ok := servicesData.(map[interface{}]interface{}); ok { + for name, data := range servicesData { + if serviceData, ok := data.(map[interface{}]interface{}); ok { + service, err := unmarshalService(serviceData) + if err != nil { + return nil, err + } + service.Name = name.(string) // Set the service name + services[name.(string)] = service } } - if hasLabel { - active, activeExists := service.Labels["dockermi.active"] - if activeExists && active == "true" { - // Default value for dockermi.key if not present - if _, exists := service.Labels["dockermi.key"]; !exists && withKey { - // Assign a default value or generate a unique key - service.Labels["dockermi.key"] = "default" // Example default value - } + } - services[name] = DockermiTypes.Service{ - Name: name, - Labels: service.Labels, - } + return services, nil +} + +// Custom unmarshal function to handle labels +func unmarshalService(data map[interface{}]interface{}) (DockermiTypes.Service, error) { + service := DockermiTypes.Service{ + Labels: make(map[string]string), + } + + if val, ok := data["image"].(string); ok { + service.Image = val + } + if ports, ok := data["ports"].([]interface{}); ok { + for _, port := range ports { + if p, ok := port.(string); ok { + service.Ports = append(service.Ports, p) } + } + } + // Handle labels + if labels, ok := data["labels"]; ok { + switch labels := labels.(type) { + case []interface{}: + for _, label := range labels { + if strLabel, ok := label.(string); ok { + parts := strings.SplitN(strLabel, "=", 2) + if len(parts) == 2 { + service.Labels[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) + } + } + } + case map[interface{}]interface{}: + for k, v := range labels { + if key, ok := k.(string); ok { + if value, ok := v.(string); ok { + service.Labels[key] = value + } + } + } } } - return services, nil + return service, nil } diff --git a/pkg/dockermi.go b/pkg/dockermi.go index f2a7717..cd26ec8 100644 --- a/pkg/dockermi.go +++ b/pkg/dockermi.go @@ -17,7 +17,7 @@ import ( ) func GetVersion() string { - return "v0.1.4" + return "v0.1.5" } // RunDockermi executes the main logic of the dockermi command. It takes a @@ -34,8 +34,8 @@ func RunDockermi(projectDir string) (string, error) { // Define flags for help and version help := flag.Bool("help", false, "Display help information") versionFlag := flag.Bool("version", false, "Display version information") - // Short version flag shortVersionFlag := flag.Bool("v", false, "Display version information") + force := flag.Bool("force", false, "Force script generation") flag.Parse() // Check for version flags @@ -61,14 +61,12 @@ func RunDockermi(projectDir string) (string, error) { return "", fmt.Errorf("missing key for create command") } return createDockermiScript(projectDir, os.Args[2]) - case "--force": - return generateScripts(projectDir, true) default: - return generateScripts(projectDir, false) + return generateScripts(projectDir, *force) } } // If no specific command is provided, generate the scripts - return generateScripts(projectDir, false) + return generateScripts(projectDir, *force) } // handleUpDownCommand handles the 'up' command logic. @@ -149,8 +147,6 @@ func createDockermiScript(projectDir string, key string) (string, error) { return "", err } - color.Red("find %v", services) - // Check if the key exists in the services map groupedServices, exists := services[key] if !exists { diff --git a/pkg/dockermi_test.go b/pkg/dockermi_test.go index c569ea5..ea6852d 100644 --- a/pkg/dockermi_test.go +++ b/pkg/dockermi_test.go @@ -51,7 +51,7 @@ func TestCreatedDockermi(t *testing.T) { // Check if the dockermi.sh file is created scriptPath := filepath.Join(currentDir, "dockermi.sh") if _, err := os.Stat(scriptPath); os.IsNotExist(err) { - t.Errorf("Expected dockermi.sh to be created, but it was not.") + t.Errorf("TestCreatedDockermi Expected dockermi.sh to be created, but it was not.") } // Clean up after test @@ -78,9 +78,9 @@ func TestFindService(t *testing.T) { servicesLength := len(services) - expectedLength := 6 + expectedLength := 10 if servicesLength != expectedLength { - t.Fatalf("Expected %v keys to be created. Created keys are: %v", expectedLength, servicesLength) + t.Fatalf("[TestFindService] Expected %v keys to be created. Created keys are: %v", expectedLength, servicesLength) } } @@ -101,9 +101,9 @@ func TestFindServiceForce(t *testing.T) { } servicesLength := len(services) - expectedLength := 9 + expectedLength := 14 if servicesLength != expectedLength { - t.Fatalf("Expected %v keys to be created. Created keys are: %v", expectedLength, servicesLength) + t.Fatalf("[TestFindServiceForce] Expected %v keys to be created. Created keys are: %v", expectedLength, servicesLength) } } @@ -118,13 +118,14 @@ func TestFindServiceByKey(t *testing.T) { t.Fatalf("Error getting current working directory: %v", err) } - services, err := dockercompose.FindServicesWithKey(projectDir) + groupedServices, err := dockercompose.FindServicesWithKey(projectDir) if err != nil { t.Fatalf("Error finding services: %v", err) } - servicesLength := len(services) - if servicesLength != 3 { - t.Fatalf("Expected 3 keys to be created. Create keys are: %v", servicesLength) + servicesLength := len(groupedServices) + expectedGroups := 2 + if servicesLength != expectedGroups { + t.Fatalf("Expected %v groupedServices to be created. Grouped keys are: %v ", expectedGroups, servicesLength) } } diff --git a/test/nginx/docker-compose.yml b/test/nginx/docker-compose.yml index 8bd0c6f..4143bb6 100644 --- a/test/nginx/docker-compose.yml +++ b/test/nginx/docker-compose.yml @@ -5,5 +5,4 @@ services: - "80:80" labels: dockermi.order: "1" - dockermi.active: "true" - dockermi.key: 'yourweb' \ No newline at end of file + dockermi.active: "true" \ No newline at end of file diff --git a/test/oldcompose/docker-compose.yml b/test/oldcompose/docker-compose.yml new file mode 100644 index 0000000..da652bf --- /dev/null +++ b/test/oldcompose/docker-compose.yml @@ -0,0 +1,6 @@ +services: + oldcompose: + image: hello-world + labels: + - "dockermi.order=2" + - "dockermi.active=true" diff --git a/test/postgres/docker-compose.yml b/test/postgres/docker-compose.yml index b7cd541..afd566c 100644 --- a/test/postgres/docker-compose.yml +++ b/test/postgres/docker-compose.yml @@ -5,5 +5,4 @@ services: - "5432:5432" labels: dockermi.order: "1" - dockermi.active: "true" - dockermi.key: "myweb" \ No newline at end of file + dockermi.active: "true" \ No newline at end of file diff --git a/test/withkeys1/docker-compose.yml b/test/withkeys1/docker-compose.yml new file mode 100644 index 0000000..7a2a713 --- /dev/null +++ b/test/withkeys1/docker-compose.yml @@ -0,0 +1,14 @@ +services: + servicewithkey1x: + image: hello-world + labels: + dockermi.order: "1" + dockermi.active: "true" + dockermi.key: "key1" + + servicewithkey1xx: + image: hello-world + labels: + dockermi.order: "2" + dockermi.active: "true" + dockermi.key: "key1" diff --git a/test/withkeys2/docker-compose.yml b/test/withkeys2/docker-compose.yml new file mode 100644 index 0000000..d183a27 --- /dev/null +++ b/test/withkeys2/docker-compose.yml @@ -0,0 +1,14 @@ +services: + servicewithkey2x: + image: hello-world + labels: + dockermi.order: "1" + dockermi.active: "false" # This service is not active + dockermi.key: "key2" + + servicewithkey2xx: + image: hello-world + labels: + dockermi.order: "2" + dockermi.active: "true" + dockermi.key: "key2" diff --git a/types/internal.go b/types/internal.go index 2d83266..d2102ba 100644 --- a/types/internal.go +++ b/types/internal.go @@ -12,9 +12,9 @@ type ServiceScriptReturn []ServiceScript // Service represents a service in the docker-compose.yml file. type Service struct { - Name string - // Image string `yaml:"image"` - // Ports []string `yaml:"ports"` + Name string + Image string `yaml:"image"` + Ports []string `yaml:"ports"` Labels map[string]string `yaml:"labels"` }