Skip to content

Commit

Permalink
ignore failure parsing yaml file when looking for project name
Browse files Browse the repository at this point in the history
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
  • Loading branch information
ndeloof committed Feb 16, 2024
1 parent ede4e8e commit fa15db7
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 53 deletions.
108 changes: 55 additions & 53 deletions loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,18 +305,17 @@ func LoadWithContext(ctx context.Context, configDetails types.ConfigDetails, opt
}
opts.ResourceLoaders = append(opts.ResourceLoaders, localResourceLoader{configDetails.WorkingDir})

projectName, err := projectName(configDetails, opts)
err := projectName(configDetails, opts)
if err != nil {
return nil, err
}
opts.projectName = projectName

// TODO(milas): this should probably ALWAYS set (overriding any existing)
if _, ok := configDetails.Environment[consts.ComposeProjectName]; !ok && projectName != "" {
if _, ok := configDetails.Environment[consts.ComposeProjectName]; !ok && opts.projectName != "" {
if configDetails.Environment == nil {
configDetails.Environment = map[string]string{}
}
configDetails.Environment[consts.ComposeProjectName] = projectName
configDetails.Environment[consts.ComposeProjectName] = opts.projectName
}

return load(ctx, configDetails, opts, nil)
Expand All @@ -329,7 +328,7 @@ func loadYamlModel(ctx context.Context, config types.ConfigDetails, opts *Option
)
for _, file := range config.ConfigFiles {
fctx := context.WithValue(ctx, consts.ComposeFileKey{}, file.Filename)
if len(file.Content) == 0 && file.Config == nil {
if file.Content == nil && file.Config == nil {
content, err := os.ReadFile(file.Filename)
if err != nil {
return nil, err
Expand Down Expand Up @@ -477,6 +476,10 @@ func load(ctx context.Context, configDetails types.ConfigDetails, opts *Options,
return nil, errors.New("empty compose file")
}

if opts.projectName == "" {
return nil, errors.New("project name must not be empty")
}

project := &types.Project{
Name: opts.projectName,
WorkingDir: configDetails.WorkingDir,
Expand Down Expand Up @@ -544,69 +547,68 @@ func InvalidProjectNameErr(v string) error {
//
// TODO(milas): restructure loading so that we don't need to re-parse the YAML
// here, as it's both wasteful and makes this code error-prone.
func projectName(details types.ConfigDetails, opts *Options) (string, error) {
projectName, projectNameImperativelySet := opts.GetProjectName()
func projectName(details types.ConfigDetails, opts *Options) error {
if opts.projectNameImperativelySet {
if NormalizeProjectName(opts.projectName) != opts.projectName {
return InvalidProjectNameErr(opts.projectName)
}
return nil
}

type named struct {
Name string `yaml:"name"`
}

// if user did NOT provide a name explicitly, then see if one is defined
// in any of the config files
if !projectNameImperativelySet {
var pjNameFromConfigFile string
for _, configFile := range details.ConfigFiles {
content := configFile.Content
if content == nil {
// This can be hit when Filename is set but Content is not. One
// example is when using ToConfigFiles().
d, err := os.ReadFile(configFile.Filename)
if err != nil {
return "", fmt.Errorf("failed to read file %q: %w", configFile.Filename, err)
}
content = d
var pjNameFromConfigFile string
for _, configFile := range details.ConfigFiles {
content := configFile.Content
if content == nil {
// This can be hit when Filename is set but Content is not. One
// example is when using ToConfigFiles().
d, err := os.ReadFile(configFile.Filename)
if err != nil {
return fmt.Errorf("failed to read file %q: %w", configFile.Filename, err)
}
content = d
configFile.Content = d
}
var n named
r := bytes.NewReader(content)
decoder := yaml.NewDecoder(r)
for {
err := decoder.Decode(&n)
if err != nil && errors.Is(err, io.EOF) {
break
}
yml, err := ParseYAML(content)
if err != nil {
// HACK: the way that loading is currently structured, this is
// a duplicative parse just for the `name`. if it fails, we
// give up but don't return the error, knowing that it'll get
// caught downstream for us
return "", nil
}
if val, ok := yml["name"]; ok && val != "" {
sVal, ok := val.(string)
if !ok {
// HACK: see above - this is a temporary parsed version
// that hasn't been schema-validated, but we don't want
// to be the ones to actually report that, so give up,
// knowing that it'll get caught downstream for us
return "", nil
}
pjNameFromConfigFile = sVal
break
}
}
if !opts.SkipInterpolation {
interpolated, err := interp.Interpolate(
map[string]interface{}{"name": pjNameFromConfigFile},
*opts.Interpolate,
)
if err != nil {
return "", err
if n.Name != "" {
pjNameFromConfigFile = n.Name
}
pjNameFromConfigFile = interpolated["name"].(string)
}
pjNameFromConfigFile = NormalizeProjectName(pjNameFromConfigFile)
if pjNameFromConfigFile != "" {
projectName = pjNameFromConfigFile
}
}

if projectName == "" {
return "", errors.New("project name must not be empty")
if !opts.SkipInterpolation {
interpolated, err := interp.Interpolate(
map[string]interface{}{"name": pjNameFromConfigFile},
*opts.Interpolate,
)
if err != nil {
return err
}
pjNameFromConfigFile = interpolated["name"].(string)
}

if NormalizeProjectName(projectName) != projectName {
return "", InvalidProjectNameErr(projectName)
pjNameFromConfigFile = NormalizeProjectName(pjNameFromConfigFile)
if pjNameFromConfigFile != "" {
opts.projectName = pjNameFromConfigFile
}

return projectName, nil
return nil
}

func NormalizeProjectName(s string) string {
Expand Down
24 changes: 24 additions & 0 deletions loader/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3084,3 +3084,27 @@ services:
assert.Check(t, ok)
assert.Equal(t, magic.Foo, "bar")
}

func TestLoadWithEmptyFile(t *testing.T) {
yaml := `
name: test-with-empty-file
services:
test:
image: foo
`

p, err := LoadWithContext(context.Background(), types.ConfigDetails{
ConfigFiles: []types.ConfigFile{
{
Filename: "(inlined)",
Content: []byte(yaml),
},
{
Filename: "(override)",
Content: []byte(""),
},
},
})
assert.NilError(t, err)
assert.Equal(t, p.Name, "test-with-empty-file")
}

0 comments on commit fa15db7

Please sign in to comment.