2012/05/07


  • 絶対パスの先頭に/が来る事を期待してはいけない
  • しかしながら絶対パスの先頭にドライブレターが来る事を期待してはいけない
  • UNCパスのホスト名やシェア名はディレクトリではないのでファイルシステムAPIは使えない事を意識しておく
  • unixに比べパス内に空白文字が入る可能性が高い事を意識しておく
  • ホームディレクトリを意味するパスの先頭チルダは自前で展開する必要があり、またパスの途中にチルダが混じる事は日常的にある
  • ソケットディスクリプタに対してもread/writeで送受信できる事を期待してはいけない
  • パイプでない標準入力のselectはやっても意味がない
  • ディレクトリ内にあるファイルを開き、ハンドルを保持したままディレクトリを消せるのは当たり前だと思わない
  • パスのセパレータがである事を期待してANSI APIを使ってはいけない
  • Cランタイム(POSIX互換API)とWindows APIを併用する際にはerrnoを信用してはならない
  • PATH環境変数のセパレータが:であることを期待してはいけない
  • コマンドラインプログラムの引数はシェルにあたるcmd.exeが展開しているのではなく、プログラム自身が展開しているのでワイルドカードが展開される事を期待してはいけない
  • system関数を使う際にコマンドの引数をシングルクォートでクォートしない方が良い
  • エスケープシーケンスはリテラルに埋め込まず切り離し可能にしておく
  • utf-8にしか存在しないグリフは極力使用しない
  • forkは可能な限り使わない
  • fork&execはCreateProcessに置き換わるので、なるべく部品化し置き換え易くしておく
  • テンポラリファイルの削除をランタイムの後処理に期待してはいけない
  • unixドメインソケットや、名前付きパイプファイルは、TCP/IPソケットやWindowsでの名前付きパイプに置き換わるのでファイルシステムを意識した処理を纏めて行い部品化する
  • cygwinで出来るよ→ダウト
Posted at by



2012/05/03


unite.vim と ctrlp をつかってみた比較 - ”><xmp>TokuLog 改メ tokuhirom’s blog
  • 存在しないファイル名いれたときに作れない
  • 存在しないディレクトリ名いれたときに mkpath モードにはいれない
http://d.hatena.ne.jp/tokuhirom/20120502/1335936640

存在しないファイル名いれたときに作れない

作れます!
ctrlp1
CtrlPを起動するとこんな風になっています。この autoload の下にファイルを作りましょう。
au とだけタイプすれば autoload/zencoding.vim だけに絞りこまれているはずです。絞りこまれてなければ移動させて下さい。
ここで <c-z> をタイプしマークします。以下は分かりやすいように a だけで絞り込んだ場合の模様です。
ctrlp2
マークされたら入力した au<c-w> で消して、作りたいファイル名をタイプした後に <c-y> で作れます。

mkpath については現在 CtrlP の作者に相談中です。

追記
既に、親ディレクトリが自動で作られる機能は入ってるそうです。
Posted at by



2012/05/02


BigQueryが正式版としてリリースされたようです。
Google、ビッグデータ分析サービス「BigQuery」を一般公開 - ITmedia ニュース

米Googleは11月14日(現地時間)、同社のクラウド上でいわゆる「ビッグデータ」を分析する企業向けサービス「Google BigQuery Service」のプレビュー版を公開したと発表した。正式版は有料になる見込みだが、現在は無料で利用できる。

http://www.itmedia.co.jp/news/articles/1111/15/news028.html
サンプルデータも幾つかある様で、githubのリポジトリ情報を格納している物もあったので試しにGo言語からクエリを発行して問い合わせてみた。 以下コード。 package main

import (
    "code.google.com/p/goauth2/oauth"
    "code.google.com/p/google-api-go-client/bigquery/v2"
    "encoding/gob"
    "fmt"
    "log"
    "net/http"
    "net/http/httptest"
    "net/url"
    "os"
    "os/exec"
    "path/filepath"
    "runtime"
    "time"
)

func osUserCacheDir() string {
    switch runtime.GOOS {
    case "darwin":
        return filepath.Join(os.Getenv("HOME"), "Library""Caches")
    case "linux""freebsd":
        return filepath.Join(os.Getenv("HOME"), ".cache")
    }
    log.Printf("TODO: osUserCacheDir on GOOS %q", runtime.GOOS)
    return "."
}

func tokenFromWeb(config *oauth.Config) *oauth.Token {
    ch := make(chan string)
    randState := fmt.Sprintf("st%d", time.Now())
    ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
        if req.URL.Path == "/favicon.ico" {
            http.Error(rw, ""404)
            return
        }
        if req.FormValue("state") != randState {
            log.Printf("State doesn't match: req = %#v", req)
            http.Error(rw, ""500)
            return
        }
        if code := req.FormValue("code"); code != "" {
            fmt.Fprintf(rw, "<h1>Success</h1>Authorized.")
            rw.(http.Flusher).Flush()
            ch <- code
            return
        }
        log.Printf("no code")
        http.Error(rw, ""500)
    }))
    defer ts.Close()

    config.RedirectURL = ts.URL
    authUrl := config.AuthCodeURL(randState)
    go openUrl(authUrl)
    log.Printf("Authorize this app at: %s", authUrl)
    code := <-ch
    log.Printf("Got code: %s", code)

    t := &oauth.Transport{
        Config:    config,
        Transport: http.DefaultTransport,
    }
    _, err := t.Exchange(code)
    if err != nil {
        log.Fatalf("Token exchange error: %v", err)
    }
    return t.Token
}

func openUrl(url string) {
    try := []string{"xdg-open""google-chrome""open"}
    for _, bin := range try {
        err := exec.Command(bin, url).Run()
        if err == nil {
            return
        }
    }
    log.Printf("Error opening URL in browser.")
}

func tokenCacheFile(config *oauth.Config) string {
    return filepath.Join(osUserCacheDir(), url.QueryEscape(
        fmt.Sprintf("go-api-demo-%s-%s-%s", config.ClientId, config.ClientSecret, config.Scope)))
}

func tokenFromFile(file string) (*oauth.Token, error) {
    f, err := os.Open(file)
    if err != nil {
        return nil, err
    }
    t := new(oauth.Token)
    err = gob.NewDecoder(f).Decode(t)
    return t, err
}

func saveToken(file string, token *oauth.Token) {
    f, err := os.Create(file)
    if err != nil {
        log.Printf("Warning: failed to cache oauth token: %v", err)
        return
    }
    defer f.Close()
    gob.NewEncoder(f).Encode(token)
}

func getOAuthClient(config *oauth.Config) *http.Client {
    cacheFile := tokenCacheFile(config)
    token, err := tokenFromFile(cacheFile)
    if err != nil {
        token = tokenFromWeb(config)
        saveToken(cacheFile, token)
    } else {
        log.Printf("Using cached token %#v from %q", token, cacheFile)
    }

    t := &oauth.Transport{
        Token:     token,
        Config:    config,
        Transport: http.DefaultTransport,
    }
    return t.Client()
}

func main() {

    var config = &oauth.Config{
        ClientId:     "XXXXXXXXXXXXX.apps.googleusercontent.com",
        ClientSecret: "YYYYYYYYYYYYYYYYYYYYYYYY",
        Scope:        bigquery.BigqueryScope,
        AuthURL:      "https://accounts.google.com/o/oauth2/auth",
        TokenURL:     "https://accounts.google.com/o/oauth2/token",
    }

    bigqueryService, err := bigquery.New(getOAuthClient(config))
    if err == nil {
        table, err := bigqueryService.Jobs.Query("XXXXXXXXXXXXX", &bigquery.QueryRequest {
            Query: "SELECT repository_description FROM [publicdata:samples.github_timeline] where repository_url = 'https://github.com/mattn/growl-for-linux'",
        }).Do()
        if err == nil {
            for _, row := range table.Rows {
                for _, f := range row.F {
                    println(f.V)
                }
            }
        }
    }
}
XXXXXXXXXXXXX にはプロジェクトIDを(ClientIDの一部になってるみたい)、YYYYYYYYYYYYYYYYYYYYYYYY には ClientSecret を埋めて実行して下さい。発行しているクエリは以下。 SELECT repository_description FROM [publicdata:samples.github_timeline] where repository_url = 'https://github.com/mattn/growl-for-linux'
これを実行すると以下のデータが得られた。 Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
実行はそれほど速くありませんでした。巨大なデータをオンラインで扱えるインフラとしては面白いかなーと思った。
ただ最近の API は OAuth な物が多く、実行するにはアクセストークンが必要になり、アクセストークンを得るにはブラウザを起動する必要がある。今回 Go言語のdatabase/sqlドライバの一つに加えようと思ってけどちょっと難しいかも。どっちかっていうとユーザ単位にアクセストークンを取らせる様なコンシューマサービス向けなのかな。
Posted at by