@cryptotaxi247 / kubo / commits / 6817fd474

feat(cmds): allow to set the configuration file path

Lucas Molas committed Jan 3, 2022 at 12:00 UTC 6817fd474467face64b08440e5c938e6566c39d5
10 files changed +88 -68
cmd/ipfs/daemon.go
+3 -2
@@ -298,7 +298,8 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
298 }
299
300 // Read Migration section of IPFS config
301 - migrationCfg, err := migrations.ReadMigrationConfig(cctx.ConfigRoot)
301 + configFileOpt, _ := req.Options[commands.ConfigFileOption].(string)
302 + migrationCfg, err := migrations.ReadMigrationConfig(cctx.ConfigRoot, configFileOpt)
303 if err != nil {
304 return err
305 }
@@ -309,7 +310,7 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
310 // to construct the particular IPFS fetcher implementation used here,
311 // which is called only if an IPFS fetcher is needed.
312 newIpfsFetcher := func(distPath string) migrations.Fetcher {
312 - return ipfsfetcher.NewIpfsFetcher(distPath, 0, &cctx.ConfigRoot)
313 + return ipfsfetcher.NewIpfsFetcher(distPath, 0, &cctx.ConfigRoot, configFileOpt)
314 }
315
316 // Fetch migrations from current distribution, or location from environ
cmd/ipfs/main.go
+1 -1
@@ -303,7 +303,7 @@ func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
303 }
304
305 func getRepoPath(req *cmds.Request) (string, error) {
306 - repoOpt, found := req.Options["config"].(string)
306 + repoOpt, found := req.Options[corecmds.RepoDirOption].(string)
307 if found && repoOpt != "" {
308 return repoOpt, nil
309 }
config/config.go
+17 -3
@@ -76,9 +76,23 @@ func Path(configroot, extension string) (string, error) {
76 }
77
78 // Filename returns the configuration file path given a configuration root
79 -// directory. If the configuration root directory is empty, use the default one
80 -func Filename(configroot string) (string, error) {
81 - return Path(configroot, DefaultConfigFile)
79 +// directory and a user-provided configuration file path argument with the
80 +// following rules:
81 +// * If the user-provided configuration file path is empty, use the default one.
82 +// * If the configuration root directory is empty, use the default one.
83 +// * If the user-provided configuration file path is only a file name, use the
84 +// configuration root directory, otherwise use only the user-provided path
85 +// and ignore the configuration root.
86 +func Filename(configroot string, userConfigFile string) (string, error) {
87 + if userConfigFile == "" {
88 + return Path(configroot, DefaultConfigFile)
89 + }
90 +
91 + if filepath.Dir(userConfigFile) == "." {
92 + return Path(configroot, userConfigFile)
93 + }
94 +
95 + return userConfigFile, nil
96 }
97
98 // HumanOutput gets a config value ready for printing
core/commands/config.go
+4 -2
@@ -186,7 +186,8 @@ NOTE: For security reasons, this command will omit your private key and remote s
186 return err
187 }
188
189 - fname, err := config.Filename(cfgRoot)
189 + configFileOpt, _ := req.Options[ConfigFileOption].(string)
190 + fname, err := config.Filename(cfgRoot, configFileOpt)
191 if err != nil {
192 return err
193 }
@@ -291,7 +292,8 @@ variable set to your preferred text editor.
292 return err
293 }
294
294 - filename, err := config.Filename(cfgRoot)
295 + configFileOpt, _ := req.Options[ConfigFileOption].(string)
296 + filename, err := config.Filename(cfgRoot, configFileOpt)
297 if err != nil {
298 return err
299 }
core/commands/root.go
+5 -1
@@ -19,6 +19,8 @@ var log = logging.Logger("core/commands")
19 var ErrNotOnline = errors.New("this command must be run in online mode. Try running 'ipfs daemon' first")
20
21 const (
22 + RepoDirOption = "repo-dir"
23 + ConfigFileOption = "config-file"
24 ConfigOption = "config"
25 DebugOption = "debug"
26 LocalOption = "local" // DEPRECATED: use OfflineOption
@@ -94,7 +96,9 @@ The CLI will exit with one of the following values:
96 `,
97 },
98 Options: []cmds.Option{
97 - cmds.StringOption(ConfigOption, "c", "Path to the configuration file to use."),
99 + cmds.StringOption(RepoDirOption, "Path to the repository directory to use."),
100 + cmds.StringOption(ConfigFileOption, "Path to the configuration file to use."),
101 + cmds.StringOption(ConfigOption, "c", "[DEPRECATED] Path to the configuration file to use."),
102 cmds.BoolOption(DebugOption, "D", "Operate in debug mode."),
103 cmds.BoolOption(cmds.OptLongHelp, "Show the full command help text."),
104 cmds.BoolOption(cmds.OptShortHelp, "Show a short version of the command help text."),
repo/fsrepo/fsrepo.go
+32 -35
@@ -96,6 +96,9 @@ type FSRepo struct {
96 closed bool
97 // path is the file-system path
98 path string
99 + // Path to the configuration file that may or may not be inside the FSRepo
100 + // path (see config.Filename for more details).
101 + configFilePath string
102 // lockfile is the file system lock to prevent others from opening
103 // the same fsrepo path concurrently
104 lockfile io.Closer
@@ -111,16 +114,25 @@ var _ repo.Repo = (*FSRepo)(nil)
114 // initialized.
115 func Open(repoPath string) (repo.Repo, error) {
116 fn := func() (repo.Repo, error) {
114 - return open(repoPath)
117 + return open(repoPath, "")
118 }
119 return onlyOne.Open(repoPath, fn)
120 }
121
119 -func open(repoPath string) (repo.Repo, error) {
122 +// OpenWithUserConfig is the equivalent to the Open function above but with the
123 +// option to set the configuration file path instead of using the default.
124 +func OpenWithUserConfig(repoPath string, userConfigFilePath string) (repo.Repo, error) {
125 + fn := func() (repo.Repo, error) {
126 + return open(repoPath, userConfigFilePath)
127 + }
128 + return onlyOne.Open(repoPath, fn)
129 +}
130 +
131 +func open(repoPath string, userConfigFilePath string) (repo.Repo, error) {
132 packageLock.Lock()
133 defer packageLock.Unlock()
134
123 - r, err := newFSRepo(repoPath)
135 + r, err := newFSRepo(repoPath, userConfigFilePath)
136 if err != nil {
137 return nil, err
138 }
@@ -185,13 +197,19 @@ func open(repoPath string) (repo.Repo, error) {
197 return r, nil
198 }
199
188 -func newFSRepo(rpath string) (*FSRepo, error) {
200 +func newFSRepo(rpath string, userConfigFilePath string) (*FSRepo, error) {
201 expPath, err := homedir.Expand(filepath.Clean(rpath))
202 if err != nil {
203 return nil, err
204 }
205
194 - return &FSRepo{path: expPath}, nil
206 + configFilePath, err := config.Filename(rpath, userConfigFilePath)
207 + if err != nil {
208 + // FIXME: Personalize this when the user config path is "".
209 + return nil, fmt.Errorf("finding config filepath from repo %s and user config %s: %w",
210 + rpath, userConfigFilePath, err)
211 + }
212 + return &FSRepo{path: expPath, configFilePath: configFilePath}, nil
213 }
214
215 func checkInitialized(path string) error {
@@ -208,7 +226,7 @@ func checkInitialized(path string) error {
226 // configIsInitialized returns true if the repo is initialized at
227 // provided |path|.
228 func configIsInitialized(path string) bool {
211 - configFilename, err := config.Filename(path)
229 + configFilename, err := config.Filename(path, "")
230 if err != nil {
231 return false
232 }
@@ -222,7 +240,7 @@ func initConfig(path string, conf *config.Config) error {
240 if configIsInitialized(path) {
241 return nil
242 }
225 - configFilename, err := config.Filename(path)
243 + configFilename, err := config.Filename(path, "")
244 if err != nil {
245 return err
246 }
@@ -372,11 +390,7 @@ func (r *FSRepo) SetAPIAddr(addr ma.Multiaddr) error {
390
391 // openConfig returns an error if the config file is not present.
392 func (r *FSRepo) openConfig() error {
375 - configFilename, err := config.Filename(r.path)
376 - if err != nil {
377 - return err
378 - }
379 - conf, err := serialize.Load(configFilename)
393 + conf, err := serialize.Load(r.configFilePath)
394 if err != nil {
395 return err
396 }
@@ -507,12 +521,7 @@ func (r *FSRepo) BackupConfig(prefix string) (string, error) {
521 }
522 defer temp.Close()
523
510 - configFilename, err := config.Filename(r.path)
511 - if err != nil {
512 - return "", err
513 - }
514 -
515 - orig, err := os.OpenFile(configFilename, os.O_RDONLY, 0600)
524 + orig, err := os.OpenFile(r.configFilePath, os.O_RDONLY, 0600)
525 if err != nil {
526 return "", err
527 }
@@ -546,15 +555,11 @@ func (r *FSRepo) SetConfig(updated *config.Config) error {
555 packageLock.Lock()
556 defer packageLock.Unlock()
557
549 - configFilename, err := config.Filename(r.path)
550 - if err != nil {
551 - return err
552 - }
558 // to avoid clobbering user-provided keys, must read the config from disk
559 // as a map, write the updated struct values to the map and write the map
560 // to disk.
561 var mapconf map[string]interface{}
557 - if err := serialize.ReadConfigFile(configFilename, &mapconf); err != nil {
562 + if err := serialize.ReadConfigFile(r.configFilePath, &mapconf); err != nil {
563 return err
564 }
565 m, err := config.ToMap(updated)
@@ -562,7 +567,7 @@ func (r *FSRepo) SetConfig(updated *config.Config) error {
567 return err
568 }
569 mergedMap := common.MapMergeDeep(mapconf, m)
565 - if err := serialize.WriteConfigFile(configFilename, mergedMap); err != nil {
570 + if err := serialize.WriteConfigFile(r.configFilePath, mergedMap); err != nil {
571 return err
572 }
573 // Do not use `*r.config = ...`. This will modify the *shared* config
@@ -580,12 +585,8 @@ func (r *FSRepo) GetConfigKey(key string) (interface{}, error) {
585 return nil, errors.New("repo is closed")
586 }
587
583 - filename, err := config.Filename(r.path)
584 - if err != nil {
585 - return nil, err
586 - }
588 var cfg map[string]interface{}
588 - if err := serialize.ReadConfigFile(filename, &cfg); err != nil {
589 + if err := serialize.ReadConfigFile(r.configFilePath, &cfg); err != nil {
590 return nil, err
591 }
592 return common.MapGetKV(cfg, key)
@@ -600,13 +601,9 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
601 return errors.New("repo is closed")
602 }
603
603 - filename, err := config.Filename(r.path)
604 - if err != nil {
605 - return err
606 - }
604 // Load into a map so we don't end up writing any additional defaults to the config file.
605 var mapconf map[string]interface{}
609 - if err := serialize.ReadConfigFile(filename, &mapconf); err != nil {
606 + if err := serialize.ReadConfigFile(r.configFilePath, &mapconf); err != nil {
607 return err
608 }
609
@@ -636,7 +633,7 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
633 }
634 r.config = conf
635
639 - if err := serialize.WriteConfigFile(filename, mapconf); err != nil {
636 + if err := serialize.WriteConfigFile(r.configFilePath, mapconf); err != nil {
637 return err
638 }
639
repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go
+12 -10
@@ -33,9 +33,10 @@ const (
33 )
34
35 type IpfsFetcher struct {
36 - distPath string
37 - limit int64
38 - repoRoot *string
36 + distPath string
37 + limit int64
38 + repoRoot *string
39 + userConfigFile string
40
41 openOnce sync.Once
42 openErr error
@@ -62,11 +63,12 @@ var _ migrations.Fetcher = (*IpfsFetcher)(nil)
63 // Bootstrap and peer information in read from the IPFS config file in
64 // repoRoot, unless repoRoot is nil. If repoRoot is empty (""), then read the
65 // config from the default IPFS directory.
65 -func NewIpfsFetcher(distPath string, fetchLimit int64, repoRoot *string) *IpfsFetcher {
66 +func NewIpfsFetcher(distPath string, fetchLimit int64, repoRoot *string, userConfigFile string) *IpfsFetcher {
67 f := &IpfsFetcher{
67 - limit: defaultFetchLimit,
68 - distPath: migrations.LatestIpfsDist,
69 - repoRoot: repoRoot,
68 + limit: defaultFetchLimit,
69 + distPath: migrations.LatestIpfsDist,
70 + repoRoot: repoRoot,
71 + userConfigFile: userConfigFile,
72 }
73
74 if distPath != "" {
@@ -92,7 +94,7 @@ func (f *IpfsFetcher) Fetch(ctx context.Context, filePath string) ([]byte, error
94 // Initialize and start IPFS node on first call to Fetch, since the fetcher
95 // may be created by not used.
96 f.openOnce.Do(func() {
95 - bootstrap, peers := readIpfsConfig(f.repoRoot)
97 + bootstrap, peers := readIpfsConfig(f.repoRoot, f.userConfigFile)
98 f.ipfsTmpDir, f.openErr = initTempNode(ctx, bootstrap, peers)
99 if f.openErr != nil {
100 return
@@ -288,12 +290,12 @@ func parsePath(fetchPath string) (ipath.Path, error) {
290 return ipfsPath, ipfsPath.IsValid()
291 }
292
291 -func readIpfsConfig(repoRoot *string) (bootstrap []string, peers []peer.AddrInfo) {
293 +func readIpfsConfig(repoRoot *string, userConfigFile string) (bootstrap []string, peers []peer.AddrInfo) {
294 if repoRoot == nil {
295 return
296 }
297
296 - cfgPath, err := config.Filename(*repoRoot)
298 + cfgPath, err := config.Filename(*repoRoot, userConfigFile)
299 if err != nil {
300 fmt.Fprintln(os.Stderr, err)
301 return
repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher_test.go
+7 -7
@@ -26,7 +26,7 @@ func TestIpfsFetcher(t *testing.T) {
26 ctx, cancel := context.WithCancel(context.Background())
27 defer cancel()
28
29 - fetcher := NewIpfsFetcher("", 0, nil)
29 + fetcher := NewIpfsFetcher("", 0, nil, "")
30 defer fetcher.Close()
31
32 out, err := fetcher.Fetch(ctx, "go-ipfs/versions")
@@ -62,7 +62,7 @@ func TestInitIpfsFetcher(t *testing.T) {
62 ctx, cancel := context.WithCancel(context.Background())
63 defer cancel()
64
65 - f := NewIpfsFetcher("", 0, nil)
65 + f := NewIpfsFetcher("", 0, nil, "")
66 defer f.Close()
67
68 // Init ipfs repo
@@ -132,7 +132,7 @@ func TestReadIpfsConfig(t *testing.T) {
132 `
133
134 noSuchDir := "no_such_dir-5953aa51-1145-4efd-afd1-a069075fcf76"
135 - bootstrap, peers := readIpfsConfig(&noSuchDir)
135 + bootstrap, peers := readIpfsConfig(&noSuchDir, "")
136 if bootstrap != nil {
137 t.Error("expected nil bootstrap")
138 }
@@ -142,12 +142,12 @@ func TestReadIpfsConfig(t *testing.T) {
142
143 tmpDir := makeConfig(t, testConfig)
144
145 - bootstrap, peers = readIpfsConfig(nil)
145 + bootstrap, peers = readIpfsConfig(nil, "")
146 if bootstrap != nil || peers != nil {
147 t.Fatal("expected nil ipfs config items")
148 }
149
150 - bootstrap, peers = readIpfsConfig(&tmpDir)
150 + bootstrap, peers = readIpfsConfig(&tmpDir, "")
151 if len(bootstrap) != 2 {
152 t.Fatal("wrong number of bootstrap addresses")
153 }
@@ -189,7 +189,7 @@ func TestBadBootstrappingIpfsConfig(t *testing.T) {
189
190 tmpDir := makeConfig(t, configBadBootstrap)
191
192 - bootstrap, peers := readIpfsConfig(&tmpDir)
192 + bootstrap, peers := readIpfsConfig(&tmpDir, "")
193 if bootstrap != nil {
194 t.Fatal("expected nil bootstrap")
195 }
@@ -219,7 +219,7 @@ func TestBadPeersIpfsConfig(t *testing.T) {
219
220 tmpDir := makeConfig(t, configBadPeers)
221
222 - bootstrap, peers := readIpfsConfig(&tmpDir)
222 + bootstrap, peers := readIpfsConfig(&tmpDir, "")
223 if peers != nil {
224 t.Fatal("expected nil peers")
225 }
repo/fsrepo/migrations/migrations.go
+2 -2
@@ -115,12 +115,12 @@ func ExeName(name string) string {
115 // ReadMigrationConfig reads the Migration section of the IPFS config, avoiding
116 // reading anything other than the Migration section. That way, we're free to
117 // make arbitrary changes to all _other_ sections in migrations.
118 -func ReadMigrationConfig(repoRoot string) (*config.Migration, error) {
118 +func ReadMigrationConfig(repoRoot string, userConfigFile string) (*config.Migration, error) {
119 var cfg struct {
120 Migration config.Migration
121 }
122
123 - cfgPath, err := config.Filename(repoRoot)
123 + cfgPath, err := config.Filename(repoRoot, userConfigFile)
124 if err != nil {
125 return nil, err
126 }
repo/fsrepo/migrations/migrations_test.go
+5 -5
@@ -221,7 +221,7 @@ var testConfig = `
221 func TestReadMigrationConfigDefaults(t *testing.T) {
222 tmpDir := makeConfig(t, "{}")
223
224 - cfg, err := ReadMigrationConfig(tmpDir)
224 + cfg, err := ReadMigrationConfig(tmpDir, "")
225 if err != nil {
226 t.Fatal(err)
227 }
@@ -243,7 +243,7 @@ func TestReadMigrationConfigDefaults(t *testing.T) {
243 func TestReadMigrationConfigErrors(t *testing.T) {
244 tmpDir := makeConfig(t, `{"Migration": {"Keep": "badvalue"}}`)
245
246 - _, err := ReadMigrationConfig(tmpDir)
246 + _, err := ReadMigrationConfig(tmpDir, "")
247 if err == nil {
248 t.Fatal("expected error")
249 }
@@ -252,13 +252,13 @@ func TestReadMigrationConfigErrors(t *testing.T) {
252 }
253
254 os.RemoveAll(tmpDir)
255 - _, err = ReadMigrationConfig(tmpDir)
255 + _, err = ReadMigrationConfig(tmpDir, "")
256 if err == nil {
257 t.Fatal("expected error")
258 }
259
260 tmpDir = makeConfig(t, `}{`)
261 - _, err = ReadMigrationConfig(tmpDir)
261 + _, err = ReadMigrationConfig(tmpDir, "")
262 if err == nil {
263 t.Fatal("expected error")
264 }
@@ -267,7 +267,7 @@ func TestReadMigrationConfigErrors(t *testing.T) {
267 func TestReadMigrationConfig(t *testing.T) {
268 tmpDir := makeConfig(t, testConfig)
269
270 - cfg, err := ReadMigrationConfig(tmpDir)
270 + cfg, err := ReadMigrationConfig(tmpDir, "")
271 if err != nil {
272 t.Fatal(err)
273 }