標準愚痴出力

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

import を全て絶対パスにした

こんな感じに

-       "../completion"
-       "../shell"
+       "github.com/zetamatta/nyagos/completion"
+       "github.com/zetamatta/nyagos/shell"

これにより:

  • ソースを GOPATH 内に置けなかった
  • go get github.com/zetamatta/nyagos で全ソースをダウンロードできなかった。
    git clone http://github.com/zetamatta/nyagos/ は可能)

が解消する。そのかわり

  • ソースの置き場が $GOPATH/src/github.com/zetamatta/nyagos と一意になってしまう。
    • amd64 用のビルド場所はこちら、386 用のビルド場所はこちらと、複数設けることができなくなってしまう。
      (lua53.dll が 64bit 用も 32bit 用も同じ名前なので、同じ場所におけない)

という問題が発生してしまう。

いろいろと検討した結果、とりあえず現行の自分のビルド環境は次のようにすることにした。

  • メインのメンテナンスディレクトリは ~/go/nyagos から ~/go/src/github.com/zetamatta/nyagos に変更 (ここでamd64用ビルドする)
    • 移動が大変なので lnk ~/go/src/github.com/zetamatta/nyagos ~ でショートカットを張る
  • 386 ビルド用ディレクトリは従来どおり ~/go/386-nyagos のまま
    • ただしビルド専用。import の先が ~/go/src/github.com/zetamatta/nyagos になってしまうので、ソースの編集はこちらではできない

でいこうと思う。

将来的には ~/go/src/github.com/zetamatta/nyagos のいたまま amd64 も 386 もビルドできるようにしたい。 そのためには、今 ~/go/src/github.com/zetamatta/nyagos 直下にある lua53.dll を適当なサブフォルダーに移動させなくてはいけない。 でも、lua53.dll って git に登録していないバイナリファイルなので、移動させるとなるとソースからビルドしてくれているユーザにそれをアナウンスしなくちゃ いけないんですよね…むーん。

lua53.dll も git に登録しちうという手もあるが、そうすると git clone とか go get でバイナリファイルがダウンロードされるので、 アンチウィルスにひっかかってしまう可能性が出てきてしまうという…

将来的に $GOPATH 以下でも、相対パスの import ができるようにならないですかね (これ、なぜできないようにしたんでしょうね)

追記

「386 と amd64 で $GOPATH を分ける」という方法を思いついた。いずれやってみよう

まだ、NYAGOS 4.2 は出せない

Luaインスタンスのクローンについては今のところ問題は出ていない。 無論、不具合の一つ二つは出たが、 確認当日中にあっさりと解決できて、この程度で済むのなら上出来だったと思う。

また、もう一つの懸案も解決できた。

これは Args[] を Windows 風の一枚引数文字列に展開する際の二重引用符の扱い方のために、 FIND コマンドが期待するような「検索文字列の前後には二重引用符をつける」という仕様を呼び出し時に満たすことができないという問題だ。

この issue 自体は最近起案したものだけれども、Args[] の展開を自前でやるというのは前々からの課題だった。 やろうと思うと、API の CreateProcessW を呼ぶライブラリから作られなばならないと思っていたので、 すぐには実現できないと思っていた。 が、Go のライブラリのソースを見てたら、実は Args[] の展開を自分でやる手段が提供されていることが分かり、 思わぬタイミングで懸案は解決した。 詳細は前に書いた記事を参照のこと。

というわけで、結構大きい課題が二つの解決して、満を持して 4.2.0 をリリースしたいところだが、もう一つ欲張りたいところがある。

それは foreach とか if ~ then ~ endif とかの制御構文。 nyaos-3000 は、その辺をちゃんと実装していたが、nyagos は Lua で全部やればいいからと完全にスルーしてしまった。 ところがユーザの傾向を見ると、Lua だからカスタマイズの仕方が分からない、調べれば分かるが、学習コストに見合わないという人が多い。 完全に計算違いだった。

foreach を実装するには、コマンド列の任意の位置へ移動できなくてはいけない。 そのためには shell パッケージは単品のコマンドの実行だけではなく、前後のコマンドも含めたセッションも管理して、 コマンド列の移動可能箇所をマーク&移動できるようにしなければいけない。 これまでは一連のコマンド列の管理は mains パッケージ(旧mainパッケージ)で行っていた。 昨日・今日で、それをようやく shell パッケージ(旧interpreterパッケージ)側に移動した。 結果、mains パッケージからは「shell.Loop(コマンド列読み込みオブジェクト)」だけを呼ぶだけとなった。

これ、日本語で書くと簡単に見えるが

  • shell パッケージは Lua へ依存させてはいけない。Lua への依存は mains パッケージが隠蔽するか、注入するかしてやらないといけない
  • インタラクティブシェルか、スクリプトかの管理に shell パッケージは関与してはならない

とか制約が多くてたいへんだった。が、最終的にはコマンド列読み込みインターフェイス

package shell

type Stream interface {
    ReadLine(context.Context) (context.Context, string, error)
    GetPos() int
    SetPos(int) error
}

をベースにうまいこと実装できた。おかげで shell パッケージは奇麗さを維持できた。 が、mains パッケージはかなりグダグダである。 「依存性」が全部 mains パッケージに集まってるのだから仕方がない。

Go for Windows で子プロセスに二重引用符を引数でそのまま渡したい時

問題の症状

親プロセスのソース:

// exec1.go
package main

import (
    "os"
    "os/exec"
)

func main() {
    c := exec.Command("foo", `"<BAR>"`)
    c.Stdout = os.Stdout
    c.Stderr = os.Stderr
    c.Stdin = os.Stdin
    c.Run()
}

子プロセスのソース(バッチファイル):

@rem foo.cmd
@echo %0 %*
@exit /b 0

実行すると

$ go run exec1.go
foo \"<BAR>\"

二重引用符の前にバックスラッシュがついてしまう。

解決方法

バックスラッシュが付かないようにするには、Go言語標準のexec.Cmd.Args[]Windows 形式の引数形式に展開する処理をパスして、自前で直接指定すればよい。

//exec2.go
package main

import (
    "os"
    "os/exec"
    "syscall"
)

func main() {
    c := exec.Command("foo")
    c.SysProcAttr = &syscall.SysProcAttr{CmdLine: `foo "<BAR>"`}
    c.Stdout = os.Stdout
    c.Stderr = os.Stderr
    c.Stdin = os.Stdin
    c.Run()
}
$ go run exec2.go
foo "<BAR>"

なぜ、こんなことをする必要があるのか

FIND.EXE や CMD.EXE は、引数につけられた二重引用符の有無で、その引数がどういうものか判別しています。このため、Goのプログラムから FIND.EXE が意図どおりに呼べないという問題が発生していました。

こういう仕様って、どこに書いてあったの?

ここ

Qiita から回答をいただきました>自作公開OSSに関する解説はガイドラインの「自社の製品の宣伝行為はしない」に抵触しますか?

先日 Qiita に問い合わせてみました:自作公開OSSに関する解説はガイドラインの「自社の製品の宣伝行為はしない」に抵触しますか?という記事を書いたわけですが、 本日返信をいただきました。1営業日とは早い。

zetamatta さまが投稿されている記事を確認させていただきましたが、
ガイドラインが指す宣伝行為には該当しないと判断しております。

上記、宣伝が主目的と読み取れる記事については宣伝行為に当たると判断いたしますが、
技術的な解説が主目的である場合には、対象が個人・法人に関わらず宣伝行為には当たりません。

なお、上記の線引については多くのユーザーさまからもお声を頂戴しておりますため
現在ガイドラインの拡充などの対応を検討中です。
準備ができ次第 Qiita公式ブログ や Twitterアカウント にてアナウンスさせていだきますのでお待ちくださいませ。

> 無罪 <

ご回答、ありがとうございました。これで心置きなく、記事を書けるというものです。 今後ともよろしくお願いいたします。

cd ショートカット.lnk

NYAGOS は cd ショートカット.lnk という書き方をサポートしている。

これは Go言語で実装した内蔵コマンドの cd で直接サポートしているわけではなくて、 nyagos.d\cdlnk.luaという Lua スクリプトcdエイリアスを書き、 その中で nyagos.create_object("WScript.Shell") で COM オブジェクトを生成、 それでショートカットの宛先を問い合わせている。

この「cd ショートカット.lnk」を便利に使うため、 自分は %USERPROFILE% の下に開発ソースフォルダーへのショートカットを多数作っている。

ショートカットは無論エクスプローラでも作れるが、いちいちマウスで操作するのも 面倒なので、lnk.js という JScript を書いている。具体的には下記のようなスクリプトになる。

if( WScript.Arguments.length == 1  ){
    var wshShell = new ActiveXObject("WScript.Shell");
    var lnkSrc = wshShell.CreateShortcut(WScript.Arguments.Unnamed(0));
    if( lnkSrc == null ){
        WScript.Echo("Fail to create ShortCut Object");
    } else {
        WScript.Echo( "    " + lnkSrc + "\n<-- " + lnkSrc.TargetPath ); 
    }
    WScript.Quit(1);
}

if( WScript.Arguments.length < 2 ){
    WScript.Echo(
        "Usage: cscript lnk.js FILENAME SHORTCUT {Option=Value}... make shortcut\n" +
        "       cscript lnk.js SHORTCUT          ... print shortcut-target")
    WScript.Quit(1);
}

var fsObj = new ActiveXObject("Scripting.FileSystemObject");
var src = fsObj.GetAbsolutePathName(WScript.Arguments.Item(0));
var dst = fsObj.GetAbsolutePathName(WScript.Arguments.Item(1));

if( fsObj.FolderExists(dst) ){
    dst = fsObj.BuildPath(dst,fsObj.GetFileName(src));
}
if( dst.length >= 4 && dst.substring(dst.length-4) != ".lnk" ){
    dst += ".lnk";
}
var wshShell=new ActiveXObject("WScript.Shell");
var shortcut1=wshShell.CreateShortcut(dst);

if( shortcut1 == null ){
    WScript.Echo("Fail to create ShortCut Object");
    WScript.Quit(1);
}
shortcut1.TargetPath=src;

if( WScript.Arguments.length >= 3 ){
    for(var i=2 ; i < WScript.Arguments.length ; i++ ){
        var equation = WScript.Arguments.Item(i);
        var pos = equation.indexOf("=",0);
        if( pos >= 0 ){
            equation="shortcut1." + equation.substring(0,pos) + "=\"" +
                    equation.substring(pos+1).replace(/\\/g,"\\\\") + "\"";
            WScript.Echo(equation);
            eval(equation);
        }else{
            WScript.Echo("Equal(=) not found: " + equation)
        }
    }
}
shortcut1.Save()
WScript.Echo("    " + src + "\n--> " + dst);
WScript.Quit(0)

こういうのを作っておくと、Visual Studio の開発フォルダーから

cd ~\PATH\TO\DEVELOP\FOLDER1
lnk.js . ~

とかできる。すると

cd FOLDER1.lnk

だけで深いフォルダーへ一気に移動できて、入力が楽になる

無論、mklink でも同様のことが可能だが、そうするとツールによっては見かけのパス構成が変わってしまって、いろいろ不都合がでる場合もある。こちらの方が手軽で有用ではないかと思われるが、いかがだろうか。

Qiita に問い合わせてみました:自作公開OSSに関する解説はガイドラインの「自社の製品の宣伝行為はしない」に抵触しますか?

こんな感じ。現在、返事待ち返信来ました

自作公開OSSに関する解説はガイドラインの「自社の製品の宣伝行為はしない」に抵触しますか?

わたくし、個人で開発している、Windows用拡張コマンドラインシェル NYAGOS (https://github.com/zetamatta/nyagos)というソフトウェアを New BSD ライセンスにて公開しており、本ソフトウェアの機能についての紹介、解説をたびたび [nyagos] というタグで Qiita 様にて書かせていただいています。

これはこの度公開された「ガイドライン」にございます「自社の技術の利用や導入を勧めることを主目的とする記事等、あからさまな宣伝行為は禁止します」に抵触するでしょうか?

「自社」とあることから法人ならばダメだが個人ならばよいとも解釈可能ですが、法人・個人を分ける合理的理由が思い当たらないため、念のため確認させていただきたいと思った次第です。もし、個人でも自作ソフトウェアの紹介にあたるものは NG であるという判断せざるを得ないようでしたら、御社の主旨に従い該当すると思われる記事を順次ひきあげさせていただく所存ですが、もし Ok であればその旨どこかで明示いただけると幸いです。

お忙しいところおそれいりますが、ご検討のほど、よろしくお願いいたします。

スーパーで…

(twitterから転載)

スーパーで、本来は専用の容器を買わないと取ってはいけない氷を、ポリ袋に取り込んでいるじいさんがいた。 やらしいなぁと蔑むような目で見てしまったのだが、 よく考えればじいさんも好きでそんな卑しいことはしたくはないだろう。 豊かであれば、わずかなお金をけちる真似したくはなかっただろう。

知識人が日本が貧しくなることを肯定するようなことをいっているようだが、 こういう実態をわかっているのだろうか。 豊かであればこそ、守れるマナーも、ルールも、誇りもある。 貧しくなければ、ジャン・バルジャンも銀の食器を盗まなかっただろう。

自分は比較的マナーの類いは守るようにしている(と思う、たぶん、きっと)。 それは親が不自由なく育ててくれて、ちゃんと学校に行かせてくれて、 学をつけてひとりでそれなりに食べていけるようお金をかけてくれたからだ。 貧しくなると、そういうことが難しくなってしまう

国が貧しくなるというのは、国民の気品を保つことがまず「しんどく」なることを、 左翼系知識人は自覚して欲しいものだ。終わり