应用场景
在提取图片翻译工具中,需要分次提取项目中的图片文件。项目中的文件一般由svn管理,所以工具需要从SVN中读取一段时间明变更的文件,把文件中的文字提取出来。
相关知识
SVN相关命令
svn log -l -q 读取log(PATH表示文件或目录路径,count表示输出条数)
svn status 获取本地和资源服务器之间的差异
svn diff --summarize -c 获取svn指定版本和最新版本之间的差异
svn diff --summarize -r : 获取svn指定两个版本之间的差异
AIR NativeProcess类
参考https://help.adobe.com/zh_CN/as3/dev/WSb2ba3b1aad8a27b060d22f991220f00ad8a-8000.html
一旦 AIR 应用程序启动本机进程后,它就可以与该进程的标准输入、标准输出和标准错误流通信。
使用 NativeProcess 对象的下列属性流读取数据以及将数据写入流:
standardInput — 包含访问标准输入流数据的权限。
standardOutput — 包含对标准输出流数据的访问。
standardError — 包含访问标准错误流数据的权限。
标准输入输出流
执行一个shell命令行时通常会自动打开三个标准文件,即标准输入文件(stdin),通常对应终端的键盘;标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。
进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。
源码放最后吧
SvnManager 说明一下步骤
1.在提供的公开方法中,把传入的参数用模版拼凑成svn命令,模版就是上面提的svn命令
2.调用svn.exe,我这里把svn填到环境变量里了,所以直接svn...
3.把命令传到NativeProcessStartupInfo
4.NativeProcess侦听标准输出流和和标准错误流
5.处理输出和错误
package controller
{
import flash.desktop.NativeProcess;
import flash.desktop.NativeProcessStartupInfo;
import flash.events.NativeProcessExitEvent;
import flash.events.ProgressEvent;
import flash.filesystem.File;
import mx.controls.Alert;
import mx.utils.StringUtil;
import model.EventConfig;
import model.ViewModel;
import utils.FileUtil;
/****** SVN工具,主要功能是
* 1.查看新增的文件
* 2.对比本地目录和SVN服务器中最新版本的差异
* 3.对比SVN两个版本之间的差异
* */
public class SvnManager
{
private static var _ins:SvnManager;
public static function getIns():SvnManager
{
if(_ins==null)_ins = new SvnManager();
return _ins;
}
/**SVN路径**/
private var svnFile1:File = File.applicationDirectory.resolvePath("resource/sdk/svn-1.7.9/bin/svn.exe");
/**SVN路径**/
private var svnFile2:File = File.applicationDirectory.resolvePath("resource/sdk/svn-1.8.13/bin/svn.exe");
/***bat模版路径*/
private var template:File = File.applicationDirectory.resolvePath("assets/template/template.txt");
/**增加的数组*/
private var addArr:Array = [];
/**删除数组**/
private var delArr:Array = [];
/**对比结果出来之后的回调**/
private var callBack:Function;
/**输出回调**/
private var output:Function;
/**输出一条信息*/
public function setPrintHandler(callBack:Function):void
{
output = callBack;
}
/***检查SVN版本,未实现**/
private function checkSvnVersion():String
{
return "1.0";
}
/*** * 读取命令模版
* @param type 0为log的命令模版 1为status模版 2为diff的模版
* */
private function getTemplate(type:int=0):String
{
var templateStr:String = FileUtil.readByUTFBytes(template);
var templateArr:Array = templateStr.split("\r\n");
return templateArr[type];
}
/**检查目录是否在SVN控制内**/
public function checkSvnControl(path:String,outputCallBack:Function,errorCallback:Function):void
{
var command:String = "list {1}";
callSvn(command,outputCallBack,null,errorCallback);
}
/** * 获取目录的log
* @param file 文件,对些文件执行log命令
* @param callBack 回调
* @param count 获取记录数量(从最后的记录开始)
* ***/
public function getSvnLog(file:File,callBackHandler:Function=null,count:int = 5):void
{
addArr.length = 0;//先清除输出结果
callBack = callBackHandler;
var str:String = getTemplate(0);
str = str.replace(/\$SVNEXE\$/g,"");
str = str.replace(/\$PATH\$/g,file.nativePath);
str = str.replace(/\$count\$/g,count);
callSvn(str,onLogOutput,onLogExit)
}
private function onLogOutput(str:String):void
{
var logs:Array = str.split(/[-]+\s/);//分隔符是"------------------"
for(var i:* in logs)
{
var tempStr:String = StringUtil.trim(logs[i]);
var arr:Array = tempStr.split("|");
if(arr.length>1)
{
var logObj:Object = {};
logObj.version = arr[0];
logObj.author = arr[1];
logObj.date = arr[2];
addArr.push(logObj.version);//只需要版本号
}
}
}
private function onLogExit():void
{
if(callBack!=null)
{
callBack(addArr);
}
}
/***status
* 获取(本地和资源服务器)之间的差异
* @param path 文件路径
* @param callback 回调方法
* **/
public function getStatusSvnFiles(file:File,callBackHandler:Function=null):void
{
delArr.length = addArr.length = 0
callBack = callBackHandler;
//从模版中读命令的字符串,然后把命令中的路径替换
var str:String = getTemplate(1);
str = str.replace(/\$SVNEXE\$/g,"");
str = str.replace(/\$PATH\$/g,file.nativePath);
//执行
callSvn(str,onSVNOutput,onSVNExit);
}
/***diff
* 获取某一个版本的内容 (可以知道某个版本号下面提交了什么)
* @param path 文件路径
* @param version1 开始的版本号
* @param callback 回调方法
* **/
public function getVersionDiff(file:File,version:String,callBackHandler:Function=null):void
{
delArr.length = addArr.length = 0;
callBack = callBackHandler;
//从模版中读命令的字符串,然后把命令中的路径替换
var str:String = getTemplate(2);
str = str.replace(/\$SVNEXE\$/g,"");
str = str.replace(/\$PATH\$/g,file.nativePath);
str = str.replace(/\$version\$/g,version);
callSvn(str,onSVNOutput,onSVNExit);
}
/**获取两个版本之间的差异**/
public function getDiffBetween(file:File,version:String,version2:String,callBackHandler:Function=null):void
{
delArr.length = addArr.length = 0;
callBack = callBackHandler;
//从模版中读命令的字符串,然后把命令中的路径替换
var str:String = getTemplate(3);
str = str.replace(/\$SVNEXE\$/g,"");
str = str.replace(/\$PATH\$/g,file.nativePath);
str = str.replace(/\$version\$/g,version);
str = str.replace(/\$version2\$/g,version2);
callSvn(str,onSVNOutput,onSVNExit);
}
/**SVN输出*/
private function onSVNOutput(str:String):void
{
var addReg:RegExp = /^[ACMR?]\s+\+?\s+/g;//-->标记为修改的,或者增加的
var delReg:RegExp = /^[DL!]\s+\+?\s+/g;//标记为丢失或删除的
var fileUrl:String;
var lineArr:Array = str.split("\r\n");
for each(var line:String in lineArr)
{
if(line.search(addReg)!=-1)
{
fileUrl = line.replace(addReg,"");
if(fileUrl=="")continue;
if(addArr.indexOf(fileUrl)!=-1)continue;
addArr.push(fileUrl);
}
else if(line.search(delReg) != -1)
{
fileUrl = line.replace(delReg,"");
if(fileUrl=="")continue;
if(delArr.indexOf(fileUrl)!=-1)continue;
delArr.push(fileUrl);
}
}
}
/**状态回调*/
private function onSVNExit():void
{
if(callBack!=null)
{
callBack(addArr,delArr);
}
}
//svn执行的一轮start
/**是否svn正在执行**/
private var isSvnExecute:Boolean;
/**输出执行回调**/
private var outputHandler:Function;
/**结束执行回调**/
private var exitHandler:Function;
/**报错执行回调**/
private var errorHandler:Function;
/***call
* 直接调用svn的命令,而不生成BAT命令的文件
* @param command 执行命令行
* @param onOutput SVN命令会多次输出,会把每次输出回调
* @param onExit cmd界面关闭之后回调
* @param onError
* **/
// * @param version 使用的SVN版本,当前只区分1.7/1.8版本(要与你本机安装的SVN一致,要不然执行不了)
private function callSvn(command:String,onOutput:Function = null,onExit:Function = null,onError:Function = null):void
{
if(isSvnExecute)
{
if(output!=null)output("上一次SVN还在执行呢!!!")
Alert("上一次SVN还在执行呢...");
return;
}
isSvnExecute = true;
var svnToolVersion:String = ViewModel.getInstance().svnToolVersion;
var svnFile:File = svnToolVersion == "1.8" ? svnFile2 : svnFile1;
if(output!=null)output("使用SVN版本:"+svnFile)
outputHandler = onOutput;
exitHandler = onExit;
errorHandler = onError;
var commandArr:Array = command.split(" ");
var process:NativeProcess = new NativeProcess();
var processArg:Vector.<String> = new Vector.<String>();
cloneArryToVector(commandArr,processArg);
var info:NativeProcessStartupInfo = new NativeProcessStartupInfo();
info.executable = svnFile;
info.arguments = processArg;
process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, onErrorData);
process.addEventListener(NativeProcessExitEvent.EXIT, onExitData);
process.start(info);
if(output!=null)output("开始执行命领:"+command)
}
private function cloneArryToVector(ary:Array,vec:Vector.<String>):void
{
for(var i:* in ary)
{
vec.push(ary[i]);
}
}
/**输出数据*/
private function onOutputData(event:ProgressEvent):void
{
var process:NativeProcess = event.target as NativeProcess;
var str:String = process.standardOutput.readMultiByte(process.standardOutput.bytesAvailable,"iso-8859-01");
if(outputHandler!=null)
{
outputHandler(str);
}
if(output!=null)output("执行成功,结果:"+str)
}
/**报错回调*/
private function onErrorData(event:ProgressEvent):void
{
isSvnExecute = false;
var process:NativeProcess = event.target as NativeProcess;
var str:String = process.standardError.readMultiByte(process.standardError.bytesAvailable,"iso-8859-01");
if(output!=null)output("SVN报错:"+str)
if(errorHandler!=null)errorHandler(str);
}
/**退出回调*/
private function onExitData(event:NativeProcessExitEvent):void
{
isSvnExecute = false;
if(exitHandler != null)
{
exitHandler();
}
if(output!=null)output("退出")
}
//svn执行的一轮end
}
}