Nim
Nimble
NimDay 5

Nimbleファイルのバージョン情報をソースに埋め込む


概要

追記:2018/12/24

最終的には @flat_leon さんのコメントの方式にしました。

気になる方はコメントへジャンプ!!

以下、読み物としてどうぞ。

Nimbleファイルのバージョン情報をstaticExecを使って、ソースに埋め込みます。


コンパイル時実行

Nimにはコンパイル時に実行するstaticRead/staticExecという機能があるそうで、@2vgさんのこちらの記事(Nimでコンパイルタイム実行を使用してみる)を読んで初めて知りました。


リリース時のミス

ちょうど私のNimで作っているツールのバージョンをアップしようと、Nimbleファイルに記述しているバージョン番号を変更したところ、ツール内で利用しているコマンドラインパーサー(docopt)に渡しているバージョン番号と合っていないという状態になりました。


sample.nimble

srcDir  = "src"         # ソースフォルダ

version = "0.2.0" # バージョン情報


main.nim

import docopt

let doc = """
application

Usage:
application (-v | --version)

Options:
-v --version Show version.
"""

# docoptの初期化はバージョンを渡す必要があり、nimbleのversionと合っていない
let args = docopt(doc, version = "application 0.1.0")



コンパイル実行時にnimbleファイルを読んでしまえ

で、冒頭の記事にてstaticExecを使って、コンパイル時に自動でソースにバージョン情報を埋め込んでしまおうというのが今回の内容となります。

ディレクトリ構成は以下を想定します。

utilディレクトリはビルド対象外フォルダとしています。

C:.

| application.nimble <= nimbleファイル。バージョンが記述されている
+---src
| main.nim <= バージョンを表示したいモジュール
| version.nim <= バージョンを埋め込むソース
\---util
get_version.nim <= application.nimbleからバージョンを抜き出す


main.nim

import version    # バージョン情報が埋め込まれたソース

# version.nimでexportされたcurrent_versionをバージョン情報として渡す
let args = docopt(doc, version = "application " & version.current_version)



src/version.nim

# staticExecで、util/get_version.nimを実行した結果を埋め込む

const current_version* = staticExec(
"nim c -r --hints:off --verbosity:0 -o:../bin/test ../util/get_version.nim application")

バージョン埋め込みがリリース時のみで良いなら、以下のようにすれば、ビルドのたびにバージョン読み込みしなくても良いかもしれません。


src/version.nim

when defined(release):

# staticExecで、util/get_version.nimを実行した結果を埋め込む
const current_version* = staticExec(
"nim c -r --hints:off --verbosity:0 -o:../bin/test ../util/get_version.nim application")
else:
const current_version* = "X.X.X"

nimbleファイルからバージョンを取得


util/get_version.nim

import os

import nre, options, strutils
import strformat

# 引数を取得
let
cmdArgs = os.commandLineParams()
pkgName = cmdArgs[0]

# XXXX.nimbleを読んで、version = X.X.X の X.X.Xを抜き出して、表示する
let f = open(fmt"../{pkgName}.nimble", FileMode.fmRead)
let lines = f.readAll().split("\n")
for line in lines:
let mOpt = line.match(re"(version)\s*=\s+""(\d+\.\d+\.\d+)""")
if mOpt.isSome:
let m = mOpt.get
echo m.captures[1]
break
f.close



まとめ


  • staticExecを使って、Nimbleファイルに記述されたバージョン番号をソースに埋め込むことができました。

  • staticReadというメソッドもあり、ファイルの内容を埋め込んでしまうこともできるみたいです。

  • なんでもありなNimが大好きです。