Skip to content

Commit

Permalink
fix: brackets in the folder names
Browse files Browse the repository at this point in the history
  • Loading branch information
katerina20 committed Dec 16, 2023
1 parent 8fe52bd commit 2f66144
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 6 deletions.
16 changes: 16 additions & 0 deletions src/main/java/com/crowdin/cli/properties/helper/FileMatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,23 @@
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.regex.Pattern;

import static com.crowdin.cli.utils.Utils.isWindows;

/**
* File matcher for Crowdin CLI's documented syntax.
*/
class FileMatcher implements PathMatcher {
private final PathMatcher delegate;

public static final String ESCAPE_BRACKET_OPEN = isWindows() ? "^[" : "\\[";
public static final String ESCAPE_BRACKET_CLOSE = isWindows() ? "^]" : "\\]";
public static final String ESCAPE_BRACKET_OPEN_REGEX = "\\\\[";
public static final String ESCAPE_BRACKET_CLOSE_REGEX = "\\\\]";
private static final String ESCAPE_BRACKET_OPEN_PLACEHOLDER = "ESCAPE_BRACKET_OPEN_PLACEHOLDER";
private static final String ESCAPE_BRACKET_CLOSE_PLACEHOLDER = "ESCAPE_BRACKET_CLOSE_PLACEHOLDER";

FileMatcher(String pattern, String basePath) {

// Making matchers match the full path.
Expand All @@ -24,11 +34,17 @@ class FileMatcher implements PathMatcher {
pattern = pattern.replace(Utils.PATH_SEPARATOR_REGEX + Utils.PATH_SEPARATOR_REGEX, Utils.PATH_SEPARATOR_REGEX);
}
}
pattern = pattern.replaceAll(Pattern.quote(ESCAPE_BRACKET_OPEN), ESCAPE_BRACKET_OPEN_PLACEHOLDER);
pattern = pattern.replaceAll(Pattern.quote(ESCAPE_BRACKET_CLOSE), ESCAPE_BRACKET_CLOSE_PLACEHOLDER);

pattern = pattern.replaceAll("\\\\+", Utils.PATH_SEPARATOR_REGEX + Utils.PATH_SEPARATOR_REGEX);
pattern = pattern.replaceAll("/+", "/");
pattern = pattern.replaceAll("\\{\\{+", "\\\\{\\\\{");
pattern = pattern.replaceAll("}}+", "\\\\}\\\\}");

pattern = pattern.replaceAll(ESCAPE_BRACKET_OPEN_PLACEHOLDER, ESCAPE_BRACKET_OPEN_REGEX);
pattern = pattern.replaceAll(ESCAPE_BRACKET_CLOSE_PLACEHOLDER, ESCAPE_BRACKET_CLOSE_REGEX);

// We *could* implement exactly what's documented. The idea would be to implement something like
// Java's Globs.toRegexPattern but supporting only the documented syntax. Instead, we will use
// the real globber.
Expand Down
14 changes: 11 additions & 3 deletions src/main/java/com/crowdin/cli/utils/PlaceholderUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import java.util.Set;
import java.util.stream.Collectors;

import static com.crowdin.cli.utils.Utils.isWindows;

public class PlaceholderUtil {

public static final String PLACEHOLDER_ANDROID_CODE = "%android_code%";
Expand Down Expand Up @@ -47,8 +49,12 @@ public class PlaceholderUtil {
private static final String QUESTION_MARK = "?";
private static final String DOT = ".";
private static final String DOT_PLUS = ".+";
private static final String SET_OPEN_BRACKET = "[";
private static final String SET_CLOSE_BRACKET = "]";
private static final String SQUARE_BRACKET_OPEN = "[";
private static final String SQUARE_BRACKET_CLOSE = "]";
public static final String REGEX_SQUARE_BRACKET_OPEN = "\\[";
public static final String ESCAPE_SQUARE_BRACKET_OPEN = isWindows()? "^[" : "\\\\\\[";
public static final String ESCAPE_SQUARE_BRACKET_CLOSE = isWindows()? "^]" : "\\\\]";

public static final String ROUND_BRACKET_OPEN = "(";
public static final String ROUND_BRACKET_CLOSE = ")";
public static final String ESCAPE_ROUND_BRACKET_OPEN = "\\(";
Expand Down Expand Up @@ -192,6 +198,8 @@ public String replaceFileDependentPlaceholders(String toFormat, File file) {
prefix = prefix.length() > 1 && file.getPath().contains(prefix) ? StringUtils.substringBefore(fileParent, Utils.noSepAtStart(prefix)) : "";
String doubleAsterisks =
StringUtils.removeStart(Utils.noSepAtStart(StringUtils.removeStart(fileParent, prefix)), Utils.noSepAtEnd(Utils.noSepAtStart(StringUtils.substringBefore(toFormat, "**"))));
doubleAsterisks = doubleAsterisks.replaceAll(REGEX_SQUARE_BRACKET_OPEN, ESCAPE_SQUARE_BRACKET_OPEN);
doubleAsterisks = doubleAsterisks.replaceAll(SQUARE_BRACKET_CLOSE, ESCAPE_SQUARE_BRACKET_CLOSE);
toFormat = toFormat.replace("**", doubleAsterisks);
}

Expand Down Expand Up @@ -228,7 +236,7 @@ public List<String> formatForRegex(List<String> toFormat, boolean onProjectLangs
}

public static String formatSourcePatternForRegex(String toFormat) {
if(Utils.isWindows()){
if(isWindows()){
toFormat = toFormat
.replace("\\", "\\\\");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.stream.Stream;

import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -517,6 +520,68 @@ public void testUploadOneSourceWithDestAndDeleteObsoleteOption_Project() throws
verifyNoMoreInteractions(client);
}

@ParameterizedTest
@MethodSource
public void testUploadOneSourceWithAsteriskSourceBracketsDirAndIgnore_Project(String folderName) throws ResponseException {
project.addFile(Utils.normalizePath(folderName + "/first.md"), "Hello, World!");
project.addFile(Utils.normalizePath(folderName + "/1.md"), "Hello, World!");
String translationPattern = Utils.PATH_SEPARATOR + "%original_file_name%-CR-%locale%";
NewPropertiesWithFilesUtilBuilder pbBuilder = NewPropertiesWithFilesUtilBuilder
.minimalBuiltPropertiesBean(Utils.normalizePath("**/*"), translationPattern, Arrays.asList("**/[0-9].*"))
.setBasePath(project.getBasePath());
PropertiesWithFiles pb = pbBuilder.build();
pb.setPreserveHierarchy(true);
ProjectClient client = mock(ProjectClient.class);
when(client.downloadFullProject())
.thenReturn(ProjectBuilder.emptyProject(Long.parseLong(pb.getProjectId())).build());

AddDirectoryRequest addDirectoryRequest = new AddDirectoryRequest() {{
setName(folderName);
}};
Directory directory = DirectoryBuilder.standard().setProjectId(Long.parseLong(pb.getProjectId()))
.setIdentifiers(folderName, 201L, null, null).build();
when(client.addDirectory(eq(addDirectoryRequest)))
.thenReturn(directory);

when(client.uploadStorage(eq("first.md"), any()))
.thenReturn(1L);

NewAction<PropertiesWithFiles, ProjectClient> action = new UploadSourcesAction(null, true, false, true, false, false);
action.act(Outputter.getDefault(), pb, client);

verify(client).downloadFullProject();
verify(client).listLabels();
verify(client).uploadStorage(eq("first.md"), any());
verify(client).addDirectory(eq(addDirectoryRequest));
AddFileRequest addFileRequest = new AddFileRequest() {{
setName("first.md");
setStorageId(1L);
setDirectoryId(201L);
setImportOptions(new OtherFileImportOptions() {{
setContentSegmentation(pb.getFiles().get(0).getContentSegmentation());
}}
);
setExportOptions(new GeneralFileExportOptions() {{
setExportPattern(pb.getFiles().get(0).getTranslation().replaceAll("[\\\\/]+", "/"));
}}
);
}};
verify(client).addSource(eq(addFileRequest));
verifyNoMoreInteractions(client);
}

static Stream<Arguments> testUploadOneSourceWithAsteriskSourceBracketsDirAndIgnore_Project() {
return Stream.of(
arguments("[en]"),
arguments("t[en]"),
arguments("[en]t"),
arguments("t[en]t"),
arguments("t[en]"),
arguments("[en]t"),
arguments("tent")
);
}

@Test
public void testUpdateOneUploadOneSource_Project() throws ResponseException {
project.addFile(Utils.normalizePath("first.po"), "Hello, World!");
Expand Down

0 comments on commit 2f66144

Please sign in to comment.