tweeeetyのぶろぐ的めも

アウトプットが少なかったダメな自分をアウトプット<br>\(^o^)/

【git】.gitignoreの書き方 - テンプレートを使うその1 - gitignore.io

はじめに

git管理化から特定のファイルなどを無視したければ.gitignoreに追加します。
しかもだいたいが適宜気づいたら、つどつど。

ただ、言語、フレームワーク、ツールなどのファイルは
新しいプロジェクトのたび x 適宜気づくたびに追加するのは面倒です。

そこで、
今回はお決まりのgitignoreテンプレを提供してくれるgitignore.ioのメモ f:id:tweeeety:20170622002147p:plain

アジェンダ

  1. gitignore.ioとは
  2. gitignore.ioをcurlで使ってみる
  3. gitignore.ioをbashのコマンドにする
  4. gitignore.ioをgit aliasにしてgit ignore xxxで使えるようにする

1. gitignore.ioとは

公式サイトはこちらです。 https://www.gitignore.io/

Create useful .gitignore files for your project

公式ページからの引用ですが、有用な.gitignoreを作ってくれる君ですね。

また、テンプレ集という意味だと
https://github.com/github/gitignore もあるので見てみると良いかもしれないです。

2. gitignore.ioをcurlで使ってみる

使い方は簡単。
https://www.gitignore.io/api/${言語やツール} と指定するだけです。

ためしにvim用のgitignore

$ curl -L -s https://www.gitignore.io/api/vim

# Created by https://www.gitignore.io/api/vim

### Vim ###
# swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-v][a-z]
[._]sw[a-p]
# session
Session.vim
# temporary
.netrwhist
*~
# auto-generated tag files
tags

# End of https://www.gitignore.io/api/vim

標準出力に出力されるので、そのまま.gitignoreを作るなり追記するなりでも良さそうです。

# 追記
curl -L -s https://www.gitignore.io/api/vim >> .gitignore

また、同時に複数指定することもできます。

$ curl -L -s https://www.gitignore.io/api/vim,java

# Created by https://www.gitignore.io/api/vim,java

### Java ###
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

### Vim ###
# swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-v][a-z]
[._]sw[a-p]
# session
Session.vim
# temporary
.netrwhist
*~
# auto-generated tag files
tags

# End of https://www.gitignore.io/api/vim,java

3. gitignore.ioをbashのコマンドにする

公式のまんまですが下のようにbashのfunctionにしてしまいます。

echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.bash_profile && source ~/.bash_profile

使ってみる

# bashの設定に追加
$ echo "function gi() { curl -L -s https://www.gitignore.io/api/\$@ ;}" >> ~/.bash_profile && source ~/.bash_profile

# 打ってみる
$ gi vim

# Created by https://www.gitignore.io/api/vim

### Vim ###
# swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-v][a-z]
[._]sw[a-p]
# session
Session.vim
# temporary
.netrwhist
*~
# auto-generated tag files
tags

# End of https://www.gitignore.io/api/vim

4. gitignore.ioをgit aliasにしてgit ignore xxxで使えるようにする

bash的なコマンドも良いですが、どうせならgitコマンドぽく使いたいですよね。

こちらも公式のまんまですが、
以下のようにするとgitのsubコマンドのように使えます。

git config --global alias.ignore '!gi() { curl -L -s https://www.gitignore.io/api/$@ ;}; gi'

使ってみる

# aliasにする前
# 当然怒られる
$ git ignore vim
git: 'ignore' is not a git command. See 'git --help'.

# aliasにする
$ git config --global alias.ignore '!gi() { curl -L -s https://www.gitignore.io/api/$@ ;}; gi'

# どや!
$ git ignore vim

# Created by https://www.gitignore.io/api/vim

### Vim ###
# swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-v][a-z]
[._]sw[a-p]
# session
Session.vim
# temporary
.netrwhist
*~
# auto-generated tag files
tags

# End of https://www.gitignore.io/api/vim

おわり

こういうテンプレは自分でメンテしてくのも大変だし
お任せできるって素敵ですね\(^o^)/

【go】funcの引数にstructの値渡し、ポインタ渡ししたときの挙動メモ

はじめに

goをなんとなく書き始めて半年経っていないくらいですが、
Goでxxxのポインタを取っているプログラムはだいたい全部間違っている という記事を見てなるほどなーと思いました。

最初のころとか確かに何となく無駄にポインタで渡していた気がする…

と、思ったところで、structについても自分で再確認するかーと思ったので
funcの引数にstructの値渡しとポインタ渡しで挙動を確かめてみるだけのgo初心者メモ

ソース

structを値として渡す場合とポインタとして渡す場合のいくつかだけの単純サンプル

package main

import "log"

type Data struct {
  Name string
  Age  int64
}

// #1.
//   arg :値渡し
//   処理:値のままプロパティアクセスして代入
func changeNameArgNormalAccessNormal(d Data) {
  d.Name = "fuga"
}

// #2.
//   arg :値渡し
//   処理:ポインタにしてからプロパティアクセスして代入
func changeNameArgNormalAccessPointer(d Data) {
  dPointer := &d
  dPointer.Name = "fuga"
}

// #3.
//   arg :ポインタ渡し
//   処理:値にしてからプロパティアクセスして代入
func changeNameArgPointerAccessNormal(dPointer *Data) {
  d := *dPointer
  d.Name = "fuga"
}

// #4.
//   arg :ポインタ渡し
//   処理:ポインタのままプロパティアクセスして代入
func changeNameArgPointerAccessPointer(dPointer *Data) {
  dPointer.Name = "fuga"
}

func main() {
  // #1
  d1 := Data{Name: "hoge", Age: 20}
  changeNameArgNormalAccessNormal(d1)
  log.Printf("d1: %+v", d1)

  // #2
  d2 := Data{Name: "hoge", Age: 20}
  changeNameArgNormalAccessPointer(d2)
  log.Printf("d2: %+v", d2)

  // #3
  d3 := Data{Name: "hoge", Age: 20}
  changeNameArgPointerAccessNormal(&d3)
  log.Printf("d3: %+v", d3)

  // #4
  d4 := Data{Name: "hoge", Age: 20}
  changeNameArgPointerAccessPointer(&d4)
  log.Printf("d4: %+v", d4)
}

https://github.com/tweeeety/go-struct-ref-sample

結果

#4 だけが元のコードの結果も変わります。
まぁ、そうだよね、というくらいでした。

$ go run struct_ref.go 
2017/06/21 23:53:22 d1: {Name:hoge Age:20}
2017/06/21 23:53:22 d2: {Name:hoge Age:20}
2017/06/21 23:53:22 d3: {Name:hoge Age:20}
2017/06/21 23:53:22 d4: {Name:fuga Age:20}

おわり

最初のころmapあたりは無駄にポインタにしたことがある気もしなくもない\(^o^)/

【go】golangのCLIパッケージ(urfave/cli)を使ってみるメモ

はじめに

command line cliなscriptを作りたいとき、
たいていどの言語でも引数を扱うライブラリがありますよね。

golangではとても便利なurfave/cliというパッケージがあります。
(以前は github.com/codegangsta/cli というリポジトリでした)

この使い方を簡単にメモ

アジェンダ

  1. getting start的な
  2. Arguments とか
  3. Flags 使ってみる
  4. Subcommands でいろいろ

その前に

この記事に使用したソースです。
https://github.com/tweeeety/go-command-line-sample/tree/master/src/script

1. getting start的な

install

go getするだけです。
glide使ってればglide installするだけですね。

$ go get github.com/urfave/cli

使ってみる

前提

これ以降の記述は、すべて以下のようなdir構成になっているものとして進めます。
今回の記事ようにgo-command-line-sampleというプロジェクト ディレクトリを作ってます。

# 作成したgo-command-line-sample
$ pwd
パス/go-command-line-sample

$ tree -L 3 ../go-command-line-sample
../go-command-line-sample
└── src
    └── script # この配下にscriptごとにdirを切る
        ├── glide.lock
        ├── glide.yaml
        └── vendor
簡単に試す

まずはprintするだけ、help出すだけ。
公式と同じですね

src/script/cli_10/main.go
package main

import (
  "10t"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "boom"
  app.Usage = "make an explosive entrance"

  app.Action = func(c *cli.Context) error {
    fmt.Println("boom! I say!")
    return nil
  }

  app.Run(os.Args)
}
実行
# 叩いてみる
$ go run src/script/cli_10/main.go 
boom! I say!

# helpってみる
$ go run src/script/cli_10/main.go help
NAME:
   boom - make an explosive entrance

USAGE:
   main [global options] command [command options] [arguments...]

VERSION:
   0.0.0

COMMANDS:
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version
go install

おもむろにgo installしてみます。

# scriptがいる場所まで移動
$ cd src/script/cli_10

# install
$ go instal

# プロジェクト直下にもどる
$ cd パス/go-command-line-sample

# binにcli_10が出来てる
$ tree -L 3
.
├── bin
│   └── cli_10
├── pkg
│   └── darwin_amd64
│       └── script
└── src
    └── script
        ├── cli_10
        ├── glide.lock
        ├── glide.yaml
        └── vendor

# たたいてみる
$ ./bin/cli_10
boom! I say!

ここまで動かすのもめっちゃ簡単ですね!

2. Arguments とか

app := cli.NewApp() した後の基本的な使い方です。

src/script/cli_20/main.go
package main

import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_20"
  app.Usage = "cli_20 sample"
  app.Version = "1.2.1"

  // before
  app.Before = func(c *cli.Context) error {
    fmt.Println("-- Before --")
    return nil
  }

  // action
  app.Action = func(c *cli.Context) error {
    fmt.Println("-- Action --")

    fmt.Printf("c.NArg()        : %+v\n", c.NArg())
    fmt.Printf("c.Args()        : %+v\n", c.Args())
    fmt.Printf("c.Args().Get(0) : %+v\n", c.Args().Get(0))
    fmt.Printf("c.Args()[0]     : %+v\n", c.Args()[0])
    fmt.Printf("c.FlagNames     : %+v\n", c.FlagNames())

    // Help表示
    //cli.ShowAppHelp(c) 

    // version表示
    cli.ShowVersion(c) 

    return nil
  }

  // after
  app.After = func(c *cli.Context) error {
    fmt.Println("-- After --")
    return nil
  }

  // true: go run app.go helpと打ってもhelpが出なくなる
  app.HideHelp = true

  app.Run(os.Args)
}
実行
# そのまま実行
$ go run src/script/cli_20/main.go hoge fuga piyo
-- Before --
-- Action --
c.NArg()        : 3
c.Args()        : [hoge fuga piyo]
c.Args().Get(0) : hoge
c.Args()[0]     : hoge
c.FlagNames     : []
cli_20 version 1.2.1
-- After --

# help
$ go run main.go help
-- Before --
NAME:
   cli_20 - cli_20 sample

USAGE:
   main [global options] command [command options] [arguments...]

VERSION:
   1.2.1

COMMANDS:
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version
-- After --


# `app.HideHelp = true` なのでhelpは引数として見なされる
$ go run src/script/cli_20/main.go help
-- Before --
-- Action --
c.NArg()        : 1
c.Args()        : [help]
c.Args().Get(0) : help
c.Args()[0]     : help
c.String()      : 
cli_20 version 1.2.1
-- After --
context

c.XXXXで取れるcontextについてはこの辺を見るとかなりたくさんありますね。
https://godoc.org/github.com/urfave/cli#Context

3. Flags 使ってみる

flagsは-lang english-l english的なオプションを受け取るためのものです。
ショートオプションや省略時のdefault optionも指定できます。

command、option、flagとは?というところは以下が大変参考になります。
Go言語によるCLIツール開発とUNIX哲学について

使ってみる

src/script/cli_30/main.go
package main

import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_30"
  app.Usage = "cli_30 sample"
  app.Version = "1.2.1"

  os.Setenv("SAMPLE_ENV", "sample env dayo")

  // flags
  app.Flags = []cli.Flag{
    cli.StringFlag{
      Name:  "lang, l",
      Value: "english",
      Usage: "language for the greeting",
    },
    cli.StringFlag{
      Name:  "meridian, m",
      Value: "AM",
      Usage: "meridian for the greeting",
    },
    cli.StringFlag{
      Name:  "time, t",
      Value: "07:00",
      // ``で囲むとhelp時のPlaceholderとしても使える
      // https://github.com/urfave/cli#placeholder-values
      Usage: "`your time` for the greeting",
    },
    cli.StringFlag{
      Name:  "aaa, a",
      Value: "sample",
      // default値をValueからではなくEnvから取る
      EnvVar: "SAMPLE_ENV",
    },
  }

  // action
  app.Action = func(c *cli.Context) error {
    fmt.Println("-- Action --")

    fmt.Printf("c.GlobalFlagNames() : %+v\n", c.GlobalFlagNames())
    fmt.Printf("c.String(\"lang\")    : %+v\n", c.String("lang"))
    fmt.Printf("c.String(\"m\")       : %+v\n", c.String("m"))
    fmt.Printf("c.String(\"time\")    : %+v\n", c.String("time"))
    fmt.Printf("c.String(\"a\")       : %+v\n", c.String("a"))

    return nil
  }

  app.Run(os.Args)
}
実行
# 実行
# 引数のkey:valueはスペースでもイコールでもいける
$ go run src/script/cli_30/main.go -l hoge -m=PM
-- Action --
c.GlobalFlagNames() : [aaa lang meridian time]
c.String("lang")    : hoge
c.String("m")       : PM
c.String("time")    : 07:00
c.String("a")       : sample env dayo

# help
$ go run src/script/cli_30/main.go -h
NAME:
   cli_30 - cli_30 sample

USAGE:
   main [global options] command [command options] [arguments...]

VERSION:
   1.2.1

COMMANDS:
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --aaa value, -a value           (default: "sample") [$SAMPLE_ENV]
   --lang value, -l value          language for the greeting (default: "english")
   --meridian value, -m value      meridian for the greeting (default: "AM")
   --time your time, -t your time  your time for the greeting (default: "07:00")
   --help, -h                      show help
   --version, -v                   print the version

Flagの種類

Flagとして設定できる種類がいくつかあるのでその例です。
StringFlagBoolFlagが指定できます。

src/script/cli_31/main.go
package main

import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_31"
  app.Usage = "cli_31 sample"
  app.Version = "1.2.1"

  // flags
  app.Flags = []cli.Flag{
    // StringFlag
    cli.StringFlag{
      Name:  "name, n",
      Value: "tarou",
      Usage: "your name",
    },
    // BoolFlag
    cli.BoolFlag{
      Name:  "gay, g",
      Usage: "are you gay boy?",
    },
  }

  // action
  app.Action = func(c *cli.Context) error {
    fmt.Println("-- Action --")
    fmt.Printf("c.GlobalFlagNames() : %+v\n", c.GlobalFlagNames())
    fmt.Printf("c.String(\"name\")    : %+v\n", c.String("name"))
    fmt.Printf("c.String(\"g\")       : %+v\n", c.Bool("g"))

    return nil
  }

  app.Run(os.Args)
}

実行
# 指定無しで叩いてみる
$ go run src/script/cli_31/main.go 
-- Action --
c.GlobalFlagNames() : [name gay]
c.String("name")    : tarou
c.String("g")       : false

# 指定有りで叩いてみる
# BoolFlagは、オプションを指定することでtrueとなるFlag
$ go run src/script/cli_31/main.go --name hoge -g
-- Action --
c.GlobalFlagNames() : [name gay]
c.String("name")    : hoge
c.String("g")       : true

4. Subcommands でいろいろ

公式の通りですが、
git-like のようなコマンドが設定できます。

普通に使ってみる

まずは公式のお試し

src/script/cli_40/main.go
package main

import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_40"
  app.Usage = "cli_40 sample"

  // command action
  // これまでのActionとは違い、flagsごとの挙動(Action)が設定できる
  app.Commands = []cli.Command{
    // `go run cli_40/main.go add パラメータ`でactionするコマンド
    {
      Name:    "add",
      Aliases: []string{"a"},
      Usage:   "add a task to the list",
      Action: func(c *cli.Context) error {
        fmt.Println("added task: ", c.Args().First())
        return nil
      },
    },
    // `go run cli_40/main.go complete パラメータ`でactionするコマンド
    {
      Name:    "complete",
      Aliases: []string{"c"},
      Usage:   "complete a task on the list",
      Action: func(c *cli.Context) error {
        fmt.Println("completed task: ", c.Args().First())
        return nil
      },
    },
    {
      Name:    "template",
      Aliases: []string{"t"},
      Usage:   "options for task templates",
      Subcommands: []cli.Command{
        // `go run cli_40/main.go template add パラメータ`でactionするコマンド
        {
          Name:  "add",
          Usage: "add a new template",
          Action: func(c *cli.Context) error {
            fmt.Println("new task template: ", c.Args().First())
            return nil
          },
        },
        // `go run cli_40/main.go template remove パラメータ`でactionするコマンド
        {
          Name:  "remove",
          Usage: "remove an existing template",
          Action: func(c *cli.Context) error {
            fmt.Println("removed task template: ", c.Args().First())
            return nil
          },
        },
      },
    },
  }

  app.Run(os.Args)
}

実行

実行してみるとこんな感じ

# addコマンドとパラメータで実行
$ go run src/script/cli_40/main.go t add hoge
added task:  hoge

# t(template)コマンドとaddサブコマンドで実行
$ go run src/script/cli_40/main.go t t add hoge
new task template:  hoge

$ go run src/script/cli_40/main.go -h
NAME:
   cli_04 - cli_04 sample

USAGE:
   main [global options] command [command options] [arguments...]

VERSION:
   0.0.0

COMMANDS:
     add, a       add a task to the list
     complete, c  complete a task on the list
     template, t  options for task templates
     help, h      Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version

COMMANDStemplateのSubcommandsが表示されないじゃないかーと思いますが
templateまで打って-hすればちゃんと出ます。

かしこい!

$ go run cli_40/main.go t -h
NAME:
   cli_04 template - options for task templates

USAGE:
   cli_04 template command [command options] [arguments...]

COMMANDS:
     add     add a new template
     remove  remove an existing template

OPTIONS:
   --help, -h  show help

before/action/afterとの関係を見る

COMMANDS(のAction)とbefore/action/after らへんはどういう関係で動くか。

src/script/cli_41/main.go
import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_41"
  app.Usage = "cli_41 sample"

  // before
  app.Before = func(c *cli.Context) error {
    fmt.Println("-- Before --")
    return nil
  }

  // command action
  app.Commands = []cli.Command{
    // `go run cli_04/main.go sample パラメータ`でactionするコマンド
    {
      Name:    "sample",
      Aliases: []string{"s"},
      Usage:   "sample task",
      Action: func(c *cli.Context) error {
        fmt.Println("-- Sample Action --")
        fmt.Println("sample task: ", c.Args().First())
        return nil
      },
    },
  }

  // action
  app.Action = func(c *cli.Context) error {
    fmt.Println("-- Nomal Action --")
    return nil
  }

  // after
  app.After = func(c *cli.Context) error {
    fmt.Println("-- After --")
    return nil
  }
  app.Run(os.Args)
}
実行

COMMANDSが渡されたときはapp.Actionは実行されず、
COMMANDSが何も渡されないとapp.Actionが実行されます。

$ go run src/script/cli_41/main.go sample hoge
-- Before --
-- Sample Action --
sample task:  hoge
-- After --

$ go run src/script/cli_41/main.go
-- Before --
-- Nomal Action --
-- After --

c.Commandを見てみる

COMMANDS に指定したAction: func内で使えるc.Commandを見てみます。
こんなのが使えるよー程度ですね。

src/script/cli_42/main.go
package main

import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_42"
  app.Usage = "cli_42 sample"

  // command action
  app.Commands = []cli.Command{
    {
      Name:    "sample",
      Aliases: []string{"s"},
      Usage:   "sample task",
      Action: func(c *cli.Context) error {
        fmt.Println("-- Sample Action --")

        fmt.Printf("c.Command.FullName()        : %+v\n", c.Command.FullName())
        fmt.Printf("c.Command.HasName(\"sample\") : %+v\n", c.Command.HasName("sample"))
        fmt.Printf("c.Command.Names()           : %+v\n", c.Command.Names())
        fmt.Printf("c.Command.VisibleFlags()    : %+v\n", c.Command.VisibleFlags())

        return nil
      },
    },
  }

  app.Run(os.Args)
}
実行
$ go run src/script/cli_42/main.go sample hoge
-- Sample Action --
c.Command.FullName()        : sample
c.Command.HasName("sample") : true
c.Command.Names()           : [sample s]
c.Command.VisibleFlags()    : [--help, -h show help]

Subcommands x Flags

次はSubcommands x Flagsの例です。
Flags単独の例は前述してますが、各Subcommandsごとにも設定できます。

src/script/cli_43/main.go
import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_43"
  app.Usage = "cli_43 sample"

  // command action
  app.Commands = []cli.Command{
    // addコマンドに対してFlagsを設定
    {
      Name:    "add",
      Aliases: []string{"a"},
      Usage:   "add a task to the list",
      Action: func(c *cli.Context) error {
        fmt.Println("added task: ", c.Args().First())
        fmt.Println("json      : ", c.String("j"))
        fmt.Println("exec      : ", c.String("e"))
        return nil
      },
      Flags: []cli.Flag{
        cli.StringFlag{
          Name:  "json, j",
          Value: "add.json",
        },
        cli.BoolFlag{
          Name: "exec, e",
        },
      },
    },
    // completeコマンドに対してFlagsを設定
    {
      Name:    "complete",
      Aliases: []string{"c"},
      Usage:   "complete a task on the list",
      Action: func(c *cli.Context) error {
        fmt.Println("completed task: ", c.Args().First())
        fmt.Println("csv           : ", c.String("c"))
        fmt.Println("exec          : ", c.String("e"))
        return nil
      },
      Flags: []cli.Flag{
        cli.StringFlag{
          Name:  "csv, c",
          Value: "add.json",
        },
        cli.BoolFlag{
          Name: "exec, e",
        },
      },
    },
  }
  app.Run(os.Args)
}
実行
# addコマンドを実行。addコマンドに指定したFlagsを指定
$ go run src/script/cli_43/main.go add -j test.json -e
added task:  
json      :  test.json
exec      :  true

# addコマンドを実行。completeコマンドに指定したFlagsを指定
# オプションが違うよ、という事でhelpが出る
$ go run src/script/cli_43/main.go add -c test.csv -e
Incorrect Usage: flag provided but not defined: -c

NAME:
   main add - add a task to the list

USAGE:
   main add [command options] [arguments...]

OPTIONS:
   --json value, -j value  (default: "add.json")
   --exec, -e              

# completeコマンドを実行。addコマンドに指定したFlagsを指定
$ go run src/script/cli_43/main.go complete -c test.csv
completed task:  
csv           :  test.csv
exec          :  false

おわり

urfave/cli いろいろてんこもりで便利ですね。
ここまでがっつり機能いらないよって場合は、標準のflag パッケージの方を使ってサクっと作るのも良さそうです
\(^o^)/

【go】direnvで環境(プロジェクトやディレクトリ)ごとに環境変数を分けるメモ - 例:GOPATH

はじめ

golangに限らないですが、
環境ごとに環境変数を切り替えたいときはまぁまぁありますよね。
そんなときのdirenvメモです。

mac x golangな環境を前提に書きますが
direnv自体はlinuxでも他の言語や環境でも同じです。

アジェンダ

  1. direnvとは
  2. direnvのinstall&設定
  3. direnv使ってみる
  4. direnv: error .envrc is blocked. Run direnv allow to approve its content.なとき

1. direnvとは

まずはdirenvのリポジトリ
https://github.com/direnv/direnv

簡単にいうとプロジェクトやディレクトリごとに環境変数を勝手に切り替えてくれる君です。
公式から引用するとこんな感じ。

direnv is an environment switcher for the shell. It knows how to hook into bash, zsh, tcsh and fish shell to load or unload environment variables depending on the current directory. This allows project-specific environment variables without cluttering the “~/.profile” file.

使うとこんな事が可能になります。

* ディレクトリごとにGPATHを設定できる
* ディレクトリへ移動すると自動的に設定される(出ると勝手に解除)

2. direnvのinstall&設定

使う前のinstall&設定。簡単です

# install
$ brew update
$ brew install direnv

# shellに設定
$ echo 'eval "$(direnv hook bash)"' >> ~/.bashrc

3. direnv使ってみる

設定してみる

ここでは環境(ディレクトリ)ごとにGOPATHを切り替える という例で書きますが、他の環境変数でも同じです。

# 移動
$ cd path/to/設定したいディレクトリ

# .envrcを作成
$ direnv edit .
---- vi追記 ----
export GOPATH=$(pwd) 
--------------- 

使い方

# direnvを設定したdir以外にいる前提
$ pwd
path/to/direnv設定してないdir

# 移動
$ cd path/to/設定したdir
direnv: loading .envrc
direnv: export ~GOPATH

# 出てみる
$ cd ..
direnv: unloading

補足

direnv edit .でエラー

direnv edit .するとdirenv: $EDITOR not found なエラーができるときは$EDITORを設定してやります

# 怒られる
$ direnv edit .
direnv: $EDITOR not found.

# bashrcに設定&読み込み
$ echo 'export EDITOR=vim' >> ~/.bashrc
$ source ~/.bashrc

# vimが開けばok
$ direnv edit .

4. direnv: error .envrc is blocked. Run direnv allow to approve its content.なとき

.envrcを直接編集すると以下のようなエラーが出るときがあります。
編集後は安全のためにdirenv allowで明示的に読み込むまでは無効になっているよ、という事らしいです。

# 何かしたらこれがでる
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.

# 素直に打つ
$ direnv allow

参考

終わり

いまさら direnv の解説という記事を参考にさせてもらって
さらに今さら感がありますが自分用メモ>\(^o^)/

【Homebrew】brew updateとbrew upgradeどっちがどっちメモ

はじめに

いつも忘れるのでメモ

違い

参考サイトのまんまですが違いをメモ。

update

Homebrew自体を最新版にして,内部で管理しているformula(パッケージ)も最新版にする

upgrade

Homebrew内部で管理しているformulaのみを最新版にする

参考

もうちょっと詳しく書いてあるので気になる場合は参考サイトをどぞ http://glass5er.hatenablog.com/entry/20121208/1354983531

【go】golangでyamlを読み込んでstructに入れるメモ - gopkg.in/yaml.v2

はじめに

golangyamlを読み込むときのメモ

読み込みたいyaml

userのデータが入ってると仮定したyamlです

sample.yaml
users:
    -   
        name: ほげ ほげ男
        full_name:
            first_name: ほげ
            last_name: ほげ男
        sex: male
        birthday: 1990-12-12
        self_introduction:
            long: ほげほげ男です。よろしくおねがいします!
            short: しゃす!
        image_urls:
            - /my/photo/01.png
            - /my/photo/02.png
            - /my/photo/03.png
        shemale: false
    -   
        name: ふが ふが子
        full_name:
            first_name: ふが
            last_name: ふが子
        sex: female
        birthday: 1994-03-03
        self_introduction:
            long: ふが子です!(≧∀≦*)
        image_urls:
            - /my/photo/01.png
        shemale: true

使うパッケージ

gopkg.in/yaml.v2 というパッケージを使います。

go getで取得すればいけるはず

$ go get gopkg.in/yaml.v2

今回はglideで入れました

構成

sample.yaml が読み込みたいyamlです。
glideな関係でmainのコードはsrc/go-yaml-sample/yaml_sample.goとなってます。

$ pwd
プロジェクトdir

$ tree -L 3
.
├── sample.yaml
└── src
    └── yaml_sample
        ├── glide.lock
        ├── glide.yaml
        ├── vendor
        └── yaml_sample.go

コード

gopkg.in/yaml.v2 を使うと、json.Marshalな感じでyamlを読み込んでくれます。

src/go-yaml-sample/yaml_sample.go
package main

import (
  "fmt"
  "io/ioutil"

  yaml "gopkg.in/yaml.v2"
)

// structたち
type Data struct {
  Users []User `yaml:"users"`
}

type User struct {
  Name             string           `yaml:"common"`
  FullName         fullName         `yaml:"full_name"`
  Sex              string           `yaml:"sex"`
  SelfIntroduction selfIntroduction `yaml:"self_introduction"`
  ImageURLs        []string         `yaml:"image_urls"`
  Shemale          bool             `yaml:"shemale"`
}

type fullName struct {
  FirstName string `yaml:"first_name"`
  LastName  string `yaml:"last_name"`
}

type selfIntroduction struct {
  Long  string `yaml:"long"`
  Short string `yaml:"short"`
}

func main() {
  // yamlを読み込む
  buf, err := ioutil.ReadFile("../../sample.yaml")
  if err != nil {
    panic(err)
  }
  fmt.Printf("buf: %+v\n", string(buf))

  // structにUnmasrshal
  var d Data
  err = yaml.Unmarshal(buf, &d)
  if err != nil {
    panic(err)
  }
  fmt.Printf("d: %+v", d)

}
結果
$ cd src/yaml_sample/

$ go run yaml_sample.go 
buf: users:
    -
        name: ほげ ほげ男
        full_name:
            first_name: ほげ
            last_name: ほげ男
        sex: male
        birthday: 1990-12-12
        self_introduction:
            long: ほげほげ男です。よろしくおねがいします!
            short: しゃす!
        image_urls:
            - /my/photo/01.png
            - /my/photo/02.png
            - /my/photo/03.png
        shemale: false
    -
        name: ふが ふが子
        full_name:
            first_name: ふが
            last_name: ふが子
        sex: female
        birthday: 1994-03-03
        self_introduction:
            long: ふが子です!(≧∀≦*)
        image_urls:
            - /my/photo/01.png
        shemale: true


d: {Users:[{Name: FullName:{FirstName:ほげ LastName:ほげ男} Sex:male SelfIntroduction:{Long:ほげほげ男です。よろしくおねがいします! Short:しゃす!} ImageURLs:[/my/photo/01.png /my/photo/02.png /my/photo/03.png] Shemale:false} {Name: FullName:{FirstName:ふが LastName:ふが子} Sex:female SelfIntroduction:{Long:ふが子です!(≧∀≦*) Short:} ImageURLs:[/my/photo/01.png] Shemale:true}]}

リポジトリ

おわり

yamlもサクっと簡単!\(^o^)/

【git】git tagを取り消す

はじめに

git tagを取り消すメモ。 ほとんど手順メモ程度な感じ+他記事で使うスニペット記事。

補足

他の取り消しもぱっと見たい自分用にまとめたので参考までに。

【git】add、commit、push、merge、pull request、merge pull request、tagの取り消し

アジェンダ

  1. localでの取り消し(削除)
  2. リモートでの取り消し

1. localでの取り消し(削除)

ローカルで消す場合は git tag -d タグ とします。

$ git tag
v1.0.0
v1.0.1
v1.0.2
v1.0.4
v1.0.5

$ git tag v1.0.6

$ git tag
v1.0.0
v1.0.1
v1.0.2
v1.0.4
v1.0.5
v1.0.6

$ git tag -d v1.0.6
Deleted tag 'v1.0.6' (was 7bd2f6b)

$ git tag
v1.0.0
v1.0.1
v1.0.2
v1.0.4
v1.0.5safdsa

2. リモートでの取り消し

リモートのtagを消す場合は git push origin :refs/tags/タグ とします。
ローカルを先に消す必要も無いし、localのが一緒に消えるわけでもないです。

# リモートのタグを確認
$ git ls-remote --tags
From https://github.com/tweeeety/git-tag-sample.git
6d0a343aa89b63f6d01116116afcca30c7250ed1  refs/tags/v1.0.0
08c9f32c3f36a7577366440f24b095a697c8645d  refs/tags/v1.0.1
0715d6e897c84b003ee3f1d9833bfe23d0023355  refs/tags/v1.0.2
063adbe5ed48fc19dbea5d92491995e09ad762f2  refs/tags/v1.0.4
33ed691e1c4363b4b5cf7f102fab3ca27f5ba5ab  refs/tags/v1.0.5
7bd2f6b05c73cc1042d0b9b8b311e96d3375b13f  refs/tags/v1.0.6

# リモートのタグを削除
$ git push origin :refs/tags/v1.0.6
To https://github.com/tweeeety/git-tag-sample.git
 - [deleted]         v1.0.6

# 消えてるか確認
$ git ls-remote --tags
From https://github.com/tweeeety/git-tag-sample.git
6d0a343aa89b63f6d01116116afcca30c7250ed1  refs/tags/v1.0.0
08c9f32c3f36a7577366440f24b095a697c8645d  refs/tags/v1.0.1
0715d6e897c84b003ee3f1d9833bfe23d0023355  refs/tags/v1.0.2
063adbe5ed48fc19dbea5d92491995e09ad762f2  refs/tags/v1.0.4
33ed691e1c4363b4b5cf7f102fab3ca27f5ba5ab  refs/tags/v1.0.5

# ローカルには残ってるので別途消してね
$ git tag
v1.0.0
v1.0.1
v1.0.2
v1.0.4
v1.0.5
v1.0.6

終わり

git ls-remote --tags のほうを忘れそうw