diff --git a/.builds/apple.yml b/.builds/apple.yml
index d5cf7e68..f159ca19 100644
--- a/.builds/apple.yml
+++ b/.builds/apple.yml
@@ -62,13 +62,3 @@ tasks:
- test_ios: |
cd gio
CC=$APPLE_TOOLCHAIN_ROOT/tools/clang-ios GOOS=darwin GOARCH=arm64 CGO_ENABLED=1 go build -tags ios ./...
- - install_gogio: |
- cd gio/cmd
- go install ./gogio
- - test_ios_gogio: |
- mkdir tmp
- cd tmp
- go mod init example.com
- go get -d gioui.org/example/kitchen
- export PATH=/home/build/appletools/bin:$PATH
- gogio -target ios -o app.app gioui.org/example/kitchen
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index ce132598..2d59f050 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -20,6 +20,3 @@ tasks:
- test_gio: |
cd gio
go test ./...
- - test_cmd: |
- cd gio/cmd
- go test ./...
diff --git a/.builds/linux.yml b/.builds/linux.yml
index 172f4256..8f781bf2 100644
--- a/.builds/linux.yml
+++ b/.builds/linux.yml
@@ -29,7 +29,6 @@ packages:
sources:
- https://git.sr.ht/~eliasnaur/gio
environment:
- GOFLAGS: -mod=readonly
PATH: /home/build/sdk/go/bin:/usr/bin:/home/build/go/bin:/home/build/android/tools/bin
ANDROID_SDK_ROOT: /home/build/android
android_sdk_tools_zip: sdk-tools-linux-3859397.zip
@@ -54,6 +53,9 @@ tasks:
exit 1
fi
done
+ - mirror: |
+ # mirror to github
+ ssh-keyscan github.com > "$HOME"/.ssh/known_hosts && cd gio && git push --mirror "$github_mirror" || echo "failed mirroring"
- test_gio: |
cd gio
go test -race ./...
@@ -64,10 +66,6 @@ tasks:
sudo sh -c 'echo "deb [arch=amd64] https://dl-ssl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
sudo apt-get -qq update
sudo apt-get -qq install -y google-chrome-stable
- - test_cmd: |
- cd gio/cmd
- go test ./...
- go test -race ./...
- install_jdk8: |
curl -so jdk.deb "https://cdn.azul.com/zulu/bin/zulu8.42.0.21-ca-jdk8.0.232-linux_amd64.deb"
sudo apt-get -qq install -y -f ./jdk.deb
@@ -87,15 +85,3 @@ tasks:
cd gio
CC=$ANDROID_SDK_ROOT/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android29-clang GOOS=android GOARCH=arm64 CGO_ENABLED=1 go build ./...
CC=$ANDROID_SDK_ROOT/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi29-clang GOOS=android GOARCH=arm CGO_ENABLED=1 go build ./...
- - install_gogio: |
- cd gio/cmd
- go install ./gogio
- - test_android_gogio: |
- mkdir tmp
- cd tmp
- go mod init example.com
- go get -d gioui.org/example/kitchen
- gogio -target android gioui.org/example/kitchen
- - mirror: |
- # mirror to github
- ssh-keyscan github.com > "$HOME"/.ssh/known_hosts && cd gio && git push --mirror "$github_mirror" || echo "failed mirroring"
diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml
index 9c79c3a6..eae42c3b 100644
--- a/.builds/openbsd.yml
+++ b/.builds/openbsd.yml
@@ -16,6 +16,3 @@ tasks:
- test_gio: |
cd gio
go test ./...
- - test_cmd: |
- cd gio/cmd
- go test ./...
diff --git a/cmd/go.mod b/cmd/go.mod
deleted file mode 100644
index f49a1d3b..00000000
--- a/cmd/go.mod
+++ /dev/null
@@ -1,14 +0,0 @@
-module gioui.org/cmd
-
-go 1.13
-
-require (
- gioui.org v0.0.0-20220328154813-a3f147541fd0
- github.com/akavel/rsrc v0.10.1
- github.com/chromedp/cdproto v0.0.0-20191114225735-6626966fbae4
- github.com/chromedp/chromedp v0.5.2
- golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
- golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
- golang.org/x/text v0.3.6
- golang.org/x/tools v0.1.0
-)
diff --git a/cmd/go.sum b/cmd/go.sum
deleted file mode 100644
index 719fb4c2..00000000
--- a/cmd/go.sum
+++ /dev/null
@@ -1,475 +0,0 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-eliasnaur.com/font v0.0.0-20220124212145-832bb8fc08c3/go.mod h1:OYVuxibdk9OSLX8vAqydtRPP87PyTFcT9uH3MlEGBQA=
-gioui.org v0.0.0-20220328154813-a3f147541fd0 h1:n4FUiCT6P4a2wF6hwX4a5R8TpjAhu/d+3nhwZW16MAI=
-gioui.org v0.0.0-20220328154813-a3f147541fd0/go.mod h1:b8vBukexG6eYuXZa14asjLAWJ+JjbZ/ophEnS2FjYUg=
-gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
-gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc=
-gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
-gioui.org/shader v1.0.6 h1:cvZmU+eODFR2545X+/8XucgZdTtEjR3QWW6W65b0q5Y=
-gioui.org/shader v1.0.6/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
-github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
-github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
-github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
-github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
-github.com/akavel/rsrc v0.10.1 h1:hCCPImjmFKVNGpeLZyTDRHEFC283DzyTXTo0cO0Rq9o=
-github.com/akavel/rsrc v0.10.1/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
-github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
-github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
-github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
-github.com/benoitkugler/pstokenizer v1.0.0/go.mod h1:l1G2Voirz0q/jj0TQfabNxVsa8HZXh/VMxFSRALWTiE=
-github.com/benoitkugler/textlayout v0.0.5/go.mod h1:puH4v13Uz7uIhIH0XMk5jgc8U3MXcn5r3VlV9K8n0D8=
-github.com/benoitkugler/textlayout v0.0.10 h1:uIaQgH4pBFw1LQ0tPkfjgxo94WYcckzzQaB41L2X84w=
-github.com/benoitkugler/textlayout v0.0.10/go.mod h1:puH4v13Uz7uIhIH0XMk5jgc8U3MXcn5r3VlV9K8n0D8=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
-github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chromedp/cdproto v0.0.0-20191114225735-6626966fbae4 h1:QD3KxSJ59L2lxG6MXBjNHxiQO2RmxTQ3XcK+wO44WOg=
-github.com/chromedp/cdproto v0.0.0-20191114225735-6626966fbae4/go.mod h1:PfAWWKJqjlGFYJEidUM6aVIWPr0EpobeyVWEEmplX7g=
-github.com/chromedp/chromedp v0.5.2 h1:W8xBXQuUnd2dZK0SN/lyVwsQM7KgW+kY5HGnntms194=
-github.com/chromedp/chromedp v0.5.2/go.mod h1:rsTo/xRo23KZZwFmWk2Ui79rBaVRRATCjLzNQlOFSiA=
-github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=
-github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
-github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
-github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gioui/uax v0.2.1-0.20220325163150-e3d987515a12 h1:1bjaB/5IIicfKpP4k0s30T2WEw//Kh00zULa8DQ0cxA=
-github.com/gioui/uax v0.2.1-0.20220325163150-e3d987515a12/go.mod h1:kDhBRTA/i3H46PVdhqcw26TdGSIj42TOKNWKY+Kipnw=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
-github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
-github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-text/typesetting v0.0.0-20220112121102-58fe93c84506 h1:1TPz/Gn/MsXwJ6bEtI9wdkPcQYr2X3V9I+wz4wPYUdY=
-github.com/go-text/typesetting v0.0.0-20220112121102-58fe93c84506/go.mod h1:R0mlTNeyszZ/tKQhbZA7SRGjx+OHsmNzgN2jTV7yZcs=
-github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
-github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
-github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
-github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
-github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
-github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
-github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
-github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
-github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
-github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
-github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
-github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08 h1:V0an7KRw92wmJysvFvtqtKMAPmvS5O0jtB0nYo6t+gs=
-github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08/go.mod h1:dFWs1zEqDjFtnBXsd1vPOZaLsESovai349994nHx3e0=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
-github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
-github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
-github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
-github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
-github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
-github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
-github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
-github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
-github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
-github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
-github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
-github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
-github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg=
-github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
-github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
-github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
-github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
-github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
-github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
-github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
-github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
-github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
-github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM=
-github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
-github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
-github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
-github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
-go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
-go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
-go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
-go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
-go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
-go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
-go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
-go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
-golang.org/x/exp v0.0.0-20210722180016-6781d3edade3 h1:IlrJD2AM5p8JhN/wVny9jt6gJ9hut2VALhSeZ3SYluk=
-golang.org/x/exp v0.0.0-20210722180016-6781d3edade3/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
-golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
-golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
-golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
-golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
-golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
-gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
-gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
-sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
-sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/cmd/gogio/android_test.go b/cmd/gogio/android_test.go
deleted file mode 100644
index e73386f9..00000000
--- a/cmd/gogio/android_test.go
+++ /dev/null
@@ -1,143 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-package main_test
-
-import (
- "bytes"
- "context"
- "fmt"
- "image"
- "image/png"
- "os"
- "os/exec"
- "path/filepath"
- "regexp"
-)
-
-type AndroidTestDriver struct {
- driverBase
-
- sdkDir string
- adbPath string
-}
-
-var rxAdbDevice = regexp.MustCompile(`(.*)\s+device$`)
-
-func (d *AndroidTestDriver) Start(path string) {
- d.sdkDir = os.Getenv("ANDROID_SDK_ROOT")
- if d.sdkDir == "" {
- d.Skipf("Android SDK is required; set $ANDROID_SDK_ROOT")
- }
- d.adbPath = filepath.Join(d.sdkDir, "platform-tools", "adb")
- if _, err := os.Stat(d.adbPath); os.IsNotExist(err) {
- d.Skipf("adb not found")
- }
-
- devOut := bytes.TrimSpace(d.adb("devices"))
- devices := rxAdbDevice.FindAllSubmatch(devOut, -1)
- switch len(devices) {
- case 0:
- d.Skipf("no Android devices attached via adb; skipping")
- case 1:
- default:
- d.Skipf("multiple Android devices attached via adb; skipping")
- }
-
- // If the device is attached but asleep, it's probably just charging.
- // Don't use it; the screen needs to be on and unlocked for the test to
- // work.
- if !bytes.Contains(
- d.adb("shell", "dumpsys", "power"),
- []byte(" mWakefulness=Awake"),
- ) {
- d.Skipf("Android device isn't awake; skipping")
- }
-
- // First, build the app.
- apk := filepath.Join(d.tempDir("gio-endtoend-android"), "e2e.apk")
- d.gogio("-target=android", "-appid="+appid, "-o="+apk, path)
-
- // Make sure the app isn't installed already, and try to uninstall it
- // when we finish. Previous failed test runs might have left the app.
- d.tryUninstall()
- d.adb("install", apk)
- d.Cleanup(d.tryUninstall)
-
- // Force our e2e app to be fullscreen, so that the android system bar at
- // the top doesn't mess with our screenshots.
- // TODO(mvdan): is there a way to do this via gio, so that we don't need
- // to set up a global Android setting via the shell?
- d.adb("shell", "settings", "put", "global", "policy_control", "immersive.full="+appid)
-
- // Make sure the app isn't already running.
- d.adb("shell", "pm", "clear", appid)
-
- // Start listening for log messages.
- {
- ctx, cancel := context.WithCancel(context.Background())
- cmd := exec.CommandContext(ctx, d.adbPath,
- "logcat",
- "-s", // suppress other logs
- "-T1", // don't show previous log messages
- appid+":*", // show all logs from our gio app ID
- )
- output, err := cmd.StdoutPipe()
- if err != nil {
- d.Fatal(err)
- }
- cmd.Stderr = cmd.Stdout
- d.output = output
- if err := cmd.Start(); err != nil {
- d.Fatal(err)
- }
- d.Cleanup(cancel)
- }
-
- // Start the app.
- d.adb("shell", "monkey", "-p", appid, "1")
-
- // Wait for the gio app to render.
- d.waitForFrame()
-}
-
-func (d *AndroidTestDriver) Screenshot() image.Image {
- out := d.adb("shell", "screencap", "-p")
- img, err := png.Decode(bytes.NewReader(out))
- if err != nil {
- d.Fatal(err)
- }
- return img
-}
-
-func (d *AndroidTestDriver) tryUninstall() {
- cmd := exec.Command(d.adbPath, "shell", "pm", "uninstall", appid)
- out, err := cmd.CombinedOutput()
- if err != nil {
- if bytes.Contains(out, []byte("Unknown package")) {
- // The package is not installed. Don't log anything.
- return
- }
- d.Logf("could not uninstall: %v\n%s", err, out)
- }
-}
-
-func (d *AndroidTestDriver) adb(args ...interface{}) []byte {
- strs := []string{}
- for _, arg := range args {
- strs = append(strs, fmt.Sprint(arg))
- }
- cmd := exec.Command(d.adbPath, strs...)
- out, err := cmd.CombinedOutput()
- if err != nil {
- d.Errorf("%s", out)
- d.Fatal(err)
- }
- return out
-}
-
-func (d *AndroidTestDriver) Click(x, y int) {
- d.adb("shell", "input", "tap", x, y)
-
- // Wait for the gio app to render after this click.
- d.waitForFrame()
-}
diff --git a/cmd/gogio/androidbuild.go b/cmd/gogio/androidbuild.go
deleted file mode 100644
index cddba994..00000000
--- a/cmd/gogio/androidbuild.go
+++ /dev/null
@@ -1,1044 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-package main
-
-import (
- "archive/zip"
- "bytes"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strconv"
- "strings"
- "text/template"
-
- "golang.org/x/sync/errgroup"
- "golang.org/x/tools/go/packages"
-)
-
-type androidTools struct {
- buildtools string
- androidjar string
-}
-
-// zip.Writer with a sticky error.
-type zipWriter struct {
- err error
- w *zip.Writer
-}
-
-// Writer that saves any errors.
-type errWriter struct {
- w io.Writer
- err *error
-}
-
-var exeSuffix string
-
-type manifestData struct {
- AppID string
- Version int
- MinSDK int
- TargetSDK int
- Permissions []string
- Features []string
- IconSnip string
- AppName string
-}
-
-const (
- themes = `
-
-
-`
- themesV21 = `
-
-
-`
-)
-
-func init() {
- if runtime.GOOS == "windows" {
- exeSuffix = ".exe"
- }
-}
-
-func buildAndroid(tmpDir string, bi *buildInfo) error {
- sdk := os.Getenv("ANDROID_SDK_ROOT")
- if sdk == "" {
- return errors.New("please set ANDROID_SDK_ROOT to the Android SDK path")
- }
- if _, err := os.Stat(sdk); err != nil {
- return err
- }
- platform, err := latestPlatform(sdk)
- if err != nil {
- return err
- }
- buildtools, err := latestTools(sdk)
- if err != nil {
- return err
- }
-
- tools := &androidTools{
- buildtools: buildtools,
- androidjar: filepath.Join(platform, "android.jar"),
- }
- perms := []string{"default"}
- const permPref = "gioui.org/app/permission/"
- cfg := &packages.Config{
- Mode: packages.NeedName +
- packages.NeedFiles +
- packages.NeedImports +
- packages.NeedDeps,
- Env: append(
- os.Environ(),
- "GOOS=android",
- "CGO_ENABLED=1",
- ),
- }
- pkgs, err := packages.Load(cfg, bi.pkgPath)
- if err != nil {
- return err
- }
- var extraJars []string
- visitedPkgs := make(map[string]bool)
- var visitPkg func(*packages.Package) error
- visitPkg = func(p *packages.Package) error {
- if len(p.GoFiles) == 0 {
- return nil
- }
- dir := filepath.Dir(p.GoFiles[0])
- jars, err := filepath.Glob(filepath.Join(dir, "*.jar"))
- if err != nil {
- return err
- }
- extraJars = append(extraJars, jars...)
- switch {
- case p.PkgPath == "net":
- perms = append(perms, "network")
- case strings.HasPrefix(p.PkgPath, permPref):
- perms = append(perms, p.PkgPath[len(permPref):])
- }
-
- for _, imp := range p.Imports {
- if !visitedPkgs[imp.ID] {
- visitPkg(imp)
- visitedPkgs[imp.ID] = true
- }
- }
- return nil
- }
- if err := visitPkg(pkgs[0]); err != nil {
- return err
- }
-
- if err := compileAndroid(tmpDir, tools, bi); err != nil {
- return err
- }
- switch *buildMode {
- case "archive":
- return archiveAndroid(tmpDir, bi, perms)
- case "exe":
- file := *destPath
- if file == "" {
- file = fmt.Sprintf("%s.apk", bi.name)
- }
-
- isBundle := false
- switch filepath.Ext(file) {
- case ".apk":
- case ".aab":
- isBundle = true
- default:
- return fmt.Errorf("the specified output %q does not end in '.apk' or '.aab'", file)
- }
-
- if err := exeAndroid(tmpDir, tools, bi, extraJars, perms, isBundle); err != nil {
- return err
- }
- if isBundle {
- return signAAB(tmpDir, file, tools, bi)
- }
- return signAPK(tmpDir, file, tools, bi)
- default:
- panic("unreachable")
- }
-}
-
-func compileAndroid(tmpDir string, tools *androidTools, bi *buildInfo) (err error) {
- androidHome := os.Getenv("ANDROID_SDK_ROOT")
- if androidHome == "" {
- return errors.New("ANDROID_SDK_ROOT is not set. Please point it to the root of the Android SDK")
- }
- javac, err := findJavaC()
- if err != nil {
- return fmt.Errorf("could not find javac: %v", err)
- }
- ndkRoot, err := findNDK(androidHome)
- if err != nil {
- return err
- }
- minSDK := 17
- if bi.minsdk > minSDK {
- minSDK = bi.minsdk
- }
- tcRoot := filepath.Join(ndkRoot, "toolchains", "llvm", "prebuilt", archNDK())
- var builds errgroup.Group
- for _, a := range bi.archs {
- arch := allArchs[a]
- clang, err := latestCompiler(tcRoot, a, minSDK)
- if err != nil {
- return fmt.Errorf("%s. Please make sure you have NDK >= r19c installed. Use the command `sdkmanager ndk-bundle` to install it.", err)
- }
- if runtime.GOOS == "windows" {
- // Because of https://github.com/android-ndk/ndk/issues/920,
- // we need NDK r19c, not just r19b. Check for the presence of
- // clang++.cmd which is only available in r19c.
- clangpp := clang + "++.cmd"
- if _, err := os.Stat(clangpp); err != nil {
- return fmt.Errorf("NDK version r19b detected, but >= r19c is required. Use the command `sdkmanager ndk-bundle` to install it")
- }
- }
- archDir := filepath.Join(tmpDir, "jni", arch.jniArch)
- if err := os.MkdirAll(archDir, 0755); err != nil {
- return fmt.Errorf("failed to create %q: %v", archDir, err)
- }
- libFile := filepath.Join(archDir, "libgio.so")
- cmd := exec.Command(
- "go",
- "build",
- "-ldflags=-w -s "+bi.ldflags,
- "-buildmode=c-shared",
- "-tags", bi.tags,
- "-o", libFile,
- bi.pkgPath,
- )
- cmd.Env = append(
- os.Environ(),
- "GOOS=android",
- "GOARCH="+a,
- "GOARM=7", // Avoid softfloat.
- "CGO_ENABLED=1",
- "CC="+clang,
- )
- builds.Go(func() error {
- _, err := runCmd(cmd)
- return err
- })
- }
- appDir, err := runCmd(exec.Command("go", "list", "-f", "{{.Dir}}", "gioui.org/app/"))
- if err != nil {
- return err
- }
- javaFiles, err := filepath.Glob(filepath.Join(appDir, "*.java"))
- if err != nil {
- return err
- }
- if len(javaFiles) == 0 {
- return fmt.Errorf("the gioui.org/app package contains no .java files (gioui.org module too old?)")
- }
- if len(javaFiles) > 0 {
- classes := filepath.Join(tmpDir, "classes")
- if err := os.MkdirAll(classes, 0755); err != nil {
- return err
- }
- javac := exec.Command(
- javac,
- "-target", "1.8",
- "-source", "1.8",
- "-sourcepath", appDir,
- "-bootclasspath", tools.androidjar,
- "-d", classes,
- )
- javac.Args = append(javac.Args, javaFiles...)
- builds.Go(func() error {
- _, err := runCmd(javac)
- return err
- })
- }
- return builds.Wait()
-}
-
-func archiveAndroid(tmpDir string, bi *buildInfo, perms []string) (err error) {
- aarFile := *destPath
- if aarFile == "" {
- aarFile = fmt.Sprintf("%s.aar", bi.name)
- }
- if filepath.Ext(aarFile) != ".aar" {
- return fmt.Errorf("the specified output %q does not end in '.aar'", aarFile)
- }
- aar, err := os.Create(aarFile)
- if err != nil {
- return err
- }
- defer func() {
- if cerr := aar.Close(); err == nil {
- err = cerr
- }
- }()
- aarw := newZipWriter(aar)
- defer aarw.Close()
- aarw.Create("R.txt")
- themesXML := aarw.Create("res/values/themes.xml")
- themesXML.Write([]byte(themes))
- themesXML21 := aarw.Create("res/values-v21/themes.xml")
- themesXML21.Write([]byte(themesV21))
- permissions, features := getPermissions(perms)
- // Disable input emulation on ChromeOS.
- manifest := aarw.Create("AndroidManifest.xml")
- manifestSrc := manifestData{
- AppID: bi.appID,
- MinSDK: bi.minsdk,
- Permissions: permissions,
- Features: features,
- }
- tmpl, err := template.New("manifest").Parse(
- `
-
-{{range .Permissions}}
-{{end}}{{range .Features}}
-{{end}}
-`)
- if err != nil {
- panic(err)
- }
- err = tmpl.Execute(manifest, manifestSrc)
- proguard := aarw.Create("proguard.txt")
- proguard.Write([]byte(`-keep class org.gioui.** { *; }`))
-
- for _, a := range bi.archs {
- arch := allArchs[a]
- libFile := filepath.Join("jni", arch.jniArch, "libgio.so")
- aarw.Add(filepath.ToSlash(libFile), filepath.Join(tmpDir, libFile))
- }
- classes := filepath.Join(tmpDir, "classes")
- if _, err := os.Stat(classes); err == nil {
- jarFile := filepath.Join(tmpDir, "classes.jar")
- if err := writeJar(jarFile, classes); err != nil {
- return err
- }
- aarw.Add("classes.jar", jarFile)
- }
- return aarw.Close()
-}
-
-func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, perms []string, isBundle bool) (err error) {
- classes := filepath.Join(tmpDir, "classes")
- var classFiles []string
- err = filepath.Walk(classes, func(path string, f os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if filepath.Ext(path) == ".class" {
- classFiles = append(classFiles, path)
- }
- return nil
- })
- classFiles = append(classFiles, extraJars...)
- dexDir := filepath.Join(tmpDir, "apk")
- if err := os.MkdirAll(dexDir, 0755); err != nil {
- return err
- }
- // https://developer.android.com/distribute/best-practices/develop/target-sdk
- targetSDK := 31
- if bi.minsdk > targetSDK {
- targetSDK = bi.minsdk
- }
- minSDK := 16
- if bi.minsdk > minSDK {
- minSDK = bi.minsdk
- }
- if len(classFiles) > 0 {
- d8 := exec.Command(
- filepath.Join(tools.buildtools, "d8"),
- "--lib", tools.androidjar,
- "--output", dexDir,
- "--min-api", strconv.Itoa(minSDK),
- )
- d8.Args = append(d8.Args, classFiles...)
- if _, err := runCmd(d8); err != nil {
- major, minor, ok := determineJDKVersion()
- if ok && (major != 1 || minor != 8) {
- return fmt.Errorf("unsupported JDK version %d.%d, expected 1.8\nd8 error: %v", major, minor, err)
- }
- return err
- }
- }
-
- // Compile resources.
- resDir := filepath.Join(tmpDir, "res")
- valDir := filepath.Join(resDir, "values")
- v21Dir := filepath.Join(resDir, "values-v21")
- v26mipmapDir := filepath.Join(resDir, `mipmap-anydpi-v26`)
- for _, dir := range []string{valDir, v21Dir, v26mipmapDir} {
- if err := os.MkdirAll(dir, 0755); err != nil {
- return err
- }
- }
- iconSnip := ""
- if _, err := os.Stat(bi.iconPath); err == nil {
- err := buildIcons(resDir, bi.iconPath, []iconVariant{
- {path: filepath.Join("mipmap-hdpi", "ic_launcher.png"), size: 72},
- {path: filepath.Join("mipmap-xhdpi", "ic_launcher.png"), size: 96},
- {path: filepath.Join("mipmap-xxhdpi", "ic_launcher.png"), size: 144},
- {path: filepath.Join("mipmap-xxxhdpi", "ic_launcher.png"), size: 192},
- {path: filepath.Join("mipmap-mdpi", "ic_launcher_adaptive.png"), size: 108},
- {path: filepath.Join("mipmap-hdpi", "ic_launcher_adaptive.png"), size: 162},
- {path: filepath.Join("mipmap-xhdpi", "ic_launcher_adaptive.png"), size: 216},
- {path: filepath.Join("mipmap-xxhdpi", "ic_launcher_adaptive.png"), size: 324},
- {path: filepath.Join("mipmap-xxxhdpi", "ic_launcher_adaptive.png"), size: 432},
- })
- if err != nil {
- return err
- }
- err = ioutil.WriteFile(filepath.Join(v26mipmapDir, `ic_launcher.xml`), []byte(`
-
-
-
-`), 0660)
- if err != nil {
- return err
- }
- iconSnip = `android:icon="@mipmap/ic_launcher"`
- }
- err = ioutil.WriteFile(filepath.Join(valDir, "themes.xml"), []byte(themes), 0660)
- if err != nil {
- return err
- }
- err = ioutil.WriteFile(filepath.Join(v21Dir, "themes.xml"), []byte(themesV21), 0660)
- if err != nil {
- return err
- }
- resZip := filepath.Join(tmpDir, "resources.zip")
- aapt2 := filepath.Join(tools.buildtools, "aapt2")
- _, err = runCmd(exec.Command(
- aapt2,
- "compile",
- "-o", resZip,
- "--dir", resDir))
- if err != nil {
- return err
- }
-
- // Link APK.
- permissions, features := getPermissions(perms)
- appName := strings.Title(bi.name)
- manifestSrc := manifestData{
- AppID: bi.appID,
- Version: bi.version,
- MinSDK: minSDK,
- TargetSDK: targetSDK,
- Permissions: permissions,
- Features: features,
- IconSnip: iconSnip,
- AppName: appName,
- }
- tmpl, err := template.New("test").Parse(
- `
-
-
-{{range .Permissions}}
-{{end}}{{range .Features}}
-{{end}}
-
-
-
-
-
-
-
-`)
- var manifestBuffer bytes.Buffer
- if err := tmpl.Execute(&manifestBuffer, manifestSrc); err != nil {
- return err
- }
- manifest := filepath.Join(tmpDir, "AndroidManifest.xml")
- if err := ioutil.WriteFile(manifest, manifestBuffer.Bytes(), 0660); err != nil {
- return err
- }
-
- linkAPK := filepath.Join(tmpDir, "link.apk")
-
- args := []string{
- "link",
- "--manifest", manifest,
- "-I", tools.androidjar,
- "-o", linkAPK,
- }
- if isBundle {
- args = append(args, "--proto-format")
- }
- args = append(args, resZip)
-
- if _, err := runCmd(exec.Command(aapt2, args...)); err != nil {
- return err
- }
-
- // The Go standard library archive/zip doesn't support appending to zip
- // files. Copy files from `link.apk` (generated by aapt2) along with classes.dex and
- // the Go libraries to a new `app.zip` file.
-
- // Load link.apk as zip.
- linkAPKZip, err := zip.OpenReader(linkAPK)
- if err != nil {
- return err
- }
- defer linkAPKZip.Close()
-
- // Create new "APK".
- unsignedAPK := filepath.Join(tmpDir, "app.zip")
- unsignedAPKFile, err := os.Create(unsignedAPK)
- if err != nil {
- return err
- }
- defer func() {
- if cerr := unsignedAPKFile.Close(); err == nil {
- err = cerr
- }
- }()
- unsignedAPKZip := zip.NewWriter(unsignedAPKFile)
- defer unsignedAPKZip.Close()
-
- // Copy files from linkAPK to unsignedAPK.
- for _, f := range linkAPKZip.File {
- header := zip.FileHeader{
- Name: f.FileHeader.Name,
- Method: f.FileHeader.Method,
- }
-
- if isBundle {
- // AAB have pre-defined folders.
- switch header.Name {
- case "AndroidManifest.xml":
- header.Name = "manifest/AndroidManifest.xml"
- }
- }
-
- w, err := unsignedAPKZip.CreateHeader(&header)
- if err != nil {
- return err
- }
- r, err := f.Open()
- if err != nil {
- return err
- }
- if _, err := io.Copy(w, r); err != nil {
- return err
- }
- }
-
- // Append new files (that doesn't exists inside the link.apk).
- appendToZip := func(path string, file string) error {
- f, err := os.Open(file)
- if err != nil {
- return err
- }
- defer f.Close()
- w, err := unsignedAPKZip.CreateHeader(&zip.FileHeader{
- Name: filepath.ToSlash(path),
- Method: zip.Deflate,
- })
- if err != nil {
- return err
- }
- _, err = io.Copy(w, f)
- return err
- }
-
- // Append Go binaries (libgio.so).
- for _, a := range bi.archs {
- arch := allArchs[a]
- libFile := filepath.Join(arch.jniArch, "libgio.so")
- if err := appendToZip(filepath.Join("lib", libFile), filepath.Join(tmpDir, "jni", libFile)); err != nil {
- return err
- }
- }
-
- // Append classes.dex.
- if len(classFiles) > 0 {
- classesFolder := "classes.dex"
- if isBundle {
- classesFolder = "dex/classes.dex"
- }
- if err := appendToZip(classesFolder, filepath.Join(dexDir, "classes.dex")); err != nil {
- return err
- }
- }
-
- return unsignedAPKZip.Close()
-}
-
-func determineJDKVersion() (int, int, bool) {
- path, err := findJavaC()
- if err != nil {
- return 0, 0, false
- }
- java := exec.Command(filepath.Join(filepath.Dir(path), "java"), "-version")
- out, err := java.CombinedOutput()
- if err != nil {
- return 0, 0, false
- }
- var vendor string
- var major, minor int
- _, err = fmt.Sscanf(string(out), "%s version \"%d.%d", &vendor, &major, &minor)
- return major, minor, err == nil
-}
-
-func signAPK(tmpDir string, apkFile string, tools *androidTools, bi *buildInfo) error {
- if err := zipalign(tools, filepath.Join(tmpDir, "app.zip"), apkFile); err != nil {
- return err
- }
-
- if bi.key == "" {
- if err := defaultAndroidKeystore(tmpDir, bi); err != nil {
- return err
- }
- }
-
- _, err := runCmd(exec.Command(
- filepath.Join(tools.buildtools, "apksigner"),
- "sign",
- "--ks-pass", "pass:"+bi.password,
- "--ks", bi.key,
- apkFile,
- ))
-
- return err
-}
-
-func signAAB(tmpDir string, aabFile string, tools *androidTools, bi *buildInfo) error {
- allBundleTools, err := filepath.Glob(filepath.Join(tools.buildtools, "bundletool*.jar"))
- if err != nil {
- return err
- }
-
- bundletool := ""
- for _, v := range allBundleTools {
- bundletool = v
- break
- }
-
- if bundletool == "" {
- return fmt.Errorf("bundletool was not found at %s. Download it from https://github.com/google/bundletool/releases and move to the respective folder", tools.buildtools)
- }
-
- _, err = runCmd(exec.Command(
- "java",
- "-jar", bundletool,
- "build-bundle",
- "--modules="+filepath.Join(tmpDir, "app.zip"),
- "--output="+filepath.Join(tmpDir, "app.aab"),
- ))
- if err != nil {
- return err
- }
-
- if err := zipalign(tools, filepath.Join(tmpDir, "app.aab"), aabFile); err != nil {
- return err
- }
-
- if bi.key == "" {
- if err := defaultAndroidKeystore(tmpDir, bi); err != nil {
- return err
- }
- }
-
- keytoolList, err := runCmd(exec.Command(
- "keytool",
- "-keystore", bi.key,
- "-list",
- "-keypass", bi.password,
- "-v",
- ))
- if err != nil {
- return err
- }
-
- var alias string
- for _, t := range strings.Split(keytoolList, "\n") {
- if i, _ := fmt.Sscanf(t, "Alias name: %s", &alias); i > 0 {
- break
- }
- }
-
- _, err = runCmd(exec.Command(
- filepath.Join("jarsigner"),
- "-sigalg", "SHA256withRSA",
- "-digestalg", "SHA-256",
- "-keystore", bi.key,
- "-storepass", bi.password,
- aabFile,
- strings.TrimSpace(alias),
- ))
-
- return err
-}
-
-func zipalign(tools *androidTools, input, output string) error {
- _, err := runCmd(exec.Command(
- filepath.Join(tools.buildtools, "zipalign"),
- "-f",
- "4", // 32-bit alignment.
- input,
- output,
- ))
- return err
-}
-
-func defaultAndroidKeystore(tmpDir string, bi *buildInfo) error {
- home, err := os.UserHomeDir()
- if err != nil {
- return err
- }
-
- // Use debug.keystore, if exists.
- bi.key = filepath.Join(home, ".android", "debug.keystore")
- bi.password = "android"
- if _, err := os.Stat(bi.key); err == nil {
- return nil
- }
-
- // Generate new key.
- bi.key = filepath.Join(tmpDir, "sign.keystore")
- keytool, err := findKeytool()
- if err != nil {
- return err
- }
- _, err = runCmd(exec.Command(
- keytool,
- "-genkey",
- "-keystore", bi.key,
- "-storepass", bi.password,
- "-alias", "android",
- "-keyalg", "RSA", "-keysize", "2048",
- "-validity", "10000",
- "-noprompt",
- "-dname", "CN=android",
- ))
- return err
-}
-
-func findNDK(androidHome string) (string, error) {
- ndks, err := filepath.Glob(filepath.Join(androidHome, "ndk", "*"))
- if err != nil {
- return "", err
- }
- if bestNDK, found := latestVersionPath(ndks); found {
- return bestNDK, nil
- }
- // The old NDK path was $ANDROID_SDK_ROOT/ndk-bundle.
- ndkBundle := filepath.Join(androidHome, "ndk-bundle")
- if _, err := os.Stat(ndkBundle); err == nil {
- return ndkBundle, nil
- }
- // Certain non-standard NDK isntallations set the $ANDROID_NDK_ROOT
- // environment variable
- if ndkBundle, ok := os.LookupEnv("ANDROID_NDK_ROOT"); ok {
- if _, err := os.Stat(ndkBundle); err == nil {
- return ndkBundle, nil
- }
- }
-
- return "", fmt.Errorf("no NDK found in $ANDROID_SDK_ROOT (%s). Set $ANDROID_NDK_ROOT or use `sdkmanager ndk-bundle` to install the NDK", androidHome)
-}
-
-func findKeytool() (string, error) {
- javaHome := os.Getenv("JAVA_HOME")
- if javaHome == "" {
- return exec.LookPath("keytool")
- }
- keytool := filepath.Join(javaHome, "jre", "bin", "keytool"+exeSuffix)
- if _, err := os.Stat(keytool); err != nil {
- return "", err
- }
- return keytool, nil
-}
-
-func findJavaC() (string, error) {
- javaHome := os.Getenv("JAVA_HOME")
- if javaHome == "" {
- return exec.LookPath("javac")
- }
- javac := filepath.Join(javaHome, "bin", "javac"+exeSuffix)
- if _, err := os.Stat(javac); err != nil {
- return "", err
- }
- return javac, nil
-}
-
-func writeJar(jarFile, dir string) (err error) {
- jar, err := os.Create(jarFile)
- if err != nil {
- return err
- }
- defer func() {
- if cerr := jar.Close(); err == nil {
- err = cerr
- }
- }()
- jarw := newZipWriter(jar)
- const manifestHeader = `Manifest-Version: 1.0
-Created-By: 1.0 (Go)
-
-`
- jarw.Create("META-INF/MANIFEST.MF").Write([]byte(manifestHeader))
- err = filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if f.IsDir() {
- return nil
- }
- if filepath.Ext(path) == ".class" {
- rel := filepath.ToSlash(path[len(dir)+1:])
- jarw.Add(rel, path)
- }
- return nil
- })
- if err != nil {
- return err
- }
- return jarw.Close()
-}
-
-func archNDK() string {
- var arch string
- switch runtime.GOARCH {
- case "386":
- arch = "x86"
- case "amd64":
- arch = "x86_64"
- case "arm64":
- if runtime.GOOS == "darwin" {
- // Workaround for arm64 macOS. This will keep working until
- // Apple deprecates Rosetta 2.
- arch = "x86_64"
- } else {
- panic("unsupported GOARCH: " + runtime.GOARCH)
- }
- default:
- panic("unsupported GOARCH: " + runtime.GOARCH)
- }
- return runtime.GOOS + "-" + arch
-}
-
-func getPermissions(ps []string) ([]string, []string) {
- var permissions, features []string
- seenPermissions := make(map[string]bool)
- seenFeatures := make(map[string]bool)
- for _, perm := range ps {
- for _, x := range AndroidPermissions[perm] {
- if !seenPermissions[x] {
- permissions = append(permissions, x)
- seenPermissions[x] = true
- }
- }
- for _, x := range AndroidFeatures[perm] {
- if !seenFeatures[x] {
- features = append(features, x)
- seenFeatures[x] = true
- }
- }
- }
- return permissions, features
-}
-
-func latestPlatform(sdk string) (string, error) {
- allPlats, err := filepath.Glob(filepath.Join(sdk, "platforms", "android-*"))
- if err != nil {
- return "", err
- }
- var bestVer int
- var bestPlat string
- for _, platform := range allPlats {
- _, name := filepath.Split(platform)
- // The glob above guarantees the "android-" prefix.
- verStr := name[len("android-"):]
- ver, err := strconv.Atoi(verStr)
- if err != nil {
- continue
- }
- if ver < bestVer {
- continue
- }
- bestVer = ver
- bestPlat = platform
- }
- if bestPlat == "" {
- return "", fmt.Errorf("no platforms found in %q", sdk)
- }
- return bestPlat, nil
-}
-
-func latestCompiler(tcRoot, a string, minsdk int) (string, error) {
- arch := allArchs[a]
- allComps, err := filepath.Glob(filepath.Join(tcRoot, "bin", arch.clangArch+"*-clang"))
- if err != nil {
- return "", err
- }
- var bestVer int
- var firstVer int
- var bestCompiler string
- var firstCompiler string
- for _, compiler := range allComps {
- var ver int
- pattern := filepath.Join(tcRoot, "bin", arch.clangArch) + "%d-clang"
- if n, err := fmt.Sscanf(compiler, pattern, &ver); n < 1 || err != nil {
- continue
- }
- if firstCompiler == "" || ver < firstVer {
- firstVer = ver
- firstCompiler = compiler
- }
- if ver < bestVer {
- continue
- }
- if ver > minsdk {
- continue
- }
- bestVer = ver
- bestCompiler = compiler
- }
- if bestCompiler == "" {
- bestCompiler = firstCompiler
- }
- if bestCompiler == "" {
- return "", fmt.Errorf("no NDK compiler found for architecture %s in %s", a, tcRoot)
- }
- return bestCompiler, nil
-}
-
-func latestTools(sdk string) (string, error) {
- allTools, err := filepath.Glob(filepath.Join(sdk, "build-tools", "*"))
- if err != nil {
- return "", err
- }
- tools, found := latestVersionPath(allTools)
- if !found {
- return "", fmt.Errorf("no build-tools found in %q", sdk)
- }
- return tools, nil
-}
-
-// latestVersionFile finds the path with the highest version
-// among paths on the form
-//
-// /some/path/major.minor.patch
-func latestVersionPath(paths []string) (string, bool) {
- var bestVer [3]int
- var bestDir string
-loop:
- for _, path := range paths {
- name := filepath.Base(path)
- s := strings.SplitN(name, ".", 3)
- var version [3]int
- for i, v := range s {
- v, err := strconv.Atoi(v)
- if err != nil {
- continue loop
- }
- if v < bestVer[i] {
- continue loop
- }
- if v > bestVer[i] {
- break
- }
- version[i] = v
- }
- bestVer = version
- bestDir = path
- }
- return bestDir, bestDir != ""
-}
-
-func newZipWriter(w io.Writer) *zipWriter {
- return &zipWriter{
- w: zip.NewWriter(w),
- }
-}
-
-func (z *zipWriter) Close() error {
- err := z.w.Close()
- if z.err == nil {
- z.err = err
- }
- return z.err
-}
-
-func (z *zipWriter) Create(name string) io.Writer {
- if z.err != nil {
- return ioutil.Discard
- }
- w, err := z.w.Create(name)
- if err != nil {
- z.err = err
- return ioutil.Discard
- }
- return &errWriter{w: w, err: &z.err}
-}
-
-func (z *zipWriter) Store(name, file string) {
- z.add(name, file, false)
-}
-
-func (z *zipWriter) Add(name, file string) {
- z.add(name, file, true)
-}
-
-func (z *zipWriter) add(name, file string, compressed bool) {
- if z.err != nil {
- return
- }
- f, err := os.Open(file)
- if err != nil {
- z.err = err
- return
- }
- defer f.Close()
- fh := &zip.FileHeader{
- Name: name,
- }
- if compressed {
- fh.Method = zip.Deflate
- }
- w, err := z.w.CreateHeader(fh)
- if err != nil {
- z.err = err
- return
- }
- if _, err := io.Copy(w, f); err != nil {
- z.err = err
- return
- }
-}
-
-func (w *errWriter) Write(p []byte) (n int, err error) {
- if err := *w.err; err != nil {
- return 0, err
- }
- n, err = w.w.Write(p)
- *w.err = err
- return
-}
diff --git a/cmd/gogio/build_info.go b/cmd/gogio/build_info.go
deleted file mode 100644
index 13818fa9..00000000
--- a/cmd/gogio/build_info.go
+++ /dev/null
@@ -1,156 +0,0 @@
-package main
-
-import (
- "flag"
- "fmt"
- "os"
- "os/exec"
- "path"
- "path/filepath"
- "runtime"
- "strings"
-)
-
-type buildInfo struct {
- appID string
- archs []string
- ldflags string
- minsdk int
- name string
- pkgDir string
- pkgPath string
- iconPath string
- tags string
- target string
- version int
- key string
- password string
-}
-
-func newBuildInfo(pkgPath string) (*buildInfo, error) {
- pkgMetadata, err := getPkgMetadata(pkgPath)
- if err != nil {
- return nil, err
- }
- appID := getAppID(pkgMetadata)
- appIcon := filepath.Join(pkgMetadata.Dir, "appicon.png")
- if *iconPath != "" {
- appIcon = *iconPath
- }
- bi := &buildInfo{
- appID: appID,
- archs: getArchs(),
- ldflags: getLdFlags(appID),
- minsdk: *minsdk,
- name: getPkgName(pkgMetadata),
- pkgDir: pkgMetadata.Dir,
- pkgPath: pkgPath,
- iconPath: appIcon,
- tags: *extraTags,
- target: *target,
- version: *version,
- key: *signKey,
- password: *signPass,
- }
- return bi, nil
-}
-
-func getArchs() []string {
- if *archNames != "" {
- return strings.Split(*archNames, ",")
- }
- switch *target {
- case "js":
- return []string{"wasm"}
- case "ios", "tvos":
- // Only 64-bit support.
- return []string{"arm64", "amd64"}
- case "android":
- return []string{"arm", "arm64", "386", "amd64"}
- case "windows":
- goarch := os.Getenv("GOARCH")
- if goarch == "" {
- goarch = runtime.GOARCH
- }
- return []string{goarch}
- default:
- // TODO: Add flag tests.
- panic("The target value has already been validated, this will never execute.")
- }
-}
-
-func getLdFlags(appID string) string {
- var ldflags []string
- if extra := *extraLdflags; extra != "" {
- ldflags = append(ldflags, strings.Split(extra, " ")...)
- }
- // Pass appID along, to be used for logging on platforms like Android.
- ldflags = append(ldflags, fmt.Sprintf("-X gioui.org/app/internal/log.appID=%s", appID))
- // Pass along all remaining arguments to the app.
- if appArgs := flag.Args()[1:]; len(appArgs) > 0 {
- ldflags = append(ldflags, fmt.Sprintf("-X gioui.org/app.extraArgs=%s", strings.Join(appArgs, "|")))
- }
- if m := *linkMode; m != "" {
- ldflags = append(ldflags, "-linkmode="+m)
- }
- return strings.Join(ldflags, " ")
-}
-
-type packageMetadata struct {
- PkgPath string
- Dir string
-}
-
-func getPkgMetadata(pkgPath string) (*packageMetadata, error) {
- pkgImportPath, err := runCmd(exec.Command("go", "list", "-f", "{{.ImportPath}}", pkgPath))
- if err != nil {
- return nil, err
- }
- pkgDir, err := runCmd(exec.Command("go", "list", "-f", "{{.Dir}}", pkgPath))
- if err != nil {
- return nil, err
- }
- return &packageMetadata{
- PkgPath: pkgImportPath,
- Dir: pkgDir,
- }, nil
-}
-
-func getAppID(pkgMetadata *packageMetadata) string {
- if *appID != "" {
- return *appID
- }
- elems := strings.Split(pkgMetadata.PkgPath, "/")
- domain := strings.Split(elems[0], ".")
- name := ""
- if len(elems) > 1 {
- name = "." + elems[len(elems)-1]
- }
- if len(elems) < 2 && len(domain) < 2 {
- name = "." + domain[0]
- domain[0] = "localhost"
- } else {
- for i := 0; i < len(domain)/2; i++ {
- opp := len(domain) - 1 - i
- domain[i], domain[opp] = domain[opp], domain[i]
- }
- }
-
- pkgDomain := strings.Join(domain, ".")
- appid := []rune(pkgDomain + name)
-
- // a Java-language-style package name may contain upper- and lower-case
- // letters and underscores with individual parts separated by '.'.
- // https://developer.android.com/guide/topics/manifest/manifest-element
- for i, c := range appid {
- if !('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' ||
- c == '_' || c == '.') {
- appid[i] = '_'
- }
- }
- return string(appid)
-}
-
-func getPkgName(pkgMetadata *packageMetadata) string {
- return path.Base(pkgMetadata.PkgPath)
-}
diff --git a/cmd/gogio/build_info_test.go b/cmd/gogio/build_info_test.go
deleted file mode 100644
index 397e2a3c..00000000
--- a/cmd/gogio/build_info_test.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package main
-
-import "testing"
-
-type expval struct {
- in, out string
-}
-
-func TestAppID(t *testing.T) {
- t.Parallel()
-
- tests := []expval{
- {"example", "localhost.example"},
- {"example.com", "com.example"},
- {"www.example.com", "com.example.www"},
- {"examplecom/app", "examplecom.app"},
- {"example.com/app", "com.example.app"},
- {"www.example.com/app", "com.example.www.app"},
- {"www.en.example.com/app", "com.example.en.www.app"},
- {"example.com/dir/app", "com.example.app"},
- {"example.com/dir.ext/app", "com.example.app"},
- {"example.com/dir/app.ext", "com.example.app.ext"},
- {"example-com.net/dir/app", "net.example_com.app"},
- }
-
- for i, test := range tests {
- got := getAppID(&packageMetadata{PkgPath: test.in})
- if exp := test.out; got != exp {
- t.Errorf("(%d): expected '%s', got '%s'", i, exp, got)
- }
- }
-}
diff --git a/cmd/gogio/doc.go b/cmd/gogio/doc.go
deleted file mode 100644
index 82da8129..00000000
--- a/cmd/gogio/doc.go
+++ /dev/null
@@ -1,10 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-/*
-The gogio tool builds and packages Gio programs for Android, iOS/tvOS
-and WebAssembly.
-
-Run gogio with no arguments for instructions, or see the examples at
-https://gioui.org.
-*/
-package main
diff --git a/cmd/gogio/e2e_test.go b/cmd/gogio/e2e_test.go
deleted file mode 100644
index 0b3ee97f..00000000
--- a/cmd/gogio/e2e_test.go
+++ /dev/null
@@ -1,331 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-package main_test
-
-import (
- "bufio"
- "errors"
- "flag"
- "fmt"
- "image"
- "image/color"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "strings"
- "testing"
- "time"
-)
-
-var raceEnabled = false
-
-var headless = flag.Bool("headless", true, "run end-to-end tests in headless mode")
-
-const appid = "localhost.gogio.endtoend"
-
-// TestDriver is implemented by each of the platforms we can run end-to-end
-// tests on. None of its methods return any errors, as the errors are directly
-// reported to testing.T via methods like Fatal.
-type TestDriver interface {
- initBase(t *testing.T, width, height int)
-
- // Start opens the Gio app found at path. The driver should attempt to
- // run the app with the base driver's width and height, and the
- // platform's background should be white.
- //
- // When the function returns, the gio app must be ready to use on the
- // platform, with its initial frame fully drawn.
- Start(path string)
-
- // Screenshot takes a screenshot of the Gio app on the platform.
- Screenshot() image.Image
-
- // Click performs a pointer click at the specified coordinates,
- // including both press and release. It returns when the next frame is
- // fully drawn.
- Click(x, y int)
-}
-
-type driverBase struct {
- *testing.T
-
- width, height int
-
- output io.Reader
- frameNotifs chan bool
-}
-
-func (d *driverBase) initBase(t *testing.T, width, height int) {
- d.T = t
- d.width, d.height = width, height
-}
-
-func TestEndToEnd(t *testing.T) {
- if testing.Short() {
- t.Skipf("end-to-end tests tend to be slow")
- }
-
- t.Parallel()
-
- const (
- testdataWithGoImportPkgPath = "gioui.org/cmd/gogio/testdata"
- testdataWithRelativePkgPath = "testdata/testdata.go"
- )
- // Keep this list local, to not reuse TestDriver objects.
- subtests := []struct {
- name string
- driver TestDriver
- pkgPath string
- }{
- {"X11 using go import path", &X11TestDriver{}, testdataWithGoImportPkgPath},
- {"X11", &X11TestDriver{}, testdataWithRelativePkgPath},
- // Doesn't work on the builders.
- //{"Wayland", &WaylandTestDriver{}, testdataWithRelativePkgPath},
- {"JS", &JSTestDriver{}, testdataWithRelativePkgPath},
- {"Android", &AndroidTestDriver{}, testdataWithRelativePkgPath},
- {"Windows", &WineTestDriver{}, testdataWithRelativePkgPath},
- }
-
- for _, subtest := range subtests {
- t.Run(subtest.name, func(t *testing.T) {
- subtest := subtest // copy the changing loop variable
- t.Parallel()
- runEndToEndTest(t, subtest.driver, subtest.pkgPath)
- })
- }
-}
-
-func runEndToEndTest(t *testing.T, driver TestDriver, pkgPath string) {
- size := image.Point{X: 800, Y: 600}
- driver.initBase(t, size.X, size.Y)
-
- t.Log("starting driver and gio app")
- driver.Start(pkgPath)
-
- beef := color.NRGBA{R: 0xde, G: 0xad, B: 0xbe, A: 0xff}
- white := color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}
- black := color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff}
- gray := color.NRGBA{R: 0xbb, G: 0xbb, B: 0xbb, A: 0xff}
- red := color.NRGBA{R: 0xff, G: 0x00, B: 0x00, A: 0xff}
-
- // These are the four colors at the beginning.
- t.Log("taking initial screenshot")
- withRetries(t, 4*time.Second, func() error {
- img := driver.Screenshot()
- size = img.Bounds().Size() // override the default size
- return checkImageCorners(img, beef, white, black, gray)
- })
-
- // TODO(mvdan): implement this properly in the Wayland driver; swaymsg
- // almost works to automate clicks, but the button presses end up in the
- // wrong coordinates.
- if _, ok := driver.(*WaylandTestDriver); ok {
- return
- }
-
- // Click the first and last sections to turn them red.
- t.Log("clicking twice and taking another screenshot")
- driver.Click(1*(size.X/4), 1*(size.Y/4))
- driver.Click(3*(size.X/4), 3*(size.Y/4))
- withRetries(t, 4*time.Second, func() error {
- img := driver.Screenshot()
- return checkImageCorners(img, red, white, black, red)
- })
-}
-
-// withRetries keeps retrying fn until it succeeds, or until the timeout is hit.
-// It uses a rudimentary kind of backoff, which starts with 100ms delays. As
-// such, timeout should generally be in the order of seconds.
-func withRetries(t *testing.T, timeout time.Duration, fn func() error) {
- t.Helper()
-
- timeoutTimer := time.NewTimer(timeout)
- defer timeoutTimer.Stop()
- backoff := 100 * time.Millisecond
-
- tries := 0
- var lastErr error
- for {
- if lastErr = fn(); lastErr == nil {
- return
- }
- tries++
- t.Logf("retrying after %s", backoff)
-
- // Use a timer instead of a sleep, so that the timeout can stop
- // the backoff early. Don't reuse this timer, since we're not in
- // a hot loop, and we don't want tricky code.
- backoffTimer := time.NewTimer(backoff)
- defer backoffTimer.Stop()
-
- select {
- case <-timeoutTimer.C:
- t.Errorf("last error: %v", lastErr)
- t.Fatalf("hit timeout of %s after %d tries", timeout, tries)
- case <-backoffTimer.C:
- }
-
- // Keep doubling it until a maximum. With the start at 100ms,
- // we'll do: 100ms, 200ms, 400ms, 800ms, 1.6s, and 2s forever.
- backoff *= 2
- if max := 2 * time.Second; backoff > max {
- backoff = max
- }
- }
-}
-
-type colorMismatch struct {
- x, y int
- wantRGB, gotRGB [3]uint32
-}
-
-func (m colorMismatch) String() string {
- return fmt.Sprintf("%3d,%-3d got 0x%04x%04x%04x, want 0x%04x%04x%04x",
- m.x, m.y,
- m.gotRGB[0], m.gotRGB[1], m.gotRGB[2],
- m.wantRGB[0], m.wantRGB[1], m.wantRGB[2],
- )
-}
-
-func checkImageCorners(img image.Image, topLeft, topRight, botLeft, botRight color.Color) error {
- // The colors are split in four rectangular sections. Check the corners
- // of each of the sections. We check the corners left to right, top to
- // bottom, like when reading left-to-right text.
-
- size := img.Bounds().Size()
- var mismatches []colorMismatch
-
- checkColor := func(x, y int, want color.Color) {
- r, g, b, _ := want.RGBA()
- got := img.At(x, y)
- r_, g_, b_, _ := got.RGBA()
- if r_ != r || g_ != g || b_ != b {
- mismatches = append(mismatches, colorMismatch{
- x: x,
- y: y,
- wantRGB: [3]uint32{r, g, b},
- gotRGB: [3]uint32{r_, g_, b_},
- })
- }
- }
-
- {
- minX, minY := 5, 5
- maxX, maxY := (size.X/2)-5, (size.Y/2)-5
- checkColor(minX, minY, topLeft)
- checkColor(maxX, minY, topLeft)
- checkColor(minX, maxY, topLeft)
- checkColor(maxX, maxY, topLeft)
- }
- {
- minX, minY := (size.X/2)+5, 5
- maxX, maxY := size.X-5, (size.Y/2)-5
- checkColor(minX, minY, topRight)
- checkColor(maxX, minY, topRight)
- checkColor(minX, maxY, topRight)
- checkColor(maxX, maxY, topRight)
- }
- {
- minX, minY := 5, (size.Y/2)+5
- maxX, maxY := (size.X/2)-5, size.Y-5
- checkColor(minX, minY, botLeft)
- checkColor(maxX, minY, botLeft)
- checkColor(minX, maxY, botLeft)
- checkColor(maxX, maxY, botLeft)
- }
- {
- minX, minY := (size.X/2)+5, (size.Y/2)+5
- maxX, maxY := size.X-5, size.Y-5
- checkColor(minX, minY, botRight)
- checkColor(maxX, minY, botRight)
- checkColor(minX, maxY, botRight)
- checkColor(maxX, maxY, botRight)
- }
- if n := len(mismatches); n > 0 {
- b := new(strings.Builder)
- fmt.Fprintf(b, "encountered %d color mismatches:\n", n)
- for _, m := range mismatches {
- fmt.Fprintf(b, "%s\n", m)
- }
- return errors.New(b.String())
- }
- return nil
-}
-
-func (d *driverBase) waitForFrame() {
- d.Helper()
-
- if d.frameNotifs == nil {
- // Start the goroutine that reads output lines and notifies of
- // new frames via frameNotifs. The test doesn't wait for this
- // goroutine to finish; it will naturally end when the output
- // reader reaches an error like EOF.
- d.frameNotifs = make(chan bool, 1)
- if d.output == nil {
- d.Fatal("need an output reader to be notified of frames")
- }
- go func() {
- scanner := bufio.NewScanner(d.output)
- for scanner.Scan() {
- line := scanner.Text()
- d.Log(line)
- if strings.Contains(line, "gio frame ready") {
- d.frameNotifs <- true
- }
- }
- // Since we're only interested in the output while the
- // app runs, and we don't know when it finishes here,
- // ignore "already closed" pipe errors.
- if err := scanner.Err(); err != nil && !errors.Is(err, os.ErrClosed) {
- d.Errorf("reading app output: %v", err)
- }
- }()
- }
-
- // Unfortunately, there isn't a way to select on a test failing, since
- // testing.T doesn't have anything like a context or a "done" channel.
- //
- // We can't let selects block forever, since the default -test.timeout
- // is ten minutes - far too long for tests that take seconds.
- //
- // For now, a static short timeout is better than nothing. 5s is plenty
- // for our simple test app to render on any device.
- select {
- case <-d.frameNotifs:
- case <-time.After(5 * time.Second):
- d.Fatalf("timed out waiting for a frame to be ready")
- }
-}
-
-func (d *driverBase) needPrograms(names ...string) {
- d.Helper()
- for _, name := range names {
- if _, err := exec.LookPath(name); err != nil {
- d.Skipf("%s needed to run", name)
- }
- }
-}
-
-func (d *driverBase) tempDir(name string) string {
- d.Helper()
- dir, err := ioutil.TempDir("", name)
- if err != nil {
- d.Fatal(err)
- }
- d.Cleanup(func() { os.RemoveAll(dir) })
- return dir
-}
-
-func (d *driverBase) gogio(args ...string) {
- d.Helper()
- prog, err := os.Executable()
- if err != nil {
- d.Fatal(err)
- }
- cmd := exec.Command(prog, args...)
- cmd.Env = append(os.Environ(), "RUN_GOGIO=1")
- if out, err := cmd.CombinedOutput(); err != nil {
- d.Fatalf("gogio error: %s:\n%s", err, out)
- }
-}
diff --git a/cmd/gogio/help.go b/cmd/gogio/help.go
deleted file mode 100644
index 87879aef..00000000
--- a/cmd/gogio/help.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-package main
-
-const mainUsage = `The gogio command builds and packages Gio (gioui.org) programs.
-
-Usage:
-
- gogio -target [flags] [run arguments]
-
-The gogio tool builds and packages Gio programs for platforms where additional
-metadata or support files are required.
-
-The package argument specifies an import path or a single Go source file to
-package. Any run arguments are appended to os.Args at runtime.
-
-Compiled Java class files from jar files in the package directory are
-included in Android builds.
-
-The mandatory -target flag selects the target platform: ios or android for the
-mobile platforms, tvos for Apple's tvOS, js for WebAssembly/WebGL.
-
-The -arch flag specifies a comma separated list of GOARCHs to include. The
-default is all supported architectures.
-
-The -o flag specifies an output file or directory, depending on the target.
-
-The -buildmode flag selects the build mode. Two build modes are available, exe
-and archive. Buildmode exe outputs an .ipa file for iOS or tvOS, an .apk file
-for Android or a directory with the WebAssembly module and support files for
-a browser.
-
-The -ldflags and -tags flags pass extra linker flags and tags to the go tool.
-
-As a special case for iOS or tvOS, specifying a path that ends with ".app"
-will output an app directory suitable for a simulator.
-
-The other buildmode is archive, which will output an .aar library for Android
-or a .framework for iOS and tvOS.
-
-The -icon flag specifies a path to a PNG image to use as app icon on iOS and Android.
-If left unspecified, the appicon.png file from the main package is used
-(if it exists).
-
-The -appid flag specifies the package name for Android or the bundle id for
-iOS and tvOS. A bundle id must be provisioned through Xcode before the gogio
-tool can use it.
-
-The -version flag specifies the integer version code for Android and the last
-component of the 1.0.X version for iOS and tvOS.
-
-For Android builds the -minsdk flag specify the minimum SDK level. For example,
-use -minsdk 22 to target Android 5.1 (Lollipop) and later.
-
-For Windows builds the -minsdk flag specify the minimum OS version. For example,
-use -mindk 10 to target Windows 10 and later, -minsdk 6 for Windows Vista and later.
-
-For iOS builds the -minsdk flag specify the minimum iOS version. For example,
-use -mindk 15 to target iOS 15.0 and later.
-
-The -work flag prints the path to the working directory and suppress
-its deletion.
-
-The -x flag will print all the external commands executed by the gogio tool.
-
-The -signkey flag specifies the path of the keystore, used for signing Android apk/aab files.
-
-The -signpass flag specifies the password of the keystore, ignored if -signkey is not provided.
-`
diff --git a/cmd/gogio/iosbuild.go b/cmd/gogio/iosbuild.go
deleted file mode 100644
index c3b596ad..00000000
--- a/cmd/gogio/iosbuild.go
+++ /dev/null
@@ -1,589 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-package main
-
-import (
- "archive/zip"
- "crypto/sha1"
- "encoding/hex"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "strconv"
- "strings"
- "time"
-
- "golang.org/x/sync/errgroup"
-)
-
-const (
- minIOSVersion = 10
- // Metal is available from iOS 8 on devices, yet from version 13 on the
- // simulator.
- minSimulatorVersion = 13
-)
-
-func buildIOS(tmpDir, target string, bi *buildInfo) error {
- appName := bi.name
- switch *buildMode {
- case "archive":
- framework := *destPath
- if framework == "" {
- framework = fmt.Sprintf("%s.framework", strings.Title(appName))
- }
- return archiveIOS(tmpDir, target, framework, bi)
- case "exe":
- out := *destPath
- if out == "" {
- out = appName + ".ipa"
- }
- forDevice := strings.HasSuffix(out, ".ipa")
- // Filter out unsupported architectures.
- for i := len(bi.archs) - 1; i >= 0; i-- {
- switch bi.archs[i] {
- case "arm", "arm64":
- if forDevice {
- continue
- }
- case "386", "amd64":
- if !forDevice {
- continue
- }
- }
-
- bi.archs = append(bi.archs[:i], bi.archs[i+1:]...)
- }
- tmpFramework := filepath.Join(tmpDir, "Gio.framework")
- if err := archiveIOS(tmpDir, target, tmpFramework, bi); err != nil {
- return err
- }
- if !forDevice && !strings.HasSuffix(out, ".app") {
- return fmt.Errorf("the specified output directory %q does not end in .app or .ipa", out)
- }
- if !forDevice {
- return exeIOS(tmpDir, target, out, bi)
- }
- payload := filepath.Join(tmpDir, "Payload")
- appDir := filepath.Join(payload, appName+".app")
- if err := os.MkdirAll(appDir, 0755); err != nil {
- return err
- }
- if err := exeIOS(tmpDir, target, appDir, bi); err != nil {
- return err
- }
- if err := signIOS(bi, tmpDir, appDir); err != nil {
- return err
- }
- return zipDir(out, tmpDir, "Payload")
- default:
- panic("unreachable")
- }
-}
-
-func signIOS(bi *buildInfo, tmpDir, app string) error {
- home, err := os.UserHomeDir()
- if err != nil {
- return err
- }
- provPattern := filepath.Join(home, "Library", "MobileDevice", "Provisioning Profiles", "*.mobileprovision")
- provisions, err := filepath.Glob(provPattern)
- if err != nil {
- return err
- }
- provInfo := filepath.Join(tmpDir, "provision.plist")
- var avail []string
- for _, prov := range provisions {
- // Decode the provision file to a plist.
- _, err := runCmd(exec.Command("security", "cms", "-D", "-i", prov, "-o", provInfo))
- if err != nil {
- return err
- }
- expUnix, err := runCmd(exec.Command("/usr/libexec/PlistBuddy", "-c", "Print:ExpirationDate", provInfo))
- if err != nil {
- return err
- }
- exp, err := time.Parse(time.UnixDate, expUnix)
- if err != nil {
- return fmt.Errorf("sign: failed to parse expiration date from %q: %v", prov, err)
- }
- if exp.Before(time.Now()) {
- continue
- }
- appIDPrefix, err := runCmd(exec.Command("/usr/libexec/PlistBuddy", "-c", "Print:ApplicationIdentifierPrefix:0", provInfo))
- if err != nil {
- return err
- }
- provAppID, err := runCmd(exec.Command("/usr/libexec/PlistBuddy", "-c", "Print:Entitlements:application-identifier", provInfo))
- if err != nil {
- return err
- }
- expAppID := fmt.Sprintf("%s.%s", appIDPrefix, bi.appID)
- avail = append(avail, provAppID)
- if expAppID != provAppID {
- continue
- }
- // Copy provisioning file.
- embedded := filepath.Join(app, "embedded.mobileprovision")
- if err := copyFile(embedded, prov); err != nil {
- return err
- }
- certDER, err := runCmdRaw(exec.Command("/usr/libexec/PlistBuddy", "-c", "Print:DeveloperCertificates:0", provInfo))
- if err != nil {
- return err
- }
- // Omit trailing newline.
- certDER = certDER[:len(certDER)-1]
- entitlements, err := runCmd(exec.Command("/usr/libexec/PlistBuddy", "-x", "-c", "Print:Entitlements", provInfo))
- if err != nil {
- return err
- }
- entFile := filepath.Join(tmpDir, "entitlements.plist")
- if err := ioutil.WriteFile(entFile, []byte(entitlements), 0660); err != nil {
- return err
- }
- identity := sha1.Sum(certDER)
- idHex := hex.EncodeToString(identity[:])
- _, err = runCmd(exec.Command("codesign", "-s", idHex, "-v", "--entitlements", entFile, app))
- return err
- }
- return fmt.Errorf("sign: no valid provisioning profile found for bundle id %q among %v", bi.appID, avail)
-}
-
-func exeIOS(tmpDir, target, app string, bi *buildInfo) error {
- if bi.appID == "" {
- return errors.New("app id is empty; use -appid to set it")
- }
- if err := os.RemoveAll(app); err != nil {
- return err
- }
- if err := os.Mkdir(app, 0755); err != nil {
- return err
- }
- mainm := filepath.Join(tmpDir, "main.m")
- const mainmSrc = `@import UIKit;
-@import Gio;
-
-@interface GioAppDelegate : UIResponder
-@property (strong, nonatomic) UIWindow *window;
-@end
-
-@implementation GioAppDelegate
-- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- GioViewController *controller = [[GioViewController alloc] initWithNibName:nil bundle:nil];
- self.window.rootViewController = controller;
- [self.window makeKeyAndVisible];
- return YES;
-}
-@end
-
-int main(int argc, char * argv[]) {
- @autoreleasepool {
- return UIApplicationMain(argc, argv, nil, NSStringFromClass([GioAppDelegate class]));
- }
-}`
- if err := ioutil.WriteFile(mainm, []byte(mainmSrc), 0660); err != nil {
- return err
- }
- appName := strings.Title(bi.name)
- exe := filepath.Join(app, appName)
- lipo := exec.Command("xcrun", "lipo", "-o", exe, "-create")
- var builds errgroup.Group
- for _, a := range bi.archs {
- clang, cflags, err := iosCompilerFor(target, a, bi.minsdk)
- if err != nil {
- return err
- }
- exeSlice := filepath.Join(tmpDir, "app-"+a)
- lipo.Args = append(lipo.Args, exeSlice)
- compile := exec.Command(clang, cflags...)
- compile.Args = append(compile.Args,
- "-Werror",
- "-fmodules",
- "-fobjc-arc",
- "-x", "objective-c",
- "-F", tmpDir,
- "-o", exeSlice,
- mainm,
- )
- builds.Go(func() error {
- _, err := runCmd(compile)
- return err
- })
- }
- if err := builds.Wait(); err != nil {
- return err
- }
- if _, err := runCmd(lipo); err != nil {
- return err
- }
- infoPlist := buildInfoPlist(bi)
- plistFile := filepath.Join(app, "Info.plist")
- if err := ioutil.WriteFile(plistFile, []byte(infoPlist), 0660); err != nil {
- return err
- }
- if _, err := os.Stat(bi.iconPath); err == nil {
- assetPlist, err := iosIcons(bi, tmpDir, app, bi.iconPath)
- if err != nil {
- return err
- }
- // Merge assets plist with Info.plist
- cmd := exec.Command(
- "/usr/libexec/PlistBuddy",
- "-c", "Merge "+assetPlist,
- plistFile,
- )
- if _, err := runCmd(cmd); err != nil {
- return err
- }
- }
- if _, err := runCmd(exec.Command("plutil", "-convert", "binary1", plistFile)); err != nil {
- return err
- }
- return nil
-}
-
-// iosIcons builds an asset catalog and compile it with the Xcode command actool.
-// iosIcons returns the asset plist file to be merged into Info.plist.
-func iosIcons(bi *buildInfo, tmpDir, appDir, icon string) (string, error) {
- assets := filepath.Join(tmpDir, "Assets.xcassets")
- if err := os.Mkdir(assets, 0700); err != nil {
- return "", err
- }
- appIcon := filepath.Join(assets, "AppIcon.appiconset")
- err := buildIcons(appIcon, icon, []iconVariant{
- {path: "ios_2x.png", size: 120},
- {path: "ios_3x.png", size: 180},
- // The App Store icon is not allowed to contain
- // transparent pixels.
- {path: "ios_store.png", size: 1024, fill: true},
- })
- if err != nil {
- return "", err
- }
- contentJson := `{
- "images" : [
- {
- "size" : "60x60",
- "idiom" : "iphone",
- "filename" : "ios_2x.png",
- "scale" : "2x"
- },
- {
- "size" : "60x60",
- "idiom" : "iphone",
- "filename" : "ios_3x.png",
- "scale" : "3x"
- },
- {
- "size" : "1024x1024",
- "idiom" : "ios-marketing",
- "filename" : "ios_store.png",
- "scale" : "1x"
- }
- ]
-}`
- contentFile := filepath.Join(appIcon, "Contents.json")
- if err := ioutil.WriteFile(contentFile, []byte(contentJson), 0600); err != nil {
- return "", err
- }
- assetPlist := filepath.Join(tmpDir, "assets.plist")
-
- minsdk := bi.minsdk
- if minsdk == 0 {
- minsdk = minIOSVersion
- }
- compile := exec.Command(
- "actool",
- "--compile", appDir,
- "--platform", iosPlatformFor(bi.target),
- "--minimum-deployment-target", strconv.Itoa(minsdk),
- "--app-icon", "AppIcon",
- "--output-partial-info-plist", assetPlist,
- assets)
- _, err = runCmd(compile)
- return assetPlist, err
-}
-
-func buildInfoPlist(bi *buildInfo) string {
- appName := strings.Title(bi.name)
- platform := iosPlatformFor(bi.target)
- var supportPlatform string
- switch bi.target {
- case "ios":
- supportPlatform = "iPhoneOS"
- case "tvos":
- supportPlatform = "AppleTVOS"
- }
- return fmt.Sprintf(`
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleExecutable
- %s
- CFBundleIdentifier
- %s
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- %s
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- 1.0.%d
- CFBundleVersion
- %d
- UILaunchStoryboardName
- LaunchScreen
- UIRequiredDeviceCapabilities
- arm64
- DTPlatformName
- %s
- DTPlatformVersion
- 12.4
- MinimumOSVersion
- %d
- UIDeviceFamily
-
- 1
- 2
-
- CFBundleSupportedPlatforms
-
- %s
-
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
- DTCompiler
- com.apple.compilers.llvm.clang.1_0
- DTPlatformBuild
- 16G73
- DTSDKBuild
- 16G73
- DTSDKName
- %s12.4
- DTXcode
- 1030
- DTXcodeBuild
- 10G8
-
-`, appName, bi.appID, appName, bi.version, bi.version, platform, minIOSVersion, supportPlatform, platform)
-}
-
-func iosPlatformFor(target string) string {
- switch target {
- case "ios":
- return "iphoneos"
- case "tvos":
- return "appletvos"
- default:
- panic("invalid platform " + target)
- }
-}
-
-func archiveIOS(tmpDir, target, frameworkRoot string, bi *buildInfo) error {
- framework := filepath.Base(frameworkRoot)
- const suf = ".framework"
- if !strings.HasSuffix(framework, suf) {
- return fmt.Errorf("the specified output %q does not end in '.framework'", frameworkRoot)
- }
- framework = framework[:len(framework)-len(suf)]
- if err := os.RemoveAll(frameworkRoot); err != nil {
- return err
- }
- frameworkDir := filepath.Join(frameworkRoot, "Versions", "A")
- for _, dir := range []string{"Headers", "Modules"} {
- p := filepath.Join(frameworkDir, dir)
- if err := os.MkdirAll(p, 0755); err != nil {
- return err
- }
- }
- symlinks := [][2]string{
- {"Versions/Current/Headers", "Headers"},
- {"Versions/Current/Modules", "Modules"},
- {"Versions/Current/" + framework, framework},
- {"A", filepath.Join("Versions", "Current")},
- }
- for _, l := range symlinks {
- if err := os.Symlink(l[0], filepath.Join(frameworkRoot, l[1])); err != nil && !os.IsExist(err) {
- return err
- }
- }
- exe := filepath.Join(frameworkDir, framework)
- lipo := exec.Command("xcrun", "lipo", "-o", exe, "-create")
- var builds errgroup.Group
- tags := bi.tags
- goos := "ios"
- supportsIOS, err := supportsGOOS("ios")
- if err != nil {
- return err
- }
- if !supportsIOS {
- // Go 1.15 and earlier target iOS with GOOS=darwin, tags=ios.
- goos = "darwin"
- tags = "ios " + tags
- }
- for _, a := range bi.archs {
- clang, cflags, err := iosCompilerFor(target, a, bi.minsdk)
- if err != nil {
- return err
- }
- lib := filepath.Join(tmpDir, "gio-"+a)
- cmd := exec.Command(
- "go",
- "build",
- "-ldflags=-s -w "+bi.ldflags,
- "-buildmode=c-archive",
- "-o", lib,
- "-tags", tags,
- bi.pkgPath,
- )
- lipo.Args = append(lipo.Args, lib)
- cflagsLine := strings.Join(cflags, " ")
- cmd.Env = append(
- os.Environ(),
- "GOOS="+goos,
- "GOARCH="+a,
- "CGO_ENABLED=1",
- "CC="+clang,
- "CGO_CFLAGS="+cflagsLine,
- "CGO_LDFLAGS="+cflagsLine,
- )
- builds.Go(func() error {
- _, err := runCmd(cmd)
- return err
- })
- }
- if err := builds.Wait(); err != nil {
- return err
- }
- if _, err := runCmd(lipo); err != nil {
- return err
- }
- appDir, err := runCmd(exec.Command("go", "list", "-f", "{{.Dir}}", "gioui.org/app/"))
- if err != nil {
- return err
- }
- headerDst := filepath.Join(frameworkDir, "Headers", framework+".h")
- headerSrc := filepath.Join(appDir, "framework_ios.h")
- if err := copyFile(headerDst, headerSrc); err != nil {
- return err
- }
- module := fmt.Sprintf(`framework module "%s" {
- header "%[1]s.h"
-
- export *
-}`, framework)
- moduleFile := filepath.Join(frameworkDir, "Modules", "module.modulemap")
- return ioutil.WriteFile(moduleFile, []byte(module), 0644)
-}
-
-func supportsGOOS(wantGoos string) (bool, error) {
- geese, err := runCmd(exec.Command("go", "tool", "dist", "list"))
- if err != nil {
- return false, err
- }
- for _, pair := range strings.Split(geese, "\n") {
- s := strings.SplitN(pair, "/", 2)
- if len(s) != 2 {
- return false, fmt.Errorf("go tool dist list: invalid GOOS/GOARCH pair: %s", pair)
- }
- goos := s[0]
- if goos == wantGoos {
- return true, nil
- }
- }
- return false, nil
-}
-
-func iosCompilerFor(target, arch string, minsdk int) (string, []string, error) {
- var (
- platformSDK string
- platformOS string
- )
- switch target {
- case "ios":
- platformOS = "ios"
- platformSDK = "iphone"
- case "tvos":
- platformOS = "tvos"
- platformSDK = "appletv"
- }
- switch arch {
- case "arm", "arm64":
- platformSDK += "os"
- if minsdk == 0 {
- minsdk = minIOSVersion
- }
- case "386", "amd64":
- platformOS += "-simulator"
- platformSDK += "simulator"
- if minsdk == 0 {
- minsdk = minSimulatorVersion
- }
- default:
- return "", nil, fmt.Errorf("unsupported -arch: %s", arch)
- }
- sdkPath, err := runCmd(exec.Command("xcrun", "--sdk", platformSDK, "--show-sdk-path"))
- if err != nil {
- return "", nil, err
- }
- clang, err := runCmd(exec.Command("xcrun", "--sdk", platformSDK, "--find", "clang"))
- if err != nil {
- return "", nil, err
- }
- cflags := []string{
- "-fembed-bitcode",
- "-arch", allArchs[arch].iosArch,
- "-isysroot", sdkPath,
- "-m" + platformOS + "-version-min=" + strconv.Itoa(minsdk),
- }
- return clang, cflags, nil
-}
-
-func zipDir(dst, base, dir string) (err error) {
- f, err := os.Create(dst)
- if err != nil {
- return err
- }
- defer func() {
- if cerr := f.Close(); err == nil {
- err = cerr
- }
- }()
- zipf := zip.NewWriter(f)
- err = filepath.Walk(filepath.Join(base, dir), func(path string, f os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if f.IsDir() {
- return nil
- }
- rel := filepath.ToSlash(path[len(base)+1:])
- entry, err := zipf.Create(rel)
- if err != nil {
- return err
- }
- src, err := os.Open(path)
- if err != nil {
- return err
- }
- defer src.Close()
- _, err = io.Copy(entry, src)
- return err
- })
- if err != nil {
- return err
- }
- return zipf.Close()
-}
diff --git a/cmd/gogio/js_test.go b/cmd/gogio/js_test.go
deleted file mode 100644
index 85848946..00000000
--- a/cmd/gogio/js_test.go
+++ /dev/null
@@ -1,123 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-package main_test
-
-import (
- "bytes"
- "context"
- "errors"
- "image"
- "image/png"
- "io"
- "net/http"
- "net/http/httptest"
- "os/exec"
-
- "github.com/chromedp/cdproto/runtime"
- "github.com/chromedp/chromedp"
-
- _ "gioui.org/unit" // the build tool adds it to go.mod, so keep it there
-)
-
-type JSTestDriver struct {
- driverBase
-
- // ctx is the chromedp context.
- ctx context.Context
-}
-
-func (d *JSTestDriver) Start(path string) {
- if raceEnabled {
- d.Skipf("js/wasm doesn't support -race; skipping")
- }
-
- // First, build the app.
- dir := d.tempDir("gio-endtoend-js")
- d.gogio("-target=js", "-o="+dir, path)
-
- // Second, start Chrome.
- opts := append(chromedp.DefaultExecAllocatorOptions[:],
- chromedp.Flag("headless", *headless),
- )
-
- actx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
- d.Cleanup(cancel)
-
- ctx, cancel := chromedp.NewContext(actx,
- // Send all logf/errf calls to t.Logf
- chromedp.WithLogf(d.Logf),
- )
- d.Cleanup(cancel)
- d.ctx = ctx
-
- if err := chromedp.Run(ctx); err != nil {
- if errors.Is(err, exec.ErrNotFound) {
- d.Skipf("test requires Chrome to be installed: %v", err)
- return
- }
- d.Fatal(err)
- }
- pr, pw := io.Pipe()
- d.Cleanup(func() { pw.Close() })
- d.output = pr
- chromedp.ListenTarget(ctx, func(ev interface{}) {
- switch ev := ev.(type) {
- case *runtime.EventConsoleAPICalled:
- switch ev.Type {
- case "log", "info", "warning", "error":
- var b bytes.Buffer
- b.WriteString("console.")
- b.WriteString(string(ev.Type))
- b.WriteString("(")
- for i, arg := range ev.Args {
- if i > 0 {
- b.WriteString(", ")
- }
- b.Write(arg.Value)
- }
- b.WriteString(")\n")
- pw.Write(b.Bytes())
- }
- }
- })
-
- // Third, serve the app folder, set the browser tab dimensions, and
- // navigate to the folder.
- ts := httptest.NewServer(http.FileServer(http.Dir(dir)))
- d.Cleanup(ts.Close)
-
- if err := chromedp.Run(ctx,
- chromedp.EmulateViewport(int64(d.width), int64(d.height)),
- chromedp.Navigate(ts.URL),
- ); err != nil {
- d.Fatal(err)
- }
-
- // Wait for the gio app to render.
- d.waitForFrame()
-}
-
-func (d *JSTestDriver) Screenshot() image.Image {
- var buf []byte
- if err := chromedp.Run(d.ctx,
- chromedp.CaptureScreenshot(&buf),
- ); err != nil {
- d.Fatal(err)
- }
- img, err := png.Decode(bytes.NewReader(buf))
- if err != nil {
- d.Fatal(err)
- }
- return img
-}
-
-func (d *JSTestDriver) Click(x, y int) {
- if err := chromedp.Run(d.ctx,
- chromedp.MouseClickXY(float64(x), float64(y)),
- ); err != nil {
- d.Fatal(err)
- }
-
- // Wait for the gio app to render after this click.
- d.waitForFrame()
-}
diff --git a/cmd/gogio/jsbuild.go b/cmd/gogio/jsbuild.go
deleted file mode 100644
index ba59a991..00000000
--- a/cmd/gogio/jsbuild.go
+++ /dev/null
@@ -1,201 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-package main
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
- "text/template"
-
- "golang.org/x/tools/go/packages"
-)
-
-func buildJS(bi *buildInfo) error {
- out := *destPath
- if out == "" {
- out = bi.name
- }
- if err := os.MkdirAll(out, 0700); err != nil {
- return err
- }
- cmd := exec.Command(
- "go",
- "build",
- "-ldflags="+bi.ldflags,
- "-tags="+bi.tags,
- "-o", filepath.Join(out, "main.wasm"),
- bi.pkgPath,
- )
- cmd.Env = append(
- os.Environ(),
- "GOOS=js",
- "GOARCH=wasm",
- )
- _, err := runCmd(cmd)
- if err != nil {
- return err
- }
-
- var faviconPath string
- if _, err := os.Stat(bi.iconPath); err == nil {
- // Copy icon to the output folder
- icon, err := ioutil.ReadFile(bi.iconPath)
- if err != nil {
- return err
- }
- if err := ioutil.WriteFile(filepath.Join(out, filepath.Base(bi.iconPath)), icon, 0600); err != nil {
- return err
- }
- faviconPath = filepath.Base(bi.iconPath)
- }
-
- indexTemplate, err := template.New("").Parse(jsIndex)
- if err != nil {
- return err
- }
-
- var b bytes.Buffer
- if err := indexTemplate.Execute(&b, struct {
- Name string
- Icon string
- }{
- Name: bi.name,
- Icon: faviconPath,
- }); err != nil {
- return err
- }
-
- if err := ioutil.WriteFile(filepath.Join(out, "index.html"), b.Bytes(), 0600); err != nil {
- return err
- }
-
- goroot, err := runCmd(exec.Command("go", "env", "GOROOT"))
- if err != nil {
- return err
- }
- wasmJS := filepath.Join(goroot, "misc", "wasm", "wasm_exec.js")
- if _, err := os.Stat(wasmJS); err != nil {
- return fmt.Errorf("failed to find $GOROOT/misc/wasm/wasm_exec.js driver: %v", err)
- }
- pkgs, err := packages.Load(&packages.Config{
- Mode: packages.NeedName | packages.NeedFiles | packages.NeedImports | packages.NeedDeps,
- Env: append(os.Environ(), "GOOS=js", "GOARCH=wasm"),
- }, bi.pkgPath)
- if err != nil {
- return err
- }
- extraJS, err := findPackagesJS(pkgs[0], make(map[string]bool))
- if err != nil {
- return err
- }
-
- return mergeJSFiles(filepath.Join(out, "wasm.js"), append([]string{wasmJS}, extraJS...)...)
-}
-
-func findPackagesJS(p *packages.Package, visited map[string]bool) (extraJS []string, err error) {
- if len(p.GoFiles) == 0 {
- return nil, nil
- }
- js, err := filepath.Glob(filepath.Join(filepath.Dir(p.GoFiles[0]), "*_js.js"))
- if err != nil {
- return nil, err
- }
- extraJS = append(extraJS, js...)
- for _, imp := range p.Imports {
- if !visited[imp.ID] {
- extra, err := findPackagesJS(imp, visited)
- if err != nil {
- return nil, err
- }
- extraJS = append(extraJS, extra...)
- visited[imp.ID] = true
- }
- }
- return extraJS, nil
-}
-
-// mergeJSFiles will merge all files into a single `wasm.js`. It will prepend the jsSetGo
-// and append the jsStartGo.
-func mergeJSFiles(dst string, files ...string) (err error) {
- w, err := os.Create(dst)
- if err != nil {
- return err
- }
- defer func() {
- if cerr := w.Close(); err != nil {
- err = cerr
- }
- }()
- _, err = io.Copy(w, strings.NewReader(jsSetGo))
- if err != nil {
- return err
- }
- for i := range files {
- r, err := os.Open(files[i])
- if err != nil {
- return err
- }
- _, err = io.Copy(w, r)
- r.Close()
- if err != nil {
- return err
- }
- }
- _, err = io.Copy(w, strings.NewReader(jsStartGo))
- return err
-}
-
-const (
- jsIndex = `
-
-
-
-
-
- {{ if .Icon }}{{ end }}
- {{ if .Name }}{{.Name}}{{ end }}
-
-
-
-
-
-`
- // jsSetGo sets the `window.go` variable.
- jsSetGo = `(() => {
- window.go = {argv: [], env: {}, importObject: {go: {}}};
- const argv = new URLSearchParams(location.search).get("argv");
- if (argv) {
- window.go["argv"] = argv.split(" ");
- }
-})();`
- // jsStartGo initializes the main.wasm.
- jsStartGo = `(() => {
- defaultGo = new Go();
- Object.assign(defaultGo["argv"], defaultGo["argv"].concat(go["argv"]));
- Object.assign(defaultGo["env"], go["env"]);
- for (let key in go["importObject"]) {
- if (typeof defaultGo["importObject"][key] === "undefined") {
- defaultGo["importObject"][key] = {};
- }
- Object.assign(defaultGo["importObject"][key], go["importObject"][key]);
- }
- window.go = defaultGo;
- if (!WebAssembly.instantiateStreaming) { // polyfill
- WebAssembly.instantiateStreaming = async (resp, importObject) => {
- const source = await (await resp).arrayBuffer();
- return await WebAssembly.instantiate(source, importObject);
- };
- }
- WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
- go.run(result.instance);
- });
-})();`
-)
diff --git a/cmd/gogio/main.go b/cmd/gogio/main.go
deleted file mode 100644
index 38018f76..00000000
--- a/cmd/gogio/main.go
+++ /dev/null
@@ -1,224 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-package main
-
-import (
- "bytes"
- "errors"
- "flag"
- "fmt"
- "image"
- "image/color"
- "image/png"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-
- "golang.org/x/image/draw"
- "golang.org/x/sync/errgroup"
-)
-
-var (
- target = flag.String("target", "", "specify target (ios, tvos, android, js).\n")
- archNames = flag.String("arch", "", "specify architecture(s) to include (arm, arm64, amd64).")
- minsdk = flag.Int("minsdk", 0, "specify the minimum supported operating system level")
- buildMode = flag.String("buildmode", "exe", "specify buildmode (archive, exe)")
- destPath = flag.String("o", "", "output file or directory.\nFor -target ios or tvos, use the .app suffix to target simulators.")
- appID = flag.String("appid", "", "app identifier (for -buildmode=exe)")
- version = flag.Int("version", 1, "app version (for -buildmode=exe)")
- printCommands = flag.Bool("x", false, "print the commands")
- keepWorkdir = flag.Bool("work", false, "print the name of the temporary work directory and do not delete it when exiting.")
- linkMode = flag.String("linkmode", "", "set the -linkmode flag of the go tool")
- extraLdflags = flag.String("ldflags", "", "extra flags to the Go linker")
- extraTags = flag.String("tags", "", "extra tags to the Go tool")
- iconPath = flag.String("icon", "", "specify an icon for iOS and Android")
- signKey = flag.String("signkey", "", "specify the path of the keystore to be used to sign Android apk files.")
- signPass = flag.String("signpass", "", "specify the password to decrypt the signkey.")
-)
-
-func main() {
- flag.Usage = func() {
- fmt.Fprint(os.Stderr, mainUsage)
- }
- flag.Parse()
- if err := flagValidate(); err != nil {
- fmt.Fprintf(os.Stderr, "gogio: %v\n", err)
- os.Exit(1)
- }
- buildInfo, err := newBuildInfo(flag.Arg(0))
- if err != nil {
- fmt.Fprintf(os.Stderr, "gogio: %v\n", err)
- os.Exit(1)
- }
- if err := build(buildInfo); err != nil {
- fmt.Fprintf(os.Stderr, "gogio: %v\n", err)
- os.Exit(1)
- }
- os.Exit(0)
-}
-
-func flagValidate() error {
- pkgPathArg := flag.Arg(0)
- if pkgPathArg == "" {
- return errors.New("specify a package")
- }
- if *target == "" {
- return errors.New("please specify -target")
- }
- switch *target {
- case "ios", "tvos", "android", "js", "windows":
- default:
- return fmt.Errorf("invalid -target %s", *target)
- }
- switch *buildMode {
- case "archive", "exe":
- default:
- return fmt.Errorf("invalid -buildmode %s", *buildMode)
- }
- return nil
-}
-
-func build(bi *buildInfo) error {
- tmpDir, err := ioutil.TempDir("", "gogio-")
- if err != nil {
- return err
- }
- if *keepWorkdir {
- fmt.Fprintf(os.Stderr, "WORKDIR=%s\n", tmpDir)
- } else {
- defer os.RemoveAll(tmpDir)
- }
- switch *target {
- case "js":
- return buildJS(bi)
- case "ios", "tvos":
- return buildIOS(tmpDir, *target, bi)
- case "android":
- return buildAndroid(tmpDir, bi)
- case "windows":
- return buildWindows(tmpDir, bi)
- default:
- panic("unreachable")
- }
-}
-
-func runCmdRaw(cmd *exec.Cmd) ([]byte, error) {
- if *printCommands {
- fmt.Printf("%s\n", strings.Join(cmd.Args, " "))
- }
- out, err := cmd.Output()
- if err == nil {
- return out, nil
- }
- if err, ok := err.(*exec.ExitError); ok {
- return nil, fmt.Errorf("%s failed: %s%s", strings.Join(cmd.Args, " "), out, err.Stderr)
- }
- return nil, err
-}
-
-func runCmd(cmd *exec.Cmd) (string, error) {
- out, err := runCmdRaw(cmd)
- return string(bytes.TrimSpace(out)), err
-}
-
-func copyFile(dst, src string) (err error) {
- r, err := os.Open(src)
- if err != nil {
- return err
- }
- defer r.Close()
- w, err := os.Create(dst)
- if err != nil {
- return err
- }
- defer func() {
- if cerr := w.Close(); err == nil {
- err = cerr
- }
- }()
- _, err = io.Copy(w, r)
- return err
-}
-
-type arch struct {
- iosArch string
- jniArch string
- clangArch string
-}
-
-var allArchs = map[string]arch{
- "arm": {
- iosArch: "armv7",
- jniArch: "armeabi-v7a",
- clangArch: "armv7a-linux-androideabi",
- },
- "arm64": {
- iosArch: "arm64",
- jniArch: "arm64-v8a",
- clangArch: "aarch64-linux-android",
- },
- "386": {
- iosArch: "i386",
- jniArch: "x86",
- clangArch: "i686-linux-android",
- },
- "amd64": {
- iosArch: "x86_64",
- jniArch: "x86_64",
- clangArch: "x86_64-linux-android",
- },
-}
-
-type iconVariant struct {
- path string
- size int
- fill bool
-}
-
-func buildIcons(baseDir, icon string, variants []iconVariant) error {
- f, err := os.Open(icon)
- if err != nil {
- return err
- }
- defer f.Close()
- img, _, err := image.Decode(f)
- if err != nil {
- return err
- }
- var resizes errgroup.Group
- for _, v := range variants {
- v := v
- resizes.Go(func() (err error) {
- path := filepath.Join(baseDir, v.path)
- if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
- return err
- }
- f, err := os.Create(path)
- if err != nil {
- return err
- }
- defer func() {
- if cerr := f.Close(); err == nil {
- err = cerr
- }
- }()
- return png.Encode(f, resizeIcon(v, img))
- })
- }
- return resizes.Wait()
-}
-
-func resizeIcon(v iconVariant, img image.Image) *image.NRGBA {
- scaled := image.NewNRGBA(image.Rectangle{Max: image.Point{X: v.size, Y: v.size}})
- op := draw.Src
- if v.fill {
- op = draw.Over
- draw.Draw(scaled, scaled.Bounds(), &image.Uniform{color.White}, image.Point{}, draw.Src)
- }
- draw.CatmullRom.Scale(scaled, scaled.Bounds(), img, img.Bounds(), op, nil)
-
- return scaled
-}
diff --git a/cmd/gogio/main_test.go b/cmd/gogio/main_test.go
deleted file mode 100644
index 98dcb273..00000000
--- a/cmd/gogio/main_test.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package main
-
-import (
- "os"
- "testing"
-)
-
-func TestMain(m *testing.M) {
- if os.Getenv("RUN_GOGIO") != "" {
- // Allow the end-to-end tests to call the gogio tool without
- // having to build it from scratch, nor having to refactor the
- // main function to avoid using global variables.
- main()
- os.Exit(0) // main already exits, but just in case.
- }
- os.Exit(m.Run())
-}
diff --git a/cmd/gogio/permission.go b/cmd/gogio/permission.go
deleted file mode 100644
index b22fcef2..00000000
--- a/cmd/gogio/permission.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package main
-
-var AndroidPermissions = map[string][]string{
- "network": {
- "android.permission.INTERNET",
- },
- "networkstate": {
- "android.permission.ACCESS_NETWORK_STATE",
- },
- "bluetooth": {
- "android.permission.BLUETOOTH",
- "android.permission.BLUETOOTH_ADMIN",
- "android.permission.ACCESS_FINE_LOCATION",
- },
- "camera": {
- "android.permission.CAMERA",
- },
- "storage": {
- "android.permission.READ_EXTERNAL_STORAGE",
- "android.permission.WRITE_EXTERNAL_STORAGE",
- },
-}
-
-var AndroidFeatures = map[string][]string{
- "default": {`glEsVersion="0x00020000"`, `name="android.hardware.type.pc"`},
- "bluetooth": {
- `name="android.hardware.bluetooth"`,
- `name="android.hardware.bluetooth_le"`,
- },
- "camera": {
- `name="android.hardware.camera"`,
- },
-}
diff --git a/cmd/gogio/race_test.go b/cmd/gogio/race_test.go
deleted file mode 100644
index 1f3c689a..00000000
--- a/cmd/gogio/race_test.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-//go:build race
-// +build race
-
-package main_test
-
-func init() { raceEnabled = true }
diff --git a/cmd/gogio/testdata/testdata.go b/cmd/gogio/testdata/testdata.go
deleted file mode 100644
index dca562ef..00000000
--- a/cmd/gogio/testdata/testdata.go
+++ /dev/null
@@ -1,142 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-// A simple app used for gogio's end-to-end tests.
-package main
-
-import (
- "fmt"
- "image"
- "image/color"
- "log"
-
- "gioui.org/app"
- "gioui.org/io/pointer"
- "gioui.org/io/system"
- "gioui.org/layout"
- "gioui.org/op"
- "gioui.org/op/clip"
- "gioui.org/op/paint"
-)
-
-func main() {
- go func() {
- w := app.NewWindow()
- if err := loop(w); err != nil {
- log.Fatal(err)
- }
- }()
- app.Main()
-}
-
-type notifyFrame int
-
-const (
- notifyNone notifyFrame = iota
- notifyInvalidate
- notifyPrint
-)
-
-// notify keeps track of whether we want to print to stdout to notify the user
-// when a frame is ready. Initially we want to notify about the first frame.
-var notify = notifyInvalidate
-
-type (
- C = layout.Context
- D = layout.Dimensions
-)
-
-func loop(w *app.Window) error {
- topLeft := quarterWidget{
- color: color.NRGBA{R: 0xde, G: 0xad, B: 0xbe, A: 0xff},
- }
- topRight := quarterWidget{
- color: color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
- }
- botLeft := quarterWidget{
- color: color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
- }
- botRight := quarterWidget{
- color: color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0x80},
- }
-
- var ops op.Ops
- for {
- e := <-w.Events()
- switch e := e.(type) {
- case system.DestroyEvent:
- return e.Err
- case system.FrameEvent:
- gtx := layout.NewContext(&ops, e)
- // Clear background to white, even on embedded platforms such as webassembly.
- paint.Fill(gtx.Ops, color.NRGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff})
- layout.Flex{Axis: layout.Vertical}.Layout(gtx,
- layout.Flexed(1, func(gtx C) D {
- return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
- // r1c1
- layout.Flexed(1, func(gtx C) D { return topLeft.Layout(gtx) }),
- // r1c2
- layout.Flexed(1, func(gtx C) D { return topRight.Layout(gtx) }),
- )
- }),
- layout.Flexed(1, func(gtx C) D {
- return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
- // r2c1
- layout.Flexed(1, func(gtx C) D { return botLeft.Layout(gtx) }),
- // r2c2
- layout.Flexed(1, func(gtx C) D { return botRight.Layout(gtx) }),
- )
- }),
- )
-
- e.Frame(gtx.Ops)
-
- switch notify {
- case notifyInvalidate:
- notify = notifyPrint
- w.Invalidate()
- case notifyPrint:
- notify = notifyNone
- fmt.Println("gio frame ready")
- }
- }
- }
-}
-
-// quarterWidget paints a quarter of the screen with one color. When clicked, it
-// turns red, going back to its normal color when clicked again.
-type quarterWidget struct {
- color color.NRGBA
-
- clicked bool
-}
-
-var red = color.NRGBA{R: 0xff, G: 0x00, B: 0x00, A: 0xff}
-
-func (w *quarterWidget) Layout(gtx layout.Context) layout.Dimensions {
- var color color.NRGBA
- if w.clicked {
- color = red
- } else {
- color = w.color
- }
-
- r := image.Rectangle{Max: gtx.Constraints.Max}
- paint.FillShape(gtx.Ops, color, clip.Rect(r).Op())
-
- defer clip.Rect(image.Rectangle{
- Max: image.Pt(gtx.Constraints.Max.X, gtx.Constraints.Max.Y),
- }).Push(gtx.Ops).Pop()
- pointer.InputOp{
- Tag: w,
- Types: pointer.Press,
- }.Add(gtx.Ops)
-
- for _, e := range gtx.Events(w) {
- if e, ok := e.(pointer.Event); ok && e.Type == pointer.Press {
- w.clicked = !w.clicked
- // notify when we're done updating the frame.
- notify = notifyInvalidate
- }
- }
- return layout.Dimensions{Size: gtx.Constraints.Max}
-}
diff --git a/cmd/gogio/wayland_test.go b/cmd/gogio/wayland_test.go
deleted file mode 100644
index df10410a..00000000
--- a/cmd/gogio/wayland_test.go
+++ /dev/null
@@ -1,196 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-package main_test
-
-import (
- "bufio"
- "bytes"
- "context"
- "fmt"
- "image"
- "image/png"
- "os"
- "os/exec"
- "path/filepath"
- "regexp"
- "strings"
- "sync"
- "text/template"
- "time"
-)
-
-type WaylandTestDriver struct {
- driverBase
-
- runtimeDir string
- socket string
- display string
-}
-
-// No bars or anything fancy. Just a white background with our dimensions.
-var tmplSwayConfig = template.Must(template.New("").Parse(`
-output * bg #FFFFFF solid_color
-output * mode {{.Width}}x{{.Height}}
-default_border none
-`))
-
-var rxSwayReady = regexp.MustCompile(`Running compositor on wayland display '(.*)'`)
-
-func (d *WaylandTestDriver) Start(path string) {
- // We want os.Environ, so that it can e.g. find $DISPLAY to run within
- // X11. wlroots env vars are documented at:
- // https://github.com/swaywm/wlroots/blob/master/docs/env_vars.md
- env := os.Environ()
- if *headless {
- env = append(env, "WLR_BACKENDS=headless")
- }
-
- d.needPrograms(
- "sway", // to run a wayland compositor
- "grim", // to take screenshots
- "swaymsg", // to send input
- )
-
- // First, build the app.
- dir := d.tempDir("gio-endtoend-wayland")
- bin := filepath.Join(dir, "red")
- flags := []string{"build", "-tags", "nox11", "-o=" + bin}
- if raceEnabled {
- flags = append(flags, "-race")
- }
- flags = append(flags, path)
- cmd := exec.Command("go", flags...)
- if out, err := cmd.CombinedOutput(); err != nil {
- d.Fatalf("could not build app: %s:\n%s", err, out)
- }
-
- conf := filepath.Join(dir, "config")
- f, err := os.Create(conf)
- if err != nil {
- d.Fatal(err)
- }
- defer f.Close()
- if err := tmplSwayConfig.Execute(f, struct{ Width, Height int }{
- d.width, d.height,
- }); err != nil {
- d.Fatal(err)
- }
-
- d.socket = filepath.Join(dir, "socket")
- env = append(env, "SWAYSOCK="+d.socket)
- d.runtimeDir = dir
- env = append(env, "XDG_RUNTIME_DIR="+d.runtimeDir)
-
- var wg sync.WaitGroup
- d.Cleanup(wg.Wait)
-
- // First, start sway.
- {
- ctx, cancel := context.WithCancel(context.Background())
- cmd := exec.CommandContext(ctx, "sway", "--config", conf, "--verbose")
- cmd.Env = env
- stderr, err := cmd.StderrPipe()
- if err != nil {
- d.Fatal(err)
- }
- if err := cmd.Start(); err != nil {
- d.Fatal(err)
- }
- d.Cleanup(cancel)
- d.Cleanup(func() {
- // Give it a chance to exit gracefully, cleaning up
- // after itself. After 10ms, the deferred cancel above
- // will signal an os.Kill.
- cmd.Process.Signal(os.Interrupt)
- time.Sleep(10 * time.Millisecond)
- })
-
- // Wait for sway to be ready. We probably don't need a deadline
- // here.
- br := bufio.NewReader(stderr)
- for {
- line, err := br.ReadString('\n')
- if err != nil {
- d.Fatal(err)
- }
- if m := rxSwayReady.FindStringSubmatch(line); m != nil {
- d.display = m[1]
- break
- }
- }
-
- wg.Add(1)
- go func() {
- if err := cmd.Wait(); err != nil && ctx.Err() == nil && !strings.Contains(err.Error(), "interrupt") {
- // Don't print all stderr, since we use --verbose.
- // TODO(mvdan): if it's useful, probably filter
- // errors and show them.
- d.Error(err)
- }
- wg.Done()
- }()
- }
-
- // Then, start our program on the sway compositor above.
- {
- ctx, cancel := context.WithCancel(context.Background())
- cmd := exec.CommandContext(ctx, bin)
- cmd.Env = []string{"XDG_RUNTIME_DIR=" + d.runtimeDir, "WAYLAND_DISPLAY=" + d.display}
- output, err := cmd.StdoutPipe()
- if err != nil {
- d.Fatal(err)
- }
- cmd.Stderr = cmd.Stdout
- d.output = output
- if err := cmd.Start(); err != nil {
- d.Fatal(err)
- }
- d.Cleanup(cancel)
- wg.Add(1)
- go func() {
- if err := cmd.Wait(); err != nil && ctx.Err() == nil {
- d.Error(err)
- }
- wg.Done()
- }()
- }
-
- // Wait for the gio app to render.
- d.waitForFrame()
-}
-
-func (d *WaylandTestDriver) Screenshot() image.Image {
- cmd := exec.Command("grim", "/dev/stdout")
- cmd.Env = []string{"XDG_RUNTIME_DIR=" + d.runtimeDir, "WAYLAND_DISPLAY=" + d.display}
- out, err := cmd.CombinedOutput()
- if err != nil {
- d.Errorf("%s", out)
- d.Fatal(err)
- }
- img, err := png.Decode(bytes.NewReader(out))
- if err != nil {
- d.Fatal(err)
- }
- return img
-}
-
-func (d *WaylandTestDriver) swaymsg(args ...interface{}) {
- strs := []string{"--socket", d.socket}
- for _, arg := range args {
- strs = append(strs, fmt.Sprint(arg))
- }
- cmd := exec.Command("swaymsg", strs...)
- if out, err := cmd.CombinedOutput(); err != nil {
- d.Errorf("%s", out)
- d.Fatal(err)
- }
-}
-
-func (d *WaylandTestDriver) Click(x, y int) {
- d.swaymsg("seat", "-", "cursor", "set", x, y)
- d.swaymsg("seat", "-", "cursor", "press", "button1")
- d.swaymsg("seat", "-", "cursor", "release", "button1")
-
- // Wait for the gio app to render after this click.
- d.waitForFrame()
-}
diff --git a/cmd/gogio/windows_test.go b/cmd/gogio/windows_test.go
deleted file mode 100644
index 996b5114..00000000
--- a/cmd/gogio/windows_test.go
+++ /dev/null
@@ -1,152 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-package main_test
-
-import (
- "context"
- "image"
- "io"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "sync"
- "time"
-
- "golang.org/x/image/draw"
-)
-
-// Wine is tightly coupled with X11 at the moment, and we can reuse the same
-// methods to automate screenshots and clicks. The main difference is how we
-// build and run the app.
-
-// The only quirk is that it seems impossible for the Wine window to take the
-// entirety of the X server's dimensions, even if we try to resize it to take
-// the entire display. It seems to want to leave some vertical space empty,
-// presumably for window decorations or the "start" bar on Windows. To work
-// around that, make the X server 50x50px bigger, and crop the screenshots back
-// to the original size.
-
-type WineTestDriver struct {
- X11TestDriver
-}
-
-func (d *WineTestDriver) Start(path string) {
- d.needPrograms("wine")
-
- // First, build the app.
- bin := filepath.Join(d.tempDir("gio-endtoend-windows"), "red.exe")
- flags := []string{"build", "-o=" + bin}
- if raceEnabled {
- if runtime.GOOS != "windows" {
- // cross-compilation disables CGo, which breaks -race.
- d.Skipf("can't cross-compile -race for Windows; skipping")
- }
- flags = append(flags, "-race")
- }
- flags = append(flags, path)
- cmd := exec.Command("go", flags...)
- cmd.Env = os.Environ()
- cmd.Env = append(cmd.Env, "GOOS=windows")
- if out, err := cmd.CombinedOutput(); err != nil {
- d.Fatalf("could not build app: %s:\n%s", err, out)
- }
-
- var wg sync.WaitGroup
- d.Cleanup(wg.Wait)
-
- // Add 50x50px to the display dimensions, as discussed earlier.
- d.startServer(&wg, d.width+50, d.height+50)
-
- // Then, start our program via Wine on the X server above.
- {
- cacheDir, err := os.UserCacheDir()
- if err != nil {
- d.Fatal(err)
- }
- // Use a wine directory separate from the default ~/.wine, so
- // that the user's winecfg doesn't affect our test. This will
- // default to ~/.cache/gio-e2e-wine. We use the user's cache,
- // to reuse a previously set up wineprefix.
- wineprefix := filepath.Join(cacheDir, "gio-e2e-wine")
-
- // First, ensure that wineprefix is up to date with wineboot.
- // Wait for this separately from the first frame, as setting up
- // a new prefix might take 5s on its own.
- env := []string{
- "DISPLAY=" + d.display,
- "WINEDEBUG=fixme-all", // hide "fixme" noise
- "WINEPREFIX=" + wineprefix,
-
- // Disable wine-gecko (Explorer) and wine-mono (.NET).
- // Otherwise, if not installed, wineboot will get stuck
- // with a prompt to install them on the virtual X
- // display. Moreover, Gio doesn't need either, and wine
- // is faster without them.
- "WINEDLLOVERRIDES=mscoree,mshtml=",
- }
- {
- start := time.Now()
- cmd := exec.Command("wine", "wineboot", "-i")
- cmd.Env = env
- // Use a combined output pipe instead of CombinedOutput,
- // so that we only wait for the child process to exit,
- // and we don't need to wait for all of wine's
- // grandchildren to exit and stop writing. This is
- // relevant as wine leaves "wineserver" lingering for
- // three seconds by default, to be reused later.
- stdout, err := cmd.StdoutPipe()
- if err != nil {
- d.Fatal(err)
- }
- cmd.Stderr = cmd.Stdout
- if err := cmd.Run(); err != nil {
- io.Copy(os.Stderr, stdout)
- d.Fatal(err)
- }
- d.Logf("set up WINEPREFIX in %s", time.Since(start))
- }
-
- ctx, cancel := context.WithCancel(context.Background())
- cmd := exec.CommandContext(ctx, "wine", bin)
- cmd.Env = env
- output, err := cmd.StdoutPipe()
- if err != nil {
- d.Fatal(err)
- }
- cmd.Stderr = cmd.Stdout
- d.output = output
- if err := cmd.Start(); err != nil {
- d.Fatal(err)
- }
- d.Cleanup(cancel)
- wg.Add(1)
- go func() {
- if err := cmd.Wait(); err != nil && ctx.Err() == nil {
- d.Error(err)
- }
- wg.Done()
- }()
- }
- // Wait for the gio app to render.
- d.waitForFrame()
-
- // xdotool seems to fail at actually moving the window if we use it
- // immediately after Gio is ready. Why?
- // We can't tell if the windowmove operation worked until we take a
- // screenshot, because the getwindowgeometry op reports the 0x0
- // coordinates even if the window wasn't moved properly.
- // A sleep of ~20ms seems to be enough on an idle laptop. Use 20x that.
- // TODO(mvdan): revisit this, when you have a spare three hours.
- time.Sleep(400 * time.Millisecond)
- id := d.xdotool("search", "--sync", "--onlyvisible", "--name", "Gio")
- d.xdotool("windowmove", "--sync", id, 0, 0)
-}
-
-func (d *WineTestDriver) Screenshot() image.Image {
- img := d.X11TestDriver.Screenshot()
- // Crop the screenshot back to the original dimensions.
- cropped := image.NewRGBA(image.Rect(0, 0, d.width, d.height))
- draw.Draw(cropped, cropped.Bounds(), img, image.Point{}, draw.Src)
- return cropped
-}
diff --git a/cmd/gogio/windowsbuild.go b/cmd/gogio/windowsbuild.go
deleted file mode 100644
index 23cdd517..00000000
--- a/cmd/gogio/windowsbuild.go
+++ /dev/null
@@ -1,416 +0,0 @@
-package main
-
-import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "image/png"
- "io"
- "math"
- "os"
- "os/exec"
- "path/filepath"
- "reflect"
- "strconv"
- "strings"
- "text/template"
-
- "github.com/akavel/rsrc/binutil"
- "github.com/akavel/rsrc/coff"
- "golang.org/x/text/encoding/unicode"
-)
-
-func buildWindows(tmpDir string, bi *buildInfo) error {
- builder := &windowsBuilder{TempDir: tmpDir}
- builder.DestDir = *destPath
- if builder.DestDir == "" {
- builder.DestDir = bi.pkgPath
- }
-
- name := bi.name
- if *destPath != "" {
- if filepath.Ext(*destPath) != ".exe" {
- return fmt.Errorf("invalid output name %q, it must end with `.exe`", *destPath)
- }
- name = filepath.Base(*destPath)
- }
- name = strings.TrimSuffix(name, ".exe")
- sdk := bi.minsdk
- if sdk > 10 {
- return fmt.Errorf("invalid minsdk (%d) it's higher than Windows 10", sdk)
- }
- version := strconv.Itoa(bi.version)
- if bi.version > math.MaxUint16 {
- return fmt.Errorf("version (%d) is larger than the maximum (%d)", bi.version, math.MaxUint16)
- }
-
- for _, arch := range bi.archs {
- builder.Coff = coff.NewRSRC()
- builder.Coff.Arch(arch)
-
- if err := builder.embedIcon(bi.iconPath); err != nil {
- return err
- }
-
- if err := builder.embedManifest(windowsManifest{
- Version: "1.0.0." + version,
- WindowsVersion: sdk,
- Name: name,
- }); err != nil {
- return fmt.Errorf("can't create manifest: %v", err)
- }
-
- if err := builder.embedInfo(windowsResources{
- Version: [2]uint32{uint32(1) << 16, uint32(bi.version)},
- VersionHuman: "1.0.0." + version,
- Name: name,
- Language: 0x0400, // Process Default Language: https://docs.microsoft.com/en-us/previous-versions/ms957130(v=msdn.10)
- }); err != nil {
- return fmt.Errorf("can't create info: %v", err)
- }
-
- if err := builder.buildResource(bi, name, arch); err != nil {
- return fmt.Errorf("can't build the resources: %v", err)
- }
-
- if err := builder.buildProgram(bi, name, arch); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-type (
- windowsResources struct {
- Version [2]uint32
- VersionHuman string
- Language uint16
- Name string
- }
- windowsManifest struct {
- Version string
- WindowsVersion int
- Name string
- }
- windowsBuilder struct {
- TempDir string
- DestDir string
- Coff *coff.Coff
- }
-)
-
-const (
- // https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types
- windowsResourceIcon = 3
- windowsResourceIconGroup = windowsResourceIcon + 11
- windowsResourceManifest = 24
- windowsResourceVersion = 16
-)
-
-type bufferCoff struct {
- bytes.Buffer
-}
-
-func (b *bufferCoff) Size() int64 {
- return int64(b.Len())
-}
-
-func (b *windowsBuilder) embedIcon(path string) (err error) {
- iconFile, err := os.Open(path)
- if err != nil {
- if errors.Is(err, os.ErrNotExist) {
- return nil
- }
- return fmt.Errorf("can't read the icon located at %s: %v", path, err)
- }
- defer iconFile.Close()
-
- iconImage, err := png.Decode(iconFile)
- if err != nil {
- return fmt.Errorf("can't decode the PNG file (%s): %v", path, err)
- }
-
- sizes := []int{16, 32, 48, 64, 128, 256}
- var iconHeader bufferCoff
-
- // GRPICONDIR structure.
- if err := binary.Write(&iconHeader, binary.LittleEndian, [3]uint16{0, 1, uint16(len(sizes))}); err != nil {
- return err
- }
-
- for _, size := range sizes {
- var iconBuffer bufferCoff
-
- if err := png.Encode(&iconBuffer, resizeIcon(iconVariant{size: size, fill: false}, iconImage)); err != nil {
- return fmt.Errorf("can't encode image: %v", err)
- }
-
- b.Coff.AddResource(windowsResourceIcon, uint16(size), &iconBuffer)
-
- if err := binary.Write(&iconHeader, binary.LittleEndian, struct {
- Size [2]uint8
- Color [2]uint8
- Planes uint16
- BitCount uint16
- Length uint32
- Id uint16
- }{
- Size: [2]uint8{uint8(size % 256), uint8(size % 256)}, // "0" means 256px.
- Planes: 1,
- BitCount: 32,
- Length: uint32(iconBuffer.Len()),
- Id: uint16(size),
- }); err != nil {
- return err
- }
- }
-
- b.Coff.AddResource(windowsResourceIconGroup, 1, &iconHeader)
-
- return nil
-}
-
-func (b *windowsBuilder) buildResource(buildInfo *buildInfo, name string, arch string) error {
- out, err := os.Create(filepath.Join(buildInfo.pkgPath, name+"_windows_"+arch+".syso"))
- if err != nil {
- return err
- }
- defer out.Close()
- b.Coff.Freeze()
-
- // See https://github.com/akavel/rsrc/internal/write.go#L13.
- w := binutil.Writer{W: out}
- binutil.Walk(b.Coff, func(v reflect.Value, path string) error {
- if binutil.Plain(v.Kind()) {
- w.WriteLE(v.Interface())
- return nil
- }
- vv, ok := v.Interface().(binutil.SizedReader)
- if ok {
- w.WriteFromSized(vv)
- return binutil.WALK_SKIP
- }
- return nil
- })
-
- if w.Err != nil {
- return fmt.Errorf("error writing output file: %s", w.Err)
- }
-
- return nil
-}
-
-func (b *windowsBuilder) buildProgram(buildInfo *buildInfo, name string, arch string) error {
- dest := b.DestDir
- if len(buildInfo.archs) > 1 {
- dest = filepath.Join(filepath.Dir(b.DestDir), name+"_"+arch+".exe")
- }
-
- cmd := exec.Command(
- "go",
- "build",
- "-ldflags=-H=windowsgui "+buildInfo.ldflags,
- "-tags="+buildInfo.tags,
- "-o", dest,
- buildInfo.pkgPath,
- )
- cmd.Env = append(
- os.Environ(),
- "GOOS=windows",
- "GOARCH="+arch,
- )
- _, err := runCmd(cmd)
- return err
-}
-
-func (b *windowsBuilder) embedManifest(v windowsManifest) error {
- t, err := template.New("manifest").Parse(`
-
-
- {{.Name}}
-
-
- {{if (le .WindowsVersion 10)}}
-{{end}}
- {{if (le .WindowsVersion 9)}}
-{{end}}
- {{if (le .WindowsVersion 8)}}
-{{end}}
- {{if (le .WindowsVersion 7)}}
-{{end}}
- {{if (le .WindowsVersion 6)}}
-{{end}}
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-`)
- if err != nil {
- return err
- }
-
- var manifest bufferCoff
- if err := t.Execute(&manifest, v); err != nil {
- return err
- }
-
- b.Coff.AddResource(windowsResourceManifest, 1, &manifest)
-
- return nil
-}
-
-func (b *windowsBuilder) embedInfo(v windowsResources) error {
- page := uint16(1)
-
- // https://docs.microsoft.com/pt-br/windows/win32/menurc/vs-versioninfo
- t := newValue(valueBinary, "VS_VERSION_INFO", []io.WriterTo{
- // https://docs.microsoft.com/pt-br/windows/win32/api/VerRsrc/ns-verrsrc-vs_fixedfileinfo
- windowsInfoValueFixed{
- Signature: 0xFEEF04BD,
- StructVersion: 0x00010000,
- FileVersion: v.Version,
- ProductVersion: v.Version,
- FileFlagMask: 0x3F,
- FileFlags: 0,
- FileOS: 0x40004,
- FileType: 0x1,
- FileSubType: 0,
- },
- // https://docs.microsoft.com/pt-br/windows/win32/menurc/stringfileinfo
- newValue(valueText, "StringFileInfo", []io.WriterTo{
- // https://docs.microsoft.com/pt-br/windows/win32/menurc/stringtable
- newValue(valueText, fmt.Sprintf("%04X%04X", v.Language, page), []io.WriterTo{
- // https://docs.microsoft.com/pt-br/windows/win32/menurc/string-str
- newValue(valueText, "ProductVersion", v.VersionHuman),
- newValue(valueText, "FileVersion", v.VersionHuman),
- newValue(valueText, "FileDescription", v.Name),
- newValue(valueText, "ProductName", v.Name),
- // TODO include more data: gogio must have some way to provide such information (like Company Name, Copyright...)
- }),
- }),
- // https://docs.microsoft.com/pt-br/windows/win32/menurc/varfileinfo
- newValue(valueBinary, "VarFileInfo", []io.WriterTo{
- // https://docs.microsoft.com/pt-br/windows/win32/menurc/var-str
- newValue(valueBinary, "Translation", uint32(page)<<16|uint32(v.Language)),
- }),
- })
-
- // For some reason the ValueLength of the VS_VERSIONINFO must be the byte-length of `windowsInfoValueFixed`:
- t.ValueLength = 52
-
- var verrsrc bufferCoff
- if _, err := t.WriteTo(&verrsrc); err != nil {
- return err
- }
-
- b.Coff.AddResource(windowsResourceVersion, 1, &verrsrc)
-
- return nil
-}
-
-type windowsInfoValueFixed struct {
- Signature uint32
- StructVersion uint32
- FileVersion [2]uint32
- ProductVersion [2]uint32
- FileFlagMask uint32
- FileFlags uint32
- FileOS uint32
- FileType uint32
- FileSubType uint32
- FileDate [2]uint32
-}
-
-func (v windowsInfoValueFixed) WriteTo(w io.Writer) (_ int64, err error) {
- return 0, binary.Write(w, binary.LittleEndian, v)
-}
-
-type windowsInfoValue struct {
- Length uint16
- ValueLength uint16
- Type uint16
- Key []byte
- Value []byte
-}
-
-func (v windowsInfoValue) WriteTo(w io.Writer) (_ int64, err error) {
- // binary.Write doesn't support []byte inside struct.
- if err = binary.Write(w, binary.LittleEndian, [3]uint16{v.Length, v.ValueLength, v.Type}); err != nil {
- return 0, err
- }
- if _, err = w.Write(v.Key); err != nil {
- return 0, err
- }
- if _, err = w.Write(v.Value); err != nil {
- return 0, err
- }
- return 0, nil
-}
-
-const (
- valueBinary uint16 = 0
- valueText uint16 = 1
-)
-
-func newValue(valueType uint16, key string, input interface{}) windowsInfoValue {
- v := windowsInfoValue{
- Type: valueType,
- Length: 6,
- }
-
- padding := func(in []byte) []byte {
- if l := uint16(len(in)) + v.Length; l%4 != 0 {
- return append(in, make([]byte, 4-l%4)...)
- }
- return in
- }
-
- v.Key = padding(utf16Encode(key))
- v.Length += uint16(len(v.Key))
-
- switch in := input.(type) {
- case string:
- v.Value = padding(utf16Encode(in))
- v.ValueLength = uint16(len(v.Value) / 2)
- case []io.WriterTo:
- var buff bytes.Buffer
- for k := range in {
- if _, err := in[k].WriteTo(&buff); err != nil {
- panic(err)
- }
- }
- v.Value = buff.Bytes()
- default:
- var buff bytes.Buffer
- if err := binary.Write(&buff, binary.LittleEndian, in); err != nil {
- panic(err)
- }
- v.ValueLength = uint16(buff.Len())
- v.Value = buff.Bytes()
- }
-
- v.Length += uint16(len(v.Value))
-
- return v
-}
-
-// utf16Encode encodes the string to UTF16 with null-termination.
-func utf16Encode(s string) []byte {
- b, err := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder().Bytes([]byte(s))
- if err != nil {
- panic(err)
- }
- return append(b, 0x00, 0x00) // null-termination.
-}
diff --git a/cmd/gogio/x11_test.go b/cmd/gogio/x11_test.go
deleted file mode 100644
index 9bb3174b..00000000
--- a/cmd/gogio/x11_test.go
+++ /dev/null
@@ -1,170 +0,0 @@
-// SPDX-License-Identifier: Unlicense OR MIT
-
-package main_test
-
-import (
- "bytes"
- "context"
- "fmt"
- "image"
- "image/png"
- "io"
- "math/rand"
- "os"
- "os/exec"
- "path/filepath"
- "sync"
- "time"
-)
-
-type X11TestDriver struct {
- driverBase
-
- display string
-}
-
-func (d *X11TestDriver) Start(path string) {
- // First, build the app.
- bin := filepath.Join(d.tempDir("gio-endtoend-x11"), "red")
- flags := []string{"build", "-tags", "nowayland", "-o=" + bin}
- if raceEnabled {
- flags = append(flags, "-race")
- }
- flags = append(flags, path)
- cmd := exec.Command("go", flags...)
- if out, err := cmd.CombinedOutput(); err != nil {
- d.Fatalf("could not build app: %s:\n%s", err, out)
- }
-
- var wg sync.WaitGroup
- d.Cleanup(wg.Wait)
-
- d.startServer(&wg, d.width, d.height)
-
- // Then, start our program on the X server above.
- {
- ctx, cancel := context.WithCancel(context.Background())
- cmd := exec.CommandContext(ctx, bin)
- cmd.Env = []string{"DISPLAY=" + d.display}
- output, err := cmd.StdoutPipe()
- if err != nil {
- d.Fatal(err)
- }
- cmd.Stderr = cmd.Stdout
- d.output = output
- if err := cmd.Start(); err != nil {
- d.Fatal(err)
- }
- d.Cleanup(cancel)
- wg.Add(1)
- go func() {
- if err := cmd.Wait(); err != nil && ctx.Err() == nil {
- d.Error(err)
- }
- wg.Done()
- }()
- }
-
- // Wait for the gio app to render.
- d.waitForFrame()
-}
-
-func (d *X11TestDriver) startServer(wg *sync.WaitGroup, width, height int) {
- // Pick a random display number between 1 and 100,000. Most machines
- // will only be using :0, so there's only a 0.001% chance of two
- // concurrent test runs to run into a conflict.
- rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
- d.display = fmt.Sprintf(":%d", rnd.Intn(100000)+1)
-
- var xprog string
- xflags := []string{
- "-wr", // we want a white background; the default is black
- }
- if *headless {
- xprog = "Xvfb" // virtual X server
- xflags = append(xflags, "-screen", "0", fmt.Sprintf("%dx%dx24", width, height))
- } else {
- xprog = "Xephyr" // nested X server as a window
- xflags = append(xflags, "-screen", fmt.Sprintf("%dx%d", width, height))
- }
- xflags = append(xflags, d.display)
-
- d.needPrograms(
- xprog, // to run the X server
- "scrot", // to take screenshots
- "xdotool", // to send input
- )
- ctx, cancel := context.WithCancel(context.Background())
- cmd := exec.CommandContext(ctx, xprog, xflags...)
- combined := &bytes.Buffer{}
- cmd.Stdout = combined
- cmd.Stderr = combined
- if err := cmd.Start(); err != nil {
- d.Fatal(err)
- }
- d.Cleanup(cancel)
- d.Cleanup(func() {
- // Give it a chance to exit gracefully, cleaning up
- // after itself. After 10ms, the deferred cancel above
- // will signal an os.Kill.
- cmd.Process.Signal(os.Interrupt)
- time.Sleep(10 * time.Millisecond)
- })
-
- // Wait for the X server to be ready. The socket path isn't
- // terribly portable, but that's okay for now.
- withRetries(d.T, time.Second, func() error {
- socket := fmt.Sprintf("/tmp/.X11-unix/X%s", d.display[1:])
- _, err := os.Stat(socket)
- return err
- })
-
- wg.Add(1)
- go func() {
- if err := cmd.Wait(); err != nil && ctx.Err() == nil {
- // Print all output and error.
- io.Copy(os.Stdout, combined)
- d.Error(err)
- }
- wg.Done()
- }()
-}
-
-func (d *X11TestDriver) Screenshot() image.Image {
- cmd := exec.Command("scrot", "--silent", "--overwrite", "/dev/stdout")
- cmd.Env = []string{"DISPLAY=" + d.display}
- out, err := cmd.CombinedOutput()
- if err != nil {
- d.Errorf("%s", out)
- d.Fatal(err)
- }
- img, err := png.Decode(bytes.NewReader(out))
- if err != nil {
- d.Fatal(err)
- }
- return img
-}
-
-func (d *X11TestDriver) xdotool(args ...interface{}) string {
- d.Helper()
- strs := make([]string, len(args))
- for i, arg := range args {
- strs[i] = fmt.Sprint(arg)
- }
- cmd := exec.Command("xdotool", strs...)
- cmd.Env = []string{"DISPLAY=" + d.display}
- out, err := cmd.CombinedOutput()
- if err != nil {
- d.Errorf("%s", out)
- d.Fatal(err)
- }
- return string(bytes.TrimSpace(out))
-}
-
-func (d *X11TestDriver) Click(x, y int) {
- d.xdotool("mousemove", "--sync", x, y)
- d.xdotool("click", "1")
-
- // Wait for the gio app to render after this click.
- d.waitForFrame()
-}