-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
#18: Add utilities for assisting with common migration logic
- Loading branch information
Showing
13 changed files
with
498 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
baton-maven-plugin/src/main/java/org/technologybrewery/baton/util/CommonUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.technologybrewery.baton.util; | ||
import com.vdurmont.semver4j.Semver; | ||
|
||
/** | ||
* Common logic used when performing a migration. | ||
*/ | ||
public final class CommonUtils { | ||
private CommonUtils(){ | ||
} | ||
|
||
/** | ||
* Checks if version1 is less than version2 using the Semver4j library. | ||
* | ||
* @param version1 | ||
* @param version2 | ||
* @return isLessThanVersion - if true, version1 is less than version2. | ||
*/ | ||
public static boolean isLessThanVersion(String version1, String version2) { | ||
Semver sem = new Semver(version1); | ||
return sem.isLowerThan(version2); | ||
} | ||
} |
220 changes: 220 additions & 0 deletions
220
baton-maven-plugin/src/main/java/org/technologybrewery/baton/util/FileUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
package org.technologybrewery.baton.util; | ||
|
||
import org.apache.commons.io.IOUtils; | ||
import org.codehaus.plexus.util.StringUtils; | ||
|
||
import java.io.File; | ||
import java.io.FileOutputStream; | ||
import java.io.IOException; | ||
import java.nio.charset.Charset; | ||
import java.nio.charset.StandardCharsets; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
import static org.apache.commons.lang3.StringUtils.SPACE; | ||
|
||
/** | ||
* Common file-related logic used when performing a migration. | ||
*/ | ||
public final class FileUtils { | ||
private FileUtils(){ | ||
} | ||
|
||
/** | ||
* Evaluates a file against a literal string and replaces each match with a specified replacement. | ||
* | ||
* @param file the File | ||
* @param toReplace a string representing the text to replace | ||
* @param replacement the replacement text to substitute the toReplace string | ||
* @return a boolean set to true if at least one replacement was performed in the file | ||
*/ | ||
public static boolean replaceLiteralInFile(File file, String toReplace, String replacement) throws IOException { | ||
boolean replacedInFile = false; | ||
|
||
if (file != null && file.exists()) { | ||
String content = new String(Files.readAllBytes((file.toPath()))); | ||
content = content.replace(toReplace, replacement); | ||
Files.write(file.toPath(), content.getBytes()); | ||
replacedInFile = true; | ||
} | ||
return replacedInFile; | ||
} | ||
|
||
/** | ||
* Evaluates a file against a regex pattern and replaces the captured string(s) of each regex match | ||
* with a specified replacement | ||
* | ||
* @param file the File | ||
* @param regex a regex representing the text to replace, as a String | ||
* @param replacement the replacement text to substitute the regex | ||
* @return a boolean set to true if at least one replacement was performed in the file | ||
*/ | ||
public static boolean replaceInFile(File file, String regex, String replacement) throws IOException { | ||
boolean replacedInFile = false; | ||
if (file != null && file.exists()) { | ||
Charset charset = StandardCharsets.UTF_8; | ||
String fileContent = new String(Files.readAllBytes(file.toPath()), charset); | ||
|
||
Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE); | ||
Matcher matcher = pattern.matcher(fileContent); | ||
String newFileContent = matcher.replaceAll(replacement); | ||
IOUtils.write(newFileContent, new FileOutputStream(file), charset); | ||
replacedInFile = true; | ||
} | ||
return replacedInFile; | ||
} | ||
|
||
/** | ||
* Evaluates a file against a regex pattern and replaces a substring of each regex match | ||
* with a specified replacement. | ||
* | ||
* @param file the File | ||
* @param regex a regex representing the text to replace a substring of | ||
* @param substring the substring of the regex match that will be replaced | ||
* @param replacement the replacement of the match substring | ||
* @return a boolean set to true if at least one modification was performed in the file | ||
*/ | ||
public static boolean modifyRegexMatchInFile(File file, String regex, String substring, String replacement) { | ||
if (file == null || !file.exists()) { | ||
return false; | ||
} | ||
|
||
boolean modified = false; | ||
|
||
try { | ||
Path path = file.toPath(); | ||
Charset charset = StandardCharsets.UTF_8; | ||
List<String> resultLines = new ArrayList<>(); | ||
|
||
Pattern pattern = Pattern.compile(regex); | ||
for (String line : Files.readAllLines(path, charset)) { | ||
if (pattern.matcher(line).find()) { | ||
line = line.replace(substring, replacement); | ||
modified = true; | ||
} | ||
resultLines.add(line); | ||
} | ||
if (modified) { | ||
Files.write(path, resultLines, charset); | ||
} | ||
} catch (IOException e) { | ||
return false; | ||
} | ||
return modified; | ||
} | ||
|
||
/** | ||
* Reads in the {@link File} object and returns a {@link List} of the contents. | ||
* | ||
* @param file {@link File} to read | ||
* @return {@link List} of the contents | ||
* @throws IOException | ||
*/ | ||
public static List<String> readAllFileLines(File file) throws IOException { | ||
return Files.readAllLines(file.toPath(), StandardCharsets.UTF_8); | ||
} | ||
|
||
/** | ||
* Writes a {@link List} of the contents to the {@link File} object. | ||
* | ||
* @param file {@link File} to write | ||
* @param contents {@link List} of the contents | ||
* @throws IOException | ||
*/ | ||
public static void writeFile(File file, List<String> contents) throws IOException { | ||
Files.write(file.toPath(), contents, StandardCharsets.UTF_8); | ||
} | ||
|
||
/** | ||
* Retrieves capture groups from a regular expression match inside a file. | ||
* | ||
* @see FileUtils#getRegExCaptureGroups(String, String) | ||
* @param regex a regex containing capture groups, as a String | ||
* @param file the file to search for matching capture groups | ||
* @return An ArrayList of Strings representing each capture group in the regex that was matched | ||
*/ | ||
public static List<String> getRegExCaptureGroups(String regex, File file) throws IOException { | ||
String fileContent = ""; | ||
if (file != null && file.exists()) { | ||
Charset charset = StandardCharsets.UTF_8; | ||
fileContent = new String(Files.readAllBytes(file.toPath()), charset); | ||
} | ||
return StringUtils.isNotEmpty(fileContent) ? getRegExCaptureGroups(regex, fileContent) : new ArrayList<>(); | ||
} | ||
|
||
/** | ||
* Retrieves capture groups from a regular expression match inside a String. | ||
* | ||
* @param regex a regex containing capture groups, as a String | ||
* @param input the string to search for matching capture groups | ||
* @return An ArrayList of Strings representing each capture group in the regex that was matched | ||
*/ | ||
public static List<String> getRegExCaptureGroups(String regex, String input) { | ||
Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE); | ||
Matcher matcher = pattern.matcher(input); | ||
|
||
ArrayList<String> captured = new ArrayList<>(); | ||
if (matcher.find()) { | ||
// Skip the 0 index -- the first match is always all capture groups put together | ||
for (int i = 1; i <= matcher.groupCount(); ++i) { | ||
captured.add(matcher.group(i)); | ||
} | ||
} | ||
|
||
return captured; | ||
} | ||
|
||
/** | ||
* Evaluates a regex pattern against a file to determine if at least one regex match exists | ||
* | ||
* @param regex a regex pattern, as a String | ||
* @param file the file to search for matching substrings | ||
* @return true if there is at least one regex match, otherwise false | ||
*/ | ||
public static boolean hasRegExMatch(String regex, File file) throws IOException { | ||
String fileContent; | ||
if (file != null && file.exists()) { | ||
Charset charset = StandardCharsets.UTF_8; | ||
fileContent = Files.readString(file.toPath(), charset); | ||
return Pattern.compile(regex, Pattern.MULTILINE).matcher(fileContent).find(); | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* Infers the indentation style from the given line. | ||
* | ||
* @param line the line to infer the indentation style from | ||
* @param level the level of indentation of the line | ||
* @return a single indent in the inferred style | ||
*/ | ||
public static String getIndent(String line, int level) { | ||
if( level < 1 ) { | ||
return ""; | ||
} | ||
int i = 0; | ||
while (i < line.length() && Character.isWhitespace(line.charAt(i))) { | ||
i++; | ||
} | ||
return line.substring(0, i/level); | ||
} | ||
|
||
/** | ||
* Indent the values the desired number of tabs with a variable tab size. | ||
* | ||
* @param values List of {@link String} values to indent | ||
* @param numSpaces number of spaces to indent | ||
*/ | ||
public static void indentValues(List<String> values, int numSpaces) { | ||
for (int i = 0; i < values.size(); i++) { | ||
if (!values.get(i).isBlank()) { | ||
values.set(i, SPACE.repeat(numSpaces) + values.get(i)); | ||
} | ||
} | ||
} | ||
} |
89 changes: 89 additions & 0 deletions
89
baton-maven-plugin/src/test/java/org/technologybrewery/baton/UtilsTestSteps.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package org.technologybrewery.baton; | ||
|
||
import io.cucumber.java.en.Given; | ||
import io.cucumber.java.en.Then; | ||
import io.cucumber.java.en.When; | ||
import org.technologybrewery.baton.util.FileUtils; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
|
||
public class UtilsTestSteps { | ||
|
||
private static final File DEFAULT_TEST_DIRECTORY = new File("target/utils-test/"); | ||
private static final String DEFAULT_TEST_FILE_NAME = "text_file.txt"; | ||
File testFile; | ||
Boolean match; | ||
String inputAsString; | ||
List<String> captureGroups; | ||
|
||
@Given("I have a string containing {string}") | ||
public void i_have_a_string_containing(String str) throws Throwable { | ||
inputAsString = str; | ||
} | ||
|
||
@When("I use the regex {string} to retrieve capture groups") | ||
public void i_use_the_regex_to_retrieve_capture_groups(String regex) throws IOException { | ||
if (testFile != null) { | ||
captureGroups = FileUtils.getRegExCaptureGroups(regex, testFile); | ||
} else { | ||
captureGroups = FileUtils.getRegExCaptureGroups(regex, inputAsString); | ||
} | ||
} | ||
|
||
@Then("the size of the retrieved capture groups should be \"{int}\"") | ||
public void the_size_of_the_retrieved_capture_groups_should_be(int groups) { | ||
assertEquals(groups, captureGroups.size(),"Unexpected size for capture groups"); | ||
} | ||
|
||
@Then("the capture groups should include") | ||
public void the_capture_groups_should_include(List<String> expectedGroups) { | ||
assertEquals(expectedGroups, captureGroups); | ||
} | ||
|
||
@Given("I have a file containing the string {string}") | ||
public void i_have_a_file_containing_the_string(String string) throws IOException { | ||
testFile = new File(DEFAULT_TEST_DIRECTORY, DEFAULT_TEST_FILE_NAME); | ||
if (DEFAULT_TEST_DIRECTORY.mkdirs()) { | ||
FileUtils.writeFile(testFile, Collections.singletonList(string)); | ||
} | ||
} | ||
|
||
@When("I use the regex {string} to substitute {string}") | ||
public void i_use_the_regex_to_substitute(String regex, String substitute) throws IOException { | ||
FileUtils.replaceInFile(testFile, regex, substitute); | ||
} | ||
|
||
@When("I use the literal {string} to substitute {string}") | ||
public void iUseTheLiteralToSubstitute(String literal, String substitute) throws IOException { | ||
FileUtils.replaceLiteralInFile(testFile, literal, substitute); | ||
} | ||
|
||
@Then("the file should now contain the string {string}") | ||
public void the_file_should_now_contain_the_string(String string) throws IOException { | ||
assertTrue(FileUtils.hasRegExMatch(string, testFile), String.format("File does not contain expected string %s",string)); | ||
} | ||
|
||
@When("I use the regex {string} to substitute {string} with {string}") | ||
public void i_use_the_regex_to_substitute_with(String regex, String target, String substitute) { | ||
FileUtils.modifyRegexMatchInFile(testFile, regex, target, substitute); | ||
} | ||
|
||
@When("I use the regex {string} to search for matches in a file") | ||
public void i_use_the_regex_to_search_for_matches_in_a_file(String regex) throws IOException { | ||
match = FileUtils.hasRegExMatch(regex, testFile); | ||
|
||
} | ||
|
||
@Then("the match result should be \"{booleanValue}\"") | ||
public void the_match_result_should_be(Boolean expected) { | ||
assertEquals(expected, match, "RegEx file matcher did not return expected result"); | ||
|
||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
baton-maven-plugin/src/test/java/org/technologybrewery/baton/util/TestUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
|
||
package org.technologybrewery.baton.util; | ||
|
||
import io.cucumber.java.ParameterType; | ||
|
||
public class TestUtils { | ||
@ParameterType( value = "true|True|TRUE|false|False|FALSE") | ||
public Boolean booleanValue(String value){ | ||
return Boolean.valueOf(value); | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
baton-maven-plugin/src/test/resources/specifications/util/common-utils.feature
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Feature: Baton utilities can be used to assist with commonly used logic in a migration | ||
Scenario: I can easily compare the semantic versioning of two strings |
Oops, something went wrong.