@@ -19,6 +19,7 @@ package helm
19
19
import (
20
20
"context"
21
21
"fmt"
22
+ "net/url"
22
23
"os"
23
24
"path/filepath"
24
25
"strings"
@@ -30,22 +31,35 @@ import (
30
31
"helm.sh/helm/v3/pkg/chart/loader"
31
32
)
32
33
33
- // DependencyWithRepository is a container for a dependency and its respective
34
- // repository
34
+ // DependencyWithRepository is a container for a Helm chart dependency
35
+ // and its respective repository.
35
36
type DependencyWithRepository struct {
37
+ // Dependency holds the reference to a chart.Chart dependency.
36
38
Dependency * helmchart.Dependency
37
- Repo * ChartRepository
39
+ // Repository is the ChartRepository the dependency should be
40
+ // available at and can be downloaded from. If there is none,
41
+ // a local ('file://') dependency is assumed.
42
+ Repository * ChartRepository
38
43
}
39
44
40
- // DependencyManager manages dependencies for helm charts
45
+ // DependencyManager manages dependencies for a Helm chart.
41
46
type DependencyManager struct {
42
- BaseDir string
43
- ChartPath string
44
- Chart * helmchart.Chart
47
+ // WorkingDir is the chroot path for dependency manager operations,
48
+ // Dependencies that hold a local (relative) path reference are not
49
+ // allowed to traverse outside this directory.
50
+ WorkingDir string
51
+ // ChartPath is the path of the Chart relative to the WorkingDir,
52
+ // the combination of the WorkingDir and ChartPath is used to
53
+ // determine the absolute path of a local dependency.
54
+ ChartPath string
55
+ // Chart holds the loaded chart.Chart from the ChartPath.
56
+ Chart * helmchart.Chart
57
+ // Dependencies contains a list of dependencies, and the respective
58
+ // repository the dependency can be found at.
45
59
Dependencies []* DependencyWithRepository
46
60
}
47
61
48
- // Build compiles and builds the chart dependencies
62
+ // Build compiles and builds the dependencies of the Chart.
49
63
func (dm * DependencyManager ) Build (ctx context.Context ) error {
50
64
if len (dm .Dependencies ) == 0 {
51
65
return nil
@@ -60,85 +74,90 @@ func (dm *DependencyManager) Build(ctx context.Context) error {
60
74
default :
61
75
}
62
76
63
- var (
64
- ch * helmchart.Chart
65
- err error
66
- )
67
- if strings .HasPrefix (item .Dependency .Repository , "file://" ) {
68
- ch , err = chartForLocalDependency (item .Dependency , dm .BaseDir , dm .ChartPath )
69
- } else {
70
- ch , err = chartForRemoteDependency (item .Dependency , item .Repo )
71
- }
72
- if err != nil {
73
- return err
77
+ var err error
78
+ switch item .Repository {
79
+ case nil :
80
+ err = dm .addLocalDependency (item )
81
+ default :
82
+ err = dm .addRemoteDependency (item )
74
83
}
75
- dm .Chart .AddDependency (ch )
76
- return nil
84
+ return err
77
85
})
78
86
}
79
87
80
88
return errs .Wait ()
81
89
}
82
90
83
- func chartForLocalDependency (dep * helmchart.Dependency , baseDir , chartPath string ) (* helmchart.Chart , error ) {
84
- origPath , err := securejoin .SecureJoin (baseDir ,
85
- filepath .Join (strings .TrimPrefix (chartPath , baseDir ), strings .TrimPrefix (dep .Repository , "file://" )))
91
+ func (dm * DependencyManager ) addLocalDependency (dpr * DependencyWithRepository ) error {
92
+ sLocalChartPath , err := dm .secureLocalChartPath (dpr )
86
93
if err != nil {
87
- return nil , err
94
+ return err
88
95
}
89
96
90
- if _ , err := os .Stat (origPath ); os .IsNotExist (err ) {
91
- err := fmt .Errorf ("chart path %s not found: %w" , origPath , err )
92
- return nil , err
93
- } else if err != nil {
94
- return nil , err
97
+ if _ , err := os .Stat (sLocalChartPath ); err != nil {
98
+ if os .IsNotExist (err ) {
99
+ return fmt .Errorf ("no chart found at '%s' (reference '%s') for dependency '%s'" ,
100
+ strings .TrimPrefix (sLocalChartPath , dm .WorkingDir ), dpr .Dependency .Repository , dpr .Dependency .Name )
101
+ }
102
+ return err
95
103
}
96
104
97
- ch , err := loader .Load (origPath )
105
+ ch , err := loader .Load (sLocalChartPath )
98
106
if err != nil {
99
- return nil , err
107
+ return err
100
108
}
101
109
102
- constraint , err := semver .NewConstraint (dep .Version )
110
+ constraint , err := semver .NewConstraint (dpr . Dependency .Version )
103
111
if err != nil {
104
- err := fmt .Errorf ("dependency %s has an invalid version/constraint format: %w" , dep .Name , err )
105
- return nil , err
112
+ err := fmt .Errorf ("dependency '%s' has an invalid version/constraint format: %w" , dpr . Dependency .Name , err )
113
+ return err
106
114
}
107
115
108
116
v , err := semver .NewVersion (ch .Metadata .Version )
109
117
if err != nil {
110
- return nil , err
118
+ return err
111
119
}
112
120
113
121
if ! constraint .Check (v ) {
114
- err = fmt .Errorf ("can't get a valid version for dependency %s " , dep .Name )
115
- return nil , err
122
+ err = fmt .Errorf ("can't get a valid version for dependency '%s' " , dpr . Dependency .Name )
123
+ return err
116
124
}
117
125
118
- return ch , nil
126
+ dm .Chart .AddDependency (ch )
127
+ return nil
119
128
}
120
129
121
- func chartForRemoteDependency ( dep * helmchart. Dependency , chartRepo * ChartRepository ) ( * helmchart. Chart , error ) {
122
- if chartRepo == nil {
123
- return nil , fmt .Errorf ("chartrepo should not be nil" )
130
+ func ( dm * DependencyManager ) addRemoteDependency ( dpr * DependencyWithRepository ) error {
131
+ if dpr . Repository == nil {
132
+ return fmt .Errorf ("no ChartRepository given for '%s' dependency" , dpr . Dependency . Name )
124
133
}
125
134
126
- // Lookup the chart version in the chart repository index
127
- chartVer , err := chartRepo .Get (dep .Name , dep .Version )
135
+ chartVer , err := dpr .Repository .Get (dpr .Dependency .Name , dpr .Dependency .Version )
128
136
if err != nil {
129
- return nil , err
137
+ return err
130
138
}
131
139
132
- // Download chart
133
- res , err := chartRepo .DownloadChart (chartVer )
140
+ res , err := dpr .Repository .DownloadChart (chartVer )
134
141
if err != nil {
135
- return nil , err
142
+ return err
136
143
}
137
144
138
145
ch , err := loader .LoadArchive (res )
139
146
if err != nil {
140
- return nil , err
147
+ return err
141
148
}
142
149
143
- return ch , nil
150
+ dm .Chart .AddDependency (ch )
151
+ return nil
152
+ }
153
+
154
+ func (dm * DependencyManager ) secureLocalChartPath (dep * DependencyWithRepository ) (string , error ) {
155
+ localUrl , err := url .Parse (dep .Dependency .Repository )
156
+ if err != nil {
157
+ return "" , fmt .Errorf ("failed to parse alleged local chart reference: %w" , err )
158
+ }
159
+ if localUrl .Scheme != "file" {
160
+ return "" , fmt .Errorf ("'%s' is not a local chart reference" , dep .Dependency .Repository )
161
+ }
162
+ return securejoin .SecureJoin (dm .WorkingDir , filepath .Join (dm .ChartPath , localUrl .Host , localUrl .Path ))
144
163
}
0 commit comments