要約
renv のスナップショット(バージョン固定)にはいくつかのタイプがあります。
そのうち "explicit"
なスナップショットタイプがおすすめです。
この方法では対象となるパッケージを DESCRIPTION
ファイルで明示的に指定します。
プロジェクトの依存関係を宣言的に記述することができるため、意図が理解しやすく変更も容易になります。
renv とは
renv は R のパッケージマネージャです。
renv を使うとプロジェクトごとに使用するパッケージのバージョン固定を行い、
ライブラリの状態を再現することができるようになります。
バージョン固定を行ったとき、その情報は renv.lock
ファイルに記録されます。
renv 自体の使い方については例えば
に詳しい説明があります。
スナップショットタイプ
バージョン固定を行うための関数 renv::snapshot()
には type
というオプション引数があります。
このオプションによってバージョン固定の対象となるパッケージの選び方が変わります。
"all"
: その時点でライブラリにインストールされているすべてのパッケージが対象となる"implicit"
: プロジェクトのコードで使用されているパッケージとその依存関係が対象となる"explicit"
:DESCRIPTION
ファイルで明示的に指定されたパッケージとその依存関係を対象となる"custom"
:"implicit"
タイプの方法で選ばれたパッケージに対して、ユーザー定義のフィルタを適用した結果が対象となる
renv::init()
でプロジェクトを初期化したとき、デフォルトの設定では "implicit"
なスナップショットが使用されるようになっています。
"explicit"
なスナップショットの使い方
"explicit"
なスナップショットを使用する場合、まず DESCRIPTION
ファイルを作成します。DESCRIPTION
ファイルは通常パッケージ開発プロジェクトでパッケージのメタ情報を示すために作成されるファイルです。これについては例えば https://r-pkgs.org/description.html に詳しい説明があります。
renv ではパッケージ開発プロジェクトでなくても DESCRIPTION
ファイルで依存関係を宣言できます。
例えば、プロジェクトのルートディレクトリに DESCRIPTION
ファイルを作成して次のような内容に編集します:
Type: project
Description: My project.
Depends:
renv (0.15.4),
palmerpenguins,
dplyr (== 1.0.9),
tidyr (== 1.1.0)
このように、利用したいパッケージは Depends
フィールドや Imports
フィールドで指定します。
この状態で
renv::install()
を実行すると、パッケージ renv
、palmerpenguins
、tidyr
、dplyr
がインストールされます.
次に、バージョン固定のため
renv::snapshot(type = "explicit")
を実行すると、renv.lock
ファイルが作成されパッケージのバージョンが記録されます。ここで対象となるのは DESCRIPTION
ファイルに記載された renv
、palmerpenguins
、tidyr
、dplyr
とその依存関係のパッケージです。
このとき、例えばもしライブラリに devtools
がインストールされていたとしても、バージョン固定の対象にはなりません。またソースコード中に library(ggplot2)
のように ggplot2
を呼び出すコードが入っていたとしても、やはりこれも対象になりません。
renv.lock
ファイルの内容は例えば次のようになります:
{
"R": {
"Version": "4.2.0",
"Repositories": [
{
"Name": "CRAN",
"URL": "https://packagemanager.rstudio.com/cran/latest"
}
]
},
"Packages": {
"R6": {
"Package": "R6",
"Version": "2.5.1",
"Source": "Repository",
"Repository": "RSPM",
"Hash": "470851b6d5d0ac559e9d01bb352b4021",
"Requirements": []
},
"cli": {
"Package": "cli",
"Version": "3.3.0",
"Source": "Repository",
"Repository": "RSPM",
"Hash": "23abf173c2b783dcc43379ab9bba00ee",
"Requirements": [
"glue"
]
},
...(中略)...
"utf8": {
"Package": "utf8",
"Version": "1.2.2",
"Source": "Repository",
"Repository": "RSPM",
"Hash": "c9c462b759a5cc844ae25b5942654d13",
"Requirements": []
},
"vctrs": {
"Package": "vctrs",
"Version": "0.4.1",
"Source": "Repository",
"Repository": "RSPM",
"Hash": "8b54f22e2a58c4f275479c92ce041a57",
"Requirements": [
"cli",
"glue",
"rlang"
]
}
}
}
"explicit"
なスナップショットの利点
デフォルトの "implicit"
なスナップショットでは、ソースコードの解析によってどのパッケージが使われているかが判定されます。コードの規模が大きくなってくると、コードの解析に時間がかかったり意図しないパッケージが追加されたりする可能性が高くなってきます。
"explicit"
なスナップショットを使うことによって、コード解析を行わず開発者が DESCRIPTION
で明示的に指定したパッケージとその依存関係だけが renv.lock
に記録されるようになります。
また、DESCRIPTION
ファイルにインストールしたいパッケージを宣言することで、意図して指定したパッケージやそのバージョンに関する条件と、結果的にインストールされたパッケージやそのバージョンとを区別することができるようになります。
そのため、使用するパッケージを後から変更したときもその意図がわかりやすくなります(tidyr
を 1.0 から 1.1 に変えたが、同時にその依存関係がアップデートされたなど)。DESCRIPTION
ファイルなしで renv.lock
の差分だけから変更の意図を推測することは困難でしょう。
他言語との比較
他言語のパッケージマネージャでは、依存関係の宣言とバージョン固定用のロックファイルとを区別することはよく行われています。例えば Pipenv との比較でいうと、DESCRIPTION
ファイルは Pipfile
に、renv.lock
ファイルは Pipfile.lock
に相当します。
いくつかの例を表に示します。
言語 | パッケージマネージャ | 依存関係の宣言 | ロックファイル |
---|---|---|---|
R | renv | DESCRIPTION | renv.lock |
Python | Pipenv | Pipfile | Pipfile.lock |
JavaScript | npm | package.json | package-lock.json |
PHP | Composer | composer.json | composer.lock |
注意
現時点 (renv バージョン 0.15.4) では、DESCRIPTION
ファイルにおいて >
、>=
、<
、<=
によるバージョンの上限・下限指定は効かないので注意が必要です。
例えば tidyr
のマイナーバージョンまでは 1.1 で固定し、パッチバージョンは最新のものを反映したいという意図で
Depends:
tidyr (>= 1.1.0),
tidyr (< 1.2.0)
のように指定したとしても、renv::install()
を実行すると常に最新のバージョン(1.2 以上)がインストールされてしまいます。
現状で選択できるのは ==
で完全にバージョンを指定するか、何も指定せず新しいバージョンがインストールされるようにするかの2通りのみとなっています。
標準リポジトリ以外からのインストール
標準リポジトリ以外の場所からパッケージをインストールしたい場合は Remotes
フィールドを使います。
例えば、 GitHub から tidyr
の v1.1.0
をインストールしたい場合は次のように指定します:
Type: project
Description: My project.
Imports:
renv (0.15.4),
palmerpenguins,
dplyr (== 1.0.9),
tidyr
Remotes: tidyverse/[email protected]
Remotes
フィールドの文法について詳しくは
devtools
のドキュメント
https://devtools.r-lib.org/articles/dependencies.html
に説明があります。