Repository: twpayne/chezmoi
Pull request #443 (2019-09-30 15:31:50)

Update contributing docs


Patch:
diff --git a/README.md b/README.md
index da24899fb..b728d77e4 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,8 @@ Manage your dotfiles across multiple machines, securely.
 * [FAQ](docs/FAQ.md) for questions that aren't answered elsewhere.
 * [Changes](docs/CHANGES.md) for non-backwards compatible changes.
 * [Reference](docs/REFERENCE.md) for a complete description of chezmoi.
+* [Contributing](docs/CONTRIBUTING.md) for people looking to contribute to or
+  package chezmoi.
 
 ## What does chezmoi do and why should I use it?
 
diff --git a/cmd/apply.go b/cmd/apply.go
index 0f7d3110a..1f692e29b 100644
--- a/cmd/apply.go
+++ b/cmd/apply.go
@@ -20,12 +20,5 @@ func init() {
 
 func (c *Config) runApplyCmd(fs vfs.FS, args []string) error {
 	mutator := c.getDefaultMutator(fs)
-
-	persistentState, err := c.getPersistentState(fs, nil)
-	if err != nil {
-		return err
-	}
-	defer persistentState.Close()
-
-	return c.applyArgs(fs, args, mutator, persistentState)
+	return c.applyArgs(fs, args, mutator)
 }
diff --git a/cmd/config.go b/cmd/config.go
index baa5129d2..111c60846 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -21,7 +21,6 @@ import (
 	"github.com/twpayne/chezmoi/lib/chezmoi"
 	vfs "github.com/twpayne/go-vfs"
 	xdg "github.com/twpayne/go-xdg/v3"
-	bolt "go.etcd.io/bbolt"
 	yaml "gopkg.in/yaml.v2"
 )
 
@@ -56,6 +55,7 @@ type Config struct {
 	Pass              passCmdConfig
 	Data              map[string]interface{}
 	colored           bool
+	persistentState   chezmoi.PersistentState
 	templateFuncs     template.FuncMap
 	add               addCmdConfig
 	data              dataCmdConfig
@@ -131,7 +131,7 @@ func (c *Config) addTemplateFunc(key string, value interface{}) {
 	c.templateFuncs[key] = value
 }
 
-func (c *Config) applyArgs(fs vfs.FS, args []string, mutator chezmoi.Mutator, persistentState chezmoi.PersistentState) error {
+func (c *Config) applyArgs(fs vfs.FS, args []string, mutator chezmoi.Mutator) error {
 	fs = vfs.NewReadOnlyFS(fs)
 	ts, err := c.getTargetState(fs, nil)
 	if err != nil {
@@ -141,7 +141,7 @@ func (c *Config) applyArgs(fs vfs.FS, args []string, mutator chezmoi.Mutator, pe
 		DestDir:           ts.DestDir,
 		DryRun:            c.DryRun,
 		Ignore:            ts.TargetIgnore.Match,
-		PersistentState:   persistentState,
+		PersistentState:   c.persistentState,
 		Remove:            c.Remove,
 		ScriptStateBucket: c.scriptStateBucket,
 		Stdout:            c.Stdout(),
@@ -243,30 +243,6 @@ func (c *Config) getEntries(fs vfs.Stater, ts *chezmoi.TargetState, args []strin
 	return entries, nil
 }
 
-func (c *Config) getPersistentState(fs vfs.FS, options *bolt.Options) (chezmoi.PersistentState, error) {
-	persistentStateFile := c.getPersistentStateFile()
-	if c.DryRun {
-		if options == nil {
-			options = &bolt.Options{}
-		}
-		options.ReadOnly = true
-	}
-	return chezmoi.NewBoltPersistentState(fs, persistentStateFile, options)
-}
-
-func (c *Config) getPersistentStateFile() string {
-	if c.configFile != "" {
-		return filepath.Join(filepath.Dir(c.configFile), "chezmoistate.boltdb")
-	}
-	for _, configDir := range c.bds.ConfigDirs {
-		persistentStateFile := filepath.Join(configDir, "chezmoi", "chezmoistate.boltdb")
-		if _, err := os.Stat(persistentStateFile); err == nil {
-			return persistentStateFile
-		}
-	}
-	return filepath.Join(filepath.Dir(getDefaultConfigFile(c.bds)), "chezmoistate.boltdb")
-}
-
 func (c *Config) getTargetState(fs vfs.FS, populateOptions *chezmoi.PopulateOptions) (*chezmoi.TargetState, error) {
 	fs = vfs.NewReadOnlyFS(fs)
 	defaultData, err := getDefaultData(fs)
@@ -441,6 +417,16 @@ func getDefaultSourceDir(bds *xdg.BaseDirectorySpecification) string {
 	return filepath.Join(bds.DataHome, "chezmoi")
 }
 
+func getPersistentStateFile(bds *xdg.BaseDirectorySpecification, configFile string) string {
+	for _, configDir := range bds.ConfigDirs {
+		persistentStateFile := filepath.Join(configDir, "chezmoi", "chezmoistate.boltdb")
+		if _, err := os.Stat(persistentStateFile); err == nil {
+			return persistentStateFile
+		}
+	}
+	return filepath.Join(filepath.Dir(configFile), "chezmoistate.boltdb")
+}
+
 // isWellKnownAbbreviation returns true if word is a well known abbreviation.
 func isWellKnownAbbreviation(word string) bool {
 	_, ok := wellKnownAbbreviations[word]
diff --git a/cmd/diff.go b/cmd/diff.go
index 17074e54a..03628f6d1 100644
--- a/cmd/diff.go
+++ b/cmd/diff.go
@@ -4,7 +4,6 @@ import (
 	"github.com/spf13/cobra"
 	"github.com/twpayne/chezmoi/lib/chezmoi"
 	vfs "github.com/twpayne/go-vfs"
-	bolt "go.etcd.io/bbolt"
 )
 
 var diffCmd = &cobra.Command{
@@ -23,14 +22,5 @@ func init() {
 func (c *Config) runDiffCmd(fs vfs.FS, args []string) error {
 	c.DryRun = true
 	mutator := chezmoi.NewLoggingMutator(c.Stdout(), chezmoi.NullMutator{}, c.colored)
-
-	persistentState, err := c.getPersistentState(fs, &bolt.Options{
-		ReadOnly: true,
-	})
-	if err != nil {
-		return err
-	}
-	defer persistentState.Close()
-
-	return c.applyArgs(fs, args, mutator, persistentState)
+	return c.applyArgs(fs, args, mutator)
 }
diff --git a/cmd/init.go b/cmd/init.go
index 93bcc355b..6baaa2f87 100644
--- a/cmd/init.go
+++ b/cmd/init.go
@@ -99,11 +99,7 @@ func (c *Config) runInitCmd(fs vfs.FS, args []string) error {
 	}
 
 	if c.init.apply {
-		persistentState, err := c.getPersistentState(fs, nil)
-		if err != nil {
-			return err
-		}
-		if err := c.applyArgs(fs, nil, mutator, persistentState); err != nil {
+		if err := c.applyArgs(fs, nil, mutator); err != nil {
 			return err
 		}
 	}
diff --git a/cmd/root.go b/cmd/root.go
index e251ec272..b3ac9a504 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -108,6 +108,12 @@ func init() {
 		default:
 			printErrorAndExit(err)
 		}
+		persistentStateFile := getPersistentStateFile(config.bds, config.configFile)
+		persistentState, err := chezmoi.NewBoltPersistentState(vfs.OSFS, persistentStateFile)
+		if err != nil {
+			printErrorAndExit(err)
+		}
+		config.persistentState = persistentState
 	})
 }
 
diff --git a/cmd/update.go b/cmd/update.go
index 1e66ff31d..2b178d55b 100644
--- a/cmd/update.go
+++ b/cmd/update.go
@@ -57,12 +57,7 @@ func (c *Config) runUpdateCmd(fs vfs.FS, args []string) error {
 
 	if c.update.apply {
 		mutator := c.getDefaultMutator(fs)
-		persistentState, err := c.getPersistentState(fs, nil)
-		if err != nil {
-			return err
-		}
-		defer persistentState.Close()
-		if err := c.applyArgs(fs, nil, mutator, persistentState); err != nil {
+		if err := c.applyArgs(fs, nil, mutator); err != nil {
 			return err
 		}
 	}
diff --git a/cmd/verify.go b/cmd/verify.go
index f409d64d0..5ef726682 100644
--- a/cmd/verify.go
+++ b/cmd/verify.go
@@ -6,7 +6,6 @@ import (
 	"github.com/spf13/cobra"
 	"github.com/twpayne/chezmoi/lib/chezmoi"
 	vfs "github.com/twpayne/go-vfs"
-	bolt "go.etcd.io/bbolt"
 )
 
 var verifyCmd = &cobra.Command{
@@ -24,16 +23,7 @@ func init() {
 
 func (c *Config) runVerifyCmd(fs vfs.FS, args []string) error {
 	mutator := chezmoi.NewAnyMutator(chezmoi.NullMutator{})
-
-	persistentState, err := c.getPersistentState(fs, &bolt.Options{
-		ReadOnly: true,
-	})
-	if err != nil {
-		return err
-	}
-	defer persistentState.Close()
-
-	if err := c.applyArgs(fs, args, mutator, persistentState); err != nil {
+	if err := c.applyArgs(fs, args, mutator); err != nil {
 		return err
 	}
 	if mutator.Mutated() {
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
index 0ae6bfc54..a91e9e9ca 100644
--- a/docs/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -47,11 +47,19 @@ important.
 All changes are made via pull requests. In your pull request, please make sure
 that:
 
-* Your code is correctly formatted, according to
+* All existing tests pass.
+
+* There are appropriate additional tests that demonstrate that your PR works as
+  intended.
+
+* The documentation is updated, if necessary. For new features you should add an
+  entry in `docs/HOWTO.md` and a complete description in `docs/REFERENCE.md`.
+
+* The code is correctly formatted, according to
   [gofumports](https://mvdan.cc/gofumpt/gofumports). You can ensure this by
   running `make format`.
 
-* Your code passes [`go vet`](https://golang.org/cmd/vet/) and
+* The code passes [`go vet`](https://golang.org/cmd/vet/) and
   [`golangci-lint`](https://github.com/golangci/golangci-lint). You can ensure
   this by running `make lint`.
 
@@ -62,10 +70,6 @@ that:
 
 * Commits are logically separate, with no merge or "fixup" commits.
 
-* All tests pass. chezmoi's continuous integration tests include strict checks
-  using [`github.com/golangci/golangci-lint`](github.com/golangci/golangci-lint)
-  and [`mvdan.cc/gofumpt`](mvdan.cc/gofumpt).
-
 * The branch applies cleanly to `master`.
 
 ## Managing releases
diff --git a/docs/FAQ.md b/docs/FAQ.md
index 95cee5805..2cdfd1ea3 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -6,7 +6,6 @@
 * [If there's a mechanism in place for the above, is there also a way to tell chezmoi to ignore specific files or groups of files (e.g. by directory name or by glob)?](#if-theres-a-mechanism-in-place-for-the-above-is-there-also-a-way-to-tell-chezmoi-to-ignore-specific-files-or-groups-of-files-eg-by-directory-name-or-by-glob)
 * [If the target already exists, but is "behind" the source, can chezmoi be configured to preserve the target version before replacing it with one derived from the source?](#if-the-target-already-exists-but-is-behind-the-source-can-chezmoi-be-configured-to-preserve-the-target-version-before-replacing-it-with-one-derived-from-the-source)
 * [I've made changes to both the destination state and the source state that I want to keep. How can I keep them both?](#ive-made-changes-to-both-the-destination-state-and-the-source-state-that-i-want-to-keep-how-can-i-keep-them-both)
-* [chezmoi's source file naming system cannot handle all possible filenames](#chezmois-source-file-naming-system-cannot-handle-all-possible-filenames)
 * [gpg encryption fails. What could be wrong?](#gpg-encryption-fails-what-could-be-wrong)
 * [What inspired chezmoi?](#what-inspired-chezmoi)
 * [Can I use chezmoi outside my home directory?](#can-i-use-chezmoi-outside-my-home-directory)
@@ -52,27 +51,9 @@ diff`.
 state, target state, and destination state. Copy the changes you want to keep in
 to the source state.
 
-## chezmoi's source file naming system cannot handle all possible filenames
-
-This is correct. Certain target filenames, for example `~/dot_example`, are
-incompatible with chezmoi's
-[attributes](https://github.com/twpayne/chezmoi/blob/master/docs/REFERENCE.md#source-state-attributes)
-used in the source state.
-
-This is a deliberate, practical compromise. Target state metadata (private,
-encrypted, etc.) need to be stored for each file. Using the source state
-filename for this means that the contents of the file are untouched, there is no
-need to maintain the metadata in a separate file, is independent of the
-underlying filesystem and version control system, and unambiguously associates
-the metadata with a single file.
-
-In practice, dotfile filenames are unlikely to conflict with chezmoi's
-attributes. If this does cause a genuine problem for you, please [open an
-issue on GitHub](https://github.com/twpayne/chezmoi/issues/new).
-
 ## gpg encryption fails. What could be wrong?
 
-The `gpg.recipient` key should be ultimately trusted, otherwise encryption will
+The `gpgRecipient` key should be ultimately trusted, otherwise encryption will
 fail because gpg will prompt for input, which chezmoi does not handle. You can
 check the trust level by running:
 
@@ -81,7 +62,7 @@ check the trust level by running:
 The trust level for the recipient's key should be `6`. If it is not, you can
 change the trust level by running:
 
-    gpg --edit-key $recipient
+    gpg --edit-key $gpgRecipient
 
 Enter `trust` at the prompt and chose `5 = I trust ultimately`.
 
diff --git a/lib/chezmoi/boltpersistentstate.go b/lib/chezmoi/boltpersistentstate.go
index 40a877435..768f47396 100644
--- a/lib/chezmoi/boltpersistentstate.go
+++ b/lib/chezmoi/boltpersistentstate.go
@@ -10,20 +10,18 @@ import (
 
 // A BoltPersistentState is a state persisted with bolt.
 type BoltPersistentState struct {
-	fs      vfs.FS
-	path    string
-	perm    os.FileMode
-	options *bolt.Options
-	db      *bolt.DB
+	fs   vfs.FS
+	path string
+	perm os.FileMode
+	db   *bolt.DB
 }
 
 // NewBoltPersistentState returns a new BoltPersistentState.
-func NewBoltPersistentState(fs vfs.FS, path string, options *bolt.Options) (*BoltPersistentState, error) {
+func NewBoltPersistentState(fs vfs.FS, path string) (*BoltPersistentState, error) {
 	b := &BoltPersistentState{
-		fs:      fs,
-		path:    path,
-		perm:    0600,
-		options: options,
+		fs:   fs,
+		path: path,
+		perm: 0600,
 	}
 	_, err := fs.Stat(b.path)
 	switch {
@@ -67,7 +65,7 @@ func (b *BoltPersistentState) Delete(bucket, key []byte) error {
 
 // Get returns the value associated with key in bucket.
 func (b *BoltPersistentState) Get(bucket, key []byte) ([]byte, error) {
-	var value []byte
+	value := []byte(nil)
 	if b.db == nil {
 		return value, nil
 	}
@@ -109,12 +107,10 @@ func (b *BoltPersistentState) openDB() error {
 			return err
 		}
 	}
-	var options bolt.Options
-	if b.options != nil {
-		options = *b.options
+	options := &bolt.Options{
+		OpenFile: b.fs.OpenFile,
 	}
-	options.OpenFile = b.fs.OpenFile
-	db, err := bolt.Open(b.path, b.perm, &options)
+	db, err := bolt.Open(b.path, b.perm, options)
 	if err != nil {
 		return err
 	}
diff --git a/lib/chezmoi/chezmoi.go b/lib/chezmoi/chezmoi.go
index cec92d7aa..2be0146f4 100644
--- a/lib/chezmoi/chezmoi.go
+++ b/lib/chezmoi/chezmoi.go
@@ -28,7 +28,6 @@ const (
 
 // A PersistentState is an interface to a persistent state.
 type PersistentState interface {
-	Close() error
 	Delete(bucket, key []byte) error
 	Get(bucket, key []byte) ([]byte, error)
 	Set(bucket, key, value []byte) error


Test patch:
diff --git a/cmd/apply_test.go b/cmd/apply_test.go
index 6814b5baa..d2511f2b8 100644
--- a/cmd/apply_test.go
+++ b/cmd/apply_test.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	"github.com/twpayne/chezmoi/lib/chezmoi"
 	vfs "github.com/twpayne/go-vfs"
 	"github.com/twpayne/go-vfs/vfst"
 )
@@ -143,7 +144,6 @@ func TestApplyCommand(t *testing.T) {
 				SourceDir: "/home/user/.local/share/chezmoi",
 				DestDir:   "/home/user",
 				Umask:     022,
-				bds:       newTestBaseDirectorySpecification("/home/user"),
 			}
 			assert.NoError(t, c.runApplyCmd(fs, nil))
 			vfst.RunTests(t, fs, "",
@@ -232,7 +232,6 @@ func TestApplyFollow(t *testing.T) {
 				DestDir:   "/home/user",
 				Follow:    tc.follow,
 				Umask:     022,
-				bds:       newTestBaseDirectorySpecification("/home/user"),
 			}
 			assert.NoError(t, c.runApplyCmd(fs, nil))
 			vfst.RunTests(t, fs, "", tc.tests)
@@ -351,7 +350,6 @@ func TestApplyRemove(t *testing.T) {
 				Data:      tc.data,
 				Remove:    !tc.noRemove,
 				Umask:     022,
-				bds:       newTestBaseDirectorySpecification("/home/user"),
 			}
 			assert.NoError(t, c.runApplyCmd(fs, nil))
 			vfst.RunTests(t, fs, "", tc.tests)
@@ -369,25 +367,25 @@ func TestApplyScript(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			fs := vfs.NewPathFS(vfs.OSFS, tempDir)
 			require.NoError(t, vfst.NewBuilder().Build(fs, tc.root))
+			persistentState, err := chezmoi.NewBoltPersistentState(fs, "/home/user/.config/chezmoi/chezmoistate.boltdb")
+			require.NoError(t, err)
 			defer func() {
+				require.NoError(t, persistentState.Close())
 				require.NoError(t, os.RemoveAll(tempDir))
 				require.NoError(t, os.Mkdir(tempDir, 0700))
 			}()
-			apply := func() {
-				c := &Config{
-					SourceDir:         "/home/user/.local/share/chezmoi",
-					DestDir:           "/",
-					Umask:             022,
-					Data:              tc.data,
-					bds:               newTestBaseDirectorySpecification("/home/user"),
-					scriptStateBucket: []byte("script"),
-				}
-				require.NoError(t, c.runApplyCmd(fs, nil))
+			c := &Config{
+				SourceDir:         "/home/user/.local/share/chezmoi",
+				DestDir:           "/",
+				Umask:             022,
+				Data:              tc.data,
+				persistentState:   persistentState,
+				scriptStateBucket: []byte("script"),
 			}
 			// Run apply three times. As chezmoi should be idempotent, the
 			// result should be the same each time.
 			for i := 0; i < 3; i++ {
-				apply()
+				assert.NoError(t, c.runApplyCmd(fs, nil))
 			}
 			vfst.RunTests(t, vfs.OSFS, "", tc.tests)
 		})
@@ -395,6 +393,8 @@ func TestApplyScript(t *testing.T) {
 }
 
 func TestApplyRunOnce(t *testing.T) {
+	statePath := "/home/user/.config/chezmoi/chezmoistate.boltdb"
+
 	tempDir, err := ioutil.TempDir("", "chezmoi")
 	require.NoError(t, err)
 	defer func() {
@@ -404,12 +404,18 @@ func TestApplyRunOnce(t *testing.T) {
 
 	fs, cleanup, err := vfst.NewTestFS(
 		[]interface{}{
+			map[string]interface{}{
+				filepath.Dir(statePath): &vfst.Dir{Perm: 0755},
+			},
 			getRunOnceFiles(),
 		},
 	)
 	require.NoError(t, err)
 	defer cleanup()
 
+	persistentState, err := chezmoi.NewBoltPersistentState(fs, statePath)
+	require.NoError(t, err)
+
 	c := &Config{
 		SourceDir: "/home/user/.local/share/chezmoi",
 		DestDir:   "/",
@@ -417,13 +423,13 @@ func TestApplyRunOnce(t *testing.T) {
 		Data: map[string]interface{}{
 			"TempFile": tempFile,
 		},
-		bds:               newTestBaseDirectorySpecification("/home/user"),
+		persistentState:   persistentState,
 		scriptStateBucket: []byte("script"),
 	}
 
 	require.NoError(t, c.runApplyCmd(fs, nil))
 	vfst.RunTests(t, fs, "",
-		vfst.TestPath("/home/user/.config/chezmoi/chezmoistate.boltdb",
+		vfst.TestPath(statePath,
 			vfst.TestModeIsRegular,
 		),
 	)
diff --git a/cmd/cmd_test.go b/cmd/cmd_test.go
index d3cbd39d9..7f67cda02 100644
--- a/cmd/cmd_test.go
+++ b/cmd/cmd_test.go
@@ -22,7 +22,6 @@ func TestExercise(t *testing.T) {
 		DestDir:   "/home/user",
 		Umask:     022,
 		Verbose:   true,
-		bds:       newTestBaseDirectorySpecification("/home/user"),
 		remove: removeCmdConfig{
 			force: true,
 		},
diff --git a/cmd/config_test.go b/cmd/config_test.go
index 4c8ed52ec..84d9a7bca 100644
--- a/cmd/config_test.go
+++ b/cmd/config_test.go
@@ -1,11 +1,9 @@
 package cmd
 
 import (
-	"path/filepath"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-	"github.com/twpayne/go-xdg/v3"
 )
 
 func TestUpperSnakeCaseToCamelCase(t *testing.T) {
@@ -20,13 +18,3 @@ func TestUpperSnakeCaseToCamelCase(t *testing.T) {
 		assert.Equal(t, want, upperSnakeCaseToCamelCase(s))
 	}
 }
-
-//nolint:unparam
-func newTestBaseDirectorySpecification(homeDir string) *xdg.BaseDirectorySpecification {
-	return &xdg.BaseDirectorySpecification{
-		ConfigHome: filepath.Join(homeDir, ".config"),
-		DataHome:   filepath.Join(homeDir, ".local"),
-		CacheHome:  filepath.Join(homeDir, ".cache"),
-		RuntimeDir: filepath.Join(homeDir, ".run"),
-	}
-}
diff --git a/cmd/diff_posix_test.go b/cmd/diff_posix_test.go
index a82f979cd..469b57fa8 100644
--- a/cmd/diff_posix_test.go
+++ b/cmd/diff_posix_test.go
@@ -31,7 +31,6 @@ func TestDiffDoesNotRunScript(t *testing.T) {
 		SourceDir: "/home/user/.local/share/chezmoi",
 		DestDir:   "/",
 		Umask:     022,
-		bds:       newTestBaseDirectorySpecification("/home/user"),
 	}
 	assert.NoError(t, c.runDiffCmd(fs, nil))
 	vfst.RunTests(t, vfs.OSFS, "",
diff --git a/cmd/import_test.go b/cmd/import_test.go
index 80d7535b9..f9789eaf4 100644
--- a/cmd/import_test.go
+++ b/cmd/import_test.go
@@ -37,6 +37,7 @@ func TestImportCmd(t *testing.T) {
 		"/home/user/.local/share/chezmoi": &vfst.Dir{Perm: 0700},
 	})
 	require.NoError(t, err)
+	fs.Keep()
 	defer cleanup()
 
 	c := &Config{
diff --git a/lib/chezmoi/boltpersistentstate_test.go b/lib/chezmoi/boltpersistentstate_test.go
index 77f779599..126706250 100644
--- a/lib/chezmoi/boltpersistentstate_test.go
+++ b/lib/chezmoi/boltpersistentstate_test.go
@@ -2,12 +2,10 @@ package chezmoi
 
 import (
 	"testing"
-	"time"
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/twpayne/go-vfs/vfst"
-	bolt "go.etcd.io/bbolt"
 )
 
 var _ PersistentState = &BoltPersistentState{}
@@ -20,7 +18,7 @@ func TestBoltPersistentState(t *testing.T) {
 	defer cleanup()
 
 	path := "/home/user/.config/chezmoi/chezmoistate.boltdb"
-	b, err := NewBoltPersistentState(fs, path, nil)
+	b, err := NewBoltPersistentState(fs, path)
 	require.NoError(t, err)
 	vfst.RunTests(t, fs, "",
 		vfst.TestPath(path,
@@ -63,7 +61,7 @@ func TestBoltPersistentState(t *testing.T) {
 
 	require.NoError(t, b.Close())
 
-	b, err = NewBoltPersistentState(fs, path, nil)
+	b, err = NewBoltPersistentState(fs, path)
 	require.NoError(t, err)
 
 	require.NoError(t, b.Delete(bucket, key))
@@ -72,49 +70,3 @@ func TestBoltPersistentState(t *testing.T) {
 	require.NoError(t, err)
 	assert.Equal(t, []byte(nil), actualValue)
 }
-
-func TestBoltPersistentStateReadOnly(t *testing.T) {
-	fs, cleanup, err := vfst.NewTestFS(map[string]interface{}{
-		"/home/user/.config/chezmoi": &vfst.Dir{Perm: 0755},
-	})
-	require.NoError(t, err)
-	defer cleanup()
-
-	path := "/home/user/.config/chezmoi/chezmoistate.boltdb"
-	bucket := []byte("bucket")
-	key := []byte("key")
-	value := []byte("value")
-
-	a, err := NewBoltPersistentState(fs, path, nil)
-	require.NoError(t, err)
-	require.NoError(t, a.Set(bucket, key, value))
-	require.NoError(t, a.Close())
-
-	b, err := NewBoltPersistentState(fs, path, &bolt.Options{
-		ReadOnly: true,
-		Timeout:  1 * time.Second,
-	})
-	require.NoError(t, err)
-	defer b.Close()
-
-	c, err := NewBoltPersistentState(fs, path, &bolt.Options{
-		ReadOnly: true,
-		Timeout:  1 * time.Second,
-	})
-	require.NoError(t, err)
-	defer c.Close()
-
-	actualValueB, err := b.Get(bucket, key)
-	require.NoError(t, err)
-	assert.Equal(t, value, actualValueB)
-
-	actualValueC, err := c.Get(bucket, key)
-	require.NoError(t, err)
-	assert.Equal(t, value, actualValueC)
-
-	assert.Error(t, b.Set(bucket, key, value))
-	assert.Error(t, c.Set(bucket, key, value))
-
-	require.NoError(t, b.Close())
-	require.NoError(t, c.Close())
-}