Open lotem opened 6 years ago
听起来不错, 但是似乎破坏了现在的方案机制的简洁性,方案本身和包管理器耦合起来了。 感觉如果在 /plum/ 中对配方定义做集中管理可以减轻对方案制定的负担,就像 homebrew 做的一样。
我還考慮過一個加強版的無配方文件的簡易實現:
規範 *.custom.yaml
的格式,安裝時合併 *.custom.yaml
的內容,而非簡單地複製文件。
因爲有賴於打補靪實現的配方包之間,很容易發生同名補靪文件相互覆蓋的錯誤。
合併 *.custom.yaml
文件的具體方法是跳過文件開頭的註釋行,讀到 ^patch:$
之後,把剩餘的縮進代碼追加到已有的補靪文件。如果考慮到 patch:
以外會有其他的一級節點,則需要一點點腳本功夫。
這些編輯操作用 bash, sed, awk 可以完成。Windows 的做法需要研究。
或者不用文本操作實現。升級一下 rime_patch
程序,妥善地合併 YAML 補靪文件。只不過這樣會依賴於 librime-tools
。
Node.js 也可以用來執行文本編輯操作;調 YAML 組件需要研究除了 exe 以外得安裝多大的 node_modules。
@nameoverflow 集中管理有他的好處,查詢下載都方便;也有潛在問題,就是不夠自由。一些用家可能只想整理歸納自用的方案和配置。 還有就是那個中心的維護成本、用戶更新代碼再提交 PR 更新配方的不便,幾乎超出了 Rime 用戶羣的承受力(homebrew 軟件包的維護者是與 Rime 開發者同級別的,更付得起辛苦成本)。
我認爲沒有中心,才能實現用戶僅通過維護一份配方列表實現終極配置。 去中心化輔以在「中心」以 user/repo 登記資源,就安穩了。
用bash吧,畢竟更靈活,要能自動改名,例如提供一個xxx.schema.custom.yaml,然後根據提供的參數來確定xxx
草稿:(大體實現 https://github.com/rime-aca/OpenCC_Emoji ,加入了演示一些其他功能的代碼)
# encoding: utf-8
---
recipe:
Rx: emoji-suggestion
args:
- schema=luna_pinyin
- opt_extra_argument
description: >-
Show emoji suggestion with OpenCC
# excludes:
# includes:
install_files: >-
*.schema.yaml
*.dict.yaml
*.txt
opencc/*.*
patch_files:
- recipe.yaml: ${schema:-luna_pinyin}.custom.yaml
- default.custom.yaml
patch:
switches/+:
- name: emoji_suggestion
reset: 1
states: [ "🈚️️\uFE0E", "🈶️️\uFE0F" ]
engine/filters/+:
- simplifier@emoji_suggestion
emoji_suggestion:
opencc_config: emoji.json
option_name: emoji_suggestion
tips: all
...
--- | # this is how to apply patch to multiple files
recipe:
patch_files:
- recipe.yaml: luna_pinyin.custom.yaml
- recipe.yaml: luna_pinyin_fluency.custom.yaml
- recipe.yaml: luna_quanpin.custom.yaml
...
① 一些解釋:
不想讓配方作者具有執行任意腳本的能力(儘管用 bash 實現解析仍會有漏洞可鑽)。 所以配方文件仍是基於 YAML 語法。 但是爲了 bash 腳本實現方便,會做若干格式限定。
基於 bash 的實現,不會解析 YAML,肯定是當文本文件做字符串解析的。因此規定
__include
, __patch
)等recipe
下面的 key 嚴格按順序寫recipe/args
其實是變量賦值(默認值),會用 bash 求值recipe/install_files
包含所有要複製的文件名或 glob 通配文件名,可以寫成一個字符串(可理解爲 ls
的參數)也可以是 block style YAML 列表,省略該字段則執行默認安裝
recipe/install
或者叫這個名字?recipe/patch_files
合併補靪文件,格式爲 block style 列表或者有序映射表,每項將一個 YAML 源碼文件的 patch
節點合併到目標文件(如爲列表格式,則爲用戶文件夾的同名文件),目標文件可以使用變量替換語法,以支持參數化補靪
recipe/customize
曾考慮用這個名字,但會破壞 key 的字母表順序patch
節點,就是待合併的補靪,也可以寫在單獨的文件裏,如果配方只打個補靪,和 recipe
寫到一個文件裏比較方便
patch
之下的縮進行,注意 patch
同級的其他節點如本例的 recipe
不會合併過去② 再談 recipe 的用法
安裝口令語法爲
bash rime-install emoji-suggestion#schema=luna_pinyin
其中 #
之後的逗號分隔的賦值語句定義配方參數(bash 的賦值語句用分號分隔,但分號用在一個命令行參數中間需要加引號,容易出錯)
這裏省略了配方名 recipe
,如果寫全,會是
bash rime-install emoji-suggestion:recipe#schema=luna_pinyin
③ 如果一個包提供多個配方文件,文件名反映配方的用途,會有(配方文件、口令):
# rime/rime-luna-pinyin/enable.yaml
Rx luna-pinyin:enable
# rime/rime-util/enable_schema.yaml
Rx util:enable_schema#schema=luna_pinyin
# rime/rime-util/select_schema.yaml
Rx util:select_schema#schema=luna_pinyin
④ 上文的配方文件樣例是爲了明確地定義參數及補靪的打法。如果不寫配方文件,還可以怎樣實現呢?
對於不需要參數化的補靪,可以直接根據文件名 *.custom.yaml
識別補靪。
參數化補靪,我想可以約定前綴 arg_
加上表示目標方案(或配置文件)的變量,比如本例可將補靪文件命名爲 arg_schema.custom.yaml
前提是安裝命令中必須指定 schema
參數。也就是說沒法提供默認值。
⑤ 還有一種實現比較快,但設計比較粗糙的實現:
# encoding: utf-8
# Show emoji suggestion with OpenCC
# Rx: emoji-suggestion
#$ target=${schema:-luna_pinyin}.custom.yaml
patch:
# ...
這就是待合併的補靪文件,除了以上討論的格式要求之外,特殊註釋行 #$
將作爲 bash 命令執行,然後通過 target
變量求得目標補靪文件。schema
是可能由安裝命令定義的變量。
實現略簡單,但比較容易出安全漏洞。如果不用 bash 實現,解析反而不如直接寫進 YAML 方便。
就 opencc emoji 這個例子來看,很可能需要一個專門打補靪用的配方,因爲需要給每個輸入方案都打上補靪,於是要分多次調用,每次給不同的 schema
參數。而複製 opencc/*.*
文件只需要一次。
所用配方大概是這樣的(Rx
代表給 rime-install
命令的配方參數):
Rx emoji-suggestion # 只安裝文件(emoji-suggestion:opencc ?)
Rx emoji-suggestion:patch#schema=luna_pinyin
Rx emoji-suggestion:patch#schema=cangjie5
...
有幾個問題:
recipe/install_files
下是如何指定安裝路徑的?逐個匹配文件名,符合要求則放入相當位置/還是在repo裏面就要按照目標路徑放置文件?patch
下的內容如果與recipe/patch_files
衝突,優先級?可以考慮報警告,中止執行,同時允許用戶自行用argument指定覆寫行爲這個現在還做不到。因爲每個包都是直接安裝到用戶文件夾,情況可能是覆蓋了來自另一個包的文件,也可能是升級安裝時覆蓋上一個版本。將來如果所有配置都用配方生成,每次在一個空文件夾開始逐個安裝配方,那就可以確定發生了第一種情況從而報警。
是的,現在已經配好的配方都與用戶文件夾格局一致。opencc/
也長一樣的。
你說的衝突是指出現重複的 key 吧?如果只用 bash 和 linux 小工具做字符串處理,按 key 覆寫也很吃力。比如用不同的引號括住相同的 key,也會發生 YAML 語法錯誤。另外邏輯錯誤也會因補靪代碼相互影響而發生。這是沒法防範的。所以總的原則還是用戶自己嘗試搭配。剛開始的實現,就按我先時描述的,可能只合併補靪代碼行。不檢查衝突。
不過你說的也對,確實有有意覆蓋補靪內容的場景,比如對某個已應用的補靪的微調。
librime/tools/rime_patch
這個原來是爲 rimekit 製作的小工具,用來根據命令行參數生成補靪。一個完善的實現肯定還要用這種帶 YAML 庫的可執行程序。配方對補靪文件的修改可以看成對 *.custom.yaml
文件內容應用一個來自配方的補靪。
先找人用 bash 腳本實現一個簡單的用用看。 想要完善一些的話,我感覺 bash 很快就會不夠用了。 再考慮到多數 Windows 用戶不具有 bash,用嚴肅代碼實現配置管理器將有必要。
稍稍細化 patch_files
的語法
patch_files:
文件名甲:
- 補靪一
- 補靪二
文件名乙:
- 補靪三
補靪行及其下縮進行原樣(也考慮做字符串模板展開)追加到目標文件根節點的 __patch
節點下(若無 __patch
節點則添加)。腳本實現會非常簡單,且靈活度高。
並約定:一律寫作以 -
開頭的補靪列表,以避免出現應用多份補靪後出現 YAML key 重複的錯誤。
示例:
# emoji_suggestion.recipe.yaml
# encoding: utf-8
---
recipe:
Rx: emoji_suggestion
args:
- schema=luna_pinyin
description: >-
Customize input schema to show emoji suggestion with OpenCC
patch_files:
${schema:-luna_pinyin}.custom.yaml:
- patch/+:
__include: emoji_suggestion.recipe:/patch
patch:
switches/@next:
name: emoji_suggestion
reset: 1
states: [ "🈚️️\uFE0E", "🈶️️\uFE0F" ]
'engine/filters/@before 0':
simplifier@emoji_suggestion
emoji_suggestion:
opencc_config: emoji.json
option_name: emoji_suggestion
tips: all
配置管理器修改後的文件:
# encoding: utf-8
__patch:
# Rx opencc-emoji:emoji_suggestion {
- patch/+:
__include: emoji_suggestion.recipe:/patch
# }
更多示例:
patch_files:
# This is possible but as always we recommend
# putting user customization in luna_pinyin.custom.yaml, default.custom.yaml
${schema:-luna_pinyin}.schema.yaml:
- ${schema:-luna_pinyin}.custom:/patch
- emoji_suggestion.recipe:/patch
default.yaml:
- schema_list/=: []
- schema_list/+:
- schema: luna_pinyin
- schema_list/+:
- schema: combo_pinyin_kbcon
- menu/page_size: 9
default.custom.yaml:
- patch/+:
menu/page_size: 10
@lotem
我用 golang 实现了一个 rime-plum-go,本来是准备给 openSUSE 发行版升级 brise 做一个类似脚本一样的东西,可以在本地去把 repo 都 clone 好,结果不知不觉就做成近似完全版本的 plum 了。
目前没有 --selector 的功能,另外由于对 recipe 新概念的不熟悉可能有 bug...但是看到您的帖子,我感觉它可能可以解决 windows 用不了 bash 的问题。
目前参数是这样的:
-b 类似 Makefile 里面的功能
-d 指定 RIME_DIR
-r <prefix:-https://github.com/><user:-rime><repo:-rime-emoji>:<recipe:-customize>:<rimeOptions>
比起原来的 pattern,多了一个 prefix,可以支持除了 github 以外的网站比如 marguerite.su/marguerite/rime-custom:customize:key=value,key1=value1
但是由于加了参数的原因, selector 就不太好做了...在想别的办法比如自己实现参数的库。
另外准备看一下您在这里发的草案,检查一下对语法的处理有没有 bug...
@marguerite 久仰
目前這個格式的設計,以及打補丁的方法都在遷就文本行編輯工具,因爲bash腳本沒有解析YAML文件的能力,只好按文本文件來編輯。如果有再複雜一些的操作,已經做不下去了。 rime-plum-go 正是今後需要的工具。
具體來說,配方對 patch
節點打補丁,就是對缺乏YAML解析能力妥協的產物。所輸出的代碼非常難以維護。
理想中,補丁要直接修改 *.custom.yaml
。用嚴肅編程語言就可以實現了。
將來改成這樣做,要有兩個前提:兼容現有的配方補丁;保護好用戶自己寫的patch,補丁做的修改要能撤回。這些要怎樣實現還得大討論。
@lotem 不知道我说的对不对,翻看 recipe.sh 和自己跑那些 shell script 进行测试后,我感觉现在的 recipe 是这样的,第一行是要操作的文件 $(schema:-luna_pinyin}.schema.yaml ,针对这个文件做一个 .custom.yaml,然后把第二行开始的东西都原封不动的丢到 # Rx: xxx {} 这个 block 里去。plum 目前就做了这些事情。我的实现也就抄了这些...
看了下 config 的语法,不知道我的理解对不对。
- patch/+: 由于只有 .custom.yaml 中的 “patch:” 部分才能应用到 .schema.yaml(?) 所以这行实际上的意思是“向 .custom.yaml 的 patch: 追加”? - 表示列表,这里哪来的列表?
__include: emoji_suggestion:/patch 内容是 emoji_suggestion.yaml 的 patch: 部分。
现在已经采用 yaml 和 bash 结合的方式了,考虑到兼容性,再改纯 yaml 已经不太容易了。好比 install_files 下面可以直接写不带 - 的 opencc/*/。所以这里不差再多一个 reserved word 表示覆盖行为了,比如:
opencc/**/* !override
*.json !keep
反正这里肯定是要从 yaml 中提取出来单独 parse 的...至少我在 rime-plum-go 这边是这样做的。因为 golang 的在文件夹下 Glob 的函数是我自己写的(官方没有),只支持 re2 的 regexp。所以我这里需要转换比如 */ *.{txt,json} 这样的 shell script 为 regex。那就不差再多识别一个参数了...
另外感觉我这边可以尝试解析 yaml,直接写 custom.yaml 的。比如第一个 recipe 写 custom.yaml,我会读取 emoji_suggestion.yaml 直接把 patch: 内容写到 custom.yaml,反正 rime 是支持的。第二个 recipe 再写 custom.yaml,我也是读取 patch: 然后按 key 查找冲突。如果冲突则提示但不写入,只写入非冲突部分。至于怎么调整哪个 recipe 在先,目前没有这样的机制吧,毕竟用户安装顺序是乱序的。现在 recipe 可以嵌套吗?
install_files
本來應該用YAML列表,但是純粹爲了bash實現省力就做了一個長字符串
至於那個patch
,怕是要多費些口舌才說得清……
我先說最後一個問題。安裝配方是講究順序的。 可能發生覆蓋,有些配方可能會有意覆蓋已有的配置項。 比方說,有個配方叫做清空輸入方案列表,那正常情況要用在所有添加輸入方案的配方之前。 所以使用配方的順序重要,並且最終效果是指定順序的用戶來保證。
还需要研究一下 dependency 的问题. 比如说, 我们应该允许一个配方依赖另一些配方 (指定的方式可以是任何 git source 或者 tarball (#62)). 现有的一些配方直接把朙月拼音方案放进去, 这非常不好, 一方面这会造成资源浪费, 另一方面跟进朙月拼音的上游更新会很麻烦. 另外, 有了 dependency 就还要有 lockfile. 这些都是一个包管理工具必须的.
而且, 现在定制化 RIME 配置的方法也有些不好. 我建议把配置 RIME 等价于定义一个配方. 这有很多好处: 首先, 这会非常 portable, 因为我只要在不同的机器上用同一个配方配置 RIME 即可, 所以只要把配方 push 到 GitHub repo 就能轻松同步多台电脑的配置. 其次, 分享配置也会很方便, 因为这直接等价于让别人安装一个配方. 第三, 这会对新手也更加友好, 因为在确定好了用 YAML 定义配方的格式之后, 设计一个用于写这个 YAML 的 GUI 程序应该不难, 届时就能实现新手不用打开任何代码编辑器就能定制自己的输入法. 而且, 东风破的很多现有问题都能解决了, 例如 #18, #25, #27.
「配方」用於定義一組配置及其他數據文件,指定其如何使用。
配方定義文件的格式有以下選擇:
無論哪種格式,都允許在代碼庫缺失配方定義文件的情況下,自動推導出默認的配方定義。 在 Windows 平臺 bash 不可用的情況下,只能忽略配方定義文件,做默認安裝。
無論哪種形式,都支持在未定義安裝動作的情況下,執行默認的安裝動作。 目前已實現的默認安裝動作爲:複製代碼庫中的
*.yaml, *.txt, opencc/*.{json,ocd,txt}
文件。一份代碼庫可以提供多份配方。 安裝時指定配方
user/repo:recipe
或安裝代碼庫默認的配方user/repo
。參數化配方,允許在安裝時定義一組變量以改變(具體化)安裝動作。 例如爲某項用補靪實現的定製動作設定目標輸入方案。
若選用 bash 安裝腳本,則實現參數化比較容易; 若選用 YAML 格式的補靪,則需要模板機制。