その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

JenkinsでGitHub Pull Request Builder pluginを使いつつ任意のブランチにpushしたコミットもビルドする

JenkinsでGitHub Pull Request Builder (ghprb) を使っている時に,pull request以外のcommit (例えばmasterへのマージコミットや任意のブランチへの直push) もbuildしたいんすよね〜みたいなことをid:hdkshjmさんに相談したところ良い感じの方法を教えてもらったのでメモとして記すものです.ありがとうございます!

前提として

  • ghprbの設定は済んでいる
  • Git pluginがインストールされている
  • GitHub pluginがインストールされている
  • GitHubリポジトリのWebhook設定で $JENKINS_BASE_URL/github-webhook/ に向けてpushイベントを設定している

ものとします.

そんでもって以下のようにすると良い:

  • プロジェクト設定のGit SCMのリポジトリ設定でRefspecに +refs/pull/*:refs/remotes/origin/pr/* +refs/heads/*:refs/remotes/origin/* を指定する (高度な設定から設定できる)
    • ghprbではpull requestだけがターゲットなので +refs/pull/*:refs/remotes/origin/pr/* を指定しておけば良い
    • それに加えて +refs/heads/*:refs/remotes/origin/* を指定することによって任意のブランチへのpushも引っ張ってこれるようにしておく
  • 「ビルドするブランチ」にビルドしたいブランチの名前 (e.g. master, develop and etc) を指定する
    • ghprb向けには ${sha1} とか設定されているはずなので *1,そこに追加するという感じ
  • トリガ設定で GitHub hook trigger for GITScm polling にチェックを入れる

これでOK! 例えば「ビルドするブランチ」に master を設定しておけばmasterへのマージコミットや直push (まあ野蛮!) についてもbuildを回すことができて便利です.
pull-requestについてはghprb pluginがbuildをキックし,一方で指定したブランチへのpushについてはGitHub pluginがbuildをキックするという感じです.基本的に互いが重複してbuildをキックすることは無いでしょう (「ビルドするブランチ」に指定したブランチを他のブランチに向けるpull-requestを作ったら話は別ですが).


ところでJenkins 2.0以降を使っている場合Jenkinsfile及びパイプラインが使えますから,pipeline-githubあたりを駆使するとgroovyでプログラマブルに色々操作できるため,今となってはghprbを使わずにJenkinsfileでやったほうが良いかもわかりませんね.そう思います.現場からは以上です.

*1:${ghprbActualCommit} if you want to use the head of the pull request branch (e.g. refs/pull/4/head); or ${sha1}, to use GitHub's tentative merge of the compare and base branches (e.g. refs/pull/4/merge) if the PR can be automatically merged or the head of the pull request branch (e.g. refs/pull/4/head) if they can not be automatically merged. GitHub - jenkinsci/ghprb-plugin: github pull requests builder plugin for Jenkins

Over HTTPでやり取りするAWS Lambdaのfunctionを書く時にはKeep-Aliveがパフォーマンスに効く(場合がある)

サーバレスだ! Microservicesだ! というふうなアーキテクチャになってくるとAWS Lambdaのような実行環境でコードを動かすことが多くなってくると思います.そしてそうした環境下で他のコンポーネントとHTTP越しにやりとりをするコードを動かすこともままあるでしょう.
そういった時にKeep-Aliveを有効にしておくとLambdaは一度張ったコネクションを使いまわしてくれるので,「同じエンドポイントを頻繁に叩く」かつ「呼ばれる回数が多い」Lambda functionだと結構パフォーマンスに効いてきます (もちろん接続先がkeep-aliveに対応している必要がありますが).

ということをLambdaのパフォーマンス周りのトラブルシューティングを行っている最中にふと気づき,やってみたところ果たしてパフォーマンスの問題は見事解決したわけですが,その後AWSが出しているLambdaのベストプラクティスのドキュメントを読んでみるとまさに同じことが書いてあり,やはり公式のドキュメントは強い……

> 前回の呼び出しで確立した接続を (HTTP、データベースなど) をキープアライブにして再利用します
AWS Lambda 関数を使用する際のベストプラクティス - AWS Lambda

AWS Lambdaはそのプロセスが立ち上がってからはライフサイクルに従って一定期間同一のプロセスが使用されるので,一度確保したリソースを使い回すことができます.従ってKeep-Aliveを有効にしておくと一度確立したコネクションを使いまわしてくれるため,コネクションを毎度張らずに済んでそのぶんの実行コストが減って経済的という感じです.助かった!


なお他のコンポーネントとOver HTTPでコミュニケーションするタイプのLambdaのアーキテクチャの是非についてはid:y_uukiさんのブログに良い考察があります:


ところで

この件ですがみなさんはどう呼んでいますか? おたよりをお待ちしています.

builderscon tokyo 2018に登壇します

表題の通り,builderscon tokyo 2018に登壇します.JavaCardという環境をテーマにお話する予定です.

builderscon.io

今回はかなりマニアックな話になることが現時点で予想されていますが,内容はかなり面白いと思います (先日社内の専門家にディープな講習を受けました). いつものJavaとは一味違うJavaを目の当たりにすることになるでしょう……

9/7 (金) の15:30からセッション開始ですから,お昼から会場内のHUBで一杯引っ掛けてから来てもちょうど良い感じの時間ですね! 是非会場でお会いしましょう!!!!

pptxファイルから発表者ノートを一括削除する方法

カンペとしてスライドに発表者ノートを書くことはままあるとおもうんですが,そのスライドを共有する際には発表者ノートを削除したくなるのが人情というものです (カンペを見られるのは恥ずかしい).
Windows版のPowerPointであれば発表者ノートを一括削除するメニューがあるのですが,一方macOS版のPowerPointにはなぜかそのメニューが無いため手でポチポチやるしか方法は無いのか……と途方に暮れていたところ,pptxはそもそもzipでアーカイブされたxmlの集合体ということを思い出し,unzipしてxmlを書き換えてzipし直すという手法を思いつきました.

以下スクリプト:

#!/bin/bash

set -eu

PPTX_FILE_PATH="$1"
PPTX_FILE="$(basename "$PPTX_FILE_PATH")"

TMP_DIR="$(mktemp -d)"
trap 'rm -rf $TMP_DIR' EXIT

cp "$PPTX_FILE_PATH" "$TMP_DIR"

pushd "$TMP_DIR"

unzip "$PPTX_FILE"
rm "$PPTX_FILE"
gfind ./ppt/notesSlides/*.xml | xargs gsed -i'' -e's/<a:t>[^<]*<\/a:t>/<a:t><\/a:t>/g' # remove slide note contents
zip -0 -r "$PPTX_FILE" ./* # do not compress (-0)

popd

cp "$TMP_DIR/$PPTX_FILE" "note-removed-$PPTX_FILE"

これで発表者ノートを消すべきpptxファイルがたくさんあっても安心! よかったですね.

ESP32でZephyrを開発する環境を整える - macOS編

ZephyrはApache Lisence, Version 2.0で公開されているRTOSです.多分「ゼファー」と読むはず.
https://www.zephyrproject.org/

このZephyrをESP32のボードで開発する環境をmacOS上に整えるというのがこの記事の目的です.
なおESP32開発ボードは今回以下を使いました: http://akizukidenshi.com/catalog/g/gM-11819/

基本的にZephyrの以下のドキュメントに従うとできます:

http://docs.zephyrproject.org/getting_started/installation_mac.html
http://docs.zephyrproject.org/boards/xtensa/esp32/doc/esp32.html

事前準備
$ brew install direnv cmake ninja dfu-util doxygen qemu dtc python3 gperf

開発環境が問答無用でSystemのPython3を見てくるのでインストールする必要があります.direnvはあるとなにかと便利なので入れています.

(上記開発ボードを使っている場合) CP210x USB to UART Bridge VCP driversを入れる

https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers

もしもmacOS High Sierra以降を使っている場合は Security & Privacy でインストール時にBlockしているソフトウェアベンダーをAllowする必要があります (Silicon Laboratoriesとか).
これがないと開発ボードがシリアルデバイスとして認識されない.

Espressif Toolchainを入れる
$ mkdir -p ~/opt/esp
$ cd ~/opt/esp
$ curl -O https://dl.espressif.com/dl/xtensa-esp32-elf-osx-1.22.0-80-g6c4433a-5.2.0.tar.gz
$ tar zxf xtensa-esp32-elf-osx-1.22.0-80-g6c4433a-5.2.0.tar.gz

xtensa-esp32-elf-osxのバージョンについては実際どこを見れば最新なのかがわからなかった (ダウンロード可能なバージョン一覧が取れるページを見つけられなかった) ので,雑に調べて出てきたものを使っています.
確証はありませんが,
arduino-esp32/package_esp32_index.template.json at master · espressif/arduino-esp32 · GitHub
の中身に書いているやつを使っておけば良いような気がしています (espressifの公式リポジトリだし).

ESP32 IDFを入れる

要はRTOS SDKです.

$ git clone --recursive https://github.com/espressif/esp-idf.git
$ cd esp-idf
$ git checkout dc8c33892e0

espressifのリポジトリからESP32 IDFをcloneしてきます.
加えてZephyrのドキュメントにあったので,IDFのリビジョンを過去のものに固定しています.

Since ESP-IDF is an external project in constant development, it’s possible that files that Zephyr depends on will be moved, removed, or renamed. Those files are mostly header files containing hardware definitions, which are unlikely to change and require fixes from the vendor. In addition to setting the environment variables above, also check out an earlier version of ESP-IDF
http://docs.zephyrproject.org/boards/xtensa/esp32/doc/esp32.html

Zephyrをダウンロードして諸々の開発環境を整える
$ git clone git@github.com:zephyrproject-rtos/zephyr.git /path/to/zephyr
$ cd /path/to/zephyr
$ pip3 install --user -r scripts/requirements.txt
$ cat <<EOS >> .envrc

export PATH="$PATH:$HOME/opt/esp/xtensa-esp32-elf/bin
export ZEPHYR_TOOLCHAIN_VARIANT="espressif"
export ESP_IDF_PATH="$HOME/opt/esp/esp-idf"
export ESPRESSIF_TOOLCHAIN_PATH="$HOME/opt/esp/xtensa-esp32-elf/"

source ./zephyr-env.sh
export ESP_DEVICE="/dev/cu.blahblah" # ここは開発ボードによって変わるでしょう
export ESP_BAUD_RATE=115200 # ここは開発ボードによって変わるでしょう
export ESP_FLASH_SIZE="detect"
export ESP_FLASH_FREQ="40m"
export ESP_FLASH_MODE="dio"

EOS
$ direnv allow

ZephyrはGitHubで公開されているので普通にgit cloneしてくれば良いです.
次にpythonで書かれたツールを動かすための依存ライブラリをインストールします.このコマンドではSystem python以下に依存ライブラリが入ります (system pythonを使わずに済ます方法は無いものか……).
あとは諸々の環境変数を.envrcに書き込んでdirenvでそれらを有効にしてやる.

Hello-Worldを動かしてみる
$ cd "$ZEPHYR_BASE/samples/hello_world"
$ mkdir build && cd build
$ cmake -DESP_IDF_PATH="$ESP_IDF_PATH" -GNinja -DBOARD=esp32 ..
$ west flash \
   --esp-device="$ESP_DEVICE" \
   --esp-baud-rate="$ESP_BAUD_RATE" \
   --esp-flash-size="$ESP_FLASH_SIZE" \
   --esp-flash-freq="$ESP_FLASH_FREQ" \
   --esp-flash-mode="$ESP_FLASH_MODE"
$ screen $ESP_DEVICE $ESP_BAUD_RATE # and push reset button

以上のようにコマンドを叩くとプログラムのビルドとボードへの書き込みを行うことができます.
公式ドキュメントでは ESP_DEVICEESP_BAUD_RATE といった環境変数を設定しておくと ninja flash コマンドはそれらをリスペクトするように書いてあるが,実際にそのような処理が行われている気配はない (ざっとコードを読んだ) ので, ninja コマンドの代わりに west を利用し,そのコマンドラインオプションで各種設定を与えるようにしています.
あとはscreenでTTYにつないでボードのリセットボタンを押すと "Hello World: esp32" が表示されるはずです!


以上です.これでmacOS上でESP32向けのZephyrプログラムが開発できます.やりましたね.

Scrapboxのコンテンツエリアが広いと嬉しい!!!!

scrapbox.io
ユーザースクリプト機能で以下のCSSを読み込ませると……

.page-wrapper{
  width:100%;
  position: absolute;
  left: 0px;
}
.col-page-side{
  position: absolute;
  right: 0px;
}

f:id:moznion:20180601134210p:plain

嬉しい!!!!

expectコマンドを使ってシリアル接続で非対話的にコマンドを流し込む

シリアル接続でコマンドを実行する際は cu コマンドや screen コマンドなどでシリアルコンソールに接続して対話的にコマンドを実行することになると思うんですが,しかし「一定周期ごとにシリアルでコマンドを実行して結果を取得したい」みたいなときに対話モードだとだるいわけです.
というわけで expect の出番です.以下のように expect コマンドを利用すると非対話的にシリアルにコマンドを流し込むことができます. expect コマンドについてはこちらを参照されたい:
expect(1) - Linux man page

expect -c "
  spawn cu -l ${TTY} -s 9600
  send \"AT+CGREG=2\\n\"
  expect \"OK\"
  send \"AT+CGREG?\\n\"
  expect \"+CGREG:\"
  exit 0
"

これは

soracom.zendesk.com

にあるLACとCIDを取得するATコマンドの例ですが,こうしてやることで非対話的にATコマンドを流し込むことができます.

while :
do
  RESULT="$(expect -c "
    spawn cu -l ${TTY} -s 9600
    send \"AT+CGREG=2\\n\"
    expect \"OK\"
    send \"AT+CGREG?\\n\"
    expect \"+CGREG:\"
    exit 0
  " | grep '^+CGREG:')"

  PCRE_LAC_CID_PATTERN='"(.+?)",\s*"(.+?)"'
  LAC="$(echo "$RESULT" | perl -ale "/${PCRE_LAC_CID_PATTERN}/; print \$1")"
  CID="$(echo "$RESULT" | perl -ale "/${PCRE_LAC_CID_PATTERN}/; print \$2")"

  echo "{\"LAC\":$LAC, \"CID\":$CID}"

  sleep 60
done

例えばこうしてやると1分ごとにcell locationが取れて便利.expect コマンド最高!!!! (しかし難しい)