Skip to content

Commit ac1e50b

Browse files
authored
[nix-cache] Add cache copy command (#1891)
## Summary Note: this may not be the final UX for this command. I'm just getting it in hidden so we can build the cache feature end-to-end and will refine details later. Adds `devbox cache copy <url>` command. It copies the current devbox nix profile to the url. `<url>` can be anything supported by https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-copy There are two future plans for this command: * `url` will be optional when logged in. It will be determined by API in those cases. We may want to move url to be a flag in that case (possibly the `--to` flag to mimic `nix copy`). * This command will support specifying the package you wish to copy. Packages can be nix installable, but also devbox packages (i.e. package@version). We could even support runx in the future. I used `copy` to mimic `nix` command name, but I slightly prefer `upload`. That and the above changes would make this command look like: `devbox cache upload [--to <url>] [package]` or as simple as `devbox cache upload` to upload current profile when logged in. ## How was it tested? `devbox cache copy "s3://mike-test-nix-cache?region=us-west-2"`
1 parent 25e35f2 commit ac1e50b

File tree

6 files changed

+118
-10
lines changed

6 files changed

+118
-10
lines changed

internal/boxcli/cache.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2024 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/pkg/errors"
8+
"github.com/spf13/cobra"
9+
"go.jetpack.io/devbox/internal/devbox"
10+
"go.jetpack.io/devbox/internal/devbox/devopt"
11+
)
12+
13+
type cacheFlags struct {
14+
pathFlag
15+
}
16+
17+
func cacheCmd() *cobra.Command {
18+
flags := cacheFlags{}
19+
cacheCommand := &cobra.Command{
20+
Use: "cache",
21+
Short: "Collection of commands to interact with nix cache",
22+
PersistentPreRunE: ensureNixInstalled,
23+
}
24+
25+
copyCommand := &cobra.Command{
26+
Use: "copy <uri>",
27+
Short: "Copies all nix packages in current project to the cache at <uri>",
28+
Args: cobra.ExactArgs(1),
29+
RunE: func(cmd *cobra.Command, args []string) error {
30+
box, err := devbox.Open(&devopt.Opts{
31+
Dir: flags.path,
32+
Stderr: cmd.ErrOrStderr(),
33+
})
34+
if err != nil {
35+
return errors.WithStack(err)
36+
}
37+
return box.CacheCopy(cmd.Context(), args[0])
38+
},
39+
}
40+
41+
flags.pathFlag.register(copyCommand)
42+
43+
cacheCommand.AddCommand(copyCommand)
44+
cacheCommand.Hidden = true
45+
46+
return cacheCommand
47+
}

internal/boxcli/config.go

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,37 @@ import (
99

1010
// to be composed into xyzCmdFlags structs
1111
type configFlags struct {
12-
path string
12+
pathFlag
1313
environment string
1414
}
1515

1616
func (flags *configFlags) register(cmd *cobra.Command) {
17-
cmd.Flags().StringVarP(
18-
&flags.path, "config", "c", "", "path to directory containing a devbox.json config file",
19-
)
17+
flags.pathFlag.register(cmd)
2018
cmd.Flags().StringVar(
2119
&flags.environment, "environment", "dev", "environment to use, when supported (e.g.secrets support dev, prod, preview.)",
2220
)
2321
}
2422

2523
func (flags *configFlags) registerPersistent(cmd *cobra.Command) {
26-
cmd.PersistentFlags().StringVarP(
27-
&flags.path, "config", "c", "", "path to directory containing a devbox.json config file",
28-
)
24+
flags.pathFlag.registerPersistent(cmd)
2925
cmd.PersistentFlags().StringVar(
3026
&flags.environment, "environment", "dev", "environment to use, when supported (e.g. secrets support dev, prod, preview.)",
3127
)
3228
}
3329

34-
func (flags *configFlags) Environment() string {
35-
return flags.environment
30+
// pathFlag is a flag for specifying the path to a devbox.json file
31+
type pathFlag struct {
32+
path string
33+
}
34+
35+
func (flags *pathFlag) register(cmd *cobra.Command) {
36+
cmd.Flags().StringVarP(
37+
&flags.path, "config", "c", "", "path to directory containing a devbox.json config file",
38+
)
39+
}
40+
41+
func (flags *pathFlag) registerPersistent(cmd *cobra.Command) {
42+
cmd.PersistentFlags().StringVarP(
43+
&flags.path, "config", "c", "", "path to directory containing a devbox.json config file",
44+
)
3645
}

internal/boxcli/pull.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func pullCmdFunc(cmd *cobra.Command, url string, flags *pullCmdFlags) error {
105105

106106
return installCmdFunc(
107107
cmd,
108-
runCmdFlags{config: configFlags{path: flags.config.path}},
108+
runCmdFlags{config: configFlags{pathFlag: pathFlag{path: flags.config.path}}},
109109
)
110110
}
111111

internal/boxcli/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ func RootCmd() *cobra.Command {
6060
if featureflag.Auth.Enabled() {
6161
command.AddCommand(authCmd())
6262
}
63+
command.AddCommand(cacheCmd())
6364
command.AddCommand(createCmd())
6465
command.AddCommand(secretsCmd())
6566
command.AddCommand(generateCmd())

internal/devbox/cache.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package devbox
2+
3+
import (
4+
"context"
5+
6+
"go.jetpack.io/devbox/internal/nix"
7+
)
8+
9+
func (d *Devbox) CacheCopy(ctx context.Context, cacheURI string) error {
10+
profilePath, err := d.profilePath()
11+
if err != nil {
12+
return err
13+
}
14+
15+
return nix.CopyInstallableToCache(ctx, d.stderr, cacheURI, profilePath)
16+
}

internal/nix/cache.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package nix
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"os"
8+
)
9+
10+
func CopyInstallableToCache(
11+
ctx context.Context,
12+
out io.Writer,
13+
// Note: installable is a string instead of a flake.Installable
14+
// because flake.Installable does not support store paths yet. It converts
15+
// paths into "path" flakes which is not what we want for /nix/store paths.
16+
// TODO: Add support for store paths in flake.Installable
17+
to, installable string,
18+
) error {
19+
fmt.Fprintf(out, "Copying %s to %s\n", installable, to)
20+
cmd := commandContext(
21+
ctx,
22+
"copy", "--to", to,
23+
// --refresh checks the cache to ensure it is up to date. Otherwise if
24+
// anything has was copied previously from this machine and then purged
25+
// it may not be copied again. It's fairly fast, but not instant.
26+
"--refresh",
27+
installable,
28+
)
29+
30+
cmd.Stdin = os.Stdin
31+
cmd.Stdout = out
32+
cmd.Stderr = out
33+
34+
return cmd.Run()
35+
}

0 commit comments

Comments
 (0)