@@ -36,6 +36,7 @@ use jj_lib::config::ConfigSource;
3636use jj_lib:: config:: ConfigValue ;
3737use jj_lib:: config:: StackedConfig ;
3838use jj_lib:: dsl_util;
39+ use jj_lib:: secure_config:: SecureConfig ;
3940use regex:: Captures ;
4041use regex:: Regex ;
4142use serde:: Serialize as _;
@@ -271,6 +272,10 @@ struct UnresolvedConfigEnv {
271272}
272273
273274impl UnresolvedConfigEnv {
275+ fn root_config_dir ( & self ) -> Option < PathBuf > {
276+ self . config_dir . as_deref ( ) . map ( |c| c. join ( "jj" ) )
277+ }
278+
274279 fn resolve ( self ) -> Vec < ConfigPath > {
275280 if let Some ( paths) = self . jj_config {
276281 return split_paths ( & paths)
@@ -320,11 +325,12 @@ impl UnresolvedConfigEnv {
320325#[ derive( Clone , Debug ) ]
321326pub struct ConfigEnv {
322327 home_dir : Option < PathBuf > ,
328+ root_config_dir : Option < PathBuf > ,
323329 repo_path : Option < PathBuf > ,
324330 workspace_path : Option < PathBuf > ,
325331 user_config_paths : Vec < ConfigPath > ,
326- repo_config_path : Option < ConfigPath > ,
327- workspace_config_path : Option < ConfigPath > ,
332+ repo_config : Option < SecureConfig > ,
333+ workspace_config : Option < SecureConfig > ,
328334 command : Option < String > ,
329335 hostname : Option < String > ,
330336}
@@ -349,11 +355,12 @@ impl ConfigEnv {
349355 } ;
350356 Self {
351357 home_dir,
358+ root_config_dir : env. root_config_dir ( ) ,
352359 repo_path : None ,
353360 workspace_path : None ,
354361 user_config_paths : env. resolve ( ) ,
355- repo_config_path : None ,
356- workspace_config_path : None ,
362+ repo_config : None ,
363+ workspace_config : None ,
357364 command : None ,
358365 hostname : whoami:: fallible:: hostname ( ) . ok ( ) ,
359366 }
@@ -424,21 +431,33 @@ impl ConfigEnv {
424431 /// Sets the directory where repo-specific config file is stored. The path
425432 /// is usually `.jj/repo`.
426433 pub fn reset_repo_path ( & mut self , path : & Path ) {
434+ if self . repo_path . as_deref ( ) != Some ( path)
435+ && let Some ( root_config_dir) = self . root_config_dir . as_deref ( )
436+ {
437+ self . repo_config = Some ( SecureConfig :: new (
438+ path. to_owned ( ) ,
439+ root_config_dir. join ( "repos" ) ,
440+ "repo-config-id" ,
441+ "config.toml" ,
442+ ) ) ;
443+ }
427444 self . repo_path = Some ( path. to_owned ( ) ) ;
428- self . repo_config_path = Some ( ConfigPath :: new ( path. join ( "config.toml" ) ) ) ;
429445 }
430446
431- /// Returns a path to the repo-specific config file.
432- pub fn repo_config_path ( & self ) -> Option < & Path > {
433- self . repo_config_path . as_ref ( ) . map ( |p| p. as_path ( ) )
447+ /// Returns a path to the existing repo-specific config file.
448+ fn maybe_repo_config_path ( & self ) -> Result < Option < PathBuf > , ConfigLoadError > {
449+ Ok ( match & self . repo_config {
450+ Some ( config) => config. maybe_load_config ( ) ?. 0 ,
451+ None => None ,
452+ } )
434453 }
435454
436455 /// Returns a path to the existing repo-specific config file.
437- fn existing_repo_config_path ( & self ) -> Option < & Path > {
438- match self . repo_config_path {
439- Some ( ref path ) if path . exists ( ) => Some ( path . as_path ( ) ) ,
440- _ => None ,
441- }
456+ pub fn repo_config_path ( & self ) -> Result < Option < PathBuf > , ConfigLoadError > {
457+ Ok ( match & self . repo_config {
458+ Some ( config ) => Some ( config . load_config ( ) ? . 0 ) ,
459+ None => None ,
460+ } )
442461 }
443462
444463 /// Returns repo configuration files for modification. Instantiates one if
@@ -455,7 +474,7 @@ impl ConfigEnv {
455474 }
456475
457476 fn new_repo_config_file ( & self ) -> Result < Option < ConfigFile > , ConfigLoadError > {
458- self . repo_config_path ( )
477+ self . repo_config_path ( ) ?
459478 // The path doesn't usually exist, but we shouldn't overwrite it
460479 // with an empty config if it did exist.
461480 . map ( |path| ConfigFile :: load_or_empty ( ConfigSource :: Repo , path) )
@@ -467,32 +486,43 @@ impl ConfigEnv {
467486 #[ instrument]
468487 pub fn reload_repo_config ( & self , config : & mut RawConfig ) -> Result < ( ) , ConfigLoadError > {
469488 config. as_mut ( ) . remove_layers ( ConfigSource :: Repo ) ;
470- if let Some ( path) = self . existing_repo_config_path ( ) {
489+ if let Some ( path) = self . maybe_repo_config_path ( ) ? {
471490 config. as_mut ( ) . load_file ( ConfigSource :: Repo , path) ?;
472491 }
473492 Ok ( ( ) )
474493 }
475494
476- /// Sets the directory for the workspace and the workspace-specific config
477- /// file .
495+ /// Sets the directory where repo-specific config file is stored. The path
496+ /// is usually `.jj/repo` .
478497 pub fn reset_workspace_path ( & mut self , path : & Path ) {
498+ if self . workspace_path . as_deref ( ) != Some ( path)
499+ && let Some ( root_config_dir) = self . root_config_dir . as_deref ( )
500+ {
501+ self . workspace_config = Some ( SecureConfig :: new (
502+ path. to_owned ( ) ,
503+ root_config_dir. join ( "workspaces" ) ,
504+ "workspace-config-id" ,
505+ "workspace-config.toml" ,
506+ ) ) ;
507+ }
479508 self . workspace_path = Some ( path. to_owned ( ) ) ;
480- self . workspace_config_path = Some ( ConfigPath :: new (
481- path. join ( ".jj" ) . join ( "workspace-config.toml" ) ,
482- ) ) ;
483509 }
484510
485- /// Returns a path to the workspace-specific config file.
486- pub fn workspace_config_path ( & self ) -> Option < & Path > {
487- self . workspace_config_path . as_ref ( ) . map ( |p| p. as_path ( ) )
511+ /// Returns a path to the workspace-specific config file, if it exists.
512+ fn maybe_workspace_config_path ( & self ) -> Result < Option < PathBuf > , ConfigLoadError > {
513+ Ok ( match & self . workspace_config {
514+ Some ( config) => config. maybe_load_config ( ) ?. 0 ,
515+ None => None ,
516+ } )
488517 }
489518
490- /// Returns a path to the existing workspace-specific config file.
491- fn existing_workspace_config_path ( & self ) -> Option < & Path > {
492- match self . workspace_config_path {
493- Some ( ref path) if path. exists ( ) => Some ( path. as_path ( ) ) ,
494- _ => None ,
495- }
519+ /// Returns a path to the existing workspace-specific config file, creating
520+ /// a new one if it doesn't exist.
521+ pub fn workspace_config_path ( & self ) -> Result < Option < PathBuf > , ConfigLoadError > {
522+ Ok ( match & self . workspace_config {
523+ Some ( config) => Some ( config. load_config ( ) ?. 0 ) ,
524+ None => None ,
525+ } )
496526 }
497527
498528 /// Returns workspace configuration files for modification. Instantiates one
@@ -511,7 +541,7 @@ impl ConfigEnv {
511541 }
512542
513543 fn new_workspace_config_file ( & self ) -> Result < Option < ConfigFile > , ConfigLoadError > {
514- self . workspace_config_path ( )
544+ self . workspace_config_path ( ) ?
515545 . map ( |path| ConfigFile :: load_or_empty ( ConfigSource :: Workspace , path) )
516546 . transpose ( )
517547 }
@@ -521,7 +551,7 @@ impl ConfigEnv {
521551 #[ instrument]
522552 pub fn reload_workspace_config ( & self , config : & mut RawConfig ) -> Result < ( ) , ConfigLoadError > {
523553 config. as_mut ( ) . remove_layers ( ConfigSource :: Workspace ) ;
524- if let Some ( path) = self . existing_workspace_config_path ( ) {
554+ if let Some ( path) = self . maybe_workspace_config_path ( ) ? {
525555 config. as_mut ( ) . load_file ( ConfigSource :: Workspace , path) ?;
526556 }
527557 Ok ( ( ) )
@@ -565,8 +595,8 @@ fn config_files_for(
565595/// 1. Default
566596/// 2. Base environment variables
567597/// 3. [User configs](https://docs.jj-vcs.dev/latest/config/)
568- /// 4. Repo config `.jj/repo/config.toml`
569- /// 5. Workspace config `.jj/workspace-config.toml`
598+ /// 4. Repo config
599+ /// 5. Workspace config
570600/// 6. Override environment variables
571601/// 7. Command-line arguments `--config` and `--config-file`
572602///
@@ -1762,11 +1792,12 @@ mod tests {
17621792 } ;
17631793 ConfigEnv {
17641794 home_dir,
1795+ root_config_dir : None ,
17651796 repo_path : None ,
17661797 workspace_path : None ,
17671798 user_config_paths : env. resolve ( ) ,
1768- repo_config_path : None ,
1769- workspace_config_path : None ,
1799+ repo_config : None ,
1800+ workspace_config : None ,
17701801 command : None ,
17711802 hostname : None ,
17721803 }
0 commit comments