lvxianchao / notes

狗屁不通瞎写的博客
https://coderlxc.com
1 stars 0 forks source link

解决 Jenkins 因字符集乱码导致构建失败(java.nio.charset.UnmappableCharacterException: Input length = 1) #58

Open lvxianchao opened 1 year ago

lvxianchao commented 1 year ago

解决 Jenkins 因字符集乱码导致构建失败

操作系统: CentOS 7 Jenkins 安装方式: 官方文档 yum 安装

背景

安装完了 Jenkins 以后,我随便去创建了一个自由风格的项目测试一下,然后就构建失败了,漫长的折腾之路开始了。

我在构建的执行 Shell 里输入如下:

echo "构建 - 开始"
whoami
echo "构建 - 结束"

报错

结果构建失败,查看控制台输出发现如下文:

Checking out Revision d147f439ea5cf57e460e48886db15a3971828499 (refs/remotes/origin/main)
 > git config core.sparsecheckout # timeout=10
 > git checkout -f d147f439ea5cf57e460e48886db15a3971828499 # timeout=10
Commit message: "???? 01"
 > git rev-list --no-walk d147f439ea5cf57e460e48886db15a3971828499 # timeout=10
FATAL: Unable to produce a script file
java.nio.charset.UnmappableCharacterException: Input length = 1
    at java.base/java.nio.charset.CoderResult.throwException(CoderResult.java:275)
    at java.base/sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:307)
    at java.base/sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:282)
    at java.base/sun.nio.cs.StreamEncoder.write(StreamEncoder.java:132)
    at java.base/java.io.OutputStreamWriter.write(OutputStreamWriter.java:205)
    at java.base/java.io.BufferedWriter.flushBuffer(BufferedWriter.java:120)
    at java.base/java.io.BufferedWriter.close(BufferedWriter.java:268)
    at hudson.FilePath$CreateTextTempFile.invoke(FilePath.java:1658)
    at hudson.FilePath$CreateTextTempFile.invoke(FilePath.java:1628)
    at hudson.FilePath.act(FilePath.java:1198)
    at hudson.FilePath.act(FilePath.java:1181)
    at hudson.FilePath.createTextTempFile(FilePath.java:1622)
Caused: java.io.IOException: Failed to create a temp file on /var/lib/jenkins/workspace/XXXXXXXX
    at hudson.FilePath.createTextTempFile(FilePath.java:1624)
    at hudson.tasks.CommandInterpreter.createScriptFile(CommandInterpreter.java:202)
    at hudson.tasks.CommandInterpreter.perform(CommandInterpreter.java:120)
    at hudson.tasks.CommandInterpreter.perform(CommandInterpreter.java:92)
    at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
    at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:818)
    at hudson.model.Build$BuildExecution.build(Build.java:199)
    at hudson.model.Build$BuildExecution.doRun(Build.java:164)
    at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:526)
    at hudson.model.Run.execute(Run.java:1900)
    at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:44)
    at hudson.model.ResourceController.execute(ResourceController.java:101)
    at hudson.model.Executor.run(Executor.java:442)
Build step 'Execute shell' marked build as failure
Finished: FAILURE

在这段信息之前还有一些信息,都是 Git 拉取代码相关的,没什么用。

定位

这段报错信息中,有 3 段有用的信息可以提供线索。

第一个有用的信息

Commit message: "???? 01"

这里明显是 Git Commit 信息乱码了,在 01 前面还有 4 个中文。

想便大概是和字符集有关了,但我当时认为,乱码就先乱码吧,应该不至于影响后面的构建吧。

第二个有用的信息

接着往下看,发现 Java 的异常信息:

java.nio.charset.UnmappableCharacterException: Input length = 1

这个比较关键,去查了一下说是字符集设置不正确导致,于是上网搜索了一堆答案,都没有效果,暂时放弃。

第三个有用的信息

Caused: java.io.IOException: Failed to create a temp file on /var/lib/jenkins/workspace/XXXXXXXX

看起来意思是 Jenkins 在编译构建的过程中,拉取了 Git 代码以后,创建临时目录失败了,但是我去服务器上看了,目录都还在,什么鬼?

把目录删除了,重新构建也不行。

心态崩了

从编译失败的信息中, 一共获取到了三段有用的信息,两个尝试了未果,也许有可能都是串联的吧?

那就先从第一个下手好了,搜索出来的结果操作起来都比较简单,都是些什么在这个位置添加环境变量,设置 LANG,在那个位置添加环境变量设置 Lang,结果没有一个好用的,就一个小小的字符集问题,搞起来这么难?心态崩了。

进一步发现线索

在上面的 搜索问题 - 得到答案 - 尝试 - 失败 的循环中,发现了一条比较有用的线索,那就是可以通过 Jenkins 的系统信息中看到一些 Java 相关的运行参数,其中便有字符集相关的,最主要的一个,就是 file.encoding

在我的 Jenkins 上可以看到是 ANSI_X3.4-1968,网上的老司机们都说这个不对,搞成 UTF-8,他们的问题就解决了,但是我按照他们的该当一顿操作下来,死活改不掉这个字符集,继续崩溃。

柳暗花明

就在我苦苦地一遍又一遍地问候着 Jenkins 这个玩意儿怎么这么多坑的时候,突然想起来,就在刚刚安装好 Jenkins 的时候,遇到过类似的情况,改 Jenkins 配置结果死活都不生效,最后是去修改的 service 文件才解决!

立马执行 systemctl status jenkins 查看到 Jenkins 的 service 文件位置 /usr/lib/systemd/system/jenkins.service,Vim 它!

在里面翻到了一个 Environment="JAVA_OPTS=-Djava.awt.headless=true" 的配置项,想必就是你了吧,把 -Dfile.encoding=UTF-8 加进去,就成了:

Environment="JAVA_OPTS=-Djava.awt.headless=true -Dfile.encoding=UTF-8"

systemctl daemon-reload && systemctl restart jenkins 以后,再次查看 Jenkins 系统信息,终于变过来了!

执行构建,查看结果也没有问题了,在编译过程中的中文的 Git Commit 也能正常显示了,哦特么噎死~