@@ -6,6 +6,7 @@ package boxcli
6
6
import (
7
7
"cmp"
8
8
"fmt"
9
+ "path/filepath"
9
10
"regexp"
10
11
11
12
"github.com/pkg/errors"
@@ -24,6 +25,7 @@ type generateCmdFlags struct {
24
25
force bool
25
26
printEnvrcContent bool
26
27
rootUser bool
28
+ envrcDir string // only used by generate direnv command
27
29
}
28
30
29
31
type generateDockerfileCmdFlags struct {
@@ -151,6 +153,15 @@ func direnvCmd() *cobra.Command {
151
153
// this command marks a flag as hidden. Error handling for it is not necessary.
152
154
_ = command .Flags ().MarkHidden ("print-envrc" )
153
155
156
+ // --envrc-dir allows users to specify a directory where the .envrc file should be generated
157
+ // separately from the devbox config directory. Without this flag, the .envrc file
158
+ // will be generated in the same directory as the devbox config file (i.e., either the current
159
+ // directory or the directory specified by --config). This is useful for users who want to keep
160
+ // their .envrc and devbox config files in different locations.
161
+ command .Flags ().StringVar (
162
+ & flags .envrcDir , "envrc-dir" , "" , "path to directory where the .envrc file should be generated. " +
163
+ "If not specified, the .envrc file will be generated in the current working directory." )
164
+
154
165
flags .config .register (command )
155
166
return command
156
167
}
@@ -266,13 +277,32 @@ func runGenerateCmd(cmd *cobra.Command, flags *generateCmdFlags) error {
266
277
}
267
278
268
279
func runGenerateDirenvCmd (cmd * cobra.Command , flags * generateCmdFlags ) error {
280
+ // --print-envrc is used within the .envrc file and therefore doesn't make sense to also
281
+ // use it with --envrc-dir, which specifies a directory where the .envrc file should be generated.
282
+ if flags .printEnvrcContent && flags .envrcDir != "" {
283
+ return usererr .New (
284
+ "Cannot use --print-envrc with --envrc-dir. " +
285
+ "Use --envrc-dir to specify the directory where the .envrc file should be generated." )
286
+ }
287
+
288
+ // Determine the directories for .envrc and config
289
+ configDir , envrcDir , err := determineDirenvDirs (flags .config .path , flags .envrcDir )
290
+ if err != nil {
291
+ return errors .WithStack (err )
292
+ }
293
+
294
+ generateOpts := devopt.EnvrcOpts {
295
+ EnvrcDir : envrcDir ,
296
+ ConfigDir : configDir ,
297
+ EnvFlags : devopt .EnvFlags (flags .envFlag ),
298
+ }
299
+
269
300
if flags .printEnvrcContent {
270
- return devbox .PrintEnvrcContent (
271
- cmd .OutOrStdout (), devopt .EnvFlags (flags .envFlag ))
301
+ return devbox .PrintEnvrcContent (cmd .OutOrStdout (), generateOpts )
272
302
}
273
303
274
304
box , err := devbox .Open (& devopt.Opts {
275
- Dir : flags . config . path ,
305
+ Dir : filepath . Join ( envrcDir , configDir ) ,
276
306
Environment : flags .config .environment ,
277
307
Stderr : cmd .ErrOrStderr (),
278
308
})
@@ -281,5 +311,33 @@ func runGenerateDirenvCmd(cmd *cobra.Command, flags *generateCmdFlags) error {
281
311
}
282
312
283
313
return box .GenerateEnvrcFile (
284
- cmd .Context (), flags .force , devopt .EnvFlags (flags .envFlag ))
314
+ cmd .Context (), flags .force , generateOpts )
315
+ }
316
+
317
+ // Returns cononical paths for configDir and envrcDir. Both locations are relative to the current
318
+ // working directory when provided to this function. However, since the config file will ultimately
319
+ // be relative to the .envrc file, we need to determine the relative path from envrcDir to configDir.
320
+ func determineDirenvDirs (configDir , envrcDir string ) (string , string , error ) {
321
+ // If envrcDir is specified, use it as the directory for .envrc and
322
+ // then determine configDir relative to that.
323
+ if envrcDir != "" {
324
+ if configDir == "" {
325
+ return "" , envrcDir , nil
326
+ }
327
+
328
+ relativeConfigDir , err := filepath .Rel (envrcDir , configDir )
329
+ if err != nil {
330
+ return "" , "" , errors .Wrapf (err , "failed to determine relative path from %s to %s" , envrcDir , configDir )
331
+ }
332
+
333
+ // If the relative path is ".", it means configDir is the same as envrcDir.
334
+ if relativeConfigDir == "." {
335
+ relativeConfigDir = ""
336
+ }
337
+
338
+ return relativeConfigDir , envrcDir , nil
339
+ }
340
+ // If envrcDir is not specified, we will use the configDir as the location for .envrc. This is
341
+ // for backward compatibility (prior to the --envrc-dir flag being introduced).
342
+ return "" , configDir , nil
285
343
}
0 commit comments