From 32a6bbfd8fcdf9e77f7a1a453ff7dd64ceda33ab Mon Sep 17 00:00:00 2001 From: Daniel Trebbien Date: Sat, 13 Jan 2018 14:37:43 -0800 Subject: [PATCH 1/2] [JENKINS-48923] Core should use UTF-8 by default --- .../lifecycle/WindowsInstallerLink.java | 4 +- .../lifecycle/WindowsServiceLifecycle.java | 3 +- .../java/hudson/model/AsyncAperiodicWork.java | 3 +- .../java/hudson/model/AsyncPeriodicWork.java | 3 +- core/src/main/java/hudson/model/Computer.java | 4 +- core/src/main/java/hudson/model/JDK.java | 4 +- core/src/main/java/hudson/model/Queue.java | 4 +- core/src/main/java/hudson/model/Run.java | 52 +++++++++------ .../hudson/model/StreamBuildListener.java | 13 ++-- .../main/java/hudson/model/TaskListener.java | 4 +- .../main/java/hudson/model/TaskThread.java | 10 +-- .../java/hudson/os/solaris/ZFSInstaller.java | 6 +- .../hudson/slaves/AbstractCloudSlave.java | 2 +- .../java/hudson/slaves/SlaveComputer.java | 18 ++--- core/src/main/java/hudson/tasks/Maven.java | 4 +- .../main/java/hudson/triggers/SCMTrigger.java | 13 ++-- .../java/hudson/util/AtomicFileWriter.java | 19 ++---- .../java/hudson/util/LogTaskListener.java | 10 ++- .../main/java/hudson/util/SecretRewriter.java | 66 +++++++++---------- .../java/hudson/util/StreamTaskListener.java | 46 ++++++++----- core/src/main/java/hudson/util/TextFile.java | 2 + .../AsynchronousAdministrativeMonitor.java | 8 +-- core/src/main/java/jenkins/model/Jenkins.java | 3 +- .../jenkins/util/BuildListenerAdapter.java | 6 ++ core/src/test/java/hudson/FilePathTest.java | 5 +- core/src/test/java/hudson/LauncherTest.java | 7 +- core/src/test/java/hudson/UtilTest.java | 6 +- .../hudson/util/AtomicFileWriterTest.java | 9 ++- .../test/java/hudson/util/TextFileTest.java | 5 +- .../java/jenkins/model/RunIdMigratorTest.java | 3 +- test/src/test/java/hudson/ProcTest.java | 4 +- .../cli/ReloadConfigurationCommandTest.java | 12 ++-- .../console/AnnotatedLargeTextTest.java | 8 +-- .../test/java/hudson/model/ProjectTest.java | 7 +- .../hudson/tools/InstallerTranslatorTest.java | 2 +- .../hudson/util/ArgumentListBuilder2Test.java | 4 +- .../model/JenkinsReloadConfigurationTest.java | 12 ++-- 37 files changed, 208 insertions(+), 183 deletions(-) diff --git a/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java b/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java index 14bbb60584bc..541f6374b37b 100644 --- a/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java +++ b/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java @@ -54,8 +54,8 @@ import javax.servlet.ServletException; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.logging.Logger; import java.util.logging.Level; import java.net.URL; @@ -141,7 +141,7 @@ public void doDoInstall(StaplerRequest req, StaplerResponse rsp, @QueryParameter // install as a service ByteArrayOutputStream baos = new ByteArrayOutputStream(); - StreamTaskListener task = new StreamTaskListener(baos); + StreamTaskListener task = new StreamTaskListener(baos, StandardCharsets.UTF_8); task.getLogger().println("Installing a service"); int r = runElevated(new File(dir, "jenkins.exe"), "install", task, dir); if(r!=0) { diff --git a/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java b/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java index 42519eb21b0b..0c17acf15e09 100644 --- a/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java +++ b/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java @@ -39,6 +39,7 @@ import java.io.IOException; import java.io.FileWriter; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.logging.Level; import java.util.logging.Logger; @@ -130,7 +131,7 @@ public void restart() throws IOException, InterruptedException { File home = me.getParentFile(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - StreamTaskListener task = new StreamTaskListener(baos); + StreamTaskListener task = new StreamTaskListener(baos, StandardCharsets.UTF_8); task.getLogger().println("Restarting a service"); String exe = System.getenv("WINSW_EXECUTABLE"); File executable; diff --git a/core/src/main/java/hudson/model/AsyncAperiodicWork.java b/core/src/main/java/hudson/model/AsyncAperiodicWork.java index 1d295fa7161d..1fab8e2176cd 100644 --- a/core/src/main/java/hudson/model/AsyncAperiodicWork.java +++ b/core/src/main/java/hudson/model/AsyncAperiodicWork.java @@ -28,6 +28,7 @@ import hudson.util.StreamTaskListener; import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -190,7 +191,7 @@ protected StreamTaskListener createListener() { } } try { - return new StreamTaskListener(f, true, null); + return new StreamTaskListener(f, true, StandardCharsets.UTF_8); } catch (IOException e) { throw new Error(e); } diff --git a/core/src/main/java/hudson/model/AsyncPeriodicWork.java b/core/src/main/java/hudson/model/AsyncPeriodicWork.java index f3ffcc64976a..0c3cca36ffb2 100644 --- a/core/src/main/java/hudson/model/AsyncPeriodicWork.java +++ b/core/src/main/java/hudson/model/AsyncPeriodicWork.java @@ -5,6 +5,7 @@ import hudson.util.StreamTaskListener; import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -173,7 +174,7 @@ protected StreamTaskListener createListener() { } } try { - return new StreamTaskListener(f, true, null); + return new StreamTaskListener(f, true, StandardCharsets.UTF_8); } catch (IOException e) { throw new Error(e); } diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index 43fa2d31d707..6d41026107dc 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -316,14 +316,14 @@ public WorkspaceList getWorkspaceList() { * Gets the string representation of the agent log. */ public String getLog() throws IOException { - return Util.loadFile(getLogFile()); + return Util.loadFile(getLogFile(), getDefaultCharset()); } /** * Used to URL-bind {@link AnnotatedLargeText}. */ public AnnotatedLargeText getLogText() { - return new AnnotatedLargeText(getLogFile(), Charset.defaultCharset(), false, this); + return new AnnotatedLargeText(getLogFile(), getDefaultCharset(), false, this); } public ACL getACL() { diff --git a/core/src/main/java/hudson/model/JDK.java b/core/src/main/java/hudson/model/JDK.java index b04376eb74ae..25037dc6d5c8 100644 --- a/core/src/main/java/hudson/model/JDK.java +++ b/core/src/main/java/hudson/model/JDK.java @@ -23,8 +23,6 @@ */ package hudson.model; -import hudson.util.StreamTaskListener; -import hudson.util.NullStream; import hudson.util.FormValidation; import hudson.Launcher; import hudson.Extension; @@ -157,7 +155,7 @@ public JDK forEnvironment(EnvVars environment) { */ public static boolean isDefaultJDKValid(Node n) { try { - TaskListener listener = new StreamTaskListener(new NullStream()); + TaskListener listener = TaskListener.NULL; Launcher launcher = n.createLauncher(listener); return launcher.launch().cmds("java","-fullversion").stdout(listener).join()==0; } catch (IOException e) { diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index 6ad10d5f818e..7348f8b64568 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -76,7 +76,7 @@ import java.io.File; import java.io.IOException; import java.lang.ref.WeakReference; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -376,7 +376,7 @@ public void load() { // first try the old format File queueFile = getQueueFile(); if (queueFile.exists()) { - try (BufferedReader in = Files.newBufferedReader(Util.fileToPath(queueFile), Charset.defaultCharset())) { + try (BufferedReader in = Files.newBufferedReader(Util.fileToPath(queueFile), StandardCharsets.UTF_8)) { String line; while ((line = in.readLine()) != null) { AbstractProject j = Jenkins.getInstance().getItemByFullName(line, AbstractProject.class); diff --git a/core/src/main/java/hudson/model/Run.java b/core/src/main/java/hudson/model/Run.java index f7e11b1c657f..8fe328c73122 100644 --- a/core/src/main/java/hudson/model/Run.java +++ b/core/src/main/java/hudson/model/Run.java @@ -74,6 +74,7 @@ import java.io.RandomAccessFile; import java.io.Reader; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -267,6 +268,7 @@ private static enum State { * @since 1.257 */ protected String charset; + private transient Charset charsetInstance; /** * Keeps this log entries. @@ -551,8 +553,18 @@ public boolean isLogUpdated() { * @since 1.257 */ public final @Nonnull Charset getCharset() { - if(charset==null) return Charset.defaultCharset(); - return Charset.forName(charset); + if (charsetInstance==null) + return StandardCharsets.UTF_8; + return charsetInstance; + } + + /** + * Sets the charset in which the log file is written. + * @since TODO + */ + public final void setCharset(Charset charset) { + this.charsetInstance = charset; + this.charset = (charset==null ? null : charset.name()); } /** @@ -1111,7 +1123,7 @@ public boolean getHasArtifacts() { private int addArtifacts(@Nonnull VirtualFile dir, @Nonnull String path, @Nonnull String pathHref, - @Nonnull ArtifactList r, @Nonnull Artifact parent, int upTo) throws IOException { + @Nonnull ArtifactList r, Artifact parent, int upTo) throws IOException { VirtualFile[] kids = dir.list(); Arrays.sort(kids); @@ -1124,6 +1136,7 @@ private int addArtifacts(@Nonnull VirtualFile dir, boolean collapsed = (kids.length==1 && parent!=null); Artifact a; if (collapsed) { + assert parent!=null; // Collapse single items into parent node where possible: a = new Artifact(parent.getFileName() + '/' + child, childPath, sub.isDirectory() ? null : childHref, length, @@ -1378,12 +1391,11 @@ public String toString() { } String message = "No such file: " + logFile; - return new ByteArrayInputStream(charset != null ? message.getBytes(charset) : message.getBytes()); + return new ByteArrayInputStream(message.getBytes(getCharset())); } public @Nonnull Reader getLogReader() throws IOException { - if (charset==null) return new InputStreamReader(getLogInputStream()); - else return new InputStreamReader(getLogInputStream(),charset); + return new InputStreamReader(getLogInputStream(), getCharset()); } /** @@ -1414,7 +1426,7 @@ public void writeLogTo(long offset, @Nonnull XMLOutput out) throws IOException { */ public void writeWholeLogTo(@Nonnull OutputStream out) throws IOException, InterruptedException { long pos = 0; - AnnotatedLargeText logText; + AnnotatedLargeText> logText; logText = getLogText(); pos = logText.writeLogTo(pos, out); @@ -1431,8 +1443,8 @@ public void writeWholeLogTo(@Nonnull OutputStream out) throws IOException, Inter * Used to URL-bind {@link AnnotatedLargeText}. * @return A {@link Run} log with annotations */ - public @Nonnull AnnotatedLargeText getLogText() { - return new AnnotatedLargeText(getLogFile(),getCharset(),!isLogUpdated(),this); + public @Nonnull AnnotatedLargeText> getLogText() { + return new AnnotatedLargeText<>(getLogFile(), getCharset(), !isLogUpdated(), this); } @Override @@ -1697,15 +1709,14 @@ protected final void execute(@Nonnull RunExecution job) { long start = System.currentTimeMillis(); try { + Computer computer = Computer.currentComputer(); + if (computer != null) { + setCharset(computer.getDefaultCharset()); + } + logger = createLogger(); + listener = createBuildListener(job, logger, getCharset()); + try { - Computer computer = Computer.currentComputer(); - Charset charset = null; - if (computer != null) { - charset = computer.getDefaultCharset(); - this.charset = charset.name(); - } - logger = createLogger(); - listener = createBuildListener(job, logger, charset); listener.started(getCauses()); Authentication auth = Jenkins.getAuthentication(); @@ -1869,7 +1880,7 @@ private void createSymlink(@Nonnull TaskListener listener, @Nonnull String name, /** * Handles a fatal build problem (exception) that occurred during the build. */ - private void handleFatalBuildProblem(@Nonnull BuildListener listener, @Nonnull Throwable e) { + private void handleFatalBuildProblem(BuildListener listener, @Nonnull Throwable e) { if(listener!=null) { LOGGER.log(FINE, getDisplayName()+" failed to build",e); @@ -2127,8 +2138,7 @@ public void doBuildNumber(StaplerResponse rsp) throws IOException { * Returns the build time stamp in the body. */ public void doBuildTimestamp( StaplerRequest req, StaplerResponse rsp, @QueryParameter String format) throws IOException { - rsp.setContentType("text/plain"); - rsp.setCharacterEncoding("US-ASCII"); + rsp.setContentType("text/plain;charset=UTF-8"); rsp.setStatus(HttpServletResponse.SC_OK); DateFormat df = format==null ? DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.SHORT, Locale.ENGLISH) : @@ -2140,7 +2150,7 @@ public void doBuildTimestamp( StaplerRequest req, StaplerResponse rsp, @QueryPar * Sends out the raw console output. */ public void doConsoleText(StaplerRequest req, StaplerResponse rsp) throws IOException { - rsp.setContentType("text/plain;charset=UTF-8"); + rsp.setContentType("text/plain;charset=" + getCharset().name()); try (InputStream input = getLogInputStream(); OutputStream os = rsp.getCompressedOutputStream(req); PlainTextConsoleOutputStream out = new PlainTextConsoleOutputStream(os)) { diff --git a/core/src/main/java/hudson/model/StreamBuildListener.java b/core/src/main/java/hudson/model/StreamBuildListener.java index 226f06ba26aa..f96fdf1e2f8f 100644 --- a/core/src/main/java/hudson/model/StreamBuildListener.java +++ b/core/src/main/java/hudson/model/StreamBuildListener.java @@ -39,6 +39,15 @@ * @author Kohsuke Kawaguchi */ public class StreamBuildListener extends StreamTaskListener implements BuildListener { + + /** + * @deprecated use {@link #StreamBuildListener(java.io.OutputStream, java.nio.charset.Charset)} instead. + */ + @Deprecated + public StreamBuildListener(OutputStream out) { + super(out); + } + public StreamBuildListener(OutputStream out, Charset charset) { super(out, charset); } @@ -47,10 +56,6 @@ public StreamBuildListener(File out, Charset charset) throws IOException { super(out, charset); } - public StreamBuildListener(OutputStream w) { - super(w); - } - /** * @deprecated as of 1.349 * The caller should use {@link #StreamBuildListener(OutputStream, Charset)} to pass in diff --git a/core/src/main/java/hudson/model/TaskListener.java b/core/src/main/java/hudson/model/TaskListener.java index aeaae6643902..dc740a2d2ee1 100644 --- a/core/src/main/java/hudson/model/TaskListener.java +++ b/core/src/main/java/hudson/model/TaskListener.java @@ -89,7 +89,7 @@ default PrintWriter _error(String prefix, String msg) { // annotate(new HudsonExceptionNote()) if and when this is made to do something Charset charset = getCharset(); - return new PrintWriter(charset != null ? new OutputStreamWriter(out, charset) : new OutputStreamWriter(out), true); + return new PrintWriter(new OutputStreamWriter(out, charset), true); } /** @@ -154,5 +154,5 @@ default PrintWriter fatalError(String format, Object... args) { /** * {@link TaskListener} that discards the output. */ - TaskListener NULL = new StreamTaskListener(new NullStream()); + TaskListener NULL = new StreamTaskListener(new NullStream(), StandardCharsets.UTF_8); } diff --git a/core/src/main/java/hudson/model/TaskThread.java b/core/src/main/java/hudson/model/TaskThread.java index 73623e7b0d04..99fd662956ed 100644 --- a/core/src/main/java/hudson/model/TaskThread.java +++ b/core/src/main/java/hudson/model/TaskThread.java @@ -31,7 +31,7 @@ import java.io.IOException; import java.io.Reader; import java.lang.ref.WeakReference; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import org.kohsuke.stapler.framework.io.LargeText; import org.kohsuke.stapler.framework.io.ByteBuffer; @@ -187,8 +187,8 @@ public static ListenerAndText forMemory(TaskAction context) { ByteBuffer log = new ByteBuffer(); return new ListenerAndText( - new StreamTaskListener(log), - new AnnotatedLargeText(log,Charset.defaultCharset(),false,context) + new StreamTaskListener(log, StandardCharsets.UTF_8), + new AnnotatedLargeText(log, StandardCharsets.UTF_8, false, context) ); } @@ -197,8 +197,8 @@ public static ListenerAndText forMemory(TaskAction context) { */ public static ListenerAndText forFile(File f, TaskAction context) throws IOException { return new ListenerAndText( - new StreamTaskListener(f), - new AnnotatedLargeText(f,Charset.defaultCharset(),false,context) + new StreamTaskListener(f, StandardCharsets.UTF_8), + new AnnotatedLargeText(f, StandardCharsets.UTF_8, false, context) ); } } diff --git a/core/src/main/java/hudson/os/solaris/ZFSInstaller.java b/core/src/main/java/hudson/os/solaris/ZFSInstaller.java index a5709e8976ad..6d7dae09eb68 100644 --- a/core/src/main/java/hudson/os/solaris/ZFSInstaller.java +++ b/core/src/main/java/hudson/os/solaris/ZFSInstaller.java @@ -61,6 +61,8 @@ import java.io.IOException; import java.io.PrintStream; import java.io.Serializable; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -225,7 +227,7 @@ public void doStart(StaplerRequest req, StaplerResponse rsp, @QueryParameter Str final String datasetName; ByteArrayOutputStream log = new ByteArrayOutputStream(); - StreamTaskListener listener = new StreamTaskListener(log); + StreamTaskListener listener = new StreamTaskListener(log, StandardCharsets.UTF_8); try { datasetName = createZfsFileSystem(listener,username,password); } catch (Exception e) { @@ -285,7 +287,7 @@ public static AdministrativeMonitor init() { String migrationTarget = SystemProperties.getString(ZFSInstaller.class.getName() + ".migrate"); if(migrationTarget!=null) { ByteArrayOutputStream out = new ByteArrayOutputStream(); - StreamTaskListener listener = new StreamTaskListener(new ForkOutputStream(System.out, out)); + StreamTaskListener listener = new StreamTaskListener(new ForkOutputStream(System.out, out), Charset.defaultCharset()); try { if(migrate(listener,migrationTarget)) { // completed successfully diff --git a/core/src/main/java/hudson/slaves/AbstractCloudSlave.java b/core/src/main/java/hudson/slaves/AbstractCloudSlave.java index 93f0f93b0c9a..770d7b00b293 100644 --- a/core/src/main/java/hudson/slaves/AbstractCloudSlave.java +++ b/core/src/main/java/hudson/slaves/AbstractCloudSlave.java @@ -64,7 +64,7 @@ public void terminate() throws InterruptedException, IOException { } try { // TODO: send the output to somewhere real - _terminate(new StreamTaskListener(System.out, Charset.defaultCharset())); + _terminate(StreamTaskListener.fromStdout()); } finally { try { Jenkins.getInstance().removeNode(this); diff --git a/core/src/main/java/hudson/slaves/SlaveComputer.java b/core/src/main/java/hudson/slaves/SlaveComputer.java index 9b87bf5dec3f..37c8446c1a75 100644 --- a/core/src/main/java/hudson/slaves/SlaveComputer.java +++ b/core/src/main/java/hudson/slaves/SlaveComputer.java @@ -75,6 +75,7 @@ import java.io.OutputStream; import java.io.PrintStream; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.security.Security; import java.util.ArrayList; import java.util.Collections; @@ -96,7 +97,6 @@ public class SlaveComputer extends Computer { private volatile Channel channel; private volatile transient boolean acceptingTasks = true; - private Charset defaultCharset; private Boolean isUnix; /** * Effective {@link ComputerLauncher} that hides the details of @@ -139,7 +139,7 @@ public class SlaveComputer extends Computer { public SlaveComputer(Slave slave) { super(slave); this.log = new RewindableRotatingFileOutputStream(getLogFile(), 10); - this.taskListener = new StreamTaskListener(decorate(this.log)); + this.taskListener = new StreamTaskListener(decorate(this.log), StandardCharsets.UTF_8); assert slave.getNumExecutors()!=0 : "Computer created with 0 executors"; } @@ -513,7 +513,7 @@ public void setChannel(Channel channel, OutputStream launchLog, Channel.Listener if(this.channel!=null) throw new IllegalStateException("Already connected"); - final TaskListener taskListener = new StreamTaskListener(launchLog); + final TaskListener taskListener = new StreamTaskListener(launchLog, StandardCharsets.UTF_8); PrintStream log = taskListener.getLogger(); channel.setProperty(SlaveComputer.class, this); @@ -549,8 +549,6 @@ public void onClosed(Channel c, IOException cause) { boolean _isUnix = channel.call(new DetectOS()); log.println(_isUnix? hudson.model.Messages.Slave_UnixSlave():hudson.model.Messages.Slave_WindowsSlave()); - String defaultCharsetName = channel.call(new DetectDefaultCharset()); - Slave node = getNode(); if (node == null) { // Node has been disabled/removed during the connection throw new IOException("Node "+nodeName+" has been deleted during the channel setup"); @@ -599,7 +597,6 @@ public void onClosed(Channel c, IOException cause) { numRetryAttempt = 0; this.channel = channel; this.absoluteRemoteFs = remoteFS; - defaultCharset = Charset.forName(defaultCharsetName); synchronized (statusChangeLock) { statusChangeLock.notifyAll(); @@ -622,8 +619,9 @@ public Channel getChannel() { return channel; } + @Override public Charset getDefaultCharset() { - return defaultCharset; + return StandardCharsets.UTF_8; } public List getLogRecords() throws IOException, InterruptedException { @@ -824,12 +822,6 @@ public String call() throws IOException { } } - private static final class DetectDefaultCharset extends MasterToSlaveCallable { - public String call() throws IOException { - return Charset.defaultCharset().name(); - } - } - /** * Puts the {@link #SLAVE_LOG_HANDLER} into a separate class so that loading this class * in JVM doesn't end up loading tons of additional classes. diff --git a/core/src/main/java/hudson/tasks/Maven.java b/core/src/main/java/hudson/tasks/Maven.java index c1e4a610fe18..7b17d82caee6 100644 --- a/core/src/main/java/hudson/tasks/Maven.java +++ b/core/src/main/java/hudson/tasks/Maven.java @@ -51,8 +51,6 @@ import hudson.tools.ToolInstaller; import hudson.tools.ToolProperty; import hudson.util.ArgumentListBuilder; -import hudson.util.NullStream; -import hudson.util.StreamTaskListener; import hudson.util.VariableResolver; import hudson.util.VariableResolver.ByMap; import hudson.util.VariableResolver.Union; @@ -646,7 +644,7 @@ private File getExeFile(String execName) { */ public boolean getExists() { try { - return getExecutable(new LocalLauncher(new StreamTaskListener(new NullStream())))!=null; + return getExecutable(new LocalLauncher(TaskListener.NULL))!=null; } catch (IOException | InterruptedException e) { return false; } diff --git a/core/src/main/java/hudson/triggers/SCMTrigger.java b/core/src/main/java/hudson/triggers/SCMTrigger.java index 682ce987fb81..c9ae41c7769b 100644 --- a/core/src/main/java/hudson/triggers/SCMTrigger.java +++ b/core/src/main/java/hudson/triggers/SCMTrigger.java @@ -51,6 +51,7 @@ import java.io.OutputStream; import java.io.PrintStream; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collection; @@ -457,8 +458,8 @@ public void doPollingLog(StaplerRequest req, StaplerResponse rsp) throws IOExcep } } - public AnnotatedLargeText getPollingLogText() { - return new AnnotatedLargeText(getPollingLogFile(), Charset.defaultCharset(), true, this); + public AnnotatedLargeText getPollingLogText() { + return new AnnotatedLargeText(getPollingLogFile(), StandardCharsets.UTF_8, true, this); } /** @@ -512,7 +513,7 @@ public String getUrlName() { } public String getLog() throws IOException { - return Util.loadFile(getLogFile()); + return Util.loadFile(getLogFile(), StandardCharsets.UTF_8); } /** @@ -520,7 +521,7 @@ public String getLog() throws IOException { * @since 1.350 */ public void writeLogTo(XMLOutput out) throws IOException { - new AnnotatedLargeText(getLogFile(),Charset.defaultCharset(),true,this).writeHtmlTo(0,out.asWriter()); + new AnnotatedLargeText(getLogFile(), StandardCharsets.UTF_8, true, this).writeHtmlTo(0, out.asWriter()); } } @@ -585,7 +586,7 @@ private boolean runPolling() { try { // to make sure that the log file contains up-to-date text, // don't do buffering. - StreamTaskListener listener = new StreamTaskListener(getLogFile()); + StreamTaskListener listener = new StreamTaskListener(getLogFile(), StandardCharsets.UTF_8); try { PrintStream logger = listener.getLogger(); @@ -619,7 +620,7 @@ public void run() { // note that job().poll(listener) should also check this SCMDecisionHandler veto = SCMDecisionHandler.firstShouldPollVeto(job); if (veto != null) { - try (StreamTaskListener listener = new StreamTaskListener(getLogFile())) { + try (StreamTaskListener listener = new StreamTaskListener(getLogFile(), StandardCharsets.UTF_8)) { listener.getLogger().println( "Skipping polling on " + DateFormat.getDateTimeInstance().format(new Date()) + " due to veto from " + veto); diff --git a/core/src/main/java/hudson/util/AtomicFileWriter.java b/core/src/main/java/hudson/util/AtomicFileWriter.java index 05f752ce281e..e499192a3652 100644 --- a/core/src/main/java/hudson/util/AtomicFileWriter.java +++ b/core/src/main/java/hudson/util/AtomicFileWriter.java @@ -23,6 +23,7 @@ */ package hudson.util; +import hudson.Util; import jenkins.util.SystemProperties; import javax.annotation.Nonnull; @@ -32,9 +33,9 @@ import java.io.IOException; import java.io.Writer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.AtomicMoveNotSupportedException; import java.nio.file.Files; -import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; @@ -71,7 +72,7 @@ public class AtomicFileWriter extends Writer { * Writes with UTF-8 encoding. */ public AtomicFileWriter(File f) throws IOException { - this(f,"UTF-8"); + this(toPath(f), StandardCharsets.UTF_8); } /** @@ -84,20 +85,8 @@ public AtomicFileWriter(@Nonnull File f, @Nullable String encoding) throws IOExc this(toPath(f), encoding == null ? Charset.defaultCharset() : Charset.forName(encoding)); } - /** - * Wraps potential {@link java.nio.file.InvalidPathException} thrown by {@link File#toPath()} in an - * {@link IOException} for backward compatibility. - * - * @param file - * @return the path for that file - * @see File#toPath() - */ private static Path toPath(@Nonnull File file) throws IOException { - try { - return file.toPath(); - } catch (InvalidPathException e) { - throw new IOException(e); - } + return Util.fileToPath(file); } /** diff --git a/core/src/main/java/hudson/util/LogTaskListener.java b/core/src/main/java/hudson/util/LogTaskListener.java index bb3afc41e159..9b3d472fb983 100644 --- a/core/src/main/java/hudson/util/LogTaskListener.java +++ b/core/src/main/java/hudson/util/LogTaskListener.java @@ -31,9 +31,12 @@ import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; +import javax.annotation.Nonnull; // TODO: AbstractTaskListener is empty now, but there are dependencies on that e.g. Ruby Runtime - JENKINS-48116) // The change needs API deprecation policy or external usages cleanup. @@ -47,7 +50,7 @@ public class LogTaskListener extends AbstractTaskListener implements TaskListene private final TaskListener delegate; public LogTaskListener(Logger logger, Level level) { - delegate = new StreamTaskListener(new LogOutputStream(logger, level, new Throwable().getStackTrace()[1])); + delegate = new StreamTaskListener(new LogOutputStream(logger, level, new Throwable().getStackTrace()[1]), StandardCharsets.UTF_8); } @Override @@ -55,6 +58,11 @@ public PrintStream getLogger() { return delegate.getLogger(); } + @Override + public @Nonnull Charset getCharset() { // getCharset() in TaskListener is annotated @Nonnull + return delegate.getCharset(); + } + @Override @SuppressWarnings("rawtypes") public void annotate(ConsoleNote ann) { diff --git a/core/src/main/java/hudson/util/SecretRewriter.java b/core/src/main/java/hudson/util/SecretRewriter.java index 66967f9bd8b3..32f6f8af30b5 100644 --- a/core/src/main/java/hudson/util/SecretRewriter.java +++ b/core/src/main/java/hudson/util/SecretRewriter.java @@ -2,21 +2,20 @@ import com.trilead.ssh2.crypto.Base64; import hudson.Functions; +import hudson.Util; import hudson.model.TaskListener; -import java.io.InputStream; import java.nio.file.Files; -import java.nio.file.InvalidPathException; import javax.crypto.Cipher; import javax.crypto.SecretKey; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStreamReader; import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; import java.nio.file.LinkOption; +import java.nio.file.Path; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.util.HashSet; @@ -82,39 +81,36 @@ public boolean rewrite(File f, File backup) throws InvalidKeyException, IOExcept public boolean rewrite(File f) throws InvalidKeyException, IOException { - AtomicFileWriter w = new AtomicFileWriter(f, "UTF-8"); + Path path = Util.fileToPath(f); + AtomicFileWriter w = new AtomicFileWriter(path, StandardCharsets.UTF_8); try { boolean modified = false; // did we actually change anything? - try (PrintWriter out = new PrintWriter(new BufferedWriter(w))) { - try (InputStream fin = Files.newInputStream(f.toPath())) { - BufferedReader r = new BufferedReader(new InputStreamReader(fin, "UTF-8")); - String line; - StringBuilder buf = new StringBuilder(); - - while ((line = r.readLine()) != null) { - int copied = 0; - buf.setLength(0); - while (true) { - int sidx = line.indexOf('>', copied); - if (sidx < 0) break; - int eidx = line.indexOf('<', sidx); - if (eidx < 0) break; - - String elementText = line.substring(sidx + 1, eidx); - String replacement = tryRewrite(elementText); - if (!replacement.equals(elementText)) - modified = true; - - buf.append(line.substring(copied, sidx + 1)); - buf.append(replacement); - copied = eidx; - } - buf.append(line.substring(copied)); - out.println(buf.toString()); + try (PrintWriter out = new PrintWriter(new BufferedWriter(w)); + BufferedReader r = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { + String line; + StringBuilder buf = new StringBuilder(); + + while ((line = r.readLine()) != null) { + int copied = 0; + buf.setLength(0); + while (true) { + int sidx = line.indexOf('>', copied); + if (sidx < 0) break; + int eidx = line.indexOf('<', sidx); + if (eidx < 0) break; + + String elementText = line.substring(sidx + 1, eidx); + String replacement = tryRewrite(elementText); + if (!replacement.equals(elementText)) + modified = true; + + buf.append(line.substring(copied, sidx + 1)); + buf.append(replacement); + copied = eidx; } - } catch (InvalidPathException e) { - throw new IOException(e); + buf.append(line.substring(copied)); + out.println(buf.toString()); } } @@ -143,8 +139,8 @@ public synchronized int rewriteRecursive(File dir, TaskListener listener) throws private int rewriteRecursive(File dir, String relative, TaskListener listener) throws InvalidKeyException { String canonical; try { - canonical = dir.toPath().toRealPath(new LinkOption[0]).toString(); - } catch (IOException | InvalidPathException e) { + canonical = Util.fileToPath(dir).toRealPath(new LinkOption[0]).toString(); + } catch (IOException e) { canonical = dir.getAbsolutePath(); // } if (!callstack.add(canonical)) { diff --git a/core/src/main/java/hudson/util/StreamTaskListener.java b/core/src/main/java/hudson/util/StreamTaskListener.java index bd2b6dc87e81..223936e703fe 100644 --- a/core/src/main/java/hudson/util/StreamTaskListener.java +++ b/core/src/main/java/hudson/util/StreamTaskListener.java @@ -24,6 +24,7 @@ package hudson.util; import hudson.CloseProofOutputStream; +import hudson.Util; import hudson.model.TaskListener; import hudson.remoting.RemoteOutputStream; import java.io.Closeable; @@ -36,12 +37,13 @@ import java.io.UnsupportedEncodingException; import java.io.Writer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.logging.Level; import java.util.logging.Logger; +import javax.annotation.Nonnull; import org.kohsuke.stapler.framework.io.WriterOutputStream; // TODO: AbstractTaskListener is empty now, but there are dependencies on that e.g. Ruby Runtime - JENKINS-48116) @@ -57,7 +59,7 @@ */ public class StreamTaskListener extends AbstractTaskListener implements TaskListener, Closeable { private PrintStream out; - private Charset charset; + private @Nonnull Charset charset; /** * @deprecated as of 1.349 @@ -70,16 +72,22 @@ public StreamTaskListener(PrintStream out) { this(out,null); } + /** + * @deprecated use {@link #StreamTaskListener(java.io.OutputStream, java.nio.charset.Charset)} instead. + */ + @Deprecated public StreamTaskListener(OutputStream out) { this(out,null); } public StreamTaskListener(OutputStream out, Charset charset) { try { - if (charset == null) - this.out = (out instanceof PrintStream) ? (PrintStream)out : new PrintStream(out, false); - else + if (charset == null) { + charset = Charset.defaultCharset(); + this.out = (out instanceof PrintStream) ? (PrintStream)out : new PrintStream(out, false, charset.name()); + } else { this.out = new PrintStream(out, false, charset.name()); + } this.charset = charset; } catch (UnsupportedEncodingException e) { // it's not very pretty to do this, but otherwise we'd have to touch too many call sites. @@ -87,6 +95,10 @@ public StreamTaskListener(OutputStream out, Charset charset) { } } + /** + * @deprecated use {@link #StreamTaskListener(java.io.File, java.nio.charset.Charset)} instead. + */ + @Deprecated public StreamTaskListener(File out) throws IOException { this(out,null); } @@ -99,11 +111,7 @@ public StreamTaskListener(File out, Charset charset) throws IOException { } private static Path asPath(File out) throws IOException { - try { - return out.toPath(); - } catch (InvalidPathException e) { - throw new IOException(e); - } + return Util.fileToPath(out); } /** @@ -128,7 +136,10 @@ public StreamTaskListener(File out, boolean append, Charset charset) throws IOEx } public StreamTaskListener(Writer w) throws IOException { - this(new WriterOutputStream(w)); + // It's not possible to retrieve the charset that the writer is using; + // however, for all uses of this constructor, the writer is an instance + // of StringWriter, so it's okay to assume UTF-8. + this(new WriterOutputStream(w), StandardCharsets.UTF_8); } /** @@ -141,11 +152,11 @@ public StreamTaskListener() throws IOException { } public static StreamTaskListener fromStdout() { - return new StreamTaskListener(System.out,Charset.defaultCharset()); + return new StreamTaskListener(System.out); } public static StreamTaskListener fromStderr() { - return new StreamTaskListener(System.err,Charset.defaultCharset()); + return new StreamTaskListener(System.err); } @Override @@ -154,24 +165,25 @@ public PrintStream getLogger() { } @Override - public Charset getCharset() { + public @Nonnull Charset getCharset() { // getCharset() in TaskListener is annotated @Nonnull return charset; } private void writeObject(ObjectOutputStream out) throws IOException { out.writeObject(new RemoteOutputStream(new CloseProofOutputStream(this.out))); - out.writeObject(charset==null? null : charset.name()); + out.writeObject(charset.name()); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { out = new PrintStream((OutputStream)in.readObject(),true); String name = (String)in.readObject(); - charset = name==null ? null : Charset.forName(name); + charset = name==null ? Charset.defaultCharset() : Charset.forName(name); } @Override public void close() throws IOException { - out.close(); + if (out != System.out && out != System.err) + out.close(); } /** diff --git a/core/src/main/java/hudson/util/TextFile.java b/core/src/main/java/hudson/util/TextFile.java index 0ac1326ce7e7..115e5f484bb5 100644 --- a/core/src/main/java/hudson/util/TextFile.java +++ b/core/src/main/java/hudson/util/TextFile.java @@ -194,7 +194,9 @@ public void write(String text) throws IOException { /** * Uses the platform default encoding. + * @deprecated use {@link #fastTail(int, java.nio.charset.Charset)} instead. */ + @Deprecated public @Nonnull String fastTail(int numChars) throws IOException { return fastTail(numChars,Charset.defaultCharset()); } diff --git a/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java b/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java index 4e621ab53b24..dcc28fc45e3e 100644 --- a/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java +++ b/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java @@ -12,7 +12,7 @@ import java.io.File; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nonnull; @@ -46,9 +46,9 @@ public boolean isFixingActive() { /** * Used to URL-bind {@link AnnotatedLargeText}. */ - public AnnotatedLargeText getLogText() { + public AnnotatedLargeText getLogText() { return new AnnotatedLargeText( - getLogFile(), Charset.defaultCharset(), + getLogFile(), StandardCharsets.UTF_8, !isFixingActive(), this); } @@ -100,7 +100,7 @@ public void run() { ACL.impersonate(ACL.SYSTEM); StreamTaskListener listener = null; try { - listener = new StreamTaskListener(getLogFile()); + listener = new StreamTaskListener(getLogFile(), StandardCharsets.UTF_8); try { doRun(listener); } finally { diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 5de956996b79..2c2e3983c290 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -252,6 +252,7 @@ import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Arrays; @@ -4810,7 +4811,7 @@ public VirtualChannel getChannel() { @Override public Charset getDefaultCharset() { - return Charset.defaultCharset(); + return StandardCharsets.UTF_8; } public List getLogRecords() throws IOException, InterruptedException { diff --git a/core/src/main/java/jenkins/util/BuildListenerAdapter.java b/core/src/main/java/jenkins/util/BuildListenerAdapter.java index 341aeece866e..70245e3ce169 100644 --- a/core/src/main/java/jenkins/util/BuildListenerAdapter.java +++ b/core/src/main/java/jenkins/util/BuildListenerAdapter.java @@ -30,6 +30,8 @@ import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; +import java.nio.charset.Charset; +import javax.annotation.Nonnull; /** * Wraps a {@link TaskListener} as a {@link BuildListener} for compatibility with APIs which historically expected the latter. @@ -48,6 +50,10 @@ public BuildListenerAdapter(TaskListener delegate) { return delegate.getLogger(); } + @Override public @Nonnull Charset getCharset() { // getCharset() in TaskListener is annotated @Nonnull + return delegate.getCharset(); + } + @SuppressWarnings("rawtypes") @Override public void annotate(ConsoleNote ann) throws IOException { delegate.annotate(ann); diff --git a/core/src/test/java/hudson/FilePathTest.java b/core/src/test/java/hudson/FilePathTest.java index 57815f661831..4c6f2e47273b 100644 --- a/core/src/test/java/hudson/FilePathTest.java +++ b/core/src/test/java/hudson/FilePathTest.java @@ -41,6 +41,7 @@ import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -659,7 +660,7 @@ public void testValidateCaseSensitivity() throws Exception { when(con.getInputStream()).thenThrow(new ConnectException()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); String message = "going ahead"; - assertFalse(d.installIfNecessaryFrom(url, new StreamTaskListener(baos), message)); + assertFalse(d.installIfNecessaryFrom(url, new StreamTaskListener(baos, StandardCharsets.UTF_8), message)); verify(con).setIfModifiedSince(123000); String log = baos.toString(); assertFalse(log, log.contains(message)); @@ -685,7 +686,7 @@ public void testValidateCaseSensitivity() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); String message = "going ahead"; - assertTrue(d.installIfNecessaryFrom(url, new StreamTaskListener(baos), message)); + assertTrue(d.installIfNecessaryFrom(url, new StreamTaskListener(baos, StandardCharsets.UTF_8), message)); } private URL someUrlToZipFile(final URLConnection con) throws IOException { diff --git a/core/src/test/java/hudson/LauncherTest.java b/core/src/test/java/hudson/LauncherTest.java index 4df308b41d17..02c40761f06e 100644 --- a/core/src/test/java/hudson/LauncherTest.java +++ b/core/src/test/java/hudson/LauncherTest.java @@ -31,6 +31,7 @@ import hudson.util.StreamTaskListener; import java.io.ByteArrayOutputStream; import java.io.File; +import java.nio.charset.StandardCharsets; import jenkins.security.MasterToSlaveCallable; import org.apache.commons.io.FileUtils; import static org.junit.Assert.*; @@ -85,7 +86,7 @@ public Object call() throws RuntimeException { @Issue("JENKINS-15733") @Test public void decorateByEnv() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - TaskListener l = new StreamBuildListener(baos); + TaskListener l = new StreamBuildListener(baos, StandardCharsets.UTF_8); Launcher base = new Launcher.LocalLauncher(l); EnvVars env = new EnvVars("key1", "val1"); Launcher decorated = base.decorateByEnv(env); @@ -98,7 +99,7 @@ public Object call() throws RuntimeException { @Issue("JENKINS-18368") @Test public void decoratedByEnvMaintainsIsUnix() throws Exception { ByteArrayOutputStream output = new ByteArrayOutputStream(); - TaskListener listener = new StreamBuildListener(output); + TaskListener listener = new StreamBuildListener(output, StandardCharsets.UTF_8); Launcher remoteLauncher = new Launcher.RemoteLauncher(listener, FilePath.localChannel, false); Launcher decorated = remoteLauncher.decorateByEnv(new EnvVars()); assertEquals(false, decorated.isUnix()); @@ -110,7 +111,7 @@ public Object call() throws RuntimeException { @Issue("JENKINS-18368") @Test public void decoratedByPrefixMaintainsIsUnix() throws Exception { ByteArrayOutputStream output = new ByteArrayOutputStream(); - TaskListener listener = new StreamBuildListener(output); + TaskListener listener = new StreamBuildListener(output, StandardCharsets.UTF_8); Launcher remoteLauncher = new Launcher.RemoteLauncher(listener, FilePath.localChannel, false); Launcher decorated = remoteLauncher.decorateByPrefix("test"); assertEquals(false, decorated.isUnix()); diff --git a/core/src/test/java/hudson/UtilTest.java b/core/src/test/java/hudson/UtilTest.java index f1cf6140551f..ede4b998b251 100644 --- a/core/src/test/java/hudson/UtilTest.java +++ b/core/src/test/java/hudson/UtilTest.java @@ -36,6 +36,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.nio.file.FileSystemException; import java.nio.file.Files; import java.nio.file.Path; @@ -60,7 +61,6 @@ import hudson.util.StreamTaskListener; import org.junit.Rule; -import org.junit.internal.AssumptionViolatedException; import org.junit.rules.TemporaryFolder; import com.google.common.collect.Lists; @@ -192,7 +192,7 @@ public void testSymlink() throws Exception { Assume.assumeTrue(!Functions.isWindows()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - StreamTaskListener l = new StreamTaskListener(baos); + StreamTaskListener l = new StreamTaskListener(baos, StandardCharsets.UTF_8); File d = tmp.getRoot(); try { new FilePath(new File(d, "a")).touch(0); @@ -240,7 +240,7 @@ public void testIsSymlink() throws IOException, InterruptedException { Assume.assumeTrue(!Functions.isWindows()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - StreamTaskListener l = new StreamTaskListener(baos); + StreamTaskListener l = new StreamTaskListener(baos, StandardCharsets.UTF_8); File d = tmp.getRoot(); try { new FilePath(new File(d, "original")).touch(0); diff --git a/core/src/test/java/hudson/util/AtomicFileWriterTest.java b/core/src/test/java/hudson/util/AtomicFileWriterTest.java index 51bd205cb4a4..9190483d6918 100644 --- a/core/src/test/java/hudson/util/AtomicFileWriterTest.java +++ b/core/src/test/java/hudson/util/AtomicFileWriterTest.java @@ -1,7 +1,6 @@ package hudson.util; import org.apache.commons.io.FileUtils; -import org.hamcrest.core.StringContains; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -9,7 +8,7 @@ import java.io.File; 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.nio.file.Paths; @@ -33,7 +32,7 @@ public class AtomicFileWriterTest { public void setUp() throws IOException { af = tmp.newFile(); FileUtils.writeStringToFile(af, PREVIOUS); - afw = new AtomicFileWriter(af.toPath(), Charset.defaultCharset()); + afw = new AtomicFileWriter(af.toPath(), StandardCharsets.UTF_8); } @Test @@ -46,7 +45,7 @@ public void symlinkToDirectory() throws Exception { final Path childFileInSymlinkToDir = Paths.get(zeSymlink.toString(), "childFileInSymlinkToDir"); - new AtomicFileWriter(childFileInSymlinkToDir, Charset.forName("UTF-8")); + new AtomicFileWriter(childFileInSymlinkToDir, StandardCharsets.UTF_8); } @Test @@ -117,7 +116,7 @@ public void badPath() throws Exception { assertFalse(parentExistsAndIsAFile.exists()); try { - new AtomicFileWriter(parentExistsAndIsAFile.toPath(), Charset.forName("UTF-8")); + new AtomicFileWriter(parentExistsAndIsAFile.toPath(), StandardCharsets.UTF_8); fail("Expected a failure"); } catch (IOException e) { assertThat(e.getMessage(), diff --git a/core/src/test/java/hudson/util/TextFileTest.java b/core/src/test/java/hudson/util/TextFileTest.java index cb689a080fe5..e03043d498a9 100644 --- a/core/src/test/java/hudson/util/TextFileTest.java +++ b/core/src/test/java/hudson/util/TextFileTest.java @@ -4,6 +4,7 @@ import java.io.FileOutputStream; import java.io.OutputStream; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import static org.junit.Assert.*; @@ -44,7 +45,7 @@ public void tail() throws Exception { TextFile t = new TextFile(f); String tailStr = "la, vitae interdum quam rutrum id." + System.lineSeparator(); assertEquals(34 + System.lineSeparator().length(), tailStr.length()); - assertEquals(tailStr, t.fastTail(tailStr.length())); + assertEquals(tailStr, t.fastTail(tailStr.length(), StandardCharsets.UTF_8)); } @Test @@ -53,7 +54,7 @@ public void shortTail() throws Exception { FileUtils.write(f, "hello"); TextFile t = new TextFile(f); - assertEquals("hello", t.fastTail(35)); + assertEquals("hello", t.fastTail(35, StandardCharsets.UTF_8)); } /** diff --git a/core/src/test/java/jenkins/model/RunIdMigratorTest.java b/core/src/test/java/jenkins/model/RunIdMigratorTest.java index 71a3e47832b8..784b87dc2268 100644 --- a/core/src/test/java/jenkins/model/RunIdMigratorTest.java +++ b/core/src/test/java/jenkins/model/RunIdMigratorTest.java @@ -29,7 +29,6 @@ import hudson.util.StreamTaskListener; import java.io.File; import java.io.IOException; -import java.nio.charset.Charset; import java.util.Map; import java.util.TimeZone; import java.util.TreeMap; @@ -165,7 +164,7 @@ private void write(String file, String text) throws Exception { } private void link(String symlink, String dest) throws Exception { - Util.createSymlink(dir, dest, symlink, new StreamTaskListener(System.out, Charset.defaultCharset())); + Util.createSymlink(dir, dest, symlink, StreamTaskListener.fromStdout()); } private String summarize() throws Exception { diff --git a/test/src/test/java/hudson/ProcTest.java b/test/src/test/java/hudson/ProcTest.java index 4f7133ccff93..8e0be128bb47 100644 --- a/test/src/test/java/hudson/ProcTest.java +++ b/test/src/test/java/hudson/ProcTest.java @@ -99,14 +99,14 @@ public Void call() throws IOException { @Test public void ioPumpingWithLocalLaunch() throws Exception { assumeFalse("TODO: Implement this test for Windows", Functions.isWindows()); - doIoPumpingTest(new LocalLauncher(new StreamTaskListener(System.out, Charset.defaultCharset()))); + doIoPumpingTest(new LocalLauncher(StreamTaskListener.fromStdout())); } @Test public void ioPumpingWithRemoteLaunch() throws Exception { assumeFalse("TODO: Implement this test for Windows", Functions.isWindows()); doIoPumpingTest(new RemoteLauncher( - new StreamTaskListener(System.out, Charset.defaultCharset()), + StreamTaskListener.fromStdout(), createSlaveChannel(), true)); } diff --git a/test/src/test/java/hudson/cli/ReloadConfigurationCommandTest.java b/test/src/test/java/hudson/cli/ReloadConfigurationCommandTest.java index 1f4094dfdf45..e2a8640ce654 100644 --- a/test/src/test/java/hudson/cli/ReloadConfigurationCommandTest.java +++ b/test/src/test/java/hudson/cli/ReloadConfigurationCommandTest.java @@ -38,8 +38,10 @@ import org.jvnet.hudson.test.JenkinsRule; import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import static hudson.cli.CLICommandInvoker.Matcher.failedWith; import static hudson.cli.CLICommandInvoker.Matcher.hasNoStandardOutput; @@ -182,13 +184,13 @@ private void replace(String path, String search, String replace) { File configFile = new File(j.jenkins.getRootDir(), path); try { - String oldConfig = Util.loadFile(configFile); + String oldConfig = Util.loadFile(configFile, StandardCharsets.UTF_8); String newConfig = oldConfig.replaceAll(search, replace); - FileWriter fw = new FileWriter(configFile); - fw.write(newConfig); - fw.close(); + try (Writer w = Files.newBufferedWriter(Util.fileToPath(configFile), StandardCharsets.UTF_8)) { + w.write(newConfig); + } } catch (IOException ex) { throw new AssertionError(ex); } diff --git a/test/src/test/java/hudson/console/AnnotatedLargeTextTest.java b/test/src/test/java/hudson/console/AnnotatedLargeTextTest.java index 43ca1aee547a..33c078fef247 100644 --- a/test/src/test/java/hudson/console/AnnotatedLargeTextTest.java +++ b/test/src/test/java/hudson/console/AnnotatedLargeTextTest.java @@ -29,8 +29,8 @@ import java.io.IOException; import java.io.PrintStream; import java.io.StringWriter; +import java.nio.charset.StandardCharsets; import java.util.logging.Level; -import org.apache.commons.io.Charsets; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.junit.ClassRule; @@ -58,7 +58,7 @@ public void smokes() throws Exception { ps.print("Some text.\n"); ps.print("Go back to " + TestNote.encodeTo("/root", "your home") + ".\n"); ps.print("More text.\n"); - AnnotatedLargeText text = new AnnotatedLargeText<>(buf, Charsets.UTF_8, true, null); + AnnotatedLargeText text = new AnnotatedLargeText<>(buf, StandardCharsets.UTF_8, true, null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); text.writeLogTo(0, baos); assertEquals("Some text.\nGo back to your home.\nMore text.\n", baos.toString()); @@ -72,7 +72,7 @@ public void smokes() throws Exception { public void oldDeserialization() throws Exception { ByteBuffer buf = new ByteBuffer(); buf.write(("hello" + ConsoleNote.PREAMBLE_STR + "AAAAwR+LCAAAAAAAAP9dzLEOwVAUxvHThtiNprYxsGiMQhiwNSIhMR/tSZXr3Lr3oJPwPt7FM5hM3gFh8i3/5Bt+1yeUrYH6ap9Yza1Ys9WKWuMiR05wqWhEgpmyEy306Jxvwb19ccGNoBJjLplmgWq0xgOGCjkNZ2IyTrsRlFayVTs4gVMYqP3pw28/JnznuABF/rYWyIyeJfLQe1vxZiDQ7NnYZLn0UZGRRjA9MiV+0OyFv3+utadQyH8B+aJxVM4AAAA=" + ConsoleNote.POSTAMBLE_STR + "there\n").getBytes()); - AnnotatedLargeText text = new AnnotatedLargeText<>(buf, Charsets.UTF_8, true, null); + AnnotatedLargeText text = new AnnotatedLargeText<>(buf, StandardCharsets.UTF_8, true, null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); text.writeLogTo(0, baos); assertEquals("hellothere\n", baos.toString()); @@ -95,7 +95,7 @@ public void oldDeserialization() throws Exception { public void badMac() throws Exception { ByteBuffer buf = new ByteBuffer(); buf.write(("Go back to " + ConsoleNote.PREAMBLE_STR + "////4ByIhqPpAc43AbrEtyDUDc1/UEOXsoY6LeoHSeSlb1d7AAAAlR+LCAAAAAAAAP9b85aBtbiIQS+jNKU4P08vOT+vOD8nVc8xLy+/JLEkNcUnsSg9NSS1oiQktbhEBUT45ZekCpys9xWo8J3KxMDkycCWk5qXXpLhw8BcWpRTwiDkk5VYlqifk5iXrh9cUpSZl25dUcQghWaBM4QGGcYAAYxMDAwVBUAGZwkDq35Rfn4JABmN28qcAAAA" + ConsoleNote.POSTAMBLE_STR + "your home.\n").getBytes()); - AnnotatedLargeText text = new AnnotatedLargeText<>(buf, Charsets.UTF_8, true, null); + AnnotatedLargeText text = new AnnotatedLargeText<>(buf, StandardCharsets.UTF_8, true, null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); text.writeLogTo(0, baos); assertEquals("Go back to your home.\n", baos.toString()); diff --git a/test/src/test/java/hudson/model/ProjectTest.java b/test/src/test/java/hudson/model/ProjectTest.java index f966f4e56b96..8228fef42da5 100644 --- a/test/src/test/java/hudson/model/ProjectTest.java +++ b/test/src/test/java/hudson/model/ProjectTest.java @@ -32,12 +32,9 @@ import hudson.security.HudsonPrivateSecurityRealm; import hudson.security.GlobalMatrixAuthorizationStrategy; -import java.io.Closeable; -import java.net.HttpURLConnection; import java.net.URL; import java.util.Collections; -import hudson.util.Scrambler; import org.jvnet.hudson.reactor.ReactorException; import org.jvnet.hudson.test.FakeChangeLogSCM; import hudson.scm.SCMRevisionState; @@ -76,7 +73,7 @@ import java.util.List; import java.util.ArrayList; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Collection; import org.junit.Rule; import org.junit.Test; @@ -444,7 +441,7 @@ public void testCheckout() throws IOException, Exception{ assertNotNull(ws); FilePath path = slave.toComputer().getWorkspaceList().allocate(ws, build).path; build.setWorkspace(path); - BuildListener listener = new StreamBuildListener(BuildListener.NULL.getLogger(), Charset.defaultCharset()); + BuildListener listener = new StreamBuildListener(BuildListener.NULL.getLogger(), StandardCharsets.UTF_8); assertTrue("Project with null smc should perform checkout without problems.", p.checkout(build, new RemoteLauncher(listener, slave.getChannel(), true), listener, new File(build.getRootDir(),"changelog.xml"))); p.setScm(scm); assertTrue("Project should perform checkout without problems.",p.checkout(build, new RemoteLauncher(listener, slave.getChannel(), true), listener, new File(build.getRootDir(),"changelog.xml"))); diff --git a/test/src/test/java/hudson/tools/InstallerTranslatorTest.java b/test/src/test/java/hudson/tools/InstallerTranslatorTest.java index dc0057fa001b..d4e4b0b5d108 100644 --- a/test/src/test/java/hudson/tools/InstallerTranslatorTest.java +++ b/test/src/test/java/hudson/tools/InstallerTranslatorTest.java @@ -58,7 +58,7 @@ public class InstallerTranslatorTest { r.jenkins.getJDKs().add(jdk); FreeStyleProject p = r.createFreeStyleProject(); p.setJDK(jdk); - StreamTaskListener listener = new StreamTaskListener(System.out, Charset.defaultCharset()); + StreamTaskListener listener = StreamTaskListener.fromStdout(); String javaHomeProp = "JAVA_HOME"; // cf. JDK.buildEnvVars assertEquals(globalDefaultLocation, p.getEnvironment(slave, listener).get(javaHomeProp)); String slaveDefaultLocation = "/System/JDK"; diff --git a/test/src/test/java/hudson/util/ArgumentListBuilder2Test.java b/test/src/test/java/hudson/util/ArgumentListBuilder2Test.java index 3ba9183fff19..f2de532f2ab3 100644 --- a/test/src/test/java/hudson/util/ArgumentListBuilder2Test.java +++ b/test/src/test/java/hudson/util/ArgumentListBuilder2Test.java @@ -46,7 +46,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.StringWriter; -import java.net.URL; +import java.nio.charset.StandardCharsets; /** * @author Kohsuke Kawaguchi @@ -104,7 +104,7 @@ public String echoArgs(String... arguments) throws Exception { .toWindowsCommand(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - final StreamTaskListener listener = new StreamTaskListener(out); + final StreamTaskListener listener = new StreamTaskListener(out, StandardCharsets.UTF_8); Proc p = new LocalLauncher(listener) .launch() .stderr(System.err) diff --git a/test/src/test/java/jenkins/model/JenkinsReloadConfigurationTest.java b/test/src/test/java/jenkins/model/JenkinsReloadConfigurationTest.java index 89016dae7083..2172720e3979 100644 --- a/test/src/test/java/jenkins/model/JenkinsReloadConfigurationTest.java +++ b/test/src/test/java/jenkins/model/JenkinsReloadConfigurationTest.java @@ -10,8 +10,10 @@ import hudson.tasks.Mailer; import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import org.junit.Rule; import org.junit.Test; @@ -127,13 +129,13 @@ private void replace(String path, String search, String replace) { File configFile = new File(j.jenkins.getRootDir(), path); try { - String oldConfig = Util.loadFile(configFile); + String oldConfig = Util.loadFile(configFile, StandardCharsets.UTF_8); String newConfig = oldConfig.replaceAll(search, replace); - FileWriter fw = new FileWriter(configFile); - fw.write(newConfig); - fw.close(); + try (Writer w = Files.newBufferedWriter(Util.fileToPath(configFile), StandardCharsets.UTF_8)) { + w.write(newConfig); + } } catch (IOException ex) { throw new AssertionError(ex); } From e22276be6f1360849bafba95264d8497d0c59b9c Mon Sep 17 00:00:00 2001 From: Daniel Trebbien Date: Sat, 20 Jan 2018 17:52:49 -0800 Subject: [PATCH 2/2] Pass StandardCharsets.UTF_8 to the WriterOutputStream constructor --- core/src/main/java/hudson/util/StreamTaskListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/util/StreamTaskListener.java b/core/src/main/java/hudson/util/StreamTaskListener.java index 223936e703fe..65ce9eb963b6 100644 --- a/core/src/main/java/hudson/util/StreamTaskListener.java +++ b/core/src/main/java/hudson/util/StreamTaskListener.java @@ -139,7 +139,7 @@ public StreamTaskListener(Writer w) throws IOException { // It's not possible to retrieve the charset that the writer is using; // however, for all uses of this constructor, the writer is an instance // of StringWriter, so it's okay to assume UTF-8. - this(new WriterOutputStream(w), StandardCharsets.UTF_8); + this(new WriterOutputStream(w, StandardCharsets.UTF_8), StandardCharsets.UTF_8); } /**