標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

xnhttpd に静的コンテンツ&markdownテキストの発信機能をつけました

前回:「CGIをローカルテストするための簡易ウェブサーバー xnhttpd をGoで書きました 」で実装した CGIテスト用ウェブサーバー xnhttpd に、静的コンテンツや markdown を発信する機能を実装しました。

markdown プレビューアとして、これまで mkup を使っていたのですが、自分好みのスタイルシートを使いたかったのと、もう少しウェブサーバーを作り込んでみたかったというのが開発動機です。

  • 拡張子が .jpg , .gif , .html の時、xnhttpd のカレントディレクトリ以下にそのファイルがあれば、そのまま静的コンテンツとして発信するようにした
  • 拡張子が .md の時は、同ファイルを yuin/goldmarkmarkdown → HTML 化してから発信する
  • markdown テキストの時の CSS は 本当は GitHub のやつを使いたかったが、ソースを見ても複雑すぎてよう分からんので(汗)、適当に wifky に使われているデフォルトのやつをベタでくっつけた。

TO DO

  • ディレクトリを指定された時は index.html もしくは readme.md を出力するようにする
  • CGI機能を使わず、markdown プレビューアとしてだけ使う時、今のところ echo {} | xnhttpd としないと標準入力からの EOF 待ちになってしまう。もう設定ファイル入力なりオプションなりを検討する

以上

CGIをローカルテストするための簡易ウェブサーバー xnhttpd をGoで書きました

これな

今は昔、wifky という 1ファイルで動作するPerlWikiEngine を開発していました。当時は、AN Httpd でローカルテストしてからサーバーにアップするということをしていたのですが、その後、AN Httpd は公式サイトは閉鎖され、パブリックなサポートがなくなってしまいました。

当時はもう真面目に wifky も保守しなくなっていて困ってもなかったのですが、最近になって不具合修正の依頼があって、何とかせんといかなくなりました。てっとり早く archive.org あたりから AN Httpd のバイナリをゲットしてきてもいいのですが、せっかくなので、この機会に Go 言語でウェブサーバーでもでっちあげようと思いました。

xnhttpd は、WindowsCGI を起動する機能しかありません。まず、拡張子とインタプリタのリンクを JSON に書きます

sample.json

{
    "handler":{
        ".pl":"c:/Program Files/Git/usr/bin/perl.exe"
    }
}

この JSON を標準入力から読み込んで起動させます。

.\xnhttpd.exe < sample.json 

すると、起動した時のカレントディレクトリ以下にある Perl スクリプト(例:.\sample.pl)が http://localhost:8000/sample.pl みたいな URL でブラウザ呼び出すことができるようになります。

wifky は画像とかコンテンツを全部 CGI 側で動的に発信させるようになっているため、本ウェブサーバーは静的コンテンツをウェブサーバー側で発信する機能はありません。それゆえサーバーに負荷がかかります。が、テスト用なので、そこは気にしなくてもいいでしょう。

将来的には静的コンテンツの発信機能とか、markdownファイルを HTML 化して発信する機能をつけてもいいかな…とか思いますが、wifky の不具合を直した途端にまたやる気を失ってしまいました。やれやれだぜ

それにしても、最近の言語はウェブサーバーをサクッと書けてしまうくらいライブラリが充実してて、ほんと便利になりましたよね

Goの reflect で Perlでいうところの「sorted keys %HASH」的なことをする

とある slack で reflect のよい使用例についての話題が出てました。

reflect を使用したいというケースは、encoding とか O/R mapper 以外となると、ほとんどの場合「interface で済むんじゃね?さもなければプログラマがよく Go 言語を理解していないんじゃね?」という場合が多いのですが…

実は「ちょっとコレはいけるんじゃね?」というコードを前に書いていたので、ちょっと紹介してみます(← お前も実は Go言語を理解していないんじゃね?)

任意の型Tに対する map[string]T という辞書のキーをソートして配列化する関数です。Perl でいうところの sorted keys %HASH ですね。

func SortedKeys(mapInt interface{}) []string {
    values := reflect.ValueOf(mapInt).MapKeys()
    result := make([]string, len(values))
    for i, value1 := range values {
        result[i] = value1.String()
    }
    sort.Strings(result)
    return result
}
// test
func TestSortedKeys(t *testing.T) {
    example := map[string]int{
        "a": 1, "b": 2, "c": 3,
    }

    result := SortedKeys(example)

    if result[0] != "a" ||
        result[1] != "b" ||
        result[2] != "c" {

        t.Fail()
    }
}

nyagos でエイリアスとか環境変数の一覧を表示するところとかに使ってます。一覧表示はキーをソートして表示したいですからね。こういうのって、キーはたいてい string ですけど、値の方は様々な構造体なんですよね。

Qiitaの自分の記事を全部ダウンロードして、GitHubに転載してみた。

Qiitaで不祥事があって退会者が結構出てるみたい。

LGTMがもったいないから、自分はすぐ退会しようとは思わないけど、一応、備えはしとこう。

ということで、一応、自分の記事を全部ダウンロードして、GitHub にアップしてみた。

ツールは自分で作ってみた。

  • zetamatta/qiitaexport: Download user's all Qiita articles
    • qiitaexport - 引数で与えたアカウントの全記事の markdown ファイルをそのままカレントディレクトリに展開するだけ。だから、画像へのリンクはそのまま Qiita に置きっぱなし
    • imgreplace - 引数で与えた markdown ファイルの中のイメージリンク ![...](https://....) の先のファイルをカレントディレクトリにダウンロードし、リンクもそちらへ書き換える

Goはライブラリが豊富だから、楽だ!

Windows で git diff の結果を patch.exe で使う

「git 互換 patch」で検索すると、次のようなページがすぐ見つかる。

こうか!

$ git show --no-prefix 5f682fb657439fe518475e6effc6e7e30b1dfd33 > patch.1

だが、Windows では、このパッチを適用すると

$ patch.exe < ../../patch.1
patching file readline.go
Assertion failed: hunk, file ../patch-2.5.9-src/patch.c, line 354       

とエラー終了してしまう。「patch assertion failed」でググると、すぐ対処方法を記載したページが見つかる。

どうも、改行コードが LF だと、こうなってしまうようだ。パッチコードの改行コードを変換してもいいんだが、お手軽にバイナリモードを使用した。

(パッチ作成)
$ git show --no-prefix 5f682fb657439fe518475e6effc6e7e30b1dfd33 > patch.1
(パッチ適用)
$ patch.exe --binary < ../../patch.1 

しかし、assertion failed は、ひどいよな。もうちょっとマシなエラーメッセージは出せなかったものか…

余談1:UAC ダイアログ版

patch.exe は WindowsXP 時代のものを使うと UACダイアログが起動してしまう(「patch」という名前を含んでいるせい)。UAC ダイアログが出ないバージョンは 次より配布されている

余談2:-p オプション

パッチを作る側と、パッチを適用する場所で、ディレクトリの深さが違うと当然だが、パッチ適用が失敗する。

patch コマンドの -p オプションを使うと、パッチの相対パスの深さを減らすことができる。-p0 だとそのまま、-p1 だとディレクトリを一つ減らすという感じだ。

%PATH%が長すぎる時

%PATH%が長すぎて、これ以上フォルダーを追加できないけど、いちいちコマンド毎に alias の設定もやってられない場合:

nyagos.envadd("NYAGOSPATH",
    "C:\\Program Files\\Oracle\\VirtualBox")

とか

nyagos.envadd("NYAGOSPATH",
    "~\\Share\\Program Files\\idmanager",
    "%VBOX_MSI_INSTALL_PATH%",
    "C:\\Program Files\\Oracle\\VirtualBox",
    "C:\\Program Files\\Mercurial",
    "C:\\Program Files (x86)\\Mercurial",
    "%ProgramFiles%\\Subversion\\bin",
    "%ProgramFiles(x86)%\\Subversion\\bin",
    "~\\.cargo\\bin")

などと .nyagos にかけば、nyagosのコマンド検索パスだけにフォルダーを追加できます。

コマンドラインから

set NYAGOSPATH=%NYAGOSPATH%;C:\Program Files\Oracle\VirtualBox

やったり、.nyagosから

nyagos.env.nyagospath=nyagos.env.nyagospath .. ";C:\\Program Files\\Oracle\\VirtualBox"

とやっても等価です。nyagos.envadd関数は、環境変数 NYAGOSPATH を直接修正する場合と比較すると:

  • 存在しないフォルダーや既に登録済みのフォルダーは追加しない
  • チルダ(~) などを %HOME% もしくは %USERPROFILE% の内容に展開する

などの点が違います。

nyagos 4.4.5_3~4 を公開しました。

ちょっと、立て続けですが、4.4.5_3~4 を公開しています(4.4.5_3 でちょっと失敗したので、_4 をすぐリリースした的な)

一番、すぐ直したかったのはコレ

  • echo $(gawk "BEGIN{ print \"\x22\x22\" }") で二重引用符が出ない不具合を修正

プロセスの出力結果の中の機能文字はそのまま機能文字として解釈されないように、基本 %U+nnnn% 形式にエスケープしているんですが、その中で二重引用符が漏れていました。それを直しただけ(本体の EXE ではなく nyagos.d/backquote.lua レベルの話)

で、これに巻き込んで入れてしまったのが、コレ

  • github.com/BixData/gluabit32 が 404 になって、Lua関数 bit32.* が利用できなくなった。

それなのに、なぜリリースしてしまうかな、俺。というわけで、続く 4.4.5_4 で次のようなフォロー入れています。

  • github.com/BixData/gluabit32 が消えて C-xC-r C-xC-h , C-xC-g が動かなくなった問題を修正
  • (#319) 自前版 bit32.band , bor , bxor を再び追加

あと、ちょっと誤解されたのは、コレ

  • サブコマンド補完(complete_for)では拡張子は無視してコマンドのマッチングを行うようにした

補完フックには二種類がありまして、

  • 昔からある nyagos.complete_hook
    • 何でもできるが、その分 Lua でガッツリ書かないといけない
    • nyagos.d/スクリプトがあるのは、こっち向け 最近、試験的に追加した nyagos.complete_for
    • コマンドごとに特化していて、Luaコード少なめでよいが、そのかわり自由度が少ない *(bash の complete 文程度にコマンド特化の補完コードを楽に書けないかという試作品

で、compete_hook の方は相変わらず、拡張子は無視せずにコマンドのマッチングをしていました。これについても 4.4.5_4 でフォローしました。

  • (#378) nyagos.d/catalog/subcomplete.lua: こちらのサブコマンド補完でも拡張子なし・英大文字・小文字は区別しないでコマンドを照合する動作を標準にした

あと、これは気づいたのは僕だけだったんじゃないかなと思うんですが、

  • (#377) scoop でインストールされた git で git gui を実行すると、エスケープシーケンスが効かなくなる問題に対応

そもそも git gui なんていうコマンドを知っている人は少ないと思いますが、これ GUI で git を操作するという文字どおりのサブコマンドです。が、これ非同期に動作してコンソールのモード変えちゃうんですよね。だから、コマンドが終わった時にコンソールのモードを元に戻しても、その後に非同期プロセスがそれを上書きしてしまう。

ということで、プロンプトが表示されるたびにいちいちコンソールを操作してエスケープシーケンスを有効にするようにしています。

今回の修正はこんなもんでしょうか。2回ダウンロードしてインストールした方には申し訳ないことでした。