func ComposerInstall()

in pkg/php/php.go [153:227]


func ComposerInstall(ctx *gcp.Context, cacheTag string) (*libcnb.Layer, error) {
	var flags []string
	if composerArgs := os.Getenv(ComposerArgsEnv); composerArgs != "" {
		flags = strings.Split(composerArgs, " ")
	} else {
		// We don't install dev dependencies (i.e. we pass --no-dev to composer) because doing so has caused
		// problems for customers in the past. For more information see these links:
		//   https://github.com/GoogleCloudPlatform/php-docs-samples/issues/736
		//   https://github.com/GoogleCloudPlatform/runtimes-common/pull/763
		//   https://github.com/GoogleCloudPlatform/runtimes-common/commit/6c4970f609d80f9436ac58ae272cfcc6bcd57143
		flags = []string{"--no-dev", "--no-progress", "--no-interaction", "--optimize-autoloader"}
	}

	if err := ctx.RemoveAll(Vendor); err != nil {
		return nil, err
	}
	l, err := ctx.Layer("composer", gcp.CacheLayer)
	if err != nil {
		return nil, fmt.Errorf("creating layer: %w", err)
	}
	layerVendor := filepath.Join(l.Path, Vendor)

	composerLockExists, err := ctx.FileExists(composerLock)
	if err != nil {
		return nil, err
	}
	// If there's no composer.lock then don't attempt to cache. We'd have to cache using composer.json,
	// which could result in outdated dependencies if the version constraints in composer.json resolve
	// to newer versions in the future.
	if !composerLockExists {
		ctx.Logf("*** Improve build performance by generating and committing %s.", composerLock)
		if err := composerInstall(ctx, flags); err != nil {
			return nil, err
		}
		return l, nil
	}

	currentPHPVersion, err := version(ctx)
	if err != nil {
		return nil, err
	}
	hash, cached, err := cache.HashAndCheck(ctx, l, dependencyHashKey, cache.WithFiles(composerJSON, composerLock), cache.WithStrings(currentPHPVersion))
	if err != nil {
		return nil, err
	}

	if cached {
		// PHP expects the vendor/ directory to be in the application directory.
		if _, err := ctx.Exec([]string{"cp", "--archive", layerVendor, Vendor}, gcp.WithUserTimingAttribution); err != nil {
			return nil, err
		}
	} else {
		ctx.Logf("Installing application dependencies.")
		// Clear layer so we don't end up with outdated dependencies (e.g. something was removed from composer.json).
		if err := ctx.ClearLayer(l); err != nil {
			return nil, fmt.Errorf("clearing layer %q: %w", l.Name, err)
		}
		if err := composerInstall(ctx, flags); err != nil {
			return nil, err
		}

		// Update the layer metadata.
		cache.Add(ctx, l, dependencyHashKey, hash)

		// Ensure vendor exists even if no dependencies were installed.
		if err := ctx.MkdirAll(Vendor, 0755); err != nil {
			return nil, err
		}
		if _, err := ctx.Exec([]string{"cp", "--archive", Vendor, layerVendor}, gcp.WithUserTimingAttribution); err != nil {
			return nil, err
		}
	}

	return l, nil
}