Subscribed unsubscribe Subscribe Subscribe

git grep+pecoで絞りこんだ結果をvimで開く時、git grep word | x としたい

はじめは grep-vim word みたいな関数でいいかなと思っていたんだけど、「git grep した後に開きたいファイルがあることが分かる」というようなケースが何度かあって、そうなると、人/設定等によっても違うだろうけども git grep word から grep-vim word とするのに一個履歴を遡ってから C-a -> M-d -> M-d -> x となってちょっと面倒。| -> x でやりたいという気持ちが強まってこういう感じにした。

find-and-open-file() {
  input=$(cat)
  selected=$(echo $input | grep '.\+:[0-9]\+:.*' | peco)
  echo "$selected" | awk -F : '{print "-c " $2 " " $1}' | xargs -o vim 
}
alias fof=find-and-open-file

そもそもこの用途だと「git grep した後に開きたいファイルがあることが分かる」って時点でだいたい開きたいファイルが決まってるから x filename:line_number で開ければいい気がしないでもない

参考

jaws-framework で作ったアプリケーションを MFA によって保護された API アクセスでデプロイする

JAWS/best_practices.md at 6bfd2ca7a00054b750add46a909af3f4a9d4a749 · jaws-framework/JAWS · GitHub によると cloudformation の実行は jaws が生成したテンプレートを多段階の認証を経てAWS Consoleにアクセスし、UI上でペーストして実行すると良いみたいなことが書いてあるが、とてもやりたくないと思う。

かといってアクセスキーで認証できるアカウントに AdministratorAccess をやらないというは確かにそうしたい。

CLIAPI アクセスも MFA で認証する方法があることを知って、上の記事を読むと意外に手間がかからなかった。

  • IamUser: jaws (MFA 有効化 + アクセスキー発行 + いくらか使いたいポリシーをアタッチ)
  • Role: cfn-executer (MFA による認証が済んだ jaws ユーザーにロールを使うのを許可している)

を用意して ~/.aws/credentialsをこのようにした。

[toqoz-jaws]
aws_access_key_id = aaa # jawsユーザーのアクセスキー
aws_secret_access_key = AAA
[toqoz-jaws-cloudformation]
source_profile = toqoz-jaws
role_arn = arn:aws:iam::$ACCOUNT_ID:role/cfn-executer
mfa_serial = $MFA_SERIAL

aws cli とかだと、これでプロファイル toqoz-jaws-cloudformation を使えば勝手に mfa code を聞いてくれるんだけど、jaws dash はそうもいかなかったので、cloudformation の update は aws cli からそれ以外は jawsのコマンドでやることにした

bin/deploy

~/.aws/credentials の default を削除した

もともと default しか無いところに B を追加してこういう形になっていて、B でやりたい時は指定するようにしていた。

[default]
aws_access_key_id = AAA
aws_secret_access_key = aaa
[B]
aws_access_key_id = BBB
aws_secret_access_key = bbb

--profile オプション(もしくは環境変数 AWS_PROFILE)付け忘れてる時に、意図せず A のアカウントで実行されたりしてヒヤッとしたりしたので default を消した。

[A]
aws_access_key_id = AAA
aws_secret_access_key = aaa
[B]
aws_access_key_id = BBB
aws_secret_access_key = bbb

常にどれかを指定しないといけなくなったけど、今のところちょっと面倒以外に問題はないのでまあいいかと思ってる。

AWS Lambdaを利用しスクレイピングしたい

  • なんとか EC2 にインスタンス立てたりすることなく楽に安く済ませたい
  • 適度な速度でHTMLをダウンロードしてきたい

HTML 保存した後はまあ適当にやれば良いと思っていて、ゆっくりダウンロードしてくるところが面倒。

今動いてるやつは 200-300個ぐらいしか URL がないのもあって Timeout を5分に設定した lambda:crawl で setTimeout しながら lambda:download_html を invoke してるんだけど増えてきて5分で終わらなくなったら困るなというのがあって考えたやつ

1つめの方法

  1. 適当な URL が DynamoDB とかに入ってるとして lambda:crawl で Table を Scan して SQS へ {s3_key: "", url: ""} のようなメッセージを送っていく
  2. lambda:consume_download_html_queue を Scheduled Event で5分おきに実行し、適度な速度で5分間メッセージを消費/lambda:download_html の invoke を行う
  3. lambda:download_html で HTML をダウンロードし、S3 に Put する

2つめの方法

SQS について調べるの面倒だなと思っていたら浮かんだやつ。

{tableName: "ダイナモ"} みたいなのを渡されてそっから URL とってきて動きはじめて、いくらか処理してから残ってたら自分に {urls: [処理してないURL]} を渡してinvoke する。

var AWS = require("aws-sdk");
var lambda = new AWS.Lambda();
var dynamoDB = new AWS.DynamoDB();
var s3 = new AWS.S3();

var Promise = require('bluebird');
Promise.promisifyAll(Object.getPrototypeOf(dynamoDB));
Promise.promisifyAll(Object.getPrototypeOf(lambda));

var MAX_FETCH_COUNT = 300;
var FETCH_INTERVAL = 1000;
var DOWNLOAD_HTML_LAMBDA_FUNCTION_NAME = "download-html";

exports.handler = function crawl(event, context) {
  console.log("start to crawl");

  var fetchUrls = event.urls ? Promise.resolve(event.urls) : fetchUrlsFromTable(event.tableName);
  fetchUrls
    .then(function(urls) {
      var fetchCount = Math.min(MAX_FETCH_COUNT, urls.length);
      var urlsToFetch = [];
      for (var i = 0; i < fetchCount; i++) {
        urlsToFetch.push(urls.pop());
      }

      return Promise
        .all(urlsToFetch.map(function(item, index) {
          // downloaded_html/site_a/ 以下にズラっとファイルを並べたいので / を適当に置換しておく
          var s3_key = "downloaded_html/site_a/" + url.replace(/\//g, "$");
          var params = buildLambdaParams(DOWNLOAD_HTML_LAMBDA_FUNCTION_NAME, {
            url: url,
            s3_key: s3_key
          });
          return delayedLambdaInvoke(params, FETCH_INTERVAL * index);
        }))
        .then(function(_) {
          console.log("finish to crawl");

          if (urls.length > 0) {
            var params = buildLambdaParams(process.env.AWS_LAMBDA_FUNCTION_NAME, {
              urls: urls
            });
            return lambda.invokeAsync(params);
          }
        });
    })
    .then(function(_) {
      context.done(null, "OK");
    })
    .catch(function(err) {
      context.done(err);
    });
};

function fetchUrlsDynamoDB(tableName) {
  return dynamoDB
    .scanAsync({
      TableName: tableName
    })
    .then(function(data) {
      var urls = [];
      data.Items.forEach(function(item) {
        urls.push(item.url.S);
      });

      return Promise.resolve(urls);
    });
}

function delayedLambdaInvoke(params, delay) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      console.log("Invoke lambda with " + JSON.stringify(params, null, 2));

      lambda.invokeAsync(params, function(err, data) {
        if (err) {
          reject(err);
        } else {
          resolve(data);
        }
      });
    }, delay);
  });
}

function lambdaInvoke(params) {
  return new Promise(function(resolve, reject) {
    console.log("Invoke lambda with " + JSON.stringify(params, null, 2));

    lambda.invokeAsync(params, function(err, data) {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
}

function buildLambdaParams(funcName, payloadObject) {
  return {
    FunctionName: funcName,
    InvocationType: 'Event',
    LogType: 'None',
    Payload: JSON.stringify(payloadObject, null, 2),
  };
}

API Gateway+LambdaでWebサイトを作っている時に404ページを出す最悪な方法

*で/含めてなんでも受けれるみたいな機能があったならもう少し嬉しいんだけど、特にそれっぽいのも見付からなかったので。 /a/b/c/d まではこれでなんとなく動いてるので、このまま放置して忘れたい。

f:id:ToQoz:20151128033415p:plain

TexturePackerのフリーライセンスを申請した

自分のブログのURLを書く欄があるんだけど、それが自分のだと証明するためにコード(TP:A1EC9A8E)をどっか見えるところに置いてくれって書いてあったので。ついでになんで使ってるかというと、

  1. sketchtoolでスライス書き出し -> 2. onion_ringで9patch -> 3. TexturePackerでTextureAtlas作る -> 4. Unity上で2, 3の情報を持たせる

ということをするために使っている。c.f. http://qiita.com/kyubuns/items/cb01f926966b51a5501c


Tools/sketchimport

#!/bin/sh

ROOT=$(dirname $0)/..

sketchtool export layers $ROOT/Sketches/Dark.sketch --output=$ROOT/Images/Export

# 9patch
find $ROOT/Images/Export/UI -depth 1 -type f | grep ".9.png" | $ROOT/Tools/9patch > $ROOT/Assets/Images/UI_border.txt

# pack
TexturePacker --max-size 2048 --opt RGBA4444 --format unity-texture2d --sheet Assets/Images/UI.png --data Assets/Images/UI.tpsheet Images/Export/UI

Tools/9patch

#!/usr/bin/env bundle exec ruby

require_relative "../Deps/onion_ring/onion_ring.rb"

borders = []
ARGF.each do |before|
  before = File.expand_path(before.chomp)
  name = File.basename(before).gsub(".png", "")
  borders << [name, OnionRing::run(before, before)]
end

borders_text = borders.map { |line| line.flatten.join(',') }.join("\n")
STDOUT.puts borders_text

# vim:set ft=ruby:

みたいなのを書いといて、Tools/sketchimport 実行するやつと http://qiita.com/kyubuns/items/cb01f926966b51a5501c の AtlasBorderSetter.cs をEditor以下置いて、TexturePacker ImporterってのをAsset Storeからインポートおく。そうすると.sketchいじった後はUnity開いたら上手いことなっている。

初めてメールでパッチを送った

プログラムを書き始めた時にはもうgithubがあったので、どういう風な作法で送るのか全然分からなくて困った。

あたりを読んで、git format-patch でパッチを作って git send-email で送るのが楽っぽいことが分かった。

上記のLinuxのパッチの送り方だと添付ファイルで送るなって書いてあったんだけど、送ろうとしているtmuxのメーリングリストを見ると添付してるのもインラインで書いてるのも両方あった。 git format-patch も --attach っていうの指定すると添付ファイルとして送るように保存してくれる。悩んだあげくどっちでも受け入れられているなら見るための敷居が低くて検索/引用しやすいようにインラインのほうにした。

http://sourceforge.net/p/tmux/mailman/message/33500685/


たいしたことないものとはいえ、githubでpull request出すよりもかなり緊張感があった。

KeyRemap4MacBook から名前が変わって結構立つ気がするけど未だに綴りを間違えるkarabinerと、seilだけども

  • /Applications/Karabiner.app/Contents/Library/bin/karabiner
  • /Applications/Seil.app/Contents/Library/bin/seil

が入ってて、コマンドラインで色々出来る。

で今の状態まで karabiner set 使って持ってこう。ちょっと面倒だなあ。と思ったんだけど、karabiner export とかってやると求めているものがまるっとexportされて便利だった。

goコマンドで予約されている(特別な意味を表わしてる)インポートパス

golang go

go get -u all とか go get -u std って出来るの知った。めちゃくちゃ便利。

(mainもっぽいけどそれに対しての何か実装はまだ見つけてない)

testing.Mが追加されテスト実行前後に何かを書けるようになった

go golang

例えば

// main_test.go

var exitCode = 0

func TestMain(m *testing.M) {
    defer os.Exit(exitCode)

    beforeAll()
    defer afterAll()

    exitCode = m.Run()
}

func beforeAll() {}
func afterAll() {}

みたいにして、mainパッケージのようにテスト実行の前後に適当処理入れたりとかが出来るようになった(1.4rc2から)。 mysqldとかテストの間ずーっと立ちあげといて最後に止めたいもの(テスト毎やるとコストがかかるもの)があったりすると重宝すると思う。


以前からそういう願望があった。

たしか1.3かその直前ぐらいだったと思うけど、なんとかできないかなと思ってそのへんのコード読んでいると「TestGoFilesのASTを順番見てってfunc Test*(*testing.T) をひろってテンプレートに渡して、それを実行する。」な風になっていてそれを利用してこういうことをしていた。

testing.Mainも自由にやりたい、もしくはtesting.after書きかえたい
testing.afterを自由にしたかった。テストの最後になんかしたかった。golang - コンドルが飛んでいる。 2014/01/14

久々にGo書いていて、ふと他にやり方ないかもう一回見とこうと cmd/go/test.go とか testing あたりを見ていたら、testing.M とか TestMain(*testing.M) とかってのがあって、どうやらこれは目的のものだってことで喜んでいた。

net/httpz_last_test.go もこれを使った形に書き直されている。 net/http: replace z_last_test hack with testing.Main · 93e5cc2 · golang/go · GitHub

とりあえずここに落ち着いたGoの即時実行環境 -2014年冬-

goで同一ディレクトリに、複数main.mainをおきたい - コンドルが飛んでいる。

の続編。上記の方法だと色々と不満があったので、適当なtempdirにmain.go置いて$EDITOR立ちあげて編集終えると実行するやつみたいなの作った。

ToQoz/gomain · GitHub

一回で上手くかけるとは限らないのでさっきの続きから書きはじめるのどうしようかなーと思って放置してたんだけど、 実行後にもっかい編集する? って聞いて同意した場合前回のやつから書けるようにした。

demo.gif

近所の医者に行ったら、オイ、デングということでデカめ病院のとこに行かされて検査してきたんだけど特に何もなくて単なる風邪っぽいねってなった。 まあ良かったんだけど、とにかくこの一連の行動に半日ぐらいかかってメチャクチャ疲れた。 後日おたふくワクチンの効果が切れかけだから今度打っとけってのと、サイトメガロウイルスとやらの抗体がないからそのうちそれ感染するかもだから覚えといてってのも言われた。

Internal Server Error

GoでWeb API書いてる時に、システム内部のエラーだったりで詳細をそのままユーザーに返さないもの、例えば(*sql.DB).Execとかでもいいんだけどそういうのをどう扱うか悩んでる。

  • どうせhttp.Handlerはpanic起こったらInternal server error返すようみたいな作りにするだろうし、モデルっぽいところでpanicしてしまう。
  • http.Handler内でエラーを比較してって必要なものだけ詳細を返す、マッチしなかったらログ吐いて、serveInternalServerError(http.ResponseWriter, *http.Response)みたいなのに渡す。

gopwt(PowerAssert for golang)がだいたいできた

http://github.com/ToQoz/gopwt

この時は、「Assert内で副作用のある関数を呼んでいるとそれがコケた場合に、出力の時に再度呼ばれて実際の値と違うものが表示されたり、それ以降のテストに影響がある」みたいな問題があった。それを解決するには適当に関数の呼び出しをキャッシュしてやる必要があって、型のチェックが実行時にしかない言語なら、a() == b() とかってのを memorized(a) == memorized(b) とかってできると思うけど、わりかし大変だった。

  • reflect.ValueOf(f).Call(reflect.ValueOf(arg1), reflect.ValueOf(arg2))[0].Interface() というように変換して変換後のコンパイル時の型のチェックを捨てる
  • そうすると取れる型が決まってる二項演算子が使えない Opなんとか(x, y interface{}) を実装してその中で型をチェックしながら適当に適用していく感じにする
  • 組み込みの関数は、reflect.ValueOf(f).Call で呼べないから普通に呼ぶがそうすると型がハマらないので Op*と一緒のようなものを実装する
  • このへんまではまあ別にいいかなと思ってたんだけど、型の変換(string('r')) で上手くいかないことに気付いてかなり辛くなる。
  • こざかしいことをして*ast.CallExprが普通の関数呼び出しか型の変換かを調べて、後者なら reflect.ValueOf(x).Convert(reflect.ValueOf(new(t)).Elem().Type()) に変換する。

みたいなことをやった。こざかしいことは、code.google.com/p/go.tools/goのgcimporterとtypesのおかげで、楽に出来たんだけど一気にブラックボックス感が高まった感じがした。

そもそもこういうアプローチはGoっぽくないと思う(作る前もgo testに乗せれないかとかなんとか色々悩んだ)けど、TDDでdebugの代わりのテストみたいなのを書いて開発してく時とか、CIでテストコケた時の情報量の多さは結構メリットがあるかなと思う。自分以外が関わるところでこれに依存したテストをコミットするかどうかは今のところ自分自身悩ましい感じはある。まずはv0.0.1を打てるようにやっていく予定

(仕事する気力が無さすぎてエントリ書き出したものの気力がないから雑になった。)