Unverified Commit 900654f4 authored by Silvano Cerza's avatar Silvano Cerza Committed by GitHub

Add --dest-file flag to config init command (#957)

parent a8985daf
......@@ -17,16 +17,20 @@ package config
import (
"os"
"path/filepath"
"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
paths "github.com/arduino/go-paths-helper"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var destDir string
var (
destDir string
destFile string
overwrite bool
)
const defaultFileName = "arduino-cli.yaml"
......@@ -37,39 +41,66 @@ func initInitCommand() *cobra.Command {
Long: "Creates or updates the configuration file in the data directory or custom directory with the current configuration settings.",
Example: "" +
" # Writes current configuration to the configuration file in the data directory.\n" +
" " + os.Args[0] + " config init",
" " + os.Args[0] + " config init" +
" " + os.Args[0] + " config init --dest-dir /home/user/MyDirectory" +
" " + os.Args[0] + " config init --dest-file /home/user/MyDirectory/my_settings.yaml",
Args: cobra.NoArgs,
Run: runInitCommand,
}
initCommand.Flags().StringVar(&destDir, "dest-dir", "", "Sets where to save the configuration file.")
initCommand.Flags().StringVar(&destFile, "dest-file", "", "Sets where to save the configuration file.")
initCommand.Flags().BoolVar(&overwrite, "overwrite", false, "Overwrite existing config file.")
return initCommand
}
func runInitCommand(cmd *cobra.Command, args []string) {
if destDir == "" {
if destFile != "" && destDir != "" {
feedback.Errorf("Can't use both --dest-file and --dest-dir flags at the same time.")
os.Exit(errorcodes.ErrGeneric)
}
var configFileAbsPath *paths.Path
var absPath *paths.Path
var err error
switch {
case destFile != "":
configFileAbsPath, err = paths.New(destFile).Abs()
if err != nil {
feedback.Errorf("Cannot find absolute path: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
absPath = configFileAbsPath.Parent()
case destDir == "":
destDir = viper.GetString("directories.Data")
fallthrough
default:
absPath, err = paths.New(destDir).Abs()
if err != nil {
feedback.Errorf("Cannot find absolute path: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
configFileAbsPath = absPath.Join(defaultFileName)
}
absPath, err := filepath.Abs(destDir)
if err != nil {
feedback.Errorf("Cannot find absolute path: %v", err)
if !overwrite && configFileAbsPath.Exist() {
feedback.Error("Config file already exists, use --overwrite to discard the existing one.")
os.Exit(errorcodes.ErrGeneric)
}
configFileAbsPath := filepath.Join(absPath, defaultFileName)
logrus.Infof("Writing config file to: %s", absPath)
if err := os.MkdirAll(absPath, os.FileMode(0755)); err != nil {
if err := absPath.MkdirAll(); err != nil {
feedback.Errorf("Cannot create config file directory: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
if err := viper.WriteConfigAs(configFileAbsPath); err != nil {
if err := viper.WriteConfigAs(configFileAbsPath.String()); err != nil {
feedback.Errorf("Cannot create config file: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
msg := "Config file written to: " + configFileAbsPath
msg := "Config file written to: " + configFileAbsPath.String()
logrus.Info(msg)
feedback.Print(msg)
}
......@@ -18,6 +18,7 @@ package daemon
import (
"context"
"encoding/json"
"path/filepath"
"testing"
"github.com/spf13/viper"
......@@ -30,12 +31,12 @@ import (
var svc = SettingsService{}
func init() {
configuration.Init("testdata")
configuration.Init(filepath.Join("testdata", "arduino-cli.yaml"))
}
func reset() {
viper.Reset()
configuration.Init("testdata")
configuration.Init(filepath.Join("testdata", "arduino-cli.yaml"))
}
func TestGetAll(t *testing.T) {
......
......@@ -35,7 +35,13 @@ import (
func Init(configPath string) {
// Config file metadata
jww.SetStdoutThreshold(jww.LevelFatal)
viper.SetConfigName("arduino-cli")
configDir := paths.New(configPath)
if configDir != nil && !configDir.IsDir() {
viper.SetConfigName(strings.TrimSuffix(configDir.Base(), configDir.Ext()))
} else {
viper.SetConfigName("arduino-cli")
}
// Get default data path if none was provided
if configPath == "" {
......@@ -43,7 +49,7 @@ func Init(configPath string) {
}
// Add paths where to search for a config file
viper.AddConfigPath(configPath)
viper.AddConfigPath(filepath.Dir(configPath))
// Bind env vars
viper.SetEnvPrefix("ARDUINO")
......@@ -185,30 +191,39 @@ func IsBundledInDesktopIDE() bool {
}
// FindConfigFile returns the config file path using the argument '--config-file' if specified or via the current working dir
func FindConfigFile() string {
func FindConfigFile(args []string) string {
configFile := ""
for i, arg := range os.Args {
for i, arg := range args {
// 0 --config-file ss
if arg == "--config-file" {
if len(os.Args) > i+1 {
configFile = os.Args[i+1]
if len(args) > i+1 {
configFile = args[i+1]
}
}
}
if configFile != "" {
if fi, err := os.Stat(configFile); err == nil {
if fi.IsDir() {
return configFile
}
return filepath.Dir(configFile)
}
return configFile
}
return searchCwdForConfig()
}
func searchCwdForConfig() string {
cwd, err := os.Getwd()
if err != nil {
return ""
}
configFile := searchConfigTree(cwd)
if configFile == "" {
return configFile
}
return configFile + string(os.PathSeparator) + "arduino-cli.yaml"
}
func searchConfigTree(cwd string) string {
// go back up to root and search for the config file
......@@ -230,13 +245,3 @@ func searchConfigTree(cwd string) string {
}
}
func searchCwdForConfig() string {
cwd, err := os.Getwd()
if err != nil {
return ""
}
return searchConfigTree(cwd)
}
......@@ -30,6 +30,12 @@ func tmpDirOrDie() string {
if err != nil {
panic(fmt.Sprintf("error creating tmp dir: %v", err))
}
// Symlinks are evaluated becase the temp folder on Mac OS is inside /var, it's not writable
// and is a symlink to /private/var, we want the full path so we do this
dir, err = filepath.EvalSymlinks(dir)
if err != nil {
panic(fmt.Sprintf("error evaluating tmp dir symlink: %v", err))
}
return dir
}
......@@ -71,3 +77,40 @@ func BenchmarkSearchConfigTree(b *testing.B) {
}
result = s
}
func TestFindConfigFile(t *testing.T) {
configFile := FindConfigFile([]string{"--config-file"})
require.Equal(t, "", configFile)
configFile = FindConfigFile([]string{"--config-file", "some/path/to/config"})
require.Equal(t, "some/path/to/config", configFile)
configFile = FindConfigFile([]string{"--config-file", "some/path/to/config/arduino-cli.yaml"})
require.Equal(t, "some/path/to/config/arduino-cli.yaml", configFile)
configFile = FindConfigFile([]string{})
require.Equal(t, "", configFile)
// Create temporary directories
tmp := tmpDirOrDie()
defer os.RemoveAll(tmp)
target := filepath.Join(tmp, "foo", "bar", "baz")
os.MkdirAll(target, os.ModePerm)
require.Nil(t, os.Chdir(target))
// Create a config file
f, err := os.Create(filepath.Join(target, "..", "..", "arduino-cli.yaml"))
require.Nil(t, err)
f.Close()
configFile = FindConfigFile([]string{})
require.Equal(t, filepath.Join(tmp, "foo", "arduino-cli.yaml"), configFile)
// Create another config file
f, err = os.Create(filepath.Join(target, "arduino-cli.yaml"))
require.Nil(t, err)
f.Close()
configFile = FindConfigFile([]string{})
require.Equal(t, filepath.Join(target, "arduino-cli.yaml"), configFile)
}
......@@ -25,7 +25,7 @@ import (
)
func main() {
configuration.Init(configuration.FindConfigFile())
configuration.Init(configuration.FindConfigFile(os.Args))
i18n.Init()
arduinoCmd := cli.NewCommand()
if err := arduinoCmd.Execute(); err != nil {
......
......@@ -13,6 +13,7 @@
# software without disclosing the source code of your own applications. To purchase
# a commercial license, send an email to license@arduino.cc.
from pathlib import Path
import json
def test_init(run_command, data_dir, working_dir):
......@@ -21,8 +22,116 @@ def test_init(run_command, data_dir, working_dir):
assert data_dir in result.stdout
def test_init_dest(run_command, working_dir):
dest = str(Path(working_dir) / "config" / "test")
def test_init_dest_absolute_path(run_command, working_dir):
dest = Path(working_dir) / "config" / "test"
expected_config_file = dest / "arduino-cli.yaml"
assert not expected_config_file.exists()
result = run_command(f'config init --dest-dir "{dest}"')
assert result.ok
assert dest in result.stdout
assert str(expected_config_file) in result.stdout
assert expected_config_file.exists()
def test_init_dest_relative_path(run_command, working_dir):
dest = Path(working_dir) / "config" / "test"
expected_config_file = dest / "arduino-cli.yaml"
assert not expected_config_file.exists()
result = run_command('config init --dest-dir "config/test"')
assert result.ok
assert str(expected_config_file) in result.stdout
assert expected_config_file.exists()
def test_init_dest_flag_with_overwrite_flag(run_command, working_dir):
dest = Path(working_dir) / "config" / "test"
expected_config_file = dest / "arduino-cli.yaml"
assert not expected_config_file.exists()
result = run_command(f'config init --dest-dir "{dest}"')
assert result.ok
assert expected_config_file.exists()
result = run_command(f'config init --dest-dir "{dest}"')
assert result.failed
assert "Config file already exists, use --overwrite to discard the existing one." in result.stderr
result = run_command(f'config init --dest-dir "{dest}" --overwrite')
assert result.ok
assert str(expected_config_file) in result.stdout
def test_init_dest_and_config_file_flags(run_command, working_dir):
result = run_command('config init --dest-file "some_other_path" --dest-dir "some_path"')
assert result.failed
assert "Can't use both --dest-file and --dest-dir flags at the same time." in result.stderr
def test_init_config_file_flag_absolute_path(run_command, working_dir):
config_file = Path(working_dir) / "config" / "test" / "config.yaml"
assert not config_file.exists()
result = run_command(f'config init --dest-file "{config_file}"')
assert result.ok
assert str(config_file) in result.stdout
assert config_file.exists()
def test_init_config_file_flag_relative_path(run_command, working_dir):
config_file = Path(working_dir) / "config.yaml"
assert not config_file.exists()
result = run_command('config init --dest-file "config.yaml"')
assert result.ok
assert str(config_file) in result.stdout
assert config_file.exists()
def test_init_config_file_flag_with_overwrite_flag(run_command, working_dir):
config_file = Path(working_dir) / "config" / "test" / "config.yaml"
assert not config_file.exists()
result = run_command(f'config init --dest-file "{config_file}"')
assert result.ok
assert config_file.exists()
result = run_command(f'config init --dest-file "{config_file}"')
assert result.failed
assert "Config file already exists, use --overwrite to discard the existing one." in result.stderr
result = run_command(f'config init --dest-file "{config_file}" --overwrite')
assert result.ok
assert str(config_file) in result.stdout
def test_dump(run_command, working_dir):
# Create a config file first
config_file = Path(working_dir) / "config" / "test" / "config.yaml"
assert not config_file.exists()
result = run_command(f'config init --dest-file "{config_file}"')
assert result.ok
assert config_file.exists()
result = run_command("config dump --format json")
assert result.ok
settings_json = json.loads(result.stdout)
assert [] == settings_json["board_manager"]["additional_urls"]
def test_dump_with_config_file_flag(run_command, working_dir):
# Create a config file first
config_file = Path(working_dir) / "config" / "test" / "config.yaml"
assert not config_file.exists()
result = run_command(f'config init --dest-file "{config_file}" --additional-urls=https://example.com')
assert result.ok
assert config_file.exists()
result = run_command(f'config dump --config-file "{config_file}" --format json')
assert result.ok
settings_json = json.loads(result.stdout)
assert ["https://example.com"] == settings_json["board_manager"]["additional_urls"]
result = run_command(
f'config dump --config-file "{config_file}" --additional-urls=https://another-url.com --format json'
)
assert result.ok
settings_json = json.loads(result.stdout)
assert ["https://another-url.com"] == settings_json["board_manager"]["additional_urls"]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment