Skip to content

Commit 5b1f0f3

Browse files
authored
[nix] Add nix install command (#337)
## Summary This is a first step in having devbox install nix for you. This command can help us iterate faster. It's currently hidden. This adds `devbox nix install` which does exactly that, it attempts to install nix. Right now all output/input is redirected to stdout/stdin which means the user will control how the installation proceeds (nix explains, prompts and requests sudo). In follow ups we can improve this by: * Requiring sudo up front * Hiding prompts and answering them automatically. * Detecting if nix is not installed and offering to install it when user takes any step that requires it. ## How was it tested? `devbox nix install`
1 parent 3ed922b commit 5b1f0f3

File tree

5 files changed

+199
-0
lines changed

5 files changed

+199
-0
lines changed

.golangci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ linters-settings:
4848
- ns string
4949
- r *http.Request
5050
- r io.Reader
51+
- r *os.File
5152
- sh *Shell
5253
- sh *shell
5354
- sh *shell.Shell
@@ -56,6 +57,7 @@ linters-settings:
5657
- t testing.T
5758
- w http.ResponseWriter
5859
- w io.Writer
60+
- w *os.File
5961
wrapcheck:
6062
ignorePackageGlobs:
6163
- go.jetpack.io/devbox/*

boxcli/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ func RootCmd() *cobra.Command {
3434
command.AddCommand(PlanCmd())
3535
command.AddCommand(RemoveCmd())
3636
command.AddCommand(RunCmd())
37+
command.AddCommand(SetupCmd())
3738
command.AddCommand(ShellCmd())
3839
command.AddCommand(VersionCmd())
3940
command.AddCommand(genDocsCmd())

boxcli/setup.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2022 Jetpack Technologies Inc and contributors. All rights reserved.
2+
// Use of this source code is governed by the license in the LICENSE file.
3+
4+
package boxcli
5+
6+
import (
7+
"github.com/spf13/cobra"
8+
"go.jetpack.io/devbox/nix"
9+
)
10+
11+
func SetupCmd() *cobra.Command {
12+
setupCommand := &cobra.Command{
13+
Use: "setup",
14+
Short: "Setup devbox dependencies",
15+
Hidden: true,
16+
}
17+
18+
installNixCommand := &cobra.Command{
19+
Use: "nix",
20+
Short: "Installs Nix",
21+
RunE: func(cmd *cobra.Command, args []string) error {
22+
return runInstallNixCmd()
23+
},
24+
}
25+
26+
setupCommand.AddCommand(installNixCommand)
27+
return setupCommand
28+
}
29+
30+
func runInstallNixCmd() error {
31+
return nix.Install()
32+
}

nix/install.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package nix
2+
3+
import (
4+
_ "embed"
5+
"fmt"
6+
"io"
7+
"os"
8+
"os/exec"
9+
10+
"github.com/pkg/errors"
11+
)
12+
13+
//go:embed install.sh
14+
var installScript string
15+
16+
func Install() error {
17+
r, w, err := os.Pipe()
18+
if err != nil {
19+
return errors.WithStack(err)
20+
}
21+
defer r.Close()
22+
defer w.Close()
23+
24+
cmd := exec.Command("sudo", "sh", "-c", installScript)
25+
// Attach stdout but no stdin. This makes the command run in non-TTY mode
26+
// which skips the interactive prompts.
27+
// We could attach stderr? but the stdout prompt is pretty useful.
28+
cmd.Stdin = nil
29+
cmd.Stdout = w
30+
cmd.Stderr = nil
31+
32+
fmt.Println("Installing Nix. This will require sudo access.")
33+
if err = cmd.Start(); err != nil {
34+
return errors.WithStack(err)
35+
}
36+
37+
go func() {
38+
_, err := io.Copy(os.Stdout, r)
39+
if err != nil {
40+
fmt.Println(err)
41+
}
42+
}()
43+
44+
return errors.WithStack(cmd.Wait())
45+
}

nix/install.sh

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/bin/sh
2+
3+
# This script installs the Nix package manager on your system by
4+
# downloading a binary distribution and running its installer script
5+
# (which in turn creates and populates /nix).
6+
7+
{ # Prevent execution if this script was only partially downloaded
8+
oops() {
9+
echo "$0:" "$@" >&2
10+
exit 1
11+
}
12+
13+
umask 0022
14+
15+
tmpDir="$(mktemp -d -t nix-binary-tarball-unpack.XXXXXXXXXX || \
16+
oops "Can't create temporary directory for downloading the Nix binary tarball")"
17+
cleanup() {
18+
rm -rf "$tmpDir"
19+
}
20+
trap cleanup EXIT INT QUIT TERM
21+
22+
require_util() {
23+
command -v "$1" > /dev/null 2>&1 ||
24+
oops "you do not have '$1' installed, which I need to $2"
25+
}
26+
27+
case "$(uname -s).$(uname -m)" in
28+
Linux.x86_64)
29+
hash=c6d48479d50a01cdfc3669440776692ca7094ff29028b1fec6da0abeead16a01
30+
path=sicsy40akh9hs5r8iz1rkgnh46yfns4h/nix-2.11.1-x86_64-linux.tar.xz
31+
system=x86_64-linux
32+
;;
33+
Linux.i?86)
34+
hash=37fa1567394baf7fac2651d4d60890191b9d183626faf2069c59dbc602136ac5
35+
path=17s133r9xnvwkg7v6var7i24w2av285g/nix-2.11.1-i686-linux.tar.xz
36+
system=i686-linux
37+
;;
38+
Linux.aarch64)
39+
hash=b8ef85ea43d30ed89fdd176d8b044c5d1301628a77886742ea3f684cd4dc6db3
40+
path=fhi79b7zvz6np2rhld034qzpf7pfmb67/nix-2.11.1-aarch64-linux.tar.xz
41+
system=aarch64-linux
42+
;;
43+
Linux.armv6l_linux)
44+
hash=7181889751cb83add9b4ef7ea6bd0adb90eb0cd8c78422315cc22e6a7188dafd
45+
path=r44jpi4hki9llkznyxdl18a7f634an2p/nix-2.11.1-armv6l-linux.tar.xz
46+
system=armv6l-linux
47+
;;
48+
Linux.armv7l_linux)
49+
hash=8550980d6001f42f5dd2e969a016304f3e659bdcd9146e04c18b02f5b63994cd
50+
path=0kmd8q1g4gyw6pr474xp3nxs8mvyigqh/nix-2.11.1-armv7l-linux.tar.xz
51+
system=armv7l-linux
52+
;;
53+
Darwin.x86_64)
54+
hash=16dac47e397ff9026af23f355cc84465a2af7ec56b65ddb52c8b124d700556b1
55+
path=f0zhwzkvn5vv583mzbj0dqahzcajkglx/nix-2.11.1-x86_64-darwin.tar.xz
56+
system=x86_64-darwin
57+
;;
58+
Darwin.arm64|Darwin.aarch64)
59+
hash=ddead2fa8ef6b9b58fec4ab12b460f802a962fff68fb1c8fa47c7b8b5739bc0b
60+
path=d2gq40kvzckjmhwbbnh718w64v6zlr3m/nix-2.11.1-aarch64-darwin.tar.xz
61+
system=aarch64-darwin
62+
;;
63+
*) oops "sorry, there is no binary distribution of Nix for your platform";;
64+
esac
65+
66+
# Use this command-line option to fetch the tarballs using nar-serve or Cachix
67+
if [ "${1:-}" = "--tarball-url-prefix" ]; then
68+
if [ -z "${2:-}" ]; then
69+
oops "missing argument for --tarball-url-prefix"
70+
fi
71+
url=${2}/${path}
72+
shift 2
73+
else
74+
url=https://releases.nixos.org/nix/nix-2.11.1/nix-2.11.1-$system.tar.xz
75+
fi
76+
77+
tarball=$tmpDir/nix-2.11.1-$system.tar.xz
78+
79+
require_util tar "unpack the binary tarball"
80+
if [ "$(uname -s)" != "Darwin" ]; then
81+
require_util xz "unpack the binary tarball"
82+
fi
83+
84+
if command -v curl > /dev/null 2>&1; then
85+
fetch() { curl --fail -L "$1" -o "$2"; }
86+
elif command -v wget > /dev/null 2>&1; then
87+
fetch() { wget "$1" -O "$2"; }
88+
else
89+
oops "you don't have wget or curl installed, which I need to download the binary tarball"
90+
fi
91+
92+
echo "downloading Nix 2.11.1 binary tarball for $system from '$url' to '$tmpDir'..."
93+
fetch "$url" "$tarball" || oops "failed to download '$url'"
94+
95+
if command -v sha256sum > /dev/null 2>&1; then
96+
hash2="$(sha256sum -b "$tarball" | cut -c1-64)"
97+
elif command -v shasum > /dev/null 2>&1; then
98+
hash2="$(shasum -a 256 -b "$tarball" | cut -c1-64)"
99+
elif command -v openssl > /dev/null 2>&1; then
100+
hash2="$(openssl dgst -r -sha256 "$tarball" | cut -c1-64)"
101+
else
102+
oops "cannot verify the SHA-256 hash of '$url'; you need one of 'shasum', 'sha256sum', or 'openssl'"
103+
fi
104+
105+
if [ "$hash" != "$hash2" ]; then
106+
oops "SHA-256 hash mismatch in '$url'; expected $hash, got $hash2"
107+
fi
108+
109+
unpack=$tmpDir/unpack
110+
mkdir -p "$unpack"
111+
tar -xJf "$tarball" -C "$unpack" || oops "failed to unpack '$url'"
112+
113+
script=$(echo "$unpack"/*/install)
114+
115+
[ -e "$script" ] || oops "installation script is missing from the binary tarball!"
116+
export INVOKED_FROM_INSTALL_IN=1
117+
"$script" "$@"
118+
119+
} # End of wrapping

0 commit comments

Comments
 (0)