Go Modules 갈아타기

go 1.11.1 이 나오기 전에는 dep 이라는 의존성 관리툴을 사용했고, 이번에 1.11.1 이 나오면서 modules 가 추가되어 적용해 보려한다.

go modules 는 go mod 라는 go 명령어로 사용가능 하며, 아래와 같은 옵션을 제공하고 있다.

  • go mod init 모듈이름
    : 패키지 초기화
  • go mod tidy
    : 패키지 정리, 패키지 삭제 및 추가 cf) go build -mod vendor
  • go mod vendor
    : vendor 디렉토리에 의존성 패키지 다운로드
  • go mod help
    : 위에 소개되지 않은 옵션들을 살펴볼 수 있다

의존성 관리툴 갈아타기

go module 를 적용하기 위해 지긋지긋한 $GOPATH/src 에서, 업무 성격 별로 나누어 둔 Workspace 로 위치를 변경 했고 다음과 같이 패키지 초기화를 진행했다.

패키지 초기화

적용하려는 패키지는 'straitgate' 라는 사내 프로젝트이다. 아래 초기화 명령을 던지면 go.mod 이라는 파일이 하나 생성되고 이 파일에 의존성 패키지가 서술 되게 된다. 처음에는 module straitgate 라는 패키지명 이외에는 아무것도 없다.
$ go mod init straitgate

go: creating new go.mod: module straitgate

위 모듈패스를  straitgate 라고 간단하게 주었지만 정확한 모듈패스를 주는 것이 좋다.

예를 들어, 초기화시에 아래와 같이 정확한 경로를 주어야, 다른 패키지에서 의존성을 주입할때 정상적으로 패키지가 인식된다. 제대로 인식이 되지 않는 경우에는 아예 로드가 되지 않거나, versioning 에 실패하게 되는 경우가 있다.

$ go mod init github.com/breezymind/gq

vendor 디렉토리 생성

go mod vendor 명령어로 의존성 패키지 vendor 디렉토리 만들수 있으며, 해당 디렉토리에는 go.mod 에 명시된 패키지들이 다운로드 되어 저장된다. vendor 폴더에는 modules.txt 라는 파일이 생성되고, 상세한 하위 패키지와 디렉토리가 기술되어 저장 된다.
$ go mod vendor -v

Fetching https://stathat.com/c/consistent?go-get=1
go: finding github.com/breezymind/go-misc latest
go: finding github.com/mediocregopher/radix.v3 latest
go: finding github.com/qiangxue/fasthttp-routing latest
go: finding github.com/valyala/tcplisten latest
go: finding github.com/breezymind/gq latest
go: finding github.com/zheng-ji/goSnowFlake latest
go: finding github.com/bwmarrin/snowflake latest
go: finding github.com/schigh/str latest
Parsing meta tags from https://stathat.com/c/consistent?go-get=1 (status code 200)
.......

go.mod 확인

go.mod 에서 의존성 패키지 목록을 확인했고, 필요한 패키지들이 잘 들어가 있는 듯 하다.  (불필요한 패키지가 들어가서 확인해 봤더니 test 디렉토리에서 몇가지 테스트 하느라 넣어둔 코드들에서 필요한 패키지들이었다)
$ cat go.mod

module straitgate

require (
	github.com/breezymind/go-misc v0.0.0-20180511072242-98feae43f930
	github.com/breezymind/gq v0.0.0-20180601085530-64d3d2ebe983
	github.com/bwmarrin/snowflake v0.0.0-20180412010544-68117e6bbede
	github.com/go-redis/redis v6.14.2+incompatible
	github.com/gogo/protobuf v1.1.1 // indirect
	github.com/mediocregopher/radix.v3 v0.0.0-20181106162134-5d49359cd9c3
	github.com/nats-io/go-nats v1.6.0 // indirect
	github.com/nats-io/go-nats-streaming v0.4.0
	github.com/nats-io/nuid v1.0.0 // indirect
	github.com/qiangxue/fasthttp-routing v0.0.0-20160225050629-6ccdc2a18d87
	github.com/schigh/str v0.0.0-20170715183927-361193c512d2
	github.com/sirupsen/logrus v1.2.0
	github.com/valyala/fasthttp v1.0.0
	github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a
	github.com/vmihailenco/msgpack v4.0.1+incompatible
	github.com/zheng-ji/goSnowFlake v0.0.0-20180906112711-fc763800eec9
	google.golang.org/appengine v1.3.0 // indirect
	stathat.com/c/consistent v1.0.0
)

초기화 이후 정상동작 확인

go run 으로 정상동작 확인 하였으나, 아래와 같이 패키지 오류가 발생했다. 이유는 gq 라는 개인적으로 개발한 패키지를 로컬에 개발하고 온라인에 push 하지 않아서 문제가 되었다. 한마디로 오류가나는 패키지가 온라인이 아닌 로컬에 있는 최신 버전의 프로젝트를 필요로 해서 발생한 문제다.
$ go run cmd/sg-cli-api/sg-cli-api.go

# straitgate/internal/redis/radix
internal/redis/radix/radix.go:70:38: undefined: gq.NewMapByMsgPackByte
internal/redis/radix/radix.go:77:20: undefined: misc.LoadFiles
# straitgate/api
api/api.go:28:12: undefined: misc.ToJSON

의존성 패키지가 로컬을 바라보게 하기

아래와 같이 go.mod 에서 문제가 된 패키지를 require 항목에서 찾아서 replace 항목에 넣고 replace 모듈패스 => 로컬 패키지경로 와 같은 문법으로 작성해준다. 더불어 로컬 패키지 경로에 있는 패키지에도 go.mod 가 존재해야 함. 없는 경우에는 간단하게 초기화 해주면 된다.
module straitgate

replace (
	github.com/breezymind/go-misc v0.0.0-20180511072242-98feae43f930 => /Users/breezymind/Workspace/Playground/github/go-misc

	github.com/breezymind/gq v0.0.0-20180601085530-64d3d2ebe983 => /Users/breezymind/Workspace/Playground/github/gq
)

require (
	github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
	github.com/boltdb/bolt v1.3.1 // indirect
	github.com/breezymind/go-misc v0.0.0-20180511072242-98feae43f930
	github.com/breezymind/gq v0.0.0-20180601085530-64d3d2ebe983
......
)

프로젝트 내부 vendor 패키지로만 구동/빌드 하기

위 처럼 의존성 패키지가 로컬을 바라보게 go.mod 를 수정하고 나서 go run example.go  하면 정상 구동하게 되나,   go run -mod vendor example.go 와 같이 vendor 패키지 기반으로만 구동시키게 되면 기존에 나던 오류사항이 그대로 노출 되는 것을 볼 수 있다.
이유는 vendor 이하 modules.txt 가 go.mod 의 변경된 내용을 적용하지 못한 까닭이고 go mod vendor 명령어로 반영하고 다시 구동시키면 된다.
빌드도 마찬가지고 명령어도 다음과 같이 유사하게 사용하면 된다. go build -mod vendor example.go
다음은 vendor/modules.txt 상단에 변경된 부분을 나타낸다.
$ cat vendor/modules.txt

# github.com/breezymind/go-misc v0.0.0-20180511072242-98feae43f930 => /Users/breezymind/Workspace/Playground/github/go-misc
github.com/breezymind/go-misc
# github.com/breezymind/gq v0.0.0-20180601085530-64d3d2ebe983 => /Users/breezymind/Workspace/Playground/github/gq
github.com/breezymind/gq
# github.com/bwmarrin/snowflake v0.0.0-20180412010544-68117e6bbede
github.com/bwmarrin/snowflake
# github.com/go-redis/redis v6.14.2+incompatible
github.com/go-redis/redis
github.com/go-redis/redis/internal
github.com/go-redis/redis/internal/consistenthash
github.com/go-redis/redis/internal/hashtag
github.com/go-redis/redis/internal/pool
github.com/go-redis/redis/internal/proto
github.com/go-redis/redis/internal/singleflight
github.com/go-redis/redis/internal/util
.....