LambdaでGitHubのプライベートリポジトリをcloneする（バイナリ版）

# はじめに
LambdaでGitHubのプライベートリポジトリをcloneする。

# ポイント
- 必要なバイナリと共有ライブラリは全てデプロイパッケージに含める。
    - バイナリと共有ライブラリはAmazonLinuxのものを用いる。
        - LambdaFunctionはAmazonLinux上で動くため（[Lambda 実行環境と利用できるライブラリ](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/current-supported-versions.html)より）。
    - 必要なバイナリは以下の通り。
        - `/usr/bin/git`
        - `/usr/libexec/git-core`
        - `/usr/share/git-core`
    - 必要な共有ライブラリは `ldd` コマンドで調べる。
- デプロイパッケージに含まれるファイルを参照するよう環境変数 `GIT_EXEC_PATH` と `GIT_TEMPLATE_DIR` を設定する。
- Lambdaでは `/tmp` 以外へは書き込めない。そのため `/tmp` をホームディレクトリとしたうえで `.gitconfig` や `git-credentials` を `/tmp` に置く。

# 手順

## gitの設定ファイルの作成

### .gitconfig
```
[credential]
	helper = store --file /tmp/git-credentials
```

### git-credentials
```
https://username:password@github.com
```

## LambdaFunctionの実装（Python）
```python
# coding: utf-8

from __future__ import print_function

import os
import subprocess
import shutil

print('Loading function')


def run(event, context):
    root = os.path.abspath(os.path.join(__file__, ".."))

    os.environ["HOME"] = "/tmp"
    os.environ["GIT_EXEC_PATH"] = os.path.join(
        root, "usr/libexec/git-core"
    )
    os.environ["GIT_TEMPLATE_DIR"] = os.path.join(
        root, "usr/share/git-core/templates"
    )

    shutil.copy(os.path.join(root, "gitconfig"), "/tmp/.gitconfig")
    shutil.copy(os.path.join(root, "git-credentials"), "/tmp/git-credentials")

    path_to_git = os.path.join(root, "usr/bin/git")
    url = "https://github.com/shibataka000/snippets"
    path = "/tmp/snippets"

    cmd = "{} clone {} {}".format(path_to_git, url, path)

    p = subprocess.Popen(
        cmd,
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    p.wait()
    print("stdout:", p.stdout.readlines())
    print("stderr:", p.stderr.readlines())
```

## デプロイパッケージの作成
以下のスクリプトを実行する。

```bash
#!/bin/sh

ROOT=`pwd`
ZIP_FILE_NAME="project.zip"
ZIP_FILE=$ROOT/$ZIP_FILE_NAME

# pythonスクリプト
cd $ROOT
zip $ZIP_FILE *.py

# git設定ファイル
cd $ROOT
zip $ZIP_FILE gitconfig
zip $ZIP_FILE git-credentials

# gitバイナリ
cd /
zip $ZIP_FILE /usr/bin/git
zip $ZIP_FILE /usr/share/git-core -r

# /usr/share/git-coreをそのままデプロイパッケージに含めると50MBを超えてLambdaのデプロイパッケージのサイズ上限を超えてしまう
# そのため同一バイナリをシンボリックリンクに置き換える
cd $ROOT
mkdir usr/libexec -p
cp /usr/libexec/git-core usr/libexec -r
cd usr/libexec/git-core
for f in `ls`
do
    if [ -f $f -a ! $f = "git" ]; then
	diff "git" "$f"
	if [ $? = 0 ]; then
	    echo "ln -sf git $f"
	    rm $f
	    ln -sf git $f
	fi
    fi
done
cd $ROOT
zip $ZIP_FILE usr/libexec/git-core -r --symlinks
rm -r usr

# git-remote-httpsの依存ライブラリ
cd /usr/lib64/
zip $ZIP_FILE libcurl.so.4
zip $ZIP_FILE libssh2.so.1
zip $ZIP_FILE libpsl.so.0
zip $ZIP_FILE libcom_err.so.2
zip $ZIP_FILE libssl.so.10
zip $ZIP_FILE libicuuc.so.50
zip $ZIP_FILE libsasl2.so.2
zip $ZIP_FILE libicudata.so.50
zip $ZIP_FILE libstdc++.so.6
zip $ZIP_FILE libselinux.so.1
zip $ZIP_FILE libssl3.so
zip $ZIP_FILE libsmime3.so
zip $ZIP_FILE libnss3.so
zip $ZIP_FILE libnssutil3.so
cd /lib64
zip $ZIP_FILE libexpat.so.1
zip $ZIP_FILE libpcre.so.0
zip $ZIP_FILE libz.so.1
zip $ZIP_FILE libpthread.so.0
zip $ZIP_FILE librt.so.1
zip $ZIP_FILE libc.so.6
zip $ZIP_FILE libidn.so.11
zip $ZIP_FILE libplds4.so
zip $ZIP_FILE libplc4.so
zip $ZIP_FILE libnspr4.so
zip $ZIP_FILE libdl.so.2
zip $ZIP_FILE libgssapi_krb5.so.2
zip $ZIP_FILE libkrb5.so.3
zip $ZIP_FILE libk5crypto.so.3
zip $ZIP_FILE liblber-2.4.so.2
zip $ZIP_FILE libldap-2.4.so.2
zip $ZIP_FILE libcrypto.so.10
zip $ZIP_FILE libkrb5support.so.0
zip $ZIP_FILE libkeyutils.so.1
zip $ZIP_FILE libresolv.so.2
zip $ZIP_FILE libm.so.6
zip $ZIP_FILE libgcc_s.so.1
zip $ZIP_FILE libcrypt.so.1
zip $ZIP_FILE libfreebl3.so
```

# 比較

[LambdaでGitHubのプライベートリポジトリをcloneする - Qiita](http://qiita.com/shibataka000/items/910754486ba2585209b2)では[dulwich](https://github.com/jelmer/dulwich)（Pythonのgitライブラリ）を使用している。
gitバイナリを使う方法とdulwichを使う方法を比較する

## gitバイナリを使う方法
- メリット
    - 普段私達が使用しているのと同じgitバイナリを使用している。すなわちgitの機能が全て使える？
        - ただし今回はhttpsによるcloneができるところまでしか確認していない。他のgitサブコマンドを使う場合は更に依存ライブラリの解決が必要と思われる。
- デメリット
    - デプロイパッケージのサイズが大きくなる（20MB〜30MB）

## dulwichを使う方法
- メリット
    - （gitバイナリを使う方法と比べて）デプロイパッケージのサイズが小さい
- デメリット
    - サポートしていないgitの機能がある（submoduleなど）

# 参考
- [LambdaでGitHubのプライベートリポジトリをcloneする - Qiita](http://qiita.com/shibataka000/items/910754486ba2585209b2)
    - dulwich（Pythonのgitライブラリ）を使ってプライベートリポジトリをcloneする方法
- [shibataka000/snippets](https://github.com/shibataka000/snippets/tree/master/lambda_with_git_binary)
    - 今回使用したコード