有时候,我想按作者,修订范围和/或提交消息快速搜索Subversion存储库。 Krzysztof Kotowicz 用svn-grep发布了博客文章Grep Subversion日志消息,其中引入了svn-grep ,这是一个bash脚本,使用了命令行XML工具包xmlstarlet ( 在Windows上也可以使用 xmlstarlet)。 这本身就是一个非常有用的脚本,但是它为我提供了一个基于Groovy的脚本的想法,该脚本可以在多个(所有JVM支持的)平台上运行。
searchSvnLog.groovy
#!/usr/bin/env groovy
//
// searchSvnLog.groovy
//
def cli = new CliBuilder(
usage: 'searchSvnLog.groovy -r <revision1> -p <revision2> -a <author> -s <stringInMessage>')
import org.apache.commons.cli.Option
cli.with
{
h(longOpt: 'help', 'Usage Information', required: false)
r(longOpt: 'revision1', 'First SVN Revision', args: 1, required: false)
p(longOpt: 'revision2', 'Last SVN Revision', args: 1, required: false)
a(longOpt: 'author', 'Revision Author', args: 1, required: false)
s(longOpt: 'search', 'Search String', args: 1, required: false)
t(longOpt: 'target', 'SVN target directory/URL', args: 1, required: true)
}
def opt = cli.parse(args)
if (!opt) return
if (opt.h) cli.usage()
Integer revision1 = opt.r ? (opt.r as int) : null
Integer revision2 = opt.p ? (opt.p as int) : null
if (revision1 != null && revision2 != null && revision1 > revision2)
{
println "It makes no sense to search for revisions ${revision1} through ${revision2}."
System.exit(-1)
}
String author = opt.a ? (opt.a as String) : null
String search = opt.s ? (opt.s as String) : null
String logTarget = opt.t
String command = "svn log -r ${revision1 ?: 1} ${revision2 ?: 'HEAD'} ${logTarget} --xml"
def proc = command.execute()
StringBuilder standard = new StringBuilder()
StringBuilder error = new StringBuilder()
proc.waitForProcessOutput(standard, error)
def returnedCode = proc.exitValue()
if (returnedCode != 0)
{
println "ERROR: Returned code ${returnedCode}"
}
def xmlLogOutput = standard.toString()
def log = new XmlSlurper().parseText(xmlLogOutput)
def logEntries = new TreeMap<Integer, LogEntry>()
log.logentry.each
{ svnLogEntry ->
Integer logRevision = Integer.valueOf(svnLogEntry.@revision as String)
String message = svnLogEntry.msg as String
String entryAuthor = svnLogEntry.author as String
if ( (!revision1 || revision1 <= logRevision)
&& (!revision2 || revision2 >= logRevision)
&& (!author || author == entryAuthor)
&& (!search || message.toLowerCase().contains(search.toLowerCase()))
)
{
def logEntry =
new LogEntry(logRevision, svnLogEntry.author as String,
svnLogEntry.date as String, message)
logEntries.put(logRevision, logEntry)
}
}
logEntries.each
{ logEntryRevisionId, logEntry ->
println "${logEntryRevisionId} : ${logEntry.author}/${logEntry.date} : ${logEntry.message}"
}
使该脚本更易于编写的一件事是Subversion的log命令具有使用–xml标志以XML格式写入其输出的功能。 尽管近年来XML一直受到广泛的批评,但是我对XML可用性的满意之处之一是广泛的工具支持编写和读取XML。 Subversion用XML编写某些类型的输出的能力就是一个很好的例子。 如果没有XML,该脚本将需要编写自定义的解析代码以解析非标准SVN日志输出。 因为Subversion支持为其输出写入标准XML格式,所以任何支持XML的工具都可以读取它。 在这种情况下,我利用了Groovy极其简单的XML Slurping (XML解析)功能。
该脚本还使用了Groovy的增强型(GDK)Process类,正如我在最近的文章《 使用Groovy编写脚本的崇高简单性》中所简要描述的那样。
脚本中使用了Groovy的内置命令行支持 ( CliBuilder )来接受用于缩小搜索范围的参数(例如适用的修订版,提交的作者或用于搜索提交注释的字符串)。 一个必需的参数是“目标”,可以是文件,目录或URL。
该脚本引用了一个名为LogEntry的Groovy类,然后显示该类的代码清单。
LogEntry.groovy
@groovy.transform.Canonical
class LogEntry
{
int revision
String author
String date
String message
}
外观简单的LogEntry
它最初出现时要强大得多。 因为是Groovy,所以自动为四个属性提供了setter / getter方法。 感谢@Canonical批注 ,它还支持构造函数equals , hashCode和toString方法。 换句话说,总共少于十行的此类具有存取器和更改器方法以及为此适当覆盖的通用类方法。
结论
Groovy提供了许多功能来简化脚本编写。 在本文中,我使用了一个通过Subversion log
命令(及其--xml
选项)“搜索” Subversion提交的示例,以演示其中一些有用的Groovy脚本功能(命令行参数解析,本机操作系统集成和简单的XML)。解析)。 在此过程中,还使用了Groovy的一些不错的语法优势(闭包,动态类型,GString值占位符)。
翻译自: https://www.javacodegeeks.com/2014/01/searching-subversion-logs-with-groovy.html