Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 900654f

Browse files
authoredOct 5, 2020
Add --dest-file flag to config init command (#957)
1 parent a8985da commit 900654f

File tree

6 files changed

+230
-41
lines changed

6 files changed

+230
-41
lines changed
 

‎cli/config/init.go

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@ package config
1717

1818
import (
1919
"os"
20-
"path/filepath"
2120

2221
"github.com/arduino/arduino-cli/cli/errorcodes"
2322
"github.com/arduino/arduino-cli/cli/feedback"
23+
paths "github.com/arduino/go-paths-helper"
2424
"github.com/sirupsen/logrus"
2525
"github.com/spf13/cobra"
2626
"github.com/spf13/viper"
2727
)
2828

29-
var destDir string
29+
var (
30+
destDir string
31+
destFile string
32+
overwrite bool
33+
)
3034

3135
const defaultFileName = "arduino-cli.yaml"
3236

@@ -37,39 +41,66 @@ func initInitCommand() *cobra.Command {
3741
Long: "Creates or updates the configuration file in the data directory or custom directory with the current configuration settings.",
3842
Example: "" +
3943
" # Writes current configuration to the configuration file in the data directory.\n" +
40-
" " + os.Args[0] + " config init",
44+
" " + os.Args[0] + " config init" +
45+
" " + os.Args[0] + " config init --dest-dir /home/user/MyDirectory" +
46+
" " + os.Args[0] + " config init --dest-file /home/user/MyDirectory/my_settings.yaml",
4147
Args: cobra.NoArgs,
4248
Run: runInitCommand,
4349
}
4450
initCommand.Flags().StringVar(&destDir, "dest-dir", "", "Sets where to save the configuration file.")
51+
initCommand.Flags().StringVar(&destFile, "dest-file", "", "Sets where to save the configuration file.")
52+
initCommand.Flags().BoolVar(&overwrite, "overwrite", false, "Overwrite existing config file.")
4553
return initCommand
4654
}
4755

4856
func runInitCommand(cmd *cobra.Command, args []string) {
49-
if destDir == "" {
57+
if destFile != "" && destDir != "" {
58+
feedback.Errorf("Can't use both --dest-file and --dest-dir flags at the same time.")
59+
os.Exit(errorcodes.ErrGeneric)
60+
}
61+
62+
var configFileAbsPath *paths.Path
63+
var absPath *paths.Path
64+
var err error
65+
66+
switch {
67+
case destFile != "":
68+
configFileAbsPath, err = paths.New(destFile).Abs()
69+
if err != nil {
70+
feedback.Errorf("Cannot find absolute path: %v", err)
71+
os.Exit(errorcodes.ErrGeneric)
72+
}
73+
74+
absPath = configFileAbsPath.Parent()
75+
case destDir == "":
5076
destDir = viper.GetString("directories.Data")
77+
fallthrough
78+
default:
79+
absPath, err = paths.New(destDir).Abs()
80+
if err != nil {
81+
feedback.Errorf("Cannot find absolute path: %v", err)
82+
os.Exit(errorcodes.ErrGeneric)
83+
}
84+
configFileAbsPath = absPath.Join(defaultFileName)
5185
}
5286

53-
absPath, err := filepath.Abs(destDir)
54-
if err != nil {
55-
feedback.Errorf("Cannot find absolute path: %v", err)
87+
if !overwrite && configFileAbsPath.Exist() {
88+
feedback.Error("Config file already exists, use --overwrite to discard the existing one.")
5689
os.Exit(errorcodes.ErrGeneric)
5790
}
58-
configFileAbsPath := filepath.Join(absPath, defaultFileName)
5991

6092
logrus.Infof("Writing config file to: %s", absPath)
61-
62-
if err := os.MkdirAll(absPath, os.FileMode(0755)); err != nil {
93+
if err := absPath.MkdirAll(); err != nil {
6394
feedback.Errorf("Cannot create config file directory: %v", err)
6495
os.Exit(errorcodes.ErrGeneric)
6596
}
6697

67-
if err := viper.WriteConfigAs(configFileAbsPath); err != nil {
98+
if err := viper.WriteConfigAs(configFileAbsPath.String()); err != nil {
6899
feedback.Errorf("Cannot create config file: %v", err)
69100
os.Exit(errorcodes.ErrGeneric)
70101
}
71102

72-
msg := "Config file written to: " + configFileAbsPath
103+
msg := "Config file written to: " + configFileAbsPath.String()
73104
logrus.Info(msg)
74105
feedback.Print(msg)
75106
}

‎commands/daemon/settings_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package daemon
1818
import (
1919
"context"
2020
"encoding/json"
21+
"path/filepath"
2122
"testing"
2223

2324
"github.com/spf13/viper"
@@ -30,12 +31,12 @@ import (
3031
var svc = SettingsService{}
3132

3233
func init() {
33-
configuration.Init("testdata")
34+
configuration.Init(filepath.Join("testdata", "arduino-cli.yaml"))
3435
}
3536

3637
func reset() {
3738
viper.Reset()
38-
configuration.Init("testdata")
39+
configuration.Init(filepath.Join("testdata", "arduino-cli.yaml"))
3940
}
4041

4142
func TestGetAll(t *testing.T) {

‎configuration/configuration.go

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,21 @@ import (
3535
func Init(configPath string) {
3636
// Config file metadata
3737
jww.SetStdoutThreshold(jww.LevelFatal)
38-
viper.SetConfigName("arduino-cli")
38+
39+
configDir := paths.New(configPath)
40+
if configDir != nil && !configDir.IsDir() {
41+
viper.SetConfigName(strings.TrimSuffix(configDir.Base(), configDir.Ext()))
42+
} else {
43+
viper.SetConfigName("arduino-cli")
44+
}
3945

4046
// Get default data path if none was provided
4147
if configPath == "" {
4248
configPath = getDefaultArduinoDataDir()
4349
}
4450

4551
// Add paths where to search for a config file
46-
viper.AddConfigPath(configPath)
52+
viper.AddConfigPath(filepath.Dir(configPath))
4753

4854
// Bind env vars
4955
viper.SetEnvPrefix("ARDUINO")
@@ -185,30 +191,39 @@ func IsBundledInDesktopIDE() bool {
185191
}
186192

187193
// FindConfigFile returns the config file path using the argument '--config-file' if specified or via the current working dir
188-
func FindConfigFile() string {
189-
194+
func FindConfigFile(args []string) string {
190195
configFile := ""
191-
for i, arg := range os.Args {
196+
for i, arg := range args {
192197
// 0 --config-file ss
193198
if arg == "--config-file" {
194-
if len(os.Args) > i+1 {
195-
configFile = os.Args[i+1]
199+
if len(args) > i+1 {
200+
configFile = args[i+1]
196201
}
197202
}
198203
}
199204

200205
if configFile != "" {
201-
if fi, err := os.Stat(configFile); err == nil {
202-
if fi.IsDir() {
203-
return configFile
204-
}
205-
return filepath.Dir(configFile)
206-
}
206+
return configFile
207207
}
208208

209209
return searchCwdForConfig()
210210
}
211211

212+
func searchCwdForConfig() string {
213+
cwd, err := os.Getwd()
214+
215+
if err != nil {
216+
return ""
217+
}
218+
219+
configFile := searchConfigTree(cwd)
220+
if configFile == "" {
221+
return configFile
222+
}
223+
224+
return configFile + string(os.PathSeparator) + "arduino-cli.yaml"
225+
}
226+
212227
func searchConfigTree(cwd string) string {
213228

214229
// go back up to root and search for the config file
@@ -230,13 +245,3 @@ func searchConfigTree(cwd string) string {
230245
}
231246

232247
}
233-
234-
func searchCwdForConfig() string {
235-
cwd, err := os.Getwd()
236-
237-
if err != nil {
238-
return ""
239-
}
240-
241-
return searchConfigTree(cwd)
242-
}

‎configuration/configuration_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ func tmpDirOrDie() string {
3030
if err != nil {
3131
panic(fmt.Sprintf("error creating tmp dir: %v", err))
3232
}
33+
// Symlinks are evaluated becase the temp folder on Mac OS is inside /var, it's not writable
34+
// and is a symlink to /private/var, we want the full path so we do this
35+
dir, err = filepath.EvalSymlinks(dir)
36+
if err != nil {
37+
panic(fmt.Sprintf("error evaluating tmp dir symlink: %v", err))
38+
}
3339
return dir
3440
}
3541

@@ -71,3 +77,40 @@ func BenchmarkSearchConfigTree(b *testing.B) {
7177
}
7278
result = s
7379
}
80+
81+
func TestFindConfigFile(t *testing.T) {
82+
configFile := FindConfigFile([]string{"--config-file"})
83+
require.Equal(t, "", configFile)
84+
85+
configFile = FindConfigFile([]string{"--config-file", "some/path/to/config"})
86+
require.Equal(t, "some/path/to/config", configFile)
87+
88+
configFile = FindConfigFile([]string{"--config-file", "some/path/to/config/arduino-cli.yaml"})
89+
require.Equal(t, "some/path/to/config/arduino-cli.yaml", configFile)
90+
91+
configFile = FindConfigFile([]string{})
92+
require.Equal(t, "", configFile)
93+
94+
// Create temporary directories
95+
tmp := tmpDirOrDie()
96+
defer os.RemoveAll(tmp)
97+
target := filepath.Join(tmp, "foo", "bar", "baz")
98+
os.MkdirAll(target, os.ModePerm)
99+
require.Nil(t, os.Chdir(target))
100+
101+
// Create a config file
102+
f, err := os.Create(filepath.Join(target, "..", "..", "arduino-cli.yaml"))
103+
require.Nil(t, err)
104+
f.Close()
105+
106+
configFile = FindConfigFile([]string{})
107+
require.Equal(t, filepath.Join(tmp, "foo", "arduino-cli.yaml"), configFile)
108+
109+
// Create another config file
110+
f, err = os.Create(filepath.Join(target, "arduino-cli.yaml"))
111+
require.Nil(t, err)
112+
f.Close()
113+
114+
configFile = FindConfigFile([]string{})
115+
require.Equal(t, filepath.Join(target, "arduino-cli.yaml"), configFile)
116+
}

‎main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525
)
2626

2727
func main() {
28-
configuration.Init(configuration.FindConfigFile())
28+
configuration.Init(configuration.FindConfigFile(os.Args))
2929
i18n.Init()
3030
arduinoCmd := cli.NewCommand()
3131
if err := arduinoCmd.Execute(); err != nil {

‎test/test_config.py

Lines changed: 112 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# software without disclosing the source code of your own applications. To purchase
1414
# a commercial license, send an email to license@arduino.cc.
1515
from pathlib import Path
16+
import json
1617

1718

1819
def test_init(run_command, data_dir, working_dir):
@@ -21,8 +22,116 @@ def test_init(run_command, data_dir, working_dir):
2122
assert data_dir in result.stdout
2223

2324

24-
def test_init_dest(run_command, working_dir):
25-
dest = str(Path(working_dir) / "config" / "test")
25+
def test_init_dest_absolute_path(run_command, working_dir):
26+
dest = Path(working_dir) / "config" / "test"
27+
expected_config_file = dest / "arduino-cli.yaml"
28+
assert not expected_config_file.exists()
2629
result = run_command(f'config init --dest-dir "{dest}"')
2730
assert result.ok
28-
assert dest in result.stdout
31+
assert str(expected_config_file) in result.stdout
32+
assert expected_config_file.exists()
33+
34+
35+
def test_init_dest_relative_path(run_command, working_dir):
36+
dest = Path(working_dir) / "config" / "test"
37+
expected_config_file = dest / "arduino-cli.yaml"
38+
assert not expected_config_file.exists()
39+
result = run_command('config init --dest-dir "config/test"')
40+
assert result.ok
41+
assert str(expected_config_file) in result.stdout
42+
assert expected_config_file.exists()
43+
44+
45+
def test_init_dest_flag_with_overwrite_flag(run_command, working_dir):
46+
dest = Path(working_dir) / "config" / "test"
47+
48+
expected_config_file = dest / "arduino-cli.yaml"
49+
assert not expected_config_file.exists()
50+
51+
result = run_command(f'config init --dest-dir "{dest}"')
52+
assert result.ok
53+
assert expected_config_file.exists()
54+
55+
result = run_command(f'config init --dest-dir "{dest}"')
56+
assert result.failed
57+
assert "Config file already exists, use --overwrite to discard the existing one." in result.stderr
58+
59+
result = run_command(f'config init --dest-dir "{dest}" --overwrite')
60+
assert result.ok
61+
assert str(expected_config_file) in result.stdout
62+
63+
64+
def test_init_dest_and_config_file_flags(run_command, working_dir):
65+
result = run_command('config init --dest-file "some_other_path" --dest-dir "some_path"')
66+
assert result.failed
67+
assert "Can't use both --dest-file and --dest-dir flags at the same time." in result.stderr
68+
69+
70+
def test_init_config_file_flag_absolute_path(run_command, working_dir):
71+
config_file = Path(working_dir) / "config" / "test" / "config.yaml"
72+
assert not config_file.exists()
73+
result = run_command(f'config init --dest-file "{config_file}"')
74+
assert result.ok
75+
assert str(config_file) in result.stdout
76+
assert config_file.exists()
77+
78+
79+
def test_init_config_file_flag_relative_path(run_command, working_dir):
80+
config_file = Path(working_dir) / "config.yaml"
81+
assert not config_file.exists()
82+
result = run_command('config init --dest-file "config.yaml"')
83+
assert result.ok
84+
assert str(config_file) in result.stdout
85+
assert config_file.exists()
86+
87+
88+
def test_init_config_file_flag_with_overwrite_flag(run_command, working_dir):
89+
config_file = Path(working_dir) / "config" / "test" / "config.yaml"
90+
assert not config_file.exists()
91+
92+
result = run_command(f'config init --dest-file "{config_file}"')
93+
assert result.ok
94+
assert config_file.exists()
95+
96+
result = run_command(f'config init --dest-file "{config_file}"')
97+
assert result.failed
98+
assert "Config file already exists, use --overwrite to discard the existing one." in result.stderr
99+
100+
result = run_command(f'config init --dest-file "{config_file}" --overwrite')
101+
assert result.ok
102+
assert str(config_file) in result.stdout
103+
104+
105+
def test_dump(run_command, working_dir):
106+
# Create a config file first
107+
config_file = Path(working_dir) / "config" / "test" / "config.yaml"
108+
assert not config_file.exists()
109+
result = run_command(f'config init --dest-file "{config_file}"')
110+
assert result.ok
111+
assert config_file.exists()
112+
113+
result = run_command("config dump --format json")
114+
assert result.ok
115+
settings_json = json.loads(result.stdout)
116+
assert [] == settings_json["board_manager"]["additional_urls"]
117+
118+
119+
def test_dump_with_config_file_flag(run_command, working_dir):
120+
# Create a config file first
121+
config_file = Path(working_dir) / "config" / "test" / "config.yaml"
122+
assert not config_file.exists()
123+
result = run_command(f'config init --dest-file "{config_file}" --additional-urls=https://example.com')
124+
assert result.ok
125+
assert config_file.exists()
126+
127+
result = run_command(f'config dump --config-file "{config_file}" --format json')
128+
assert result.ok
129+
settings_json = json.loads(result.stdout)
130+
assert ["https://example.com"] == settings_json["board_manager"]["additional_urls"]
131+
132+
result = run_command(
133+
f'config dump --config-file "{config_file}" --additional-urls=https://another-url.com --format json'
134+
)
135+
assert result.ok
136+
settings_json = json.loads(result.stdout)
137+
assert ["https://another-url.com"] == settings_json["board_manager"]["additional_urls"]

0 commit comments

Comments
 (0)
Please sign in to comment.