diff --git a/hw08_envdir_tool/.sync b/hw08_envdir_tool/.sync deleted file mode 100644 index e69de29..0000000 diff --git a/hw08_envdir_tool/env_reader.go b/hw08_envdir_tool/env_reader.go index 92e9823..0fa3a0a 100644 --- a/hw08_envdir_tool/env_reader.go +++ b/hw08_envdir_tool/env_reader.go @@ -1,5 +1,16 @@ package main +import ( + "bufio" + "fmt" + "io/fs" + "io/ioutil" + "os" + "strings" +) + +const INVALID_FILE_NAME_CHARACTER = "=" + type Environment map[string]EnvValue // EnvValue helps to distinguish between empty files and files with the first empty line. @@ -11,6 +22,74 @@ type EnvValue struct { // 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 + var valName string + var valValue string + var needRemove bool + var ok bool + + result := make(Environment) + + files, err := ioutil.ReadDir(dir) + if err != nil { + return result, fmt.Errorf("read dir: %w", err) + } + + for _, f := range files { + + valName, ok = getFileName(f) + if ok == false { + continue + } + + valValue, needRemove, err = getValue(dir, f) + if err != nil { + return result, fmt.Errorf("get value error: %w", err) + } + + result[valName] = EnvValue{valValue, needRemove} + } + + return result, nil +} + +func getFileName(file fs.FileInfo) (string, bool) { + if file.IsDir() { + return "", false + } + + if strings.Contains(file.Name(), INVALID_FILE_NAME_CHARACTER) { + return "", false + } + + return file.Name(), true +} + +func getValue(dir string, fileInfo fs.FileInfo) (string, bool, error) { + if fileInfo.Size() == 0 { + return "", true, nil + } + + file, err := os.Open(dir + "/" + fileInfo.Name()) + + if err != nil { + return "", false, err + } + + defer file.Close() + + scanner := bufio.NewScanner(file) + + scanner.Scan() + value := scanner.Text() + + err = scanner.Err() + if err != nil { + return "", false, err + } + + result := strings.TrimRight(value, " \t") + + result = strings.Replace(result, "\x00", "\n", -1) + + return result, false, nil } diff --git a/hw08_envdir_tool/env_reader_test.go b/hw08_envdir_tool/env_reader_test.go index 7962c06..5f9ccf2 100644 --- a/hw08_envdir_tool/env_reader_test.go +++ b/hw08_envdir_tool/env_reader_test.go @@ -1,7 +1,72 @@ package main -import "testing" +import ( + "fmt" + "github.com/stretchr/testify/require" + "os" + "testing" +) func TestReadDir(t *testing.T) { - // Place your code here + _, err := ReadDir("not_exist_dir") + require.Error(t, err) + + result, err := ReadDir("testdata/env") + require.NoError(t, err) + require.Equal(t, getExpectedResult(), result) + + // check if ignores files + testDirName := "testdata/env/2" + createTestDir(testDirName) + result, err = ReadDir("testdata/env") + require.NoError(t, err) + require.Equal(t, getExpectedResult(), result) + removeTestDir(testDirName) + + // check if ignores files with the - in the name + testFileName := "testdata/env/2=2.txt" + createTestFile(testFileName, []byte("hello\ngo\n")) + result, err = ReadDir("testdata/env") + require.NoError(t, err) + require.Equal(t, getExpectedResult(), result) + removeTestFile(testFileName) +} + +func createTestDir(dir string) { + err := os.MkdirAll(dir, os.ModePerm) + if err != nil { + panic(fmt.Errorf("Error creating test directory: %w", err)) + } +} + +func removeTestDir(dir string) { + err := os.RemoveAll(dir) + if err != nil { + panic(fmt.Errorf("Error removing test directory: %w", err)) + } +} + +func createTestFile(file string, data []byte) { + err := os.WriteFile(file, data, os.ModePerm) + if err != nil { + panic(fmt.Errorf("Error creating test file: %w", err)) + } +} + +func removeTestFile(file string) { + err := os.Remove(file) + if err != nil { + panic(fmt.Errorf("Error removing test directory: %w", err)) + } +} + +func getExpectedResult() Environment { + result := make(Environment) + result["BAR"] = EnvValue{"bar", false} + result["EMPTY"] = EnvValue{"", false} + result["FOO"] = EnvValue{" foo\nwith new line", false} + result["HELLO"] = EnvValue{"\"hello\"", false} + result["UNSET"] = EnvValue{"", true} + + return result } diff --git a/hw08_envdir_tool/executor.go b/hw08_envdir_tool/executor.go index 33589ea..1962002 100644 --- a/hw08_envdir_tool/executor.go +++ b/hw08_envdir_tool/executor.go @@ -1,7 +1,40 @@ package main +import ( + "os" + "os/exec" +) + // RunCmd runs a command + arguments (cmd) with environment variables from env. func RunCmd(cmd []string, env Environment) (returnCode int) { - // Place your code here. - return + command := exec.Command(cmd[0], cmd[1:]...) + setEnvironmentVariables(env) + + command.Stdout = os.Stdout + command.Stdin = os.Stdin + + err := command.Start() + if err != nil { + panic(err) + } + + err = command.Wait() + if err != nil { + panic(err) + } + + return command.ProcessState.ExitCode() +} + +func setEnvironmentVariables(env Environment) bool { + for name, envValue := range env { + if envValue.NeedRemove == true { + os.Unsetenv(name) + continue + } + + os.Setenv(name, envValue.Value) + } + + return true } diff --git a/hw08_envdir_tool/executor_test.go b/hw08_envdir_tool/executor_test.go index 6402ce3..9486fca 100644 --- a/hw08_envdir_tool/executor_test.go +++ b/hw08_envdir_tool/executor_test.go @@ -1,7 +1,84 @@ package main -import "testing" +import ( + "github.com/stretchr/testify/require" + "testing" + //"fmt" + "os" +) + +func TestCanSetEnvironmentVariables(t *testing.T) { + // backup env variables before the test if any was set + backup := backupEnvironment() + + os.Unsetenv("HELLO") + + env := make(Environment) + env["HELLO"] = EnvValue{"hello", false} + + setEnvironmentVariables(env) + + value, present := os.LookupEnv("HELLO") + require.Equal(t, true, present) + require.Equal(t, "hello", value) + + // restore backup variables + restoreEnvironmentFromTheBackup(backup) +} + +func TestCanRemoveEnvironmentVariables(t *testing.T) { + // backup env variables before the test if any was set + backup := backupEnvironment() + + os.Setenv("HELLO", "hello") + + env := make(Environment) + env["HELLO"] = EnvValue{"hello", true} + + setEnvironmentVariables(env) + _, present := os.LookupEnv("HELLO") + require.Equal(t, false, present) + + // restore backup variables + restoreEnvironmentFromTheBackup(backup) +} func TestRunCmd(t *testing.T) { - // Place your code here + cmd := make([]string, 2) + cmd[0] = "testdata/echo.sh" + cmd[1] = "arg1" + code := RunCmd(cmd, getAllValues()) + require.Equal(t, 0, code) +} + +func backupEnvironment() map[string]string { + var testEnvNames = []string{"HELLO", "BAR", "FOO", "UNSET", "ADDED", "EMPTY"} + result := make(map[string]string) + + for _, name := range testEnvNames { + value, present := os.LookupEnv(name) + if present == true { + result[name] = value + } + } + + return result +} + +func restoreEnvironmentFromTheBackup(env map[string]string) { + for name, value := range env { + os.Setenv(name, value) + } +} + +func getAllValues() Environment { + result := make(Environment) + result["HELLO"] = EnvValue{"hello", false} + result["BAR"] = EnvValue{"bar", false} + result["FOO"] = EnvValue{"foo", false} + result["UNSET"] = EnvValue{"unset", false} + result["ADDED"] = EnvValue{"added", false} + result["EMPTY"] = EnvValue{"empty", false} + + return result } diff --git a/hw08_envdir_tool/go.mod b/hw08_envdir_tool/go.mod index c15cae8..286d14d 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/sofiiakulish/hw08_envdir_tool go 1.16 + +require github.com/stretchr/testify v1.8.0 diff --git a/hw08_envdir_tool/go.sum b/hw08_envdir_tool/go.sum new file mode 100644 index 0000000..5164829 --- /dev/null +++ b/hw08_envdir_tool/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/hw08_envdir_tool/hw08_envdir_tool b/hw08_envdir_tool/hw08_envdir_tool new file mode 100755 index 0000000..d9be756 Binary files /dev/null and b/hw08_envdir_tool/hw08_envdir_tool differ diff --git a/hw08_envdir_tool/main.go b/hw08_envdir_tool/main.go index 1eca213..2c523dd 100644 --- a/hw08_envdir_tool/main.go +++ b/hw08_envdir_tool/main.go @@ -1,5 +1,16 @@ package main +import ( + "os" +) + func main() { - // Place your code here. + // go-envdir /path/to/env/dir command arg1 arg2 + args := os.Args + env, err := ReadDir(args[1]) + if err != nil { + panic(err) + } + + RunCmd(args[2:], env) }