Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HW08 is completed #8

Merged
merged 2 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file removed hw08_envdir_tool/.sync
Empty file.
85 changes: 83 additions & 2 deletions hw08_envdir_tool/env_reader.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
package main

import (
"bufio"
"bytes"
"fmt"
"log"
"os"
"path/filepath"
"strings"
)

type Environment map[string]EnvValue

// EnvValue helps to distinguish between empty files and files with the first empty line.
Expand All @@ -11,6 +21,77 @@ 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
dir = filepath.Clean(dir)

des, err := os.ReadDir(dir)
if err != nil {
return nil, fmt.Errorf("readDir: %w", err)
}

env := make(Environment)

for _, de := range des {
info, err := de.Info()
if err != nil {
log.Printf("info file '%s': %s", de.Name(), err)
continue
}
if !info.Mode().IsRegular() {
log.Printf("file '%s' is not regular", de.Name())
continue
}

if info.Size() == 0 {
env[de.Name()] = EnvValue{Value: "", NeedRemove: true}
continue
}

fName := filepath.Join(dir, de.Name())
data, err := readData(fName)
if err != nil {
log.Printf("ReadFile: %s", err)
continue
}

data = bytes.ReplaceAll(data, []byte("\000"), []byte("\n"))

env[de.Name()] = EnvValue{Value: strings.TrimRight(string(data), " \t"), NeedRemove: false}
}

return env, nil
}

func readData(fileName string) ([]byte, error) {
f, err := os.Open(fileName)
if err != nil {
return nil, fmt.Errorf("open file '%s': %w", fileName, err)
}
defer f.Close()

scanner := bufio.NewScanner(f)
scanner.Split(bufio.ScanLines)

if !scanner.Scan() {
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("scan: %w", err)
}
return make([]byte, 0), nil
}

return scanner.Bytes(), nil
}

func SetEnv(env Environment) error {
for envName, envVal := range env {
if envVal.NeedRemove {
if err := os.Unsetenv(envName); err != nil {
return err
}
} else {
if err := os.Setenv(envName, envVal.Value); err != nil {
return err
}
}
}
return nil
}
103 changes: 101 additions & 2 deletions hw08_envdir_tool/env_reader_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,106 @@
package main

import "testing"
import (
"fmt"
"log"
"os"
"testing"

"github.com/stretchr/testify/require"
)

const testdataPath = "." + string(os.PathSeparator) + "testdata"

func TestReadDir(t *testing.T) {
// Place your code here
t.Run("no error", func(t *testing.T) {
envDir := testdataPath + string(os.PathSeparator) + "env"
testEnv := Environment{
"BAR": EnvValue{Value: "bar", NeedRemove: false},
"EMPTY": EnvValue{Value: "", NeedRemove: false},
"FOO": EnvValue{Value: " foo\nwith new line", NeedRemove: false},
"HELLO": EnvValue{Value: "\"hello\"", NeedRemove: false},
"UNSET": EnvValue{Value: "", NeedRemove: true},
}

fmt.Println("envDir =", envDir)
env, err := ReadDir(envDir)

require.NoError(t, err, "no error")
require.Equal(t, env, testEnv, "Environment incorrect")
})

t.Run("no such directory", func(t *testing.T) {
envDir := testdataPath + string(os.PathSeparator) + "env_nosuch"

_, tstErr := ReadDir(envDir)

require.EqualError(
t,
tstErr,
"readDir: open testdata/env_nosuch: no such file or directory",
"actual err - %v", tstErr)
})

t.Run("empty directory", func(t *testing.T) {
envDir, err := os.MkdirTemp(testdataPath, "env_*")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(envDir)

env, tstErr := ReadDir(envDir)

require.Len(t, env, 0, "Env must be empty")
require.NoError(t, tstErr, "no error")
})
}

func TestSetEnv(t *testing.T) {
t.Run("empty map", func(t *testing.T) {
errTest := SetEnv(Environment{})

require.NoError(t, errTest, "no error")
})

t.Run("var remove", func(t *testing.T) {
os.Setenv("var1", "Value1")
os.Setenv("var2", "Value2")

errTest := SetEnv(Environment{
"var1": {"", true},
"var2": {"value2", false},
"var3": {"", false},
})

require.NoError(t, errTest, "no error")

_, var1Exists := os.LookupEnv("var1")
require.Equal(t, false, var1Exists, "var1 must be remove")

var2Val, var2Exists := os.LookupEnv("var2")
require.Equal(t, true, var2Exists, "var2 should be")
require.Equal(t, "value2", var2Val, "var2 must be 'value2'")

var3Val, var3Exists := os.LookupEnv("var3")
require.Equal(t, true, var3Exists, "var3 should be")
require.Equal(t, "", var3Val, "var3 must be empty")
})

t.Run("error variable name", func(t *testing.T) {
errTest := SetEnv(Environment{
"var=": {"varVal", false},
})

require.EqualError(t, errTest, "setenv: invalid argument", "expected error: 'setenv: invalid argument'")
})

t.Run("error variable value", func(t *testing.T) {
varVal := "var" + string([]byte("\000")) + "Val"

errTest := SetEnv(Environment{
"var": {varVal, false},
})

require.EqualError(t, errTest, "setenv: invalid argument", "expected error: 'setenv: invalid argument'")
})
}
33 changes: 31 additions & 2 deletions hw08_envdir_tool/executor.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,36 @@
package main

import (
"log"
"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
if len(cmd) < 1 {
return 0
}
if err := SetEnv(env); err != nil {
log.Println("SetEnv:", err)
return 0x7F
}
cmdName := cmd[0]

cmdArgs := []string{}
if len(cmd) > 1 {
cmdArgs = cmd[1:]
}

cmdExec := exec.Command(cmdName, cmdArgs...)

cmdExec.Stdin = os.Stdin
cmdExec.Stdout = os.Stdout
cmdExec.Stderr = os.Stderr

if err := cmdExec.Run(); err != nil {
log.Println("error Run:", err)
}

return cmdExec.ProcessState.ExitCode()
}
30 changes: 28 additions & 2 deletions hw08_envdir_tool/executor_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
package main

import "testing"
import (
"testing"

"github.com/stretchr/testify/require"
)

func TestRunCmd(t *testing.T) {
// Place your code here
t.Run("ls no error no args", func(t *testing.T) {
exitCode := RunCmd([]string{"ls"}, Environment{})

require.Equal(t, exitCode, 0, "exitCode incorrect")
})

t.Run("unknow command", func(t *testing.T) {
exitCode := RunCmd([]string{"lssssss"}, Environment{})

require.Equal(t, exitCode, -1, "exitCode incorrect")
})

t.Run("ls correct argument", func(t *testing.T) {
exitCode := RunCmd([]string{"ls", "-l"}, Environment{})

require.Equal(t, exitCode, 0, "exitCode incorrect")
})

t.Run("ls unknow argument", func(t *testing.T) {
exitCode := RunCmd([]string{"ls", "-y"}, Environment{})

require.Equal(t, exitCode, 2, "exitCode incorrect")
})
}
10 changes: 9 additions & 1 deletion hw08_envdir_tool/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
module github.com/fixme_my_friend/hw08_envdir_tool
module github.com/DimVlas/otus_hw/hw08_envdir_tool

go 1.19

require github.com/stretchr/testify v1.9.0

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
10 changes: 10 additions & 0 deletions hw08_envdir_tool/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
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/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
22 changes: 21 additions & 1 deletion hw08_envdir_tool/main.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
package main

import (
"fmt"
"os"
"path/filepath"
)

func main() {
// Place your code here.
if len(os.Args) < 3 {
fmt.Printf("usage: %s <path_to_env_dir> <command> [arg1 arg2 ...]\n", filepath.Base(os.Args[0]))
return
}

envDir := os.Args[1]

env, err := ReadDir(envDir)
if err != nil {
fmt.Println("ReadDir:", err)
}

retCode := RunCmd(os.Args[2:], env)

os.Exit(retCode)
}
Loading