aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go.mod9
-rw-r--r--go.sum26
-rw-r--r--version/go1.10.4/main.go24
-rw-r--r--version/go1.11.1/main.go24
-rw-r--r--version/ko/main.go12
-rw-r--r--version/version.go455
6 files changed, 469 insertions, 81 deletions
diff --git a/go.mod b/go.mod
index 7f6c40a..ddb6ce6 100644
--- a/go.mod
+++ b/go.mod
@@ -1,30 +1,24 @@
module github.com/Xe/x
require (
- github.com/GeertJohan/yubigo v0.0.0-20140521141543-b1764f04aa9b // indirect
github.com/McKael/madon v2.3.0+incompatible
github.com/McKael/madon/v2 v2.0.0-20180929094633-c679abc985d6
- github.com/Syfaro/finch v1.0.0
github.com/Xe/johaus v0.0.0-20181126154118-fe870a11f3b2
github.com/Xe/ln v0.1.2
github.com/aclements/go-moremath v0.0.0-20180329182055-b1aff36309c7 // indirect
github.com/bearbin/mcgorcon v0.0.0-20141104170123-f611ad04551a
- github.com/belak/irc v2.1.0+incompatible
github.com/bwmarrin/discordgo v0.18.0
github.com/caarlos0/env v3.4.0+incompatible
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd
github.com/dgryski/go-failure v0.0.0-20151001134759-4963dbd58fd0
github.com/dgryski/go-onlinestats v0.0.0-20170612111826-1c7d19468768 // indirect
github.com/disintegration/imaging v1.5.0
- github.com/eaburns/johaus v0.0.0-20180211190535-0482c3c1f4ff
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect
github.com/facebookgo/flagenv v0.0.0-20160425205200-fcd59fca7456
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
github.com/fogleman/gg v1.1.0 // indirect
github.com/fogleman/primitive v0.0.0-20170926175833-69506c928bef
- github.com/go-telegram-bot-api/telegram-bot-api v4.6.2+incompatible
- github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.0.0-rc1
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/google/go-github v17.0.0+incompatible
github.com/google/go-querystring v1.0.0 // indirect
@@ -39,7 +33,6 @@ require (
github.com/klauspost/crc32 v0.0.0-20170628072449-bab58d77464a // indirect
github.com/klauspost/reedsolomon v0.0.0-20180704173009-925cb01d6510 // indirect
github.com/kr/pretty v0.1.0
- github.com/mzohreva/GoGraphviz v0.0.0-20180226085351-533f4a37d9c6 // indirect
github.com/olekukonko/tablewriter v0.0.0-20180912035003-be2c049b30cc // indirect
github.com/pborman/uuid v1.2.0
github.com/peterh/liner v1.1.0
@@ -55,7 +48,5 @@ require (
golang.org/x/image v0.0.0-20180926015637-991ec62608f3 // indirect
golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced
golang.org/x/sys v0.0.0-20181004145325-8469e314837c // indirect
- gopkg.in/irc.v1 v1.3.0
gopkg.in/tucnak/telebot.v2 v2.0.0-20181115150921-4688194c178d
- gopkg.in/yaml.v2 v2.2.1 // indirect
)
diff --git a/go.sum b/go.sum
index bcf1f82..c7771eb 100644
--- a/go.sum
+++ b/go.sum
@@ -2,14 +2,10 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
contrib.go.opencensus.io/exporter/stackdriver v0.5.0/go.mod h1:QeFzMJDAw8TXt5+aRaSuE8l5BwaMIOIlaVkBOPRuMuw=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
-github.com/GeertJohan/yubigo v0.0.0-20140521141543-b1764f04aa9b h1:SDBD2Avdba3sXg0F0xKeGZXz8+HODPl35jCSdZdFE9I=
-github.com/GeertJohan/yubigo v0.0.0-20140521141543-b1764f04aa9b/go.mod h1:njRCDrl+1RQ/A/+KVU8Ho2EWAxUSkohOWczdW3dzDG0=
github.com/McKael/madon v2.3.0+incompatible h1:xMUA+Fy4saDV+8tN3MMnwJUoYWC//5Fy8LeOqJsRNIM=
github.com/McKael/madon v2.3.0+incompatible/go.mod h1:+issnvJjN1rpjAHZwXRB/x30uHh/NoQR7QaojJK/lSI=
github.com/McKael/madon/v2 v2.0.0-20180929094633-c679abc985d6 h1:9cJcTOeILzInNo+DCYmXKME1QfAP07FYdo3M9/9jyc4=
github.com/McKael/madon/v2 v2.0.0-20180929094633-c679abc985d6/go.mod h1:mvlJhxZCchfiasx3XvN3hBu5RekGwTDm09dKlSM/dQQ=
-github.com/Syfaro/finch v1.0.0 h1:znxWMPCvB73U9Gtks/2GNnDdvr1GHy0mvGWgrHDHUpY=
-github.com/Syfaro/finch v1.0.0/go.mod h1:k9gfYahBVfVswGiwOKlmuoH/46AL2Y2Pkar0DyeYThM=
github.com/Xe/johaus v0.0.0-20181126154118-fe870a11f3b2 h1:UGyUwa0KVLJ8lA7A5wj9vreeQRDxnWCpTqyI6DRFM6s=
github.com/Xe/johaus v0.0.0-20181126154118-fe870a11f3b2/go.mod h1:AxheHD7a8X/KIoOUFa2krQkHFIKqhoP+VTWqNJ+3Joo=
github.com/Xe/ln v0.1.2 h1:VTF6Z95Kdd6S1RSjpnn0DFJV5Do9cfmHTHsE9OGI1dw=
@@ -19,20 +15,17 @@ github.com/aclements/go-moremath v0.0.0-20180329182055-b1aff36309c7/go.mod h1:id
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/bearbin/mcgorcon v0.0.0-20141104170123-f611ad04551a h1:WS0mhgU8W7T5gN1WNrBXqJUAeQ9eyWOpZx1cSyJw/Ew=
github.com/bearbin/mcgorcon v0.0.0-20141104170123-f611ad04551a/go.mod h1:Gt6oUa/biURD8wKBXC9vIlV/VQQSNHhSVRvUMHxPPzM=
-github.com/belak/irc v2.1.0+incompatible h1:0Y5sEJKrspau4xzZm7Mj9qcFEUyp0SJfH7Y/1rvig7E=
-github.com/belak/irc v2.1.0+incompatible/go.mod h1:vr/2iDlct72CfBLqW1hksy/xS9gwJ2gfeQpWSKng4pQ=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/bwmarrin/discordgo v0.18.0 h1:XopVQXCIFy7Cr2eT7NcYcm4k0l2PYX+AP5RUbIWX2/8=
github.com/bwmarrin/discordgo v0.18.0/go.mod h1:5NIvFv5Z7HddYuXbuQegZ684DleQaCFqChP2iuBivJ8=
github.com/caarlos0/env v3.4.0+incompatible h1:FRwBdvENjLHZoUbFnULnFss9wKtcapdaM35DfxiTjeM=
github.com/caarlos0/env v3.4.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y=
-github.com/certifi/gocertifi v0.0.0-20180905225744-ee1a9a0726d2 h1:MmeatFT1pTPSVb4nkPmBFN/LRZ97vPjsFKsZrU3KKTs=
-github.com/certifi/gocertifi v0.0.0-20180905225744-ee1a9a0726d2/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-systemd v0.0.0-20180705093442-88bfeed483d3/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-failure v0.0.0-20151001134759-4963dbd58fd0 h1:SJzP6kZNFsdxFN4fRtVXu2yrf8QrKnofjQouzaCn36w=
github.com/dgryski/go-failure v0.0.0-20151001134759-4963dbd58fd0/go.mod h1:vVcpVd0tzL5XdRrkHax1asNJsHVpgA0cd9fHPHU5a/w=
@@ -45,6 +38,7 @@ github.com/eaburns/johaus v0.0.0-20180211190535-0482c3c1f4ff h1:UYJFJoLfHqPuxd9K
github.com/eaburns/johaus v0.0.0-20180211190535-0482c3c1f4ff/go.mod h1:haq7Ati+IITjB94ZcX9Pur49JW6bQRs/yTcYaqDPxsc=
github.com/eaburns/peggy v0.0.0-20180405011029-d685ddd3cbcb h1:VNtdhXiCNFtQkeRwcS8XW2+gyxollG4Kc4wnHbzGpP8=
github.com/eaburns/peggy v0.0.0-20180405011029-d685ddd3cbcb/go.mod h1:5tfPwI6ukiK3W5vJzkj5MBQKHHY9Gcy2y6k1FC/23Xk=
+github.com/eaburns/pretty v0.0.0-20170305202417-362524b72369 h1:C/RhDONMNTxvyaQNWbxj2RAyHOGVYoq+kP5j9hdnYOk=
github.com/eaburns/pretty v0.0.0-20170305202417-362524b72369/go.mod h1:iW/TU1T4mA4w2KzqNbBCjacPFdJ9PfGvNSxr8ajT/iM=
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
@@ -60,13 +54,7 @@ github.com/fogleman/gg v1.1.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzP
github.com/fogleman/primitive v0.0.0-20170926175833-69506c928bef h1:b2hzCO7V6vnDYAvucXo5smx9wut3A3Huw4VRNg1SMK8=
github.com/fogleman/primitive v0.0.0-20170926175833-69506c928bef/go.mod h1:Tm6t8LbdhSCXNfpjTwoL1mdjCnyKHkMyf6PqQXo7Or8=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/getsentry/raven-go v0.0.0-20180903072508-084a9de9eb03 h1:G/9fPivTr5EiyqE9OlW65iMRUxFXMGRHgZFGo50uG8Q=
-github.com/getsentry/raven-go v0.0.0-20180903072508-084a9de9eb03/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
-github.com/go-telegram-bot-api/telegram-bot-api v4.6.2+incompatible h1:tI1+S63aiYb8JDRY8WBqn7Q1Utnr09L9ga5T2VA2ZDI=
-github.com/go-telegram-bot-api/telegram-bot-api v4.6.2+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
-github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.0.0-rc1 h1:Mr8jIV7wDfLw5Fw6BPupm0aduTFdLjhI3wFuIIZKvO4=
-github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.0.0-rc1/go.mod h1:2s/IzRcxCszyNh760IjJiqoYHTnifk8ZeNYL33z8Pww=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -118,8 +106,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/microcosm-cc/bluemonday v1.0.0/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
-github.com/mzohreva/GoGraphviz v0.0.0-20180226085351-533f4a37d9c6 h1:yd4o0qJNQc2PBlymcRCUHM0ltxciTkPjUuVTj8cDbLA=
-github.com/mzohreva/GoGraphviz v0.0.0-20180226085351-533f4a37d9c6/go.mod h1:eILxk8m1m1XGxWu1nQHdKKKl/JnDltcRTe2n84cUWDw=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/olekukonko/tablewriter v0.0.0-20180912035003-be2c049b30cc h1:rQ1O4ZLYR2xXHXgBCCfIIGnuZ0lidMQw2S5n1oOv+Wg=
@@ -166,8 +152,6 @@ github.com/streamrail/concurrent-map v0.0.0-20160823150647-8bf1e9bacbf6/go.mod h
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/tarm/serial v0.0.0-20180114052751-eaafced92e96/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
-github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
-github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tmc/scp v0.0.0-20170824174625-f7b48647feef h1:7D6Nm4D6f0ci9yttWaKjM1TMAXrH5Su72dojqYGntFY=
github.com/tmc/scp v0.0.0-20170824174625-f7b48647feef/go.mod h1:WLFStEdnJXpjK8kd4qKLwQKX/1vrDzp5BcDyiZJBHJM=
github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89/go.mod h1:ejwOYCjnDMyO5LXFXRARQJGBZ6xQJZ3rgAHE5drSuMM=
@@ -212,13 +196,7 @@ google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH2
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180731170733-daca94659cb5/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/irc.v1 v1.3.0 h1:28A0njDuHNueatbQZsRB78CaU8sueA8JWIXVvue60sg=
-gopkg.in/irc.v1 v1.3.0/go.mod h1:yXDeqklL7+ht3OdUIo0r8WaraGQyjyD+/92R1YxNZxM=
gopkg.in/tucnak/telebot.v2 v2.0.0-20181115150921-4688194c178d h1:rwP+DFa5TQOEP7iCCc2z0ql57CtuI+divggCiXbuYR0=
gopkg.in/tucnak/telebot.v2 v2.0.0-20181115150921-4688194c178d/go.mod h1:EmWSFwexO5JPTHiU7gDd9HMCCiyatACwO0HhuKNsOd0=
-gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
diff --git a/version/go1.10.4/main.go b/version/go1.10.4/main.go
deleted file mode 100644
index 232dbe7..0000000
--- a/version/go1.10.4/main.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// The go1.10.4 command runs the go command from go1.10.4.
-//
-// To install, run:
-//
-// $ go get golang.org/x/build/version/go1.10.4
-// $ go1.10.4 download
-//
-// And then use the go1.10.4 command as if it were your normal go
-// command.
-//
-// See the release notes at https://beta.golang.org/doc/go1.10
-//
-// File bugs at http://golang.org/issues/new
-package main
-
-import "golang.org/x/build/version"
-
-func main() {
- version.Run("go1.10.4")
-}
diff --git a/version/go1.11.1/main.go b/version/go1.11.1/main.go
deleted file mode 100644
index e8ff2ab..0000000
--- a/version/go1.11.1/main.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// The go1.11.1 command runs the go command from go1.11.1.
-//
-// To install, run:
-//
-// $ go get golang.org/x/build/version/go1.11.1
-// $ go1.11.1 download
-//
-// And then use the go1.11.1 command as if it were your normal go
-// command.
-//
-// See the release notes at https://beta.golang.org/doc/go1.11.1
-//
-// File bugs at http://golang.org/issues/new
-package main
-
-import "golang.org/x/build/version"
-
-func main() {
- version.Run("go1.11.1")
-}
diff --git a/version/ko/main.go b/version/ko/main.go
new file mode 100644
index 0000000..a299bab
--- /dev/null
+++ b/version/ko/main.go
@@ -0,0 +1,12 @@
+package main
+
+import (
+ "os"
+
+ "github.com/Xe/x/version"
+ _ "github.com/joho/godotenv/autoload"
+)
+
+func main() {
+ version.Run(os.Getenv("GO_VERSION"))
+}
diff --git a/version/version.go b/version/version.go
new file mode 100644
index 0000000..7ae7894
--- /dev/null
+++ b/version/version.go
@@ -0,0 +1,455 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The version package permits running a specific version of Go.
+package version
+
+import (
+ "archive/tar"
+ "archive/zip"
+ "compress/gzip"
+ "crypto/sha256"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "os/exec"
+ "os/user"
+ "path"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "time"
+
+ "golang.org/x/build/envutil"
+)
+
+func init() {
+ http.DefaultTransport = &userAgentTransport{http.DefaultTransport}
+}
+
+// Run runs the "go" tool of the provided Go version.
+func Run(version string) {
+ log.SetFlags(0)
+
+ root, err := goroot(version)
+ if err != nil {
+ log.Fatalf("%s: %v", version, err)
+ }
+
+ if len(os.Args) == 2 && os.Args[1] == "download" {
+ if err := install(root, version); err != nil {
+ log.Fatalf("%s: download failed: %v", version, err)
+ }
+ os.Exit(0)
+ }
+
+ if _, err := os.Stat(filepath.Join(root, unpackedOkay)); err != nil {
+ log.Fatalf("%s: not downloaded. Run '%s download' to install to %v", version, os.Args[0], root)
+ }
+
+ gobin := filepath.Join(root, "bin", "go"+exe())
+ cmd := exec.Command(gobin, os.Args[1:]...)
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ cmd.Env = envutil.Dedup(caseInsensitiveEnv, append(os.Environ(), "GOROOT="+root))
+ if err := cmd.Run(); err != nil {
+ // TODO: return the same exit status maybe.
+ os.Exit(1)
+ }
+ os.Exit(0)
+}
+
+// install installs a version of Go to the named target directory, creating the
+// directory as needed.
+func install(targetDir, version string) error {
+ if _, err := os.Stat(filepath.Join(targetDir, unpackedOkay)); err == nil {
+ log.Printf("%s: already downloaded in %v", version, targetDir)
+ return nil
+ }
+
+ goURL, err := versionArchiveURL(version)
+ if err != nil {
+ return err
+ }
+ if err := os.MkdirAll(targetDir, 0755); err != nil {
+ return err
+ }
+ res, err := http.Head(goURL)
+ if err != nil {
+ return err
+ }
+ if res.StatusCode == http.StatusNotFound {
+ return fmt.Errorf("no binary release of %v for %v/%v at %v", version, getOS(), runtime.GOARCH, goURL)
+ }
+ if res.StatusCode != http.StatusOK {
+ return fmt.Errorf("server returned %v checking size of %v", http.StatusText(res.StatusCode), goURL)
+ }
+ base := path.Base(goURL)
+ archiveFile := filepath.Join(targetDir, base)
+ defer os.RemoveAll(archiveFile)
+ if fi, err := os.Stat(archiveFile); err != nil || fi.Size() != res.ContentLength {
+ if err != nil && !os.IsNotExist(err) {
+ // Something weird. Don't try to download.
+ return err
+ }
+ if err := copyFromURL(archiveFile, goURL); err != nil {
+ return fmt.Errorf("error downloading %v: %v", goURL, err)
+ }
+ fi, err = os.Stat(archiveFile)
+ if err != nil {
+ return err
+ }
+ if fi.Size() != res.ContentLength {
+ return fmt.Errorf("downloaded file %s size %v doesn't match server size %v", archiveFile, fi.Size(), res.ContentLength)
+ }
+ }
+ wantSHA, err := slurpURLToString(goURL + ".sha256")
+ if err != nil {
+ return err
+ }
+ if err := verifySHA256(archiveFile, strings.TrimSpace(wantSHA)); err != nil {
+ return fmt.Errorf("error verifying SHA256 of %v: %v", archiveFile, err)
+ }
+ log.Printf("Unpacking %v ...", archiveFile)
+ if err := unpackArchive(targetDir, archiveFile); err != nil {
+ return fmt.Errorf("extracting archive %v: %v", archiveFile, err)
+ }
+ if err := ioutil.WriteFile(filepath.Join(targetDir, unpackedOkay), nil, 0644); err != nil {
+ return err
+ }
+ log.Printf("Success. You may now run '%v'", os.Args[0])
+ return nil
+}
+
+// unpackArchive unpacks the provided archive zip or tar.gz file to targetDir,
+// removing the "go/" prefix from file entries.
+func unpackArchive(targetDir, archiveFile string) error {
+ switch {
+ case strings.HasSuffix(archiveFile, ".zip"):
+ return unpackZip(targetDir, archiveFile)
+ case strings.HasSuffix(archiveFile, ".tar.gz"):
+ return unpackTarGz(targetDir, archiveFile)
+ default:
+ return errors.New("unsupported archive file")
+ }
+}
+
+// unpackTarGz is the tar.gz implementation of unpackArchive.
+func unpackTarGz(targetDir, archiveFile string) error {
+ r, err := os.Open(archiveFile)
+ if err != nil {
+ return err
+ }
+ defer r.Close()
+ madeDir := map[string]bool{}
+ zr, err := gzip.NewReader(r)
+ if err != nil {
+ return err
+ }
+ tr := tar.NewReader(zr)
+ for {
+ f, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return err
+ }
+ if !validRelPath(f.Name) {
+ return fmt.Errorf("tar file contained invalid name %q", f.Name)
+ }
+ rel := filepath.FromSlash(strings.TrimPrefix(f.Name, "go/"))
+ abs := filepath.Join(targetDir, rel)
+
+ fi := f.FileInfo()
+ mode := fi.Mode()
+ switch {
+ case mode.IsRegular():
+ // Make the directory. This is redundant because it should
+ // already be made by a directory entry in the tar
+ // beforehand. Thus, don't check for errors; the next
+ // write will fail with the same error.
+ dir := filepath.Dir(abs)
+ if !madeDir[dir] {
+ if err := os.MkdirAll(filepath.Dir(abs), 0755); err != nil {
+ return err
+ }
+ madeDir[dir] = true
+ }
+ wf, err := os.OpenFile(abs, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode.Perm())
+ if err != nil {
+ return err
+ }
+ n, err := io.Copy(wf, tr)
+ if closeErr := wf.Close(); closeErr != nil && err == nil {
+ err = closeErr
+ }
+ if err != nil {
+ return fmt.Errorf("error writing to %s: %v", abs, err)
+ }
+ if n != f.Size {
+ return fmt.Errorf("only wrote %d bytes to %s; expected %d", n, abs, f.Size)
+ }
+ if !f.ModTime.IsZero() {
+ if err := os.Chtimes(abs, f.ModTime, f.ModTime); err != nil {
+ // benign error. Gerrit doesn't even set the
+ // modtime in these, and we don't end up relying
+ // on it anywhere (the gomote push command relies
+ // on digests only), so this is a little pointless
+ // for now.
+ log.Printf("error changing modtime: %v", err)
+ }
+ }
+ case mode.IsDir():
+ if err := os.MkdirAll(abs, 0755); err != nil {
+ return err
+ }
+ madeDir[abs] = true
+ default:
+ return fmt.Errorf("tar file entry %s contained unsupported file type %v", f.Name, mode)
+ }
+ }
+ return nil
+}
+
+// unpackZip is the zip implementation of unpackArchive.
+func unpackZip(targetDir, archiveFile string) error {
+ zr, err := zip.OpenReader(archiveFile)
+ if err != nil {
+ return err
+ }
+ defer zr.Close()
+
+ for _, f := range zr.File {
+ name := strings.TrimPrefix(f.Name, "go/")
+
+ outpath := filepath.Join(targetDir, name)
+ if f.FileInfo().IsDir() {
+ if err := os.MkdirAll(outpath, 0755); err != nil {
+ return err
+ }
+ continue
+ }
+
+ rc, err := f.Open()
+ if err != nil {
+ return err
+ }
+
+ // File
+ if err := os.MkdirAll(filepath.Dir(outpath), 0755); err != nil {
+ return err
+ }
+ out, err := os.OpenFile(outpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(out, rc)
+ rc.Close()
+ if err != nil {
+ out.Close()
+ return err
+ }
+ if err := out.Close(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// verifySHA256 reports whether the named file has contents with
+// SHA-256 of the given wantHex value.
+func verifySHA256(file, wantHex string) error {
+ f, err := os.Open(file)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ hash := sha256.New()
+ if _, err := io.Copy(hash, f); err != nil {
+ return err
+ }
+ if fmt.Sprintf("%x", hash.Sum(nil)) != wantHex {
+ return fmt.Errorf("%s corrupt? does not have expected SHA-256 of %v", file, wantHex)
+ }
+ return nil
+}
+
+// slurpURLToString downloads the given URL and returns it as a string.
+func slurpURLToString(url_ string) (string, error) {
+ res, err := http.Get(url_)
+ if err != nil {
+ return "", err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusOK {
+ return "", fmt.Errorf("%s: %v", url_, res.Status)
+ }
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ return "", fmt.Errorf("reading %s: %v", url_, err)
+ }
+ return string(slurp), nil
+}
+
+// copyFromURL downloads srcURL to dstFile.
+func copyFromURL(dstFile, srcURL string) (err error) {
+ f, err := os.Create(dstFile)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err != nil {
+ f.Close()
+ os.Remove(dstFile)
+ }
+ }()
+ c := &http.Client{
+ Transport: &userAgentTransport{&http.Transport{
+ // It's already compressed. Prefer accurate ContentLength.
+ // (Not that GCS would try to compress it, though)
+ DisableCompression: true,
+ DisableKeepAlives: true,
+ Proxy: http.ProxyFromEnvironment,
+ }},
+ }
+ res, err := c.Get(srcURL)
+ if err != nil {
+ return err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusOK {
+ return errors.New(res.Status)
+ }
+ pw := &progressWriter{w: f, total: res.ContentLength}
+ n, err := io.Copy(pw, res.Body)
+ if err != nil {
+ return err
+ }
+ if res.ContentLength != -1 && res.ContentLength != n {
+ return fmt.Errorf("copied %v bytes; expected %v", n, res.ContentLength)
+ }
+ pw.update() // 100%
+ return f.Close()
+}
+
+type progressWriter struct {
+ w io.Writer
+ n int64
+ total int64
+ last time.Time
+}
+
+func (p *progressWriter) update() {
+ end := " ..."
+ if p.n == p.total {
+ end = ""
+ }
+ fmt.Fprintf(os.Stderr, "Downloaded %0.1f%% (%d / %d bytes)%s\n",
+ (100.0*float64(p.n))/float64(p.total),
+ p.n, p.total, end)
+}
+
+func (p *progressWriter) Write(buf []byte) (n int, err error) {
+ n, err = p.w.Write(buf)
+ p.n += int64(n)
+ if now := time.Now(); now.Unix() != p.last.Unix() {
+ p.update()
+ p.last = now
+ }
+ return
+}
+
+// getOS returns runtime.GOOS. It exists as a function just for lazy
+// testing of the Windows zip path when running on Linux/Darwin.
+func getOS() string {
+ return runtime.GOOS
+}
+
+// versionArchiveURL returns the zip or tar.gz URL of the given Go version.
+func versionArchiveURL(version string) (string, error) {
+ goos := getOS()
+
+ // TODO: Maybe we should parse
+ // https://storage.googleapis.com/go-builder-data/dl-index.txt ?
+ // Let's just guess the URL for now and see if it's there.
+ // Then we don't have to maintain that txt file too.
+ ext := ".tar.gz"
+ if goos == "windows" {
+ ext = ".zip"
+ }
+ arch := runtime.GOARCH
+ if goos == "linux" && runtime.GOARCH == "arm" {
+ arch = "armv6l"
+ }
+ // https://dl.google.com/go/go1.11.2.linux-amd64.tar.gz
+ return "https://dl.google.com/go/" + version + "." + goos + "-" + arch + ext, nil
+}
+
+const caseInsensitiveEnv = runtime.GOOS == "windows"
+
+// unpackedOkay is a sentinel zero-byte file to indicate that the Go
+// version was downloaded and unpacked successfully.
+const unpackedOkay = ".unpacked-success"
+
+func exe() string {
+ if runtime.GOOS == "windows" {
+ return ".exe"
+ }
+ return ""
+}
+
+func goroot(version string) (string, error) {
+ home, err := homedir()
+ if err != nil {
+ return "", fmt.Errorf("failed to get home directory: %v", err)
+ }
+ return filepath.Join(home, ".ko", "installed", version), nil
+}
+
+func homedir() (string, error) {
+ switch getOS() {
+ case "plan9":
+ return "", fmt.Errorf("%q not yet supported", runtime.GOOS)
+ case "windows":
+ if dir := os.Getenv("USERPROFILE"); dir != "" {
+ return dir, nil
+ }
+ return "", errors.New("can't find user home directory; %USERPROFILE% is empty")
+ default:
+ if dir := os.Getenv("HOME"); dir != "" {
+ return dir, nil
+ }
+ if u, err := user.Current(); err == nil && u.HomeDir != "" {
+ return u.HomeDir, nil
+ }
+ return "", errors.New("can't find user home directory; $HOME is empty")
+ }
+}
+
+func validRelPath(p string) bool {
+ if p == "" || strings.Contains(p, `\`) || strings.HasPrefix(p, "/") || strings.Contains(p, "../") {
+ return false
+ }
+ return true
+}
+
+type userAgentTransport struct {
+ rt http.RoundTripper
+}
+
+func (uat userAgentTransport) RoundTrip(r *http.Request) (*http.Response, error) {
+ version := runtime.Version()
+ if strings.Contains(version, "devel") {
+ // Strip the SHA hash and date. We don't want spaces or other tokens (see RFC2616 14.43)
+ version = "devel"
+ }
+ r.Header.Set("User-Agent", "github-com-Xe-x/"+version)
+ return uat.rt.RoundTrip(r)
+}