uchan note

プログラミングや電子工作の話題を書きます

Python で Markdown 文書を HTML へ変換する

python-markdown2, py-gfm, pygments というライブラリを使って Markdown 文書を HTML へ変換するメモです。

GitHub Flavored Markdown (GFM) の特徴である Fenced Code Block にも対応しています。

インストール

$ pip3 install --user python-markdown2 py-gfm pygments pygments-style-github

スクリプト

md2html.py

#!/usr/bin/python3

import sys
from textwrap import dedent

from markdown2 import markdown


CHARSET = 'utf-8'


def main():
    if len(sys.argv) < 2:
        print('Usage: md2html path/to/file', file=sys.stderr)
        sys.exit(1)

    with open(sys.argv[1], encoding=CHARSET) as f:
        source = f.read()

    body = markdown(source, extras=['fenced-code-blocks'])
    html = dedent('''\
        <html>
        <head>
            <meta charset="{charset}">
            <link rel="stylesheet" type="text/css" href="github_pygments.css">
        </head>
        <body>{body}</body>
        </html>
        ''').format(charset=CHARSET, body=body)
    print(html)


if __name__ == '__main__':
    main()

CSS の準備

$ ~/.local/bin/pygmentize -S github -f html > github_pygments.css

変換

$ ./md2html.py hoge.md > hoge.html

おまけ:ブラウザから確認

手軽にブラウザから確認するには Python で HTTP サーバを立てると便利です。 この程度の静的 HTML なら直接ブラウザで開いてもいいのですが、HTTP サーバを立てればリモート開発している時も便利です。

$ python3 -m http.server 8000

8000 番ポートで起動します。

フリースタンディングな GCC 5.3 をビルド on Ubuntu 15.10

自作 OS 製作などでお世話になるフリースタンディングな GCC をビルドする手順のメモ。完全にきれいな環境でビルドしたわけではなく、依存関係をすべてメモに記載できていない。手順通りにビルドしてもツールが不足していたりしてエラーになることがあるが、悪しからず。

続きを読む

deb パッケージングメモ - alien 編

Ubuntudeb パッケージを作ろうとして調べ、実験したメモです。

なぜ自作ツールdeb パッケージを作るのか

開発したソフトウェアを Chef や Ansible などでデプロイするのに、apt-get install できると便利です。 deb にすることで、プログラム本体だけでなく、正しく動かすために必要なもろもろを deb 製作側の責任で作り込むことができます。 依存関係を考慮してくれたり、アップデートやアンインストールが容易なことも魅力です。

自作のプログラムに加え、Oracle Java のように tar.gz または rpm でしか提供されていないものを deb 化したいという需要もあります。

deb 化の方法の選択肢

プログラムを deb 化するに当たって、幾つかのやり方があります。

  • alien コマンドを使う
  • 正攻法でビルドする

alien

alien は tar.gz や rpm 形式のアーカイブを deb に変換するコマンドです。

tar.gz も rpmdeb も、基本的にはインストールするファイルをまとめて圧縮したものです。 したがって、ビルド済みのプログラムを含むアーカイブなら、簡単に変換できます。 Oracle Javadeb 化にはこの方法が合っていると思われます。

正攻法

dh_make や pdebuild を使い、ソースコードから deb パッケージを生成する方法です。

正攻法を正しく行うには事前の学習がそれなりに必要ですが、ビルド済みアーカイブがなくても良い点や、コンテナを用いたクリーンビルドができる点が優れています。 また、alien ではメタデータを細かく調整できなかったりしますが、正攻法ではその心配はありません。

正攻法はこの記事では扱いません。後日、別記事で書くかもしれません。書かないかもしれません。

alien を使って tar.gz から deb を作る

Oracle Java 8 JDK を例に、ビルド済みバイナリの tar.gz アーカイブを deb に変換する方法を紹介します。

まずはそのまま変換してみる

変換元のアーカイブが jdk-8u73-linux-x64.tar.gz であるとします。まずファイル名を希望するパッケージ名に変えます。

$ mv jdk-8u73-linux-x64.tar.gz oraclejdk8-jdk.tar.gz

Ubuntuリポジトリにある OpenJDK 7 のパッケージ名は openjdk-7-jdk なので、それに合わせて oraclejdk-8-jdk というように 8 の前にハイフンを入れたくなります。しかし、alien の制約で、数字の前にハイフンがあるとその数字以降が無視されてしまいます。恐らく、バージョン番号だから無視すべきと判断しているのでしょう。したがって、8 の前にはハイフンを入れない名前にしました。

いよいよ deb に変換します。

$ sudo alien -v --version=1.8.0.73 --bump=0 oraclejdk8-jdk.tar.gz

alien コマンドは root ユーザを要求します。sudo または fakeroot とともに実行してください。

出来上がったパッケージのバージョンを指定するのに --version オプションを使います。また、パッケージのリビジョン(debian バージョン)を指定するのに --bump オプションを使います。

--bump は変換元のリビジョンに加算する数値を指定するオプションで、デフォルトでは 1 です。tar.gz にはもともとリビジョン(およびバージョンも)がありませんから、リビジョンとして 1 が指定されているとみなされます。したがって、--bump を指定せずに実行すると oraclejdk8-jdk_1.8.0.73-2_amd64.deb というファイルが生成されます。

最初のパッケージなのにリビジョンが 2 になるのは気持ち悪いですね。ということで、例では --bump=0 として、リビジョンを増加させないように指示しています。oraclejdk8-jdk パッケージを一度でも外部に出した後、同じバージョンでビルドしなおすときは --bump を増やしましょう。リビジョンを上げておけば、APT の仕組みでアップグレードされるようになります。

alien コマンドがどのような処理をしているかを見たいので -v オプションを付けましたが、これは付けなくても動作は変わりません。

最後に出来上がったパッケージの中身を確認してみます。

$ dpkg -c oraclejdk8-jdk_1.8.0.73-1_amd64.deb | less

パッケージをインストールすると、ここで表示されたパスにファイルが配置されます。すべてのファイルが /jdk-1.8.0_73/ 以下に配置されることが分かりました。このパスは通常使われるインストール先ではありません。後ほど、ルートディレクトリを調整する方法を紹介します。

インストールスクリプトを含ませてみる

rpmdeb はインストール前後に実行するスクリプトを含むことができます。スクリプトを使うと例えば、配置したバイナリを update-alternatives に登録したりできます。

これをやるには、一旦アーカイブを展開し、スクリプトを含めた DEBIAN ディレクトリとともに圧縮しなおします。(アーカイブのファイル名は元に戻した前提で話を進めます。)

$ tar xzf jdk-8u73-linux-x64.tar.gz
$ mkdir DEBIAN
$ vim DEBIAN/postinst
$ chmod +x DEBIAN/postinst

postinst はインストールの後処理で呼ばれるスクリプトです。ファイルがすべて配置し終わった後に呼び出されます。 postinst の中身はなんでもいいですが、例えばこんな感じにしてみましょうか。

#!/bin/sh
for f in $(ls /jdk-1.8.0_73/bin/*); do
    update-alternatives --install /usr/bin/$f $f /jdk-1.8.0_73/bin/$f 1
done

このスクリプトはインストールされたすべてのコマンドを update-alternatives に登録します。update-alternatives は、/usr/bin/java などをシンボリックリンクにし、実際に指すコマンドを手軽に切り替えられる仕組みです。

スクリプトを含めた deb パッケージを生成してみます。

$ tar czf oraclejdk8-jdk.tar.gz jdk-1.8.0_73/ DEBIAN/
$ sudo alien -v --version=1.8.0.73 --bump=1 oraclejdk8-jdk.tar.gz

oraclejdk8-jdk_1.8.0.73-2_amd64.deb をインストールしてみると、最後の方で update-alternatives が実行されるのを確認できます。

インストール先を調整してみる

これまでのやり方では、インストール先が /jdk-1.8.0_73 となってあまり綺麗ではありません。標準的には /usr/opt にインストールすることになっていますから、それに従うように調整してみます。

これには、tar で展開するときにオプションを使って調整してしまうのが楽です。

$ mkdir -p opt/oraclejdk8-jdk
$ tar xzf jdk-8u73-linux-x64.tar.gz -C opt/oraclejdk8-jdk --strip-component 1

tar コマンドは -C オプションで展開先を指定できます。さらに --stript-component 1 で先頭から 1 つのパスを削りつつ展開するよう指示しています。これらを組み合わせると opt/oraclejdk8-jdk/bin/java などに展開できます。

インストール先を変えたので、postinst も変更しておきましょう。ls /jdk-1.8.0_73/bin/*ls /opt/oraclejdk8-jdk/bin/* に変えれば OK です。

あとはアーカイブを作り alien を実行するだけです。

$ tar czf oraclejdk8-jdk.tar.gz opt/ DEBIAN/
$ sudo alien -v --version=1.8.0.73 --bump=2 oraclejdk8-jdk.tar.gz
$ dpkg -c oraclejdk8-jdk_1.8.0.73-3_amd64.deb | less

どうでしょうか。/opt/oraclejdk8-jdk 以下にインストール先を変更できたことが分かるはずです。

楽しい仕様書と生産性に関する考察

結論:楽しい仕様書は将来にわたってチームの生産性を向上させる。

仕様書を書く効果

『Joel on Software』(オーム社 2005)でジョエルはこんなことを書いている。

仕様書の最も重要な役割はプログラムをデザインすることだ。」

仕様書を書くには設計することを強いられる。 仕様書段階での設計は、実装しながらする設計に比べてはるかに簡単にレビューでき、手直しできるので、生産性の向上につながる。 ジョエルはこうも言っている。

「大きな理由の2番目はコミュニケーションにかかる時間を節約できるということだ。」

仕様書を1度書くだけで、実装時やテスト時に何度も参照され、コミュニケーションコストを大幅に節約するし、認識の齟齬を防げる。 このとき、ちゃんと皆に仕様書を読んでもらうには、楽しく(可笑しく)読める仕様書が大切になってくる。

先ほどの設計の話と合わせて、仕様書を書くということは開発からテスト、保守まで含めた生産性を向上させることは明らかだ。

期日を設けない場合の生産性

話は変わって『Peopleware』(日経BP社 2013)を取り出そう。ニューサウスウェールズ大学での調査の結果として、こんなことが書いてある。

「上司が日程的なプレッシャーを少しもかけなかったプロジェクトは、最高の生産性を示した」

私の個人的な経験から、生産性が高いのはやるべきことがはっきりしている、つまりどうやって実装したらいいか道筋が見えているときだ。 そういうときは、期日の目標値を定められないで放任されるほど、高品質なものが早く完成する傾向にある。 仕事への誇りからくる高生産性だと思う。

逆に、生産性が低いのは、対象の理解ができておらず、何から手を付けるか分からないときである。 こういうときは、タスクをやらなくちゃと思いつつ、何も進まずに非生産的な時間を過ごしてしまう。 強制的に期日の目標値を定めてもらわないと仕事が進まないケースだ。

このように、上司が強制的に期日を設定するのが必要なときもある。 しかし、その生産性は、やるべきことが見えているときに放任される場合の生産性よりずっと低い。

チームの生産性を最高に保つ

チームの生産性を常に最高に保つにはどうすればよいか。 自分たちのチームに新たに配属された人が、そのチームで作っているソフトウェアをよく理解できるようにしておくことだと思う。 もちろん、そうしておけば新人だけでなく既存メンバーがよりよくソフトウェアを理解することにもつながる。

メンバーが対象ソフトウェアをよく理解していれば、ソフトウェアの修正タスクに対する実現方法が思いつきやすくなる。 この状態になれば、期日を設定せずタスクを割り当てることができ、自動的に最高の生産性を発揮するはずである。

つまり、楽しく読め、きちんと対象を理解できるような仕様書をいつでもちゃんと書いておくことは、 後々、そのチーム全体の生産性を最高の状態に保つことにつながる。

Git で deb パッケージング

Git で管理しているソフトウェアを deb パッケージにしたいことがあります。 本記事は、1 つの Git リポジトリの中でソフトウェア本体と deb パッケージのメタデータを管理する方法を説明します。

2016/02/29追記:ここで紹介するブランチ構成には問題があることが分かりました。 debian ブランチを master に rebase した後、debian ブランチを push できないのです。 rebase する代わりに debian_1.0.1 のようなブランチを作り、cherry-pick するといける気がします。

目次

続きを読む

KiCad Pcbnew 各レイヤの役割

概要

KiCad のプリント基板エディタ Pcbnew の各レイヤの役割をメモします。

この記事は KiCad 4.0.1-stable を対象に記述しています。古いバージョンではレイヤ名が日本語になっていたりと違いがあるようです。バージョン 4.0.1 に対応した体系的な説明が見つからなかったので、独自に調べてまとめてみました。

続きを読む

MOSFET を用いた双方向レベル変換回路の考察

前回の記事 で紹介したレベル変換回路(level shifter)の動作を説明し、MOSFET の機種選択の考慮点を考えます。結論は、MOSFET のゲートしきい値電圧が高い機種は使えないので注意しましょうということです。

続きを読む