標準愚痴出力

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

C:\Program Files へファイルをコピーするバッチファイルの作り方

一般ユーザでは C:\Program Files 以下へファイルをコピーすることはできないので、管理者権限で自分自身を起動しなおすようにする。

make.cmd

setlocal
set "EXE=%~dp0\bin\Release\HogeHoge.exe"
call :"%1"
endlocal
exit /b

:"install"
    powershell Start-Process "%~dpnx0 install_" -verb runas
    exit /b

:"install_"
    copy "%EXE%" "C:\Program Files\nyaosorg\."
    copy "%EXE:.exe=.ini%" "C:\Program Files\nyaosorg\."
    pause
    exit /b

make install とタイプすると、UACダイアログが表示されるので、はい(Y)を選ぶと、管理者権限で目的のファイルを C:\Program Files\nyaosorg 以下へコピーしてくれる。

%~dp0 とか %EXE:exe=.ini% などは環境変数の置換で、これらは cmd /hcmd /c set /?cmd /c for /? などでガイドが出てくるので、そちらを参照いただきたい(つきはなし)

nyagos のソースフォルダー構成をもうちょっと簡単に

あまりにソースのサブフォルダーが多くて、改造しようという人が迷いそうなので、ちょっとだけ整理した(でも、まだ多い)

  • Cmd/ … ビルド結果置き場
  • Doc/ … ドキュメント
  • Etc/ … ビルド時に参照する設定ファイル置き場など(旧Misc/)
  • alias/ … エイリアス機能関連ソース(shell/ に依存)
  • commands/ … 内蔵コマンドの実装(shell/ に依存)
  • completion/ … 補完機能(readline/ に依存する)
  • defined/ … ifdef 的な機能を提供するパッケージ
  • dos/ … syscall 的なツールパッケージ。Windows に依存する
  • frame/ … メインルーチンの中で Lua に依存しないソース
  • functions/ … Lua向け関数だが、interface機能で Lua に依存しないようになっている
  • history/ … ヒストリ機能関連
  • mains/ … 真のメインルーチン。vanilla.go 以外は Lua に依存する
  • nodos/ … syscall 的なツールパッケージだが、Windows/Linux 双方で利用できるもの
  • nyagos.d/ … Lua スクリプト
  • readline/ … 一行入力パッケージ
  • shell/ … 一行実行パッケージ
  • t/ … テスト用の Lua スクリプト
  • texts/ … 文字列操作用ツールパッケージ

今回、削除したのは ngs/ だけ。ここをカレントディレクトリにして go build すれば ngs.exe という Lua を使わない nyagos をビルドできていた。が、今回、tag に vanilla を与えてビルド(make.cmd vanillaでOk)すれば Lua を参照しないようにすることで廃止した。

基本的な構造としては、shell(一行実行)と readline(一行入力) という二本柱がある。mains パッケージでこれらが用意している「フック」に対して、alias、completion、commands などの機能の関数をつっこんで呼び出しているという感じですわ。

昔の Go は exit status が fmt.Errorf("exit status %d",ERRORLEVEL) で返ってきたような

Go 1.12 で、実行したプロセスの ERRORLEVEL を得るためのメソッド:"os".ProcessState.ExitCode() が追加されたので、対応の準備をすすめていて気づいたのだけれども…

昔の Go言語だと、0 以外の ERRORLEVEL を受け取ると、"os/exec".Cmd.Run()fmt.Errorf("exit status %d",(ERRORLEVEL値) ) みたいな error を返していたように思うんだけど、1.11~だと、そういう挙動が見られなくなった。

いつ、どうして変わったんだろう… golang の issue を検索したが、数が多すぎて分からん汗

それなりに便利だったので、NYAGOS では、その error をそのまま表示していたんだけれども、いつの間にはそういう挙動がなくなってしまった。 バッチファイル実行の際のコードが EXE ファイル実行の時の挙動に合わせて ERRORLEVEL 値を表示するような形になっていたので、今度は逆に EXE ファイル実行の際の挙動も古い挙動に合わせて、わざわざ「exit status %d」と表示するように修正した。

挙動が変わった原因については、暇を見て、おいおい調べよう(続く…かな?)

(追記)

タイトルとか間違えちゃった。

(旧) 昔の Go は exit status が errors.Fmt("exit status %d",ERRORLEVEL) で返ってきたような

(新) 昔の Go は exit status が fmt.Errorf("exit status %d",ERRORLEVEL) で返ってきたような

Windows のアプリケーションディレクトリ

nyagos では、ヒストリなどを

  • Windows では %APPDATA%\nyaos_org
  • Linux では $HOME/.nyaos_org

に保存している。このパスは環境変数を元に生成しているのだが、ここのところで OS ごとに処理を分けるのは可読性を下げるので、できれば標準ライブラリが吸収してくれたらなぁと思った。

標準ライブラリのユーザのディレクトリを教えてくれる関数の結果を確認してみた。

u,_:= "os/user".Current() ; u.HomeDir
    → %USERPROFILE% or $HOME相当※
dir,_ := "os".UserCacheDir() ; dir
    → %USERPROFILE%\AppData\Local or $HOME/.cache相当※

(※ 実際は環境変数は展開済み)

結果はちょっと欲しいものとは違ったのだけれども、はて AppData の下の Local とは Roaming 等とはどう違うのだろうか?と今更だが、疑問が湧いてきた。

ぐぐってみたところ、解説ページが見つかった

どうやら

  • Roaming(=%APPDATA%) … ユーザデータのうち、プロファイルを移動させた時にいっしょに移動させるべきデータ。
    • あまり大きいものを入れるべきでない
    • その PC 固有のものは入れるべきではない
  • Local(os.UserCacheDir()) … プロセスの信頼レベルが Low より上のもののデータを格納
  • LocalLow … プロセスの信頼レベルが Low 以下のもののデータを格納(主に Internet Explorer 用?)

というような使い分けらしい。なるほど

Shift-JISファイルの作成

現在のコードページの文字形式ではなくて、本当に ShiftJIS 固定となるので、日本語特化のアプリとなるが

package main

import (
    "fmt"
    "os"
    "path/filepath"

    "golang.org/x/text/encoding/japanese"
)

const fname = "search.lst"

func main1() error {
    fd, err := os.OpenFile(fname, os.O_CREATE|os.O_EXCL, 0666)
    if err != nil {
        return err
    }
    defer fd.Close()

    w := japanese.ShiftJIS.NewEncoder().Writer(fd)

となる。O_EXCL はただの上書き禁止オプションで SJIS とは直接の関係はない。

PowerShell で .NET のアセンブリ内の関数の動作確認

HogeHoge.exe の中のクラス Config の shared メソッド Load を呼んでみる。

test.ps1:

[reflection.assembly]::LoadFrom("bin\Release\HogeHoge.exe")

$data = [HogeHoge.Config]::Load("hogehoge.xml")

Write-Host("---")
Write-Host($data.ToString())
Write-Host("---")

あれ、もっと面倒だったような気がしたのだが、勘違いかな?

NYAGOS保守ノート: 欧州向けキーボード対応ふたたび(AltGR キー処理)

日本では馴染みがないのだが、ヨーロッパのキーボードには AltGR というキーがあるようだ。用途としては、英語圏にない文字等を入力する時にシフト的に用いるようだ。

それが入力できなくなったという issue を起案いただいた。

AltGR 対応は、以前、一度行ったのだが、当時は一文字キー入力は自前(zetamatta/go-getch)でやっていた。

nyagos 4.4 で Linux 対応をするにあたって、mattn/go-tty に切り替えたのだが、本件についてはその際対応漏れとなっていたようだ。(いや、実はうすうす気付いてはいたのだが、テスト協力者がいなくてな)

さて、go-tty の場合、どうやればいいだろうか。 というか、キーボードそのものがないのに、どうやって動作確認をとれば?

報告者に確認してみたところ、AltGR + 6 を押下すると本来はパイプライン記号(|)が入力されるべきところが、^[| (ESCAPE + | )がデータとしてきてしまっている。つまり、単に ESCAPE が多いだけではないか。

で、実際、go-tty のコードを拝見すると、Ctrlキーと Altキーを同時押しした時、ESCAPE + その文字の Unicode を返すような動作となっている。 報告者のリポートを見ると、「CTRL+ALT+6」でも同じ結果になったと言っている。 OS的には AltGR キーは Ctrl+Alt 同時押しと同じ扱いになっており、go-tty もちゃんと対応していると見てよいだろう。

よって、対応としては、ESCAPE + 1文字が来た時は、ESCAPE をカットすればよさそうである。 ただ、そうすると、他の ESCAPE 文字で表現される特殊キーのアサインに支障が発生する。 そこで未アサインのキーが来た場合、つまり、そのキーの内容をそのまま一行入力バッファに格納する場合のみ、先頭にある ESCAPE をカットするという風に対応した。

これでコミットして、AppVeyor のバイナリを報告者に使ってみていただいたところ Ok がもらえた。バッチリである。