0. 大綱

本文說明如何製作一個 R package。

  1. 環境設定
  2. 建立基本的 R Project, push 到 git 中
  3. 使用 library, 以及編寫自己的 function
  4. 使用 master, develop 分支

參考這兩篇文章: Write an R package from scratch, and Designing Projects

1. 環境設定

由系統管理員使用下面的命令,建立用戶(用戶名: andy)

# add linux user
$ sudo useradd -m -s /bin/bash andy
# 設定密碼
$ sudo passwd andy
# 接著重複輸入密碼兩次確認

接著使用者 andy 可以登入系統,進行初始設定

# ssh 登入遠端服務器
$ ssh andy@your.server.com

# 設定 git 的使用者信息
$ git config --global user.email "andy@gomi.com"
$ git config --global user.name "Andy WANG"
$ git config --global merge.ff false
# 這些信息會寫入到 ~/.gitconfig 文件中
$ cat ~/.gitconfig
[user]
	email = andy@gomi.com
	name = Andy WANG

# create SSH-Key for tester1
$ mkdir ~/.ssh && chmod 700 ~/.ssh
$ ssh-keygen -t rsa -b 4096 -C "andy@gomi" -f ~/.ssh/id_rsa
# 這個步驟會在 ~/.ssh 資料夾中建立 一對公私密鑰: id_rsa, id_rsa.pub
# 將公鑰的內容放到 BitBucket 中,登記為自己的
# BitBucket 右上角個人照片 > [Bitbucket settings] > [SSH keys] > [Add key]
# 查看 公鑰 的內容,複製貼上:
$ cat ~/.ssh/id_rsa.pub

# 完成後試試看,下面指令,bitbucket應該可以認出使用者是 andy
$ ssh -v git@bitbucket.org
...
logged in as andy.
...

# 建立一個 repos 資料夾,之後的 repository 都放在這裡
$ mkdir ~/repos

2. 建立基本的 R Project, push 到 git 中

建立一個 git 的 repository, 這裡以 BitBucket 為例, 名稱為 fufu

獲得該 repository 的位置: git clone git@bitbucket.org:goming/fufu.git

登入 web 介面的 R Server

用 R-Studio 新建 project: [New Project] > [Version Control] > [Git], 輸入

  • Repository URL: git@bitbucket.org:goming/fufu.git
  • Project directory name: fufu
  • Create project as subdirectory of: ~/repos

用 git, clone 回來 project, 獲得 project 的基礎資料夾: fufu。

# 在 R studio 查看當前路徑
> getwd()
[1] "/home/andy/repos/fufu"
# 到上一層目錄
> setwd('..')
# 引用工具: devtools
> library(devtools)
# 初始化 R package, 會多出 DESCRIPTION, NAMESPACE... 文件。overwrite? 選 Yes
> devtools::create('fufu')

# 完成後,將目前路徑設定回到 fufu
setwd('fufu')

接下來新增 R 的程式: 一個叫做 dodo 的 function。

新增一個文件: ./R/dodo.R 內容如下:

#' My First Function
#'
#' dodo will loggin a message, and return "a" multiply by 11
#' @param params explain parameter 1
#' @param today  explain parameter 2
#' @return ball
#' @export

dodo <- function(a) {
  return(a * 11)
}

測試一下新的 function:

# 到 R Console 試著運行 dodo
> dodo(123)
Error: could not find function "dodo"
# 找不到剛才添加的函數

# 使用 devtools::document() ,將 dodo 函數加入 R package 的設定。
# 注意當前目錄需要是 "/home/andy/repos/fufu"
> document()
Updating fufu documentation
...

# 接著就可以成功呼叫 dodo(123)
# 這種方式,不需要事先 source('./R/dodo.R')
> dodo(123)
[1] 1353

將現有的 R project 放入 git 中

  • 現在還沒有 git 分支(branch), 所以先新增一個分支: master
  • 將現有的 project commit 到 本地的 master 分支上。
  • 將本地的 master 分支 push 到遠端的 BitBucket 服務器上。

到命令行,[git TAB] > [齒輪] > [shell]

# 建立 git master 分支
git checkout -b master

到 R Studio 的 [git TAB] » [commit]

  • commit message: 隨便寫,如 “initial project structure”
  • 選擇左側的文件 staged 打勾

確認按下 [Commit] 按鈕,將這些文件在自己機器上加入源碼管理。 然後按下 [Push] 按鈕,將這些文件同步傳送到遠端 BitBucket 的管理中。

這時候到 BitBucket 左側的 [Source] menu,就可以看到剛才 push 上的文件,在 master 分支中。

3. 使用 library, 以及編寫自己的 function

重新打開 R Studio Project,應該多了一個 [Build TAB],打開文件 DESCRIPTION,在裡頭加入兩個部分: Imports, Suggests

  • Imports: 必須使用到的 library
  • Suggests: 建議使用到的 library (通常是開發用的,如文件產生器 roxygen2)

如下:

Description: What the package does (one paragraph).
Depends:
    R (>= 3.3.1)
Imports:
    bigrquery,
    futile.logger
Suggests:
    devtools,
    roxygen2

此時可以點擊 右上 [Build TAB] > [Build & Reload],會進行程式的重新編譯,並載入更新的程序。

接著新建立一個 analysis.R 文件,在 fufu 資料夾中;注意不是在 fufu/R/ 資料夾下。

analysis.R 中可以寫不是 function 的 R Script, 然後呼叫 fufu/R/ 資料夾下的 R function,運行這些自訂的 function。

analysis.R 中需要引用 library(xxx), 在 fufu/R/ 資料夾下的 R function 文件中,不需要再引用 library(xxx)

analysis.R 的內容如下:

#!/usr/bin/env Rscript

library(fufu)
library(futile.logger)
result <- dodo(11)
sprintf('the result of my program is: %d', result)

修改 ./R/dodo.R 的 function 內容,加上呼叫其他 library (futil.logger) 的內容:

dodo <- function(a) {
  flog.info('this is a 3rd library call!!!')
  return(a * 11)
}
# 試試看在 R Console 呼叫 dodo(11),沒有變化!
> dodo(11)
[1] 121

# 重新編譯並載入:點擊 [Build TAB] > [Build & Reload]
> dodo(11)
INFO [2016-10-11 11:19:16] this is a 3rd library call!!!
[1] 121
# 可以看到剛才對 dodo function 的修改已經生效

接著可以到 linux 命令行試試看使用 RScript 運行程式,也可以獲得一樣的結果。

$ Rscript --vanilla ~/repos/fufu/analysis.R
INFO [2016-10-11 11:27:17] this is a 3rd library call!!!
[1] "the result of my program is: 121"

將目前為止的原始碼,再 commit, push 同步到 BitBucket 服務器上;注意看看有哪些文件被修改了。

4. 使用 master, develop 分支

看看 git flow 的做法

最簡單的兩個分支 master, develop

  • master: 對應生產環境的正式代碼
  • develop: 對應還在不停開發,修修改改的 開發中版本

img

gitflow 全貌,熟悉後再引入

  • feature: 某個功能
  • hotfix: 某個BUG修正

img

回到 R Studio, 在 git shell 中建立新的 develop 分支 (基於 master 上長出來的)

# 建立 git develop 分支
git checkout -b develop

隨便改點東西,例如把 dodo.R 改成 return(a * 11 + 99000)

然後 commit 這些變動到 本地的 develop 分支中。

此時遠端 BitBucket 中仍然沒有 新的 develop 分支,利用下面的命令,將 本地的 develop 分支放上 遠端(origin)的 BitBucket 服務器

# 在 R Studio 中的 [git TAB] > [shell] 中輸入
git push -u origin develop

到 BitBucket 中看到已經有兩個分支 master, develop。 剛才的修改只能在 develop 中看到。master 中沒有變化。

接下來先在 [Git TAB] 中,使用右側的 下拉框,選擇 master 分支;然後打開 [Git TAB] > [shell] 。輸入下面指令將 develop 分支合併到 master 上

# 在 R Studio 中的 [git TAB] > [shell] 中輸入

# 確認現在停留在 master 分支上 (前面有*符號)
$ git branch
  develop
* master

# 將 develop 分支合併回到 master 上
# 註: 最早的 環境設定 將 fast forward 取消了 (merge.ff = false)。
$ git merge -m "something is done" develop
Merge made by the 'recursive' strategy.
 R/dodo.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

再將 master 分支 push 同步上 BitBucket 服務器。然後打開 [Git TAB] > [Commit] > [History],可以看到類似的圖:

img

這張圖說明了:

  • 總共有四次 commit
  • 本地 master 分支 與 遠端 origin/master 分支同步 (在同一水平上)
  • 本地 develop 分支 與 遠端 origin/develop 分支同步
  • develop 分支已經合併回到 master 分支。