Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Microsoft SDK Hive directly #366

Merged
merged 5 commits into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 16 additions & 43 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/Masterminds/semver"
"github.com/paketo-buildpacks/packit/v2"
"github.com/paketo-buildpacks/packit/v2/chronos"
"github.com/paketo-buildpacks/packit/v2/fs"
"github.com/paketo-buildpacks/packit/v2/postal"
"github.com/paketo-buildpacks/packit/v2/sbom"
"github.com/paketo-buildpacks/packit/v2/scribe"
Expand All @@ -20,32 +21,20 @@ type EntryResolver interface {
MergeLayerTypes(name string, entries []packit.BuildpackPlanEntry) (launch, build bool)
}

//go:generate faux --interface DependencyMapper --output fakes/dependency_mapper.go
type DependencyMapper interface {
FindCorrespondingVersion(path, versionKey string) (string, error)
}

//go:generate faux --interface DependencyManager --output fakes/dependency_manager.go
type DependencyManager interface {
Resolve(path, id, version, stack string) (postal.Dependency, error)
Deliver(dependency postal.Dependency, cnbPath, layerPath, platformPath string) error
GenerateBillOfMaterials(dependencies ...postal.Dependency) []packit.BOMEntry
}

//go:generate faux --interface DotnetSymlinker --output fakes/dotnet_symlinker.go
type DotnetSymlinker interface {
Link(workingDir, layerPath string) error
}

//go:generate faux --interface SBOMGenerator --output fakes/sbom_generator.go
type SBOMGenerator interface {
GenerateFromDependency(dependency postal.Dependency, dir string) (sbom.SBOM, error)
}

func Build(entryResolver EntryResolver,
dependencyMapper DependencyMapper,
dependencyManager DependencyManager,
dotnetSymlinker DotnetSymlinker,
sbomGenerator SBOMGenerator,
logger scribe.Emitter,
clock chronos.Clock,
Expand All @@ -54,21 +43,6 @@ func Build(entryResolver EntryResolver,
logger.Title("%s %s", context.BuildpackInfo.Name, context.BuildpackInfo.Version)
logger.Process("Resolving .NET Core SDK version")

if runtimeVersion, ok := os.LookupEnv("RUNTIME_VERSION"); ok {
sdkVersion, err := dependencyMapper.FindCorrespondingVersion(filepath.Join(context.CNBPath, "buildpack.toml"), runtimeVersion)
if err != nil {
return packit.BuildResult{}, err
}

context.Plan.Entries = append(context.Plan.Entries, packit.BuildpackPlanEntry{
Name: DotnetDependency,
Metadata: map[string]interface{}{
"version-source": "RUNTIME_VERSION",
"version": sdkVersion,
},
})
}

planEntry, entries := entryResolver.Resolve(DotnetDependency, context.Plan.Entries, Priorities)
logger.Candidates(entries)

Expand Down Expand Up @@ -97,9 +71,12 @@ func Build(entryResolver EntryResolver,
if err != nil {
return packit.BuildResult{}, err
}

envLayer.Launch = true
envLayer.Build = true

err = os.MkdirAll(filepath.Join(context.WorkingDir, ".dotnet_root"), os.ModePerm)
if err != nil {
return packit.BuildResult{}, err
}

bom := dependencyManager.GenerateBillOfMaterials(sdkDependency)
launch, build := entryResolver.MergeLayerTypes(DotnetDependency, context.Plan.Entries)
Expand All @@ -119,24 +96,22 @@ func Build(entryResolver EntryResolver,
logger.Process(fmt.Sprintf("Reusing cached layer %s", sdkLayer.Path))
logger.Break()

err = dotnetSymlinker.Link(context.WorkingDir, sdkLayer.Path)
err = fs.Copy(filepath.Join(sdkLayer.Path, "dotnet"), filepath.Join(context.WorkingDir, ".dotnet_root", "dotnet"))
if err != nil {
return packit.BuildResult{}, err
}

envLayer.SharedEnv.Prepend("PATH",
filepath.Join(context.WorkingDir, ".dotnet_root"),
string(os.PathListSeparator))

envLayer.SharedEnv.Override("DOTNET_ROOT", filepath.Join(context.WorkingDir, ".dotnet_root"))
sdkLayer.BuildEnv.Prepend("PATH", sdkLayer.Path, string(os.PathListSeparator))
logger.EnvironmentVariables(sdkLayer)
envLayer.LaunchEnv.Prepend("PATH", filepath.Join(context.WorkingDir, ".dotnet_root"), string(os.PathListSeparator))
Comment on lines +104 to +106
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is setting one in the BuildEnv and the other in the LaunchEnv to prevent a case where both layers put a version of the dotnet CLI on the PATH?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite, it's more to prevent more than what's needed being available during launch. The dotnet CLI in both cases is the same. This is confusing and I would've liked to find a way to avoid doing this. The reason for this code is:

  1. The first case is in the .NET Publish case, we want the full SDK hive, so we make the entire SDK layer available on the PATH during build.
  2. The less obvious case is in the .NET Execute case (FDD case specifically), the dotnet CLI is needed at launch-time, so we just copy it into the /workspace/.dotnet_root to isolate it, and make it accessible via the PATH. This envLayer is ALWAYS marked for launch.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you can think of a nicer way to just have the dotnet CLI available at launch-time, let me know, I'm all ears.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for laying this out. That makes sense to me. I agree it's not the nicest, but I'm ok with it for now because Forest + my forthcoming proposal to expand the ASP.NET dependency + rearrange buildpack order will enable us to use the dotnet CLI that ships with ASP.NET at launch time in the future!

logger.EnvironmentVariables(envLayer)

sdkLayer.Build, sdkLayer.Launch, sdkLayer.Cache = build, launch, build || launch

return packit.BuildResult{
Layers: []packit.Layer{
sdkLayer,
envLayer,
sdkLayer,
},
Build: buildMetadata,
Launch: launchMetadata,
Expand Down Expand Up @@ -165,18 +140,16 @@ func Build(entryResolver EntryResolver,
"dependency-sha": sdkDependency.SHA256,
}

err = dotnetSymlinker.Link(context.WorkingDir, sdkLayer.Path)
err = fs.Copy(filepath.Join(sdkLayer.Path, "dotnet"), filepath.Join(context.WorkingDir, ".dotnet_root", "dotnet"))
if err != nil {
return packit.BuildResult{}, err
}

sdkLayer.Build, sdkLayer.Launch, sdkLayer.Cache = build, launch, build || launch

envLayer.SharedEnv.Prepend("PATH",
filepath.Join(context.WorkingDir, ".dotnet_root"),
string(os.PathListSeparator))

envLayer.SharedEnv.Override("DOTNET_ROOT", filepath.Join(context.WorkingDir, ".dotnet_root"))
sdkLayer.BuildEnv.Prepend("PATH", sdkLayer.Path, string(os.PathListSeparator))
logger.EnvironmentVariables(sdkLayer)
envLayer.LaunchEnv.Prepend("PATH", filepath.Join(context.WorkingDir, ".dotnet_root"), string(os.PathListSeparator))
logger.EnvironmentVariables(envLayer)

logger.GeneratingSBOM(sdkLayer.Path)
Expand All @@ -200,8 +173,8 @@ func Build(entryResolver EntryResolver,

return packit.BuildResult{
Layers: []packit.Layer{
sdkLayer,
envLayer,
sdkLayer,
},
Build: buildMetadata,
Launch: launchMetadata,
Expand Down
Loading