@@ -4,34 +4,95 @@ import (
44 "fmt"
55 "io"
66 "log/slog"
7+ "path/filepath"
78 "strings"
89
10+ "github.com/BurntSushi/toml"
911 "github.com/input-output-hk/catalyst-forge/lib/project/deployment/providers/kcl/client"
1012 "github.com/input-output-hk/catalyst-forge/lib/project/schema"
13+ "github.com/spf13/afero"
1114)
1215
16+ // KCLModule represents a KCL module.
17+ type KCLModule struct {
18+ Package KCLModulePackage `toml:"package"`
19+ }
20+
21+ // KCLModulePackage represents a KCL module package.
22+ type KCLModulePackage struct {
23+ Name string `toml:"name"`
24+ Edition string `toml:"edition"`
25+ Version string `toml:"version"`
26+ }
27+
1328// KCLManifestGenerator is a ManifestGenerator that uses KCL.
1429type KCLManifestGenerator struct {
1530 client client.KCLClient
31+ fs afero.Fs
1632 logger * slog.Logger
1733}
1834
1935func (g * KCLManifestGenerator ) Generate (mod schema.DeploymentModule ) ([]byte , error ) {
20- container := fmt .Sprintf ("oci://%s/%s?tag=%s" , strings .TrimSuffix (mod .Registry , "/" ), mod .Name , mod .Version )
21- conf := client.KCLModuleConfig {
22- InstanceName : mod .Instance ,
23- Namespace : mod .Namespace ,
24- Values : mod .Values ,
36+ var conf client.KCLModuleConfig
37+ var path string
38+ if mod .Path != nil {
39+ g .logger .Info ("Parsing local KCL module" , "path" , * mod .Path )
40+ kmod , err := g .parseModule (* mod .Path )
41+ if err != nil {
42+ return nil , fmt .Errorf ("failed to parse KCL module: %w" , err )
43+ }
44+
45+ path = * mod .Path
46+ conf = client.KCLModuleConfig {
47+ Instance : mod .Instance ,
48+ Name : kmod .Package .Name ,
49+ Namespace : mod .Namespace ,
50+ Values : mod .Values ,
51+ Version : kmod .Package .Version ,
52+ }
53+ } else {
54+ path = fmt .Sprintf ("oci://%s/%s?tag=%s" , strings .TrimSuffix (* mod .Registry , "/" ), * mod .Name , * mod .Version )
55+ conf = client.KCLModuleConfig {
56+ Instance : mod .Instance ,
57+ Name : * mod .Name ,
58+ Namespace : mod .Namespace ,
59+ Values : mod .Values ,
60+ Version : * mod .Version ,
61+ }
2562 }
2663
27- out , err := g .client .Run (container , conf )
64+ out , err := g .client .Run (path , conf )
2865 if err != nil {
2966 return nil , fmt .Errorf ("failed to run KCL module: %w" , err )
3067 }
3168
3269 return []byte (out ), nil
3370}
3471
72+ // parseModule parses a KCL module from the given path.
73+ func (g * KCLManifestGenerator ) parseModule (path string ) (KCLModule , error ) {
74+ modPath := filepath .Join (path , "kcl.mod" )
75+ exists , err := afero .Exists (g .fs , modPath )
76+ if err != nil {
77+ return KCLModule {}, fmt .Errorf ("failed to check if KCL module exists: %w" , err )
78+ } else if ! exists {
79+ return KCLModule {}, fmt .Errorf ("KCL module not found" )
80+ }
81+
82+ src , err := afero .ReadFile (g .fs , modPath )
83+ if err != nil {
84+ return KCLModule {}, fmt .Errorf ("failed to read KCL module: %w" , err )
85+ }
86+
87+ var mod KCLModule
88+ _ , err = toml .Decode (string (src ), & mod )
89+ if err != nil {
90+ return KCLModule {}, fmt .Errorf ("failed to decode KCL module: %w" , err )
91+ }
92+
93+ return mod , nil
94+ }
95+
3596// NewKCLManifestGenerator creates a new KCL manifest generator.
3697func NewKCLManifestGenerator (logger * slog.Logger ) * KCLManifestGenerator {
3798 if logger == nil {
@@ -40,6 +101,7 @@ func NewKCLManifestGenerator(logger *slog.Logger) *KCLManifestGenerator {
40101
41102 return & KCLManifestGenerator {
42103 client : client.KPMClient {},
104+ fs : afero .NewOsFs (),
43105 logger : logger ,
44106 }
45107}
0 commit comments