[
  {
    "path": ".travis.yml",
    "content": "language: go\ngo:\n  - tip\nbefore_install:\n  - go get github.com/mattn/goveralls\n  - go get golang.org/x/tools/cmd/cover\nscript:\n    - $HOME/gopath/bin/goveralls -repotoken MLMW2kUwHGbt4hXxxt7uboywTNJsdqCjr\n"
  },
  {
    "path": "README.md",
    "content": "# qq\n\n[![Build Status](https://travis-ci.org/mattn/qq.svg?branch=master)](https://travis-ci.org/mattn/qq)\n\n[![Coverage Status](https://coveralls.io/repos/github/mattn/qq/badge.svg?branch=master)](https://coveralls.io/github/mattn/qq?branch=master)\n\nSelect stdin with query.\n\n## Usage\n\n```\n$ ps | qq -q \"select pid from stdin\"\n9324\n16344\n13824\n```\n\n```\n$ ps | qq -q \"select command from stdin where pid = 9324\"\n/usr/bin/grep\n```\n\n## Requirements\n\n* go\n\n## Installation\nLibrary install\n```\n$ go get github.com/mattn/qq\n```\nor Command install\n```\n$ go get github.com/mattn/qq/...\n```\n\n## License\n\nMIT\n\n## Author\n\nYasuhiro Matsumoto (a.k.a. mattn)\n"
  },
  {
    "path": "cmd/qq/main.go",
    "content": "package main\n\nimport (\n\t\"encoding/csv\"\n\t\"encoding/json\"\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/mattn/go-encoding\"\n\t\"github.com/mattn/qq\"\n\txenc \"golang.org/x/text/encoding\"\n)\n\nvar (\n\tnoheader   = flag.Bool(\"nh\", false, \"don't treat first line as header\")\n\toutheader  = flag.Bool(\"oh\", false, \"output header line\")\n\tinputcsv   = flag.Bool(\"ic\", false, \"input csv\")\n\tinputtsv   = flag.Bool(\"it\", false, \"input tsv\")\n\tinputltsv  = flag.Bool(\"il\", false, \"input ltsv\")\n\tinputpat   = flag.String(\"ip\", \"\", \"input delimiter pattern as regexp\")\n\toutputjson = flag.Bool(\"oj\", false, \"output json\")\n\toutputraw  = flag.Bool(\"or\", false, \"output raw\")\n\tenc        = flag.String(\"e\", \"\", \"encoding of input stream\")\n\tquery      = flag.String(\"q\", \"\", \"select query\")\n)\n\nfunc main() {\n\tflag.Parse()\n\n\tvar ee xenc.Encoding\n\tif *enc != \"\" {\n\t\tee = encoding.GetEncoding(*enc)\n\t\tif ee == nil {\n\t\t\tfmt.Fprintln(os.Stderr, \"invalid encoding name:\", *enc)\n\t\t\tos.Exit(1)\n\t\t}\n\t}\n\n\tqq, err := qq.NewQQ(&qq.Option{\n\t\tNoHeader:  *noheader,\n\t\tOutHeader: *outheader,\n\t\tInputCSV:  *inputcsv,\n\t\tInputTSV:  *inputtsv,\n\t\tInputLTSV: *inputltsv,\n\t\tInputPat:  *inputpat,\n\t\tEncoding:  ee,\n\t})\n\tif err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n\n\terr = qq.Import(os.Stdin, \"stdin\")\n\tif err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n\n\tfor _, fn := range flag.Args() {\n\t\tif fn != \"-\" {\n\t\t\tfb := filepath.Base(fn)\n\t\t\tf, err := os.Open(fn)\n\t\t\tif err != nil {\n\t\t\t\tfmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t\terr = qq.Import(f, fb)\n\t\t\tf.Close()\n\t\t\tif err != nil {\n\t\t\t\tfmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t}\n\n\tif *query == \"\" {\n\t\t*query = \"select * from stdin\"\n\t}\n\n\trows, err := qq.Query(*query)\n\tif err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n\n\tif *outputjson {\n\t\terr = json.NewEncoder(os.Stdout).Encode(rows)\n\t} else if *outputraw {\n\t\tfor _, row := range rows {\n\t\t\tfor c, col := range row {\n\t\t\t\tif c > 0 {\n\t\t\t\t\tfmt.Print(\"\\t\")\n\t\t\t\t}\n\t\t\t\tfmt.Print(col)\n\t\t\t}\n\t\t\tfmt.Println()\n\t\t}\n\t} else {\n\t\terr = csv.NewWriter(os.Stdout).WriteAll(rows)\n\t}\n\tif err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "qq.go",
    "content": "package qq\n\nimport (\n\t\"bufio\"\n\t\"database/sql\"\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"regexp\"\n\t\"strings\"\n\t\"unicode\"\n\n\txenc \"golang.org/x/text/encoding\"\n\n\t\"github.com/mattn/go-runewidth\"\n\t_ \"github.com/mattn/go-sqlite3\"\n\t\"github.com/najeira/ltsv\"\n)\n\nconst (\n\tComma = \",\"\n)\n\n// QQ is the most basic structure of qq\ntype QQ struct {\n\tdb  *sql.DB\n\tOpt *Option\n}\n\n// Option is a structure that qq command can receive\ntype Option struct {\n\tNoHeader  bool\n\tOutHeader bool\n\tInputCSV  bool\n\tInputTSV  bool\n\tInputLTSV bool\n\tInputPat  string\n\tEncoding  xenc.Encoding\n}\n\nvar renum = regexp.MustCompile(`^[+-]?[1-9][0-9]*(\\.[0-9]+)?(e-?[0-9]+)?$`)\n\nfunc readLines(r io.Reader) ([]string, error) {\n\tvar lines []string\n\tscanner := bufio.NewScanner(r)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif strings.TrimSpace(line) == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tlines = append(lines, line)\n\t}\n\treturn lines, scanner.Err()\n}\n\nfunc (qq *QQ) lines2rows(lines []string) [][]string {\n\tcr := []rune(lines[0])\n\tw := 0\n\n\trows := make([][]string, len(lines))\n\ti := 0\n\nskip_white:\n\tfor ; i < len(cr); i++ {\n\t\tfor _, line := range lines {\n\t\t\tif !unicode.IsSpace(rune(line[i])) {\n\t\t\t\tbreak skip_white\n\t\t\t}\n\t\t}\n\t\tw++\n\t}\n\tli := i\n\n\tfor ; i < len(cr); i++ {\n\t\tr := cr[i]\n\t\tw += runewidth.RuneWidth(r)\n\t\tlast := i == len(cr)-1\n\n\t\tif i == 0 || (!unicode.IsSpace(r) && !last) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif last {\n\t\t\tfor ri := range rows {\n\t\t\t\tfv := strings.TrimSpace(string(([]rune(lines[ri]))[li:]))\n\t\t\t\tif ri == 0 && fv == \"\" && !qq.Opt.NoHeader {\n\t\t\t\t\tfv = fmt.Sprintf(\"______f%d\", ri+1)\n\t\t\t\t}\n\t\t\t\trows[ri] = append(rows[ri], fv)\n\t\t\t}\n\t\t} else {\n\t\t\tpart := false\n\t\t\tfor _, line := range lines {\n\t\t\t\tpr := []rune(runewidth.Truncate(line, w, \"\"))\n\t\t\t\tif !unicode.IsSpace(pr[len(pr)-1]) {\n\t\t\t\t\tpart = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !part {\n\t\t\t\tfor ri := range rows {\n\t\t\t\t\tlr := []rune(lines[ri])\n\t\t\t\t\tib := i\n\t\t\t\t\tif ib >= len(lr) {\n\t\t\t\t\t\tib = len(lr) - 1\n\t\t\t\t\t}\n\t\t\t\t\tfv := strings.TrimSpace(string(lr[li:ib]))\n\t\t\t\t\tif ri == 0 && fv == \"\" && !qq.Opt.NoHeader {\n\t\t\t\t\t\tfv = fmt.Sprintf(\"______f%d\", ri+1)\n\t\t\t\t\t}\n\t\t\t\t\trows[ri] = append(rows[ri], fv)\n\t\t\t\t}\n\n\t\t\t\tfor ; i < len(cr); i++ {\n\t\t\t\t\tcw := runewidth.RuneWidth(r)\n\t\t\t\t\tfor _, line := range lines {\n\t\t\t\t\t\tpr := []rune(runewidth.Truncate(line, w+cw, \"\"))\n\t\t\t\t\t\tif !unicode.IsSpace(pr[len(pr)-1]) {\n\t\t\t\t\t\t\tpart = true\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif part {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tw += cw\n\t\t\t\t}\n\n\t\t\t\tli = i\n\t\t\t}\n\t\t}\n\t}\n\treturn rows\n}\n\n// NewQQ creates new connection to sqlite3\nfunc NewQQ(opt *Option) (*QQ, error) {\n\tdb, err := sql.Open(\"sqlite3\", \":memory:\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &QQ{db, opt}, nil\n}\n\nconst (\n\tsqliteINTEGER = \"INTEGER\"\n\tsqliteTEXT    = \"TEXT\"\n\tsqliteREAL    = \"REAL\"\n)\n\ntype column struct {\n\tName string\n\tType string\n}\n\nfunc newColumn(name string) *column {\n\treturn &column{\n\t\tName: name,\n\t\tType: sqliteINTEGER,\n\t}\n}\n\nfunc (qq *QQ) columnsAndRows(r io.Reader) (cn []*column, rows [][]string, err error) {\n\tif qq.Opt.Encoding != nil {\n\t\tr = qq.Opt.Encoding.NewDecoder().Reader(r)\n\t}\n\tif qq.Opt.InputCSV {\n\t\trows, err = csv.NewReader(r).ReadAll()\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t} else if qq.Opt.InputTSV {\n\t\tcsv := csv.NewReader(r)\n\t\tcsv.Comma = '\\t'\n\t\trows, err = csv.ReadAll()\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t} else if qq.Opt.InputLTSV {\n\t\trawRows, err := ltsv.NewReader(r).ReadAll()\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tkeys := make(map[string]struct{})\n\t\tfor _, rowMap := range rawRows {\n\t\t\tfor k := range rowMap {\n\t\t\t\tkeys[k] = struct{}{}\n\t\t\t}\n\t\t}\n\t\tfor k := range keys {\n\t\t\tcn = append(cn, newColumn(k))\n\t\t}\n\t\tfor _, rowMap := range rawRows {\n\t\t\trow := make([]string, len(cn))\n\t\t\tfor i, v := range cn {\n\t\t\t\trow[i] = rowMap[v.Name]\n\t\t\t}\n\t\t\trows = append(rows, row)\n\t\t}\n\t} else if qq.Opt.InputPat != \"\" {\n\t\tlines, err := readLines(r)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tif len(lines) == 0 {\n\t\t\treturn nil, nil, nil\n\t\t}\n\t\tre, err := regexp.Compile(qq.Opt.InputPat)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tfor _, line := range lines {\n\t\t\trows = append(rows, re.Split(line, -1))\n\t\t}\n\t} else {\n\t\tlines, err := readLines(r)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tif len(lines) == 0 {\n\t\t\treturn nil, nil, nil\n\t\t}\n\t\trows = qq.lines2rows(lines)\n\t}\n\n\tif !qq.Opt.InputLTSV {\n\t\tif qq.Opt.NoHeader {\n\t\t\tfor i := 0; i < len(rows[0]); i++ {\n\t\t\t\tcn = append(cn, newColumn(fmt.Sprintf(`f%d`, i+1)))\n\t\t\t}\n\t\t} else {\n\t\t\tfor _, v := range rows[0] {\n\t\t\t\tcn = append(cn, newColumn(v))\n\t\t\t}\n\t\t}\n\t}\n\tif !qq.Opt.NoHeader && !qq.Opt.InputLTSV {\n\t\trows = rows[1:]\n\t}\n\tfor _, row := range rows {\n\t\tfor i, col := range row {\n\t\t\tif col == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcolDef := cn[i]\n\t\t\tif colDef.Type == sqliteTEXT {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif matches := renum.FindStringSubmatch(col); len(matches) > 0 {\n\t\t\t\tif matches[1] != \"\" || matches[2] != \"\" {\n\t\t\t\t\tcolDef.Type = sqliteREAL\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcolDef.Type = sqliteTEXT\n\t\t\t}\n\t\t}\n\t}\n\treturn cn, rows, nil\n}\n\n// Import from csv/tsv files or stdin\nfunc (qq *QQ) Import(r io.Reader, name string) error {\n\tcn, rows, err := qq.columnsAndRows(r)\n\tif err != nil || len(rows) == 0 {\n\t\treturn err\n\t}\n\ts := `create table '` + strings.Replace(name, `'`, `''`, -1) + `'(`\n\tfor i, n := range cn {\n\t\tif i > 0 {\n\t\t\ts += Comma\n\t\t}\n\t\ts += fmt.Sprintf(`'%s' %s`, strings.Replace(n.Name, `'`, `''`, -1), n.Type)\n\t}\n\ts += `)`\n\t_, err = qq.db.Exec(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ts = `insert into '` + strings.Replace(name, `'`, `''`, -1) + `'(`\n\tfor i, n := range cn {\n\t\tif i > 0 {\n\t\t\ts += Comma\n\t\t}\n\t\ts += `'` + strings.Replace(n.Name, `'`, `''`, -1) + `'`\n\t}\n\ts += `) values`\n\td := ``\n\tfor _, row := range rows {\n\t\tif d != `` {\n\t\t\td += `,`\n\t\t}\n\t\td += `(`\n\t\tfor i, col := range row {\n\t\t\tif i >= len(cn) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif i > 0 {\n\t\t\t\td += Comma\n\t\t\t}\n\t\t\tif renum.MatchString(col) {\n\t\t\t\td += col\n\t\t\t} else {\n\t\t\t\td += `'` + strings.Replace(col, `'`, `''`, -1) + `'`\n\t\t\t}\n\t\t}\n\t\td += `)`\n\t}\n\t_, err = qq.db.Exec(s + d)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Query runs a query and formatize result set\nfunc (qq *QQ) Query(query string) ([][]string, error) {\n\tqrows, err := qq.db.Query(query)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer qrows.Close()\n\n\tcols, err := qrows.Columns()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(cols) == 0 {\n\t\treturn nil, nil\n\t}\n\n\trows := [][]string{}\n\tif qq.Opt.OutHeader {\n\t\trows = append(rows, cols)\n\t}\n\n\tvalues := make([]interface{}, len(cols))\n\tptrs := make([]interface{}, len(cols))\n\tfor i := range cols {\n\t\tptrs[i] = &values[i]\n\t}\n\tfor qrows.Next() {\n\t\terr = qrows.Scan(ptrs...)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tcells := []string{}\n\t\tfor _, val := range values {\n\t\t\tb, ok := val.([]byte)\n\t\t\tvar v string\n\t\t\tif ok {\n\t\t\t\tv = string(b)\n\t\t\t} else {\n\t\t\t\tv = fmt.Sprint(val)\n\t\t\t}\n\t\t\tcells = append(cells, v)\n\t\t}\n\t\trows = append(rows, cells)\n\t}\n\n\treturn rows, nil\n}\n\n// Close database connection\nfunc (qq *QQ) Close() error {\n\treturn qq.db.Close()\n}\n"
  },
  {
    "path": "qq_test.go",
    "content": "package qq\n\nimport (\n\t\"io\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n)\n\nvar testcasesReadlines = []struct {\n\tinput  string\n\toutput []string\n}{\n\t{\n\t\tinput: \"  PID command   \\n\" +\n\t\t\t\"\\n\" +\n\t\t\t\"   1   ls       \\n\",\n\t\toutput: []string{\n\t\t\t\"  PID command   \", \"   1   ls       \",\n\t\t},\n\t},\n}\n\nfunc TestReadLines(t *testing.T) {\n\tfor _, testcase := range testcasesReadlines {\n\t\tlines, err := readLines(strings.NewReader(testcase.input))\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tif !reflect.DeepEqual(lines, testcase.output) {\n\t\t\tt.Fatalf(\"%q should be read as %v: got %v\", testcase.input, testcase.output, lines)\n\t\t}\n\t}\n}\n\nvar testcasesLines2rows = []struct {\n\tinput  []string\n\toutput [][]string\n}{\n\t{\n\t\tinput: []string{\n\t\t\t\"  PID command   \",\n\t\t\t\"   1   ls       \",\n\t\t},\n\t\toutput: [][]string{\n\t\t\t{\"PID\", \"command\"}, {\"1\", \"ls\"},\n\t\t},\n\t},\n\t{\n\t\tinput: []string{\n\t\t\t\"  PID command   \",\n\t\t\t\"     1   ls     \",\n\t\t},\n\t\toutput: [][]string{\n\t\t\t{\"PID command\"}, {\"1   ls\"},\n\t\t},\n\t},\n\t{\n\t\tinput: []string{\n\t\t\t\"  PID command   \",\n\t\t\t\"      1   ls    \",\n\t\t},\n\t\toutput: [][]string{\n\t\t\t{\"PID\", \"command\"}, {\"\", \"1   ls\"},\n\t\t},\n\t},\n\t{\n\t\tinput: []string{\n\t\t\t\"      command   \",\n\t\t\t\"    1   ls      \",\n\t\t},\n\t\toutput: [][]string{\n\t\t\t{\"______f1\", \"command\"}, {\"1\", \"ls\"},\n\t\t},\n\t},\n\t{\n\t\tinput: []string{\n\t\t\t\" 1 \",\n\t\t\t\"  \",\n\t\t},\n\t\toutput: [][]string{\n\t\t\t{\"1\"}, {\"\"},\n\t\t},\n\t},\n\t{\n\t\tinput: []string{\n\t\t\t\"   \",\n\t\t\t\" 1 \",\n\t\t},\n\t\toutput: [][]string{\n\t\t\t{\"______f1\"}, {\"1\"},\n\t\t},\n\t},\n\t{\n\t\tinput: []string{\n\t\t\t\"a b\",\n\t\t\t\"1 \",\n\t\t},\n\t\toutput: [][]string{\n\t\t\t{\"a\", \"b\"}, {\"1\", \"\"},\n\t\t},\n\t},\n}\n\nfunc TestLines2Rows(t *testing.T) {\n\tqq, err := NewQQ(&Option{})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer qq.Close()\n\n\tfor _, testcase := range testcasesLines2rows {\n\t\trows := qq.lines2rows(testcase.input)\n\t\tif !reflect.DeepEqual(rows, testcase.output) {\n\t\t\tt.Fatalf(\"%q should be parsed as %v: got %v\", testcase.input, testcase.output, rows)\n\t\t}\n\t}\n}\n\nfunc test(r io.Reader, name string, query string, opt *Option) ([][]string, error) {\n\tqq, err := NewQQ(opt)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer qq.Close()\n\n\terr = qq.Import(r, name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trows, err := qq.Query(query)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn rows, nil\n}\n\nfunc TestQQ(t *testing.T) {\n\tinput := `\nPID command\n  1 /usr/bin/ls\n  2 /usr/bin/grep\n  3 /usr/bin/php run.php --opt='1'\n`\n\trows, err := test(strings.NewReader(input), \"stdin\", \"select pid from stdin\", &Option{})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif len(rows) != 3 {\n\t\tt.Fatalf(\"rows should have three row: got %v\", rows)\n\t}\n\n\tif len(rows[0]) != 1 {\n\t\tt.Fatalf(\"columns should have only one: got %v\", rows[0])\n\t}\n\n\tif rows[0][0] != \"1\" {\n\t\tt.Fatalf(\"first result should be 1: got %v\", rows[0][0])\n\t}\n\n\tif rows[1][0] != \"2\" {\n\t\tt.Fatalf(\"second result should be 2: got %v\", rows[0][0])\n\t}\n\n\tif rows[2][0] != \"3\" {\n\t\tt.Fatalf(\"second result should be 3: got %v\", rows[0][0])\n\t}\n\n\trows, err = test(strings.NewReader(input), \"stdin\", \"select command from stdin where pid = 2\", &Option{})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif rows[0][0] != \"/usr/bin/grep\" {\n\t\tt.Fatalf(\"result should be '/usr/bin/grep': got %v\", rows[0][0])\n\t}\n\n\trows, err = test(strings.NewReader(input), \"stdin\", \"select command from stdin where pid = 3\", &Option{})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif rows[0][0] != \"/usr/bin/php run.php --opt='1'\" {\n\t\tt.Fatalf(\"result should be '/usr/bin/php run.php --opt='1': got %v\", rows[0][0])\n\t}\n}\n\nfunc TestInputCSV(t *testing.T) {\n\tinput := `\nPID,command\n1,/usr/bin/ls\n2,/usr/bin/grep\n`\n\topt := &Option{\n\t\tInputCSV: true,\n\t}\n\trows, err := test(strings.NewReader(input), \"stdin\", \"select pid from stdin\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif len(rows) != 2 {\n\t\tt.Fatalf(\"rows should have two row: got %v\", rows)\n\t}\n\n\tif len(rows[0]) != 1 {\n\t\tt.Fatalf(\"columns should have only one: got %v\", rows[0])\n\t}\n\n\tif rows[0][0] != \"1\" {\n\t\tt.Fatalf(\"first result should be 1: got %v\", rows[0][0])\n\t}\n\n\tif rows[1][0] != \"2\" {\n\t\tt.Fatalf(\"second result should be 2: got %v\", rows[0][0])\n\t}\n\n\trows, err = test(strings.NewReader(input), \"stdin\", \"select command from stdin where pid = 2\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif rows[0][0] != \"/usr/bin/grep\" {\n\t\tt.Fatalf(\"result should be '/usr/bin/grep': got %v\", rows[0][0])\n\t}\n}\n\nfunc TestInputTSV(t *testing.T) {\n\tinput := \"PID\\tcommand\\n1\\t/usr/bin/ls\\n2\\t/usr/bin/grep\\n\"\n\n\topt := &Option{\n\t\tInputTSV: true,\n\t}\n\trows, err := test(strings.NewReader(input), \"stdin\", \"select pid from stdin\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif len(rows) != 2 {\n\t\tt.Fatalf(\"rows should have two row: got %v\", rows)\n\t}\n\n\tif len(rows[0]) != 1 {\n\t\tt.Fatalf(\"columns should have only one: got %v\", rows[0])\n\t}\n\n\tif rows[0][0] != \"1\" {\n\t\tt.Fatalf(\"first result should be 1: got %v\", rows[0][0])\n\t}\n\n\tif rows[1][0] != \"2\" {\n\t\tt.Fatalf(\"second result should be 2: got %v\", rows[0][0])\n\t}\n\n\trows, err = test(strings.NewReader(input), \"stdin\", \"select command from stdin where pid = 2\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif rows[0][0] != \"/usr/bin/grep\" {\n\t\tt.Fatalf(\"result should be '/usr/bin/grep': got %v\", rows[0][0])\n\t}\n}\n\nfunc TestInputPat(t *testing.T) {\n\tinput := \"PID#command\\n1#/usr/bin/ls\\n2#/usr/bin/grep\\n\"\n\n\topt := &Option{\n\t\tInputPat: `#`,\n\t}\n\trows, err := test(strings.NewReader(input), \"stdin\", \"select pid from stdin\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif len(rows) != 2 {\n\t\tt.Fatalf(\"rows should have two row: got %v\", rows)\n\t}\n\n\tif len(rows[0]) != 1 {\n\t\tt.Fatalf(\"columns should have only one: got %v\", rows[0])\n\t}\n\n\tif rows[0][0] != \"1\" {\n\t\tt.Fatalf(\"first result should be 1: got %v\", rows[0][0])\n\t}\n\n\tif rows[1][0] != \"2\" {\n\t\tt.Fatalf(\"second result should be 2: got %v\", rows[0][0])\n\t}\n\n\trows, err = test(strings.NewReader(input), \"stdin\", \"select command from stdin where pid = 2\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif rows[0][0] != \"/usr/bin/grep\" {\n\t\tt.Fatalf(\"result should be '/usr/bin/grep': got %v\", rows[0][0])\n\t}\n}\n\nfunc TestNoHeader(t *testing.T) {\n\n\tinput := `\n1    /usr/bin/ls\n2    /usr/bin/grep\n`\n\topt := &Option{\n\t\tNoHeader: true,\n\t}\n\trows, err := test(strings.NewReader(input), \"stdin\", \"select f1 from stdin\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif len(rows) != 2 {\n\t\tt.Fatalf(\"rows should have two row: got %v\", rows)\n\t}\n\n\tif len(rows[0]) != 1 {\n\t\tt.Fatalf(\"columns should have only one: got %v\", rows[0])\n\t}\n\n\tif rows[0][0] != \"1\" {\n\t\tt.Fatalf(\"first result should be 1: got %v\", rows[0][0])\n\t}\n\n\tif rows[1][0] != \"2\" {\n\t\tt.Fatalf(\"second result should be 2: got %v\", rows[0][0])\n\t}\n\n\trows, err = test(strings.NewReader(input), \"stdin\", \"select f2 from stdin where f1 = 2\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif rows[0][0] != \"/usr/bin/grep\" {\n\t\tt.Fatalf(\"result should be '/usr/bin/grep': got %v\", rows[0][0])\n\t}\n}\n\nfunc TestOutHeader(t *testing.T) {\n\n\tinput := `\nPID    command\n1    /usr/bin/ls\n2    /usr/bin/grep\n`\n\topt := &Option{\n\t\tOutHeader: true,\n\t}\n\trows, err := test(strings.NewReader(input), \"stdin\", \"select pid from stdin\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif len(rows) != 3 {\n\t\tt.Fatalf(\"rows should have three row: got %v\", rows)\n\t}\n\n\tif len(rows[0]) != 1 {\n\t\tt.Fatalf(\"columns should have only one: got %v\", rows[0])\n\t}\n\n\tif rows[0][0] != \"PID\" {\n\t\tt.Fatalf(\"first result should be 'PID': got %v\", rows[0][0])\n\t}\n\n\tif rows[1][0] != \"1\" {\n\t\tt.Fatalf(\"first result should be 1: got %v\", rows[1][0])\n\t}\n\n\tif rows[2][0] != \"2\" {\n\t\tt.Fatalf(\"second result should be 2: got %v\", rows[2][0])\n\t}\n\n\trows, err = test(strings.NewReader(input), \"stdin\", \"select command from stdin where pid = 2\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif rows[0][0] != \"command\" {\n\t\tt.Fatalf(\"result should be 'command': got %v\", rows[0][0])\n\t}\n\n\tif rows[1][0] != \"/usr/bin/grep\" {\n\t\tt.Fatalf(\"result should be '/usr/bin/grep': got %v\", rows[1][0])\n\t}\n}\n\nfunc TestInputLTSV(t *testing.T) {\n\tinput := `PID:1\tcommand:/usr/bin/ls\nPID:2\tcommand:/usr/bin/grep\n`\n\topt := &Option{\n\t\tInputLTSV: true,\n\t}\n\trows, err := test(strings.NewReader(input), \"stdin\", \"select pid from stdin\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif len(rows) != 2 {\n\t\tt.Fatalf(\"rows should have two row: got %v\", rows)\n\t}\n\n\tif len(rows[0]) != 1 {\n\t\tt.Fatalf(\"columns should have only one: got %v\", rows[0])\n\t}\n\n\tif rows[0][0] != \"1\" {\n\t\tt.Fatalf(\"first result should be 1: got %v\", rows[0][0])\n\t}\n\n\tif rows[1][0] != \"2\" {\n\t\tt.Fatalf(\"second result should be 2: got %v\", rows[0][0])\n\t}\n\n\trows, err = test(strings.NewReader(input), \"stdin\", \"select command from stdin where pid = 2\", opt)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif rows[0][0] != \"/usr/bin/grep\" {\n\t\tt.Fatalf(\"result should be '/usr/bin/grep': got %v\", rows[0][0])\n\t}\n}\n\nfunc TestColumsAndRows(t *testing.T) {\n\tinput := `\nint_key text_key      real_key\n1       1             15\n2       /usr/bin/grep 1.04\n2       10            300065\n`\n\tqq, _ := NewQQ(&Option{})\n\tcn, _, _ := qq.columnsAndRows(strings.NewReader(input))\n\tout := make([]column, len(cn))\n\tfor i, c := range cn {\n\t\tout[i] = *c\n\t}\n\texpect := []column{\n\t\t{\n\t\t\tName: \"int_key\",\n\t\t\tType: sqliteINTEGER,\n\t\t},\n\t\t{\n\t\t\tName: \"text_key\",\n\t\t\tType: sqliteTEXT,\n\t\t},\n\t\t{\n\t\t\tName: \"real_key\",\n\t\t\tType: sqliteREAL,\n\t\t},\n\t}\n\tif !reflect.DeepEqual(out, expect) {\n\t\tt.Errorf(\"\\n out =%+v\\n want=%+v\", out, expect)\n\t}\n}\n"
  },
  {
    "path": "wercker.yml",
    "content": "box: tcnksm/gox\nbuild:\n  steps:\n    - setup-go-workspace\n    - script:\n        name: show environments\n        code: |\n          git version\n          go version\n    - script:\n        name: go get\n        code: |\n          go get -t ./...\n    - script:\n        name: go test\n        code: |\n          go test -v ./...\ndeploy:\n  steps:\n    - setup-go-workspace\n    - script:\n        name: go get\n        code: |\n          go get ./...\n    - wercker/gox:\n        os: darwin linux windows\n        arch: 386 amd64\n        output: '{{.Dir}}_{{.OS}}_{{.Arch}}/{{.Dir}}'\n        dest: $WERCKER_OUTPUT_DIR/pkg\n    - tcnksm/zip:\n        input: $WERCKER_OUTPUT_DIR/pkg\n        output: $WERCKER_OUTPUT_DIR/dist\n    - script:\n        name: set release tag\n        code: |\n          if [ -n \"$GOBUMP_NEW_VERSION\" ]; then\n            export RELEASE_TAG=\"v$GOBUMP_NEW_VERSION\"\n          fi\n    - tcnksm/ghr:\n        token: $GITHUB_TOKEN\n        input: $WERCKER_OUTPUT_DIR/dist\n        replace: true\n        version: $RELEASE_TAG\n        opt: --draft\n"
  }
]