Skip to content

[package outputs] generate buildInputs for package-outputs in flake #1721

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

Merged
merged 3 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions internal/devpkg/narinfo_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ func (p *Package) IsInBinaryCache() (bool, error) {
if p.PatchGlibc {
return false, nil
}
// Packages with non-default outputs are not to be taken from the binary cache.
if len(p.Outputs) > 0 {
return false, nil
}
if eligible, err := p.isEligibleForBinaryCache(); err != nil {
return false, err
} else if !eligible {
Expand Down
6 changes: 6 additions & 0 deletions internal/devpkg/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ type Package struct {
// example: github:nixos/nixpkgs/5233fd2ba76a3accb5aaa999c00509a11fd0793c#hello
Raw string

// Outputs is a list of outputs to build from the package's derivation.
// If empty, the default output is used.
Outputs []string

// PatchGlibc applies a function to the package's derivation that
// patches any ELF binaries to use the latest version of nixpkgs#glibc.
PatchGlibc bool
Expand Down Expand Up @@ -113,6 +117,7 @@ func PackagesFromConfig(config *devconfig.Config, l lock.Locker) []*Package {
pkg := newPackage(cfgPkg.VersionedName(), cfgPkg.IsEnabledOnPlatform(), l)
pkg.DisablePlugin = cfgPkg.DisablePlugin
pkg.PatchGlibc = cfgPkg.PatchGlibc && nix.SystemIsLinux()
pkg.Outputs = cfgPkg.Outputs
result = append(result, pkg)
}
return result
Expand All @@ -126,6 +131,7 @@ func PackageFromStringWithOptions(raw string, locker lock.Locker, opts devopt.Ad
pkg := PackageFromStringWithDefaults(raw, locker)
pkg.DisablePlugin = opts.DisablePlugin
pkg.PatchGlibc = opts.PatchGlibc
pkg.Outputs = opts.Outputs
return pkg
}

Expand Down
48 changes: 47 additions & 1 deletion internal/shellgen/flake_input.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package shellgen

import (
"context"
"errors"
"runtime/trace"
"slices"
"strings"
Expand Down Expand Up @@ -50,9 +51,54 @@ func (f *flakeInput) PkgImportName() string {
return f.Name + "-pkgs"
}

type SymlinkJoin struct {
Name string
Paths []string
}

// BuildInputsForSymlinkJoin returns a list of SymlinkJoin objects that can be used
// as the buildInput. Used for packages that have non-default outputs that need to
// be combined into a single buildInput.
func (f *flakeInput) BuildInputsForSymlinkJoin() ([]*SymlinkJoin, error) {
joins := []*SymlinkJoin{}
for _, pkg := range f.Packages {
// skip packages that have no non-default outputs
if len(pkg.Outputs) == 0 {
continue
}

attributePath, err := pkg.FullPackageAttributePath()
if err != nil {
return nil, err
}

if pkg.PatchGlibc {
return nil, errors.New("patch_glibc is not yet supported for packages with non-default outputs")
}
joins = append(joins, &SymlinkJoin{
Name: pkg.String() + "-combined",
Paths: lo.Map(pkg.Outputs, func(output string, _ int) string {
if !f.IsNixpkgs() {
return f.Name + "." + attributePath + "." + output
}
parts := strings.Split(attributePath, ".")
return f.PkgImportName() + "." + strings.Join(parts[2:], ".") + "." + output
}),
})
}
return joins, nil
}

func (f *flakeInput) BuildInputs() ([]string, error) {
var err error
attributePaths := lo.Map(f.Packages, func(pkg *devpkg.Package, _ int) string {

// Filter out packages that have non-default outputs
// These are handled in BuildInputsForSymlinkJoin
packages := lo.Filter(f.Packages, func(pkg *devpkg.Package, _ int) bool {
return len(pkg.Outputs) == 0
})

attributePaths := lo.Map(packages, func(pkg *devpkg.Package, _ int) string {
attributePath, attributePathErr := pkg.FullPackageAttributePath()
if attributePathErr != nil {
err = attributePathErr
Expand Down
2 changes: 1 addition & 1 deletion internal/shellgen/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var tmplFS embed.FS
// devbox.PrintEnv, which is the core function from which devbox shell/run/direnv
// functionality is derived.
func GenerateForPrintEnv(ctx context.Context, devbox devboxer) error {
defer trace.StartRegion(ctx, "generateShellFiles").End()
defer trace.StartRegion(ctx, "GenerateForPrintEnv").End()

plan, err := newFlakePlan(ctx, devbox)
if err != nil {
Expand Down
12 changes: 11 additions & 1 deletion internal/shellgen/tmpl/flake_remove_nixpkgs.nix.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,17 @@
})
{{- end }}
{{- end }}
{{- range .FlakeInputs }}
{{- range $_, $flakeInput := .FlakeInputs }}
{{- range .BuildInputsForSymlinkJoin }}
(pkgs.symlinkJoin {
name = "{{.Name}}";
paths = [
{{- range .Paths }}
{{.}}
{{- end }}
];
})
{{- end }}
{{- range .BuildInputs }}
{{.}}
{{- end }}
Expand Down
32 changes: 32 additions & 0 deletions testscripts/add/add_outputs.test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Testscript to add packages with non-default outputs

exec devbox init

# Add prometheus with default outputs. It will not have promtool.
exec devbox add prometheus
exec devbox run -- prometheus --version
! exec devbox run -- promtool --version

# Add prometheus with cli and out outputs. It will have promtool as well.
exec devbox add prometheus --outputs cli,out
json.superset devbox.json expected_devbox.json
exec devbox run -- promtool --version
exec devbox run -- prometheus --version



-- devbox.json --
{
"packages": [
]
}

-- expected_devbox.json --
{
"packages": {
"prometheus": {
"version": "latest",
"outputs": ["cli", "out"]
}
}
}