Skip to content

Commit 49c50d5

Browse files
author
Konstantinos Bairaktaris
authored
Merge pull request #92 from transifex/two_langs_in_file_filter
Support two <lang>s in file filters
2 parents 75861cb + 5a06798 commit 49c50d5

5 files changed

Lines changed: 91 additions & 66 deletions

File tree

internal/txlib/add.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,17 @@ type AddCommandArguments struct {
4646
}
4747

4848
func validateFileFilter(input string) error {
49-
res := strings.Count(input, "<lang>")
50-
if res != 1 {
51-
return errors.New("you need one <lang> in your File Filter")
52-
}
5349
if len(filepath.Ext(input)) <= 1 {
5450
return errors.New("you need to add an extension to your file")
5551
}
52+
input = normaliseFileFilter(input)
53+
for _, part := range strings.Split(input, string(os.PathSeparator)) {
54+
if strings.Count(part, "<lang>") > 1 {
55+
return errors.New(
56+
"<lang> cannot appear more than once in the same part of the path",
57+
)
58+
}
59+
}
5660
return nil
5761
}
5862

internal/txlib/file_filter_test.go

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,12 @@ import (
1111
)
1212

1313
func beforeFileFilterTest(t *testing.T) func() {
14-
curDir, err := os.Getwd()
15-
if err != nil {
16-
t.Error(err)
17-
}
18-
tempDir, err := os.MkdirTemp("", "")
19-
if err != nil {
20-
t.Error(err)
21-
}
22-
err = os.Chdir(tempDir)
23-
if err != nil {
24-
t.Error(err)
25-
}
14+
curDir, _ := os.Getwd()
15+
tempDir, _ := os.MkdirTemp("", "")
16+
_ = os.Chdir(tempDir)
2617
return func() {
27-
err = os.Chdir(curDir)
28-
if err != nil {
29-
t.Error(err)
30-
}
31-
err := os.RemoveAll(tempDir)
32-
if err != nil {
33-
t.Error(err)
34-
}
18+
_ = os.Chdir(curDir)
19+
_ = os.RemoveAll(tempDir)
3520
}
3621
}
3722

@@ -125,6 +110,53 @@ func TestSearchFileFilterDirs(t *testing.T) {
125110
}
126111
}
127112

113+
func TestSearchFileWithTwoLangs(t *testing.T) {
114+
afterTest := beforeFileFilterTest(t)
115+
defer afterTest()
116+
117+
// <curDir>/
118+
// + en/
119+
// | + foo/
120+
// | + en.txt
121+
// | + fr.txt
122+
err := os.Mkdir("en", os.ModeDir|0755)
123+
if err != nil {
124+
t.Error(err)
125+
}
126+
err = os.Mkdir(filepath.Join("en", "foo"), os.ModeDir|0755)
127+
if err != nil {
128+
t.Error(err)
129+
}
130+
file1, err := os.OpenFile(
131+
filepath.Join("en", "foo", "en.txt"),
132+
os.O_RDWR|os.O_CREATE|os.O_TRUNC,
133+
0755,
134+
)
135+
if err != nil {
136+
t.Error(err)
137+
}
138+
defer file1.Close()
139+
file2, err := os.OpenFile(
140+
filepath.Join("en", "foo", "fr.txt"),
141+
os.O_RDWR|os.O_CREATE|os.O_TRUNC,
142+
0755,
143+
)
144+
if err != nil {
145+
t.Error(err)
146+
}
147+
defer file2.Close()
148+
149+
curDir, err := os.Getwd()
150+
if err != nil {
151+
t.Error(err)
152+
}
153+
actual := searchFileFilter(curDir, filepath.Join("<lang>", "foo", "<lang>.txt"))
154+
expected := map[string]string{"en": filepath.Join(curDir, "en", "foo", "en.txt")}
155+
if !reflect.DeepEqual(actual, expected) {
156+
t.Errorf("Got '%+v', expected '%+v'", actual, expected)
157+
}
158+
}
159+
128160
func TestNormaliseFileFilterLinuxBased(t *testing.T) {
129161
result := normaliseFileFilter("en/text.txt")
130162
expected := filepath.Join("en", "text.txt")

internal/txlib/filefilter.go

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,29 @@
11
package txlib
22

33
import (
4-
"io/ioutil"
54
"os"
65
"strings"
76
)
87

98
const PathSeparator = string(os.PathSeparator)
109

1110
/*
12-
Recursively search under the directory 'root' for files that match the
13-
'fileFilter'. The original file filter must have exactly one instance of
14-
"<lang>" in it.
11+
Recursively search under the directory 'root' for files that match the 'fileFilter'.
1512
1613
If nothing is found, an empty map will be returned.
1714
18-
If 'fileFilter' is empty, which means that we are in the last step of the
19-
recursion, 'root' is returned if it exists in the filesystem and is a file.
15+
If 'fileFilter' is empty, which means that we are in the last step of the recursion,
16+
'root' is returned if it exists in the filesystem and is a file.
2017
21-
If, in the current iteration, the file filter does not have "<lang>" (which
22-
means that the "<lang>" part is now in the 'root'), then the matching file, if
23-
found, will be returned under the "" key ({"": "/path/to/file.txt"}).
18+
If, in the current iteration, the file filter does not have "<lang>" (which means that
19+
the "<lang>" part is now in the 'root'), then the matching file, if found, will be
20+
returned under the "" key ({"": "/path/to/file.txt"}).
2421
25-
If the first item in 'fileFilter' does have a "<lang>" in it, then the contents
26-
of the 'root' directory (it must be a directory) will be matched against the
27-
pattern, the function will be called recursively for a new root that contains
28-
the matched path and the result of the recursive function will be added to the
29-
result of the current function with the matched language as the key.
22+
If the first item in 'fileFilter' does have a "<lang>" in it, then the contents of the
23+
'root' directory (it must be a directory) will be matched against the pattern, the
24+
function will be called recursively for a new root that contains the matched path and
25+
the result of the recursive function will be added to the result of the current function
26+
with the matched language as the key.
3027
3128
Examples:
3229
@@ -35,19 +32,19 @@ Examples:
3532
|
3633
+ file.txt
3734
38-
Then the invocation of:
35+
Then the invocation of:
3936
4037
searchFileFilter("/path/to/root/file.txt", "")
4138
42-
will check that 'root' does exist and is not a directory and return:
39+
will check that 'root' does exist and is not a directory and return:
4340
4441
map[string]string{"": "/path/to/root/file.txt"}
4542
46-
The invocation of:
43+
The invocation of:
4744
4845
searchFileFilter("/path/to/root", "file.txt")
4946
50-
will recursively call the previous invocation and return its result:
47+
will recursively call the previous invocation and return its result:
5148
5249
map[string]string{"": "/path/to/root/file.txt"}
5350
@@ -59,26 +56,26 @@ will recursively call the previous invocation and return its result:
5956
|
6057
+ fr.txt
6158
62-
The invocation of:
59+
The invocation of:
6360
6461
searchFileFilter("/path/to/root/en.txt", "")
6562
66-
as before, will return:
63+
as before, will return:
6764
6865
map[string]string{"": "/path/to/root/en.txt"}
6966
70-
But, the invocation of:
67+
But, the invocation of:
7168
7269
searchFileFilter("/path/to/root", "<lang>.txt")
7370
74-
will inspect the contents of 'root', match the 2 files against the pattern,
75-
make 2 invocations similar to the first (one with "en" in 'root' and one with
76-
"fr") and return their results using the matched language codes as keys. So:
71+
will inspect the contents of 'root', match the 2 files against the pattern, make 2
72+
invocations similar to the first (one with "en" in 'root' and one with "fr") and
73+
return their results using the matched language codes as keys. So:
7774
7875
map[string]string{"en": "/path/to/root/en.txt",
7976
"fr": "/path/to/root/fr.txt"}
8077
81-
3. Finally, assuming the filesystem looks like this:
78+
3. Assuming the filesystem looks like this:
8279
8380
/path/to/root/
8481
|
@@ -90,7 +87,7 @@ make 2 invocations similar to the first (one with "en" in 'root' and one with
9087
|
9188
+ file.txt
9289
93-
The following calls and results will happen:
90+
The following calls and results will happen:
9491
9592
searchFileFilter("/path/to/root/en/file.txt", "")
9693
// map[string]string{"": "/path/to/root/en/file.txt"}
@@ -102,12 +99,12 @@ The following calls and results will happen:
10299
// map[string]string{"en": "/path/to/root/en/file.txt",
103100
"fr": "/path/to/root/fr/file.txt"}
104101
*/
105-
func searchFileFilter(root string, fileFilter string) map[string]string {
102+
103+
func searchFileFilter(root, fileFilter string) map[string]string {
106104
result := make(map[string]string)
107105

108106
fileFilter = normaliseFileFilter(fileFilter)
109107

110-
fileFilterSlice := strings.Split(fileFilter, PathSeparator)
111108
if len(fileFilter) == 0 {
112109
fileInfo, err := os.Stat(root)
113110
if err != nil || fileInfo.IsDir() {
@@ -116,21 +113,18 @@ func searchFileFilter(root string, fileFilter string) map[string]string {
116113
result[""] = root
117114
return result
118115
}
119-
116+
fileFilterSlice := strings.Split(fileFilter, PathSeparator)
120117
if !strings.Contains(fileFilterSlice[0], "<lang>") {
121118
// Recursively go deeper
122-
newRoot := strings.Join([]string{root, fileFilterSlice[0]},
123-
PathSeparator)
119+
newRoot := strings.Join([]string{root, fileFilterSlice[0]}, PathSeparator)
124120
newFileFilter := strings.Join(fileFilterSlice[1:], PathSeparator)
125121
return searchFileFilter(newRoot, newFileFilter)
126122
} else {
127-
// Sometime before we checked that the original 'fileFilterSlice' had
128-
// exactly one "<lang>" in it, so 'parts' is guaranteed to be of size 2
129123
parts := strings.Split(fileFilterSlice[0], "<lang>")
130124
left := parts[0]
131125
right := parts[1]
132126

133-
fileInfos, err := ioutil.ReadDir(root)
127+
fileInfos, err := os.ReadDir(root)
134128
if err != nil {
135129
return result
136130
}
@@ -149,6 +143,8 @@ func searchFileFilter(root string, fileFilter string) map[string]string {
149143

150144
newRoot := strings.Join([]string{root, name}, PathSeparator)
151145
newFileFilter := strings.Join(fileFilterSlice[1:], PathSeparator)
146+
// IT doesn't make sense to capture 'en/fr' with '<lang>/<lang>'
147+
newFileFilter = strings.ReplaceAll(newFileFilter, "<lang>", languageCode)
152148
answer := searchFileFilter(newRoot, newFileFilter)
153149

154150
path, exists := answer[""]

internal/txlib/pull.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ func (task *ResourcePullTask) Run(send func(string), abort func()) {
114114
filePullTaskChannel := task.filePullTaskChannel
115115
cfg := task.cfg
116116

117-
118117
sendMessage := func(body string) {
119118
send(fmt.Sprintf(
120119
"%s.%s - %s",

internal/txlib/utils.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"errors"
55
"fmt"
66
"os"
7-
"strings"
87
"time"
98

109
"github.com/gosimple/slug"
@@ -145,12 +144,7 @@ func handleThrottling(do func() error, initialMsg string, send func(string)) err
145144
func checkFileFilter(fileFilter string) error {
146145
if fileFilter == "" {
147146
return errors.New("file filter is empty")
148-
} else if strings.Count(fileFilter, "<lang>") != 1 {
149-
return fmt.Errorf(
150-
"file filter '%s' should have exactly one occurrence of '<lang>'",
151-
fileFilter,
152-
)
153147
} else {
154-
return nil
148+
return validateFileFilter(fileFilter)
155149
}
156150
}

0 commit comments

Comments
 (0)