Skip to content

[nix] ensure nix is installed for generate and envsec commands #1710

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 2 commits into from
Jan 10, 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
5 changes: 3 additions & 2 deletions internal/boxcli/envsec.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ type envsecInitCmdFlags struct {

func envsecCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "envsec",
Short: "envsec commands",
Use: "envsec",
Short: "envsec commands",
PreRunE: ensureNixInstalled,
}
cmd.AddCommand(envsecInitCmd())
cmd.Hidden = true
Expand Down
7 changes: 4 additions & 3 deletions internal/boxcli/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ func generateCmd() *cobra.Command {
flags := &generateCmdFlags{}

command := &cobra.Command{
Use: "generate",
Short: "Generate supporting files for your project",
Args: cobra.MaximumNArgs(0),
Use: "generate",
Short: "Generate supporting files for your project",
Args: cobra.MaximumNArgs(0),
PersistentPreRunE: ensureNixInstalled,
}
command.AddCommand(devcontainerCmd())
command.AddCommand(dockerfileCmd())
Expand Down
22 changes: 5 additions & 17 deletions internal/boxcli/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@
package boxcli

import (
"fmt"
"os"

"github.com/samber/lo"
"github.com/spf13/cobra"
"go.jetpack.io/devbox/internal/boxcli/usererr"
"go.jetpack.io/devbox/internal/nix"
"go.jetpack.io/devbox/internal/ux"
"go.jetpack.io/devbox/internal/vercheck"
)

const nixDaemonFlag = "daemon"
Expand Down Expand Up @@ -51,24 +48,15 @@ func runInstallNixCmd(cmd *cobra.Command) error {

// ensureNixInstalled verifies that nix is installed and that it is of a supported version
func ensureNixInstalled(cmd *cobra.Command, _args []string) error {
if err := nix.EnsureNixInstalled(cmd.ErrOrStderr(), nixDaemonFlagVal(cmd)); err != nil {
return err
}

ver, err := nix.Version()
if err != nil {
return fmt.Errorf("failed to get nix version: %w", err)
}

// ensure minimum nix version installed
if vercheck.SemverCompare(ver, "2.12.0") < 0 {
return usererr.New("Devbox requires nix of version >= 2.12. Your version is %s. Please upgrade nix and try again.\n", ver)
}
return nil
return nix.EnsureNixInstalled(cmd.ErrOrStderr(), nixDaemonFlagVal(cmd))
}

// We return a closure to avoid printing the warning every time and just
// printing it if we actually need the value of the flag.
//
// TODO: devbox.Open should run nix.EnsureNixInstalled and do this logic
Copy link
Collaborator

Choose a reason for hiding this comment

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

see the PR I had shared for when I reverted this change .

To make it happen, we'll need to audit many callsites and ensure scenarios like devbox version don't end up invoking devbox.Open

from the PR, here are the callsites for devbox version that led to devbox.Open being called: https://gist.github.com/savil/0fff37124abae3d1c0088404c05a73cc

// internally. Then setup can decide if it wants to pass in the value of the
// nixDaemonFlag (if changed).
func nixDaemonFlagVal(cmd *cobra.Command) func() *bool {
return func() *bool {
if !cmd.Flags().Changed(nixDaemonFlag) {
Expand Down
11 changes: 5 additions & 6 deletions internal/devbox/devbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ func Open(opts *devopt.Opts) (*Devbox, error) {

if !opts.IgnoreWarnings &&
!legacyPackagesWarningHasBeenShown &&
// HasDeprecatedPackages required nix to be installed. Since not all
// commands require nix to be installed, only show this warning for commands
// that ensure nix.
// This warning can probably be removed soon.
nix.Ensured() &&
box.HasDeprecatedPackages() {
legacyPackagesWarningHasBeenShown = true
globalPath, err := GlobalDataPath()
Expand Down Expand Up @@ -481,12 +486,6 @@ func (d *Devbox) GenerateEnvrcFile(ctx context.Context, force bool, envFlags dev
"Remove it or use --force to overwrite it.",
)
}
// confirm .envrc doesn't exist and don't overwrite an existing .envrc
if err := nix.EnsureNixInstalled(
d.stderr, func() *bool { return lo.ToPtr(false) },
); err != nil {
return err
}

// generate all shell files to ensure we can refer to them in the .envrc script
if err := d.ensureStateIsUpToDate(ctx, ensure); err != nil {
Expand Down
39 changes: 34 additions & 5 deletions internal/nix/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ import (
"go.jetpack.io/devbox/internal/cmdutil"
"go.jetpack.io/devbox/internal/fileutil"
"go.jetpack.io/devbox/internal/ux"
"go.jetpack.io/devbox/internal/vercheck"
)

const rootError = "warning: installing Nix as root is not supported by this script!"
const (
minNixVersion = "2.12.0"
rootError = "warning: installing Nix as root is not supported by this script!"
)

// Install runs the install script for Nix. daemon has 3 states
// nil is unset. false is --no-daemon. true is --daemon.
Expand Down Expand Up @@ -95,13 +99,38 @@ func isRoot() bool {
return os.Geteuid() == 0
}

var ensured = false

func Ensured() bool {
return ensured
}

func EnsureNixInstalled(writer io.Writer, withDaemonFunc func() *bool) (err error) {
ensured = true
defer func() {
if err == nil {
// call ComputeSystem to ensure its value is internally cached so other
// callers can rely on just calling System
err = ComputeSystem()
if err != nil {
return
}
version := ""
version, err = Version()
if err != nil {
err = fmt.Errorf("failed to get nix version: %w", err)
return
}

// ensure minimum nix version installed
if vercheck.SemverCompare(version, minNixVersion) < 0 {
err = usererr.New(
"Devbox requires nix of version >= %s. Your version is %s. "+
"Please upgrade nix and try again.\n",
minNixVersion,
version,
)
return
}
// call ComputeSystem to ensure its value is internally cached so other
// callers can rely on just calling System
err = ComputeSystem()
}()

if BinaryInstalled() {
Expand Down