in cmd/go/functions_framework/main.go [326:415]
func createMainVendored(ctx *gcp.Context, fn fnInfo) error {
l, err := ctx.Layer(gopathLayerName, gcp.BuildLayer)
if err != nil {
return fmt.Errorf("creating %v layer: %w", gopathLayerName, err)
}
gopath := ctx.ApplicationRoot()
gopathSrc := filepath.Join(gopath, "src")
if err := ctx.MkdirAll(gopathSrc, 0755); err != nil {
return err
}
l.BuildEnvironment.Override(env.Buildable, appModule+"/main")
l.BuildEnvironment.Override("GOPATH", gopath)
l.BuildEnvironment.Override("GO111MODULE", "auto")
if err := ctx.Setenv("GOPATH", gopath); err != nil {
return err
}
appPath := filepath.Join(gopathSrc, appModule, "main")
if err := ctx.MkdirAll(appPath, 0755); err != nil {
return err
}
// We move the function source (including any vendored deps) into GOPATH.
if err := ctx.Rename(fn.Source, filepath.Join(gopathSrc, fn.Package)); err != nil {
return err
}
fnVendoredPath := filepath.Join(gopathSrc, fn.Package, "vendor")
fnFrameworkVendoredPath := filepath.Join(fnVendoredPath, functionsFrameworkPackage)
fnFrameworkVendoredPathExists, err := ctx.FileExists(fnFrameworkVendoredPath)
if err != nil {
return err
}
// Use v0.0.0 as the requested version for go.mod-less vendored builds, since we don't know and
// can't really tell. This won't matter for Go 1.14+, since for those we'll have a go.mod file
// regardless.
requestedFrameworkVersion := "v0.0.0"
injected := false
if fnFrameworkVendoredPathExists {
ctx.Logf("Found function with vendored dependencies including functions-framework")
if _, err := ctx.Exec([]string{"cp", "-r", fnVendoredPath, appPath}, gcp.WithUserTimingAttribution); err != nil {
return err
}
} else {
// If the framework isn't in the user-provided vendor directory, we need to fetch it ourselves.
ctx.Logf("Found function with vendored dependencies excluding functions-framework")
if err := cloudfunctions.AssertFrameworkInjectionAllowed(); err != nil {
return err
}
// Install the functions framework. Use `go mod vendor` to do this because that allows the
// versions of all of the framework's dependencies to be pinned as specified in the framework's
// go.mod. Using `go get` -- the usual way to install packages in GOPATH -- downloads each
// repository at HEAD, which can lead to breakages.
ctx.Warnf("Your vendored dependencies don't contain the functions-framework (%s) so a version will be auto-injected. Versioning conflicts might cause unexpected issues or crashes with your function. Fix this by adding a dependency on functions-framework (%s) and vendoring again.", functionsFrameworkPackage, functionsFrameworkPackage)
ffDepsDir, err := ctx.TempDir("ffdeps")
if err != nil {
return fmt.Errorf("creating temp directory: %w", err)
}
cvt := filepath.Join(ctx.BuildpackRoot(), "converter", "without-framework")
cmd := []string{
fmt.Sprintf("cp --archive %s/. %s", cvt, ffDepsDir),
// The only dependency is the functions framework.
fmt.Sprintf("go mod edit -require %s@%s", functionsFrameworkModule, functionsFrameworkVersion),
// Download dependencies and generate the go.sum file.
"go mod tidy",
// Prepare the vendor folder.
"go mod vendor",
// Copy the contents of the vendor dir into GOPATH/src.
fmt.Sprintf("cp --archive vendor/. %s", gopathSrc),
}
if _, err := golang.ExecWithGoproxyFallback(ctx, []string{"/bin/bash", "-c", strings.Join(cmd, " && ")}, gcp.WithWorkDir(ffDepsDir), gcp.WithUserAttribution); err != nil {
return fmt.Errorf("running command chain: %w", err)
}
// Since the user didn't pin it, we want the current version of the framework.
requestedFrameworkVersion = functionsFrameworkVersion
injected = true
}
cloudfunctions.AddFrameworkVersionLabel(ctx, &cloudfunctions.FrameworkVersionInfo{
Runtime: "go",
Version: requestedFrameworkVersion,
Injected: injected,
})
return createMainGoFile(ctx, fn, filepath.Join(appPath, "main.go"), requestedFrameworkVersion)
}