標準愚痴出力

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

go mod 試験導入

nyagos の依存パッケージである zetamatta/go-texts/mbcs に不具合があったので、それをちゃんと import するよう、go modules を設定してみた。 そのメモ。間違っている箇所があればご指摘歓迎

go-texts 側

go modules を使用するモードに切り替える

set GO111MODULE=on

各パッケージフォルダーで go.mod を作成し、レポジトリへ反映する。これは v0~v1のトップだけではダメのようだ。v2 とかのメジャーバージョンフォルダーにも必要。また、go.mod は go build で更新されるので、そのあとに commit するのも忘れてはいけない。

cd ~/go/src/github.com/zetamatta/go-texts/
go mod init
go build
git add go.mod
cd mbcs
go mod init
go build
git add go.mod
git commit -m "add go.mod"

v1.0.1 というタグをつけておく。v1.0.0 ではないのは単に既に同タグが使用済みだったからというだけ

git tag v1.0.1

GitHub にも go.mod とタグを反映しておく。モジュールは別フォルダーに個別にダウンロードされるので、ローカルのパッケージにだけタグがあっても意味がない。

git push
git push --tag

go-box 側

今回の不具合ではないが、go-box という依存モジュールは v2 というフォルダーを既に使っていて、そのままビルドするとエラーが発生してしまった。

cd ~/go/src/github.com/zetamatta/go-box
go mod init
go build
git add go.mod
cd v2
git mod init
go build
git add go.mod
git commit -m "Add go.mod"

nyagos 本体

cd ~/go/src/github.com/zetamatta/nyagos
go mod init
go build
git add go.mod

これで Ok なはずだが、ビルドスクリプト修正

  • 環境変数 GO111MODULE を on にするコードを追加
  • go get が必要なくなるので、make get は何もしないようにする

ところで、これ、そのバージョン以降の最新版という指定をする方法はないんでしょうかねぇ。。。

追記

気になっていた import モジュールの最新化だけど、「Go言語の基礎〜Go 1.11 開発環境構築とパッケージバージョン管理〜 – RE:ENGINES」によると、

go get -u

でいいみたい。

NYAGOS開発ノート:新補完API(試作中)

現在の補完APILua 側の負担が重いので、bash と同じくらいにお手軽な新補完APIを試作中してます。以下は git のサブコマンドを補完する例:

nyagos.complete_for["git"] = function(args)
    if #args == 2 then
        local base = args[#args]
        local len = string.len(base)
        local result = {}
        for _,s in pairs{ "commit","push","pop","diff","rebase","log" } do
            if string.sub(s,1,string.len(base)) == base then
                result[#result+1] = s
            end
        end
        return result
    else
        return nil
    end
end
  • コマンド単位に、テーブル nyagos.complete_for["コマンド名"] に関数を割り当てる
  • 引数 args はカーソルより左側を空白で区切ったテキスト(二重引用符等は削除済み)
  • 戻り値には、補完候補の文字列群をテーブルとして返す
  • 戻り値を nil にすると、従来どおりのデフォルトのファイル名補完が実行される。

まだ、もうちょっと変えるかもしれません。

追記

候補の限定処理も Go 側でやるようにしてみました。この結果、上記の例は

nyagos.complete_for["git"] = function(args)
    if #args == 2 then
        return { "commit","push","pop","diff","rebase","log" }
    else
        return nil
    end
end

とすごく簡単になります。

さらに追記

決定版!

nyagos.complete_for.git = function(args)
    while #args > 2 and args[2]:sub(1,1) == "-" do
        table.remove(args,2)
    end
    if #args == 2 then
        return nyagos.fields([[
          add                 fsck-objects        rebase
          add--interactive    gc                  receive-pack
          am                  get-tar-commit-id   reflog
          annotate            grep                relink
          apply               gui                 remote
          archimport          gui--askpass        remote-ext
          archive             gui--askyesno       remote-fd
          bisect              gui.tcl             remote-ftp
          bisect--helper      hash-object         remote-ftps
          blame               help                remote-http
          branch              http-backend        remote-https
          bundle              http-fetch          repack
          cat-file            http-push           replace
          check-attr          imap-send           request-pull
          check-ignore        index-pack          rerere
          check-mailmap       init                reset
          check-ref-format    init-db             rev-list
          checkout            instaweb            rev-parse
          checkout-index      interpret-trailers  revert
          cherry              log                 rm
          cherry-pick         ls-files            send-email
          citool              ls-remote           send-pack
          clean               ls-tree             sh-i18n--envsubst
          clone               mailinfo            shortlog
          column              mailsplit           show
          commit              merge               show-branch
          commit-tree         merge-base          show-index
          config              merge-file          show-ref
          count-objects       merge-index         stage
          credential          merge-octopus       stash
          credential-manager  merge-one-file      status
          credential-store    merge-ours          stripspace
          credential-wincred  merge-recursive     submodule
          cvsexportcommit     merge-resolve       submodule--helper
          cvsimport           merge-subtree       subtree
          cvsserver           merge-tree          svn
          daemon              mergetool           symbolic-ref
          describe            mktag               tag
          diff                mktree              unpack-file
          diff-files          mv                  unpack-objects
          diff-index          name-rev            update-index
          diff-tree           notes               update-ref
          difftool            p4                  update-server-info
          difftool--helper    pack-objects        upload-archive
          fast-export         pack-redundant      upload-pack
          fast-import         pack-refs           var
          fetch               patch-id            verify-commit
          fetch-pack          prune               verify-pack
          filter-branch       prune-packed        verify-tag
          fmt-merge-msg       pull                web--browse
          for-each-ref        push                whatchanged
          format-patch        quiltimport         worktree
          fsck                read-tree           write-tree]])
    end
    if args[#args]:sub(1,1) == "-" then
        if args[2] == "commit" then
            return { "--amend" , "-a" , "--cleanup","--dry-run" }
        end
    end
    return nil
end

nyagos.fields は文字列を空白で分割する関数です。

Gopher人類とGenerics【Golang帝国興亡史】

我々Gopher人類は「Genericsは不要」と強調しすぎたのかもしれないな。「GenericsないからGoはダメ」に対する反論だけど、実際は「7~8割のケースではGenericsは要らないけど、2~3割やはりGenerics欲しい」というところだ。そこをつかれて「おまいら矛盾してる」と言われている。

ここについては今更フォローはできないんだけど、アンチの人は思い出したかのようにGoはダメ論を展開してくる。「そんなにダメなら使わなきゃいいし、うるさいんだよ」と、なんか Perl 使ってた時と同じような気持ちになった。

それはともかくGo言語には表現しづらい暗黙の常識・合理性が多い。C言語経験者なら「appendはreallocの置き換えだな。ならば旧スライス使わんほうがいいな」(※)とか直感的に思うが、それが目立つところに書いてない。そういう事例が多い故にJavaRuby勢から落とし穴と批判されるのは謙虚に認めないといけない。

(※)本当にappend後の旧スライスが使用不能かどうかは分からん(自信ない)。もしかしたら使えるかもしれないけど、あくまで一例なので、あんまり深く突っ込まないでいただきたい。


Ruby等ではCPUの1レジスタにおさまる型と別途ヒープに領域の確保が必要な型を区別せずあつかえる。これは人間の目から見た型の直交性としては正しいんだけど、一方で実装という面では「実際は違うものを同じような表現で扱うのはやっぱり無理があるんちゃうやろか」という見方もあるのではあるまいか

多分だけど、同等に扱うのに無理が生じるなら、素直に別物にしようぜと開き直っているのがGo言語だと思う(Javaもそうだけど、あちらはどちらかというと「その発想はなかった」というだけという気がする)

たとえば文字列関連のメソッド。Python 1 では Go と同じように文字列を扱う関数/メソッドは純粋な文字列のメソッドではなく、別途 strパッケージのクラスメソッドだったと思う。その後 2 になって Ruby と同様になった。だが、Goはあえて Python 2 を真似ず、1と同じ体裁をとった。

思うに「文字列関係を操作する関数の体裁をメソッドにしたら、そりゃ確かに見やすいかもしれへんけど、そんな無茶苦茶便利で快適で『なかったら困る』ようなもんか?別に Python 1 相当の体裁でも困らんかったやろ。無理にあわてて実装するような仕様かなぁ」といったところかと

要は「品質を99%から 99.9%にするのに、10倍のコストをかけるような真似」を Go言語は行わなかったと思っていただいたいということだよ。そんな無駄なコストをかけるなら、運用を楽にする方に人的資源をかけた方がよいということだね

NYAGOS保守ノート:OpenSSH でパスワード入力中に Ctrl-C で中断すると画面が乱れる

これな

症状

nyagos から OpenSSH を起動して、パスワードプロンプトで Ctrl-C を押下すると、nyagos に復帰してこなくなる(ように見える)。

f:id:zetamatta:20190126103235p:plain

原因

これは実は nyagos には復帰しているのだが、コンソールのモードがパスワード表示向けの状態から元に戻っていないだけである。なので、画面が更新されないが「exit」と入力すると普通に終了する。

対応

コマンドを実行した後、コンソールの出力のモードをいちいち元に戻すようにした。入力のモードについては既に対応していたので、同じような対応を出力にもするようにした。

詳しくは差分みて

余談1

このコンソールのモードを変える関数(dos.ChangeConsoleMode)の仕様は我ながらなかなかうまいこと作れていると思う

if restore,err := dos.ChangeConsoleMode(windows.Stdout, dos.ModeSet(enableVirtualTerminalProcessing)) ; err == nil {
    defer restore()
}
  • モードを元に戻す関数(クロージャ)を戻り値に変えす。一時的にモードを変えるだけなら、これを defer で戻すようにすればよい
  • モードのセット・リセットは、dos.ModeOp というインターフェイスを実装した dos.ModeSet , dos.ModeReset という型をパラメータとして0個以上渡せばよい。
  • コンソールのハンドルはいちいち自分で "$CONIN" "$CONOUT" をオープンしなければいけないと思いがちだが、実は準標準の golang.org/x/sys/windowswindows.Stdout とか windows.Stdin がそのままあるので、これを使った方が早い。

余談2

なぜ、Ctrl-C で OpenSSH を中断すると、コンソールのモードを元に戻してくれないのか? beepcap さんによると、CMD.EXE や PowerShell 上では同症状は発生しなかったそうだ。

可能性としては以下の2説がある。

  • CMD.EXE や PowerShell はコマンド実行ごとにいちいちコンソールモードをリセットしている
  • Ctrl-C をキャッチした時の子プロセスの殺し方がまずい(SIGKILL相当)ので、OpenSSH が SIGINT 扱いでハンドルできない

nyagos の Ctrl-C の扱いについては、最近(go-tty導入前後)になってからうまく処理できなくなったので、 "os/exec".Run を参考にして最近実装しなおしたのだが…見直しが必要かもしれない。

Ctrl-C の取扱については、現在のように Go言語の "os/signal" の関数を使うほか、Windows のそれ用の API SetConsoleCtrlHandlerがある。 おいおいと調べなくては…

NYAGOS保守ノート:DropBoxの共有ファイルをVMの共有フォルダー越しに ls すると、意図せずダウンロードが発生する

症状

DropBox のフォルダーを \\vmware-host\Shared Folders\経由で VM から参照できるようにすると、仮想マシン内の nyagos で ls -F もしくは ls -lした時、表示対象になったファイルがオンラインにしかない場合、スマートシンク機能が動作して自動ダウンロードが動き始めてしまう。ホストからだと、そういう動作はない。

原因

オンラインにしかないファイルにはリパースポイントフラグがたっており、そのリンク先を参照する動作(os.Readlink)が「ファイルオープン」としてホスト側に伝わってしまうからのようだ。

対応

ls -F

リパースポイントがついたファイルが実際にシンボリックリンクかどうかを判別するために os.Readlink を呼ぶ動作があった。ls -F はデフォルトのlsエイリアスでくっつけて動作することが多く、脊髄反射でやってしまうこともあり、意識して使わないようにすることが難しい。

なので、ls -F でリンク先を読む動作は廃止し、リパースポイントフラグで常に @ マークをつけるようにした(@ はそういう仕様ということにする)

ls -l

ls -l ではリンク先を出力する。迷ったあげく現状維持にした。

実は VM内のエクスプローラーで共有フォルダーを参照した時も、DropBox はダウンロードをはじめてしまう。おそらく、アイコンを読む際にファイルオープンしてしまうのだろう。

そこで「エクスプローラーで無理なら、ls も無理だよね。脊髄反射ls -l しないよう気をつけよう」という方針にしたわけだ。

VS2017のC++プロジェクトを\\vmware-host\Shared Folders\ 以下に置くと

普段、仕事で VMwareWindows-VM 内で開発しているのだが、 VisualStudio 2017のC++プロジェクトを、ホストとの共有フォルダー \\vmware-host\Shared Folders\ 以下に置くと、「LNK1123 - COFF への変換中に障害が発生しました: ファイルが無効であるか、または壊れています」「CVT1101 - '….res' を開いて読み取れません」のエラーが発生して、リンク等ができなくなる問題が発生する。

LNK1123andCVT1101.png

(実際は UNC パスに直接置いているのではなく、mklink でシンボリックリンクを張ったところで作業している)

これ、普通のフォルダーにプロジェクトをコピーして、そちらでビルドすると発生しない。

ググるVisual Studio 2010 で似た事例が出てくるのだが、そちらは SP1 をあてると直る。今回の 2017 も似たような原因であるという思い込みがあったため、気づくのに3~4日ほど無駄にしてしまった。とほほ

NYAGOS 4.4.0_1 を公開してました

パッチリリースとして 4.4.0_1 を公開しました。クリティカルな不具合修正はないので、必要性を感じなければ慌てて UP する必要はありません。

(一応、マイナーバージョンアップは1ヶ月サイクル。不具合修正レベルのパッチバージョンアップは基本1周間単位だけど、緊急性が高い時は「問題発覚次第ただちにやる」かなーと思ってやってます)

  • "--go-colorable" と "--enable-virtual-terminal-processing" を廃止
    • Windows10 ではネイティブのエスケープシーケンスが効くかを自動判別するようにしたので、こちらのオプションは紛らわしいので、削除しました(まぁ、試験用に近いオプションでしたし、この程度の既存バージョンとの互換性ダウンは許してくださいまし)
  • killall コマンドを実装
    • いちいち ps| findstr してられん程度に個人的にえらく多用するので
  • Linux用の copymove を実装
    • ネイティブの cp/mv があるので、使う必要はないのですが、今後少しずつ Linux版/Windows版の機能的差異を縮めていこうという取り組みです(まぁ、そっくりにするのは不可能ではありますが)
  • (#351) END と F11 キーが動作もキー割り当てもできなかった不具合を修正

以上です。