|
沙发

楼主 |
发表于 2017-3-26 11:35:44
|
只看该作者
批处理文件、目录
本帖最后由 ancientcc 于 2020-10-15 09:20 编辑
Rose中和批处理文件相关的是class ttask。
批处理文件指的是一次性处理多个目录/文件。很明显,为方便维护不能把要处理的目录/文件写死在C/C++代码,须借助配置文件告知要执行的是什么处理,以及要处理哪些目录/文件。以下是个批处理配置例子,Studio用它“新建app”。
- [generate]
- type = new_app
- new = windows_prj_res, windows_prj_src2, rename_res_po
- [windows_prj_res]
- function = copy, windows_prj, res
- [resource]
- 0-dir = res/app-new_, app-<new_>
- 1-dir = res/data/app-new_, data/app-<new_>
- 2-dir = res/data/core/app-new_, data/core/app-<new_>
- 3-dir = res/data/gui/app-new_, data/gui/app-<new_>
- 4-dir = res/po/app-new_, po/app-<new_>
- [/resource]
- [/windows_prj_res]
- [windows_prj_src2]
- function = copy, windows_prj, src2
- [resource]
- 0-dir = src2, <new_>
- [/resource]
- [/windows_prj_src2]
- [rename_res_po]
- function = rename, res
- [resource]
- 0-dir = po/app-<new_>/cfg-cpp/new_-lib, <new_>-lib
- 1-dir = po/app-<new_>/new_-lib, <new_>-lib
- 2-file = po/app-<new_>/<new_>-lib/new_-lib.pot, <new_>-lib.pot
- [/resource]
- [/rename_res_po]
- [/generate]
复制代码
generate是Studio自个定义的名称,ttask没规定外面块要叫什么。
批处理涉及到三个术语。任务、子任务和操作。
任务(task)是总入口,定义格式是<key> = <value>。示例中“new = windows_prj_res, windows_prj_src2, rename_res_po”定义了任务。key是个主观定义的字符串,C/C++代码要基于它在块中进行定位。不把key设为固定值,目的是要支持在一个块可定义多个任务。value值指示了此任务有哪些子任务,这些子任务会按这个书写次序依次被执行。
子任务(subtask)。块中必须存在一个块名和子任务一样的子块,这子块详细定义子任务。示例中[window_prj_res]对应第一个子任务。再说下,子任务执行次序按的是任务行中value值,不是子任务块的书写序。
操作(function)。子任务块下必须存在、而且只有一条“fucntion = <value>”的行。function是固定值,后面value定义了子任务要执行的操作。value是由逗号隔开的数个字符串,第一个指示操作,后面是此操作上下文。用C语言函数类比操作的话,第一个字符串是函数名,后面是参数。示例中的“windows_prj_res”子任务,操作是复制(copy),复制来源是windows_prj,目的地是res。windows_prj_src2的操作也是复制,来源是windows_prj,目的地是src2。rename_res_po则是重命名操作,要重命名res下的目录/文件。
value中出现windows_prj、res、src2,它们称为别名,可简单认为是某一具体目录的易记名(下面会详细说别名)。不论什么操作,参数都是别名,即要操作哪个或多个目录。
子任务块下的[resources]块指示了操作要涉及到的目录/文件。操作行格式是“<key> = <value>”。key由数字表示的序号和类型两部分组成,中间用“-”连接。序号作用是要让每行有不同key。类型有三种,分别是dir(目录)、file(文件)、files(目录一级根下的文件)。value则和此个子任务要执行的操作有关,不过有种比较普遍的定义是指定路径后半部分。假设示例中“windows_prj_res”这个复制操作,别名windows_prj代表了c:/apps-src/apps/projectfiles,res代表c:/apps-res,它们是路径前部分,看如何处理下面这条资源。
- 0-dir = res/app-new_, app-<new_>
复制代码
它会把c:/apps-src/apps/projectfiles/res/app-new_复制到c:/apps-src/app-<new_>。
子任务具体有哪些操作?操作分为两种,一是ttask内置的操作,二是app自定义的操作。以下是内置的操作。
操作 | 功能和参数 | 是否支持回卷 | resource中的value | copy | 从源目录复制目录/文件到目的目录。两个参数分别表示源目录、目的目录 | 支持 | 三个。参数1是源目录/文件后部分。(可选)参数2指示要自定义目的的后半部分。(可选)参数3指示是否要强制覆盖同名目录/文件,默认强制覆盖。(注1)(注2) | remove | 删除目录/文件。只一个参数,表示删除目录/文件发生在的目录 | 不支持 | 一个 | rename | 重命名目录/文件。只一个参数,表示重命名目录/文件发生在的目录 | 不支持 | 两个。参数1是要被重命名的目录/文件后半部分,参数2是要重命名到的名称 | replace | 替换文件中的字符串。只一个参数,表示发生替换文件的目录 | 不支持 | 奇数,至少3个。参数1是要被处理文件的后半部分,必须文件。参数2开始成对,N是要被替换的字符串,N+1是要被替换到的字符串 |
注1。要复制的是目录时,它首先会删除复制到的目录,然后执行复制。假设要复制到c:/apps-src/app-<new_>,那它首先会删除该目录。也就是说,如果想在已有目录增加目录/文件,不能用复制目录方法,应使用file、files。
注2。在copy前,如果有pre_remove,那会先执行pre_remove,即删除那些个(pre_remove可指定多个止录,中间用逗号隔开)目录。pre_remove值是目录的后半部分,要删除完整目录是copy指定的目标目录再加pre_remove指定的部分。类似以下公式。
- path = dst_path + "/" + subpath;
复制代码
以下是一个例子,pre_remove值是SDL/opencv,即在copy前先删除<src>/SDL/opencv。
- pre_remove = SDL/opencv
- path = <src>/SDL/opencv
复制代码
别名
别名类似程序中变量,它最后会指向一目录。别名分ttask内置的别名,app自定义的别名。以下是内置别名。假设game_config::path值是c:/apps-res。
别名 | 描述 | 值 | res | 工作包中的资源包 | 等于game_config::path。c:/apps-res | src | 工作包中的源码包 | src2的上一级目录。c:/apps-src | src2 | src中指示app源码的子目录 | res上级目录+/apps/apps。c:/apps-res/apps | user | 用户数据目录 | game_config::preferences_dir | app_res | app包中的资源包 | app_complete_paths设置,如果没设置则是game_config::path | app_src | app包中的源码包 | app_complete_paths设置,如果没设置则留空 | app_src2 | app_src中指示app源码的子目录 | app_complete_paths设置,如果没设置则留空 |
ttask填充别名分四个步骤。
- 填充res、src2、src、user。这四个是固定值。填充不管是否真正存在目录,只管补齐字符串。
- 调用app_complete_paths这个虚函数。app可在这函数填上内置的app_res、app_src、app_src2,像Studio,以及自定义别名。
- 如果app_complete_paths没填充app_res,则把它的值置为game_config::path。
- 解析块中的以“alias-”为前缀的“<key> = <value>”,增加自定义别名。以下是在配置中自定义别名示例。
- alias-kit = res, ../ios_kit
- alias-studio = kit, studio
复制代码 value中依次是基础别名、后半部分路径,中间用逗号隔开。基础别名必须是之前定义了的别名,它们合起来定义一个完整路径。假设res是c:/apps-sre,则kit别名值是c:/ios_kit,studio别名是c:/ios_kit/studio。
“alias-”方法不能定义内置别名。
app_complete_paths和“alias-”都可自定义别名,但它们不能重复定义同一别名。对自定义别名,如果后半部分是可变,像要由程序执行到时才能确定,建议放在app_complete_paths,如果不变建议放在“alias-”。
内置名称很大程度是保留给Studio。app一般只关心app_res、user,它们分别指向app资源包路径、用户数据路径。
可替换字符串
让看下这条复制项。
- 0-dir = res/app-new_, app-<new_>
复制代码
目的是要把<windows_prj_res>/res/app-new_复制到<apps-res>/app-<appid>。appid是不能预知的,新建app的appid可能是hello,可能是world,那它们分别对应app-hello、app-world。具体值要等到程序执行了才能确定。ttask支持了这一功能,允许资源项中存在一个可替换字符串。
- 一条资源中可出现多个要替换字符串,具体某一个,可重复出现多次。
- app用重载app_get_replace的方法告知ttask要替换哪些字符串,如果没有替换,一是不要重载这函数,二是返回std::vector<std::pair<std::string, std::string> >()。
- 替换要在具体执行操作时才生效。
app代码
基于ttask,app可按以下步骤进行编程。
1、定义个从task派生的类,假设是tnewer。
- class tnewer: public ttask
- {
- public:
- static const std::string windows_prj_alias;
- tnewer(const config& cfg, void*)
- : ttask(cfg)
- {}
- void set_app(const std::string& app) { app_ = app; }
- private:
- void app_complete_paths() override;
- std::pair<std::string, std::string> app_get_replace(const tsubtask& subtask) override;
- private:
- std::string app_;
- };
复制代码
tnewer需要一个可替换字符串,把资源项中的<new_>替换为新建app的appid。
- std::pair<std::string, std::string> tnewer::app_get_replace(const tsubtask& subtask)
- {
- const std::string replacee = "<new_>";
- return std::make_pair(replacee, app_);
- }
复制代码
2、用ttask::create_task构造tnewer。
- std::unique_ptr<T> create_task(const config& cfg, const std::string& key, void* context);
- 构造tnewer
- std::unique_ptr<tnewer> newer = ttask::create_task<tnewer>(c, "new", NULL);
复制代码
key就是任务行在配置中的中key值。
3、要执行批处理时调用ttask::handle。
- bool handle(display& disp);
- 执行新建app。
- newer->handle(disp)
复制代码
如果handle在执行中出现失败,像不能复制,支持回卷的操作会自动执行回卷。
|
|