無限Streamに終了条件を設定する (Java9版)
というのを以前書きましたが、Java9では Stream#takeWhile
というメソッドが追加されてこういうケースが簡単に書けるようになりました。
public static String getTreePathTakeWhile(Node node, String delimiter) { List<String> names = Stream.iterate(node, Node::getParent) .takeWhile(n -> n != null) .map(n -> n.getName()) .collect(Collectors.toList()); Collections.reverse(names); return delimiter + String.join(delimiter, names); }
これでSupplierを使った無限Streamがとても使いやすくなりますね。
必要最低限のrequirements.txtを作成する
シチュエーション
Pythonでつくったサーバーアプリを環境へのデプロイするために、依存モジュールのバージョンを固定したrequirements.txtを作りたいけど、開発環境のPython環境がだいぶ使い古しで、試しに導入した不要なモジュールもあるので、単純にpip freeze
しちゃうと余計なモジュールが大量に混ざってしまう…なんてときの対処法。
手順
注(2019/12/08追記):
この記事では Docker を使った方法を説明していますが、 Python だけ気にするのであれば virtualenv を使用する方法のほうがシンプルかつ早いので、そちらを使用しましょう。
Dockerできれいな仮想環境を作る
とりあえず、pyenvでPythonをインストールできる最低限の環境を作ります。導入するモジュールによっては追加が要るかも。
以下のようなDockerfile
を作る。とりあえずUbuntu14ベースで作ってますが、他のディストロならもうちょっとシンプルになるかも。
FROM ubuntu:14.04 ARG http_proxy ARG https_proxy ENV http_proxy=${http_proxy:-} \ https_proxy=${https_proxy:-} RUN apt-get update && apt-get install -y \ build-essential python git curl zlibc zlib1g-dev \ libssl-dev libreadline-dev libbz2-dev libsqlite3-dev \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /root RUN git clone https://github.com/yyuu/pyenv.git .pyenv ENV PATH /root/.pyenv/bin:$PATH RUN echo 'eval "$(pyenv init -)"' >> .bashrc CMD ["/bin/bash", "-i"]
これを適当なディレクトリに置いてdocker build
します。
$ cd clean_pyenv # 上記Dockerfileがおいてあるディレクトリに移動 # 直接インターネットが見られる環境の場合 $ docker build -t clean_pyenv ./ # プロキシが必要な場合 $ docker build --build-arg http_proxy=$http_proxy --build-arg https_proxy=$https_proxy -t clean_pyenv ./
仮想環境内で、pyenvを使ってターゲットバージョンのPython環境を作る
上記で作ったDockerイメージにはpyenv
がインストール済みなので、これを使って必要な環境を作っていきます。
コンテナを起動してログイン、pyenv install
で目的のバージョンをインストールして切り替えます。
$ docker run -it --rm clean_pyenv $ pyenv install 2.7.13 $ pyenv global 2.7.13
アプリから直接参照しているモジュールのリストを用意してpip install -r
した後、pip freeze
する
例として、アプリから直接参照している外部モジュールがboto3 1.4.4
だけだとします。
(モジュールがたくさんあるようであれば、列挙したテキストファイルを別のターミナルからdocker cp
で送り込んであげればよいです。モジュールバージョンが最新でよければ、バージョン番号は省略でもOK)
$ echo boto3==1.4.4 > reqirements_part.txt $ pip install -r reqirements_part.txt $ pip freeze > requirements.txt
これで、依存モジュールも含むrequirements.txt
が生成されるはずです。
途中間違えたら、コンテナからログアウトして終了してしまえば、pyenvだけのきれいな状態からやり直すことができます。もちろんDockerイメージは再利用可能。
Gitでローカル・リモート一緒にブランチ名を変更したい
Git 2.11.1で確認。
シチュエーション
hage
ってブランチ作って、
$ git checkout -b hage
諸々修正して、
$ git commit -a $ git push -u origin hage
commit・pushした後に、
「あれ、ブランチ名間違えた。hoge
だった」
ということで、ローカルとリモート併せて名前変えたい。
失敗例
upstreamブランチをリモートから削除して
$ git push --delete origin hage
ローカルブランチの名前を変えて
$ git checkout hage $ git branch -m hoge
そのまま再push!
$ git push -u origin hoge ... * [new branch] hoge -> hage ~~~~
あれー?
$ git push --delete origin hage $ git branch -vv ... hoge ff0da9d [origin/hage: gone] .... ...
リモートのブランチが消えても、一度設定されたupstreamの向き先は残ってるっぽい。
解決
upstreamブランチを削除してローカルブランチ名変えた後、明示的にupstream設定を削除する必要があるようです。
$ git branch --unset-upstream
その後、再push
$ git push -u origin hoge ... * [new branch] hoge -> hoge ~~~~
めでたしめでたし。
atom 1.9.x + graphviz-preview の表示バグの回避
Atom を使っていて、ちょっと図を書いて整理したいなんてときに便利な graphviz-preview ですが、2016/8/27現在、graphviz-previewの更新が、対応バージョン1.7.0で止まっており、現時点の最新である1.9.8で使用するとこんなことになってしまいます。
そのうち修正されてほしいなあと思いつつ、とりあえずの回避方法。
$HOME/.atom/packages/graphviz-preview/styles/graphviz-preview.less
をテキストエディタで開き、以下のwebview要素のstyleを追記します。
// The ui-variables file is provided by base themes provided by Atom. // // See https://github.com/atom/atom-dark-ui/blob/master/styles/ui-variables.less // for a full listing of what's available. @import "ui-variables"; .graphviz-preview { background-color: #fff; overflow: scroll; box-sizing: border-box; padding: 0; iframe { width: 100%; height: 100%; border: 0; } // ここから追記 webview { width: 100%; height: 100%; border: 0; } // ここまで追記 }
するとこんな感じに。 スクロールバーが二重で表示されるのカッコ悪いんですが、とりあえず使うのには困らないので、これでしのぎながら公式のアップデートを待ちます…
2016/08/28 追記
.graphviz-preview
クラスと webview
要素に overflow: none;
を設定してやると余分なスクロールバーが消えました。実際のスクロールバーは、webview内に貼られるobjectが表示してくれるようです。
// The ui-variables file is provided by base themes provided by Atom. // // See https://github.com/atom/atom-dark-ui/blob/master/styles/ui-variables.less // for a full listing of what's available. @import "ui-variables"; .graphviz-preview { background-color: #fff; overflow: none; // scroll -> none box-sizing: border-box; padding: 0; iframe { width: 100%; height: 100%; border: 0; } // ここから追記 webview { width: 100%; height: 100%; border: 0; overflow: none; } // ここまで追記 }
追記:Let's Encrypt のDV証明書更新
この記事の続きというか補足。
自サイトをHTTPS化してみた - NoisySpot/メモ帳
Let’s Encryptで発行されるDV証明書の有効期限は90日間と短めに設定してありますが、Certbotのクライアントツールを使用していれば更新は簡単。コマンド一発です。
$ sudo letsencrypt renew
確認のためのDry runも可能です。(--dry-run
オプション)
ただ、このコマンドは証明書が失効する前に実行しても、何もしてくれません。つまり証明書が期限切れ状態となる期間が発生してしまいます。
Certbotの解説によれば、cronやsystemdでの1日2回の実行が推奨されていますので、失効する期間を最小限にするためにも、こちらに従って定時バッチ化しておくのがいいと思います。
(2017/05/10 修正)
誤ってEV証明書と記載していた箇所をDV証明書に修正。今のところ、Let’s EncryptでEV、OV証明書は取得できません。
自サイトをHTTPS化してみた
はてなブログでホストしていただいている等ブログの他に、勉強のために自ドメインでサイトを構築しております。 (内容はあまりありません。日記的ブログだった残骸があるだけです…)
で、なんか最近調子が良くなかったので、OSごと再構築しまして、ついでに Let's Encrypt のDV証明書を利用してHTTPS化してみました。
以下は手順メモです。
作成時の環境
- Ubuntu 16
- Nginx 1.10.0
- OpenSSL 1.0.2g
クライアントツールの取得と申請~証明書発行
Let's Encrypt への申請、認証、証明書発行の一連の流れを自動化してくれるクライアントツールは、対象の環境や実装手段によりいくつか開発されているようです。Let's Encrypt推奨の方法としては、以下のCertbotというサイトでWebサーバとOSを選択して、表示された手順に従うというものでした。今回はそれに従いました。
まずは apt でクライアントツールを導入します。
$ sudo apt-get update $ sudo apt-get install letsencrypt
で、nginxを起動した状態で、letsencrypt
コマンドを打ちます。
$ letsencrypt certonly --webroot -w [[Webサーバのドキュメントルートのパス]] -d [[申請するドメイン名]]
すると、CUIが立ち上がり、メールアドレスを要求してくるので入力します。申請失敗時などはここで入力したアドレスに連絡が飛んで来るようなので、使えるアドレスを入力する必要があります。
メールアドレスを入力し、利用規約などをAgreeすると、申請・認証が開始します。以下の様な流れで動作するようです。
- メールアドレスとドメイン名をLet's Encryptに送付して発行申請する。戻り値としてシグネチャが返される。
- Webサーバのドキュメントルートに
.well-known/acmechallenge/
ディレクトリを作成し、返されたシグネチャを格納 - Let's Encryptのサーバから、
http://[[申請したドメイン]]/.well-known/acmechallenge/
のリクエストを飛ばし、取得したシグネチャと発行したものが同一となればドメイン所有者認証の完了 - 証明書と鍵がLet's Encryptから発行され、クライアントツールはそれらを所定の場所に格納する。
以上がコマンド実行から2分くらい放置で完了。簡単!
上記コマンド完了後 /etc/letsencrypt
に下記のファイルが格納されます。
. |-- accounts | `-- acme-v01.api.letsencrypt.org | `-- directory | `-- [[ハッシュコード]] | |-- meta.json | |-- private_key.json | `-- regr.json |-- archive | `-- [[ドメイン名]] | |-- cert1.pem | |-- chain1.pem | |-- fullchain1.pem | `-- privkey1.pem |-- csr | `-- 0000_csr-certbot.pem |-- keys | `-- 0000_key-certbot.pem |-- live | `-- [[ドメイン名]] | |-- cert.pem -> ../../archive/[[ドメイン名]]/cert1.pem | |-- chain.pem -> ../../archive/[[ドメイン名]]/chain1.pem | |-- fullchain.pem -> ../../archive/[[ドメイン名]]/fullchain1.pem | `-- privkey.pem -> ../../archive/[[ドメイン名]]/privkey1.pem `-- renewal `-- [[ドメイン名]].conf
Nginxから参照するのは以下の2ファイルです。(再発行時にそなえ、ファイル実体を直接参照するより、live以下のシンボリックリンクを参照するほうがよいでしょう)
- サーバ証明書
/etc/letsencrypt/live/[[ドメイン名]]/fullchain.pem
- 秘密鍵
/etc/letsencrypt/live/[[ドメイン名]]/privkey.pem
この時点で、ドキュメントルートの .well-known
ディレクトリは削除しておきます。
ちなみに、WebサーバがApache2等の場合、letsencryptのサブコマンド(上記の certonly
)を run
とすると、上記の証明書発行に加え、Webサーバの設定ファイルの更新までやってくれるようなのですが、現時点ではNginxはそこまでサポートされていないようです。
なので、以下はNginxへの個別設定となります。通常のhttpsサイト構築とあまり変わらないと思いますので、その辺ご存じの方は、サーバ証明書と秘密鍵の格納場所がわかれば十分でしょう。
DHパラメータファイルの作成
TLSの暗号化アルゴリズムの一つ、Diffie-Hellman暗号で使用するDHパラメータファイルを作成します。
$ sudo openssl dhparam 2048 -out /etc/nginx/dhparam.pem
`2048' は生成するビット長です。数値が大きいほど生成に時間がかかりますが、小さいと脆弱になるので、とりあえずLogjam Attack対策での推奨値である2048を設定しました。うちの環境(2CPUのVPS)で1分くらいで生成完了。 ファイルパーミッションは600にしておきます。
Nginxの設定
/etc/nginx/sites-available/
以下に任意の名前でファイルを作成し、サイト設定を記入します。
server { listen 80; server_name www.noisyspot.jp; return 301 https://$server_name$request_uri; # httpにリクエストが来たらpermanent redirectでhttpsに飛ばす } server { listen 443 ssl default_server; listen [::]:443 ssl default_server; ssl_certificate /etc/letsencrypt/live/[[ドメイン名]]/fullchain.pem; # サーバ証明書 ssl_certificate_key /etc/letsencrypt/live/[[ドメイン名]]/privkey.pem; # 秘密鍵 ssl_session_tickets on; ssl_dhparam /etc/nginx/dhparam.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!aNULL!eNull:!EXPORT:!DES:!3DES:!MD5:!DSS'; ssl_prefer_server_ciphers on; (以下略)
ssl_protocols
と ssl_ciphers
は、暗号化仕様の使用制限に関する設定です。今回は以下のサイトを参考にしました。
このへん、脆弱性が見つかっては新しい物が策定されが繰り返し、またWebサーバやブラウザ側のサポート状況にもよりますので、世間に注意しつつ定期的に更新していく必要があるでしょう。
あとは、/etc/nginx/sites-enabled/
から、上記で作成したサイト設定ファイルへのシンボリックリンクを張り、defaultのシンボリックリンクを削除すれば、設定は以上です。念のため nginx -t
で設定ファイルのバリデーションをした後、 systemctl restart nginx
サービスを再起動すればOK。
Emacsへのphp-mode, php-completion の導入方法
下記の参考資料通りにやってみたところいくつかエラーが出たので、試行錯誤して正常にインストールできた手順をメモ。
前提
- Emacs 24 (本記事は gnupack版Emacs for Windows 24.2.1でテスト)
- melpa, marmalade のパッケージマネージャが使用可能であること
必要なパッケージのインストール
M-x package-install-package
でパッケージの一覧を表示し、以下のパッケージをインストールする。
cl-lib
anything
auto-complete
php-mode
php-completion
cl-libはphp-modeインストール時に一緒に入るが、それ以外は個別に入れること
init.elの設定
init.elに以下のスクリプトを追記。(入力補完は C-o
にバインドしていますが、他のキーにしたい場合は (kbd "C-o")
の部分を変えてください)
(require 'php-mode) (add-hook 'php-mode-hook (lambda () (require 'php-completion) (php-completion-mode t) (define-key php-mode-map (kbd "C-o") 'phpcmp-complete) (make-local-variable 'ac-sources) (setq ac-sources '( ac-source-words-in-same-mode-buffers ac-source-php-completion ac-source-filename ))))
2016/07/02追記
別の環境でインストールしようと思ったら、パッケージリストにphp-completionが出てこなかったので原因調査中です… →php-completionパッケージはmelpaではなくmarmaladeにありましたので前提に追記。