diff --git a/core/src/main/java/hudson/Util.java b/core/src/main/java/hudson/Util.java index ad394e99d3..605a87bef2 100644 --- a/core/src/main/java/hudson/Util.java +++ b/core/src/main/java/hudson/Util.java @@ -20,7 +20,6 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; -import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -28,6 +27,8 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.io.PrintStream; +import java.io.InputStreamReader; +import java.io.FileInputStream; import java.net.InetAddress; import java.net.UnknownHostException; import java.net.URI; @@ -50,6 +51,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.nio.charset.Charset; /** * Various utility methods that don't have more proper home. @@ -131,12 +133,16 @@ public class Util { * Loads the contents of a file into a string. */ public static String loadFile(File logfile) throws IOException { + return loadFile(logfile, Charset.defaultCharset()); + } + + public static String loadFile(File logfile,Charset charset) throws IOException { if(!logfile.exists()) return ""; StringBuffer str = new StringBuffer((int)logfile.length()); - BufferedReader r = new BufferedReader(new FileReader(logfile)); + BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(logfile),charset)); char[] buf = new char[1024]; int len; while((len=r.read(buf,0,buf.length))>0) diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index 64dbebbfe3..0030cc0784 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -28,6 +28,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.LogRecord; +import java.nio.charset.Charset; import javax.servlet.ServletException; @@ -116,6 +117,14 @@ public abstract class Computer extends AbstractModelObject implements AccessCont */ public abstract VirtualChannel getChannel(); + /** + * Gets the default charset of this computer. + * + * @return + * never null when {@link #isOffline()}==false. + */ + public abstract Charset getDefaultCharset(); + /** * Gets the logs recorded by this slave. */ diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index 08a96eafbe..7bc7217a3d 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -140,6 +140,7 @@ import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; import java.util.regex.Pattern; +import java.nio.charset.Charset; /** * Root object of the system. @@ -2556,6 +2557,11 @@ public final class Hudson extends View implements ItemGroup, Node, return localChannel; } + @Override + public Charset getDefaultCharset() { + return Charset.defaultCharset(); + } + public List getLogRecords() throws IOException, InterruptedException { return logRecords; } diff --git a/core/src/main/java/hudson/model/Run.java b/core/src/main/java/hudson/model/Run.java index 086b985237..0f0880f2df 100644 --- a/core/src/main/java/hudson/model/Run.java +++ b/core/src/main/java/hudson/model/Run.java @@ -38,11 +38,12 @@ import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; -import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.io.Writer; +import java.io.InputStreamReader; +import java.io.FileInputStream; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -60,6 +61,7 @@ import java.util.Map; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; +import java.nio.charset.Charset; /** * A particular execution of {@link Job}. @@ -143,6 +145,16 @@ public abstract class Run ,RunT extends Run,RunT extends Run,RunT extends Run,RunT extends Run,RunT extends Run getLog(int maxLines) throws IOException { int lineCount = 0; List logLines = new LinkedList(); - BufferedReader reader = new BufferedReader(new FileReader(getLogFile())); + BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(getLogFile()),getCharset())); try { for (String line = reader.readLine(); line != null; line = reader.readLine()) { logLines.add(line); diff --git a/core/src/main/java/hudson/model/StreamBuildListener.java b/core/src/main/java/hudson/model/StreamBuildListener.java index b5a512245b..d89ed49672 100644 --- a/core/src/main/java/hudson/model/StreamBuildListener.java +++ b/core/src/main/java/hudson/model/StreamBuildListener.java @@ -10,6 +10,9 @@ import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.Serializable; +import java.io.BufferedWriter; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; /** * {@link BuildListener} that writes to an {@link OutputStream}. @@ -28,10 +31,15 @@ public class StreamBuildListener implements BuildListener, Serializable { } public StreamBuildListener(PrintStream w) { + this(w,null); + } + + public StreamBuildListener(PrintStream w, Charset charset) { this.ps = w; // unless we auto-flash, PrintStream will use BufferedOutputStream internally, // and break ordering - this.w = new PrintWriter(w,true); + this.w = new PrintWriter(new BufferedWriter( + charset==null ? new OutputStreamWriter(w) : new OutputStreamWriter(w,charset)), true); } public void started() { diff --git a/core/src/main/java/hudson/slaves/SlaveComputer.java b/core/src/main/java/hudson/slaves/SlaveComputer.java index db3fd0e957..bdb1a9cade 100644 --- a/core/src/main/java/hudson/slaves/SlaveComputer.java +++ b/core/src/main/java/hudson/slaves/SlaveComputer.java @@ -26,6 +26,7 @@ import java.util.logging.Logger; import java.util.List; import java.util.Collections; import java.util.ArrayList; +import java.nio.charset.Charset; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -41,6 +42,7 @@ import javax.servlet.http.HttpServletResponse; public final class SlaveComputer extends Computer { private volatile Channel channel; private volatile transient boolean acceptingTasks = true; + private Charset defaultCharset; private Boolean isUnix; private ComputerLauncher launcher; @@ -193,6 +195,8 @@ public final class SlaveComputer extends Computer { 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()); + String remoteFs = getNode().getRemoteFS(); if(_isUnix && !remoteFs.contains("/") && remoteFs.contains("\\")) log.println("WARNING: "+remoteFs+" looks suspiciously like Windows path. Maybe you meant "+remoteFs.replace('\\','/')+"?"); @@ -224,6 +228,7 @@ public final class SlaveComputer extends Computer { isUnix = _isUnix; numRetryAttempt = 0; this.channel = channel; + defaultCharset = Charset.forName(defaultCharsetName); } for (ComputerListener cl : Hudson.getInstance().getComputerListeners()) cl.onOnline(this); @@ -235,6 +240,10 @@ public final class SlaveComputer extends Computer { return channel; } + public Charset getDefaultCharset() { + return defaultCharset; + } + public List getLogRecords() throws IOException, InterruptedException { if(channel==null) return Collections.emptyList(); @@ -345,6 +354,12 @@ public final class SlaveComputer extends Computer { } } + private static final class DetectDefaultCharset implements Callable { + public String call() throws IOException { + return Charset.defaultCharset().name(); + } + } + /** * This field is used on each slave node to record log records on the slave. */