lua のコードをあちこちに書き散らかすよりも、機能毎にモジュール化するほうが何かと便利なので lua のパッケージマネージャの一つ LuaRocks(ちなみに、issue を見ると LR って略されてるね)を利用してモジュール化してるんだけど、今回はそのメモ。
まぁ、基本的なことはほぼドキュメント - http://luarocks.org/en/Documentation - に書いてあるし、チュートリアル見たらわかると思うので割愛して、独自リポジトリでのモジュール管理について。
っても、ドキュメントが結構残念な感じに不明な点がチラホラあるんだけど、マイナー言語なので仕方ないのかも。。
とりあえず LuaRocks をインストール
いつの間にか LuaRocks のバージョンが上がっていたので最新版をインストールする。インストールは手動でもいいけれど簡単なので Homebrew でインストール。
brew install luarocks
それから、基本的に Mac を管理者権限でログインして使うことがないのでホームディレクトリに ~/.luarocks
ディレクトリを作っておく。
mkdir ~/.luarocks
一般ユーザー権限でモジュールをインストールする時はこのディレクトリが使われることになる。あと、この中に config.lua
という設定用の lua ファイルも置けるけど今回は何もしないので詳しく知りたい人はドキュメントを読むと良いよ。
Note: 普段から管理者権限で動かしてる人は気にしないでおk。
モジュールのインストール方法色々
LuaRocks はモジュール化する時に便利だしデファクトっぽいしって理由で を利用しているのだけれど、作ったモジュールをデフォルトのリポジトリには公開してない。
なんかね、lua いじりだしてまだ1年半くらいでマナーがいまいちよくわからないってのもあるし、npm でもそうだけどモジュール名がかぶるのを気にして変な名前にするのもなんかなんかだしなぁ・・・とか、etc. な理由からなんだけど、でも、このままではものすごく不便でしょうがない。
例えば、普通に luarocks
コマンドを使ってモジュールをインストールするときは;
luarocks --local install <module_name>
Note: 一般ユーザーなので --local
オプションを付けて ~/.luarocks
にインストールされるように指定しているけど、管理者権限ならいらない。
とすると、デフォルト公開リポジトリからダウンロードされてインストールされる。もちろん検索する時は;
luarocks search <module_name>
とすることでデフォルト公開リポジトリに上がってるモジュールが検索される。
ちなみに、インストールしたモジュールを OpenResty
使いたい時は luarocks path
で LUA_PATH
と LUA_CPATH
が表示されるので、これを lua_package_path
と lua_package_cpath
に追加してあげればおk。
次に自分で作ったモジュールのインストール方法として、例えば以下のような hello
モジュールの rockspec
ファイル hello-scm-1.rockspec
があるとする;
─ lua-hello
├─ hello-scm-1.rockspec
├─ hello.lua
└─ lib
└─ world.lua
local function hello()
print( 'hello' );
end
return hello;
local function world()
print( 'hello world' );
end
return world;
package = "hello"
version = "scm-1"
source = {
url = "git://example.com/mah0x211/lua-hello.git"
}
description = {
summary = "example hello module",
detailed = [[example hello module]],
homepage = "https://example.com/mah0x211/lua-hello",
license = "MIT/X11",
maintainer = "mah0x211"
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "builtin",
modules = {
hello = "hello.lua",
["hello.world"] = "lib/world.lua"
}
}
これがローカルにある時はディレクトリ内で;
luarocks --local make
でインストールできる。リモートのどこかにある時は rockspec
の URL を指定して;
luarocks --local install https://example.com/mah0x211/lua-hello/hello-scm-1.rockspec
なんてやると rockspec
内に書いてある source.url
からダウンロードしてインストールされる。でも、これってめんどくさいし、例えば以下のように;
dependencies = {
"lua >= 5.1",
"my_dep_module"
}
my_dep_module
が自分で作ったモジュールで、それに依存してるとデフォルト公開リポジトリから検索されるので上手くいかない。npm
みたいに URL 指定できればいいんだけどね。こまた。
GitHub のリポジトリでモジュール管理
ドキュメントがあっさりしすぎてて肝心なトコがよくわからなかったのでずっと放置して、手動インストールをしてたんだけど、さすがにそろそろなんとかしたい。そんなわけで、ふと GitHub で自分用のリポジトリを作って管理できたら良いかもって思いついたのでやってみた。
ドキュメントによると、LuaRocks をインストールすると luarocks-admin
というツールも一緒にインストールされる。これを使って manifest
ファイルというリポジトリのインデックスファイルを作って自分の好きな場所に上げて管理できるとのことだったので早速やってみた。
まずは適当に GitHub でリポジトリを作って clone してくる。今回は自分のアカウントで rocks
というリポジトリを作ってみた。
git clone https://github.com/mah0x211/rocks.git
cd rocks
この中に管理したいモジュールの rockspec
ファイルをコピーして luarocks-admin make_manifest
で manifest
ファイルを生成する。とりあえず、自作のテンプレートエンジン tsukuyomi
の rockspec をいれてみる。
cp /path/to/tsukuyomi/tsukuyomi-scm-1.rockspec ./
luarocks-admin make_manifest .
こうすると以下のファイルが生成された。
- index.html
- manifest
- manifest-5.1
- manifest-5.2
これをコミット&プッシュして GitHub に上がったところで luarocks
から利用してみる。デフォルト以外のリポジトリは --from=<server>
オプションで指定することで優先して見にいかせられるとヘルプに書いてあったのでやってみる。詳しくは luarocks help
で。
luarocks --from=https://github.com/mah0x211/rocks/raw/master/ search tsukuyomi
Warning: Failed searching manifest: Failed loading manifest: Failed extracting manifest file
Search results:
===============
おー! うまくいかない。 おかしい。。
色々ぐぐってみるとヘルプには書かれてない --verbose
オプションがあるようなので指定してもう一度やってみて確認する。
... curl -L --user-agent 'LuaRocks/2.1.2 macosx-x86 via curl' 'http://mah0x211.github.io/rocks/manifest-5.1.zip' 2> /dev/null 1> ...
ファッ!?なんで zip
なの?調べてみると Release history にそれっぽいことが書かれている。
Version 2.1.1 - 29/Oct/2013 - download
Remote manifests are now compressed and locally cached, making commands faster
ということは、未実装かまたしてもドキュメント化してないオプションでもあるくさいのでソースを調べてみる。
cat `which luarocks-admin`
#!/usr/bin/env lua
local loader = require("luarocks.loader")
local command_line = require("luarocks.command_line")
program_description = "LuaRocks repository administration interface"
commands = {
help = "luarocks.help",
make_manifest = "luarocks.make_manifest",
add = "luarocks.add",
remove = "luarocks.admin_remove",
refresh_cache = "luarocks.refresh_cache",
}
command_line.run_command(...)
luarocks.make_manifest
が require
する時のパス表記になってるからモジュールっぽい。/usr/local/share/lua/5.1/luarocks/make_manifest.lua
の中を覗いてみる。
cat /usr/local/share/lua/5.1/luarocks/make_manifest.lua
--- Module implementing the luarocks-admin "make_manifest" command.
-- Compile a manifest file for a repository.
module("luarocks.make_manifest", package.seeall)
local manif = require("luarocks.manif")
local index = require("luarocks.index")
local cfg = require("luarocks.cfg")
local util = require("luarocks.util")
local deps = require("luarocks.deps")
local fs = require("luarocks.fs")
local dir = require("luarocks.dir")
help_summary = "Compile a manifest file for a repository."
help = [[
<argument>, if given, is a local repository pathname.
--local-tree If given, do not write versioned versions of the manifest file.
Use this when rebuilding the manifest of a local rocks tree.
]]
--- Driver function for "make_manifest" command.
-- @param repo string or nil: Pathname of a local repository. If not given,
-- the default local repository configured as cfg.rocks_dir is used.
-- @return boolean or (nil, string): True if manifest was generated,
-- or nil and an error message.
function run(...)
local flags, repo = util.parse_flags(...)
assert(type(repo) == "string" or not repo)
repo = repo or cfg.rocks_dir
util.printout("Making manifest for "..repo)
if repo:match("/lib/luarocks") and not flags["local-tree"] then
util.warning("This looks like a local rocks tree, but you did not pass --local-tree.")
end
local ok, err = manif.make_manifest(repo, deps.get_deps_mode(flags), not flags["local-tree"])
if ok and not flags["local-tree"] then
util.printout("Generating index.html for "..repo)
index.make_index(repo)
end
if flags["local-tree"] then
for luaver in util.lua_versions() do
fs.delete(dir.path(repo, "manifest-"..luaver))
end
end
return ok, err
end
manif.make_manifest
って箇所がきっとそれだってことで覗いてみると zip_manifests
という関数が定義されてるからこれを呼んでるトコを find /usr/local/share/lua/5.1/luarocks | xargs grep zip_manifests
で探してみると /usr/local/share/lua/5.1/luarocks/add.lua
からしか呼ばれてない。。
これって luarocks-admin add
でリモートリポジトリにアップロードするコマンドオプションなはずなので使えないっぽいし。。ここからしか呼ばれてないからこれ以上調べてもしょうがないし、手動で zip するとバージョン番号の付与とかめんどうなので、luarocks のモジュールを直接使うコードを書いて対応する。
local cfg = require("luarocks.cfg")
local manif = require("luarocks.manif");
manif.zip_manifests();
これを実行して manifest-5.1.zip
と manifest-5.2.zip
が作られてコミット&プッシュして確認してみると。
luarocks --from=https://github.com/mah0x211/rocks/raw/master/ search tsukuyomi
Search results:
===============
Rockspecs and source rocks:
---------------------------
tsukuyomi
scm-1 (rockspec) - https://github.com/mah0x211/rocks/raw/master
できた。疲れた。。午前中まるっとついやしたし。。
疲れたけど index.html
も生成されてるし、せっかくだから gh-pages
ブランチ作って http://mah0x211.github.io/rocks/ にアクセス出来るとわかりやすいだろなってことで、もうちょっとちょこちょこいじって完成。
生成された index.html
のデザインが残念すぎるけど、とりあえずこれでいいや。