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

     1  package client
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/BurntSushi/toml"
     9  
    10  	"github.com/buildpacks/lifecycle/api"
    11  
    12  	"github.com/buildpacks/pack/internal/style"
    13  	"github.com/buildpacks/pack/pkg/dist"
    14  )
    15  
    16  var (
    17  	bashBinBuild = `#!/usr/bin/env bash
    18  
    19  set -euo pipefail
    20  
    21  layers_dir="$1"
    22  env_dir="$2/env"
    23  plan_path="$3"
    24  
    25  exit 0
    26  `
    27  	bashBinDetect = `#!/usr/bin/env bash
    28  
    29  exit 0
    30  `
    31  )
    32  
    33  type NewBuildpackOptions struct {
    34  	// api compat version of the output buildpack artifact.
    35  	API string
    36  
    37  	// The base directory to generate assets
    38  	Path string
    39  
    40  	// The ID of the output buildpack artifact.
    41  	ID string
    42  
    43  	// version of the output buildpack artifact.
    44  	Version string
    45  
    46  	// Deprecated: The stacks this buildpack will work with
    47  	Stacks []dist.Stack
    48  
    49  	// the targets this buildpack will work with
    50  	Targets []dist.Target
    51  }
    52  
    53  func (c *Client) NewBuildpack(ctx context.Context, opts NewBuildpackOptions) error {
    54  	err := createBuildpackTOML(opts.Path, opts.ID, opts.Version, opts.API, opts.Stacks, opts.Targets, c)
    55  	if err != nil {
    56  		return err
    57  	}
    58  	return createBashBuildpack(opts.Path, c)
    59  }
    60  
    61  func createBashBuildpack(path string, c *Client) error {
    62  	if err := createBinScript(path, "build", bashBinBuild, c); err != nil {
    63  		return err
    64  	}
    65  
    66  	if err := createBinScript(path, "detect", bashBinDetect, c); err != nil {
    67  		return err
    68  	}
    69  
    70  	return nil
    71  }
    72  
    73  func createBinScript(path, name, contents string, c *Client) error {
    74  	binDir := filepath.Join(path, "bin")
    75  	binFile := filepath.Join(binDir, name)
    76  
    77  	_, err := os.Stat(binFile)
    78  	if os.IsNotExist(err) {
    79  		// The following line's comment is for gosec, it will ignore rule 301 in this case
    80  		// G301: Expect directory permissions to be 0750 or less
    81  		/* #nosec G301 */
    82  		if err := os.MkdirAll(binDir, 0755); err != nil {
    83  			return err
    84  		}
    85  		// The following line's comment is for gosec, it will ignore rule 306 in this case
    86  		// G306: Expect WriteFile permissions to be 0600 or less
    87  		/* #nosec G306 */
    88  		err = os.WriteFile(binFile, []byte(contents), 0755)
    89  		if err != nil {
    90  			return err
    91  		}
    92  
    93  		if c != nil {
    94  			c.logger.Infof("    %s  bin/%s", style.Symbol("create"), name)
    95  		}
    96  	}
    97  	return nil
    98  }
    99  
   100  func createBuildpackTOML(path, id, version, apiStr string, stacks []dist.Stack, targets []dist.Target, c *Client) error {
   101  	api, err := api.NewVersion(apiStr)
   102  	if err != nil {
   103  		return err
   104  	}
   105  
   106  	buildpackTOML := dist.BuildpackDescriptor{
   107  		WithAPI:     api,
   108  		WithStacks:  stacks,
   109  		WithTargets: targets,
   110  		WithInfo: dist.ModuleInfo{
   111  			ID:      id,
   112  			Version: version,
   113  		},
   114  	}
   115  
   116  	// The following line's comment is for gosec, it will ignore rule 301 in this case
   117  	// G301: Expect directory permissions to be 0750 or less
   118  	/* #nosec G301 */
   119  	if err := os.MkdirAll(path, 0755); err != nil {
   120  		return err
   121  	}
   122  
   123  	buildpackTOMLPath := filepath.Join(path, "buildpack.toml")
   124  	_, err = os.Stat(buildpackTOMLPath)
   125  	if os.IsNotExist(err) {
   126  		f, err := os.Create(buildpackTOMLPath)
   127  		if err != nil {
   128  			return err
   129  		}
   130  		if err := toml.NewEncoder(f).Encode(buildpackTOML); err != nil {
   131  			return err
   132  		}
   133  		defer f.Close()
   134  		if c != nil {
   135  			c.logger.Infof("    %s  buildpack.toml", style.Symbol("create"))
   136  		}
   137  	}
   138  
   139  	return nil
   140  }