Skip to content

Commit

Permalink
fix: Fix potential panic when textconv interpreter is empty
Browse files Browse the repository at this point in the history
  • Loading branch information
twpayne committed Apr 12, 2024
1 parent b4df44d commit d6ad485
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 42 deletions.
30 changes: 17 additions & 13 deletions internal/chezmoi/sourcestate.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ type SourceState struct {
encryption Encryption
ignore *patternSet
remove *patternSet
interpreters map[string]*Interpreter
interpreters map[string]Interpreter
httpClient *http.Client
logger *slog.Logger
version semver.Version
Expand Down Expand Up @@ -187,7 +187,7 @@ func WithHTTPClient(httpClient *http.Client) SourceStateOption {
}

// WithInterpreters sets the interpreters.
func WithInterpreters(interpreters map[string]*Interpreter) SourceStateOption {
func WithInterpreters(interpreters map[string]Interpreter) SourceStateOption {
return func(s *SourceState) {
s.interpreters = interpreters
}
Expand Down Expand Up @@ -2023,27 +2023,31 @@ func (s *SourceState) newSourceStateFile(
// If the target has an extension, determine if it indicates an
// interpreter to use.
extension := strings.ToLower(strings.TrimPrefix(targetRelPath.Ext(), "."))
interpreter := s.interpreters[extension]
if interpreter != nil {
if interpreter, ok := s.interpreters[extension]; ok {
// For modify scripts, the script extension is not considered part
// of the target name, so remove it.
targetRelPath = targetRelPath.Slice(0, targetRelPath.Len()-len(extension)-1)
targetStateEntryFunc = s.newModifyTargetStateEntryFunc(sourceRelPath, fileAttr, sourceLazyContents, &interpreter)
} else {
targetStateEntryFunc = s.newModifyTargetStateEntryFunc(sourceRelPath, fileAttr, sourceLazyContents, nil)
}
targetStateEntryFunc = s.newModifyTargetStateEntryFunc(sourceRelPath, fileAttr, sourceLazyContents, interpreter)
case SourceFileTypeRemove:
targetStateEntryFunc = s.newRemoveTargetStateEntryFunc(sourceRelPath, fileAttr)
case SourceFileTypeScript:
// If the script has an extension, determine if it indicates an
// interpreter to use.
extension := strings.ToLower(strings.TrimPrefix(targetRelPath.Ext(), "."))
interpreter := s.interpreters[extension]
targetStateEntryFunc = s.newScriptTargetStateEntryFunc(
sourceRelPath,
fileAttr,
targetRelPath,
sourceLazyContents,
interpreter,
)
if interpreter, ok := s.interpreters[extension]; ok {
targetStateEntryFunc = s.newScriptTargetStateEntryFunc(
sourceRelPath,
fileAttr,
targetRelPath,
sourceLazyContents,
&interpreter,
)
} else {
targetStateEntryFunc = s.newScriptTargetStateEntryFunc(sourceRelPath, fileAttr, targetRelPath, sourceLazyContents, nil)
}
case SourceFileTypeSymlink:
targetStateEntryFunc = s.newSymlinkTargetStateEntryFunc(sourceRelPath, fileAttr, sourceLazyContents)
default:
Expand Down
52 changes: 26 additions & 26 deletions internal/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,32 +97,32 @@ type warningsConfig struct {
// ConfigFile contains all data settable in the config file.
type ConfigFile struct {
// Global configuration.
CacheDirAbsPath chezmoi.AbsPath `json:"cacheDir" mapstructure:"cacheDir" yaml:"cacheDir"`
Color autoBool `json:"color" mapstructure:"color" yaml:"color"`
Data map[string]any `json:"data" mapstructure:"data" yaml:"data"`
Env map[string]string `json:"env" mapstructure:"env" yaml:"env"`
Format writeDataFormat `json:"format" mapstructure:"format" yaml:"format"`
DestDirAbsPath chezmoi.AbsPath `json:"destDir" mapstructure:"destDir" yaml:"destDir"`
GitHub gitHubConfig `json:"gitHub" mapstructure:"gitHub" yaml:"gitHub"`
Hooks map[string]hookConfig `json:"hooks" mapstructure:"hooks" yaml:"hooks"`
Interpreters map[string]*chezmoi.Interpreter `json:"interpreters" mapstructure:"interpreters" yaml:"interpreters"`
Mode chezmoi.Mode `json:"mode" mapstructure:"mode" yaml:"mode"`
Pager string `json:"pager" mapstructure:"pager" yaml:"pager"`
PersistentStateAbsPath chezmoi.AbsPath `json:"persistentState" mapstructure:"persistentState" yaml:"persistentState"`
PINEntry pinEntryConfig `json:"pinentry" mapstructure:"pinentry" yaml:"pinentry"`
Progress autoBool `json:"progress" mapstructure:"progress" yaml:"progress"`
Safe bool `json:"safe" mapstructure:"safe" yaml:"safe"`
ScriptEnv map[string]string `json:"scriptEnv" mapstructure:"scriptEnv" yaml:"scriptEnv"`
ScriptTempDir chezmoi.AbsPath `json:"scriptTempDir" mapstructure:"scriptTempDir" yaml:"scriptTempDir"`
SourceDirAbsPath chezmoi.AbsPath `json:"sourceDir" mapstructure:"sourceDir" yaml:"sourceDir"`
Template templateConfig `json:"template" mapstructure:"template" yaml:"template"`
TextConv textConv `json:"textConv" mapstructure:"textConv" yaml:"textConv"`
Umask fs.FileMode `json:"umask" mapstructure:"umask" yaml:"umask"`
UseBuiltinAge autoBool `json:"useBuiltinAge" mapstructure:"useBuiltinAge" yaml:"useBuiltinAge"`
UseBuiltinGit autoBool `json:"useBuiltinGit" mapstructure:"useBuiltinGit" yaml:"useBuiltinGit"`
Verbose bool `json:"verbose" mapstructure:"verbose" yaml:"verbose"`
Warnings warningsConfig `json:"warnings" mapstructure:"warnings" yaml:"warnings"`
WorkingTreeAbsPath chezmoi.AbsPath `json:"workingTree" mapstructure:"workingTree" yaml:"workingTree"`
CacheDirAbsPath chezmoi.AbsPath `json:"cacheDir" mapstructure:"cacheDir" yaml:"cacheDir"`
Color autoBool `json:"color" mapstructure:"color" yaml:"color"`
Data map[string]any `json:"data" mapstructure:"data" yaml:"data"`
Env map[string]string `json:"env" mapstructure:"env" yaml:"env"`
Format writeDataFormat `json:"format" mapstructure:"format" yaml:"format"`
DestDirAbsPath chezmoi.AbsPath `json:"destDir" mapstructure:"destDir" yaml:"destDir"`
GitHub gitHubConfig `json:"gitHub" mapstructure:"gitHub" yaml:"gitHub"`
Hooks map[string]hookConfig `json:"hooks" mapstructure:"hooks" yaml:"hooks"`
Interpreters map[string]chezmoi.Interpreter `json:"interpreters" mapstructure:"interpreters" yaml:"interpreters"`
Mode chezmoi.Mode `json:"mode" mapstructure:"mode" yaml:"mode"`
Pager string `json:"pager" mapstructure:"pager" yaml:"pager"`
PersistentStateAbsPath chezmoi.AbsPath `json:"persistentState" mapstructure:"persistentState" yaml:"persistentState"`
PINEntry pinEntryConfig `json:"pinentry" mapstructure:"pinentry" yaml:"pinentry"`
Progress autoBool `json:"progress" mapstructure:"progress" yaml:"progress"`
Safe bool `json:"safe" mapstructure:"safe" yaml:"safe"`
ScriptEnv map[string]string `json:"scriptEnv" mapstructure:"scriptEnv" yaml:"scriptEnv"`
ScriptTempDir chezmoi.AbsPath `json:"scriptTempDir" mapstructure:"scriptTempDir" yaml:"scriptTempDir"`
SourceDirAbsPath chezmoi.AbsPath `json:"sourceDir" mapstructure:"sourceDir" yaml:"sourceDir"`
Template templateConfig `json:"template" mapstructure:"template" yaml:"template"`
TextConv textConv `json:"textConv" mapstructure:"textConv" yaml:"textConv"`
Umask fs.FileMode `json:"umask" mapstructure:"umask" yaml:"umask"`
UseBuiltinAge autoBool `json:"useBuiltinAge" mapstructure:"useBuiltinAge" yaml:"useBuiltinAge"`
UseBuiltinGit autoBool `json:"useBuiltinGit" mapstructure:"useBuiltinGit" yaml:"useBuiltinGit"`
Verbose bool `json:"verbose" mapstructure:"verbose" yaml:"verbose"`
Warnings warningsConfig `json:"warnings" mapstructure:"warnings" yaml:"warnings"`
WorkingTreeAbsPath chezmoi.AbsPath `json:"workingTree" mapstructure:"workingTree" yaml:"workingTree"`

// Password manager configurations.
AWSSecretsManager awsSecretsManagerConfig `json:"awsSecretsManager" mapstructure:"awsSecretsManager" yaml:"awsSecretsManager"`
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestConfigFileFormatRoundTrip(t *testing.T) {
Data: map[string]any{},
Env: map[string]string{},
Hooks: map[string]hookConfig{},
Interpreters: map[string]*chezmoi.Interpreter{},
Interpreters: map[string]chezmoi.Interpreter{},
Mode: chezmoi.ModeFile,
PINEntry: pinEntryConfig{
Args: []string{},
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/util_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

const defaultEditor = "vi"

var defaultInterpreters = make(map[string]*chezmoi.Interpreter)
var defaultInterpreters = make(map[string]chezmoi.Interpreter)

func fileInfoUID(info fs.FileInfo) int {
return int(info.Sys().(*syscall.Stat_t).Uid) //nolint:forcetypeassert
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/util_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

const defaultEditor = "notepad.exe"

var defaultInterpreters = map[string]*chezmoi.Interpreter{
var defaultInterpreters = map[string]chezmoi.Interpreter{
"bat": {},
"cmd": {},
"com": {},
Expand Down

0 comments on commit d6ad485

Please sign in to comment.