forked from toolshed/abra
		
	feat: introduce abra config file and load abra dir from it (!419)
This is the first step to introduce a configuration file for abra. The config file must be named `abra.yaml` or àbra.yml`. abra look for the config file in the current directory and when not found traverses the directory tree up until it is found or the home/root directory is reached. For now there is only one setting that is made configurable: `abraDir`. The new logic for setting the abra dir is the following: 1. lookup `$ABRA_DIR` env 2. look for config file and take value from there 3. `$HOME/.abra` as fallback See coop-cloud/organising#303. Reviewed-on: coop-cloud/abra#419 Reviewed-by: decentral1se <decentral1se@noreply.git.coopcloud.tech> Co-authored-by: p4u1 <p4u1_f4u1@riseup.net> Co-committed-by: p4u1 <p4u1_f4u1@riseup.net>
This commit is contained in:
		
							
								
								
									
										104
									
								
								pkg/config/abra.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								pkg/config/abra.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | |||||||
|  | package config | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"os" | ||||||
|  | 	"path" | ||||||
|  | 	"path/filepath" | ||||||
|  |  | ||||||
|  | 	"github.com/sirupsen/logrus" | ||||||
|  | 	"gopkg.in/yaml.v3" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // LoadAbraConfig returns the abra configuration. It tries to find a abra | ||||||
|  | // configuration file (see findAbraConfig for lookup logic). When no | ||||||
|  | // configuration was found it returns the default config. | ||||||
|  | func LoadAbraConfig() Abra { | ||||||
|  | 	wd, _ := os.Getwd() | ||||||
|  | 	configFile := findAbraConfig(wd) | ||||||
|  | 	if configFile == "" { | ||||||
|  | 		logrus.Debugf("no config file found") | ||||||
|  | 		return Abra{} | ||||||
|  | 	} | ||||||
|  | 	data, err := os.ReadFile(configFile) | ||||||
|  | 	if err != nil { | ||||||
|  | 		// Do nothing, when an error occurs | ||||||
|  | 		logrus.Debugf("error reading config file: %s", err) | ||||||
|  | 		return Abra{} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	config := Abra{} | ||||||
|  | 	err = yaml.Unmarshal(data, &config) | ||||||
|  | 	if err != nil { | ||||||
|  | 		// Do nothing, when an error occurs | ||||||
|  | 		logrus.Debugf("error loading config file: %s", err) | ||||||
|  | 		return Abra{} | ||||||
|  | 	} | ||||||
|  | 	logrus.Debugf("config file loaded from: %s", configFile) | ||||||
|  | 	config.configPath = configFile | ||||||
|  | 	return config | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // findAbraConfig recursively looks for a abra.y(a)ml file in the given directory. | ||||||
|  | // When the file was not found it calls the function again with the parent | ||||||
|  | // directory until the home directory is hit. When no abra config was found it | ||||||
|  | // returns an empty string. | ||||||
|  | func findAbraConfig(dir string) string { | ||||||
|  | 	dir, err := filepath.Abs(dir) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	if dir == os.ExpandEnv("$HOME") || dir == "/" { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	p := path.Join(dir, "abra.yaml") | ||||||
|  | 	if _, err := os.Stat(p); err == nil { | ||||||
|  | 		return p | ||||||
|  | 	} | ||||||
|  | 	p = path.Join(dir, "abra.yml") | ||||||
|  | 	if _, err := os.Stat(p); err == nil { | ||||||
|  | 		return p | ||||||
|  | 	} | ||||||
|  | 	return findAbraConfig(filepath.Dir(dir)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Abra defines the configuration file for abra. | ||||||
|  | type Abra struct { | ||||||
|  | 	configPath string | ||||||
|  | 	AbraDir    string `yaml:"abraDir"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetAbraDir returns the abra dir. It has the following logic: | ||||||
|  | // 1. check if $ABRA_DIR is set | ||||||
|  | // 2. check if abraDir was set in a config file | ||||||
|  | // 3. use $HOME/.abra when above two options failed | ||||||
|  | func (a Abra) GetAbraDir() string { | ||||||
|  | 	if dir, exists := os.LookupEnv("ABRA_DIR"); exists && dir != "" { | ||||||
|  | 		logrus.Debug("read abra dir from $ABRA_DIR") | ||||||
|  | 		return dir | ||||||
|  | 	} | ||||||
|  | 	if a.AbraDir != "" { | ||||||
|  | 		logrus.Debug("read abra dir from config file") | ||||||
|  | 		if path.IsAbs(a.AbraDir) { | ||||||
|  | 			return a.AbraDir | ||||||
|  | 		} | ||||||
|  | 		// Make the path absolute | ||||||
|  | 		return path.Join(a.configPath, a.AbraDir) | ||||||
|  | 	} | ||||||
|  | 	logrus.Debug("using default abra dir") | ||||||
|  | 	return os.ExpandEnv("$HOME/.abra") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var config = LoadAbraConfig() | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	ABRA_DIR                 = config.GetAbraDir() | ||||||
|  | 	SERVERS_DIR              = path.Join(ABRA_DIR, "servers") | ||||||
|  | 	RECIPES_DIR              = path.Join(ABRA_DIR, "recipes") | ||||||
|  | 	VENDOR_DIR               = path.Join(ABRA_DIR, "vendor") | ||||||
|  | 	BACKUP_DIR               = path.Join(ABRA_DIR, "backups") | ||||||
|  | 	CATALOGUE_DIR            = path.Join(ABRA_DIR, "catalogue") | ||||||
|  | 	RECIPES_JSON             = path.Join(ABRA_DIR, "catalogue", "recipes.json") | ||||||
|  | 	REPOS_BASE_URL           = "https://git.coopcloud.tech/coop-cloud" | ||||||
|  | 	CATALOGUE_JSON_REPO_NAME = "recipes-catalogue-json" | ||||||
|  | 	SSH_URL_TEMPLATE         = "ssh://git@git.coopcloud.tech:2222/coop-cloud/%s.git" | ||||||
|  | ) | ||||||
							
								
								
									
										103
									
								
								pkg/config/abra_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								pkg/config/abra_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | |||||||
|  | package config | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"log" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestFindAbraConfig(t *testing.T) { | ||||||
|  | 	wd, err := os.Getwd() | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	tests := []struct { | ||||||
|  | 		Dir    string | ||||||
|  | 		Config string | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			Dir:    "testdata/abraconfig1", | ||||||
|  | 			Config: filepath.Join(wd, "testdata/abraconfig1/abra.yaml"), | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Dir:    "testdata/abraconfig1/subdir", | ||||||
|  | 			Config: filepath.Join(wd, "testdata/abraconfig1/abra.yaml"), | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Dir:    "testdata/abraconfig2", | ||||||
|  | 			Config: filepath.Join(wd, "testdata/abraconfig2/abra.yml"), | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Dir:    "testdata/abraconfig2/subdir", | ||||||
|  | 			Config: filepath.Join(wd, "testdata/abraconfig2/abra.yml"), | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Dir:    "testdata", | ||||||
|  | 			Config: "", | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, tc := range tests { | ||||||
|  | 		t.Run(tc.Dir, func(t *testing.T) { | ||||||
|  | 			config := findAbraConfig(tc.Dir) | ||||||
|  | 			if config != tc.Config { | ||||||
|  | 				t.Errorf("\nwant: %s\ngot:  %s", tc.Config, config) | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestLoadAbraConfigGetAbraDir(t *testing.T) { | ||||||
|  | 	wd, err := os.Getwd() | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	t.Setenv("ABRA_DIR", "") | ||||||
|  |  | ||||||
|  | 	t.Run("default", func(t *testing.T) { | ||||||
|  | 		cfg := LoadAbraConfig() | ||||||
|  | 		wantAbraDir := os.ExpandEnv("$HOME/.abra") | ||||||
|  | 		if cfg.GetAbraDir() != wantAbraDir { | ||||||
|  | 			t.Errorf("\nwant: %s\ngot:  %s", wantAbraDir, cfg.GetAbraDir()) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	t.Run("from config file", func(t *testing.T) { | ||||||
|  | 		t.Cleanup(func() { os.Chdir(wd) }) | ||||||
|  | 		err = os.Chdir(filepath.Join(wd, "testdata/abraconfig1")) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Fatal(err) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		cfg := LoadAbraConfig() | ||||||
|  | 		log.Println(cfg.GetAbraDir()) | ||||||
|  | 		wantAbraDir := filepath.Join(wd, "testdata/abraconfig1/abra.yaml/foobar") | ||||||
|  | 		if cfg.GetAbraDir() != wantAbraDir { | ||||||
|  | 			t.Errorf("\nwant: %s\ngot:  %s", wantAbraDir, cfg.GetAbraDir()) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	t.Run("default when config file is empty", func(t *testing.T) { | ||||||
|  | 		t.Cleanup(func() { os.Chdir(wd) }) | ||||||
|  | 		err := os.Chdir(filepath.Join(wd, "testdata/abraconfig2")) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Fatal(err) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		cfg := LoadAbraConfig() | ||||||
|  | 		wantAbraDir := os.ExpandEnv("$HOME/.abra") | ||||||
|  | 		if cfg.GetAbraDir() != wantAbraDir { | ||||||
|  | 			t.Errorf("\nwant: %s\ngot:  %s", wantAbraDir, cfg.GetAbraDir()) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	t.Run("from env variable", func(t *testing.T) { | ||||||
|  | 		t.Setenv("ABRA_DIR", "foo") | ||||||
|  | 		cfg := LoadAbraConfig() | ||||||
|  | 		wantAbraDir := "foo" | ||||||
|  | 		if cfg.GetAbraDir() != wantAbraDir { | ||||||
|  | 			t.Errorf("\nwant: %s\ngot:  %s", wantAbraDir, cfg.GetAbraDir()) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
| @ -16,26 +16,6 @@ import ( | |||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // getBaseDir retrieves the Abra base directory. |  | ||||||
| func getBaseDir() string { |  | ||||||
| 	home := os.ExpandEnv("$HOME/.abra") |  | ||||||
| 	if customAbraDir, exists := os.LookupEnv("ABRA_DIR"); exists && customAbraDir != "" { |  | ||||||
| 		home = customAbraDir |  | ||||||
| 	} |  | ||||||
| 	return home |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var ABRA_DIR = getBaseDir() |  | ||||||
| var SERVERS_DIR = path.Join(ABRA_DIR, "servers") |  | ||||||
| var RECIPES_DIR = path.Join(ABRA_DIR, "recipes") |  | ||||||
| var VENDOR_DIR = path.Join(ABRA_DIR, "vendor") |  | ||||||
| var BACKUP_DIR = path.Join(ABRA_DIR, "backups") |  | ||||||
| var CATALOGUE_DIR = path.Join(ABRA_DIR, "catalogue") |  | ||||||
| var RECIPES_JSON = path.Join(ABRA_DIR, "catalogue", "recipes.json") |  | ||||||
| var REPOS_BASE_URL = "https://git.coopcloud.tech/coop-cloud" |  | ||||||
| var CATALOGUE_JSON_REPO_NAME = "recipes-catalogue-json" |  | ||||||
| var SSH_URL_TEMPLATE = "ssh://git@git.coopcloud.tech:2222/coop-cloud/%s.git" |  | ||||||
|  |  | ||||||
| const MAX_SANITISED_APP_NAME_LENGTH = 45 | const MAX_SANITISED_APP_NAME_LENGTH = 45 | ||||||
| const MAX_DOCKER_SECRET_LENGTH = 64 | const MAX_DOCKER_SECRET_LENGTH = 64 | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								pkg/config/testdata/abraconfig1/abra.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								pkg/config/testdata/abraconfig1/abra.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | abraDir: foobar | ||||||
							
								
								
									
										0
									
								
								pkg/config/testdata/abraconfig1/subdir/.gitkeep
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								pkg/config/testdata/abraconfig1/subdir/.gitkeep
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								pkg/config/testdata/abraconfig2/abra.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								pkg/config/testdata/abraconfig2/abra.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								pkg/config/testdata/abraconfig2/subdir/.gitkeep
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								pkg/config/testdata/abraconfig2/subdir/.gitkeep
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
		Reference in New Issue
	
	Block a user