GoでSubversionからパッケージをgo getして実行する（自マシン内完結型）

社内や個人でSubversionを使ってGoコードを管理しているGopherには朗報！？Go 1.14から、goコマンドはmoduleモードでSubversionリポジトリーをサポートしました。

しかしながら、具体的な手順がなかなか見つかりませんでした。そこで「**自マシン内のSubversionサーバーに登録されたGoの外部パッケージを、自マシン内で取得して実行する**」ことを色々と目標に試してみました。実際に動作した時は心の中でガッツポーツ！q@w@p

## Subversionサーバーの構築

自マシンに「[Subversion](https://subversion.apache.org/)」と「[Apache HTTP Server](https://httpd.apache.org/)」をインストールします。

Apache HTTP Serverには、Subversionと連動してHTTP/HTTPS通信でアクセスできる仕組みが用意されています。

今回は、諸事情によりno_ssl版のためHTTP通信でアクセスした場合の内容となっています。openssl版＆HTTPS通信であればスマートに進められるはずです。

ちなみに、Subversionからの外部パッケージの取得には、svnコマンドが使用されます。

本筋ではないため、具体的なインストールやセットアップについては割愛します。

## Subversionリポジトリーの作成

svnadmin createコマンドで新規リポジトリーを作成します。

リポジトリー内に、branches/、tags/、trunk/、の定番ディレクトリーを作成します。

ここでは以下のパス構成を想定しています。

	svn://127.0.0.1/go/trunk/src/

本筋ではないため、具体的な手順は割愛します。

## GOPROXYとGOSUMDBの無効化

今回は、諸事情により外部へのインターネット接続が制限されているため、moduleに関する2つの環境変数の値を無効化します。

GOPROXYとGOSUMDBの初期値を確認します。

	$ go env GOPROXY
	https://proxy.golang.org,direct

	$ go env GOSUMDB
	sum.golang.org

GOPROXYとGOSUMDBに無効値を設定します。

	$ go env -w GOPROXY=direct
	$ go env -w GOSUMDB=off

## GOPATH上への移動

以降、GOPATH上で作業します。GOPATHは以下のコマンドで確認できます。

	$ go env GOPATH

## 外部パッケージをSubversionに登録

外部パッケージとして、Add()関数を持つcalcパッケージを用意します。

calc/ディレクトリーを作成します。

	$ mkdir calc

calc/ディレクトリー内に移動します。

	$ cd calc

modの初期化を行います。

	$ go mod init

作成されたgo.modファイルのmodule行をURLパスに修正します。

	修正前：

		module calc

		go 1.14

	修正後：

		module 127.0.0.1/svn/go/trunk/src/calc.svn

		go 1.14

calc.goを作成します。

	$ vim calc.go

		package calc

		func Add(x, y int) int {
			return x + y
		}

calc/ディレクトリーをSubversionにチェックインします。
（私はsvnコマンドではなく、Eclipseでチェックインしています m(__)m）

	svn://127.0.0.1/go/trunk/src/
	|
	+--calc/
	   |
	   +--calc.go
	   +--go.mod

## メイン パッケージの作成

test/ディレクトリーを作成します。

	$ mkdir test

test/ディレクトリー内に移動します。

	$ cd test

modの初期化を行います。

	$ go mod init

main.goファイルを作成します。

	$ vim main.go

		package main

		import (
			"fmt"

			calc "127.0.0.1/svn/go/trunk/src/calc.svn"
		)

		func main() {
			fmt.Println(calc.Add(1, 2))
		}

外部パッケージURLのホストが自マシンの場合、IPアドレス（ここでは127.0.0.1）で指定します。localhostで指定すると「import path does not begin with hostname」エラーになります。

通常でしたら、ここでmain.goファイルを実行します。

	$ go run main.go

この時、import句の"127.0.0.1/svn/go/trunk/src/calc.svn"にHTTPS通信でアクセスして自動で外部パッケージが取得されます。

	https://127.0.0.1/svn/go/trunk/src/calc.svn?go-get=1

しかし、今回はHTTP通信のためエラーとなります。そのため、go getコマンドを実行して手動で外部パッケージを取得します。

通常、go getするURLにはHTTPS通信でアクセスします。

	$ go get 127.0.0.1/svn/go/trunk/src/calc.svn

今回はHTTP通信のため、-insecure オプションを付けてgo getします。

	$ go get -insecure 127.0.0.1/svn/go/trunk/src/calc.svn

main.goファイルを実行すると、外部パッケージ「calc」のAdd(1, 2)が実行されて、結果の3が標準出力されます！

	$ go run main.go
	3

## メイン パッケージのモジュール情報

go.sumファイルが作成されます。

	$ vim -R go.sum

		127.0.0.1/svn/go/trunk/src/calc.svn v0.0.0-YYYYMMDD... h1:...=
		127.0.0.1/svn/go/trunk/src/calc.svn v0.0.0-YYYYMMDD.../go.mod h1:...=

go.modファイルに外部パッケージが追加されます。

	$ vim -R go.mod

		module test

		go 1.14

		require 127.0.0.1/svn/go/trunk/src/calc.svn v0.0.0-YYYYMMDD... // indirect

## 気づいた点など

go getではデフォルトでHTTPS通信が行われています。
	→Subversionと連動させるApache HTTP Serverはopenssl版を使いましょう。

Subversionの外部パッケージURLの最後には「.svn」が必要です。
	→GihHub経由に慣れていると、なかなか気付けない。

import句にて、Subversion経由の外部パッケージには別名を付けて使用します。
	→本ページでは"127.0.0.1/svn/go/trunk/src/calc.svn"にcalcと別名付けています。

関連するGoのソースコード
	→使われているsvnコマンドの引数とかがわかります。
	https://golang.org/src/cmd/go/internal/get/vcs.go
	https://golang.org/src/cmd/go/internal/modfetch/codehost/svn.go