项目任务4 日志内容解析
添加 .gitignore 文件
突然发现没有加 忽略文件 ,所以此处重加了这个文件
路径:项目路径下一层
.gitignore
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
# maven ignore
target/
*.jar
!.mvn/wrapper/*
*.war
*.zip
*.tar
*.tar.gz
# eclipse ignore
.myeclipse/
.settings/
.project
.classpath
# idea ignore
.idea/
*.ipr
*.iml
*.iws
out/
/bin
# temp ignore
*.log
*.cache
*.diff
*.patch
*.tmp
# system ignore
.DS_Store
Thumbs.db
*.orig
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
然后在项目下执行以下命令:
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
git rm -r --cached .
git add .
git commit -m 'update .gitignore'
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
IDEA执行后会有报错,处理如下:
全部操作后,选择 OK ,恢复正常(还不正常就重启一下项目)
制作特殊情况 log
然后执行以下命令,新建分支:
git checkout -b dev
新建分支后,在项目任意行末尾追加空行,然后进行提交,命令如下:
git status
git add -A
git commit -m "多行日志第一行
多行日志第二行
多行日志第三行"
把刚加的换行删掉,再加一个特殊日志,如下:
git status
git add -A
git commit -m "多个-m第一个" -m "多个-m第二个"
形成了两个多行日志
还有一种比较特殊,是合并冲突。先在master分支加个换行:
进行提交:
切换分支,在同样的位置加换行符,进行提交:
回到master,进行合并,制造冲突
删掉冲突行:
提交:
新日志产生了 merge行,如下:
一般这个Merge 行都是为了解决冲突的,一般不用考虑记录在周报中,是需要考虑的情况之一
包装已有生成日志代码
下图的3、4部分,本质上就是读取git内容,然后把各个项目对应的文本内容读出来,事实上这个步骤我们不关心,把这两步独立处理到文件中,最终返回一组 项目名->内容映射:
GitDealUtil.java
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
import com.weekpaper.bean.ConfigData;
import java.io.File;
import java.io.InputStream;
import java.util.*;
public class GitDealUtil {
public static Map<String,String> createLogTxt(ConfigData cd){
//2. 生成 git 执行命令行(windows,linux的类似,进入盘符的几个步骤有差别)
String commandFilePath = createGitCommandFile(cd);
//3. 执行 git 生成限定时间段日志
boolean result = executeGitCommand(commandFilePath);
//4. 读取抓到的日志内容
return readGitLog(cd,result);
}
private static Map<String,String> readGitLog(ConfigData cd, boolean result){
if(cd == null || !result){
LogUtil.severe("配置文件拿到空值或命令执行失败, 无法执行后续操作!");
System.exit(0);
return new LinkedHashMap<>();
}
Map<String,String> map = new LinkedHashMap<>();
int n = cd.getProjectPaths().size();
for(int i = 0; i < n; i++) {
String path = cd.getProjectPaths().get(i);
File f = new File(path);
if(f.exists() && f.isDirectory()){
String fullPath = FileUtil.getTmpFilePath(cd.getOutputPath(),f.getName()+".txt");
String msg = FileUtil.getInputMsg(fullPath);
System.out.println(msg);
map.put(cd.getProjectNames().get(i),msg);
}
}
return map;
}
private static boolean executeGitCommand(String path){
if(path == null || path.length() == 0){
LogUtil.severe("未生成可执行命令,无法进行后续流程!");
System.exit(0);
return false;
}
LogUtil.info("CMD /GIT命令开始执行...");
Process p;
boolean result = true;
try {
p = Runtime.getRuntime().exec(path);
InputStream fis = p.getErrorStream();//p.getInputStream();
String msg = FileUtil.getInputMsg(fis,false);
p.waitFor();
int i = p.exitValue();
if (i != 0) {
result = false;
LogUtil.severe("CMD /GIT命令执行失败!请检查是否安装 git 环境,命令是否正确!提示信息为:"+msg);
}else {
LogUtil.info("CMD /GIT命令执行成功!");
}
} catch (Exception e) {
result = false;
LogUtil.severe("未知错误!"+e.getMessage());
}
return result;
}
private static String createGitCommandFile(ConfigData cd) {
if(cd == null){
LogUtil.severe("配置文件拿到空值,无法执行后续操作!");
System.exit(0);
return "";
}
LogUtil.info("开始生成"+DateUtil.toString(cd.getStartDate())+"到"+DateUtil.toString(cd.getEndDate())+"git 命令行,如下:");
// 盘符:
// cd 【项目路径】
// for /F %%i in ('git config --get user.name') do ( set name=%%i)
// git log --author=%name% --since ==【开始时间】 --until=【结束时间】 > 【输出路径\tmp】\【项目名称英文】.txt
if(cd.getProjectPaths()==null || cd.getProjectPaths().isEmpty()){
LogUtil.severe("无可用项目!");
System.exit(0);
}
int n = cd.getProjectPaths().size();
if(cd.getProjectNames().size()<n){
LogUtil.severe("项目中文名称和项目路径数目不匹配!");
System.exit(0);
}
List<String> commands = new ArrayList<String>();
for(int i = 0; i < n; i++){
String path = cd.getProjectPaths().get(i);
String name = cd.getProjectNames().get(i);
LogUtil.info("开始创建项目"+name+"的 GIT 命令...");
File f = new File(path);
if(f.exists() && f.isDirectory()){
// 盘符:[linux不用写这个]
commands.add(path.split(":")[0]+":");
// cd 【项目路径】
commands.add("cd "+path);
// for /F %%i in ('git config --get user.name') do ( set name=%%i)
commands.add("for /F %%i in ('git config --get user.name') do ( set name=%%i)");
// git log --author=%name% --since ==【开始时间】 --until=【结束时间】 > D:\program\eclipse\work\DEST\config\【项目名称英文】.txt
File targetFilePath = FileUtil.reCreateFile(FileUtil.getTmpFilePath(cd.getOutputPath(),f.getName()+".txt"));
//注意:不包含第一天,需要向前挪动1天
commands.add("git log --author=%name% --since =="+DateUtil.getPreDayStr(cd.getStartDate())+" --until="+DateUtil.toString(cd.getEndDate())+" > "+
FileUtil.getShortPath(targetFilePath));
LogUtil.info("创建项目"+name+"的 GIT 命令成功!");
}else{
LogUtil.info("创建项目"+name+"的 GIT 命令失败,找不到文件夹!");
}
}
for(String command:commands){
System.out.println(command);
}
if(!commands.isEmpty()){
String commandPath = FileUtil.getTmpFilePath(cd.getOutputPath(),"cmd.bat");
File commandFilePath = FileUtil.reCreateFile(commandPath);
FileUtil.storeGitCommands(commands,FileUtil.getShortPath(commandFilePath));
return commandPath;
}
return "";
}
}
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
读取日志转换为Java对象
综合格式如下,大致总结出以下规律:
commit 代表日志的开头,可用于作为上一条日志的标志
Merge 说明这条日志是用于解决冲突的,可以不要
Author 里面可以抓取到用户名和邮箱,需要使用空格分割处理
Date 是时间,去掉尾巴+0800 解析即可
剩余多行是日志实际内容,可能会有空行,空行全部忽略,前面的空格删掉,即可拿到真实日志内容
另外:时间是倒序的,需要反过来
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
commit 57eecf580915851dde6b780677690ce269a87683
Merge: 12047ba ab16970
Author: 【用户名】 <【邮箱名】>
Date: Thu Jun 2 15:29:08 2022 +0800
多行日志第一行
多行日志第三行
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
规律弄懂,开始写:
WeekPaper.java
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
import com.weekpaper.bean.ConfigData;
import com.weekpaper.bean.LogContent;
import com.weekpaper.util.DateUtil;
import com.weekpaper.util.FileUtil;
import com.weekpaper.util.GitDealUtil;
import com.weekpaper.util.LogUtil;
import java.util.*;
public class WeekPaper {
public static void main(String[] args) {
if(args==null || args.length<1){
LogUtil.severe("找不到配置文件!");
System.exit(0);
}
//1.加载配置文件信息
ConfigData cd = loadConfigFile(args[0]);
//2. 创建Git日志文件读取日志内容
Map<String,String> logMsgs = GitDealUtil.createLogTxt(cd);
//3. 解析日志内容,读取为对象
Map<String,List<LogContent>> projectLogs = getListObjects(logMsgs);
for(String projectName:projectLogs.keySet()){
System.out.println(projectName+projectLogs.get(projectName));
}
}
private static Map<String, List<LogContent>> getListObjects(Map<String, String> logMsgs) {
Map<String,List<LogContent>> logAns = new HashMap<>();
for(Map.Entry<String,String> item:logMsgs.entrySet()){
String name = item.getKey();
String content = item.getValue();
String[] lines = content.split("\n");
//3.处理日志内容,抽象为对象
List<LogContent> lcs = new ArrayList<>();
LogContent lc = null;
StringBuilder sb = new StringBuilder();
boolean isMerge = false;
for(String line:lines){
if(line.startsWith("commit")){
if(lc!=null){
if(sb.length()>0){
sb.deleteCharAt(sb.length()-1);
}
lc.setContent(sb.toString());
sb.delete(0,sb.length());
if(!isMerge)
lcs.add(lc);
isMerge = false;
}
lc = new LogContent();
lc.setCommitVersion(line.substring("commit".length()+1).trim());
}else if(line.startsWith("Author:")){
String authorAndEmail = line.substring("Author:".length()+1).trim();
lc.setAuthor(authorAndEmail.split(" ")[0]);
lc.setEmail(authorAndEmail.split(" ")[1]);
lc.setEmail(lc.getEmail().substring(1,lc.getEmail().length()-1));
}else if(line.startsWith("Date:")){
lc.setDate(DateUtil.getUsDate(line.substring("Date:".length()+1).trim()));
}else if(line.startsWith("Merge: ")){
isMerge = true;
}else{
// commit 50ff270a2ba476db707df277d652t1234b732da8e
// Merge: 2677td2 1c873fe
// Author: xx <xx@xx.com>
// Date: Wed Jun 1 13:55:26 2022 +0800
//
// Merge branch 'dev'
// Merge 合并分支格式的忽略
if(line.length()<" ".length()) continue;
String str = line.substring(" ".length()).trim();
if(str.length()>0){
sb.append(str);
sb.append("\n");
}
}
}
if(lc!=null){
if(sb.length()>0){
sb.deleteCharAt(sb.length()-1);
}
lc.setContent(sb.toString());
sb.delete(0,sb.length());
if(!isMerge)
lcs.add(lc);
}
//由于时间倒序,所以需要反过来
Collections.reverse(lcs);
if(!lcs.isEmpty()){
logAns.put(name,lcs);
}
}
return logAns;
}
private static ConfigData loadConfigFile(String path) {
ConfigData cd = FileUtil.loadConfigData(path);
if(cd == null){
LogUtil.severe("配置内容有误!");
System.exit(0);
}else{
LogUtil.info("获取配置文件"+ FileUtil.getFilePath(path)+"成功!");
// LogUtil.info("获取配置文件"+ FileUtil.getFilePath(args[0])+"成功!信息如下:");
// LogUtil.info(cd.toString());
}
return cd;
}
}
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
LogContent.java
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
import com.weekpaper.util.DateUtil;
import java.util.Date;
public class LogContent {
private String commitVersion;//提交版本号
private String author;//作者
private String email;//邮箱
private Date date;//提交日期
private String content;//提交日志内容
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCommitVersion() {
return commitVersion;
}
public void setCommitVersion(String commitVersion) {
this.commitVersion = commitVersion;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "LogContent{" +
"提交版本=" + commitVersion + '\n' +
", 作者=" + author + '\n' +
", Email=" + email + '\n' +
", 日期=" + DateUtil.toString(date) +'\n'+
", 工作内容=" + content + '\n' +
"}\n";
}
}
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
DateUtil.java
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
public class DateUtil {
public static Date getDefaultStart() {
Calendar cld = Calendar.getInstance(Locale.CHINA);
cld.setFirstDayOfWeek(Calendar.MONDAY);//以周一为首日
cld.setTimeInMillis(System.currentTimeMillis());//当前时间
cld.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);//周一
return cld.getTime();
}
public static String getPreDayStr(Date d){
Calendar cld = Calendar.getInstance(Locale.CHINA);
cld.setTime(d);
cld.add(Calendar.DATE, -1);// 日期减1
return toString(cld.getTime());
}
public static Date getUsDate(String dateStr){
dateStr= dateStr.substring(0,dateStr.length()-" +0800".length());
try {
return new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy", Locale.US).parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
public static String toString(Date d){
SimpleDateFormat sdfFormat = new SimpleDateFormat("yyyy-MM-dd");
return sdfFormat.format(d);
}
public static Date toDate(String str){
SimpleDateFormat sdfFormat = new SimpleDateFormat("yyyy-MM-dd");
// 严格模式
sdfFormat.setLenient(false);
try {
return sdfFormat.parse(str);
} catch (ParseException e) {
return null;
}
}
}
❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤❤🧡💛💚💙💜🤎🖤
可以看到数据有写进来,多行日志也可正常读取