in code/go/internal/validator/folder_spec.go [43:190]
func (v *validator) Validate() specerrors.ValidationErrors {
var errs specerrors.ValidationErrors
files, err := fs.ReadDir(v.pkg, v.folderPath)
if err != nil {
errs = append(errs,
specerrors.NewStructuredErrorf("could not read folder [%s]: %w", v.pkg.Path(v.folderPath), err),
)
return errs
}
// This is not taking into account if the folder is for development. Enforce
// this limit in all cases to avoid having to read too many files.
if contentsLimit := v.spec.MaxTotalContents(); contentsLimit > 0 && len(files) > contentsLimit {
errs = append(errs,
specerrors.NewStructuredErrorf("folder [%s] exceeds the limit of %d files", v.pkg.Path(v.folderPath), contentsLimit),
)
return errs
}
// Don't enable beta features for packages marked as GA.
switch v.spec.Release() {
case "", "ga": // do nothing
case "beta":
if v.pkg.IsGA() {
errs = append(errs,
specerrors.NewStructuredErrorf("spec for [%s] defines beta features which can't be enabled for packages with a stable semantic version", v.pkg.Path(v.folderPath)),
)
} else {
message := fmt.Sprintf("package with non-stable semantic version and active beta features (enabled in [%s]) can't be released as stable version.", v.pkg.Path(v.folderPath))
if common.IsDefinedWarningsAsErrors() || v.pkg.SpecVersion.Major() >= 3 {
err = errors.New(message)
errs = append(errs, specerrors.NewStructuredError(err, specerrors.CodePrereleaseFeatureOnGAPackage))
} else {
log.Print("Warning: ", message)
}
}
default:
errs = append(errs, specerrors.NewStructuredErrorf("unsupport release level, supported values: beta, ga"))
}
for _, file := range files {
fileName := file.Name()
itemSpec, err := v.findItemSpec(fileName)
if err != nil {
errs = append(errs, specerrors.NewStructuredError(err, specerrors.UnassignedCode))
continue
}
if itemSpec == nil && v.spec.AdditionalContents() {
// No spec found for current folder item, but we do allow additional contents in folder.
if file.IsDir() {
if !v.spec.DevelopmentFolder() && strings.Contains(fileName, "-") {
errs = append(errs,
specerrors.NewStructuredErrorf(
`file "%s" is invalid: directory name inside package %s contains -: %s`,
v.pkg.Path(v.folderPath, fileName), v.pkg.Name, fileName),
)
}
}
continue
}
if itemSpec == nil && !v.spec.AdditionalContents() {
// No spec found for current folder item and we do not allow additional contents in folder.
errs = append(errs,
specerrors.NewStructuredErrorf("item [%s] is not allowed in folder [%s]", fileName, v.pkg.Path(v.folderPath)),
)
continue
}
if file.IsDir() {
if !itemSpec.IsDir() {
errs = append(errs,
specerrors.NewStructuredErrorf("[%s] is a folder but is expected to be a file", fileName),
)
continue
}
subFolderPath := path.Join(v.folderPath, fileName)
itemValidator := newValidatorForPath(itemSpec, v.pkg, subFolderPath)
subErrs := itemValidator.Validate()
if len(subErrs) > 0 {
errs = append(errs, subErrs...)
}
// Don't count files in development folders.
if !itemSpec.DevelopmentFolder() {
v.totalContents += itemValidator.totalContents
v.totalSize += itemValidator.totalSize
}
} else {
if itemSpec.IsDir() {
errs = append(errs,
specerrors.NewStructuredErrorf("[%s] is a file but is expected to be a folder", v.pkg.Path(fileName)),
)
continue
}
itemPath := path.Join(v.folderPath, file.Name())
itemValidationErrs := validateFile(itemSpec, v.pkg, itemPath)
for _, ive := range itemValidationErrs {
errs = append(errs,
specerrors.NewStructuredErrorf("file \"%s\" is invalid: %w", v.pkg.Path(itemPath), ive),
)
}
info, err := fs.Stat(v.pkg, itemPath)
if err != nil {
errs = append(errs,
specerrors.NewStructuredErrorf("failed to obtain file size for \"%s\": %w", v.pkg.Path(itemPath), err),
)
} else {
v.totalContents++
v.totalSize += spectypes.FileSize(info.Size())
}
}
}
if sizeLimit := v.spec.MaxTotalSize(); sizeLimit > 0 && v.totalSize > sizeLimit {
errs = append(errs,
specerrors.NewStructuredErrorf("folder [%s] exceeds the total size limit of %s", v.pkg.Path(v.folderPath), sizeLimit),
)
}
// validate that required items in spec are all accounted for
for _, itemSpec := range v.spec.Contents() {
if !itemSpec.Required() {
continue
}
fileFound, err := matchingFileExists(itemSpec, files)
if err != nil {
errs = append(errs, specerrors.NewStructuredError(err, specerrors.UnassignedCode))
continue
}
if !fileFound {
var err error
if itemSpec.Name() != "" {
err = fmt.Errorf("expecting to find [%s] %s in folder [%s]", itemSpec.Name(), itemSpec.Type(), v.pkg.Path(v.folderPath))
} else if itemSpec.Pattern() != "" {
err = fmt.Errorf("expecting to find %s matching pattern [%s] in folder [%s]", itemSpec.Type(), itemSpec.Pattern(), v.pkg.Path(v.folderPath))
}
errs = append(errs, specerrors.NewStructuredError(err, specerrors.UnassignedCode))
}
}
return errs
}