懒人神器
更新
大家注意一下,由于在写入MANIFEST的时候,Class-Path路径给的是 ../lib
,即上级目录的lib。 所以在对拍时如果手动移动了 jar包的位置,需要保证 lib/ 文件夹在存放jar包的上一级目录下,否则在运行时会报错 ClassNotFound
(也可以在源码中直接修改jar包的输出位置)
一种可能的文件树如下:
├──src
│ ├─ Archer.jar
│ ├─ Berserker.jar
│ ├─ Caster.jar
| ├─ ....
| └─ Alterego.jar
├──lib
│ ├─ elevator-input-hw3-1.4-jar-with-dependencies.jar
│ └─ timable-output-1.1-raw-jar-with-dependencies.jar
└──your_pat.py
一键build:zip -> jar
由于每次互测都要经过重复的操作:
download -> unzip -> compile -> run
本着一懒到底的原则,以及想要进一步熟悉一下shell指令,写了一个builder的脚本。
自己留着没意思,就拿出来分享给大家了,慢慢享用。
同时要感谢一下 fmh,过程中帮我解决了许多问题,还有 lqq 以身试法帮我测试~
使用
-
pre
- 将所有下载的zip压缩包(java源文件)放入src文件夹中
- 将本次作业的两个官方接口(外部jar包)放入lib文件夹中
- 在
2.
中,更改相应的lib文件的绝对路径
-
保证最后文件目录树如下即可:
├──src
│ ├─ Archer.zip
│ ├─ Berserker.zip
│ ├─ Caster.zip
| ├─ ....
| └─ Alterego.zip
├──lib
│ ├─ elevator-input-hw3-1.4-jar-with-dependencies.jar
│ └─ timable-output-1.1-raw-jar-with-dependencies.jar
└──builder.sh
-
run
- 运行
builder.sh
- 运行
-
然后就可以愉快地开始对拍啦
-
注意如果有player上交的src文件有多个main入口,有可能会出错。(但同样的,如果上交文件包含有多个入口,官方评测可能也过不了,这也是为什么rules中规定只能有一个入口)
实现思路
1. 解压缩并将lib中的外部包导入相应目录内
easy
2. 将src文件夹下的java编译为class文件
- 编译输出路径为
player/out/
- 注意
lib
中的 -classpath 为绝对路径
3. 将*.class打包成jar
- 难点(
坑点) 在于MANIFEST.mf
的写入- 保证 Main-Class: 带有相应的包路径 ,如
elevator3.Main
- 保证 Class-Path: 为相对路径
- 保证文件后有两个空行。
- 保证 Main-Class: 带有相应的包路径 ,如
- 因此,为满足上述需求:
- 由于.class为二进制文件,无法直接解析,但out文件夹下的.class文件结构与.java相同,故可以通过
grep
检索.java
文件,得到Main类包路径,再对得到的路径进行标准格式化操作即可。 - 相对路径:
.
表示当前路径;..
表示上一目录的路径 需要有空行是真的坑,差点自闭···
- 由于.class为二进制文件,无法直接解析,但out文件夹下的.class文件结构与.java相同,故可以通过
源码
#!/bin/bash
# Pre-Condition:
# NOTHING
# Attention:
# *.zip will be deleted
# Procedure:
# 1. put all *.zip into the src/ folder
# 2. put the external .jar into lib/ folder
# 3. run './builder.sh'
# 4. the jar-files has been generated in the 'out' folder of the corresponding directory, enjoy!
# file-tree is as follows:
# dir
# ├──src
# ├──lib
# └──builder.sh
cd src/
# 1. unzip and copy lib/ to src/
echo unzip start...
ls *.zip > temp.txt
sed 's/.zip//g' temp.txt > names.txt # sed 's/src/dst/'
names=`cat names.txt` # attention
# echo $names
for name in ${names[@]}
do
mkdir $name
unzip $name.zip -d $name
cp -a ../lib $name
done
rm *.txt
rm *.zip
echo unzip successfully...
# 2. compile to class
echo complie start...
prefix="javac -encoding utf-8 -d out/ @srcpath.txt "
lib="-classpath /C/Users/94831/Desktop/CourseCenter/OO/testShell/lib/elevator-input-hw3-1.4-jar-with-dependencies.jar:/C/Users/94831/Desktop/CourseCenter/OO/testShell/lib/timable-output-1.1-raw-jar-with-dependencies.jar "
command=${prefix}${lib}
dirs=`ls`
echo $dirs
for dir in ${dirs[@]}
do
# echo $dir
cd $dir
mkdir out
find -name "*.java" > srcpath.txt
$command
# rm srcpath.txt
cd ..
done
echo compile successfully...
# 3. pack to jar
echo packing to jar...
for dir in ${dirs[@]}
do
echo $dir
cd $dir
# write config information to MANIFEST.mf
echo -n 'Main-Class: ' > MANIFEST.mf
grep -l "public static void main" . -r | sed s/\.\///g | sed s/src\///g | sed s/\.java//g | sed s/\//./g >> MANIFEST.mf
sed '2, $d' MANIFEST.mf | tee MANIFEST.mf
echo 'Class-Path: ../lib/elevator-input-hw3-1.4-jar-with-dependencies.jar ../lib/timable-output-1.1-raw-jar-with-dependencies.jar' >> MANIFEST.mf
echo >> MANIFEST.mf
mv MANIFEST.mf out
cd out
find -name "*.class" > classpath.txt
jar cvfm $dir.jar MANIFEST.mf @classpath.txt
cd .. # from out
cd .. # from player_dir
done
echo pack successfully...