glide getやglide upが動かない
glide getで新しいライブラリをインストールしようとするとこんなエラーが出た。
[ERROR] Error scanning github.com/golang/protobuf/ptypes/duration: open /Users/yunomu/.glide/cache/src/https-github.com-golang-protobuf-ptypes-duration: no such file or directory [ERROR] This error means the referenced package was not found. [ERROR] Missing file or directory errors usually occur when multiple packages [ERROR] share a common dependency and the first reference encountered by the scanner [ERROR] sets the version to one that does not contain a subpackage needed required [ERROR] by another package that uses the shared dependency. Try setting a [ERROR] version in your glide.yaml that works for all packages that share this [ERROR] dependency.
私がメインで使っているMacだとこうなるけど、他の環境ではこのエラーは起きない。
そもそもエラーメッセージの中では https-github.com-golang-protobuf-ptypes-duration
を探そうとしているが私が探しているのは https-github.com-golang-protobuf/ptypes/duration
である。パスの切り方が違うので当然ながらファイルは見つからない。
バグかと思ったけどもそういうissueも登録されていないのでコードを見てみる。 https://github.com/Masterminds/glide/tree/v0.12.3
件のエラーメッセージが dependency/resolver.go
の543行目あたりに書かれている。
https://github.com/Masterminds/glide/blob/v0.12.3/dependency/resolver.go
543 } else if strings.Contains(errStr, "no such file or directory") { 544 r.hadError[dep] = true 545 msg.Err("Error scanning %s: %s", dep, err) 546 msg.Err("This error means the referenced package was not found.") 547 msg.Err("Missing file or directory errors usually occur when multiple packages") 548 msg.Err("share a common dependency and the first reference encountered by the scanner") 549 msg.Err("sets the version to one that does not contain a subpackage needed required") 550 msg.Err("by another package that uses the shared dependency. Try setting a") 551 msg.Err("version in your glide.yaml that works for all packages that share this") 552 msg.Err("dependency.")
エラーメッセージに “no such file or directory” という文字列が入っているかどうかでエラーを判断しているあたり大胆だ。
そのエラーの原因がここ。デバッグメッセージ付きで実行してみると、同ファイルのこの部分の時点で 493行目の r.Handler.PkgPath(dep)
が https-github.com-golang-protobuf-ptypes-duration
を返しており、成功するはずがない。
492 // Here, we want to import the package and see what imports it has. 493 msg.Debug("Trying to open %s (%s)", dep, r.Handler.PkgPath(dep)) 494 var imps []string 495 pkg, err := r.BuildContext.ImportDir(r.Handler.PkgPath(dep), 0)
次に PkgPath
の定義を見る。interfaceなので定義は2つあるが repo/installer.go
の方。
https://github.com/Masterminds/glide/blob/v0.12.3/repo/installer.go
600 // PkgPath resolves the location on the filesystem where the package should be. 601 // This handles making sure to use the cache location. 602 func (m *MissingPackageHandler) PkgPath(pkg string) string { 603 root, sub := util.NormalizeName(pkg) 604 605 // For the parent applications source skip the cache. 606 if root == m.Config.Name { 607 pth := gpath.Basepath() 608 return filepath.Join(pth, filepath.FromSlash(sub)) 609 } 610 611 d := m.Config.Imports.Get(root) 612 if d == nil { 613 d = m.Config.DevImports.Get(root) 614 } 615 616 if d == nil { 617 d, _ = m.Use.Get(root) 618 619 if d == nil { 620 d = &cfg.Dependency{Name: root} 621 } 622 } 623 624 key, err := cache.Key(d.Remote()) 625 if err != nil { 626 msg.Die("Error generating cache key for %s", d.Name) 627 } 628 629 return filepath.Join(cache.Location(), "src", key, filepath.FromSlash(sub)) 630 }
本来、最後629行目で key=https-github.com-golang-protobuf
, filePath.FromSlash(sub)=ptypes/dulation
にならなければならないが key=https-github.com-golang-protobuf-ptypes-duration
になっている。全然ダメだ。
そもそも603行目のutil.NormalizeName()が root=github.com/golang/protobuf/ptypes/duration
, sub=
を返している。
このライブラリのリポジトリは https://github.com/golang/protobuf
で、リポジトリ内のサブディレクトリは ptypes/dulation
なので、ここでは root=github.com/golang/protobuf
, sub=ptypes/dulation
となってほしい。
ということで util.NoralizeName()
を見る。
https://github.com/Masterminds/glide/blob/v0.12.3/util/util.go
300 // NormalizeName takes a package name and normalizes it to the top level package. 301 // 302 // For example, golang.org/x/crypto/ssh becomes golang.org/x/crypto. 'ssh' is 303 // returned as extra data. 304 // 305 // FIXME: Is this deprecated? 306 func NormalizeName(name string) (string, string) { 307 // Fastpath check if a name in the GOROOT. There is an issue when a pkg 308 // is in the GOROOT and GetRootFromPackage tries to look it up because it 309 // expects remote names. 310 b, err := GetBuildContext() 311 if err == nil { 312 p := filepath.Join(b.GOROOT, "src", name) 313 if _, err := os.Stat(p); err == nil { 314 return toSlash(name), "" 315 } 316 } 317 318 name = toSlash(name) 319 root := GetRootFromPackage(name) 320 extra := strings.TrimPrefix(name, root) 321 if len(extra) > 0 && extra != "/" { 322 extra = strings.TrimPrefix(extra, "/") 323 } else { 324 // If extra is / (which is what it would be here) we want to return "" 325 extra = "" 326 } 327 328 return root, extra 329 }
嫌な感じのコメントが書いてある。
それはいいとして、312行目でGOROOTから該当のライブラリを探している。
私の場合、 GOROOT=/usr/local/go
なので、 /usr/local/go/src/github.com/golang/protobuf/ptypes/duration
が存在するかどうかを確認している。実際に見てみると、あった。なんであるんじゃい。
このファイル(ディレクトリ)が存在することで314行目でreturnしてしまって、最終的におかしなURLにライブラリの更新確認に行って死んでいた模様。この後にパスからリポジトリの種類を判別してURLを作るのだがそもそも/usr/local以下はgitはgitでもbrewの配下である。
% sudo rm -rf /usr/local/go/src/github.com
で事なきを得た。そもそもなんでこんなところにこんなものが入っていたのかよくわからない。
このあたりを探っているとGoogle内部のリポジトリやパッケージ管理法とGitとの相性の悪さで外の人たちが割を食ってる感じがしてちょっと面白い。自分が悩む方でなければ。
あとGoは読むのが楽で助かる。