diff --git a/internal/compose/port.go b/internal/compose/port.go new file mode 100644 index 00000000..ff2b0108 --- /dev/null +++ b/internal/compose/port.go @@ -0,0 +1,45 @@ +package compose + +import ( + "fmt" + "github.com/compose-spec/compose-go/v2/types" + "uncloud/internal/api" +) + +const PortsExtensionKey = "x-ports" + +type PortsSource []string + +// TransformServicesPortsExtension transforms the ports extension of all services in the project by replacing a string +// representation of each port with a parsed PortSpec. +func transformServicesPortsExtension(project *types.Project) error { + for name, service := range project.Services { + ports, ok := service.Extensions[PortsExtensionKey].(PortsSource) + if !ok { + continue + } + + specs, err := transformPortsExtension(ports) + if err != nil { + return err + } + + service.Extensions[PortsExtensionKey] = specs + project.Services[name] = service + } + + return nil +} + +func transformPortsExtension(ports PortsSource) ([]api.PortSpec, error) { + var specs []api.PortSpec + for _, port := range ports { + spec, err := api.ParsePortSpec(port) + if err != nil { + return specs, fmt.Errorf("parse port %q: %w", port, err) + } + specs = append(specs, spec) + } + + return specs, nil +} diff --git a/internal/compose/project.go b/internal/compose/project.go new file mode 100644 index 00000000..7e38f298 --- /dev/null +++ b/internal/compose/project.go @@ -0,0 +1,37 @@ +package compose + +import ( + "context" + "fmt" + composecli "github.com/compose-spec/compose-go/v2/cli" + "github.com/compose-spec/compose-go/v2/types" +) + +func LoadProject(ctx context.Context, paths []string) (*types.Project, error) { + options, err := composecli.NewProjectOptions( + paths, + // First apply os.Environment, always wins. + composecli.WithOsEnv, + // Read dot env file to populate project environment. + composecli.WithDotEnv, + // Get compose file path set by COMPOSE_FILE. + composecli.WithConfigFileEnv, + // If none was selected, get default compose.yaml file from current dir or parent folders. + composecli.WithDefaultConfigPath, + composecli.WithExtension("x-ports", PortsSource{}), + ) + if err != nil { + return nil, fmt.Errorf("create compose parser options: %w", err) + } + + project, err := options.LoadProject(ctx) + if err != nil { + return nil, err + } + + if err = transformServicesPortsExtension(project); err != nil { + return nil, err + } + + return project, nil +}