1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-05-17 15:06:47 +08:00

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

This commit is contained in:
Lucas Molas
2022-01-03 12:00:01 -03:00
parent 7162a63e96
commit 6817fd4744
10 changed files with 88 additions and 68 deletions

View File

@ -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
}
@ -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

View File

@ -303,7 +303,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
}

View File

@ -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

View File

@ -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
}
@ -291,7 +292,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
}

View File

@ -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
@ -94,7 +96,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."),

View File

@ -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
@ -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
}
@ -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 {
@ -208,7 +226,7 @@ func checkInitialized(path string) 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
}
@ -222,7 +240,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
}
@ -372,11 +390,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
}
@ -507,12 +521,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
}
@ -546,15 +555,11 @@ func (r *FSRepo) SetConfig(updated *config.Config) error {
packageLock.Lock()
defer packageLock.Unlock()
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)
@ -562,7 +567,7 @@ func (r *FSRepo) SetConfig(updated *config.Config) error {
return err
}
mergedMap := common.MapMergeDeep(mapconf, m)
if err := serialize.WriteConfigFile(configFilename, mergedMap); err != nil {
if err := serialize.WriteConfigFile(r.configFilePath, mergedMap); err != nil {
return err
}
// Do not use `*r.config = ...`. This will modify the *shared* config
@ -580,12 +585,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)
@ -600,13 +601,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
}
@ -636,7 +633,7 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
}
r.config = conf
if err := serialize.WriteConfigFile(filename, mapconf); err != nil {
if err := serialize.WriteConfigFile(r.configFilePath, mapconf); err != nil {
return err
}

View File

@ -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
@ -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 != "" {
@ -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
@ -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

View File

@ -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")
@ -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
@ -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")
}
@ -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")
}
@ -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")
}
@ -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")
}

View File

@ -115,12 +115,12 @@ func ExeName(name string) string {
// ReadMigrationConfig reads the Migration section of the IPFS config, avoiding
// reading anything other than the Migration section. That way, we're free to
// make arbitrary changes to all _other_ sections in migrations.
func ReadMigrationConfig(repoRoot string) (*config.Migration, error) {
func ReadMigrationConfig(repoRoot string, userConfigFile string) (*config.Migration, error) {
var cfg struct {
Migration config.Migration
}
cfgPath, err := config.Filename(repoRoot)
cfgPath, err := config.Filename(repoRoot, userConfigFile)
if err != nil {
return nil, err
}

View File

@ -221,7 +221,7 @@ var testConfig = `
func TestReadMigrationConfigDefaults(t *testing.T) {
tmpDir := makeConfig(t, "{}")
cfg, err := ReadMigrationConfig(tmpDir)
cfg, err := ReadMigrationConfig(tmpDir, "")
if err != nil {
t.Fatal(err)
}
@ -243,7 +243,7 @@ func TestReadMigrationConfigDefaults(t *testing.T) {
func TestReadMigrationConfigErrors(t *testing.T) {
tmpDir := makeConfig(t, `{"Migration": {"Keep": "badvalue"}}`)
_, err := ReadMigrationConfig(tmpDir)
_, err := ReadMigrationConfig(tmpDir, "")
if err == nil {
t.Fatal("expected error")
}
@ -252,13 +252,13 @@ func TestReadMigrationConfigErrors(t *testing.T) {
}
os.RemoveAll(tmpDir)
_, err = ReadMigrationConfig(tmpDir)
_, err = ReadMigrationConfig(tmpDir, "")
if err == nil {
t.Fatal("expected error")
}
tmpDir = makeConfig(t, `}{`)
_, err = ReadMigrationConfig(tmpDir)
_, err = ReadMigrationConfig(tmpDir, "")
if err == nil {
t.Fatal("expected error")
}
@ -267,7 +267,7 @@ func TestReadMigrationConfigErrors(t *testing.T) {
func TestReadMigrationConfig(t *testing.T) {
tmpDir := makeConfig(t, testConfig)
cfg, err := ReadMigrationConfig(tmpDir)
cfg, err := ReadMigrationConfig(tmpDir, "")
if err != nil {
t.Fatal(err)
}