diff options
| -rw-r--r-- | go.mod | 9 | ||||
| -rw-r--r-- | go.sum | 26 | ||||
| -rw-r--r-- | version/go1.10.4/main.go | 24 | ||||
| -rw-r--r-- | version/go1.11.1/main.go | 24 | ||||
| -rw-r--r-- | version/ko/main.go | 12 | ||||
| -rw-r--r-- | version/version.go | 455 |
6 files changed, 469 insertions, 81 deletions
@@ -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 ) @@ -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) +} |
