diff --git a/.golangci.yml b/.golangci.yml index 85eb8d5..b9f4356 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -14,3 +14,4 @@ linters: - nakedret - wsl - gofumpt + - gosec diff --git a/hw08_envdir_tool/env_reader.go b/hw08_envdir_tool/env_reader.go index 1a1f12d..aa0e5c6 100644 --- a/hw08_envdir_tool/env_reader.go +++ b/hw08_envdir_tool/env_reader.go @@ -1,10 +1,69 @@ package main +import ( + "bufio" + "io" + "io/ioutil" + "os" + "regexp" + "strings" +) + type Environment map[string]string // ReadDir reads a specified directory and returns map of env variables. // Variables represented as files where filename is name of variable, file first line is a value. func ReadDir(dir string) (Environment, error) { - // Place your code here - return nil, nil + e := make(map[string]string) + files, err := ioutil.ReadDir(dir) + if err != nil { + return e, err + } + for _, file := range files { + if !file.IsDir() && file.Mode().IsRegular() { + val, err := ReadFile(dir + "/" + file.Name()) + if err != nil { + return nil, err + } + // TODO: Не правильно! + key := file.Name() + key = strings.ReplaceAll(key, `=`, ``) + key = strings.ReplaceAll(key, `;`, ``) + e[key] = ExtractEnv(val) + } + } + + return e, nil +} + +func ReadFile(filePath string) (string, error) { + f, err := os.Open(filePath) + defer func() { + if err := f.Close(); err != nil { + return + } + }() + if err != nil { + return "", err + } + reader := bufio.NewReader(f) + b, _, err := reader.ReadLine() + if err != nil && err != io.EOF { + return "", err + } + + return string(b), nil +} + +func ExtractEnv(text string) string { + text = strings.TrimSpace(text) + r := regexp.MustCompile("\"+") + text = r.ReplaceAllString(text, "") + // Удаляем все после /000 + i := strings.IndexByte(text, 0) + if i > 0 { + text = text[:i] + } + + return text } diff --git a/hw08_envdir_tool/env_reader_test.go b/hw08_envdir_tool/env_reader_test.go index 7962c06..183cec3 100644 --- a/hw08_envdir_tool/env_reader_test.go +++ b/hw08_envdir_tool/env_reader_test.go @@ -1,7 +1,73 @@ package main -import "testing" +import ( + "github.com/stretchr/testify/require" + "os" + "testing" +) func TestReadDir(t *testing.T) { - // Place your code here + t.Run("Нет файлов в директории", func(t *testing.T) { + os.RemoveAll("testdata/env/no") + if err := os.Mkdir("testdata/env/no", os.ModePerm); err != nil { + return + } + env, err := ReadDir("testdata/env/no") + os.RemoveAll("testdata/env/no") + require.Equal(t, env, Environment{}) + require.NoError(t, err) + }) + + t.Run("Проверка = и ; в именах", func(t *testing.T) { + os.RemoveAll("testdata/env/no") + if err := os.Mkdir("testdata/env/no", os.ModePerm); err != nil { + return + } + if _, err := os.Create("testdata/env/no/TES=T1"); err != nil { + return + } + if _, err := os.Create("testdata/env/no/TES;T2"); err != nil { + return + } + env, err := ReadDir("testdata/env/no") + os.RemoveAll("testdata/env/no") + require.Equal(t, env, Environment{"TEST1": "", "TEST2": ""}) + require.NoError(t, err) + }) +} + +func TestReadFile(t *testing.T) { + t.Run("Файл не существует", func(t *testing.T) { + str, err := ReadFile("dsvfsdfdfdv") + require.Equal(t, str, "") + require.Error(t, err) + }) + t.Run("Файл пуст", func(t *testing.T) { + str, err := ReadFile("testdata/env/UNSET") + require.Equal(t, str, "") + require.NoError(t, err) + }) +} + +func TestExtractEnv(t *testing.T) { + + t.Run("Zero escaping", func(t *testing.T) { + require.Equal(t, "zero_escape", ExtractEnv("zero_escape\x00with new line")) + }) + + t.Run("Quotes", func(t *testing.T) { + require.Equal(t, "quotes", ExtractEnv("\"quotes\"")) + }) + + t.Run("Pre spacing", func(t *testing.T) { + require.Equal(t, "pre_spased", ExtractEnv(" pre_spased")) + }) + + t.Run("Post spacing", func(t *testing.T) { + require.Equal(t, "post_spased", ExtractEnv("post_spased ")) + }) + + t.Run("Multy spacing", func(t *testing.T) { + require.Equal(t, "multy spased", ExtractEnv(" multy spased ")) + }) } diff --git a/hw08_envdir_tool/executor.go b/hw08_envdir_tool/executor.go index f01d6be..a0aded9 100644 --- a/hw08_envdir_tool/executor.go +++ b/hw08_envdir_tool/executor.go @@ -1,7 +1,24 @@ package main -// RunCmd runs a command + arguments (cmd) with environment variables from env +import ( + "os" + "os/exec" +) + func RunCmd(cmd []string, env Environment) (returnCode int) { - // Place your code here - return + c := exec.Command(cmd[0], cmd[1:]...) + for k, v := range env { + c.Env = append(os.Environ(), k+"="+v) + } + c.Stdout = os.Stdout + c.Stderr = os.Stderr + if err := c.Run(); err != nil { + if code, ok := err.(*exec.ExitError); ok { + return code.ExitCode() + } + + return -1 + } + + return 0 } diff --git a/hw08_envdir_tool/executor_test.go b/hw08_envdir_tool/executor_test.go index 6402ce3..233736e 100644 --- a/hw08_envdir_tool/executor_test.go +++ b/hw08_envdir_tool/executor_test.go @@ -1,7 +1,17 @@ package main -import "testing" +import ( + "github.com/stretchr/testify/require" + "testing" +) func TestRunCmd(t *testing.T) { - // Place your code here + t.Run("Команда не существует", func(t *testing.T) { + code := RunCmd([]string{"sffdsfsvs"}, Environment{"E1": "val1"}) + require.Equal(t, code, -1) + }) + t.Run("Команда выполнилась", func(t *testing.T) { + code := RunCmd([]string{"ls"}, Environment{"E1": "val1"}) + require.Equal(t, code, 0) + }) } diff --git a/hw08_envdir_tool/go.mod b/hw08_envdir_tool/go.mod index 8536af6..4008bb9 100644 --- a/hw08_envdir_tool/go.mod +++ b/hw08_envdir_tool/go.mod @@ -1,3 +1,5 @@ -module github.com/fixme_my_friend/hw08_envdir_tool +module github.com/tiburon-777/HW_OTUS/hw08_envdir_tool go 1.14 + +require github.com/stretchr/testify v1.6.1 diff --git a/hw08_envdir_tool/main.go b/hw08_envdir_tool/main.go index 441440a..dff44ae 100644 --- a/hw08_envdir_tool/main.go +++ b/hw08_envdir_tool/main.go @@ -1,5 +1,13 @@ package main +import "os" + func main() { - // Place your code here + // парсим аргументы + args := os.Args + env, err := ReadDir(args[1]) + if err != nil { + os.Exit(111) + } + os.Exit(RunCmd(args[2:], env)) }