2019-07-23 使用NativeProcess调用和读取SVN输出信息

应用场景

在提取图片翻译工具中,需要分次提取项目中的图片文件。项目中的文件一般由svn管理,所以工具需要从SVN中读取一段时间明变更的文件,把文件中的文字提取出来。

相关知识

SVN相关命令

svn log PATH -l count -q 读取log(PATH表示文件或目录路径,count表示输出条数)
svn status PATH 获取本地和资源服务器之间的差异
svn diff --summarize PATH -c version 获取svn指定版本和最新版本之间的差异
svn diff --summarize PATH -r version:version2 获取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
        
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容

  • 大多数UNIX系统命令从你的终端接受输入并将所产生的输出发送回​​到您的终端。一个命令通常从一个叫标准输入的地方读...
    Leon_Geo阅读 573评论 0 7
  • 标准输入和标准输出 在C语言里要使用标准输入和标准输出必须包含stdio.h头文件,常用的标准输出和标准输入函数是...
    牛顿学计算机阅读 360评论 0 0
  • 大多数UNIX系统命令从你的终端接受输入并将所产生的输出发送回​​到您的终端。一个命令通常从一个叫标准输入的地方读...
    Leon_Geo阅读 311评论 0 2
  • 大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回​​到您的终端。一个命令通常从一个叫标准输入的地...
    枫海阅读 427评论 0 2
  • 大多数 UNIX 系统命令从你的终端接受输入,并将所产生的输出发送回​​到您的终端。一个命令通常从一个叫标准输入的...
    无量散人阅读 170评论 0 0