Skip to content

Commit

Permalink
fix: Change init to default to --config if --config-path is absent
Browse files Browse the repository at this point in the history
  • Loading branch information
paltherr committed Jan 24, 2024
1 parent 85983f0 commit c1a83ef
Show file tree
Hide file tree
Showing 10 changed files with 215 additions and 32 deletions.
2 changes: 1 addition & 1 deletion internal/cmd/addcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ func (c *Config) runAddCmd(cmd *cobra.Command, args []string, sourceState *chezm
ProtectedAbsPaths: []chezmoi.AbsPath{
c.CacheDirAbsPath,
c.WorkingTreeAbsPath,
c.configFileAbsPath,
c.getConfigFileAbsPath(),
persistentStateFileAbsPath,
c.sourceDirAbsPath,
},
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/catconfigcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func (c *Config) newCatConfigCmd() *cobra.Command {
}

func (c *Config) runCatConfigCmd(cmd *cobra.Command, args []string) error {
data, err := c.baseSystem.ReadFile(c.configFileAbsPath)
data, err := c.baseSystem.ReadFile(c.getConfigFileAbsPath())
if err != nil {
return err
}
Expand Down
63 changes: 38 additions & 25 deletions internal/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,16 +215,17 @@ type Config struct {
versionStr string

// Configuration.
fileSystem vfs.FS
bds *xdg.BaseDirectorySpecification
configFileAbsPath chezmoi.AbsPath
configFileAbsPathErr error
baseSystem chezmoi.System
sourceSystem chezmoi.System
destSystem chezmoi.System
persistentState chezmoi.PersistentState
httpClient *http.Client
logger *zerolog.Logger
fileSystem vfs.FS
bds *xdg.BaseDirectorySpecification
defaultConfigFileAbsPath chezmoi.AbsPath
defaultConfigFileAbsPathErr error
customConfigFileAbsPath chezmoi.AbsPath
baseSystem chezmoi.System
sourceSystem chezmoi.System
destSystem chezmoi.System
persistentState chezmoi.PersistentState
httpClient *http.Client
logger *zerolog.Logger

// Computed configuration.
commandDirAbsPath chezmoi.AbsPath
Expand Down Expand Up @@ -499,7 +500,7 @@ func newConfig(options ...configOption) (*Config, error) {
if err != nil {
return nil, err
}
c.configFileAbsPath, c.configFileAbsPathErr = c.defaultConfigFile(c.fileSystem, c.bds)
c.defaultConfigFileAbsPath, c.defaultConfigFileAbsPathErr = c.defaultConfigFile(c.fileSystem, c.bds)
c.SourceDirAbsPath, err = c.defaultSourceDir(c.fileSystem, c.bds)
if err != nil {
return nil, err
Expand All @@ -510,6 +511,13 @@ func newConfig(options ...configOption) (*Config, error) {
return c, nil
}

func (c *Config) getConfigFileAbsPath() chezmoi.AbsPath {
if c.customConfigFileAbsPath.Empty() {
return c.defaultConfigFileAbsPath
}
return c.customConfigFileAbsPath
}

// Close closes resources associated with c.
func (c *Config) Close() error {
errs := make([]error, 0, len(c.tempDirs))
Expand Down Expand Up @@ -748,7 +756,11 @@ func (c *Config) createAndReloadConfigFile(cmd *cobra.Command) error {
// Write the config.
configPath := c.init.configPath
if c.init.configPath.Empty() {
configPath = chezmoi.NewAbsPath(c.bds.ConfigHome).Join(chezmoiRelPath, configTemplate.targetRelPath)
if c.customConfigFileAbsPath.Empty() {
configPath = chezmoi.NewAbsPath(c.bds.ConfigHome).Join(chezmoiRelPath, configTemplate.targetRelPath)
} else {
configPath = c.customConfigFileAbsPath
}
}
if err := chezmoi.MkdirAll(c.baseSystem, configPath.Dir(), fs.ModePerm); err != nil {
return err
Expand Down Expand Up @@ -1181,6 +1193,7 @@ func (c *Config) execute(args []string) error {
return err
}
rootCmd.SetArgs(args)

return rootCmd.Execute()
}

Expand Down Expand Up @@ -1552,7 +1565,7 @@ func (c *Config) newRootCmd() (*cobra.Command, error) {
persistentFlags.BoolVarP(&c.Verbose, "verbose", "v", c.Verbose, "Make output more verbose")
persistentFlags.VarP(&c.WorkingTreeAbsPath, "working-tree", "W", "Set working tree directory")

persistentFlags.VarP(&c.configFileAbsPath, "config", "c", "Set config file")
persistentFlags.VarP(&c.customConfigFileAbsPath, "config", "c", "Set config file")
persistentFlags.Var(&c.configFormat, "config-format", "Set config file format")
persistentFlags.Var(&c.cpuProfile, "cpu-profile", "Write a CPU profile to path")
persistentFlags.BoolVar(&c.debug, "debug", c.debug, "Include debug information in output")
Expand Down Expand Up @@ -1749,15 +1762,15 @@ func (c *Config) persistentPostRunRootE(cmd *cobra.Command, args []string) error
}

if annotations.hasTag(modifiesConfigFile) {
configFileContents, err := c.baseSystem.ReadFile(c.configFileAbsPath)
configFileContents, err := c.baseSystem.ReadFile(c.getConfigFileAbsPath())
switch {
case errors.Is(err, fs.ErrNotExist):
err = nil
case err != nil:
// err is already set, do nothing.
default:
var format chezmoi.Format
if format, err = chezmoi.FormatFromAbsPath(c.configFileAbsPath); err == nil {
if format, err = chezmoi.FormatFromAbsPath(c.getConfigFileAbsPath()); err == nil {
var config map[string]any
if err = format.Unmarshal(configFileContents, &config); err != nil { //nolint:revive
// err is already set, do nothing.
Expand All @@ -1767,7 +1780,7 @@ func (c *Config) persistentPostRunRootE(cmd *cobra.Command, args []string) error
}
}
if err != nil {
c.errorf("warning: %s: %v\n", c.configFileAbsPath, err)
c.errorf("warning: %s: %v\n", c.getConfigFileAbsPath(), err)
}
}

Expand Down Expand Up @@ -1867,15 +1880,15 @@ func (c *Config) persistentPreRunRootE(cmd *cobra.Command, args []string) error

// Read the config file.
if annotations.hasTag(doesNotRequireValidConfig) {
if c.configFileAbsPathErr == nil {
if c.defaultConfigFileAbsPathErr == nil {
_ = c.readConfig()
}
} else {
if c.configFileAbsPathErr != nil {
return c.configFileAbsPathErr
if c.defaultConfigFileAbsPathErr != nil {
return c.defaultConfigFileAbsPathErr
}
if err := c.readConfig(); err != nil {
return fmt.Errorf("invalid config: %s: %w", c.configFileAbsPath, err)
return fmt.Errorf("invalid config: %s: %w", c.getConfigFileAbsPath(), err)
}
}

Expand Down Expand Up @@ -2030,7 +2043,7 @@ func (c *Config) persistentPreRunRootE(cmd *cobra.Command, args []string) error

// Create the config directory if needed.
if annotations.hasTag(requiresConfigDirectory) {
if err := chezmoi.MkdirAll(c.baseSystem, c.configFileAbsPath.Dir(), fs.ModePerm); err != nil {
if err := chezmoi.MkdirAll(c.baseSystem, c.getConfigFileAbsPath().Dir(), fs.ModePerm); err != nil {
return err
}
}
Expand Down Expand Up @@ -2155,8 +2168,8 @@ func (c *Config) persistentStateFile() (chezmoi.AbsPath, error) {
if !c.PersistentStateAbsPath.Empty() {
return c.PersistentStateAbsPath, nil
}
if !c.configFileAbsPath.Empty() {
return c.configFileAbsPath.Dir().Join(persistentStateFileRelPath), nil
if !c.getConfigFileAbsPath().Empty() {
return c.getConfigFileAbsPath().Dir().Join(persistentStateFileRelPath), nil
}
for _, configDir := range c.bds.ConfigDirs {
configDirAbsPath, err := chezmoi.NewAbsPathFromExtPath(configDir, c.homeDirAbsPath)
Expand Down Expand Up @@ -2279,7 +2292,7 @@ func (c *Config) newTemplateData(cmd *cobra.Command) *templateData {
command: cmd.Name(),
commandDir: c.commandDirAbsPath,
config: c.ConfigFile.toMap(),
configFile: c.configFileAbsPath,
configFile: c.getConfigFileAbsPath(),
executable: chezmoi.NewAbsPath(executable),
fqdnHostname: fqdnHostname,
gid: gid,
Expand Down Expand Up @@ -2307,7 +2320,7 @@ func (c *Config) newTemplateData(cmd *cobra.Command) *templateData {

// readConfig reads the config file, if it exists.
func (c *Config) readConfig() error {
switch err := c.decodeConfigFile(c.configFileAbsPath, &c.ConfigFile); {
switch err := c.decodeConfigFile(c.getConfigFileAbsPath(), &c.ConfigFile); {
case errors.Is(err, fs.ErrNotExist):
return nil
default:
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/doctorcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ func (c *Config) runDoctorCmd(cmd *cobra.Command, args []string) error {
&configFileCheck{
basename: chezmoiRelPath,
bds: c.bds,
expected: c.configFileAbsPath,
expected: c.getConfigFileAbsPath(),
},
&dirCheck{
name: "source-dir",
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/editconfigcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ func (c *Config) newEditConfigCmd() *cobra.Command {
}

func (c *Config) runEditConfigCmd(cmd *cobra.Command, args []string) error {
return c.runEditor([]string{c.configFileAbsPath.String()})
return c.runEditor([]string{c.getConfigFileAbsPath().String()})
}
4 changes: 2 additions & 2 deletions internal/cmd/editconfigtemplatecmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ func (c *Config) runEditConfigTemplateCmd(cmd *cobra.Command, args []string, sou
!errors.Is(err, fs.ErrExist) {
return err
}
configFileBase := "." + c.configFileAbsPath.Base() + ".tmpl"
configFileBase := "." + c.getConfigFileAbsPath().Base() + ".tmpl"
configTemplateAbsPath = c.sourceDirAbsPath.JoinString(configFileBase)
switch data, err := c.baseSystem.ReadFile(c.configFileAbsPath); {
switch data, err := c.baseSystem.ReadFile(c.getConfigFileAbsPath()); {
case errors.Is(err, fs.ErrNotExist):
// Do nothing.
case err != nil:
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/purgecmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (c *Config) doPurge(options *doPurgeOptions) error {
}

if options.config {
absPaths = append(absPaths, c.configFileAbsPath.Dir(), c.configFileAbsPath)
absPaths = append(absPaths, c.getConfigFileAbsPath().Dir(), c.getConfigFileAbsPath())
}

if options.persistentState {
Expand Down
8 changes: 8 additions & 0 deletions internal/cmd/testdata/scripts/init.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ grep '# edited' $HOME/.file

chhome home10/user

# test chezmoi --config init
mkgitconfig
exec chezmoi --config=$HOME/.chezmoi.toml init file://$WORK/home/user/.local/share/chezmoi
cmp $HOME/.chezmoi.toml golden/chezmoi.toml
! exists $CHEZMOICONFIGDIR/chezmoi.toml

chhome home10-old/user

# test chezmoi init --config-path
mkgitconfig
exec chezmoi init --config-path=$HOME/.chezmoi.toml file://$WORK/home/user/.local/share/chezmoi
Expand Down
135 changes: 135 additions & 0 deletions internal/cmd/testdata/scripts/initconfig.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
[windows] skip 'test requires path separator to be forward slash'
# test the init command with 3 different sets of --config/--config-format options


#### test chezmoi init

chhome home1/user
mkdir $CHEZMOISOURCEDIR

# test that chezmoi init writes the initial config into the defaul config dir
cp golden/chezmoi1.yaml $CHEZMOISOURCEDIR/.chezmoi.yaml.tmpl
exec chezmoi init
cmp $CHEZMOICONFIGDIR/chezmoi.yaml golden/chezmoi1.yaml

# test that chezmoi init writes an updated config into the defaul config dir
cp golden/chezmoi2.yaml $CHEZMOISOURCEDIR/.chezmoi.yaml.tmpl
exec chezmoi init
cmp $CHEZMOICONFIGDIR/chezmoi.yaml golden/chezmoi2.yaml

# test that chezmoi init writes a config of a new format into the defaul config dir
rm $CHEZMOISOURCEDIR/.chezmoi.yaml.tmpl
cp golden/chezmoi3.toml $CHEZMOISOURCEDIR/.chezmoi.toml.tmpl
exec chezmoi init
cmp $CHEZMOICONFIGDIR/chezmoi.yaml golden/chezmoi2.yaml
cmp $CHEZMOICONFIGDIR/chezmoi.toml golden/chezmoi3.toml

# check that the last operation broke chezmoi
! exec chezmoi status
! stdout .
cmpenv stderr golden/error1.log

# check that deleting the old config file fixes the issue
rm $CHEZMOICONFIGDIR/chezmoi.yaml
exec chezmoi status
! stdout .
! stderr .

# check that the state file was written into the default config dir
exists $CHEZMOICONFIGDIR/chezmoistate.boltdb


#### test chezmoi --config=path init

chhome home2/user
mkdir $CHEZMOISOURCEDIR

# test that chezmoi --config=path init writes the initial config into path
cp golden/chezmoi1.yaml $CHEZMOISOURCEDIR/.chezmoi.yaml.tmpl
exec chezmoi --config=$HOME/.chezmoi/athome.yaml init
cmp $HOME/.chezmoi/athome.yaml golden/chezmoi1.yaml

# test that chezmoi --config=path init writes an updated config into path
cp golden/chezmoi2.yaml $CHEZMOISOURCEDIR/.chezmoi.yaml.tmpl
exec chezmoi --config=$HOME/.chezmoi/athome.yaml init
cmp $HOME/.chezmoi/athome.yaml golden/chezmoi2.yaml

# test that chezmoi --config=path init writes a config of a new format into path
rm $CHEZMOISOURCEDIR/.chezmoi.yaml.tmpl
cp golden/chezmoi3.toml $CHEZMOISOURCEDIR/.chezmoi.toml.tmpl
exec chezmoi --config=$HOME/.chezmoi/athome.yaml init
cmp $HOME/.chezmoi/athome.yaml golden/chezmoi3.toml

# check that the last operation broke chezmoi
! exec chezmoi --config=$HOME/.chezmoi/athome.yaml status
! stdout .
cmpenv stderr golden/error2.log

# check that renaming the file and updating the config path fixes the issue
mv $HOME/.chezmoi/athome.yaml $HOME/.chezmoi/athome.toml
exec chezmoi --config=$HOME/.chezmoi/athome.toml status
! stdout .
! stderr .

# check that the state file was written next to the config file
exists $HOME/.chezmoi/chezmoistate.boltdb

# check that nothing was ever written into the default config dir
! exists $CHEZMOICONFIGDIR/chezmoi.toml
! exists $CHEZMOICONFIGDIR/chezmoistate.boltdb


#### test chezmoi --config=path --config-format=format init

chhome home3/user
mkdir $CHEZMOISOURCEDIR

# test that chezmoi --config=path --config-format=format init writes the initial config into path
cp golden/chezmoi1.yaml $CHEZMOISOURCEDIR/.chezmoi.yaml.tmpl
exec chezmoi --config=$HOME/.chezmoi/athome.txt --config-format=yaml init
cmp $HOME/.chezmoi/athome.txt golden/chezmoi1.yaml

# test that chezmoi --config=path --config-format=format init writes an updated config into path
cp golden/chezmoi2.yaml $CHEZMOISOURCEDIR/.chezmoi.yaml.tmpl
exec chezmoi --config=$HOME/.chezmoi/athome.txt --config-format=yaml init
cmp $HOME/.chezmoi/athome.txt golden/chezmoi2.yaml

# test that chezmoi --config=path --config-format=format init writes a config of a new format into path
rm $CHEZMOISOURCEDIR/.chezmoi.yaml.tmpl
cp golden/chezmoi3.toml $CHEZMOISOURCEDIR/.chezmoi.toml.tmpl
exec chezmoi --config=$HOME/.chezmoi/athome.txt --config-format=yaml init
cmp $HOME/.chezmoi/athome.txt golden/chezmoi3.toml

# check that the last operation broke chezmoi
! exec chezmoi --config=$HOME/.chezmoi/athome.txt --config-format=yaml status
! stdout .
cmpenv stderr golden/error3.log

# check that updating the config format fixes the issue
exec chezmoi --config=$HOME/.chezmoi/athome.txt --config-format=toml status
! stdout .
! stderr .

# check that the state file was written next to the config file
exists $HOME/.chezmoi/chezmoistate.boltdb

# check that nothing was ever written into the default config dir
! exists $CHEZMOICONFIGDIR/chezmoi.toml
! exists $CHEZMOICONFIGDIR/chezmoistate.boltdb


-- golden/chezmoi1.yaml --
data:
email: "mail1@example.com"
-- golden/chezmoi2.yaml --
data:
email: "mail2@example.com"
-- golden/chezmoi3.toml --
[data]
email = "mail3@example.com"
-- golden/error1.log --
chezmoi: multiple config files: $CHEZMOICONFIGDIR/chezmoi.toml and $CHEZMOICONFIGDIR/chezmoi.yaml
-- golden/error2.log --
chezmoi: invalid config: $HOME/.chezmoi/athome.yaml: yaml: unmarshal errors: line 1: cannot unmarshal !!seq into map[string]interface {}
-- golden/error3.log --
chezmoi: invalid config: $HOME/.chezmoi/athome.txt: yaml: unmarshal errors: line 1: cannot unmarshal !!seq into map[string]interface {}
27 changes: 27 additions & 0 deletions internal/cmd/testdata/scripts/issue3127.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
mkdir $CHEZMOISOURCEDIR

# test that chezmoi --config=path init --config-path=path writes the initial config into path
cp golden/config1.toml $CHEZMOISOURCEDIR/.chezmoi.toml.tmpl
exec chezmoi --config=$HOME/config/athome.toml init --config-path=$HOME/config/athome.toml
cmp $HOME/config/athome.toml golden/config1.toml

# test that chezmoi --config=path init --config-path=path writes an updated config into path
cp golden/config2.toml $CHEZMOISOURCEDIR/.chezmoi.toml.tmpl
exec chezmoi --config=$HOME/config/athome.toml init --config-path=$HOME/config/athome.toml
cmp $HOME/config/athome.toml golden/config2.toml

# test that chezmoi --config=path init writes an updated config into path
cp golden/config3.toml $CHEZMOISOURCEDIR/.chezmoi.toml.tmpl
exec chezmoi --config=$HOME/config/athome.toml init
cmp $HOME/config/athome.toml golden/config3.toml


-- golden/config1.toml --
[data]
email = "mail1@example.com"
-- golden/config2.toml --
[data]
email = "mail2@example.com"
-- golden/config3.toml --
[data]
email = "mail3@example.com"

0 comments on commit c1a83ef

Please sign in to comment.