Skip to content

Commit

Permalink
Merge pull request #8 from DimVlas/hw08_envdir_tool
Browse files Browse the repository at this point in the history
HW08 is completed
  • Loading branch information
DimVlas authored Jul 26, 2024
2 parents 8a0142e + 196c9d1 commit 9c57809
Show file tree
Hide file tree
Showing 8 changed files with 283 additions and 10 deletions.
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)
}

0 comments on commit 9c57809

Please sign in to comment.