Skip to content

Commit

Permalink
feat(cmds): allow to set the configuration file path
Browse files Browse the repository at this point in the history
  • Loading branch information
schomatis committed Mar 9, 2022
1 parent 816a128 commit 34356a1
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 69 deletions.
5 changes: 3 additions & 2 deletions cmd/ipfs/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,8 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
}

// Read Migration section of IPFS config
migrationCfg, err := migrations.ReadMigrationConfig(cctx.ConfigRoot)
configFileOpt, _ := req.Options[commands.ConfigFileOption].(string)
migrationCfg, err := migrations.ReadMigrationConfig(cctx.ConfigRoot, configFileOpt)
if err != nil {
return err
}
Expand All @@ -309,7 +310,7 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
// to construct the particular IPFS fetcher implementation used here,
// which is called only if an IPFS fetcher is needed.
newIpfsFetcher := func(distPath string) migrations.Fetcher {
return ipfsfetcher.NewIpfsFetcher(distPath, 0, &cctx.ConfigRoot)
return ipfsfetcher.NewIpfsFetcher(distPath, 0, &cctx.ConfigRoot, configFileOpt)
}

// Fetch migrations from current distribution, or location from environ
Expand Down
2 changes: 1 addition & 1 deletion cmd/ipfs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
}

func getRepoPath(req *cmds.Request) (string, error) {
repoOpt, found := req.Options["config"].(string)
repoOpt, found := req.Options[corecmds.RepoDirOption].(string)
if found && repoOpt != "" {
return repoOpt, nil
}
Expand Down
20 changes: 17 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,23 @@ func Path(configroot, extension string) (string, error) {
}

// Filename returns the configuration file path given a configuration root
// directory. If the configuration root directory is empty, use the default one
func Filename(configroot string) (string, error) {
return Path(configroot, DefaultConfigFile)
// directory and a user-provided configuration file path argument with the
// following rules:
// * If the user-provided configuration file path is empty, use the default one.
// * If the configuration root directory is empty, use the default one.
// * If the user-provided configuration file path is only a file name, use the
// configuration root directory, otherwise use only the user-provided path
// and ignore the configuration root.
func Filename(configroot string, userConfigFile string) (string, error) {
if userConfigFile == "" {
return Path(configroot, DefaultConfigFile)
}

if filepath.Dir(userConfigFile) == "." {
return Path(configroot, userConfigFile)
}

return userConfigFile, nil
}

// HumanOutput gets a config value ready for printing
Expand Down
6 changes: 4 additions & 2 deletions core/commands/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ NOTE: For security reasons, this command will omit your private key and remote s
return err
}

fname, err := config.Filename(cfgRoot)
configFileOpt, _ := req.Options[ConfigFileOption].(string)
fname, err := config.Filename(cfgRoot, configFileOpt)
if err != nil {
return err
}
Expand Down Expand Up @@ -289,7 +290,8 @@ variable set to your preferred text editor.
return err
}

filename, err := config.Filename(cfgRoot)
configFileOpt, _ := req.Options[ConfigFileOption].(string)
filename, err := config.Filename(cfgRoot, configFileOpt)
if err != nil {
return err
}
Expand Down
6 changes: 5 additions & 1 deletion core/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ var log = logging.Logger("core/commands")
var ErrNotOnline = errors.New("this command must be run in online mode. Try running 'ipfs daemon' first")

const (
RepoDirOption = "repo-dir"
ConfigFileOption = "config-file"
ConfigOption = "config"
DebugOption = "debug"
LocalOption = "local" // DEPRECATED: use OfflineOption
Expand Down Expand Up @@ -95,7 +97,9 @@ The CLI will exit with one of the following values:
`,
},
Options: []cmds.Option{
cmds.StringOption(ConfigOption, "c", "Path to the configuration file to use."),
cmds.StringOption(RepoDirOption, "Path to the repository directory to use."),
cmds.StringOption(ConfigFileOption, "Path to the configuration file to use."),
cmds.StringOption(ConfigOption, "c", "[DEPRECATED] Path to the configuration file to use."),
cmds.BoolOption(DebugOption, "D", "Operate in debug mode."),
cmds.BoolOption(cmds.OptLongHelp, "Show the full command help text."),
cmds.BoolOption(cmds.OptShortHelp, "Show a short version of the command help text."),
Expand Down
69 changes: 33 additions & 36 deletions repo/fsrepo/fsrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ type FSRepo struct {
closed bool
// path is the file-system path
path string
// Path to the configuration file that may or may not be inside the FSRepo
// path (see config.Filename for more details).
configFilePath string
// lockfile is the file system lock to prevent others from opening
// the same fsrepo path concurrently
lockfile io.Closer
Expand All @@ -111,16 +114,25 @@ var _ repo.Repo = (*FSRepo)(nil)
// initialized.
func Open(repoPath string) (repo.Repo, error) {
fn := func() (repo.Repo, error) {
return open(repoPath)
return open(repoPath, "")
}
return onlyOne.Open(repoPath, fn)
}

func open(repoPath string) (repo.Repo, error) {
// OpenWithUserConfig is the equivalent to the Open function above but with the
// option to set the configuration file path instead of using the default.
func OpenWithUserConfig(repoPath string, userConfigFilePath string) (repo.Repo, error) {
fn := func() (repo.Repo, error) {
return open(repoPath, userConfigFilePath)
}
return onlyOne.Open(repoPath, fn)
}

func open(repoPath string, userConfigFilePath string) (repo.Repo, error) {
packageLock.Lock()
defer packageLock.Unlock()

r, err := newFSRepo(repoPath)
r, err := newFSRepo(repoPath, userConfigFilePath)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -185,13 +197,19 @@ func open(repoPath string) (repo.Repo, error) {
return r, nil
}

func newFSRepo(rpath string) (*FSRepo, error) {
func newFSRepo(rpath string, userConfigFilePath string) (*FSRepo, error) {
expPath, err := homedir.Expand(filepath.Clean(rpath))
if err != nil {
return nil, err
}

return &FSRepo{path: expPath}, nil
configFilePath, err := config.Filename(rpath, userConfigFilePath)
if err != nil {
// FIXME: Personalize this when the user config path is "".
return nil, fmt.Errorf("finding config filepath from repo %s and user config %s: %w",
rpath, userConfigFilePath, err)
}
return &FSRepo{path: expPath, configFilePath: configFilePath}, nil
}

func checkInitialized(path string) error {
Expand All @@ -214,7 +232,7 @@ func ConfigAt(repoPath string) (*config.Config, error) {
packageLock.Lock()
defer packageLock.Unlock()

configFilename, err := config.Filename(repoPath)
configFilename, err := config.Filename(repoPath, "")
if err != nil {
return nil, err
}
Expand All @@ -224,7 +242,7 @@ func ConfigAt(repoPath string) (*config.Config, error) {
// configIsInitialized returns true if the repo is initialized at
// provided |path|.
func configIsInitialized(path string) bool {
configFilename, err := config.Filename(path)
configFilename, err := config.Filename(path, "")
if err != nil {
return false
}
Expand All @@ -238,7 +256,7 @@ func initConfig(path string, conf *config.Config) error {
if configIsInitialized(path) {
return nil
}
configFilename, err := config.Filename(path)
configFilename, err := config.Filename(path, "")
if err != nil {
return err
}
Expand Down Expand Up @@ -388,11 +406,7 @@ func (r *FSRepo) SetAPIAddr(addr ma.Multiaddr) error {

// openConfig returns an error if the config file is not present.
func (r *FSRepo) openConfig() error {
configFilename, err := config.Filename(r.path)
if err != nil {
return err
}
conf, err := serialize.Load(configFilename)
conf, err := serialize.Load(r.configFilePath)
if err != nil {
return err
}
Expand Down Expand Up @@ -523,12 +537,7 @@ func (r *FSRepo) BackupConfig(prefix string) (string, error) {
}
defer temp.Close()

configFilename, err := config.Filename(r.path)
if err != nil {
return "", err
}

orig, err := os.OpenFile(configFilename, os.O_RDONLY, 0600)
orig, err := os.OpenFile(r.configFilePath, os.O_RDONLY, 0600)
if err != nil {
return "", err
}
Expand All @@ -544,15 +553,11 @@ func (r *FSRepo) BackupConfig(prefix string) (string, error) {

// setConfigUnsynced is for private use.
func (r *FSRepo) setConfigUnsynced(updated *config.Config) error {
configFilename, err := config.Filename(r.path)
if err != nil {
return err
}
// to avoid clobbering user-provided keys, must read the config from disk
// as a map, write the updated struct values to the map and write the map
// to disk.
var mapconf map[string]interface{}
if err := serialize.ReadConfigFile(configFilename, &mapconf); err != nil {
if err := serialize.ReadConfigFile(r.configFilePath, &mapconf); err != nil {
return err
}
m, err := config.ToMap(updated)
Expand All @@ -562,7 +567,7 @@ func (r *FSRepo) setConfigUnsynced(updated *config.Config) error {
for k, v := range m {
mapconf[k] = v
}
if err := serialize.WriteConfigFile(configFilename, mapconf); err != nil {
if err := serialize.WriteConfigFile(r.configFilePath, mapconf); err != nil {
return err
}
// Do not use `*r.config = ...`. This will modify the *shared* config
Expand Down Expand Up @@ -591,12 +596,8 @@ func (r *FSRepo) GetConfigKey(key string) (interface{}, error) {
return nil, errors.New("repo is closed")
}

filename, err := config.Filename(r.path)
if err != nil {
return nil, err
}
var cfg map[string]interface{}
if err := serialize.ReadConfigFile(filename, &cfg); err != nil {
if err := serialize.ReadConfigFile(r.configFilePath, &cfg); err != nil {
return nil, err
}
return common.MapGetKV(cfg, key)
Expand All @@ -611,13 +612,9 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
return errors.New("repo is closed")
}

filename, err := config.Filename(r.path)
if err != nil {
return err
}
// Load into a map so we don't end up writing any additional defaults to the config file.
var mapconf map[string]interface{}
if err := serialize.ReadConfigFile(filename, &mapconf); err != nil {
if err := serialize.ReadConfigFile(r.configFilePath, &mapconf); err != nil {
return err
}

Expand Down Expand Up @@ -645,7 +642,7 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
if err != nil {
return err
}
if err := serialize.WriteConfigFile(filename, mapconf); err != nil {
if err := serialize.WriteConfigFile(r.configFilePath, mapconf); err != nil {
return err
}
return r.setConfigUnsynced(conf) // TODO roll this into this method
Expand Down
22 changes: 12 additions & 10 deletions repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ const (
)

type IpfsFetcher struct {
distPath string
limit int64
repoRoot *string
distPath string
limit int64
repoRoot *string
userConfigFile string

openOnce sync.Once
openErr error
Expand All @@ -62,11 +63,12 @@ var _ migrations.Fetcher = (*IpfsFetcher)(nil)
// Bootstrap and peer information in read from the IPFS config file in
// repoRoot, unless repoRoot is nil. If repoRoot is empty (""), then read the
// config from the default IPFS directory.
func NewIpfsFetcher(distPath string, fetchLimit int64, repoRoot *string) *IpfsFetcher {
func NewIpfsFetcher(distPath string, fetchLimit int64, repoRoot *string, userConfigFile string) *IpfsFetcher {
f := &IpfsFetcher{
limit: defaultFetchLimit,
distPath: migrations.LatestIpfsDist,
repoRoot: repoRoot,
limit: defaultFetchLimit,
distPath: migrations.LatestIpfsDist,
repoRoot: repoRoot,
userConfigFile: userConfigFile,
}

if distPath != "" {
Expand All @@ -92,7 +94,7 @@ func (f *IpfsFetcher) Fetch(ctx context.Context, filePath string) ([]byte, error
// Initialize and start IPFS node on first call to Fetch, since the fetcher
// may be created by not used.
f.openOnce.Do(func() {
bootstrap, peers := readIpfsConfig(f.repoRoot)
bootstrap, peers := readIpfsConfig(f.repoRoot, f.userConfigFile)
f.ipfsTmpDir, f.openErr = initTempNode(ctx, bootstrap, peers)
if f.openErr != nil {
return
Expand Down Expand Up @@ -288,12 +290,12 @@ func parsePath(fetchPath string) (ipath.Path, error) {
return ipfsPath, ipfsPath.IsValid()
}

func readIpfsConfig(repoRoot *string) (bootstrap []string, peers []peer.AddrInfo) {
func readIpfsConfig(repoRoot *string, userConfigFile string) (bootstrap []string, peers []peer.AddrInfo) {
if repoRoot == nil {
return
}

cfgPath, err := config.Filename(*repoRoot)
cfgPath, err := config.Filename(*repoRoot, userConfigFile)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
Expand Down
14 changes: 7 additions & 7 deletions repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestIpfsFetcher(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

fetcher := NewIpfsFetcher("", 0, nil)
fetcher := NewIpfsFetcher("", 0, nil, "")
defer fetcher.Close()

out, err := fetcher.Fetch(ctx, "go-ipfs/versions")
Expand Down Expand Up @@ -62,7 +62,7 @@ func TestInitIpfsFetcher(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

f := NewIpfsFetcher("", 0, nil)
f := NewIpfsFetcher("", 0, nil, "")
defer f.Close()

// Init ipfs repo
Expand Down Expand Up @@ -132,7 +132,7 @@ func TestReadIpfsConfig(t *testing.T) {
`

noSuchDir := "no_such_dir-5953aa51-1145-4efd-afd1-a069075fcf76"
bootstrap, peers := readIpfsConfig(&noSuchDir)
bootstrap, peers := readIpfsConfig(&noSuchDir, "")
if bootstrap != nil {
t.Error("expected nil bootstrap")
}
Expand All @@ -142,12 +142,12 @@ func TestReadIpfsConfig(t *testing.T) {

tmpDir := makeConfig(t, testConfig)

bootstrap, peers = readIpfsConfig(nil)
bootstrap, peers = readIpfsConfig(nil, "")
if bootstrap != nil || peers != nil {
t.Fatal("expected nil ipfs config items")
}

bootstrap, peers = readIpfsConfig(&tmpDir)
bootstrap, peers = readIpfsConfig(&tmpDir, "")
if len(bootstrap) != 2 {
t.Fatal("wrong number of bootstrap addresses")
}
Expand Down Expand Up @@ -189,7 +189,7 @@ func TestBadBootstrappingIpfsConfig(t *testing.T) {

tmpDir := makeConfig(t, configBadBootstrap)

bootstrap, peers := readIpfsConfig(&tmpDir)
bootstrap, peers := readIpfsConfig(&tmpDir, "")
if bootstrap != nil {
t.Fatal("expected nil bootstrap")
}
Expand Down Expand Up @@ -219,7 +219,7 @@ func TestBadPeersIpfsConfig(t *testing.T) {

tmpDir := makeConfig(t, configBadPeers)

bootstrap, peers := readIpfsConfig(&tmpDir)
bootstrap, peers := readIpfsConfig(&tmpDir, "")
if peers != nil {
t.Fatal("expected nil peers")
}
Expand Down
Loading

0 comments on commit 34356a1

Please sign in to comment.