11package main
22
3+ import (
4+ "bufio"
5+ "bytes"
6+ "errors"
7+ "fmt"
8+ "log"
9+ "os"
10+ "strings"
11+ "sync"
12+ )
13+
14+ var (
15+ ErrInvalidDir = errors .New ("invalid directory" )
16+ ErrEmptyDir = errors .New ("empty directory" )
17+ )
18+
319type Environment map [string ]EnvValue
420
521// EnvValue helps to distinguish between empty files and files with the first empty line.
@@ -8,9 +24,84 @@ type EnvValue struct {
824 NeedRemove bool
925}
1026
27+ var mu sync.Mutex
28+
1129// ReadDir reads a specified directory and returns map of env variables.
1230// Variables represented as files where filename is name of variable, file first line is a value.
1331func ReadDir (dir string ) (Environment , error ) {
14- // Place your code here
15- return nil , nil
32+ osDir , err := os .ReadDir (dir )
33+ if err != nil {
34+ return nil , ErrInvalidDir
35+ }
36+
37+ if len (osDir ) == 0 {
38+ return nil , ErrEmptyDir
39+ }
40+
41+ wg := sync.WaitGroup {}
42+ osEnv := make (Environment )
43+
44+ for _ , file := range osDir {
45+ wg .Add (1 )
46+ go processFile (dir , file , osEnv , & wg )
47+ }
48+
49+ wg .Wait ()
50+ return osEnv , nil
51+ }
52+
53+ func processFile (dir string , file os.DirEntry , osEnv Environment , wg * sync.WaitGroup ) {
54+ defer wg .Done ()
55+ var envValue EnvValue
56+
57+ osFile , err := os .Open (dir + "/" + file .Name ())
58+ if err != nil {
59+ fmt .Println ("Couldn't open file" , err )
60+ return
61+ }
62+ defer closeFile (osFile )
63+
64+ scanner := bufio .NewScanner (osFile )
65+
66+ if file .Name () == "UNSET" {
67+ envValue .NeedRemove = true
68+ envValue .Value = ""
69+ mu .Lock ()
70+ osEnv [file .Name ()] = envValue
71+ mu .Unlock ()
72+ return
73+ }
74+
75+ for scanner .Scan () {
76+ processLine (scanner , & envValue )
77+ mu .Lock ()
78+ osEnv [file .Name ()] = envValue
79+ mu .Unlock ()
80+ break
81+ }
82+
83+ if err := scanner .Err (); err != nil {
84+ log .Println ("Scanner error:" , err )
85+ }
86+ }
87+
88+ func closeFile (osFile * os.File ) {
89+ err := osFile .Close ()
90+ if err != nil {
91+ fmt .Println ("Couldn't close file" )
92+ }
93+ }
94+
95+ func processLine (scanner * bufio.Scanner , envValue * EnvValue ) {
96+ nullByte := make ([]byte , 1 )
97+ nullByte [0 ] = 0
98+ text := string (bytes .ReplaceAll ([]byte (scanner .Text ()), nullByte , []byte ("\n " )))
99+
100+ if len (strings .TrimSpace (scanner .Text ())) > 0 {
101+ envValue .NeedRemove = false
102+ } else {
103+ envValue .NeedRemove = true
104+ }
105+
106+ envValue .Value = text
16107}
0 commit comments