Skip to content

Commit

Permalink
feat: Add charSet parameter to FILE macro (#144)
Browse files Browse the repository at this point in the history
* feat: Add ability to set the character set for reading the file.

Defaults to the default charset for the running JVM

* Fix spotbugs
  • Loading branch information
slide authored Nov 17, 2022
1 parent a987834 commit 93c7f7f
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,18 @@
import hudson.model.TaskListener;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ObjectUtils;
import org.jenkinsci.plugins.tokenmacro.DataBoundTokenMacro;
import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;

Expand All @@ -48,6 +54,8 @@ public class WorkspaceFileMacro extends DataBoundTokenMacro {
public String fileNotFoundMessage = "ERROR: File '%s' does not exist";
@Parameter
public int maxLines = -1;
@Parameter
public String charSet = Charset.defaultCharset().name();


public static final String MACRO_NAME = "FILE";
Expand Down Expand Up @@ -83,28 +91,13 @@ public String evaluate(Run<?,?> run, FilePath workspace, TaskListener listener,
}

try {
if(maxLines > 0) {
int lines = 0;

StringBuilder result = new StringBuilder();
BufferedReader reader = null;
try {
String line;
reader = new BufferedReader(new InputStreamReader(workspace.child(path).read(), Charset.defaultCharset()));
while (lines < maxLines && (line = reader.readLine()) != null) {
result.append(line);
result.append('\n');
lines++;
}
} finally {
if(reader != null) {
reader.close();
}
Charset charset = Charset.forName(charSet);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(workspace.child(path).read(), charset))) {
if (maxLines > 0) {
return reader.lines().limit(maxLines).collect(Collectors.joining("\n"));
} else {
return reader.lines().collect(Collectors.joining("\n"));
}

return result.toString();
} else {
return workspace.child(path).readToString();
}
} catch (IOException e) {
return "ERROR: File '" + path + "' could not be read";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@
import hudson.model.FreeStyleProject;
import hudson.model.TaskListener;
import hudson.util.StreamTaskListener;
import org.apache.commons.io.IOUtils;
import org.jvnet.hudson.test.TestBuilder;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;

import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;

import static org.junit.Assert.*;
import static org.mockito.Mockito.when;

/**
* @author Kohsuke Kawaguchi
Expand Down Expand Up @@ -77,4 +83,75 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
assertEquals("Hello, world! " + i, lines[i]);
}
}

@Test
public void testUtfEncodings() throws Exception {
String[] expected = { "première is first",
"première is slightly different",
"Кириллица is Cyrillic",
"\uD801\uDC00 am Deseret" };

String[] encodings = { "utf8", "utf16" };

for(String encoding : encodings) {
FreeStyleProject project = j.createFreeStyleProject();
TaskListener listener = StreamTaskListener.fromStdout();
project.getBuildersList().add(new TestBuilder() {
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
FilePath file = build.getWorkspace().child(encoding + ".txt");
try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(file.write(), encoding))) {
try(BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(encoding + ".txt"), encoding))) {
IOUtils.copy(reader, writer);
}
}
return true;
}
});
FreeStyleBuild build = project.scheduleBuild2(0).get();

WorkspaceFileMacro content = new WorkspaceFileMacro();
content.path = encoding + ".txt";
content.charSet = encoding;

String output = content.evaluate(build, listener, WorkspaceFileMacro.MACRO_NAME);
String[] lines = output.split("\n");
assertEquals(4, lines.length);

for (int i = 0; i < 4; i++) {
assertEquals(expected[i], lines[i]);
}
}
}

@Test
public void testSimpleChinese() throws Exception {
FreeStyleProject project = j.createFreeStyleProject();
TaskListener listener = StreamTaskListener.fromStdout();

String expected;
try(BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("Chinese-Simplified.txt"), "utf16"))) {
expected = IOUtils.toString(reader);
}
project.getBuildersList().add(new TestBuilder() {
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
FilePath file = build.getWorkspace().child("Chinese-Simplified.txt");
try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(file.write(), "utf16"))) {
try(BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("Chinese-Simplified.txt"), "utf16"))) {
IOUtils.copy(reader, writer);
}
}
return true;
}
});
FreeStyleBuild build = project.scheduleBuild2(0).get();

WorkspaceFileMacro content = new WorkspaceFileMacro();
content.path = "Chinese-Simplified.txt";
content.charSet = "utf16";

String output = content.evaluate(build, listener, WorkspaceFileMacro.MACRO_NAME);
assertEquals(expected, output);
}
}

Large diffs are not rendered by default.

Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
première is first
première is slightly different
Кириллица is Cyrillic
𐐀 am Deseret

0 comments on commit 93c7f7f

Please sign in to comment.