ClickAction - 本地任务快速启动器

讲在前面

Windows 一键启动器

在日常开发中的通常步骤是

  • 更新工程的代码到最新版本

  • 用编辑器打开工程(还可能会要打开多个工程)

  • 修改代码、协议,然后本地生成协议进行测试

  • 编译工程,确定代码没有问题

  • 启动本地测试服务,测试协议工作正常

等等一系列的操作其实都是很简单的固定步骤,每天都要去操作实则是麻烦。本着能偷懒就偷懒的原则根据自身的需求设计开发了启动任务的工具-ClickAction。

开发这个工具的初衷也很简单,整个成品的界面、功能也很单一,但是能够点一点就执行预先设置好的任务(命令行)也满足需求了,能用就行。

整体结构

先看看最终的界面截图

其实整个界面、功能跟操作方式都很简单明了,画了一个脑图大致说明一下有哪些内容。

第一次启动后需要在菜单:Settings->New Action后才能看到任务界面

任务界面左侧按顺序列出了除当前任务的所有其他任务,勾选上后表示前置依赖

点击“<<”按钮可以将当前任务的顺序向前挪动,该按钮后面的两个输入框分别是运行路径、任务名称。

运行路径是相对于ClickAction.exe文件的路径

点击Run的时候将命令行文本框的内容写入到临时bat文件,调用子进程执行bat文件

代码

配置文件的解析

配置的内容很简单,使用系统内置的序列化功能可以满足需求,而无需Newtonsof.json这样的第三方库。这样整个工程也更加简洁,不存在依赖使用起来也方便

如上图的配置类使用下面的代码很方便的就序列化、反序列化完成了。

        public static List<ActionItemData> UnMarshalList(string content)
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List < ActionItemData >));
            var mStream = new MemoryStream(Encoding.Default.GetBytes(content));
            //var result = (T)serializer.ReadObject(stream);
            List<ActionItemData> result = (List<ActionItemData>)serializer.ReadObject(mStream);
            return result;
        }

        public static string MarshalList(List<ActionItemData> items)
        {
            var setting = new DataContractJsonSerializerSettings();
            setting.UseSimpleDictionaryFormat = true;
            
            var mStream = new MemoryStream();
            using (var writer = JsonReaderWriterFactory.CreateJsonWriter(mStream, Encoding.UTF8, true, true," "))
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<ActionItemData>), setting);
                serializer.WriteObject(writer, items);
                writer.Flush();
                mStream.Position = 0;
                var sr = new StreamReader(mStream);
                return sr.ReadToEnd();
            }
        }

执行任务内容

在线程中调用子进程的方式执行任务,

 public void RunTaskInThread(object args)
        {
            List<ActionItemData> actionItemDatas = args as List<ActionItemData>;
            foreach (ActionItemData cmdData in actionItemDatas)
            {
                if(string.IsNullOrEmpty(cmdData.command))
                {
                    continue;
                }
                string commandFile = null;
                string workdDir = null;
                workdDir = "";
                if (cmdData.cwd != null)
                {
                    workdDir = cmdData.cwd.Replace("/", "\\");
                }
                Random rand = new Random();
                commandFile = string.Format("{0}\\{1}-{2}.bat", TEMP_FOLDER, cmdData.name, 1);

                commandFile = commandFile.Replace(" ", "_");
                commandFile = Path.GetFullPath(commandFile);
                File.WriteAllText(commandFile, cmdData.command);

                process = new Process();
                var info = process.StartInfo;
                info.FileName = commandFile;
                info.WorkingDirectory = workdDir;
                info.CreateNoWindow = true;
                info.UseShellExecute = false;
                info.RedirectStandardOutput = true;
                info.RedirectStandardError = true;
                info.RedirectStandardInput = true;
            
                process.OutputDataReceived += OnOutput;
                process.ErrorDataReceived += OnError;
                process.Start();            

                process.BeginOutputReadLine();
                process.BeginErrorReadLine();
                process.WaitForExit();

                if (File.Exists(commandFile))
                {
                    File.Delete(commandFile);
                }
            }
        }

之所以要在线程中去执行任务是为了不让界面卡住,并等待子进程执行任务结束。

在执行任务时将依赖项与当前任务都加入到了任务列表里面依次创建进程调用外部bat脚本,同时将子进程的标准输入输出都重定向以便显示到日志窗口。这段代码也常用来在C#中调用第三方程序。

这里有个小知识点

要在子线程里面将日志同步到主线程的UI显示要使用Invoke委托的方式才行,因为子线程是不能直接操作主线程UI

        private void OnCommandOutput(CommandOutputLevel level, string msg)
        {
            this.Invoke(this.onShowCommandOuput, level, msg);
        }

更多细节的代码就不分析了,已经push到github上了,感兴趣的可以看下完整的工程。

开源

已经开源到github了,欢迎点个Star https://github.com/Tessence/ClickAction

用起来还有些小bug不过已经没有动力去改了,就这么简单个工具能用就行。

公告
本博客基于TinyBlog搭建,关注公众号CoderThing