My External Storage

Jul 18, 2019 - 4 minute read - Comments - go

[Go moudles] module名がgithub.com/account/repo/vXとなっているリポジトリの古いバージョンを使う #golangjp

Go Modulesの使い方をざっくり調べたのでメモ。

TL;DR

  • go.mod内のmodule名にバージョン名が入っているリポジトリがあった
    • module github.com/golang-migrate/migrate/v4
  • 古いバージョンは使うときはmodファイル内でreplaceを使えばよい
    • replace github.com/golang-migrate/migrate/v3 latest => github.com/golang-migrate/migrate v3.5.4
  • ブランチ名がv1のようなバージョン名だとブランチではなく、自動的に関連するリリースタグ状態を確認しにいく模様

以下のコードは同じgithub.com/golang-migrate/migrateリポジトリの各バージョンを取り込むgo.modファイルだ。 バージョンの指定を"イイ感じ"に判断してもらうため、ひとまずコメントのようにlatestをした。 go mod tidyを実行後は依存性を正しく解決した状態になっている。

module github.com/budougumi0617/til/go/modules/branch

go 1.12

// go mod tidyコマンドを行う前の手動で書いたgo.modファイルの依存関係
//
// require (
// 	github.com/golang-migrate/migrate v1
// 	github.com/golang-migrate/migrate/v3 latest
//
// 	github.com/golang-migrate/migrate/v4 latest
// )
//
// replace github.com/golang-migrate/migrate/v3 latest => github.com/golang-migrate/migrate v3.5.4

require (
	github.com/golang-migrate/migrate v1.3.2
	github.com/golang-migrate/migrate/v3 v3.5.4

	github.com/golang-migrate/migrate/v4 v4.4.0
	gopkg.in/mattes/migrate.v1 v1.3.2 // indirect
)

replace github.com/golang-migrate/migrate/v3 v3.5.4 => github.com/golang-migrate/migrate v3.5.4+incompatible

なお、この記事の内容はgithub.com/golang-migrate/migrateの最新リリースがv4.4.0の時に検証された。 また、goのバージョンは1.12.6である。

go.mod内のmodule名にバージョン名が入っているリポジトリがあった

golang-migrate/migrateリポジトリのgo.modファイルを見ると、module名がgithub.com/golang-migrate/migrate/v4になっていた。 このような状態のリポジトリでv3.X.X系を使いたい場合はどうすればいいのだろうか?

// https://github.com/golang-migrate/migrate/blob/v4.4.0/go.mod
module github.com/golang-migrate/migrate/v4

require (
	cloud.google.com/go v0.37.4
	github.com/aws/aws-sdk-go v1.17.7
	github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 // indirect
	github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
	github.com/cockroachdb/apd v1.1.0 // indirect
    // ....

古いバージョンは使うときはmodファイル内でreplaceを使えばよい

replaceを使うことで、任意の古いリリース状態を使うことができた。 最初にリポジトリのタグやブランチは以下の状態になっている。

$ git branch -r
  origin/HEAD -> origin/master
  origin/cli-updates
  origin/master
  origin/v1
  origin/v1-gopkg

リリースタグは以下のような状態になっている(一部省略)。

$ git tag -l
v1.2.0
v1.3.0
v1.3.1
v1.3.2
v3.0.0
v3.0.0-prev0
v3.0.0-prev1
v3.0.0-prev2
...
v3.5.4
v4.0.0
v4.0.1
...
v4.4.0
v4.5.0

このような状態のリポジトリのとき、v3系を利用して開発する場合はreplaceを使えば良さそうだった。 以下のように手で編集したgo.modファイルを用意する。

module github.com/budougumi0617/til/go/modules/branch

go 1.12

require (
 	github.com/golang-migrate/migrate/v3 latest
)

replace github.com/golang-migrate/migrate/v3 latest => github.com/golang-migrate/migrate v3.5.4

該当リポジトリをimportするファイルを作成しておく。

package main

import (
	"fmt"

	database3 "github.com/golang-migrate/migrate/v3/database"
)

func main() {
	fmt.Println(database3.GenerateAdvisoryLockId("mod test"))
}

この状態でgo mod tidyを実行すれば、正しいrequirereplaceが指定された状態のgo.modファイルが作成された。

require (
	github.com/golang-migrate/migrate/v3 v3.5.4
)

replace github.com/golang-migrate/migrate/v3 v3.5.4 => github.com/golang-migrate/migrate v3.5.4+incompatible

また、v1ブランチを使いたいときはどうやって使うのだろう?と以下のように設定を追加してみた。

module github.com/budougumi0617/til/go/modules/branch

go 1.12

require (
	github.com/golang-migrate/migrate v1
	github.com/golang-migrate/migrate/v3 latest
)

replace github.com/golang-migrate/migrate/v3 latest => github.com/golang-migrate/migrate v3.5.4

結果はv1ブランチではなく、自動的にリリースタグのほうのv1系が参照された。

require (
	github.com/golang-migrate/migrate v1.3.2
	github.com/golang-migrate/migrate/v3 v3.5.4
)

replace github.com/golang-migrate/migrate/v3 v3.5.4 => github.com/golang-migrate/migrate v3.5.4+incompatible

v4系も含めて使おうとすると、go.modは次のようになる。

module github.com/budougumi0617/til/go/modules/branch

go 1.12

require (
	github.com/golang-migrate/migrate v1.3.2
	github.com/golang-migrate/migrate/v3 v3.5.4

	github.com/golang-migrate/migrate/v4 v4.4.0
	gopkg.in/mattes/migrate.v1 v1.3.2 // indirect
)

replace github.com/golang-migrate/migrate/v3 v3.5.4 => github.com/golang-migrate/migrate v3.5.4+incompatible

コードの中でどうやって呼ぶかというと、以下のようになる。

package main

import (
	"fmt"

	"github.com/golang-migrate/migrate/driver"
	database3 "github.com/golang-migrate/migrate/v3/database"
	database4 "github.com/golang-migrate/migrate/v4/database"
)

func main() {
	fmt.Println(database3.GenerateAdvisoryLockId("mod test"))
	fmt.Println(database4.GenerateAdvisoryLockId("mod test"))
	fmt.Println(driver.GetDriver("mod test"))
}

終わりに

(だいぶ前に調べていたのだが、)渋川さんのTweetをみて調べた内容をまとめた。 挙動を見た、というレベルなのでロジック的な部分の確認は出来ていない。

go.modファイルはいつも手で直接編集してしまうのだが、もっとシステマティックに編集するのはどうしたらいいんだろう?

関連記事