Ahk获取并解析SVN路径和版本号

自从学了点AutoHotKey,每天都想写点小脚本,偷个懒。尤其是面对每天要点几十次的流程,每次都又要填一堆重复内容的时候,内心极度不悦可又无可奈何。
最近有个流程我已经实在不想忍了,BUG结单要填涉及修改文件的SVN路径(URL)、名称和提交的版本号,而且还不能随意填,因为会做有效性校验。所以每次都要文件管理器找文件、右键菜单show log、找到提交记录拷贝url+版本号、整段复制到文档,然后分别复制3部分粘贴到流程单。当时就想着流程设计的真TM合理,迫不及待想搞个快捷键,简单研究了下,基本可行:
1)拷贝本地文件的绝对路径到剪切板;
2)用SVN提供的CLI工具,以本地文件路径为入参,获取文件的url和版本号;
3)对获取到的文本做查找解析,得到url目录、文件名称和版本号。
4)配置快捷键,通过Ahk命令将文本填充到流程单。
其实也没什么复杂的,难就难在不熟悉的脚本命令使用上反复尝试,找到正确写法。先给脚本,然后总结下要点。

#IfWinActive ahk_exe iexplore.exe
^LButton::FillCommitInfo_v1()

; 自动填写逻辑
FillCommitInfo_v1()
{
	url :=
	version :=
	requestUrlAndVersoin(url, version)	
	if(not url or not version)
		return
	
	last_slash_pos := InStr(url, "/", true, -1)		
	if(last_slash_pos > 0)
	{
	    ; 字符串剪切获取URL路径和文件名称
		url_dir := SubStr(url, 1, last_slash_pos)
		file_name := SubStr(url, last_slash_pos + 1, StrLen(url) - last_slash_pos)
		
		; 点击第一个输入框,获取编辑焦点,快捷键触发切换和文本填充
		SendInput, {Text} %url_dir%
	
		SendInput, {Tab} 
		SendInput, {Text} %file_name%
	
		SendInput, {Tab}
		SendInput, {Text} %version%
	}
}

; 获取url和版本信息
requestUrlAndVersoin(ByRef url, ByRef version)
{
    ; 默认从剪切板获取本地文件路径
	local_path := Clipboard

	;svn_arguments := " /c " "svn info " local_path
	;exec := shell.Exec(ComSpec svn_arguments)
	
	;#1 调用SVN工具获取文件的提交信息
	svn_info_cmd := "svn.exe info " local_path	
    ; WshShell object: http://msdn.microsoft.com/en-us/library/aew9yb99¬
    shell := ComObjCreate("Wscript.Shell")	
    ; Execute a single command via cmd.exe
	exec := shell.Exec(svn_info_cmd)
    ; Read and return the command's output
	output := exec.StdOut.ReadAll()	
	
	; 从中获取绝对的url,其中相对url的查找是为了获取绝对url的文本结束位置
	url_index := InStr(output, "URL:", true)
	reurl_index := Instr(output, "Relative URL", true)
	url_start := url_index + StrLen("URL:")
	url := Trim(SubStr(output, url_start, reurl_index - url_start))

	rev_cmd := "SubWCRev " local_path	
	exec := shell.Exec(rev_cmd)
    ; Read and return the command's output
	rev_desp := exec.StdOut.ReadAll()
	key_words := "Updated to revision"
	version_start := InStr(rev_desp, key_words, true) + StrLen(key_words)
	version := Trim(SubStr(rev_desp, version_start, StrLen(rev_desp) - version_start))	
}

因为只有在个ie浏览器中用所以做了个活动进程的校验。命令调用上做几点说明:

  1. 命令调用中首先要解决命令调用和获取输出的问题,Bing了一下是说可以通过Com调用脚本命令,然后读取标准输出拿到命令执行结果,如#1。Wscript.Shell是Com对象的全局唯一的id,该对象有两个命令执行的方法,一个Run,一个Exec。差别在于Run可以指定运行时的窗口形态以及是否阻塞等待,但其返回值为int类型,所以拿不到命令执行的结果文本。Exec只有一个命令入参,返回com对象,通过读标准输出可以获取到命令执行的结果。关于命令的详细说明,可参考链接:https://ss64.com/vb/shell.html
  2. SVN的安装,默认只有界面操作程序,如果要使用svn的命令行,则要在安装时,选择安装CLI组件。
  3. Exec命令中的可执行程序若已经添加到系统环境变量path,则可不指定其绝对路径;ComSpec为cmd的命令的绝对路径。各参数之间一定要有空格,否则会报错。美中不足的是每次工具调用都会弹个黑窗,试了很多方法都没能去掉。而且现在要分别执行两个命令,谈两次黑窗,后续尝试下看能够两个命令合并执行一次。
    8月3日,针对3)做了尝试,改了下命令,能够实现静默式的请求和命令合并执行,解决了每次都要弹一个窗口的问题。优化修改后的代码如下:
; 获取url和版本信息
requestUrlAndVersoin(ByRef url, ByRef version)
{
	local_path := Clipboard
	
	; 方式1:静默执行,输出写入到本地文件
	out_put_file := "C:\Users\Default\AppData\Local\Temp\svn_out.txt"
	svn_info_cmd := " /C svn info " local_path " > " out_put_file " & SubWCRev " local_path " >> " out_put_file
	shell := ComObjCreate("Wscript.Shell")	
	shell.Run(ComSpec svn_info_cmd, 0, true)
	
	output := ""
	FileRead, output, %out_put_file%

	; 方式2: 命令弹窗执行,通过com对象读输出
	;~ svn_info_cmd := "svn.exe info " local_path " & SubWCRev.exe " local_path 
    ;~ shell := ComObjCreate("Wscript.Shell")	
	;~ ;exec := shell.Exec(ComSpec " /Q /C" svn_info_cmd)
	;~ exec := shell.Exec(svn_info_cmd)
	;~ output := exec.StdOut.ReadAll()	
	
 	; 对字符串做拆分
 	url_index := InStr(output, "URL:", true)
  	reurl_index := Instr(output, "Relative URL", true)
  	url_start := url_index + StrLen("URL:")
  	url := Trim(SubStr(output, url_start, reurl_index - url_start))
	
  	key_words := "Last Changed Rev:"
  	version_start := InStr(output, key_words, true) + StrLen(key_words)
	
	last_version := ""
	version_end := version_start	
	; 跳过前面的非数字部分
	Loop 
	{
		ch := SubStr(output, version_end, 1)
		if ch is not digit
		{
			version_end := version_end + 1
			continue
		}
		break
	}
		
	; 匹配前面所有的数字部分
	Loop 
	{
		ch := SubStr(output, version_end, 1)
		if ch is not digit
			break
		
		version_end := version_end + 1
	}	
  	version := Trim(SubStr(output, version_start, version_end - version_start))	
}

之前说过,Shell的Run方法能够达到静默执行的效果,但是命令的返回值为int类型,所以拿不到程序执行的输出。一种可行的方法是将命令执行的结果输出到文件,然后读文件获取到输出。其中有几点说明:
a. ComSpec,即cmd.exe的执行输入参数一定要带/C,表示参数以命令方式执行且在执行结束后退出,否则可以正常执行但输出为空;
b. cmd支持多种重定位的操作符号,&是两条命令连续执行,|是把第一条命令的输出作为第二条命令的输入,&&第一条命令执行成功才执行第二条, ||第一条命令执行失败后执行第二条。我们这里执行达到命令连续执行的效果,所以用了&;
c. 文本输出,也有两种操作符号,>以覆盖方式写文件,>>以追加方式写文件,这也是代码种使用两种不同操作附的原因;
d. 若要静默执行,且命令返回时能够读到有效的文件内容,Run的第2个参数要传0,静默执行;第3个参数传true,表示等待命令执行结束。

你可能感兴趣的:(AutoHotKey)