github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/pkg/project/project.go (about)

     1  package project
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"github.com/BurntSushi/toml"
    10  	"github.com/pkg/errors"
    11  
    12  	"github.com/buildpacks/pack/pkg/logging"
    13  	"github.com/buildpacks/pack/pkg/project/types"
    14  	v01 "github.com/buildpacks/pack/pkg/project/v01"
    15  	v02 "github.com/buildpacks/pack/pkg/project/v02"
    16  )
    17  
    18  type Project struct {
    19  	Version string `toml:"schema-version"`
    20  }
    21  
    22  type VersionDescriptor struct {
    23  	Project Project `toml:"_"`
    24  }
    25  
    26  var parsers = map[string]func(string) (types.Descriptor, toml.MetaData, error){
    27  	"0.1": v01.NewDescriptor,
    28  	"0.2": v02.NewDescriptor,
    29  }
    30  
    31  func ReadProjectDescriptor(pathToFile string, logger logging.Logger) (types.Descriptor, error) {
    32  	projectTomlContents, err := os.ReadFile(filepath.Clean(pathToFile))
    33  	if err != nil {
    34  		return types.Descriptor{}, err
    35  	}
    36  
    37  	var versionDescriptor struct {
    38  		Project struct {
    39  			Version string `toml:"schema-version"`
    40  		} `toml:"_"`
    41  	}
    42  
    43  	_, err = toml.Decode(string(projectTomlContents), &versionDescriptor)
    44  	if err != nil {
    45  		return types.Descriptor{}, errors.Wrapf(err, "parsing schema version")
    46  	}
    47  
    48  	version := versionDescriptor.Project.Version
    49  	if version == "" {
    50  		logger.Warn("No schema version declared in project.toml, defaulting to schema version 0.1")
    51  		version = "0.1"
    52  	}
    53  
    54  	if _, ok := parsers[version]; !ok {
    55  		return types.Descriptor{}, fmt.Errorf("unknown project descriptor schema version %s", version)
    56  	}
    57  
    58  	descriptor, tomlMetaData, err := parsers[version](string(projectTomlContents))
    59  	if err != nil {
    60  		return types.Descriptor{}, err
    61  	}
    62  
    63  	warnIfTomlContainsKeysNotSupportedBySchema(version, tomlMetaData, logger)
    64  
    65  	return descriptor, validate(descriptor)
    66  }
    67  
    68  func warnIfTomlContainsKeysNotSupportedBySchema(schemaVersion string, tomlMetaData toml.MetaData, logger logging.Logger) {
    69  	unsupportedKeys := []string{}
    70  
    71  	// filter out any keys from [_]
    72  	for _, undecodedKey := range tomlMetaData.Undecoded() {
    73  		keyName := undecodedKey.String()
    74  		if keyName != "_" && !strings.HasPrefix(keyName, "_.schema-version") {
    75  			unsupportedKeys = append(unsupportedKeys, keyName)
    76  		}
    77  	}
    78  
    79  	if len(unsupportedKeys) != 0 {
    80  		logger.Warnf("The following keys declared in project.toml are not supported in schema version %s:\n", schemaVersion)
    81  		for _, unsupportedKey := range unsupportedKeys {
    82  			logger.Warnf("- %s\n", unsupportedKey)
    83  		}
    84  		logger.Warn("The above keys will be ignored. If this is not intentional, maybe try updating your schema version.\n")
    85  	}
    86  }
    87  
    88  func validate(p types.Descriptor) error {
    89  	if p.Build.Exclude != nil && p.Build.Include != nil {
    90  		return errors.New("project.toml: cannot have both include and exclude defined")
    91  	}
    92  
    93  	if len(p.Project.Licenses) > 0 {
    94  		for _, license := range p.Project.Licenses {
    95  			if license.Type == "" && license.URI == "" {
    96  				return errors.New("project.toml: must have a type or uri defined for each license")
    97  			}
    98  		}
    99  	}
   100  
   101  	for _, bp := range p.Build.Buildpacks {
   102  		if bp.ID == "" && bp.URI == "" {
   103  			return errors.New("project.toml: buildpacks must have an id or url defined")
   104  		}
   105  		if bp.URI != "" && bp.Version != "" {
   106  			return errors.New("project.toml: buildpacks cannot have both uri and version defined")
   107  		}
   108  	}
   109  
   110  	return nil
   111  }