pyenvのpythonを叩くと自作goプログラムのpanicが走る怪奇現象

タイトルで出落ち。

結論

  • ビルトインのコマンド名を自作プログラムに使うのはNG(大昔から言われてるからそれ
  • 自作プログラムへのPATHは追加する形で(昔から(ry
  • ソースコードリーディング楽しい(白目

きっかけ

算数をpythonにお願いしようとしたところ以下のエラーが発生した。

[User@PC] ~
% python
panic: Head http://localhost:18888: dial tcp 127.0.0.1:18888: getsockopt: connection refused

goroutine 1 [running]:
main.main()
    /path/to/head/head.go:11 +0x16e
[User@PC] ~

Goプログラムのソースは以下。書籍「Real World HTTP」の写経で、HTTPのHEADリクエストを送信するもの。

# Filename: head.go
package main

import (
    "log"
    "net/http"
)

func main() {
    resp, err := http.Head("http://localhost:18888")
    if err != nil {
        panic(err)
    }
    log.Println("Status: ", resp.Status)
    log.Println("Headers: ", resp.Header)
}

解決への流れ

  1. pythonの確認
  2. pyenvの確認
  3. headの確認
  4. $PATHの確認

実際

pythonの確認

ブログ用にcat、実際にはless

[User@PC] ~
% file `which python`
/path/to/.anyenv/envs/pyenv/shims/python: Bourne-Again shell script text executable, ASCII text
[User@PC] ~
% cat `which python`
#!/usr/bin/env bash
set -e
[ -n "$PYENV_DEBUG" ] && set -x

program="${0##*/}"
if [[ "$program" = "python"* ]]; then
  for arg; do
    case "$arg" in
    -c* | -- ) break ;;
    */* )
      if [ -f "$arg" ]; then
        export PYENV_FILE_ARG="$arg"
        break
      fi
      ;;
    esac
  done
fi

export PYENV_ROOT="/path/to/.anyenv/envs/pyenv"
exec "/path/to/.anyenv/envs/pyenv/libexec/pyenv" exec "$program" "$@"
[User@PC] ~

※$programや$@にエラーになる要因がないかはechoさせて確認
ここでhead.goが正常動作する場合も確認しておいた。 pyenvのエラーが有用。pyenvの中にエラーの要因があると断定。

[User@PC] ~
% python
2017/12/23 13:57:03 Status:  200 OK
2017/12/23 13:57:03 Headers:  map[Content-Length:[54] Content-Type:[text/html; charset=utf-8] Set-Cookie:[VISIT=TRUE] Date:[Sat, 23 Dec 2017 04:57:03 GMT]]
pyenv: cannot find readlink - are you missing GNU coreutils?

Goの サーバプログラムは以下。これも上記書籍の写経。

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/http/httputil"

    "github.com/k0kubun/pp"
)
〜中略〜
func main() {
    var httpServer http.Server
    http.HandleFunc("/", handler)
    httpServer.Addr = ":18888"
    log.Printf("[i] Start http listing %s\n", httpServer.Addr)
    log.Println(httpServer.ListenAndServe())
}

pyenvの確認

catの箇所では文字列検索をしたかったのでvimで開いた

[User@PC] ~
% file /path/to/.anyenv/envs/pyenv/libexec/pyenv
/path/to/.anyenv/envs/pyenv/libexec/pyenv: Bourne-Again shell script text executable, ASCII text
[User@PC] ~
% cat /path/to/.anyenv/envs/pyenv/libexec/pyenv
## 先ほどのエラー「pyenv: cannot find readlink - are you missing GNU coreutils?」で検索
#!/usr/bin/env bash
set -e
unset CDPATH

〜中略〜

  READLINK=$(type -p greadlink readlink | head -1)
  [ -n "$READLINK" ] || abort "cannot find readlink - are you missing GNU coreutils?"

〜以下略〜
[User@PC] ~
% 

エラーの箇所を発見、怪しい箇所としてはここのhead。

headの確認

ここでずっこけた。buildした覚えはなかったがどうやら指が勝手に動いていたらしい。

[User@PC] ~
% head
2017/12/23 14:16:31 Status:  200 OK
2017/12/23 14:16:31 Headers:  map[Date:[Sat, 23 Dec 2017 05:16:31 GMT] Content-Length:[54] Content-Type:[text/html; charset=utf-8] Set-Cookie:[VISIT=TRUE]]
[User@PC] ~
% which head
/path/to/$GOPATH/bin/head
[User@PC] ~
%

ひとまず/path/to/$GOPATH/bin/headを削除して動作を確認。

[User@PC] ~
% rm -f $GOPATH/bin/head
[User@PC] ~
% python
Python 2.7.10 (default, Jul 15 2017, 17:16:57) 
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> ^D
[User@PC] ~
% 

OK.

PATHの確認

編集前提なのでvimで開いた。

[User@PC] ~
% cat .zshrc

〜中略〜
# Go env
export GOROOT=$HOME/.anyenv/envs/goenv/versions/$GO_VERSION
export GOPATH=$HOME/dev
export PATH=$GOROOT/bin:$GOPATH/bin:$PATH
〜以下略〜

[User@PC] ~
%

ツラい。以下のように修正。

- export PATH=$GOROOT/bin:$GOPATH/bin:$PATH
+ export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

大切なことなので再び結論(自戒を込めて

  • ビルトインのコマンド名を自作プログラムに使うのはNG(大昔から言われてるからそれ
  • 自作プログラムへのPATHは追加する形で(昔から(ry
  • ソースコードリーディング楽しい(白目してない

所感

以上!閉廷!解散!