Help us understand the problem. What is going on with this article?

よく使うコードをgithubからダウンロードするコマンドラインツール

More than 3 years have passed since last update.

自己紹介

じゅんじゅんと言うニックネームで、関西を拠点に活動しているフロントエンドエンジニアです。

HAL大阪3回生です。(2017/05/17現在)

イベントや、勉強会に参加してるので是非お会いした際はお声掛けください!

よく使うコード、毎回書くのめんどくさい...

よく使うコードとは、例えばReactを開発する際のwebpack.config.jsとかgulpfile.jsとか、環境系のコードが多いかもしれません。

このファイルは、だいたい雛形が決まっているし毎回0から書くのもアホらしいし、いちいち書き方覚えていないので、毎回自分の過去のコードをみてコピペして、今のプロジェクトのパスなどを最適化したりしていました。

しかし、なんせブラウザ立ち上げて、自分のgithub開いて。。。。など手順がめんどくさくなってきました。

コマンドラインで完結してほしい...

ということで、作りました。まだv1.0.0で機能がとても少ないですが今後機能の追加をしていこうと思います。

code get(cget)

wgetというコマンドありますよね。似たような感じで使いたかったのでcode get(cget)コマンドとしてつくりました。いい名前あったらコメントで教えてください(もしくは、githubにissueください)

今回のフォルダ構成を作っていきます

- main.go
- menu.json
- README.md
- Manager/
   |- menuManager.go
- Utils/
   |- exportUtils.go
   |- fetchUtils.go
   |- menuUtils.go

こんな感じになります。

では、順番に作っていきます。

まずやらないとイケないものとしては

  • githubからコードを取得する
  • コマンドラインのオプションを元に分岐するマネージャー
  • ファイルに書き出す

ぐらいだと、思います。

流れとしては、

$ cget list で、取得可能なファイルを一覧する

$ cget fetch <file name> で、カレントディレクトリにそのファイルを保存する

では、まずコマンドラインのオプションを元に分岐するマネージャーを作っていきます

マネージャー作り

Manager/menuManager.goを作っていきます。

menuManager.go
package Managet

import(
  "flag"
  "fmt"
  "github.com/konojunya/cget/Utils"
)

func Init(){

  flag.Parse()
  items := flag.Args()

  switch items[0] {
  case "list":
    showAllFile()
  case "fetch":
    getCodeUrl(items[1)
  case "help":
    help()
  default:
    notfound()
  }
}

func showAllFile(){
  for _, key := range Utils.GetMenuKeys(){
    fmt.Printf("%s\n",key)
  }
}

func getCodeUrl(key string){
  url := Utils.GetCodeUrl(key)
  code := Utils.FetchCode(url)

  fmt.Printf("Downloading %s from %s...\n",key,url)

  Utils.Export(key,code)
}

func help(){
  fmt.Println("command list.")
  fmt.Println("$ cget list\t\tYou can get code list.")
  fmt.Println("$ cget fetch [key]\tYou can save file from key.")
}

func notfound(){
  fmt.Println("this args is not found.")

  fmt.Println("$ cget list\t\tYou can get code list.")
  fmt.Println("$ cget fetch [key]\tYou can save file from key.")
  fmt.Println("$ cget help\t\thelp.")
}

まず、Init()を実行します。コマンドライン引数を取得してlistfetchhelpかを見ています。

listの場合は、取得可能なコードのファイル名を一覧します。

fetchは、そのファイル名を元にコードをダウンロードします。

次に、githubからコードを取得するコードをかいていきたいと思います。

githubから取得するぞ

fetchUtils.go
package Utils

import (
  "io/ioutil"
  "log"
  "net/http"
)

func FetchCode(url string) []byte {
  res, err := http.Get(url)
  if err != nil { log.Fatal(err) }

  code, err := ioutil.ReadAll(res.Body)
  defer res.Body.Close()

  if err != nil { log.Fatal(err) }

  return code
}

FetchCodeメソッドを実装します。

引数にURLをとって、net/httpモジュールをつかって取得してきます。

ここで注意するべきは、res.Body.Close()deferを使ってCloseが呼ばれるまで待つ処理を書いておくことです。

これで、codebyte配列で取得できたので、それをファイルへ書き出したいと思います。

exportするぞい

exportUtils.go
package Utils

import (
  "log"
  "os"
)

func Export(filename string, code []byte){
  crr, _ := os.Getwd()
  file, err := os.Create(crr + "/" + filename)
  if err != nil { log.Fatal(err) }
  defer file.Close()

  file.Write(code)
}

os.Getwdで、カレントディレクトリの絶対パスを取得します。

os.Createでファイル名を入れて、ファイルをつくって、file.Writeで書き込みをします。

取得可能なファイルをjsonで管理するヨ

Utils/menuUtils.goを編集していきます。

menuUtils.go
package Utils

import (
  "encoding/json"
  "log"
  "net/http"
  "io/ioutil"
)

type Menu struct {
  Key string
  Url string
}

func initMenu() []Menu {

  res, err := http.Get("https://raw.githubusercontent.com/konojunya/cget/master/menu.json")
  if err != nil { log.Fatal(err) }

  bytes, err := ioutil.ReadAll(res.Body)
  defer res.Body.Close()
  if err != nil { log.Fatal(err) }

  var menus []Menu
  if err := json.Unmarshal(bytes,&menus); err != nil {
    log.Fatal(err)  
  }

  return menus

}

func GetMenuKeys() []string {
  menus := initMenu()

  var menuKeys []string

  for _, item := range menus {
    menuKeys = append(menuKeys,item.Key)
  }

  return menuKeys
}

func GetCodeUrl(key string) string {
  menus := initMenu()

  var url string
  for _, item := range menus {
    if item.Key == key {
      url = item.Url
    }
  }

  return url
}

まずjsonの形式の通りに構造体を作ります。

構造体のMenuは、KeyUrlを持つものと定義しておきます。

プライベートメソッドのinitMenuは、cgetのリポジトリにあるjsonファイルを確認して、メニューを構築するものです。

取得したあと、json.Unmarshal()をつかって、Menuにポインター経由で値を渡していきます。

パブリックメソッドのGetMenuKeysは、取得可能なファイルのファイル名の配列を返して、GetCodeUrlは、選択されたkeyを元にjsonから検索をして返します。

このQiitaを書いている時に、もしcget fetchで全然jsonにないファイル名を書かれた時にエラーがでることに気づきました

完成

これで全ての実装を終えたので、main.goを編集していきます。

main.go
package main

import "github.com/konojunya/cget/Manager"

func main(){
  Manager.Init()
}

これで、完成です。

あとがき

このコマンドは、Goの勉強をするのに丁度いいと思いつくってみました。

今後、ファイル名をcget fetch <filename> <filename>としたときにgoroutineをつかってみるとか、アップデートをかけていきたいと思います。

Goを書き始めて1ヶ月で、Goらしくないコードがあったり、下手くそな実装があると思うので、ぜひプルリク投げてください。。

cget/GitHub

なにかありましたら、Twitterへお願いします

@konojunya/Twitter

iotlt
IoT縛りの勉強会です。 毎月イベントを実施しているので是非遊びに来てください! 登壇者を中心にQiitaでも情報発信していきます。 https://iotlt.connpass.com
https://iotlt.connpass.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした