Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Go에서 dep으로 의존성 관리하기

Go로 간단한 프로젝트를 하려고 보니 처음 신경 쓰이는 건 의존성 관리를 어떻게 하는가였다. PackageManagementTools 문서에 패키지 관리 도구가 정리되어 있다.

dep, is an official experiment for the dependency tool. It is currently being implemented, in pre-alpha state and should be used with caution as "Lots of functionality is knowingly missing or broken".

여러 도구가 있지만 dep을 공식 의존성 관리 도구로 언급하고 있다. 아직 실험적으로 구현 중이지만 공식이라고 하니 그냥 dep을 쓰기로 했다. dep 저장소를 보면 프로덕션에서 사용해도 문제없다고 하니(dep is safe for production use.)아직 Go로 뭔가 큰 걸 만들 건 아니지만 써도 괜찮을 것 같다.

dep 설치

dpe은 go 1.8 이상의 버전이 필요하다고 한다. 현재 최신 버전이 1.10이니 나한테는 영향은 없을 것 같다. go get으로 설치해도 되지만(go get -u github.com/golang/dep/cmd/dep) 소스 파일까지는 필요 없을 것 같아서 저장소에 안내된 대로 Homebrew로 설치했다.

$ brew install dep

==> Installing dependencies for dep: go
==> Installing dep dependency: go
==> Downloading https://homebrew.bintray.com/bottles/go-1.10.high_sierra.bottle.tar.gz
######################################################################## 100.0%
==> Pouring go-1.10.high_sierra.bottle.tar.gz
==> Caveats
A valid GOPATH is required to use the `go get` command.
If $GOPATH is not specified, $HOME/go will be used by default:
  https://golang.org/doc/code.html#GOPATH

You may wish to add the GOROOT-based install location to your PATH:
  export PATH=$PATH:/usr/local/opt/go/libexec/bin
==> Summary
  /usr/local/Cellar/go/1.10: 8,150 files, 336.9MB
==> Installing dep
==> Downloading https://homebrew.bintray.com/bottles/dep-0.4.1_1.high_sierra.bottle.tar.gz
######################################################################## 100.0%
==> Pouring dep-0.4.1_1.high_sierra.bottle.tar.gz
  /usr/local/Cellar/dep/0.4.1_1: 7 files, 8.8MB

dep으로 버전을 출력해 볼 수 있으면 잘 설치된 것이다.

$ dep version
dep:
 version     : v0.4.1
 build date  : 2018-01-27
 git hash    : 37d9ea0
 go version  : go1.9.3
 go compiler : gc
 platform    : darwin/amd64

새 버전으로 업그레이드하려면 brew upgrade dep 명령어를 사용하면 된다.

dep으로 의존성 관리하기

go get이 이미 있고 goimports 등을 사용하려고 tools를 설치할 때는 go get으로 설치했다. go get으로 설치하면 $GOPATH/src 아래 소스코드가 들어가는데 이 아래 있으면 로컬에서 import로 불러서 사용할 수 있으므로 go get으로 의존성을 설치해서 사용할 수도 있다.(Go 개발자들이 정확히 어떻게 쓰는지는 아직 잘 모르지만...)

하지만 소스 코드에 import 구문이 있다고 하더라도 go get으로 설치해서 사용하면 본인은 괜찮지만 다른 사람은 의존성을 일일이 찾아서 설치해야 해서 협업하기만 어려우므로 프로젝트의 의존성은 dep같은 도구가 적합하다고 생각한다.

새 프로젝트에서 dep으로 의존성을 관리하는 방법은 dep 문서에 잘 나와 잇다. 처음에 dep으로 의존성을 관리하려면 초기화를 해야 한다.

$ dep init

초기화를 하면 아래처럼 2개의 파일과 1개의 디렉터리가 생성된다.

├── Gopkg.lock
├── Gopkg.toml
└── vendor/


Gopkg.toml

Gopkg.toml은 초기화할 때 생성되는 파일로 dep의 동작을 감시하는 여러 규칙을 담고 있다고 한다.

  • 의존성 규칙: constraints, overrides로 사용자가 적용할 의존성의 버전과 어디서 가져와야 하는지를 지정한다.
  • 패키지 그래프 규칙: required, ignored로 임포트 경로를 추가하거나 제외해서 임포트 그래프를 조작할 수 있다.
  • metadata: 사용자가 정의한 키-값의 맵으로 dep은 무시할 것이다.
  • prune: 어떤 파일과 디렉터리가 불필요하다고 판단할지 설정해서 vendor/에서 자동으로 제거한다.

아래는 dep init했을 때 생긴 Gopkg.toml의 내용이다.

# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
#   name = "github.com/user/project"
#   version = "1.0.0"
#
# [[constraint]]
#   name = "github.com/user/project2"
#   branch = "dev"
#   source = "github.com/myfork/project2"
#
# [[override]]
#   name = "github.com/x/y"
#   version = "2.4.0"
#
# [prune]
#   non-go = false
#   go-tests = true
#   unused-packages = true


[prune]
  go-tests = true
  unused-packages = true


Gopkg.lock

프로젝트의 의존성 그래프의 스냅숏을 가진 파일이다. 이 파일은 dep ensure 할 때 변경된다.

아래는 생성된 Gopkg.lock 파일의 내용이다.

# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.


[solve-meta]
  analyzer-name = "dep"
  analyzer-version = 1
  inputs-digest = "ab4fef131ee828e96ba67d31a7d690bd5f2f42040c6766b1b12fe856f87e0ff7"
  solver-name = "gps-cdcl"
  solver-version = 1

의존성 추가

웹 프레임워크로 gin을 사용하기 위해 dep ensure로 의존성을 추가해 보자. ensure가 프로젝트에 의존성을 설치하는 명령어고 새로운 의존성을 추가하려면 dep ensure -add를 사용해야 한다.

$ dep ensure -add github.com/gin-gonic/gin
no dirs contained any Go code

현재는 Go 코드를 전혀 작성하지 않아서 오류가 난다. 여기선 Go 코드는 중요하지 않으므로 다음 내용으로 main.go 파일을 만들자.

package main

다시 gin을 추가해 보자.

$ dep ensure -add github.com/gin-gonic/gin
Fetching sources...

"github.com/gin-gonic/gin" is not imported by your project, and has been temporarily added to Gopkg.lock and vendor/.
If you run "dep ensure" again before actually importing it, it will disappear from Gopkg.lock and vendor/.

아까와 달리 추가되었다. 안내 문구를 보면 아직 github.com/gin-gonic/gin를 아직 임포트 한 곳이 없어서 Gopkg.lockvender/에는 추가되었지만 임포트하지 않고 dep ensure를 실행하면 지워질 것이라고 한다.

Gopkg.toml 파일을 보면 하단에 gin이 추가된 것을 볼 수 있다.

[[constraint]]
  name = "github.com/gin-gonic/gin"
  version = "1.2.0"

Gopkg.lock 파일은 아래처럼 의존성의 자세한 정보가 추가되고 [solve-meta]inputs-digest 정보가 변경되게 된다.

[[projects]]
  name = "github.com/gin-gonic/gin"
  packages = [
    ".",
    "binding",
    "render"
  ]
  revision = "d459835d2b077e44f7c9b453505ee29881d5d12d"
  version = "v1.2"


dep 관련 파일 버전 관리

위에서 보았듯이 dep이 생성한 파일은 Gopkg.toml, Gopkg.lockvender 디렉터리다. 좀 찾아봤는데 Gopkg.toml, Gopkg.lock는 둘 다 커밋하는 것 같다. Gopkg.lock가 꼭 필요한지는 확인 안해 봤지만 npm을 생각해 보면 package-lock.json과 같은 역할을 하는 거로 보인다. 내 취향으로는 프로덕션에서 서비스하기 전까지는 lock 파일을 저장소에서 관리하는 편은 아니지만 요즘 추세는 lock 파일도 보통 넣는 것 같고 해서 dep에서도 두 파일을 모두 Git에 넣기로 했다.

vender 디렉터리의 경우 딱 봐도 Git에서 관리할 필요가 없어 보이는데 dep의 FAQ 문서를 보면 이 디렉터리를 커밋해서 관리할 때의 장단점이 나와 있다. 말이 장단점이지 그냥 의존성 파일을 다 저장소에 관리할지 말지의 얘기라서 관례대로 나는 vender 디렉터리는 git에서 제외했다.

의존성 설치

프로젝트를 협업하는 경우 Gopkg.toml, Gopkg.lock를 가진 저장소를 받아서 의존성을 설치해서 개발해야 한다.

$ dep ensure

이때는 dep ensure만 실행해야 한다. 참고로 여기서는 dep만 설명하고 있지만, 앞에서 살펴본 대로 go 소스코드에서 import "github.com/gin-gonic/gin" 처럼 임포트하고 있지 않다면 이 의존성이 지워지게 된다.

2018/02/21 22:33 2018/02/21 22:33