基于SVN提交历史筛选作者并修改文件内容
笔者最近开发的项目中,是通过SVN做为版本管理工具的,因为需要创建的文件太多,所以有许多文件是在原有文件基础上拷贝过来修改的,这里就涉及到一个问题,原有文件中注释里填的JAVA类名、作者工号、创建时间等,都是需要修改成我自己的,因为文件太多,一个个修改起来太麻烦,所以我写了一个程序来自动扫描这些文件并替换文件中指定注释。
1.需要从项目中筛选出我创建的文件:
这个就通过SVN提交日志来筛选吧,因为SVN提交历史中有提交人的工号,我通过筛选自己的工号就可以查出哪些文件是我的(当然需要注意的一点就是如果你改了别人的文件并提交,也会被筛选出,所以你可以对筛选出的文件做进一步的筛选,我这里就通过类名命名规则又筛了一次)。
查询SVN提交历史需要使用svnkit包,svnkit下载路径:svnkit
这部分的实现类在后面提到的CheckSVNComment类中。
2.替换文件中信息
文件筛选出来后,就需要检查该文件中注释信息是否正确,如果不正确的话,就需要替换成指定信息,我这里对注释中的文件名,作者,创建时间进行了检查(创建时间必须是有作者不正确的前提下才会检查)。
这部分的实现类在后面提到的ModifyFileContent类中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | import java.io.File; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNLogEntry; import org.tmatesoft.svn.core.SVNLogEntryPath; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory; import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory; import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.io.SVNRepositoryFactory; import org.tmatesoft.svn.core.wc.SVNWCUtil; @SuppressWarnings ( "all" ) public class CheckSVNComment { private static void setupLibrary() { DAVRepositoryFactory.setup(); SVNRepositoryFactoryImpl.setup(); FSRepositoryFactory.setup(); } public static Set<String> svnFileList(String authorID) { String url = "项目SVN路径" ; String name = "svn帐号" ; String password = "svn密码" ; long startRevision = 0 ; long endRevision = - 1 ; setupLibrary(); SVNRepository repository = null ; try { repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(url)); } catch (SVNException svne) { svne.printStackTrace(); System.err.println( "error while creating an SVNRepository for the location '" + url + "': " + svne.getMessage()); System.exit( 1 ); } ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager(name, password); repository.setAuthenticationManager(authManager); try { endRevision = repository.getLatestRevision(); } catch (SVNException svne) { System.err.println( "error while fetching the latest repository revision: " + svne.getMessage()); System.exit( 1 ); } Collection logEntries = null ; try { logEntries = repository.log( new String[] { "" }, null , startRevision, endRevision, true , true ); } catch (SVNException svne) { System.out.println( "error while collecting log information for '" + url + "': " + svne.getMessage()); System.exit( 1 ); } Set<String> svnHistory = new HashSet<String>(); for (Iterator entries = logEntries.iterator(); entries.hasNext();) { SVNLogEntry logEntry = (SVNLogEntry) entries.next(); // 指定作者 if (!authorID.equals(logEntry.getAuthor())) { continue ; } if (logEntry.getChangedPaths().size() > 0 ) { Set changedPathsSet = logEntry.getChangedPaths().keySet(); for (Iterator changedPaths = changedPathsSet.iterator(); changedPaths.hasNext();) { SVNLogEntryPath entryPath = (SVNLogEntryPath) logEntry.getChangedPaths().get(changedPaths.next()); String filePath = entryPath.getPath(); if (filePath.endsWith( "java" )) { svnHistory.add(filePath); } } } } System.out.println( "检查出当前作者提交的文件数:" + svnHistory.size()); return svnHistory; } public static void checkFileComment(String path, String authorID) { ModifyFileContent f = new ModifyFileContent(); File file = new File(path); String target = " * FileName" ; String newContent = " * FileName: " + file.getName(); f.operationFile(file, target, newContent, authorID); } public static void main(String[] args) { String authorID = "工号ID" ; Set<String> svnHistory = CheckSVNComment.svnFileList(authorID); for (String filePath : svnHistory) { // if (filePath.toLowerCase().indexOf("message")>=0 || filePath.toLowerCase().indexOf("singlewithdraw")>=0) // { // System.out.println(filePath); String newFilePath = filePath.replace( "/branches/" , "D:\\project\\" ).replace( "/" , "\\" ); // 检查文件中注释信息 checkFileComment(newFilePath, authorID); // } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | package zz.test; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; public class ModifyFileContent { private String target; private String newContent; private static final Map<String, String> necessaryMap = new HashMap<String, String>(); private static final Map<String, String> choiceMap = new HashMap<String, String>(); static { choiceMap.put( " * Date" , " * Date: 2017/7/17 15:26" ); choiceMap.put( " * @DATE" , " * @DATE 2017/7/17 15:26" ); } public ModifyFileContent() { } private String checkLine(String originalLine, boolean flag) { if (originalLine.startsWith( this .target) && !originalLine.equals( this .newContent)) { return newContent; } for (Entry<String, String> entry : necessaryMap.entrySet()) { if (originalLine.startsWith(entry.getKey()) && !originalLine.equals(entry.getValue())) { return entry.getValue(); } } if (!flag) { return null ; } for (Entry<String, String> entry : choiceMap.entrySet()) { if (originalLine.startsWith(entry.getKey()) && !originalLine.equals(entry.getValue())) { return entry.getValue(); } } return null ; } public void operationFile(File file, String target, String newContent, String authorID) { this .target = target; this .newContent = newContent; necessaryMap.put( " * Author" , " * Author: " + authorID); necessaryMap.put( " * @USER" , " * @USER " + authorID); try { InputStream is = new FileInputStream(file); BufferedReader reader = new BufferedReader( new InputStreamReader(is)); String filename = file.getName(); // tmpfile为缓存文件,代码运行完毕后此文件将重命名为源文件名字。 File tmpfile = new File(file.getParentFile().getAbsolutePath() + "\\" + filename + ".tmp" ); BufferedWriter writer = new BufferedWriter( new FileWriter(tmpfile)); boolean flag = false ; String str = null ; while ( true ) { str = reader.readLine(); if (str == null ) break ; String newLine = checkLine(str, flag); if (newLine != null ) { writer.write(newLine + "\n" ); flag = true ; } else { writer.write(str + "\n" ); } } is.close(); writer.flush(); writer.close(); if (flag) { file.delete(); tmpfile.renameTo( new File(file.getAbsolutePath())); } else { tmpfile.delete(); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { System.out.println( "+++++++++ start" ); ModifyFileContent f = new ModifyFileContent(); File file = new File( "C:\\Users\\XXXXXX\\Desktop\\MessageNoticeJob.java" ); String target = " * FileName" ; String newContent = " * FileName: " + file.getName(); String authorID = "工号ID" ; f.operationFile(file, target, newContent, authorID); System.out.println( "+++++++++ end" ); } } |
如:
/*
* Copyright (C), 2002-2015, XXXXXX公司
* FileName: RechargeSuccessCallBackHandler.java
* Author: 11111111
* Date: 2017/3/6 11:31
* Description: //模块目的、功能描述
* History: //修改记录
* <author> <time> <version> <desc>
* 修改人姓名 修改时间 版本号 描述
*/
package xxxxxx;
import xxxxxx;
/**
* 〈一句话功能简述〉
* 〈出款处理器〉
*
* @USER 11111111
* @DATE 2017/3/6 11:31
* @SEE [相关类/方法](可选)
* @SINCE [产品/模块版本] (可选)
*/
修改后:
/*
* Copyright (C), 2002-2015, XXXXXX公司
* FileName: SingleWithdrawRefundTicketCallBackHandler.java
* Author: 12345678
* Date: 2017/7/17 15:26
* Description: //模块目的、功能描述
* History: //修改记录
* <author> <time> <version> <desc>
* 修改人姓名 修改时间 版本号 描述
*/
package XXXXXX;
import XXXXXX;
/**
* 〈一句话功能简述〉
* 〈出款处理器〉
*
* @USER 12345678
* @DATE 2017/7/17 15:26
* @SEE [相关类/方法](可选)
* @SINCE [产品/模块版本] (可选)
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统