diff --git a/go.mod b/go.mod index 9bf1f81dc..9adaba331 100644 --- a/go.mod +++ b/go.mod @@ -42,6 +42,7 @@ require ( github.com/spf13/pflag v1.0.3 github.com/stretchr/testify v1.3.0 github.com/t3rm1n4l/go-mega v0.0.0-20190205172012-55a226cf41da + github.com/thinkhy/go-adb v0.0.0-20190123053734-b4b48de70418 github.com/xanzy/ssh-agent v0.2.0 github.com/yunify/qingstor-sdk-go v2.2.15+incompatible go.etcd.io/bbolt v1.3.2 // indirect @@ -49,10 +50,12 @@ require ( golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 - golang.org/x/sys v0.0.0-20190204203706-41f3e6584952 + golang.org/x/sys v0.0.0-20190213121743-983097b1a8a3 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c google.golang.org/api v0.1.0 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v2 v2.2.2 ) + +replace github.com/thinkhy/go-adb v0.0.0-20190123053734-b4b48de70418 => ../../../github.com/thinkhy/go-adb diff --git a/go.sum b/go.sum index 8ee801a44..fadaf4eb7 100644 --- a/go.sum +++ b/go.sum @@ -23,6 +23,9 @@ github.com/a8m/tree v0.0.0-20181222104329-6a0b80129de4 h1:mK1/QgFPU4osbhjJ26B1w7 github.com/a8m/tree v0.0.0-20181222104329-6a0b80129de4/go.mod h1:FSdwKX97koS5efgm8WevNf7XS3PqtyFkKDDXrz778cg= github.com/abbot/go-http-auth v0.4.0 h1:QjmvZ5gSC7jm3Zg54DqWE/T5m1t2AfDu6QlXJT0EVT0= github.com/abbot/go-http-auth v0.4.0/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM= +github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anacrolix/dms v0.0.0-20180117034613-8af4925bffb5 h1:lmyFvZXNGOmsKCYXNwzDLWafnxeewxsFwdsvTvSC1sg= github.com/anacrolix/dms v0.0.0-20180117034613-8af4925bffb5/go.mod h1:DGqLjaZ3ziKKNRt+U5Q9PLWJ52Q/4rxfaaH/b3QYKaE= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= @@ -32,6 +35,7 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/billziss-gh/cgofuse v1.1.0 h1:tATn9ZDvuPcOVlvR4tJitGHgAqy1y18+4mKmRfdfjec= github.com/billziss-gh/cgofuse v1.1.0/go.mod h1:LJjoaUojlVjgo5GQoEJTcJNqZJeRU0nCR84CyxKt2YM= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/cheggaaa/pb v2.0.6+incompatible/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -75,6 +79,10 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1 github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-retryablehttp v0.5.2 h1:AoISa4P4IsW0/m4T6St8Yw38gTl5GtBAgfkhYh1xAz4= +github.com/hashicorp/go-retryablehttp v0.5.2/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= @@ -95,6 +103,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -169,6 +179,7 @@ github.com/spf13/cobra v0.0.4-0.20190109003409-7547e83b2d85/go.mod h1:1l0Ry5zgKv github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 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 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= @@ -178,6 +189,8 @@ github.com/t3rm1n4l/go-mega v0.0.0-20190205172012-55a226cf41da/go.mod h1:XWL4vDy github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro= github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8= +github.com/yosemite-open/go-adb v0.0.0-20181206003817-d40962019194 h1:hQ7oP/X/5JR3gGKEEEZU3uihkDePXlFoTwr0XDu5CKg= +github.com/yosemite-open/go-adb v0.0.0-20181206003817-d40962019194/go.mod h1:OoY1zUwKq/hv/6hBuQxzSRNu1XZ289eXaDNgoHa+3lU= github.com/yunify/qingstor-sdk-go v2.2.15+incompatible h1:/Z0q3/eSMoPYAuRmhjWtuGSmVVciFC6hfm3yfCKuvz0= github.com/yunify/qingstor-sdk-go v2.2.15+incompatible/go.mod h1:w6wqLDQ5bBTzxGJ55581UrSwLrsTAsdo9N6yX/8d9RY= go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= @@ -217,6 +230,10 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952 h1:FDfvYgoVsA7TTZSbgiqjAbfPbK47CNHdWl3h/PJtii0= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503 h1:5SvYFrOM3W8Mexn9/oA44Ji7vhXAZQ9hiP+1Q/DMrWg= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190213121743-983097b1a8a3 h1:+KlxhGbYkFs8lMfwKn+2ojry1ID5eBSMXprS2u/wqCE= +golang.org/x/sys v0.0.0-20190213121743-983097b1a8a3/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= @@ -244,12 +261,18 @@ google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +gopkg.in/VividCortex/ewma.v1 v1.1.1/go.mod h1:TekXuFipeiHWiAlO1+wSS23vTcyFau5u3rxXUSXj710= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v2 v2.0.6/go.mod h1:0CiZ1p8pvtxBlQpLXkHuUTpdJ1shm3OqCF1QugkjHL4= +gopkg.in/fatih/color.v1 v1.7.0/go.mod h1:P7yosIhqIl/sX8J8UypY5M+dDpD2KmyfP5IRs5v/fo0= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/mattn/go-colorable.v0 v0.1.0/go.mod h1:BVJlBXzARQxdi3nZo6f6bnl5yR20/tOL6p+V0KejgSY= +gopkg.in/mattn/go-isatty.v0 v0.0.4/go.mod h1:wt691ab7g0X4ilKZNmMII3egK0bTxl37fEn/Fwbd8gc= +gopkg.in/mattn/go-runewidth.v0 v0.0.4/go.mod h1:BmXejnxvhwdaATwiJbB1vZ2dtXkQKZGu9yLFCZb4msQ= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= diff --git a/vendor/github.com/hashicorp/go-cleanhttp/LICENSE b/vendor/github.com/hashicorp/go-cleanhttp/LICENSE new file mode 100644 index 000000000..e87a115e4 --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/go-cleanhttp/README.md b/vendor/github.com/hashicorp/go-cleanhttp/README.md new file mode 100644 index 000000000..036e5313f --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/README.md @@ -0,0 +1,30 @@ +# cleanhttp + +Functions for accessing "clean" Go http.Client values + +------------- + +The Go standard library contains a default `http.Client` called +`http.DefaultClient`. It is a common idiom in Go code to start with +`http.DefaultClient` and tweak it as necessary, and in fact, this is +encouraged; from the `http` package documentation: + +> The Client's Transport typically has internal state (cached TCP connections), +so Clients should be reused instead of created as needed. Clients are safe for +concurrent use by multiple goroutines. + +Unfortunately, this is a shared value, and it is not uncommon for libraries to +assume that they are free to modify it at will. With enough dependencies, it +can be very easy to encounter strange problems and race conditions due to +manipulation of this shared value across libraries and goroutines (clients are +safe for concurrent use, but writing values to the client struct itself is not +protected). + +Making things worse is the fact that a bare `http.Client` will use a default +`http.Transport` called `http.DefaultTransport`, which is another global value +that behaves the same way. So it is not simply enough to replace +`http.DefaultClient` with `&http.Client{}`. + +This repository provides some simple functions to get a "clean" `http.Client` +-- one that uses the same default values as the Go standard library, but +returns a client that does not share any state with other clients. diff --git a/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go b/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go new file mode 100644 index 000000000..8d306bf51 --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go @@ -0,0 +1,57 @@ +package cleanhttp + +import ( + "net" + "net/http" + "runtime" + "time" +) + +// DefaultTransport returns a new http.Transport with similar default values to +// http.DefaultTransport, but with idle connections and keepalives disabled. +func DefaultTransport() *http.Transport { + transport := DefaultPooledTransport() + transport.DisableKeepAlives = true + transport.MaxIdleConnsPerHost = -1 + return transport +} + +// DefaultPooledTransport returns a new http.Transport with similar default +// values to http.DefaultTransport. Do not use this for transient transports as +// it can leak file descriptors over time. Only use this for transports that +// will be re-used for the same host(s). +func DefaultPooledTransport() *http.Transport { + transport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).DialContext, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1, + } + return transport +} + +// DefaultClient returns a new http.Client with similar default values to +// http.Client, but with a non-shared Transport, idle connections disabled, and +// keepalives disabled. +func DefaultClient() *http.Client { + return &http.Client{ + Transport: DefaultTransport(), + } +} + +// DefaultPooledClient returns a new http.Client with similar default values to +// http.Client, but with a shared Transport. Do not use this function for +// transient clients as it can leak file descriptors over time. Only use this +// for clients that will be re-used for the same host(s). +func DefaultPooledClient() *http.Client { + return &http.Client{ + Transport: DefaultPooledTransport(), + } +} diff --git a/vendor/github.com/hashicorp/go-cleanhttp/doc.go b/vendor/github.com/hashicorp/go-cleanhttp/doc.go new file mode 100644 index 000000000..05841092a --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/doc.go @@ -0,0 +1,20 @@ +// Package cleanhttp offers convenience utilities for acquiring "clean" +// http.Transport and http.Client structs. +// +// Values set on http.DefaultClient and http.DefaultTransport affect all +// callers. This can have detrimental effects, esepcially in TLS contexts, +// where client or root certificates set to talk to multiple endpoints can end +// up displacing each other, leading to hard-to-debug issues. This package +// provides non-shared http.Client and http.Transport structs to ensure that +// the configuration will not be overwritten by other parts of the application +// or dependencies. +// +// The DefaultClient and DefaultTransport functions disable idle connections +// and keepalives. Without ensuring that idle connections are closed before +// garbage collection, short-term clients/transports can leak file descriptors, +// eventually leading to "too many open files" errors. If you will be +// connecting to the same hosts repeatedly from the same client, you can use +// DefaultPooledClient to receive a client that has connection pooling +// semantics similar to http.DefaultClient. +// +package cleanhttp diff --git a/vendor/github.com/hashicorp/go-cleanhttp/go.mod b/vendor/github.com/hashicorp/go-cleanhttp/go.mod new file mode 100644 index 000000000..310f07569 --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/go.mod @@ -0,0 +1 @@ +module github.com/hashicorp/go-cleanhttp diff --git a/vendor/github.com/hashicorp/go-cleanhttp/handlers.go b/vendor/github.com/hashicorp/go-cleanhttp/handlers.go new file mode 100644 index 000000000..7eda3777f --- /dev/null +++ b/vendor/github.com/hashicorp/go-cleanhttp/handlers.go @@ -0,0 +1,43 @@ +package cleanhttp + +import ( + "net/http" + "strings" + "unicode" +) + +// HandlerInput provides input options to cleanhttp's handlers +type HandlerInput struct { + ErrStatus int +} + +// PrintablePathCheckHandler is a middleware that ensures the request path +// contains only printable runes. +func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler { + // Nil-check on input to make it optional + if input == nil { + input = &HandlerInput{ + ErrStatus: http.StatusBadRequest, + } + } + + // Default to http.StatusBadRequest on error + if input.ErrStatus == 0 { + input.ErrStatus = http.StatusBadRequest + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Check URL path for non-printable characters + idx := strings.IndexFunc(r.URL.Path, func(c rune) bool { + return !unicode.IsPrint(c) + }) + + if idx != -1 { + w.WriteHeader(input.ErrStatus) + return + } + + next.ServeHTTP(w, r) + return + }) +} diff --git a/vendor/github.com/hashicorp/go-retryablehttp/.gitignore b/vendor/github.com/hashicorp/go-retryablehttp/.gitignore new file mode 100644 index 000000000..caab963a3 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/.gitignore @@ -0,0 +1,3 @@ +.idea/ +*.iml +*.test diff --git a/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml b/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml new file mode 100644 index 000000000..2df4e7dfa --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml @@ -0,0 +1,12 @@ +sudo: false + +language: go + +go: + - 1.8.1 + +branches: + only: + - master + +script: make updatedeps test diff --git a/vendor/github.com/hashicorp/go-retryablehttp/LICENSE b/vendor/github.com/hashicorp/go-retryablehttp/LICENSE new file mode 100644 index 000000000..e87a115e4 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/LICENSE @@ -0,0 +1,363 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/hashicorp/go-retryablehttp/Makefile b/vendor/github.com/hashicorp/go-retryablehttp/Makefile new file mode 100644 index 000000000..da17640e6 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/Makefile @@ -0,0 +1,11 @@ +default: test + +test: + go vet ./... + go test -race ./... + +updatedeps: + go get -f -t -u ./... + go get -f -u ./... + +.PHONY: default test updatedeps diff --git a/vendor/github.com/hashicorp/go-retryablehttp/README.md b/vendor/github.com/hashicorp/go-retryablehttp/README.md new file mode 100644 index 000000000..ccdc7e87c --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/README.md @@ -0,0 +1,46 @@ +go-retryablehttp +================ + +[![Build Status](http://img.shields.io/travis/hashicorp/go-retryablehttp.svg?style=flat-square)][travis] +[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs] + +[travis]: http://travis-ci.org/hashicorp/go-retryablehttp +[godocs]: http://godoc.org/github.com/hashicorp/go-retryablehttp + +The `retryablehttp` package provides a familiar HTTP client interface with +automatic retries and exponential backoff. It is a thin wrapper over the +standard `net/http` client library and exposes nearly the same public API. This +makes `retryablehttp` very easy to drop into existing programs. + +`retryablehttp` performs automatic retries under certain conditions. Mainly, if +an error is returned by the client (connection errors, etc.), or if a 500-range +response code is received (except 501), then a retry is invoked after a wait +period. Otherwise, the response is returned and left to the caller to +interpret. + +The main difference from `net/http` is that requests which take a request body +(POST/PUT et. al) can have the body provided in a number of ways (some more or +less efficient) that allow "rewinding" the request body if the initial request +fails so that the full request can be attempted again. See the +[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp) for more +details. + +Example Use +=========== + +Using this library should look almost identical to what you would do with +`net/http`. The most simple example of a GET request is shown below: + +```go +resp, err := retryablehttp.Get("/foo") +if err != nil { + panic(err) +} +``` + +The returned response object is an `*http.Response`, the same thing you would +usually get from `net/http`. Had the request failed one or more times, the above +call would block and retry with exponential backoff. + +For more usage and examples see the +[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp). diff --git a/vendor/github.com/hashicorp/go-retryablehttp/client.go b/vendor/github.com/hashicorp/go-retryablehttp/client.go new file mode 100644 index 000000000..15f1e8850 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/client.go @@ -0,0 +1,528 @@ +// The retryablehttp package provides a familiar HTTP client interface with +// automatic retries and exponential backoff. It is a thin wrapper over the +// standard net/http client library and exposes nearly the same public API. +// This makes retryablehttp very easy to drop into existing programs. +// +// retryablehttp performs automatic retries under certain conditions. Mainly, if +// an error is returned by the client (connection errors etc), or if a 500-range +// response is received, then a retry is invoked. Otherwise, the response is +// returned and left to the caller to interpret. +// +// Requests which take a request body should provide a non-nil function +// parameter. The best choice is to provide either a function satisfying +// ReaderFunc which provides multiple io.Readers in an efficient manner, a +// *bytes.Buffer (the underlying raw byte slice will be used) or a raw byte +// slice. As it is a reference type, and we will wrap it as needed by readers, +// we can efficiently re-use the request body without needing to copy it. If an +// io.Reader (such as a *bytes.Reader) is provided, the full body will be read +// prior to the first request, and will be efficiently re-used for any retries. +// ReadSeeker can be used, but some users have observed occasional data races +// between the net/http library and the Seek functionality of some +// implementations of ReadSeeker, so should be avoided if possible. +package retryablehttp + +import ( + "bytes" + "context" + "fmt" + "io" + "io/ioutil" + "log" + "math" + "math/rand" + "net/http" + "net/url" + "os" + "strings" + "time" + + cleanhttp "github.com/hashicorp/go-cleanhttp" +) + +var ( + // Default retry configuration + defaultRetryWaitMin = 1 * time.Second + defaultRetryWaitMax = 30 * time.Second + defaultRetryMax = 4 + + // defaultClient is used for performing requests without explicitly making + // a new client. It is purposely private to avoid modifications. + defaultClient = NewClient() + + // We need to consume response bodies to maintain http connections, but + // limit the size we consume to respReadLimit. + respReadLimit = int64(4096) +) + +// ReaderFunc is the type of function that can be given natively to NewRequest +type ReaderFunc func() (io.Reader, error) + +// LenReader is an interface implemented by many in-memory io.Reader's. Used +// for automatically sending the right Content-Length header when possible. +type LenReader interface { + Len() int +} + +// Request wraps the metadata needed to create HTTP requests. +type Request struct { + // body is a seekable reader over the request body payload. This is + // used to rewind the request data in between retries. + body ReaderFunc + + // Embed an HTTP request directly. This makes a *Request act exactly + // like an *http.Request so that all meta methods are supported. + *http.Request +} + +// WithContext returns wrapped Request with a shallow copy of underlying *http.Request +// with its context changed to ctx. The provided ctx must be non-nil. +func (r *Request) WithContext(ctx context.Context) *Request { + r.Request = r.Request.WithContext(ctx) + return r +} + +// BodyBytes allows accessing the request body. It is an analogue to +// http.Request's Body variable, but it returns a copy of the underlying data +// rather than consuming it. +// +// This function is not thread-safe; do not call it at the same time as another +// call, or at the same time this request is being used with Client.Do. +func (r *Request) BodyBytes() ([]byte, error) { + if r.body == nil { + return nil, nil + } + body, err := r.body() + if err != nil { + return nil, err + } + buf := new(bytes.Buffer) + _, err = buf.ReadFrom(body) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// NewRequest creates a new wrapped request. +func NewRequest(method, url string, rawBody interface{}) (*Request, error) { + var err error + var body ReaderFunc + var contentLength int64 + + if rawBody != nil { + switch rawBody.(type) { + // If they gave us a function already, great! Use it. + case ReaderFunc: + body = rawBody.(ReaderFunc) + tmp, err := body() + if err != nil { + return nil, err + } + if lr, ok := tmp.(LenReader); ok { + contentLength = int64(lr.Len()) + } + if c, ok := tmp.(io.Closer); ok { + c.Close() + } + + case func() (io.Reader, error): + body = rawBody.(func() (io.Reader, error)) + tmp, err := body() + if err != nil { + return nil, err + } + if lr, ok := tmp.(LenReader); ok { + contentLength = int64(lr.Len()) + } + if c, ok := tmp.(io.Closer); ok { + c.Close() + } + + // If a regular byte slice, we can read it over and over via new + // readers + case []byte: + buf := rawBody.([]byte) + body = func() (io.Reader, error) { + return bytes.NewReader(buf), nil + } + contentLength = int64(len(buf)) + + // If a bytes.Buffer we can read the underlying byte slice over and + // over + case *bytes.Buffer: + buf := rawBody.(*bytes.Buffer) + body = func() (io.Reader, error) { + return bytes.NewReader(buf.Bytes()), nil + } + contentLength = int64(buf.Len()) + + // We prioritize *bytes.Reader here because we don't really want to + // deal with it seeking so want it to match here instead of the + // io.ReadSeeker case. + case *bytes.Reader: + buf, err := ioutil.ReadAll(rawBody.(*bytes.Reader)) + if err != nil { + return nil, err + } + body = func() (io.Reader, error) { + return bytes.NewReader(buf), nil + } + contentLength = int64(len(buf)) + + // Compat case + case io.ReadSeeker: + raw := rawBody.(io.ReadSeeker) + body = func() (io.Reader, error) { + raw.Seek(0, 0) + return ioutil.NopCloser(raw), nil + } + if lr, ok := raw.(LenReader); ok { + contentLength = int64(lr.Len()) + } + + // Read all in so we can reset + case io.Reader: + buf, err := ioutil.ReadAll(rawBody.(io.Reader)) + if err != nil { + return nil, err + } + body = func() (io.Reader, error) { + return bytes.NewReader(buf), nil + } + contentLength = int64(len(buf)) + + default: + return nil, fmt.Errorf("cannot handle type %T", rawBody) + } + } + + httpReq, err := http.NewRequest(method, url, nil) + if err != nil { + return nil, err + } + httpReq.ContentLength = contentLength + + return &Request{body, httpReq}, nil +} + +// Logger interface allows to use other loggers than +// standard log.Logger. +type Logger interface { + Printf(string, ...interface{}) +} + +// RequestLogHook allows a function to run before each retry. The HTTP +// request which will be made, and the retry number (0 for the initial +// request) are available to users. The internal logger is exposed to +// consumers. +type RequestLogHook func(Logger, *http.Request, int) + +// ResponseLogHook is like RequestLogHook, but allows running a function +// on each HTTP response. This function will be invoked at the end of +// every HTTP request executed, regardless of whether a subsequent retry +// needs to be performed or not. If the response body is read or closed +// from this method, this will affect the response returned from Do(). +type ResponseLogHook func(Logger, *http.Response) + +// CheckRetry specifies a policy for handling retries. It is called +// following each request with the response and error values returned by +// the http.Client. If CheckRetry returns false, the Client stops retrying +// and returns the response to the caller. If CheckRetry returns an error, +// that error value is returned in lieu of the error from the request. The +// Client will close any response body when retrying, but if the retry is +// aborted it is up to the CheckResponse callback to properly close any +// response body before returning. +type CheckRetry func(ctx context.Context, resp *http.Response, err error) (bool, error) + +// Backoff specifies a policy for how long to wait between retries. +// It is called after a failing request to determine the amount of time +// that should pass before trying again. +type Backoff func(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration + +// ErrorHandler is called if retries are expired, containing the last status +// from the http library. If not specified, default behavior for the library is +// to close the body and return an error indicating how many tries were +// attempted. If overriding this, be sure to close the body if needed. +type ErrorHandler func(resp *http.Response, err error, numTries int) (*http.Response, error) + +// Client is used to make HTTP requests. It adds additional functionality +// like automatic retries to tolerate minor outages. +type Client struct { + HTTPClient *http.Client // Internal HTTP client. + Logger Logger // Customer logger instance. + + RetryWaitMin time.Duration // Minimum time to wait + RetryWaitMax time.Duration // Maximum time to wait + RetryMax int // Maximum number of retries + + // RequestLogHook allows a user-supplied function to be called + // before each retry. + RequestLogHook RequestLogHook + + // ResponseLogHook allows a user-supplied function to be called + // with the response from each HTTP request executed. + ResponseLogHook ResponseLogHook + + // CheckRetry specifies the policy for handling retries, and is called + // after each request. The default policy is DefaultRetryPolicy. + CheckRetry CheckRetry + + // Backoff specifies the policy for how long to wait between retries + Backoff Backoff + + // ErrorHandler specifies the custom error handler to use, if any + ErrorHandler ErrorHandler +} + +// NewClient creates a new Client with default settings. +func NewClient() *Client { + return &Client{ + HTTPClient: cleanhttp.DefaultClient(), + Logger: log.New(os.Stderr, "", log.LstdFlags), + RetryWaitMin: defaultRetryWaitMin, + RetryWaitMax: defaultRetryWaitMax, + RetryMax: defaultRetryMax, + CheckRetry: DefaultRetryPolicy, + Backoff: DefaultBackoff, + } +} + +// DefaultRetryPolicy provides a default callback for Client.CheckRetry, which +// will retry on connection errors and server errors. +func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { + // do not retry on context.Canceled or context.DeadlineExceeded + if ctx.Err() != nil { + return false, ctx.Err() + } + + if err != nil { + return true, err + } + // Check the response code. We retry on 500-range responses to allow + // the server time to recover, as 500's are typically not permanent + // errors and may relate to outages on the server side. This will catch + // invalid response codes as well, like 0 and 999. + if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != 501) { + return true, nil + } + + return false, nil +} + +// DefaultBackoff provides a default callback for Client.Backoff which +// will perform exponential backoff based on the attempt number and limited +// by the provided minimum and maximum durations. +func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { + mult := math.Pow(2, float64(attemptNum)) * float64(min) + sleep := time.Duration(mult) + if float64(sleep) != mult || sleep > max { + sleep = max + } + return sleep +} + +// LinearJitterBackoff provides a callback for Client.Backoff which will +// perform linear backoff based on the attempt number and with jitter to +// prevent a thundering herd. +// +// min and max here are *not* absolute values. The number to be multipled by +// the attempt number will be chosen at random from between them, thus they are +// bounding the jitter. +// +// For instance: +// * To get strictly linear backoff of one second increasing each retry, set +// both to one second (1s, 2s, 3s, 4s, ...) +// * To get a small amount of jitter centered around one second increasing each +// retry, set to around one second, such as a min of 800ms and max of 1200ms +// (892ms, 2102ms, 2945ms, 4312ms, ...) +// * To get extreme jitter, set to a very wide spread, such as a min of 100ms +// and a max of 20s (15382ms, 292ms, 51321ms, 35234ms, ...) +func LinearJitterBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { + // attemptNum always starts at zero but we want to start at 1 for multiplication + attemptNum++ + + if max <= min { + // Unclear what to do here, or they are the same, so return min * + // attemptNum + return min * time.Duration(attemptNum) + } + + // Seed rand; doing this every time is fine + rand := rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) + + // Pick a random number that lies somewhere between the min and max and + // multiply by the attemptNum. attemptNum starts at zero so we always + // increment here. We first get a random percentage, then apply that to the + // difference between min and max, and add to min. + jitter := rand.Float64() * float64(max-min) + jitterMin := int64(jitter) + int64(min) + return time.Duration(jitterMin * int64(attemptNum)) +} + +// PassthroughErrorHandler is an ErrorHandler that directly passes through the +// values from the net/http library for the final request. The body is not +// closed. +func PassthroughErrorHandler(resp *http.Response, err error, _ int) (*http.Response, error) { + return resp, err +} + +// Do wraps calling an HTTP method with retries. +func (c *Client) Do(req *Request) (*http.Response, error) { + if c.Logger != nil { + c.Logger.Printf("[DEBUG] %s %s", req.Method, req.URL) + } + + var resp *http.Response + var err error + + for i := 0; ; i++ { + var code int // HTTP response code + + // Always rewind the request body when non-nil. + if req.body != nil { + body, err := req.body() + if err != nil { + return resp, err + } + if c, ok := body.(io.ReadCloser); ok { + req.Request.Body = c + } else { + req.Request.Body = ioutil.NopCloser(body) + } + } + + if c.RequestLogHook != nil { + c.RequestLogHook(c.Logger, req.Request, i) + } + + // Attempt the request + resp, err = c.HTTPClient.Do(req.Request) + if resp != nil { + code = resp.StatusCode + } + + // Check if we should continue with retries. + checkOK, checkErr := c.CheckRetry(req.Request.Context(), resp, err) + + if err != nil { + if c.Logger != nil { + c.Logger.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, err) + } + } else { + // Call this here to maintain the behavior of logging all requests, + // even if CheckRetry signals to stop. + if c.ResponseLogHook != nil { + // Call the response logger function if provided. + c.ResponseLogHook(c.Logger, resp) + } + } + + // Now decide if we should continue. + if !checkOK { + if checkErr != nil { + err = checkErr + } + return resp, err + } + + // We do this before drainBody beause there's no need for the I/O if + // we're breaking out + remain := c.RetryMax - i + if remain <= 0 { + break + } + + // We're going to retry, consume any response to reuse the connection. + if err == nil && resp != nil { + c.drainBody(resp.Body) + } + + wait := c.Backoff(c.RetryWaitMin, c.RetryWaitMax, i, resp) + desc := fmt.Sprintf("%s %s", req.Method, req.URL) + if code > 0 { + desc = fmt.Sprintf("%s (status: %d)", desc, code) + } + if c.Logger != nil { + c.Logger.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain) + } + time.Sleep(wait) + } + + if c.ErrorHandler != nil { + return c.ErrorHandler(resp, err, c.RetryMax+1) + } + + // By default, we close the response body and return an error without + // returning the response + if resp != nil { + resp.Body.Close() + } + return nil, fmt.Errorf("%s %s giving up after %d attempts", + req.Method, req.URL, c.RetryMax+1) +} + +// Try to read the response body so we can reuse this connection. +func (c *Client) drainBody(body io.ReadCloser) { + defer body.Close() + _, err := io.Copy(ioutil.Discard, io.LimitReader(body, respReadLimit)) + if err != nil { + if c.Logger != nil { + c.Logger.Printf("[ERR] error reading response body: %v", err) + } + } +} + +// Get is a shortcut for doing a GET request without making a new client. +func Get(url string) (*http.Response, error) { + return defaultClient.Get(url) +} + +// Get is a convenience helper for doing simple GET requests. +func (c *Client) Get(url string) (*http.Response, error) { + req, err := NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + return c.Do(req) +} + +// Head is a shortcut for doing a HEAD request without making a new client. +func Head(url string) (*http.Response, error) { + return defaultClient.Head(url) +} + +// Head is a convenience method for doing simple HEAD requests. +func (c *Client) Head(url string) (*http.Response, error) { + req, err := NewRequest("HEAD", url, nil) + if err != nil { + return nil, err + } + return c.Do(req) +} + +// Post is a shortcut for doing a POST request without making a new client. +func Post(url, bodyType string, body interface{}) (*http.Response, error) { + return defaultClient.Post(url, bodyType, body) +} + +// Post is a convenience method for doing simple POST requests. +func (c *Client) Post(url, bodyType string, body interface{}) (*http.Response, error) { + req, err := NewRequest("POST", url, body) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", bodyType) + return c.Do(req) +} + +// PostForm is a shortcut to perform a POST with form data without creating +// a new client. +func PostForm(url string, data url.Values) (*http.Response, error) { + return defaultClient.PostForm(url, data) +} + +// PostForm is a convenience method for doing simple POST operations using +// pre-filled url.Values form data. +func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) { + return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) +} diff --git a/vendor/github.com/hashicorp/go-retryablehttp/go.mod b/vendor/github.com/hashicorp/go-retryablehttp/go.mod new file mode 100644 index 000000000..d28c8c8eb --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/go.mod @@ -0,0 +1,3 @@ +module github.com/hashicorp/go-retryablehttp + +require github.com/hashicorp/go-cleanhttp v0.5.0 diff --git a/vendor/github.com/hashicorp/go-retryablehttp/go.sum b/vendor/github.com/hashicorp/go-retryablehttp/go.sum new file mode 100644 index 000000000..3ed0fd98e --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/go.sum @@ -0,0 +1,2 @@ +github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= diff --git a/vendor/github.com/thinkhy/go-adb/.travis.yml b/vendor/github.com/thinkhy/go-adb/.travis.yml new file mode 100644 index 000000000..e81ce66d2 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/.travis.yml @@ -0,0 +1,11 @@ +language: go + +go: + - 1.6 + - tip + +install: + - make get-deps + +script: + - make test diff --git a/vendor/github.com/thinkhy/go-adb/LICENSE.txt b/vendor/github.com/thinkhy/go-adb/LICENSE.txt new file mode 100644 index 000000000..9c8f3ea08 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/vendor/github.com/thinkhy/go-adb/Makefile b/vendor/github.com/thinkhy/go-adb/Makefile new file mode 100644 index 000000000..9271548a1 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/Makefile @@ -0,0 +1,13 @@ +.PHONY: test generate get-deps + +test: generate + go test -v -race ./... + +generate: + # stringer requires the packages to be installed. + go install -v + go generate -x ./... + +get-deps: + go get -t -v ./... + go get -u golang.org/x/tools/cmd/stringer diff --git a/vendor/github.com/thinkhy/go-adb/README.md b/vendor/github.com/thinkhy/go-adb/README.md new file mode 100644 index 000000000..457c9cf2e --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/README.md @@ -0,0 +1,8 @@ +#goadb + +[![Build Status](https://travis-ci.org/zach-klippenstein/goadb.svg?branch=master)](https://travis-ci.org/zach-klippenstein/goadb) +[![GoDoc](https://godoc.org/github.com/zach-klippenstein/goadb?status.svg)](https://godoc.org/github.com/zach-klippenstein/goadb) + +A Golang library for interacting with the Android Debug Bridge (adb). + +See [demo.go](cmd/demo/demo.go) for usage. diff --git a/vendor/github.com/thinkhy/go-adb/adb.go b/vendor/github.com/thinkhy/go-adb/adb.go new file mode 100644 index 000000000..5aac09a86 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/adb.go @@ -0,0 +1,176 @@ +package adb + +import ( + "strconv" + + "github.com/thinkhy/go-adb/internal/errors" + "github.com/thinkhy/go-adb/wire" +) + +/* +Adb communicates with host services on the adb server. + +Eg. + client := adb.New() + client.ListDevices() + +See list of services at https://android.googlesource.com/platform/system/core/+/master/adb/SERVICES.TXT. +*/ +// TODO(z): Finish implementing host services. +type Adb struct { + server server +} + +// New creates a new Adb client that uses the default ServerConfig. +func New() (*Adb, error) { + return NewWithConfig(ServerConfig{}) +} + +func NewWithConfig(config ServerConfig) (*Adb, error) { + server, err := newServer(config) + if err != nil { + return nil, err + } + return &Adb{server}, nil +} + +func NewWithRemoteServer(host string, port int) (*Adb, error) { + config := ServerConfig{ + Host: host, + Port: port, + } + server, err := newServer(config) + if err != nil { + return nil, err + } + return &Adb{server}, nil +} + +// Dial establishes a connection with the adb server. +func (c *Adb) Dial() (*wire.Conn, error) { + return c.server.Dial() +} + +// Starts the adb server if it’s not running. +func (c *Adb) StartServer() error { + return c.server.Start() +} + +func (c *Adb) Device(descriptor DeviceDescriptor) *Device { + return &Device{ + server: c.server, + descriptor: descriptor, + deviceListFunc: c.ListDevices, + } +} + +func (c *Adb) NewDeviceWatcher() *DeviceWatcher { + return newDeviceWatcher(c.server) +} + +// ServerVersion asks the ADB server for its internal version number. +func (c *Adb) ServerVersion() (int, error) { + resp, err := roundTripSingleResponse(c.server, "host:version") + if err != nil { + return 0, wrapClientError(err, c, "GetServerVersion") + } + + version, err := c.parseServerVersion(resp) + if err != nil { + return 0, wrapClientError(err, c, "GetServerVersion") + } + return version, nil +} + +/* +KillServer tells the server to quit immediately. + +Corresponds to the command: + adb kill-server +*/ +func (c *Adb) KillServer() error { + conn, err := c.server.Dial() + if err != nil { + return wrapClientError(err, c, "KillServer") + } + defer conn.Close() + + if err = wire.SendMessageString(conn, "host:kill"); err != nil { + return wrapClientError(err, c, "KillServer") + } + + return nil +} + +/* +ListDeviceSerials returns the serial numbers of all attached devices. + +Corresponds to the command: + adb devices +*/ +func (c *Adb) ListDeviceSerials() ([]string, error) { + resp, err := roundTripSingleResponse(c.server, "host:devices") + if err != nil { + return nil, wrapClientError(err, c, "ListDeviceSerials") + } + + devices, err := parseDeviceList(string(resp), parseDeviceShort) + if err != nil { + return nil, wrapClientError(err, c, "ListDeviceSerials") + } + + serials := make([]string, len(devices)) + for i, dev := range devices { + serials[i] = dev.Serial + } + return serials, nil +} + +/* +ListDevices returns the list of connected devices. + +Corresponds to the command: + adb devices -l +*/ +func (c *Adb) ListDevices() ([]*DeviceInfo, error) { + resp, err := roundTripSingleResponse(c.server, "host:devices-l") + if err != nil { + return nil, wrapClientError(err, c, "ListDevices") + } + + devices, err := parseDeviceList(string(resp), parseDeviceLong) + if err != nil { + return nil, wrapClientError(err, c, "ListDevices") + } + return devices, nil +} + +func (c *Adb) ListDevicesInfo() ([]string, []string, error) { + resp, err := roundTripSingleResponse(c.server, "host:devices") + if err != nil { + return nil, nil, wrapClientError(err, c, "ListDeviceSerials") + } + + devices, err := parseDeviceList(string(resp), parseDeviceShort) + if err != nil { + return nil, nil, wrapClientError(err, c, "ListDeviceSerials") + } + + serials := make([]string, len(devices)) + status := make([]string, len(devices)) + for i, dev := range devices { + serials[i] = dev.Serial + status[i] = dev.Status + } + return serials, status, nil +} + +func (c *Adb) parseServerVersion(versionRaw []byte) (int, error) { + versionStr := string(versionRaw) + version, err := strconv.ParseInt(versionStr, 16, 32) + if err != nil { + return 0, errors.WrapErrorf(err, errors.ParseError, + "error parsing server version: %s", versionStr) + } + return int(version), nil +} diff --git a/vendor/github.com/thinkhy/go-adb/asyncwriter.go b/vendor/github.com/thinkhy/go-adb/asyncwriter.go new file mode 100644 index 000000000..85c18db61 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/asyncwriter.go @@ -0,0 +1,111 @@ +package adb + +import ( + "io" + "sync" + "time" +) + +type AsyncWriter struct { + Done chan bool + DoneCopy chan bool // for debug + C chan bool + err error + dst io.WriteCloser + dstPath string + TotalSize int64 + dev *Device + bytesCompleted int64 + copyErrC chan error + wg sync.WaitGroup +} + +func newAsyncWriter(dev *Device, dst io.WriteCloser, dstPath string, totalSize int64) *AsyncWriter { + return &AsyncWriter{ + Done: make(chan bool), + DoneCopy: make(chan bool, 1), + C: make(chan bool), + dst: dst, + dstPath: dstPath, + dev: dev, + TotalSize: totalSize, + copyErrC: make(chan error, 1), + } +} + +// BytesCompleted returns the total number of bytes which have been copied to the destination +func (a *AsyncWriter) BytesCompleted() int64 { + return a.bytesCompleted +} + +func (a *AsyncWriter) Progress() float64 { + if (a.TotalSize) == 0 { + return 0.0 + } + return float64(a.bytesCompleted) / float64(a.TotalSize) +} + +// Err return error immediately +func (a *AsyncWriter) Err() error { + return a.err +} + +func (a *AsyncWriter) Cancel() error { + return a.dst.Close() +} + +// Wait blocks until sync is completed +func (a *AsyncWriter) Wait() { + <-a.Done +} + +func (a *AsyncWriter) doCopy(reader io.Reader) { + a.wg.Add(1) + defer a.wg.Done() + + go a.darinProgress() + written, err := io.Copy(a.dst, reader) + if err != nil { + a.err = err + a.copyErrC <- err + } + a.TotalSize = written + defer a.dst.Close() + a.DoneCopy <- true +} + +func (a *AsyncWriter) darinProgress() { + t := time.NewTicker(time.Millisecond * 500) + defer func() { + t.Stop() + a.wg.Wait() + a.Done <- true + }() + var lastSize int32 + for { + select { + case <-t.C: + finfo, err := a.dev.Stat(a.dstPath) + if err != nil && !HasErrCode(err, FileNoExistError) { + a.err = err + return + } + if finfo == nil { + continue + } + if lastSize != finfo.Size { + lastSize = finfo.Size + select { + case a.C <- true: + default: + } + } + a.bytesCompleted = int64(finfo.Size) + if a.TotalSize != 0 && a.bytesCompleted >= a.TotalSize { + return + } + case <-a.copyErrC: + return + } + } +} diff --git a/vendor/github.com/thinkhy/go-adb/device.go b/vendor/github.com/thinkhy/go-adb/device.go new file mode 100644 index 000000000..52d694dd3 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/device.go @@ -0,0 +1,540 @@ +package adb + +import ( + "fmt" + "io" + "os" + "path/filepath" + "strconv" + "strings" + "time" + + "github.com/thinkhy/go-adb/internal/errors" + "github.com/thinkhy/go-adb/wire" +) + +// MtimeOfClose should be passed to OpenWrite to set the file modification time to the time the Close +// method is called. +var MtimeOfClose = time.Time{} + +// Device communicates with a specific Android device. +// To get an instance, call Device() on an Adb. +type Device struct { + server server + descriptor DeviceDescriptor + + // Used to get device info. + deviceListFunc func() ([]*DeviceInfo, error) +} + +func (c *Device) String() string { + return c.descriptor.String() +} + +// get-product is documented, but not implemented, in the server. +// TODO(z): Make product exported if get-product is ever implemented in adb. +func (c *Device) product() (string, error) { + attr, err := c.getAttribute("get-product") + return attr, wrapClientError(err, c, "Product") +} + +func (c *Device) Serial() (string, error) { + attr, err := c.getAttribute("get-serialno") + return attr, wrapClientError(err, c, "Serial") +} + +func (c *Device) DevicePath() (string, error) { + attr, err := c.getAttribute("get-devpath") + return attr, wrapClientError(err, c, "DevicePath") +} + +func (c *Device) State() (DeviceState, error) { + attr, err := c.getAttribute("get-state") + state, err := parseDeviceState(attr) + return state, wrapClientError(err, c, "State") +} + +var ( + FProtocolTcp = "tcp" + FProtocolAbstract = "localabstract" + FProtocolReserved = "localreserved" + FProtocolFilesystem = "localfilesystem" +) + +type ForwardSpec struct { + Protocol string + PortOrName string +} + +func (f ForwardSpec) String() string { + return fmt.Sprintf("%s:%s", f.Protocol, f.PortOrName) +} + +func (f ForwardSpec) Port() (int, error) { + if f.Protocol != FProtocolTcp { + return 0, fmt.Errorf("protocal is not tcp") + } + return strconv.Atoi(f.PortOrName) +} + +func (f *ForwardSpec) parseString(s string) error { + fields := strings.Split(s, ":") + if len(fields) != 2 { + return fmt.Errorf("expect string contains only one ':', str = %s", s) + } + f.Protocol = fields[0] + f.PortOrName = fields[1] + return nil +} + +type ForwardPair struct { + Serial string + Local ForwardSpec + Remote ForwardSpec +} + +// ForwardList returns list with struct ForwardPair +// If no device serial specified all devices's forward list will returned +func (c *Device) ForwardList() (fs []ForwardPair, err error) { + attr, err := c.getAttribute("list-forward") + if err != nil { + return nil, err + } + fields := strings.Fields(attr) + if len(fields)%3 != 0 { + return nil, fmt.Errorf("list forward parse error") + } + fs = make([]ForwardPair, 0) + for i := 0; i < len(fields)/3; i++ { + var local, remote ForwardSpec + var serial = fields[i*3] + // skip other device serial forwards + if c.descriptor.descriptorType == DeviceSerial && c.descriptor.serial != serial { + continue + } + if err = local.parseString(fields[i*3+1]); err != nil { + return nil, err + } + if err = remote.parseString(fields[i*3+2]); err != nil { + return nil, err + } + fs = append(fs, ForwardPair{serial, local, remote}) + } + return fs, nil +} + +// ForwardRemove specified forward +func (c *Device) ForwardRemove(local ForwardSpec) error { + err := roundTripSingleNoResponse(c.server, + fmt.Sprintf("%s:killforward:%v", c.descriptor.getHostPrefix(), local)) + return wrapClientError(err, c, "ForwardRemove") +} + +// ForwardRemoveAll cancel all exists forwards +func (c *Device) ForwardRemoveAll() error { + err := roundTripSingleNoResponse(c.server, + fmt.Sprintf("%s:killforward-all", c.descriptor.getHostPrefix())) + return wrapClientError(err, c, "ForwardRemoveAll") +} + +// Forward remote connection to local +func (c *Device) Forward(local, remote ForwardSpec) error { + err := roundTripSingleNoResponse(c.server, + fmt.Sprintf("%s:forward:%v;%v", c.descriptor.getHostPrefix(), local, remote)) + return wrapClientError(err, c, "Forward") +} + +// ForwardToFreePort return random generated port +// If forward already exists, just return current forworded port +func (c *Device) ForwardToFreePort(remote ForwardSpec) (port int, err error) { + fws, err := c.ForwardList() + if err != nil { + return + } + for _, fw := range fws { + if fw.Remote == remote { + return fw.Local.Port() + } + } + port, err = getFreePort() + if err != nil { + return + } + err = c.Forward(ForwardSpec{FProtocolTcp, strconv.Itoa(port)}, remote) + return +} + +func (c *Device) DeviceInfo() (*DeviceInfo, error) { + // Adb doesn't actually provide a way to get this for an individual device, + // so we have to just list devices and find ourselves. + + serial, err := c.Serial() + if err != nil { + return nil, wrapClientError(err, c, "GetDeviceInfo(GetSerial)") + } + + devices, err := c.deviceListFunc() + if err != nil { + return nil, wrapClientError(err, c, "DeviceInfo(ListDevices)") + } + + for _, deviceInfo := range devices { + if deviceInfo.Serial == serial { + return deviceInfo, nil + } + } + + err = errors.Errorf(errors.DeviceNotFound, "device list doesn't contain serial %s", serial) + return nil, wrapClientError(err, c, "DeviceInfo") +} + +/* +RunCommand runs the specified commands on a shell on the device. + +From the Android docs: + Run 'command arg1 arg2 ...' in a shell on the device, and return + its output and error streams. Note that arguments must be separated + by spaces. If an argument contains a space, it must be quoted with + double-quotes. Arguments cannot contain double quotes or things + will go very wrong. + + Note that this is the non-interactive version of "adb shell" +Source: https://android.googlesource.com/platform/system/core/+/master/adb/SERVICES.TXT + +This method quotes the arguments for you, and will return an error if any of them +contain double quotes. + +Because the adb shell converts all "\n" into "\r\n", +so here we convert it back (maybe not good for binary output) +*/ +func (c *Device) RunCommand(cmd string, args ...string) (string, error) { + conn, err := c.OpenCommand(cmd, args...) + if err != nil { + return "", err + } + + defer conn.Close() + resp, err := conn.ReadUntilEof() + if err != nil { + return "", wrapClientError(err, c, "RunCommand") + } + outStr := strings.Replace(string(resp), "\r\n", "\n", -1) + return outStr, nil +} + +func (c *Device) OpenCommand(cmd string, args ...string) (conn *wire.Conn, err error) { + cmd, err = prepareCommandLine(cmd, args...) + if err != nil { + return nil, wrapClientError(err, c, "RunCommand") + } + conn, err = c.dialDevice() + if err != nil { + return nil, wrapClientError(err, c, "RunCommand") + } + defer func() { + if err != nil && conn != nil { + conn.Close() + } + }() + + req := fmt.Sprintf("shell:%s", cmd) + + // Shell responses are special, they don't include a length header. + // We read until the stream is closed. + // So, we can't use conn.RoundTripSingleResponse. + if err = conn.SendMessage([]byte(req)); err != nil { + return nil, wrapClientError(err, c, "Command") + } + if _, err = conn.ReadStatus(req); err != nil { + return nil, wrapClientError(err, c, "Command") + } + return conn, nil +} + +func (c *Device) RunCommandInContext(conn *wire.Conn, cmd string, args ...string) (*wire.Conn, string, error) { + conn, err := c.OpenCmdInContext(conn, cmd, args...) + if err != nil { + return nil, "", err + } + + resp, err := conn.ReadUntilEof() + if err != nil { + return nil, "", wrapClientError(err, c, "RunCommand") + } + outStr := strings.Replace(string(resp), "\r\n", "\n", -1) + return conn, outStr, nil +} + +func (c *Device) OpenCmdInContext(conn *wire.Conn, cmd string, args ...string) (*wire.Conn, error) { + cmd, err := prepareCommandLine(cmd, args...) + if err != nil { + return nil, wrapClientError(err, c, "RunCommand") + } + if conn == nil { + conn, err = c.dialDevice() + } + if err != nil { + return nil, wrapClientError(err, c, "RunCommand") + } + + req := fmt.Sprintf("shell:%s", cmd) + + // Shell responses are special, they don't include a length header. + // We read until the stream is closed. + // So, we can't use conn.RoundTripSingleResponse. + if err = conn.SendMessage([]byte(req)); err != nil { + return nil, wrapClientError(err, c, "Command") + } + if _, err = conn.ReadStatus(req); err != nil { + return nil, wrapClientError(err, c, "Command") + } + + return conn, nil +} + +/* +Remount, from the official adb command’s docs: + Ask adbd to remount the device's filesystem in read-write mode, + instead of read-only. This is usually necessary before performing + an "adb sync" or "adb push" request. + This request may not succeed on certain builds which do not allow + that. +Source: https://android.googlesource.com/platform/system/core/+/master/adb/SERVICES.TXT +*/ +func (c *Device) Remount() (string, error) { + conn, err := c.dialDevice() + if err != nil { + return "", wrapClientError(err, c, "Remount") + } + defer conn.Close() + + resp, err := conn.RoundTripSingleResponse([]byte("remount")) + return string(resp), wrapClientError(err, c, "Remount") +} + +func (c *Device) ListDirEntries(path string) (*DirEntries, error) { + conn, err := c.getSyncConn() + if err != nil { + return nil, wrapClientError(err, c, "ListDirEntries(%s)", path) + } + + entries, err := listDirEntries(conn, path) + return entries, wrapClientError(err, c, "ListDirEntries(%s)", path) +} + +func (c *Device) Stat(path string) (*DirEntry, error) { + conn, err := c.getSyncConn() + if err != nil { + return nil, wrapClientError(err, c, "Stat(%s)", path) + } + defer conn.Close() + + entry, err := stat(conn, path) + return entry, wrapClientError(err, c, "Stat(%s)", path) +} + +func (c *Device) OpenRead(path string) (io.ReadCloser, error) { + conn, err := c.getSyncConn() + if err != nil { + return nil, wrapClientError(err, c, "OpenRead(%s)", path) + } + + reader, err := receiveFile(conn, path) + return reader, wrapClientError(err, c, "OpenRead(%s)", path) +} + +// OpenWrite opens the file at path on the device, creating it with the permissions specified +// by perms if necessary, and returns a writer that writes to the file. +// The files modification time will be set to mtime when the WriterCloser is closed. The zero value +// is TimeOfClose, which will use the time the Close method is called as the modification time. +func (c *Device) OpenWrite(path string, perms os.FileMode, mtime time.Time) (io.WriteCloser, error) { + conn, err := c.getSyncConn() + if err != nil { + return nil, wrapClientError(err, c, "OpenWrite(%s)", path) + } + + writer, err := sendFile(conn, path, perms, mtime) + return writer, wrapClientError(err, c, "OpenWrite(%s)", path) +} + +// getAttribute returns the first message returned by the server by running +// :, where host-prefix is determined from the DeviceDescriptor. +func (c *Device) getAttribute(attr string) (string, error) { + resp, err := roundTripSingleResponse(c.server, + fmt.Sprintf("%s:%s", c.descriptor.getHostPrefix(), attr)) + if err != nil { + return "", err + } + return string(resp), nil +} + +func (c *Device) getSyncConn() (*wire.SyncConn, error) { + conn, err := c.dialDevice() + if err != nil { + return nil, err + } + + // Switch the connection to sync mode. + if err := wire.SendMessageString(conn, "sync:"); err != nil { + return nil, err + } + if _, err := conn.ReadStatus("sync"); err != nil { + return nil, err + } + + return conn.NewSyncConn(), nil +} + +// dialDevice switches the connection to communicate directly with the device +// by requesting the transport defined by the DeviceDescriptor. +func (c *Device) dialDevice() (*wire.Conn, error) { + conn, err := c.server.Dial() + if err != nil { + return nil, err + } + + req := fmt.Sprintf("host:%s", c.descriptor.getTransportDescriptor()) + if err = wire.SendMessageString(conn, req); err != nil { + conn.Close() + return nil, errors.WrapErrf(err, "error connecting to device '%s'", c.descriptor) + } + + if _, err = conn.ReadStatus(req); err != nil { + conn.Close() + return nil, err + } + + return conn, nil +} + +func (c *Device) Dial() (*wire.Conn, error) { + return c.dialDevice() +} + +// prepareCommandLine validates the command and argument strings, quotes +// arguments if required, and joins them into a valid adb command string. +func prepareCommandLine(cmd string, args ...string) (string, error) { + if isBlank(cmd) { + return "", errors.AssertionErrorf("command cannot be empty") + } + + for i, arg := range args { + if strings.ContainsRune(arg, '"') { + return "", errors.Errorf(errors.ParseError, "arg at index %d contains an invalid double quote: %s", i, arg) + } + if containsWhitespace(arg) { + args[i] = fmt.Sprintf("\"%s\"", arg) + } + } + + // Prepend the command to the args array. + if len(args) > 0 { + cmd = fmt.Sprintf("%s %s", cmd, strings.Join(args, " ")) + } + + return cmd, nil +} + +func (c *Device) Push(localPath, remotePath string) int64 { + if remotePath == "" { + return 1 + } + + var ( + localFile io.ReadCloser + size int + perms os.FileMode + mtime time.Time + ) + if localPath == "" { + localFile = os.Stdin + // 0 size will hide the progress bar. + perms = os.FileMode(0660) + mtime = MtimeOfClose + } else { + var err error + localFile, err = os.Open(localPath) + if err != nil { + fmt.Fprintf(os.Stderr, "error opening local file %s: %s\n", localPath, err) + return 1 + } + info, err := os.Stat(localPath) + if err != nil { + fmt.Fprintf(os.Stderr, "error reading local file %s: %s\n", localPath, err) + return 1 + } + size = int(info.Size()) + perms = info.Mode().Perm() + mtime = info.ModTime() + } + defer localFile.Close() + + client := c + writer, err := client.OpenWrite(remotePath, perms, mtime) + if err != nil { + fmt.Fprintf(os.Stderr, "error opening remote file %s: %s\n", remotePath, err) + return 1 + } + defer writer.Close() + + n, err := io.Copy(writer, localFile) + /*if err := copyWithProgressAndStats(writer, localFile, size, showProgress); err != nil { + fmt.Fprintln(os.Stderr, "error pushing file:", err) + return 1 + }*/ + if n == int64(size) { + return 0 + } else { + return n + } +} + +func (c *Device) Pull(remotePath, localPath string) (int64, error) { + if remotePath == "" { + fmt.Fprintln(os.Stderr, "error: must specify remote file") + return 0, fmt.Errorf("error: must specify remote file") + } + + if localPath == "" { + localPath = filepath.Base(remotePath) + } + + client := c + // client := client.Device(device) + + info, err := client.Stat(remotePath) + if HasErrCode(err, ErrCode(FileNoExistError)) { + // fmt.Fprintf(os.Stderr, "file %v does not exist on device ", remotePath) + return 0, err + } else if err != nil { + // fmt.Fprintf(os.Stderr, "error reading remote file %s: %s\n", remotePath, err) + return 0, err + } + + remoteFile, err := client.OpenRead(remotePath) + if err != nil { + fmt.Fprintf(os.Stderr, "error opening remote file %s: %s\n", remotePath, ErrorWithCauseChain(err)) + return 0, err + } + defer remoteFile.Close() + + var localFile io.WriteCloser + localFile, err = os.Create(localPath) + if err != nil { + fmt.Fprintf(os.Stderr, "error opening local file %s: %s\n", localPath, err) + return 0, err + } + defer localFile.Close() + + n, err := io.Copy(localFile, remoteFile) + if err != nil { + fmt.Fprintln(os.Stderr, "error pulling file:", err) + return 0, err + } + + if n == int64(info.Size) { + return int64(info.Size), nil + } else { + return n, fmt.Errorf("error: file size: %v, pull size: %v", info.Size, n) + } +} diff --git a/vendor/github.com/thinkhy/go-adb/device_descriptor.go b/vendor/github.com/thinkhy/go-adb/device_descriptor.go new file mode 100644 index 000000000..a02cf56fc --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/device_descriptor.go @@ -0,0 +1,80 @@ +package adb + +import "fmt" + +//go:generate stringer -type=deviceDescriptorType +type deviceDescriptorType int + +const ( + // host:transport-any and host: + DeviceAny deviceDescriptorType = iota + // host:transport: and host-serial:: + DeviceSerial + // host:transport-usb and host-usb: + DeviceUsb + // host:transport-local and host-local: + DeviceLocal +) + +type DeviceDescriptor struct { + descriptorType deviceDescriptorType + + // Only used if Type is DeviceSerial. + serial string +} + +func AnyDevice() DeviceDescriptor { + return DeviceDescriptor{descriptorType: DeviceAny} +} + +func AnyUsbDevice() DeviceDescriptor { + return DeviceDescriptor{descriptorType: DeviceUsb} +} + +func AnyLocalDevice() DeviceDescriptor { + return DeviceDescriptor{descriptorType: DeviceLocal} +} + +func DeviceWithSerial(serial string) DeviceDescriptor { + return DeviceDescriptor{ + descriptorType: DeviceSerial, + serial: serial, + } +} + +func (d DeviceDescriptor) String() string { + if d.descriptorType == DeviceSerial { + return fmt.Sprintf("%s[%s]", d.descriptorType, d.serial) + } + return d.descriptorType.String() +} + +func (d DeviceDescriptor) getHostPrefix() string { + switch d.descriptorType { + case DeviceAny: + return "host" + case DeviceUsb: + return "host-usb" + case DeviceLocal: + return "host-local" + case DeviceSerial: + return fmt.Sprintf("host-serial:%s", d.serial) + default: + panic(fmt.Sprintf("invalid DeviceDescriptorType: %v", d.descriptorType)) + } +} + +func (d DeviceDescriptor) getTransportDescriptor() string { + switch d.descriptorType { + case DeviceAny: + return "transport-any" + case DeviceUsb: + return "transport-usb" + case DeviceLocal: + return "transport-local" + case DeviceSerial: + return fmt.Sprintf("transport:%s", d.serial) + default: + panic(fmt.Sprintf("invalid DeviceDescriptorType: %v", d.descriptorType)) + } +} diff --git a/vendor/github.com/thinkhy/go-adb/device_extra.go b/vendor/github.com/thinkhy/go-adb/device_extra.go new file mode 100644 index 000000000..0d1c733fa --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/device_extra.go @@ -0,0 +1,278 @@ +package adb + +import ( + "bufio" + "fmt" + "io" + "math/rand" + "net/http" + "os" + "regexp" + "strconv" + "strings" + "time" + + retryablehttp "github.com/hashicorp/go-retryablehttp" +) + +type Process struct { + User string + Pid int + Name string +} + +// ListProcesses return list of Process +func (c *Device) ListProcesses() (ps []Process, err error) { + reader, err := c.OpenCommand("ps") + if err != nil { + return + } + defer reader.Close() + var fieldNames []string + bufrd := bufio.NewReader(reader) + for { + line, _, err := bufrd.ReadLine() + fields := strings.Fields(strings.TrimSpace(string(line))) + if len(fields) == 0 { + break + } + if err == io.EOF { + break + } + if fieldNames == nil { + fieldNames = fields + continue + } + var process Process + /* example output of command "ps" + USER PID PPID VSIZE RSS WCHAN PC NAME + root 1 0 684 540 ffffffff 00000000 S /init + root 2 0 0 0 ffffffff 00000000 S kthreadd + */ + if len(fields) != len(fieldNames)+1 { + continue + } + for index, name := range fieldNames { + value := fields[index] + switch strings.ToUpper(name) { + case "PID": + process.Pid, _ = strconv.Atoi(value) + case "NAME": + process.Name = fields[len(fields)-1] + case "USER": + process.User = value + } + } + if process.Pid == 0 { + continue + } + ps = append(ps, process) + } + return +} + +// KillProcessByName return if killed success +func (c *Device) KillProcessByName(name string, sig int) error { + ps, err := c.ListProcesses() + if err != nil { + return err + } + for _, p := range ps { + if p.Name != name { + continue + } + // log.Printf("kill %s with pid: %d", p.Name, p.Pid) + _, _, er := c.RunCommandWithExitCode("kill", "-"+strconv.Itoa(sig), strconv.Itoa(p.Pid)) + if er != nil { + return er + } + } + return nil +} + +type PackageInfo struct { + Name string + Path string + Version struct { + Code int + Name string + } +} + +var ( + rePkgPath = regexp.MustCompile(`codePath=([^\s]+)`) + reVerCode = regexp.MustCompile(`versionCode=(\d+)`) + reVerName = regexp.MustCompile(`versionName=([^\s]+)`) +) + +// StatPackage returns PackageInfo +// If package not found, err will be ErrPackageNotExist +func (c *Device) StatPackage(packageName string) (pi PackageInfo, err error) { + pi.Name = packageName + out, err := c.RunCommand("dumpsys", "package", packageName) + if err != nil { + return + } + + matches := rePkgPath.FindStringSubmatch(out) + if len(matches) == 0 { + err = ErrPackageNotExist + return + } + pi.Path = matches[1] + + matches = reVerCode.FindStringSubmatch(out) + if len(matches) == 0 { + err = ErrPackageNotExist + return + } + pi.Version.Code, _ = strconv.Atoi(matches[1]) + + matches = reVerName.FindStringSubmatch(out) + if len(matches) == 0 { + err = ErrPackageNotExist + return + } + pi.Version.Name = matches[1] + return +} + +// Properties extract info from $ adb shell getprop +func (c *Device) Properties() (props map[string]string, err error) { + propOutput, err := c.RunCommand("getprop") + if err != nil { + return nil, err + } + re := regexp.MustCompile(`\[(.*?)\]:\s*\[(.*?)\]`) + matches := re.FindAllStringSubmatch(propOutput, -1) + props = make(map[string]string) + for _, m := range matches { + var key = m[1] + var val = m[2] + props[key] = val + } + return +} + +/* +RunCommandWithExitCode use a little tricky to get exit code + +The tricky is append "; echo :$?" to the command, +and parse out the exit code from output +*/ +func (c *Device) RunCommandWithExitCode(cmd string, args ...string) (string, int, error) { + exArgs := append(args, ";", "echo", ":$?") + outStr, err := c.RunCommand(cmd, exArgs...) + if err != nil { + return outStr, 0, err + } + idx := strings.LastIndexByte(outStr, ':') + if idx == -1 { + return outStr, 0, fmt.Errorf("adb shell aborted, can not parse exit code") + } + exitCode, _ := strconv.Atoi(strings.TrimSpace(outStr[idx+1:])) + if exitCode != 0 { + commandLine, _ := prepareCommandLine(cmd, args...) + err = ShellExitError{commandLine, exitCode} + } + outStr = strings.Replace(outStr[0:idx], "\r\n", "\n", -1) // put somewhere else + return outStr, exitCode, err +} + +type ShellExitError struct { + Command string + ExitCode int +} + +func (s ShellExitError) Error() string { + return fmt.Sprintf("shell %s exit code %d", strconv.Quote(s.Command), s.ExitCode) +} + +// DoWriteFile return an object, use this object can Cancel write and get Process +func (c *Device) DoSyncFile(path string, rd io.ReadCloser, size int64, perms os.FileMode) (aw *AsyncWriter, err error) { + dst, err := c.OpenWrite(path, perms, time.Now()) + if err != nil { + return nil, err + } + awr := newAsyncWriter(c, dst, path, size) + go func() { + awr.doCopy(rd) + rd.Close() + }() + return awr, nil +} + +func (c *Device) DoSyncLocalFile(dst string, src string, perms os.FileMode) (aw *AsyncWriter, err error) { + f, err := os.Open(src) + if err != nil { + return + } + + finfo, err := f.Stat() + if err != nil { + return + } + return c.DoSyncFile(dst, f, finfo.Size(), perms) +} + +func (c *Device) DoSyncHTTPFile(dst string, srcUrl string, perms os.FileMode) (aw *AsyncWriter, err error) { + res, err := retryablehttp.Get(srcUrl) + + if err != nil { + return + } + var length int64 + fmt.Sscanf(res.Header.Get("Content-Length"), "%d", &length) + return c.DoSyncFile(dst, res.Body, length, perms) +} + +// WriteToFile write a reader stream to device +func (c *Device) WriteToFile(path string, rd io.Reader, perms os.FileMode) (written int64, err error) { + dst, err := c.OpenWrite(path, perms, time.Now()) + if err != nil { + return + } + defer func() { + dst.Close() + if err != nil || written == 0 { + return + } + // wait until write finished. + fromTime := time.Now() + for { + if time.Since(fromTime) > time.Second*600 { + err = fmt.Errorf("write file to device timeout (10min)") + return + } + finfo, er := c.Stat(path) + if er != nil && !HasErrCode(er, FileNoExistError) { + err = er + return + } + if finfo == nil { + err = fmt.Errorf("target file %s not created", strconv.Quote(path)) + return + } + if finfo != nil && finfo.Size == int32(written) { + break + } + time.Sleep(time.Duration(200+rand.Intn(100)) * time.Millisecond) + } + }() + written, err = io.Copy(dst, rd) + return +} + +// WriteHttpToFile download http resource to device +func (c *Device) WriteHttpToFile(path string, urlStr string, perms os.FileMode) (written int64, err error) { + res, err := retryablehttp.Get(urlStr) + if err != nil { + return + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + err = fmt.Errorf("http download <%s> status %v", urlStr, res.Status) + return + } + return c.WriteToFile(path, res.Body, perms) +} diff --git a/vendor/github.com/thinkhy/go-adb/device_info.go b/vendor/github.com/thinkhy/go-adb/device_info.go new file mode 100644 index 000000000..317b392ba --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/device_info.go @@ -0,0 +1,93 @@ +package adb + +import ( + "bufio" + "strings" + + "github.com/thinkhy/go-adb/internal/errors" +) + +type DeviceInfo struct { + // Always set. + Serial string + Status string + + // Product, device, and model are not set in the short form. + Product string + Model string + DeviceInfo string + + // Only set for devices connected via USB. + Usb string +} + +// IsUsb returns true if the device is connected via USB. +func (d *DeviceInfo) IsUsb() bool { + return d.Usb != "" +} + +func newDevice(serial string, status string, attrs map[string]string) (*DeviceInfo, error) { + if serial == "" { + return nil, errors.AssertionErrorf("device serial cannot be blank") + } + + return &DeviceInfo{ + Serial: serial, + Status: status, + Product: attrs["product"], + Model: attrs["model"], + DeviceInfo: attrs["device"], + Usb: attrs["usb"], + }, nil +} + +func parseDeviceList(list string, lineParseFunc func(string) (*DeviceInfo, error)) ([]*DeviceInfo, error) { + devices := []*DeviceInfo{} + scanner := bufio.NewScanner(strings.NewReader(list)) + + for scanner.Scan() { + device, err := lineParseFunc(scanner.Text()) + if err != nil { + return nil, err + } + devices = append(devices, device) + } + + return devices, nil +} + +func parseDeviceShort(line string) (*DeviceInfo, error) { + fields := strings.Fields(line) + if len(fields) != 2 { + return nil, errors.Errorf(errors.ParseError, + "malformed device line, expected 2 fields but found %d", len(fields)) + } + + return newDevice(fields[0], fields[1], map[string]string{}) +} + +func parseDeviceLong(line string) (*DeviceInfo, error) { + fields := strings.Fields(line) + if len(fields) < 5 { + return nil, errors.Errorf(errors.ParseError, + "malformed device line, expected at least 5 fields but found %d", len(fields)) + } + + attrs := parseDeviceAttributes(fields[2:]) + return newDevice(fields[0], fields[1], attrs) +} + +func parseDeviceAttributes(fields []string) map[string]string { + attrs := map[string]string{} + for _, field := range fields { + key, val := parseKeyVal(field) + attrs[key] = val + } + return attrs +} + +// Parses a key:val pair and returns key, val. +func parseKeyVal(pair string) (string, string) { + split := strings.Split(pair, ":") + return split[0], split[1] +} diff --git a/vendor/github.com/thinkhy/go-adb/device_state.go b/vendor/github.com/thinkhy/go-adb/device_state.go new file mode 100644 index 000000000..4b773fdff --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/device_state.go @@ -0,0 +1,36 @@ +package adb + +import "github.com/thinkhy/go-adb/internal/errors" + +// DeviceState represents one of the 3 possible states adb will report devices. +// A device can be communicated with when it's in StateOnline. +// A USB device will make the following state transitions: +// Plugged in: StateDisconnected->StateOffline->StateOnline +// Unplugged: StateOnline->StateDisconnected +//go:generate stringer -type=DeviceState +type DeviceState int8 + +const ( + StateInvalid DeviceState = iota + StateUnauthorized + StateDisconnected + StateOffline + StateConnecting + StateOnline +) + +var deviceStateStrings = map[string]DeviceState{ + "": StateDisconnected, + "offline": StateOffline, + "connecting": StateConnecting, + "device": StateOnline, + "unauthorized": StateUnauthorized, +} + +func parseDeviceState(str string) (DeviceState, error) { + state, ok := deviceStateStrings[str] + if !ok { + return StateInvalid, errors.Errorf(errors.ParseError, "invalid device state: %q", state) + } + return state, nil +} diff --git a/vendor/github.com/thinkhy/go-adb/device_watcher.go b/vendor/github.com/thinkhy/go-adb/device_watcher.go new file mode 100644 index 000000000..843dd02d7 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/device_watcher.go @@ -0,0 +1,233 @@ +package adb + +import ( + "log" + "math/rand" + "runtime" + "strings" + "sync/atomic" + "time" + + "github.com/thinkhy/go-adb/internal/errors" + "github.com/thinkhy/go-adb/wire" +) + +/* +DeviceWatcher publishes device status change events. +If the server dies while listening for events, it restarts the server. +*/ +type DeviceWatcher struct { + *deviceWatcherImpl +} + +// DeviceStateChangedEvent represents a device state transition. +// Contains the device’s old and new states, but also provides methods to query the +// type of state transition. +type DeviceStateChangedEvent struct { + Serial string + OldState DeviceState + NewState DeviceState +} + +// CameOnline returns true if this event represents a device coming online. +func (s DeviceStateChangedEvent) CameOnline() bool { + return s.OldState != StateOnline && s.NewState == StateOnline +} + +// WentOffline returns true if this event represents a device going offline. +func (s DeviceStateChangedEvent) WentOffline() bool { + return s.OldState == StateOnline && s.NewState != StateOnline +} + +type deviceWatcherImpl struct { + server server + + // If an error occurs, it is stored here and eventChan is close immediately after. + err atomic.Value + + eventChan chan DeviceStateChangedEvent +} + +func newDeviceWatcher(server server) *DeviceWatcher { + watcher := &DeviceWatcher{&deviceWatcherImpl{ + server: server, + eventChan: make(chan DeviceStateChangedEvent), + }} + + runtime.SetFinalizer(watcher, func(watcher *DeviceWatcher) { + watcher.Shutdown() + }) + + go publishDevices(watcher.deviceWatcherImpl) + + return watcher +} + +/* +C returns a channel than can be received on to get events. +If an unrecoverable error occurs, or Shutdown is called, the channel will be closed. +*/ +func (w *DeviceWatcher) C() <-chan DeviceStateChangedEvent { + return w.eventChan +} + +// Err returns the error that caused the channel returned by C to be closed, if C is closed. +// If C is not closed, its return value is undefined. +func (w *DeviceWatcher) Err() error { + if err, ok := w.err.Load().(error); ok { + return err + } + return nil +} + +// Shutdown stops the watcher from listening for events and closes the channel returned +// from C. +func (w *DeviceWatcher) Shutdown() { + // TODO(z): Implement. +} + +func (w *deviceWatcherImpl) reportErr(err error) { + w.err.Store(err) +} + +/* +publishDevices reads device lists from scanner, calculates diffs, and publishes events on +eventChan. +Returns when scanner returns an error. +Doesn't refer directly to a *DeviceWatcher so it can be GCed (which will, +in turn, close Scanner and stop this goroutine). + +TODO: to support shutdown, spawn a new goroutine each time a server connection is established. +This goroutine should read messages and send them to a message channel. Can write errors directly +to errVal. publishDevicesUntilError should take the msg chan and the scanner and select on the msg chan and stop chan, and if the stop +chan sends, close the scanner and return true. If the msg chan closes, just return false. +publishDevices can look at ret val: if false and err == EOF, reconnect. If false and other error, report err +and abort. If true, report no error and stop. +*/ +func publishDevices(watcher *deviceWatcherImpl) { + defer close(watcher.eventChan) + + var lastKnownStates map[string]DeviceState + finished := false + + for { + scanner, err := connectToTrackDevices(watcher.server) + if err != nil { + watcher.reportErr(err) + return + } + + finished, err = publishDevicesUntilError(scanner, watcher.eventChan, &lastKnownStates) + + if finished { + scanner.Close() + return + } + + if HasErrCode(err, ConnectionResetError) { + // The server died, restart and reconnect. + + // Delay by a random [0ms, 500ms) in case multiple DeviceWatchers are trying to + // start the same server. + delay := time.Duration(rand.Intn(500)) * time.Millisecond + + log.Printf("[DeviceWatcher] server died, restarting in %s…", delay) + time.Sleep(delay) + if err := watcher.server.Start(); err != nil { + log.Println("[DeviceWatcher] error restarting server, giving up") + watcher.reportErr(err) + return + } // Else server should be running, continue listening. + } else { + // Unknown error, don't retry. + watcher.reportErr(err) + return + } + } +} + +func connectToTrackDevices(server server) (wire.Scanner, error) { + conn, err := server.Dial() + if err != nil { + return nil, err + } + + if err := wire.SendMessageString(conn, "host:track-devices"); err != nil { + conn.Close() + return nil, err + } + + if _, err := conn.ReadStatus("host:track-devices"); err != nil { + conn.Close() + return nil, err + } + + return conn, nil +} + +func publishDevicesUntilError(scanner wire.Scanner, eventChan chan<- DeviceStateChangedEvent, lastKnownStates *map[string]DeviceState) (finished bool, err error) { + for { + msg, err := scanner.ReadMessage() + if err != nil { + return false, err + } + + deviceStates, err := parseDeviceStates(string(msg)) + if err != nil { + return false, err + } + + for _, event := range calculateStateDiffs(*lastKnownStates, deviceStates) { + eventChan <- event + } + *lastKnownStates = deviceStates + } +} + +func parseDeviceStates(msg string) (states map[string]DeviceState, err error) { + states = make(map[string]DeviceState) + + for lineNum, line := range strings.Split(msg, "\n") { + if len(line) == 0 { + continue + } + + fields := strings.Split(line, "\t") + if len(fields) != 2 { + err = errors.Errorf(errors.ParseError, "invalid device state line %d: %s", lineNum, line) + return + } + + serial, stateString := fields[0], fields[1] + var state DeviceState + state, err = parseDeviceState(stateString) + states[serial] = state + } + + return +} + +func calculateStateDiffs(oldStates, newStates map[string]DeviceState) (events []DeviceStateChangedEvent) { + for serial, oldState := range oldStates { + newState, ok := newStates[serial] + + if oldState != newState { + if ok { + // Device present in both lists: state changed. + events = append(events, DeviceStateChangedEvent{serial, oldState, newState}) + } else { + // Device only present in old list: device removed. + events = append(events, DeviceStateChangedEvent{serial, oldState, StateDisconnected}) + } + } + } + + for serial, newState := range newStates { + if _, ok := oldStates[serial]; !ok { + // Device only present in new list: device added. + events = append(events, DeviceStateChangedEvent{serial, StateDisconnected, newState}) + } + } + + return events +} diff --git a/vendor/github.com/thinkhy/go-adb/devicedescriptortype_string.go b/vendor/github.com/thinkhy/go-adb/devicedescriptortype_string.go new file mode 100644 index 000000000..89a4e3df1 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/devicedescriptortype_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type=deviceDescriptorType"; DO NOT EDIT + +package adb + +import "fmt" + +const _deviceDescriptorType_name = "DeviceAnyDeviceSerialDeviceUsbDeviceLocal" + +var _deviceDescriptorType_index = [...]uint8{0, 9, 21, 30, 41} + +func (i deviceDescriptorType) String() string { + if i < 0 || i >= deviceDescriptorType(len(_deviceDescriptorType_index)-1) { + return fmt.Sprintf("deviceDescriptorType(%d)", i) + } + return _deviceDescriptorType_name[_deviceDescriptorType_index[i]:_deviceDescriptorType_index[i+1]] +} diff --git a/vendor/github.com/thinkhy/go-adb/devicestate_string.go b/vendor/github.com/thinkhy/go-adb/devicestate_string.go new file mode 100644 index 000000000..9bc6e1ccc --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/devicestate_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type=DeviceState"; DO NOT EDIT + +package adb + +import "fmt" + +const _DeviceState_name = "StateInvalidStateUnauthorizedStateDisconnectedStateOfflineStateOnline" + +var _DeviceState_index = [...]uint8{0, 12, 29, 46, 58, 69} + +func (i DeviceState) String() string { + if i < 0 || i >= DeviceState(len(_DeviceState_index)-1) { + return fmt.Sprintf("DeviceState(%d)", i) + } + return _DeviceState_name[_DeviceState_index[i]:_DeviceState_index[i+1]] +} diff --git a/vendor/github.com/thinkhy/go-adb/dialer.go b/vendor/github.com/thinkhy/go-adb/dialer.go new file mode 100644 index 000000000..ab4f96e0b --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/dialer.go @@ -0,0 +1,44 @@ +package adb + +import ( + "io" + "net" + "runtime" + + "github.com/thinkhy/go-adb/internal/errors" + "github.com/thinkhy/go-adb/wire" +) + +// Dialer knows how to create connections to an adb server. +type Dialer interface { + Dial(address string) (*wire.Conn, error) +} + +type tcpDialer struct{} + +// Dial connects to the adb server on the host and port set on the netDialer. +// The zero-value will connect to the default, localhost:5037. +func (tcpDialer) Dial(address string) (*wire.Conn, error) { + netConn, err := net.Dial("tcp", address) + + if err != nil { + return nil, errors.WrapErrorf(err, errors.ServerNotAvailable, "error dialing %s", address) + } + + // net.Conn can't be closed more than once, but wire.Conn will try to close both sender and scanner + // so we need to wrap it to make it safe. + safeConn := wire.MultiCloseable(netConn) + + // Prevent leaking the network connection, not sure if TCPConn does this itself. + // Note that the network connection may still be in use after the conn isn't (scanners/senders + // can give their underlying connections to other scanner/sender types), so we can't + // set the finalizer on conn. + runtime.SetFinalizer(safeConn, func(conn io.ReadWriteCloser) { + conn.Close() + }) + + return &wire.Conn{ + Scanner: wire.NewScanner(safeConn), + Sender: wire.NewSender(safeConn), + }, nil +} diff --git a/vendor/github.com/thinkhy/go-adb/dir_entries.go b/vendor/github.com/thinkhy/go-adb/dir_entries.go new file mode 100644 index 000000000..f9107b88e --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/dir_entries.go @@ -0,0 +1,119 @@ +package adb + +import ( + "fmt" + "os" + "time" + + "github.com/thinkhy/go-adb/wire" +) + +// DirEntry holds information about a directory entry on a device. +type DirEntry struct { + Name string + Mode os.FileMode + Size int32 + ModifiedAt time.Time +} + +// DirEntries iterates over directory entries. +type DirEntries struct { + scanner wire.SyncScanner + + currentEntry *DirEntry + err error +} + +// ReadAllDirEntries reads all the remaining directory entries into a slice, +// closes self, and returns any error. +// If err is non-nil, result will contain any entries read until the error occurred. +func (entries *DirEntries) ReadAll() (result []*DirEntry, err error) { + defer entries.Close() + + for entries.Next() { + result = append(result, entries.Entry()) + } + err = entries.Err() + + return +} + +func (entries *DirEntries) Next() bool { + if entries.err != nil { + return false + } + + entry, done, err := readNextDirListEntry(entries.scanner) + if err != nil { + entries.err = err + entries.Close() + return false + } + + entries.currentEntry = entry + if done { + entries.Close() + return false + } + + return true +} + +func (entries *DirEntries) Entry() *DirEntry { + return entries.currentEntry +} + +func (entries *DirEntries) Err() error { + return entries.err +} + +// Close closes the connection to the adb. +// Next() will call Close() before returning false. +func (entries *DirEntries) Close() error { + return entries.scanner.Close() +} + +func readNextDirListEntry(s wire.SyncScanner) (entry *DirEntry, done bool, err error) { + status, err := s.ReadStatus("dir-entry") + if err != nil { + return + } + + if status == "DONE" { + done = true + return + } else if status != "DENT" { + err = fmt.Errorf("error reading dir entries: expected dir entry ID 'DENT', but got '%s'", status) + return + } + + mode, err := s.ReadFileMode() + if err != nil { + err = fmt.Errorf("error reading dir entries: error reading file mode: %v", err) + return + } + size, err := s.ReadInt32() + if err != nil { + err = fmt.Errorf("error reading dir entries: error reading file size: %v", err) + return + } + mtime, err := s.ReadTime() + if err != nil { + err = fmt.Errorf("error reading dir entries: error reading file time: %v", err) + return + } + name, err := s.ReadString() + if err != nil { + err = fmt.Errorf("error reading dir entries: error reading file name: %v", err) + return + } + + done = false + entry = &DirEntry{ + Name: name, + Mode: mode, + Size: size, + ModifiedAt: mtime, + } + return +} diff --git a/vendor/github.com/thinkhy/go-adb/doc.go b/vendor/github.com/thinkhy/go-adb/doc.go new file mode 100644 index 000000000..90723f957 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/doc.go @@ -0,0 +1,12 @@ +/* +package adb is a Go interface to the Android Debug Bridge (adb). + +See cmd/demo/demo.go for an example of how to use this library. + +The client/server spec is defined at https://android.googlesource.com/platform/system/core/+/master/adb/OVERVIEW.TXT. + +WARNING This library is under heavy development, and its API is likely to change without notice. +*/ +package adb + +// TODO(z): Write method-specific examples. diff --git a/vendor/github.com/thinkhy/go-adb/error.go b/vendor/github.com/thinkhy/go-adb/error.go new file mode 100644 index 000000000..c1674a836 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/error.go @@ -0,0 +1,38 @@ +package adb + +import "github.com/thinkhy/go-adb/internal/errors" +import sysErrors "errors" + +type ErrCode errors.ErrCode + +var ErrPackageNotExist = sysErrors.New("package not exist") + +const ( + AssertionError = ErrCode(errors.AssertionError) + ParseError = ErrCode(errors.ParseError) + // The server was not available on the requested port. + ServerNotAvailable = ErrCode(errors.ServerNotAvailable) + // General network error communicating with the server. + NetworkError = ErrCode(errors.NetworkError) + // The connection to the server was reset in the middle of an operation. Server probably died. + ConnectionResetError = ErrCode(errors.ConnectionResetError) + // The server returned an error message, but we couldn't parse it. + AdbError = ErrCode(errors.AdbError) + // The server returned a "device not found" error. + DeviceNotFound = ErrCode(errors.DeviceNotFound) + // Tried to perform an operation on a path that doesn't exist on the device. + FileNoExistError = ErrCode(errors.FileNoExistError) +) + +// HasErrCode returns true if err is an *errors.Err and err.Code == code. +func HasErrCode(err error, code ErrCode) bool { + return errors.HasErrCode(err, errors.ErrCode(code)) +} + +/* +ErrorWithCauseChain formats err and all its causes if it's an *errors.Err, else returns +err.Error(). +*/ +func ErrorWithCauseChain(err error) string { + return errors.ErrorWithCauseChain(err) +} diff --git a/vendor/github.com/thinkhy/go-adb/go.mod b/vendor/github.com/thinkhy/go-adb/go.mod new file mode 100644 index 000000000..8a6dd463e --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/go.mod @@ -0,0 +1,21 @@ +module github.com/thinkhy/go-adb + +require ( + github.com/alecthomas/kingpin v2.2.6+incompatible + github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect + github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect + github.com/cheggaaa/pb v2.0.6+incompatible + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.5.2 + github.com/mattn/go-colorable v0.1.0 // indirect + github.com/mattn/go-isatty v0.0.4 // indirect + github.com/stretchr/objx v0.1.1 // indirect + github.com/stretchr/testify v1.3.0 + golang.org/x/sys v0.0.0-20190213121743-983097b1a8a3 + gopkg.in/VividCortex/ewma.v1 v1.1.1 // indirect + gopkg.in/cheggaaa/pb.v2 v2.0.6 // indirect + gopkg.in/fatih/color.v1 v1.7.0 // indirect + gopkg.in/mattn/go-colorable.v0 v0.1.0 // indirect + gopkg.in/mattn/go-isatty.v0 v0.0.4 // indirect + gopkg.in/mattn/go-runewidth.v0 v0.0.4 // indirect +) diff --git a/vendor/github.com/thinkhy/go-adb/go.sum b/vendor/github.com/thinkhy/go-adb/go.sum new file mode 100644 index 000000000..0d754e400 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/go.sum @@ -0,0 +1,42 @@ +github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI= +github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/cheggaaa/pb v2.0.6+incompatible h1:sutSx+mRaNbeJUMCAtyqNWU/tQ0B/xBm+hyb1JQmQYs= +github.com/cheggaaa/pb v2.0.6+incompatible/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-retryablehttp v0.5.2 h1:AoISa4P4IsW0/m4T6St8Yw38gTl5GtBAgfkhYh1xAz4= +github.com/hashicorp/go-retryablehttp v0.5.2/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/mattn/go-colorable v0.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTrb8o= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503 h1:5SvYFrOM3W8Mexn9/oA44Ji7vhXAZQ9hiP+1Q/DMrWg= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190213121743-983097b1a8a3 h1:+KlxhGbYkFs8lMfwKn+2ojry1ID5eBSMXprS2u/wqCE= +golang.org/x/sys v0.0.0-20190213121743-983097b1a8a3/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +gopkg.in/VividCortex/ewma.v1 v1.1.1 h1:tWHEKkKq802K/JT9RiqGCBU5fW3raAPnJGTE9ostZvg= +gopkg.in/VividCortex/ewma.v1 v1.1.1/go.mod h1:TekXuFipeiHWiAlO1+wSS23vTcyFau5u3rxXUSXj710= +gopkg.in/cheggaaa/pb.v2 v2.0.6 h1:L2KAo2l2ZQTzxmh8b9RdQpzgLpK2mX3paGCMJSUugBk= +gopkg.in/cheggaaa/pb.v2 v2.0.6/go.mod h1:0CiZ1p8pvtxBlQpLXkHuUTpdJ1shm3OqCF1QugkjHL4= +gopkg.in/fatih/color.v1 v1.7.0 h1:bYGjb+HezBM6j/QmgBfgm1adxHpzzrss6bj4r9ROppk= +gopkg.in/fatih/color.v1 v1.7.0/go.mod h1:P7yosIhqIl/sX8J8UypY5M+dDpD2KmyfP5IRs5v/fo0= +gopkg.in/mattn/go-colorable.v0 v0.1.0 h1:WYuADWvfvYC07fm8ygYB3LMcsc5CunpxfMGKawHkAos= +gopkg.in/mattn/go-colorable.v0 v0.1.0/go.mod h1:BVJlBXzARQxdi3nZo6f6bnl5yR20/tOL6p+V0KejgSY= +gopkg.in/mattn/go-isatty.v0 v0.0.4 h1:NtS1rQGQr4IaFWBGz4Cz4BhB///gyys4gDVtKA7hIsc= +gopkg.in/mattn/go-isatty.v0 v0.0.4/go.mod h1:wt691ab7g0X4ilKZNmMII3egK0bTxl37fEn/Fwbd8gc= +gopkg.in/mattn/go-runewidth.v0 v0.0.4 h1:r0P71TnzQDlNIcizCqvPSSANoFa3WVGtcNJf3TWurcY= +gopkg.in/mattn/go-runewidth.v0 v0.0.4/go.mod h1:BmXejnxvhwdaATwiJbB1vZ2dtXkQKZGu9yLFCZb4msQ= diff --git a/vendor/github.com/thinkhy/go-adb/internal/errors/errcode_string.go b/vendor/github.com/thinkhy/go-adb/internal/errors/errcode_string.go new file mode 100644 index 000000000..1eea2495e --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/internal/errors/errcode_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type=ErrCode"; DO NOT EDIT + +package errors + +import "fmt" + +const _ErrCode_name = "AssertionErrorParseErrorServerNotAvailableNetworkErrorConnectionResetErrorAdbErrorDeviceNotFoundFileNoExistError" + +var _ErrCode_index = [...]uint8{0, 14, 24, 42, 54, 74, 82, 96, 112} + +func (i ErrCode) String() string { + if i >= ErrCode(len(_ErrCode_index)-1) { + return fmt.Sprintf("ErrCode(%d)", i) + } + return _ErrCode_name[_ErrCode_index[i]:_ErrCode_index[i+1]] +} diff --git a/vendor/github.com/thinkhy/go-adb/internal/errors/error.go b/vendor/github.com/thinkhy/go-adb/internal/errors/error.go new file mode 100644 index 000000000..dba32420f --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/internal/errors/error.go @@ -0,0 +1,188 @@ +package errors + +import ( + "bytes" + "fmt" +) + +/* +Err is the implementation of error that all goadb functions return. + +Best Practice + +External errors should be wrapped using WrapErrorf, as soon as they are known about. + +Intermediate code should pass *Errs up until they will be returned outside the library. +Errors should *not* be wrapped at every return site. + +Just before returning an *Err outside the library, it can be wrapped again, preserving the +ErrCode (e.g. with WrapErrf). +*/ +type Err struct { + // Code is the high-level "type" of error. + Code ErrCode + // Message is a human-readable description of the error. + Message string + // Details is optional, and can be used to associate any auxiliary data with an error. + Details interface{} + // Cause is optional, and points to the more specific error that caused this one. + Cause error +} + +var _ error = &Err{} + +// Keep this in sync with ../error.go. +//go:generate stringer -type=ErrCode +type ErrCode byte + +const ( + AssertionError ErrCode = iota + ParseError + // The server was not available on the requested port. + ServerNotAvailable + // General network error communicating with the server. + NetworkError + // The connection to the server was reset in the middle of an operation. Server probably died. + ConnectionResetError + // The server returned an error message, but we couldn't parse it. + AdbError + // The server returned a "device not found" error. + DeviceNotFound + // Tried to perform an operation on a path that doesn't exist on the device. + FileNoExistError +) + +func Errorf(code ErrCode, format string, args ...interface{}) error { + return &Err{ + Code: code, + Message: fmt.Sprintf(format, args...), + } +} + +/* +WrapErrf returns an *Err that wraps another *Err and has the same ErrCode. +Panics if cause is not an *Err. + +To wrap generic errors, use WrapErrorf. +*/ +func WrapErrf(cause error, format string, args ...interface{}) error { + if cause == nil { + return nil + } + + err := cause.(*Err) + return &Err{ + Code: err.Code, + Message: fmt.Sprintf(format, args...), + Cause: err, + } +} + +// CombineErrs returns an error that wraps all the non-nil errors passed to it. +// If all errors are nil, returns nil. +// If there's only one non-nil error, returns that error without wrapping. +// Else, returns an error with the message and code as passed, with the cause set to an error +// that contains all the non-nil errors and for which Error() returns the concatenation of all their messages. +func CombineErrs(msg string, code ErrCode, errs ...error) error { + var nonNilErrs []error + for _, err := range errs { + if err != nil { + nonNilErrs = append(nonNilErrs, err) + } + } + + switch len(nonNilErrs) { + case 0: + return nil + case 1: + return nonNilErrs[0] + default: + return WrapErrorf(multiError(nonNilErrs), code, "%s", msg) + } +} + +type multiError []error + +func (errs multiError) Error() string { + var buf bytes.Buffer + fmt.Fprintf(&buf, "%d errors: [", len(errs)) + for i, err := range errs { + buf.WriteString(err.Error()) + if i < len(errs)-1 { + buf.WriteString(" ∪ ") + } + } + buf.WriteRune(']') + return buf.String() +} + +/* +WrapErrorf returns an *Err that wraps another arbitrary error with an ErrCode and a message. + +If cause is nil, returns nil, so you can use it like + return util.WrapErrorf(DoSomethingDangerous(), util.NetworkError, "well that didn't work") + +If cause is known to be of type *Err, use WrapErrf. +*/ +func WrapErrorf(cause error, code ErrCode, format string, args ...interface{}) error { + if cause == nil { + return nil + } + + return &Err{ + Code: code, + Message: fmt.Sprintf(format, args...), + Cause: cause, + } +} + +func AssertionErrorf(format string, args ...interface{}) error { + return &Err{ + Code: AssertionError, + Message: fmt.Sprintf(format, args...), + } +} + +func (err *Err) Error() string { + msg := fmt.Sprintf("%s: %s", err.Code, err.Message) + if err.Details != nil { + msg = fmt.Sprintf("%s (%+v)", msg, err.Details) + } + return msg +} + +// HasErrCode returns true if err is an *Err and err.Code == code. +func HasErrCode(err error, code ErrCode) bool { + switch err := err.(type) { + case *Err: + return err.Code == code + default: + return false + } +} + +/* +ErrorWithCauseChain formats err and all its causes if it's an *Err, else returns +err.Error(). +*/ +func ErrorWithCauseChain(err error) string { + var buffer bytes.Buffer + + for { + if wrappedErr, ok := err.(*Err); ok && wrappedErr.Cause != nil { + fmt.Fprintln(&buffer, wrappedErr.Error()) + fmt.Fprint(&buffer, "caused by ") + err = wrappedErr.Cause + } else { + break + } + } + + if err != nil { + buffer.WriteString(err.Error()) + } else { + buffer.WriteString("") + } + + return buffer.String() +} diff --git a/vendor/github.com/thinkhy/go-adb/server.go b/vendor/github.com/thinkhy/go-adb/server.go new file mode 100644 index 000000000..e23f20747 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/server.go @@ -0,0 +1,136 @@ +package adb + +import ( + "fmt" + "os/exec" + "strings" + + "github.com/thinkhy/go-adb/internal/errors" + "github.com/thinkhy/go-adb/wire" +) + +const ( + AdbExecutableName = "adb" + + // Default port the adb server listens on. + AdbPort = 5037 +) + +type ServerConfig struct { + // Path to the adb executable. If empty, the PATH environment variable will be searched. + PathToAdb string + + // Host and port the adb server is listening on. + // If not specified, will use the default port on localhost. + Host string + Port int + + // Dialer used to connect to the adb server. + Dialer + + fs *filesystem +} + +// Server knows how to start the adb server and connect to it. +type server interface { + Start() error + Dial() (*wire.Conn, error) +} + +func roundTripSingleResponse(s server, req string) ([]byte, error) { + conn, err := s.Dial() + if err != nil { + return nil, err + } + defer conn.Close() + + return conn.RoundTripSingleResponse([]byte(req)) +} + +func roundTripSingleNoResponse(s server, req string) error { + conn, err := s.Dial() + if err != nil { + return err + } + defer conn.Close() + return conn.RoundTripSingleNoResponse([]byte(req)) +} + +type realServer struct { + config ServerConfig + + // Caches Host:Port so they don't have to be concatenated for every dial. + address string +} + +func newServer(config ServerConfig) (server, error) { + if config.Dialer == nil { + config.Dialer = tcpDialer{} + } + + if config.Host == "" { + // localhost becames very slow on windows(1s dial delay), use 127.0.0.1 works well + config.Host = "127.0.0.1" + } + if config.Port == 0 { + config.Port = AdbPort + } + + if config.fs == nil { + config.fs = localFilesystem + } + + if config.PathToAdb == "" { + path, err := config.fs.LookPath(AdbExecutableName) + if err != nil { + return nil, errors.WrapErrorf(err, errors.ServerNotAvailable, "could not find %s in PATH", AdbExecutableName) + } + config.PathToAdb = path + } + + return &realServer{ + config: config, + address: fmt.Sprintf("%s:%d", config.Host, config.Port), + }, nil +} + +// Dial tries to connect to the server. If the first attempt fails, tries starting the server before +// retrying. If the second attempt fails, returns the error. +func (s *realServer) Dial() (*wire.Conn, error) { + conn, err := s.config.Dial(s.address) + if err != nil { + // Attempt to start the server and try again. + if err = s.Start(); err != nil { + return nil, errors.WrapErrorf(err, errors.ServerNotAvailable, "error starting server for dial") + } + + conn, err = s.config.Dial(s.address) + if err != nil { + return nil, err + } + } + return conn, nil +} + +// StartServer ensures there is a server running. +func (s *realServer) Start() error { + output, err := s.config.fs.CmdCombinedOutput(s.config.PathToAdb, "start-server") + outputStr := strings.TrimSpace(string(output)) + return errors.WrapErrorf(err, errors.ServerNotAvailable, "error starting server: %s\noutput:\n%s", err, outputStr) +} + +// filesystem abstracts interactions with the local filesystem for testability. +type filesystem struct { + // Wraps exec.LookPath. + LookPath func(string) (string, error) + + // Wraps exec.Command().CombinedOutput() + CmdCombinedOutput func(name string, arg ...string) ([]byte, error) +} + +var localFilesystem = &filesystem{ + LookPath: exec.LookPath, + CmdCombinedOutput: func(name string, arg ...string) ([]byte, error) { + return exec.Command(name, arg...).CombinedOutput() + }, +} diff --git a/vendor/github.com/thinkhy/go-adb/sync_client.go b/vendor/github.com/thinkhy/go-adb/sync_client.go new file mode 100644 index 000000000..e9bb5f14a --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/sync_client.go @@ -0,0 +1,100 @@ +package adb + +import ( + "io" + "os" + "time" + + "github.com/thinkhy/go-adb/internal/errors" + "github.com/thinkhy/go-adb/wire" +) + +var zeroTime = time.Unix(0, 0).UTC() + +func stat(conn *wire.SyncConn, path string) (*DirEntry, error) { + if err := conn.SendOctetString("STAT"); err != nil { + return nil, err + } + if err := conn.SendBytes([]byte(path)); err != nil { + return nil, err + } + + id, err := conn.ReadStatus("stat") + if err != nil { + return nil, err + } + if id != "STAT" { + return nil, errors.Errorf(errors.AssertionError, "expected stat ID 'STAT', but got '%s'", id) + } + + return readStat(conn) +} + +func listDirEntries(conn *wire.SyncConn, path string) (entries *DirEntries, err error) { + if err = conn.SendOctetString("LIST"); err != nil { + return + } + if err = conn.SendBytes([]byte(path)); err != nil { + return + } + + return &DirEntries{scanner: conn}, nil +} + +func receiveFile(conn *wire.SyncConn, path string) (io.ReadCloser, error) { + if err := conn.SendOctetString("RECV"); err != nil { + return nil, err + } + if err := conn.SendBytes([]byte(path)); err != nil { + return nil, err + } + return newSyncFileReader(conn) +} + +// sendFile returns a WriteCloser than will write to the file at path on device. +// The file will be created with permissions specified by mode. +// The file's modified time will be set to mtime, unless mtime is 0, in which case the time the writer is +// closed will be used. +func sendFile(conn *wire.SyncConn, path string, mode os.FileMode, mtime time.Time) (io.WriteCloser, error) { + if err := conn.SendOctetString("SEND"); err != nil { + return nil, err + } + + pathAndMode := encodePathAndMode(path, mode) + if err := conn.SendBytes(pathAndMode); err != nil { + return nil, err + } + + return newSyncFileWriter(conn, mtime), nil +} + +func readStat(s wire.SyncScanner) (entry *DirEntry, err error) { + mode, err := s.ReadFileMode() + if err != nil { + err = errors.WrapErrf(err, "error reading file mode: %v", err) + return + } + size, err := s.ReadInt32() + if err != nil { + err = errors.WrapErrf(err, "error reading file size: %v", err) + return + } + mtime, err := s.ReadTime() + if err != nil { + err = errors.WrapErrf(err, "error reading file time: %v", err) + return + } + + // adb doesn't indicate when a file doesn't exist, but will return all zeros. + // Theoretically this could be an actual file, but that's very unlikely. + if mode == os.FileMode(0) && size == 0 && mtime == zeroTime { + return nil, errors.Errorf(errors.FileNoExistError, "file doesn't exist") + } + + entry = &DirEntry{ + Mode: mode, + Size: size, + ModifiedAt: mtime, + } + return +} diff --git a/vendor/github.com/thinkhy/go-adb/sync_file_reader.go b/vendor/github.com/thinkhy/go-adb/sync_file_reader.go new file mode 100644 index 000000000..304fb3ede --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/sync_file_reader.go @@ -0,0 +1,108 @@ +package adb + +import ( + "io" + + "github.com/thinkhy/go-adb/internal/errors" + "github.com/thinkhy/go-adb/wire" +) + +// syncFileReader wraps a SyncConn that has requested to receive a file. +type syncFileReader struct { + // Reader used to read data from the adb connection. + scanner wire.SyncScanner + + // Reader for the current chunk only. + chunkReader io.Reader + + // False until the DONE chunk is encountered. + eof bool +} + +var _ io.ReadCloser = &syncFileReader{} + +func newSyncFileReader(s wire.SyncScanner) (r io.ReadCloser, err error) { + r = &syncFileReader{ + scanner: s, + } + + // Read the header for the first chunk to consume any errors. + if _, err = r.Read([]byte{}); err != nil { + if err == io.EOF { + // EOF means the file was empty. This still means the file was opened successfully, + // and the next time the caller does a read they'll get the EOF and handle it themselves. + err = nil + } else { + r.Close() + return nil, err + } + } + return +} + +func (r *syncFileReader) Read(buf []byte) (n int, err error) { + if r.eof { + return 0, io.EOF + } + + if r.chunkReader == nil { + chunkReader, err := readNextChunk(r.scanner) + if err != nil { + if err == io.EOF { + // We just read the last chunk, set our flag before passing it up. + r.eof = true + } + return 0, err + } + r.chunkReader = chunkReader + } + + if len(buf) == 0 { + // Read can be called with an empty buffer to read the next chunk and check for errors. + // However, net.Conn.Read seems to return EOF when given an empty buffer, so we need to + // handle that case ourselves. + return 0, nil + } + + n, err = r.chunkReader.Read(buf) + if err == io.EOF { + // End of current chunk, don't return an error, the next chunk will be + // read on the next call to this method. + r.chunkReader = nil + return n, nil + } + + return n, err +} + +func (r *syncFileReader) Close() error { + return r.scanner.Close() +} + +// readNextChunk creates an io.LimitedReader for the next chunk of data, +// and returns io.EOF if the last chunk has been read. +func readNextChunk(r wire.SyncScanner) (io.Reader, error) { + status, err := r.ReadStatus("read-chunk") + if err != nil { + if wire.IsAdbServerErrorMatching(err, readFileNotFoundPredicate) { + return nil, errors.Errorf(errors.FileNoExistError, "no such file or directory") + } + return nil, err + } + + switch status { + case wire.StatusSyncData: + return r.ReadBytes() + case wire.StatusSyncDone: + return nil, io.EOF + default: + return nil, errors.Errorf(errors.AssertionError, "expected chunk id '%s' or '%s', but got '%s'", + wire.StatusSyncData, wire.StatusSyncDone, []byte(status)) + } +} + +// readFileNotFoundPredicate returns true if s is the adb server error message returned +// when trying to open a file that doesn't exist. +func readFileNotFoundPredicate(s string) bool { + return s == "No such file or directory" +} diff --git a/vendor/github.com/thinkhy/go-adb/sync_file_writer.go b/vendor/github.com/thinkhy/go-adb/sync_file_writer.go new file mode 100644 index 000000000..5fe42b393 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/sync_file_writer.go @@ -0,0 +1,86 @@ +package adb + +import ( + "fmt" + "io" + "os" + "time" + + "github.com/thinkhy/go-adb/internal/errors" + "github.com/thinkhy/go-adb/wire" +) + +// syncFileWriter wraps a SyncConn that has requested to send a file. +type syncFileWriter struct { + // The modification time to write in the footer. + // If 0, use the current time. + mtime time.Time + + // Reader used to read data from the adb connection. + sender wire.SyncSender +} + +var _ io.WriteCloser = &syncFileWriter{} + +func newSyncFileWriter(s wire.SyncSender, mtime time.Time) io.WriteCloser { + return &syncFileWriter{ + mtime: mtime, + sender: s, + } +} + +/* +encodePathAndMode encodes a path and file mode as required for starting a send file stream. + +From https://android.googlesource.com/platform/system/core/+/master/adb/SYNC.TXT: + The remote file name is split into two parts separated by the last + comma (","). The first part is the actual path, while the second is a decimal + encoded file mode containing the permissions of the file on device. +*/ +func encodePathAndMode(path string, mode os.FileMode) []byte { + return []byte(fmt.Sprintf("%s,%d", path, uint32(mode.Perm()))) +} + +// Write writes the min of (len(buf), 64k). +func (w *syncFileWriter) Write(buf []byte) (n int, err error) { + written := 0 + + // If buf > 64k we'll have to send multiple chunks. + // TODO Refactor this into something that can coalesce smaller writes into a single chukn. + for len(buf) > 0 { + // Writes < 64k have a one-to-one mapping to chunks. + // If buffer is larger than the max, we'll return the max size and leave it up to the + // caller to handle correctly. + partialBuf := buf + if len(partialBuf) > wire.SyncMaxChunkSize { + partialBuf = partialBuf[:wire.SyncMaxChunkSize] + } + + if err := w.sender.SendOctetString(wire.StatusSyncData); err != nil { + return written, err + } + if err := w.sender.SendBytes(partialBuf); err != nil { + return written, err + } + + written += len(partialBuf) + buf = buf[len(partialBuf):] + } + + return written, nil +} + +func (w *syncFileWriter) Close() error { + if w.mtime.IsZero() { + w.mtime = time.Now() + } + + if err := w.sender.SendOctetString(wire.StatusSyncDone); err != nil { + return errors.WrapErrf(err, "error sending done chunk to close stream") + } + if err := w.sender.SendTime(w.mtime); err != nil { + return errors.WrapErrf(err, "error writing file modification time") + } + + return errors.WrapErrf(w.sender.Close(), "error closing FileWriter") +} diff --git a/vendor/github.com/thinkhy/go-adb/util.go b/vendor/github.com/thinkhy/go-adb/util.go new file mode 100644 index 000000000..bf8f83c62 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/util.go @@ -0,0 +1,59 @@ +package adb + +import ( + "fmt" + "net" + "reflect" + "regexp" + "strconv" + "strings" + + "github.com/thinkhy/go-adb/internal/errors" +) + +var ( + whitespaceRegex = regexp.MustCompile(`^\s*$`) +) + +func containsWhitespace(str string) bool { + return strings.ContainsAny(str, " \t\v") +} + +func isBlank(str string) bool { + return whitespaceRegex.MatchString(str) +} + +func wrapClientError(err error, client interface{}, operation string, args ...interface{}) error { + if err == nil { + return nil + } + if _, ok := err.(*errors.Err); !ok { + panic("err is not a *Err: " + err.Error()) + } + + clientType := reflect.TypeOf(client) + + return &errors.Err{ + Code: err.(*errors.Err).Code, + Cause: err, + Message: fmt.Sprintf("error performing %s on %s", fmt.Sprintf(operation, args...), clientType), + Details: client, + } +} + +// Get a free port. +func getFreePort() (port int, err error) { + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return 0, err + } + defer listener.Close() + + addr := listener.Addr().String() + _, portString, err := net.SplitHostPort(addr) + if err != nil { + return 0, err + } + + return strconv.Atoi(portString) +} diff --git a/vendor/github.com/thinkhy/go-adb/wire/conn.go b/vendor/github.com/thinkhy/go-adb/wire/conn.go new file mode 100644 index 000000000..89ed92116 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/wire/conn.go @@ -0,0 +1,96 @@ +package wire + +import ( + "github.com/thinkhy/go-adb/internal/errors" +) + +const ( + // The official implementation of adb imposes an undocumented 255-byte limit + // on messages. + MaxMessageLength = 255 +) + +/* +Conn is a normal connection to an adb server. + +For most cases, usage looks something like: + conn := wire.Dial() + conn.SendMessage(data) + conn.ReadStatus() == StatusSuccess || StatusFailure + conn.ReadMessage() + conn.Close() + +For some messages, the server will return more than one message (but still a single +status). Generally, after calling ReadStatus once, you should call ReadMessage until +it returns an io.EOF error. Note: the protocol docs seem to suggest that connections will be +kept open for multiple commands, but this is not the case. The official client closes +a connection immediately after its read the response, in most cases. The docs might be +referring to the connection between the adb server and the device, but I haven't confirmed +that. + +For most commands, the server will close the connection after sending the response. +You should still always call Close() when you're done with the connection. +*/ +type Conn struct { + Scanner + Sender +} + +func NewConn(scanner Scanner, sender Sender) *Conn { + return &Conn{scanner, sender} +} + +// NewSyncConn returns connection that can operate in sync mode. +// The connection must already have been switched (by sending the sync command +// to a specific device), or the return connection will return an error. +func (c *Conn) NewSyncConn() *SyncConn { + return &SyncConn{ + SyncScanner: c.Scanner.NewSyncScanner(), + SyncSender: c.Sender.NewSyncSender(), + } +} + +// RoundTripSingleResponse sends a message to the server, and reads a single +// message response. If the reponse has a failure status code, returns it as an error. +func (conn *Conn) RoundTripSingleResponse(req []byte) (resp []byte, err error) { + if err = conn.SendMessage(req); err != nil { + return nil, err + } + + _, err = conn.ReadStatus(string(req)) + if err != nil { + return nil, err + } + + return conn.ReadMessage() +} + +// RoundTripSingleResponse sends a message to the server +// Only read status +func (conn *Conn) RoundTripSingleNoResponse(req []byte) (err error) { + err = conn.SendMessage(req) + if err != nil { + return + } + _, err = conn.ReadStatus(string(req)) + return +} + +func (conn *Conn) Close() error { + errs := struct { + SenderErr error + ScannerErr error + }{ + SenderErr: conn.Sender.Close(), + ScannerErr: conn.Scanner.Close(), + } + + if errs.ScannerErr != nil || errs.SenderErr != nil { + return &errors.Err{ + Code: errors.NetworkError, + Message: "error closing connection", + Details: errs, + } + } + return nil +} diff --git a/vendor/github.com/thinkhy/go-adb/wire/doc.go b/vendor/github.com/thinkhy/go-adb/wire/doc.go new file mode 100644 index 000000000..b16d98165 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/wire/doc.go @@ -0,0 +1,13 @@ +/* +Package wire implements the low-level part of the client/server wire protocol. +It also implements the "sync" wire format for file transfers. + +This package is not intended to be used directly. adb.Adb and adb.Device +use it to abstract away the bit-twiddling details of the protocol. You should only ever +need to work with the goadb package. Also, this package's API may change more frequently +than goadb's. + +The protocol spec can be found at +https://android.googlesource.com/platform/system/core/+/master/adb/OVERVIEW.TXT. +*/ +package wire diff --git a/vendor/github.com/thinkhy/go-adb/wire/filemode.go b/vendor/github.com/thinkhy/go-adb/wire/filemode.go new file mode 100644 index 000000000..9c5525018 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/wire/filemode.go @@ -0,0 +1,33 @@ +package wire + +import "os" + +// ADB file modes seem to only be 16 bits. +// Values are taken from http://linux.die.net/include/bits/stat.h. +const ( + ModeDir uint32 = 0040000 + ModeSymlink = 0120000 + ModeSocket = 0140000 + ModeFifo = 0010000 + ModeCharDevice = 0020000 +) + +func ParseFileModeFromAdb(modeFromSync uint32) (filemode os.FileMode) { + // The ADB filemode uses the permission bits defined in Go's os package, but + // we need to parse the other bits manually. + switch { + case modeFromSync&ModeSymlink == ModeSymlink: + filemode = os.ModeSymlink + case modeFromSync&ModeDir == ModeDir: + filemode = os.ModeDir + case modeFromSync&ModeSocket == ModeSocket: + filemode = os.ModeSocket + case modeFromSync&ModeFifo == ModeFifo: + filemode = os.ModeNamedPipe + case modeFromSync&ModeCharDevice == ModeCharDevice: + filemode = os.ModeCharDevice + } + + filemode |= os.FileMode(modeFromSync).Perm() + return +} diff --git a/vendor/github.com/thinkhy/go-adb/wire/scanner.go b/vendor/github.com/thinkhy/go-adb/wire/scanner.go new file mode 100644 index 000000000..f56111833 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/wire/scanner.go @@ -0,0 +1,187 @@ +package wire + +import ( + "encoding/binary" + "io" + "io/ioutil" + "strconv" + + "github.com/thinkhy/go-adb/internal/errors" +) + +// TODO(zach): All EOF errors returned from networoking calls should use ConnectionResetError. + +// StatusCodes are returned by the server. If the code indicates failure, the +// next message will be the error. +const ( + StatusSuccess string = "OKAY" + StatusFailure = "FAIL" + StatusSyncData = "DATA" + StatusSyncDone = "DONE" + StatusNone = "" +) + +func isFailureStatus(status string) bool { + return status == StatusFailure +} + +type StatusReader interface { + // Reads a 4-byte status string and returns it. + // If the status string is StatusFailure, reads the error message from the server + // and returns it as an AdbError. + ReadStatus(req string) (string, error) +} + +/* +Scanner reads tokens from a server. +See Conn for more details. +*/ +type Scanner interface { + io.Closer + StatusReader + Read([]byte) (int, error) + ReadMessage() ([]byte, error) + ReadUntilEof() ([]byte, error) + + NewSyncScanner() SyncScanner +} + +type realScanner struct { + reader io.ReadCloser +} + +func NewScanner(r io.ReadCloser) Scanner { + return &realScanner{r} +} + +func ReadMessageString(s Scanner) (string, error) { + msg, err := s.ReadMessage() + if err != nil { + return string(msg), err + } + return string(msg), nil +} + +func (s *realScanner) ReadStatus(req string) (string, error) { + return readStatusFailureAsError(s.reader, req, readHexLength) +} + +func (s *realScanner) ReadMessage() ([]byte, error) { + return readMessage(s.reader, readHexLength) +} + +func (s *realScanner) ReadUntilEof() ([]byte, error) { + data, err := ioutil.ReadAll(s.reader) + if err != nil { + return nil, errors.WrapErrorf(err, errors.NetworkError, "error reading until EOF") + } + return data, nil +} + +// wrap for shell +func (s *realScanner) Read(p []byte) (n int, err error) { + return s.reader.Read(p) +} + +func (s *realScanner) NewSyncScanner() SyncScanner { + return NewSyncScanner(s.reader) +} + +func (s *realScanner) Close() error { + return errors.WrapErrorf(s.reader.Close(), errors.NetworkError, "error closing scanner") +} + +var _ Scanner = &realScanner{} + +// lengthReader is a func that readMessage uses to read message length. +// See readHexLength and readInt32. +type lengthReader func(io.Reader) (int, error) + +// Reads the status, and if failure, reads the message and returns it as an error. +// If the status is success, doesn't read the message. +// req is just used to populate the AdbError, and can be nil. +// messageLengthReader is the function passed to readMessage if the status is failure. +func readStatusFailureAsError(r io.Reader, req string, messageLengthReader lengthReader) (string, error) { + status, err := readOctetString(req, r) + if err != nil { + return "", errors.WrapErrorf(err, errors.NetworkError, "error reading status for %s", req) + } + + if isFailureStatus(status) { + msg, err := readMessage(r, messageLengthReader) + if err != nil { + return "", errors.WrapErrorf(err, errors.NetworkError, + "server returned error for %s, but couldn't read the error message", req) + } + + return "", adbServerError(req, string(msg)) + } + + return status, nil +} + +func readOctetString(description string, r io.Reader) (string, error) { + octet := make([]byte, 4) + n, err := io.ReadFull(r, octet) + + if err == io.ErrUnexpectedEOF { + return "", errIncompleteMessage(description, n, 4) + } else if err != nil { + return "", errors.WrapErrorf(err, errors.NetworkError, "error reading "+description) + } + + return string(octet), nil +} + +// readMessage reads a length from r, then reads length bytes and returns them. +// lengthReader is the function used to read the length. Most operations encode +// length as a hex string (readHexLength), but sync operations use little-endian +// binary encoding (readInt32). +func readMessage(r io.Reader, lengthReader lengthReader) ([]byte, error) { + var err error + + length, err := lengthReader(r) + if err != nil { + return nil, err + } + + data := make([]byte, length) + n, err := io.ReadFull(r, data) + + if err != nil && err != io.ErrUnexpectedEOF { + return data, errors.WrapErrorf(err, errors.NetworkError, "error reading message data") + } else if err == io.ErrUnexpectedEOF { + return data, errIncompleteMessage("message data", n, length) + } + return data, nil +} + +// readHexLength reads the next 4 bytes from r as an ASCII hex-encoded length and parses them into an int. +func readHexLength(r io.Reader) (int, error) { + lengthHex := make([]byte, 4) + n, err := io.ReadFull(r, lengthHex) + if err != nil { + return 0, errIncompleteMessage("length", n, 4) + } + + length, err := strconv.ParseInt(string(lengthHex), 16, 64) + if err != nil { + return 0, errors.WrapErrorf(err, errors.NetworkError, "could not parse hex length %v", lengthHex) + } + + // COMMENT(ssx): comment the below code because I encounter message length > 255 + // Clip the length to 255, as per the Google implementation. + // if length > MaxMessageLength { + // length = MaxMessageLength + // } + + return int(length), nil +} + +// readInt32 reads the next 4 bytes from r as a little-endian integer. +// Returns an int instead of an int32 to match the lengthReader type. +func readInt32(r io.Reader) (int, error) { + var value int32 + err := binary.Read(r, binary.LittleEndian, &value) + return int(value), err +} diff --git a/vendor/github.com/thinkhy/go-adb/wire/sender.go b/vendor/github.com/thinkhy/go-adb/wire/sender.go new file mode 100644 index 000000000..f630ae4f6 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/wire/sender.go @@ -0,0 +1,52 @@ +package wire + +import ( + "fmt" + "io" + + "github.com/thinkhy/go-adb/internal/errors" +) + +// Sender sends messages to the server. +type Sender interface { + Write([]byte) (int, error) + SendMessage(msg []byte) error + NewSyncSender() SyncSender + + Close() error +} + +type realSender struct { + writer io.WriteCloser +} + +func NewSender(w io.WriteCloser) Sender { + return &realSender{w} +} + +func SendMessageString(s Sender, msg string) error { + return s.SendMessage([]byte(msg)) +} + +func (s *realSender) Write(data []byte) (n int, err error) { + return s.writer.Write(data) +} + +func (s *realSender) SendMessage(msg []byte) error { + if len(msg) > MaxMessageLength { + return errors.AssertionErrorf("message length exceeds maximum: %d", len(msg)) + } + + lengthAndMsg := fmt.Sprintf("%04x%s", len(msg), msg) + return writeFully(s.writer, []byte(lengthAndMsg)) +} + +func (s *realSender) NewSyncSender() SyncSender { + return NewSyncSender(s.writer) +} + +func (s *realSender) Close() error { + return errors.WrapErrorf(s.writer.Close(), errors.NetworkError, "error closing sender") +} + +var _ Sender = &realSender{} diff --git a/vendor/github.com/thinkhy/go-adb/wire/sync_conn.go b/vendor/github.com/thinkhy/go-adb/wire/sync_conn.go new file mode 100644 index 000000000..e621ae80d --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/wire/sync_conn.go @@ -0,0 +1,37 @@ +package wire + +import "github.com/thinkhy/go-adb/internal/errors" + +const ( + // Chunks cannot be longer than 64k. + SyncMaxChunkSize = 64 * 1024 +) + +/* +SyncConn is a connection to the adb server in sync mode. +Assumes the connection has been put into sync mode (by sending "sync" in transport mode). + +The adb sync protocol is defined at +https://android.googlesource.com/platform/system/core/+/master/adb/SYNC.TXT. + +Unlike the normal adb protocol (implemented in Conn), the sync protocol is binary. +Lengths are binary-encoded (little-endian) instead of hex. + +Notes on Encoding + +Length headers and other integers are encoded in little-endian, with 32 bits. + +File mode seems to be encoded as POSIX file mode. + +Modification time seems to be the Unix timestamp format, i.e. seconds since Epoch UTC. +*/ +type SyncConn struct { + SyncScanner + SyncSender +} + +// Close closes both the sender and the scanner, and returns any errors. +func (c SyncConn) Close() error { + return errors.CombineErrs("error closing SyncConn", errors.NetworkError, + c.SyncScanner.Close(), c.SyncSender.Close()) +} diff --git a/vendor/github.com/thinkhy/go-adb/wire/sync_scanner.go b/vendor/github.com/thinkhy/go-adb/wire/sync_scanner.go new file mode 100644 index 000000000..94f183c62 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/wire/sync_scanner.go @@ -0,0 +1,92 @@ +package wire + +import ( + "encoding/binary" + "io" + "os" + "time" + + "github.com/thinkhy/go-adb/internal/errors" +) + +type SyncScanner interface { + io.Closer + StatusReader + ReadInt32() (int32, error) + ReadFileMode() (os.FileMode, error) + ReadTime() (time.Time, error) + + // Reads an octet length, followed by length bytes. + ReadString() (string, error) + + // Reads an octet length, and returns a reader that will read length + // bytes (see io.LimitReader). The returned reader should be fully + // read before reading anything off the Scanner again. + ReadBytes() (io.Reader, error) +} + +type realSyncScanner struct { + io.Reader +} + +func NewSyncScanner(r io.Reader) SyncScanner { + return &realSyncScanner{r} +} + +func (s *realSyncScanner) ReadStatus(req string) (string, error) { + return readStatusFailureAsError(s.Reader, req, readInt32) +} + +func (s *realSyncScanner) ReadInt32() (int32, error) { + value, err := readInt32(s.Reader) + return int32(value), errors.WrapErrorf(err, errors.NetworkError, "error reading int from sync scanner") +} +func (s *realSyncScanner) ReadFileMode() (os.FileMode, error) { + var value uint32 + err := binary.Read(s.Reader, binary.LittleEndian, &value) + if err != nil { + return 0, errors.WrapErrorf(err, errors.NetworkError, "error reading filemode from sync scanner") + } + return ParseFileModeFromAdb(value), nil + +} +func (s *realSyncScanner) ReadTime() (time.Time, error) { + seconds, err := s.ReadInt32() + if err != nil { + return time.Time{}, errors.WrapErrorf(err, errors.NetworkError, "error reading time from sync scanner") + } + + return time.Unix(int64(seconds), 0).UTC(), nil +} + +func (s *realSyncScanner) ReadString() (string, error) { + length, err := s.ReadInt32() + if err != nil { + return "", errors.WrapErrorf(err, errors.NetworkError, "error reading length from sync scanner") + } + + bytes := make([]byte, length) + n, rawErr := io.ReadFull(s.Reader, bytes) + if rawErr != nil && rawErr != io.ErrUnexpectedEOF { + return "", errors.WrapErrorf(rawErr, errors.NetworkError, "error reading string from sync scanner") + } else if rawErr == io.ErrUnexpectedEOF { + return "", errIncompleteMessage("bytes", n, int(length)) + } + + return string(bytes), nil +} +func (s *realSyncScanner) ReadBytes() (io.Reader, error) { + length, err := s.ReadInt32() + if err != nil { + return nil, errors.WrapErrorf(err, errors.NetworkError, "error reading bytes from sync scanner") + } + + return io.LimitReader(s.Reader, int64(length)), nil +} + +func (s *realSyncScanner) Close() error { + if closer, ok := s.Reader.(io.Closer); ok { + return errors.WrapErrorf(closer.Close(), errors.NetworkError, "error closing sync scanner") + } + return nil +} diff --git a/vendor/github.com/thinkhy/go-adb/wire/sync_sender.go b/vendor/github.com/thinkhy/go-adb/wire/sync_sender.go new file mode 100644 index 000000000..5d59e781e --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/wire/sync_sender.go @@ -0,0 +1,79 @@ +package wire + +import ( + "encoding/binary" + "io" + "os" + "time" + + "github.com/thinkhy/go-adb/internal/errors" +) + +type SyncSender interface { + io.Closer + + // SendOctetString sends a 4-byte string. + SendOctetString(string) error + SendInt32(int32) error + SendFileMode(os.FileMode) error + SendTime(time.Time) error + + // Sends len(data) as an octet, followed by the bytes. + // If data is bigger than SyncMaxChunkSize, it returns an assertion error. + SendBytes(data []byte) error +} + +type realSyncSender struct { + io.Writer +} + +func NewSyncSender(w io.Writer) SyncSender { + return &realSyncSender{w} +} + +func (s *realSyncSender) SendOctetString(str string) error { + if len(str) != 4 { + return errors.AssertionErrorf("octet string must be exactly 4 bytes: '%s'", str) + } + + wrappedErr := errors.WrapErrorf(writeFully(s.Writer, []byte(str)), + errors.NetworkError, "error sending octet string on sync sender") + + return wrappedErr +} + +func (s *realSyncSender) SendInt32(val int32) error { + return errors.WrapErrorf(binary.Write(s.Writer, binary.LittleEndian, val), + errors.NetworkError, "error sending int on sync sender") +} + +func (s *realSyncSender) SendFileMode(mode os.FileMode) error { + return errors.WrapErrorf(binary.Write(s.Writer, binary.LittleEndian, mode), + errors.NetworkError, "error sending filemode on sync sender") +} + +func (s *realSyncSender) SendTime(t time.Time) error { + return errors.WrapErrorf(s.SendInt32(int32(t.Unix())), + errors.NetworkError, "error sending time on sync sender") +} + +func (s *realSyncSender) SendBytes(data []byte) error { + length := len(data) + if length > SyncMaxChunkSize { + // This limit might not apply to filenames, but it's big enough + // that I don't think it will be a problem. + return errors.AssertionErrorf("data must be <= %d in length", SyncMaxChunkSize) + } + + if err := s.SendInt32(int32(length)); err != nil { + return errors.WrapErrorf(err, errors.NetworkError, "error sending data length on sync sender") + } + return writeFully(s.Writer, data) +} + +func (s *realSyncSender) Close() error { + if closer, ok := s.Writer.(io.Closer); ok { + return errors.WrapErrorf(closer.Close(), errors.NetworkError, "error closing sync sender") + } + return nil +} diff --git a/vendor/github.com/thinkhy/go-adb/wire/util.go b/vendor/github.com/thinkhy/go-adb/wire/util.go new file mode 100644 index 000000000..cab539be2 --- /dev/null +++ b/vendor/github.com/thinkhy/go-adb/wire/util.go @@ -0,0 +1,101 @@ +package wire + +import ( + "fmt" + "io" + "regexp" + "sync" + + "github.com/thinkhy/go-adb/internal/errors" +) + +// ErrorResponseDetails is an error message returned by the server for a particular request. +type ErrorResponseDetails struct { + Request string + ServerMsg string +} + +// deviceNotFoundMessagePattern matches all possible error messages returned by adb servers to +// report that a matching device was not found. Used to set the DeviceNotFound error code on +// error values. +// +// Old servers send "device not found", and newer ones "device 'serial' not found". +var deviceNotFoundMessagePattern = regexp.MustCompile(`device( '.*')? not found`) + +func adbServerError(request string, serverMsg string) error { + var msg string + if request == "" { + msg = fmt.Sprintf("server error: %s", serverMsg) + } else { + msg = fmt.Sprintf("server error for %s request: %s", request, serverMsg) + } + + errCode := errors.AdbError + if deviceNotFoundMessagePattern.MatchString(serverMsg) { + errCode = errors.DeviceNotFound + } + + return &errors.Err{ + Code: errCode, + Message: msg, + Details: ErrorResponseDetails{ + Request: request, + ServerMsg: serverMsg, + }, + } +} + +// IsAdbServerErrorMatching returns true if err is an *Err with code AdbError and for which +// predicate returns true when passed Details.ServerMsg. +func IsAdbServerErrorMatching(err error, predicate func(string) bool) bool { + if err, ok := err.(*errors.Err); ok && err.Code == errors.AdbError { + return predicate(err.Details.(ErrorResponseDetails).ServerMsg) + } + return false +} + +func errIncompleteMessage(description string, actual int, expected int) error { + return &errors.Err{ + Code: errors.ConnectionResetError, + Message: fmt.Sprintf("incomplete %s: read %d bytes, expecting %d", description, actual, expected), + Details: struct { + ActualReadBytes int + ExpectedBytes int + }{ + ActualReadBytes: actual, + ExpectedBytes: expected, + }, + } +} + +// writeFully writes all of data to w. +// Inverse of io.ReadFully(). +func writeFully(w io.Writer, data []byte) error { + offset := 0 + for offset < len(data) { + n, err := w.Write(data[offset:]) + if err != nil { + return errors.WrapErrorf(err, errors.NetworkError, "error writing %d bytes at offset %d", len(data), offset) + } + offset += n + } + return nil +} + +// MultiCloseable wraps c in a ReadWriteCloser that can be safely closed multiple times. +func MultiCloseable(c io.ReadWriteCloser) io.ReadWriteCloser { + return &multiCloseable{ReadWriteCloser: c} +} + +type multiCloseable struct { + io.ReadWriteCloser + closeOnce sync.Once + err error +} + +func (c *multiCloseable) Close() error { + c.closeOnce.Do(func() { + c.err = c.ReadWriteCloser.Close() + }) + return c.err +} diff --git a/vendor/golang.org/x/sys/unix/README.md b/vendor/golang.org/x/sys/unix/README.md index 2bf415fb1..eb2f78ae2 100644 --- a/vendor/golang.org/x/sys/unix/README.md +++ b/vendor/golang.org/x/sys/unix/README.md @@ -32,7 +32,7 @@ To build the files for your current OS and architecture, make sure GOOS and GOARCH are set correctly and run `mkall.sh`. This will generate the files for your specific system. Running `mkall.sh -n` shows the commands that will be run. -Requirements: bash, perl, go +Requirements: bash, go ### New Build System (currently for `GOOS == "linux"`) @@ -52,14 +52,14 @@ system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will then generate all of the files for all of the GOOS/GOARCH pairs in the new build system. Running `mkall.sh -n` shows the commands that will be run. -Requirements: bash, perl, go, docker +Requirements: bash, go, docker ## Component files This section describes the various files used in the code generation process. It also contains instructions on how to modify these files to add a new architecture/OS or to add additional syscalls, types, or constants. Note that -if you are using the new build system, the scripts cannot be called normally. +if you are using the new build system, the scripts/programs cannot be called normally. They must be called from within the docker container. ### asm files @@ -81,8 +81,8 @@ each GOOS/GOARCH pair. ### mksysnum -Mksysnum is a script located at `${GOOS}/mksysnum.pl` (or `mksysnum_${GOOS}.pl` -for the old system). This script takes in a list of header files containing the +Mksysnum is a Go program located at `${GOOS}/mksysnum.go` (or `mksysnum_${GOOS}.go` +for the old system). This program takes in a list of header files containing the syscall number declarations and parses them to produce the corresponding list of Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated constants. @@ -92,14 +92,14 @@ new installation of the target OS (or updating the source checkouts for the new build system). However, depending on the OS, you make need to update the parsing in mksysnum. -### mksyscall.pl +### mksyscall.go The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are hand-written Go files which implement system calls (for unix, the specific OS, or the specific OS/Architecture pair respectively) that need special handling and list `//sys` comments giving prototypes for ones that can be generated. -The mksyscall.pl script takes the `//sys` and `//sysnb` comments and converts +The mksyscall.go program takes the `//sys` and `//sysnb` comments and converts them into syscalls. This requires the name of the prototype in the comment to match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function prototype can be exported (capitalized) or not. @@ -160,7 +160,7 @@ signal numbers, and constants. Generated by `mkerrors.sh` (see above). ### `zsyscall_${GOOS}_${GOARCH}.go` A file containing all the generated syscalls for a specific GOOS and GOARCH. -Generated by `mksyscall.pl` (see above). +Generated by `mksyscall.go` (see above). ### `zsysnum_${GOOS}_${GOARCH}.go` diff --git a/vendor/golang.org/x/sys/unix/mkall.sh b/vendor/golang.org/x/sys/unix/mkall.sh index d74115a8a..75152f99b 100644 --- a/vendor/golang.org/x/sys/unix/mkall.sh +++ b/vendor/golang.org/x/sys/unix/mkall.sh @@ -170,7 +170,7 @@ openbsd_arm) mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" ;; solaris_amd64) - mksyscall="./mksyscall_solaris.pl" + mksyscall="go run mksyscall_solaris.go" mkerrors="$mkerrors -m64" mksysnum= mktypes="GOARCH=$GOARCH go tool cgo -godefs" diff --git a/vendor/golang.org/x/sys/unix/mksyscall.go b/vendor/golang.org/x/sys/unix/mksyscall.go index 890652ca8..e06e4253e 100644 --- a/vendor/golang.org/x/sys/unix/mksyscall.go +++ b/vendor/golang.org/x/sys/unix/mksyscall.go @@ -88,6 +88,10 @@ func parseParam(p string) Param { func main() { // Get the OS and architecture (using GOARCH_TARGET if it exists) goos := os.Getenv("GOOS") + if goos == "" { + fmt.Fprintln(os.Stderr, "GOOS not defined in environment") + os.Exit(1) + } goarch := os.Getenv("GOARCH_TARGET") if goarch == "" { goarch = os.Getenv("GOARCH") diff --git a/vendor/golang.org/x/sys/unix/mksyscall_solaris.go b/vendor/golang.org/x/sys/unix/mksyscall_solaris.go new file mode 100644 index 000000000..3d864738b --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mksyscall_solaris.go @@ -0,0 +1,335 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +/* + This program reads a file containing function prototypes + (like syscall_solaris.go) and generates system call bodies. + The prototypes are marked by lines beginning with "//sys" + and read like func declarations if //sys is replaced by func, but: + * The parameter lists must give a name for each argument. + This includes return parameters. + * The parameter lists must give a type for each argument: + the (x, y, z int) shorthand is not allowed. + * If the return parameter is an error number, it must be named err. + * If go func name needs to be different than its libc name, + * or the function is not in libc, name could be specified + * at the end, after "=" sign, like + //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt +*/ + +package main + +import ( + "bufio" + "flag" + "fmt" + "os" + "regexp" + "strings" +) + +var ( + b32 = flag.Bool("b32", false, "32bit big-endian") + l32 = flag.Bool("l32", false, "32bit little-endian") + tags = flag.String("tags", "", "build tags") +) + +// cmdLine returns this programs's commandline arguments +func cmdLine() string { + return "go run mksyscall_solaris.go " + strings.Join(os.Args[1:], " ") +} + +// buildTags returns build tags +func buildTags() string { + return *tags +} + +// Param is function parameter +type Param struct { + Name string + Type string +} + +// usage prints the program usage +func usage() { + fmt.Fprintf(os.Stderr, "usage: go run mksyscall_solaris.go [-b32 | -l32] [-tags x,y] [file ...]\n") + os.Exit(1) +} + +// parseParamList parses parameter list and returns a slice of parameters +func parseParamList(list string) []string { + list = strings.TrimSpace(list) + if list == "" { + return []string{} + } + return regexp.MustCompile(`\s*,\s*`).Split(list, -1) +} + +// parseParam splits a parameter into name and type +func parseParam(p string) Param { + ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p) + if ps == nil { + fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p) + os.Exit(1) + } + return Param{ps[1], ps[2]} +} + +func main() { + flag.Usage = usage + flag.Parse() + if len(flag.Args()) <= 0 { + fmt.Fprintf(os.Stderr, "no files to parse provided\n") + usage() + } + + endianness := "" + if *b32 { + endianness = "big-endian" + } else if *l32 { + endianness = "little-endian" + } + + pack := "" + text := "" + dynimports := "" + linknames := "" + var vars []string + for _, path := range flag.Args() { + file, err := os.Open(path) + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + os.Exit(1) + } + s := bufio.NewScanner(file) + for s.Scan() { + t := s.Text() + t = strings.TrimSpace(t) + t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `) + if p := regexp.MustCompile(`^package (\S+)$`).FindStringSubmatch(t); p != nil && pack == "" { + pack = p[1] + } + nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t) + if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil { + continue + } + + // Line must be of the form + // func Open(path string, mode int, perm int) (fd int, err error) + // Split into name, in params, out params. + f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$`).FindStringSubmatch(t) + if f == nil { + fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t) + os.Exit(1) + } + funct, inps, outps, modname, sysname := f[2], f[3], f[4], f[5], f[6] + + // Split argument lists on comma. + in := parseParamList(inps) + out := parseParamList(outps) + + inps = strings.Join(in, ", ") + outps = strings.Join(out, ", ") + + // Try in vain to keep people from editing this file. + // The theory is that they jump into the middle of the file + // without reading the header. + text += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" + + // So file name. + if modname == "" { + modname = "libc" + } + + // System call name. + if sysname == "" { + sysname = funct + } + + // System call pointer variable name. + sysvarname := fmt.Sprintf("proc%s", sysname) + + strconvfunc := "BytePtrFromString" + strconvtype := "*byte" + + sysname = strings.ToLower(sysname) // All libc functions are lowercase. + + // Runtime import of function to allow cross-platform builds. + dynimports += fmt.Sprintf("//go:cgo_import_dynamic libc_%s %s \"%s.so\"\n", sysname, sysname, modname) + // Link symbol to proc address variable. + linknames += fmt.Sprintf("//go:linkname %s libc_%s\n", sysvarname, sysname) + // Library proc address variable. + vars = append(vars, sysvarname) + + // Go function header. + outlist := strings.Join(out, ", ") + if outlist != "" { + outlist = fmt.Sprintf(" (%s)", outlist) + } + if text != "" { + text += "\n" + } + text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outlist) + + // Check if err return available + errvar := "" + for _, param := range out { + p := parseParam(param) + if p.Type == "error" { + errvar = p.Name + continue + } + } + + // Prepare arguments to Syscall. + var args []string + n := 0 + for _, param := range in { + p := parseParam(param) + if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { + args = append(args, "uintptr(unsafe.Pointer("+p.Name+"))") + } else if p.Type == "string" && errvar != "" { + text += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) + text += fmt.Sprintf("\t_p%d, %s = %s(%s)\n", n, errvar, strconvfunc, p.Name) + text += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar) + args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) + n++ + } else if p.Type == "string" { + fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n") + text += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) + text += fmt.Sprintf("\t_p%d, _ = %s(%s)\n", n, strconvfunc, p.Name) + args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) + n++ + } else if s := regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type); s != nil { + // Convert slice into pointer, length. + // Have to be careful not to take address of &a[0] if len == 0: + // pass nil in that case. + text += fmt.Sprintf("\tvar _p%d *%s\n", n, s[1]) + text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = &%s[0]\n\t}\n", p.Name, n, p.Name) + args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n), fmt.Sprintf("uintptr(len(%s))", p.Name)) + n++ + } else if p.Type == "int64" && endianness != "" { + if endianness == "big-endian" { + args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name)) + } else { + args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name)) + } + } else if p.Type == "bool" { + text += fmt.Sprintf("\tvar _p%d uint32\n", n) + text += fmt.Sprintf("\tif %s {\n\t\t_p%d = 1\n\t} else {\n\t\t_p%d = 0\n\t}\n", p.Name, n, n) + args = append(args, fmt.Sprintf("uintptr(_p%d)", n)) + n++ + } else { + args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) + } + } + nargs := len(args) + + // Determine which form to use; pad args with zeros. + asm := "sysvicall6" + if nonblock != nil { + asm = "rawSysvicall6" + } + if len(args) <= 6 { + for len(args) < 6 { + args = append(args, "0") + } + } else { + fmt.Fprintf(os.Stderr, "%s: too many arguments to system call\n", path) + os.Exit(1) + } + + // Actual call. + arglist := strings.Join(args, ", ") + call := fmt.Sprintf("%s(uintptr(unsafe.Pointer(&%s)), %d, %s)", asm, sysvarname, nargs, arglist) + + // Assign return values. + body := "" + ret := []string{"_", "_", "_"} + doErrno := false + for i := 0; i < len(out); i++ { + p := parseParam(out[i]) + reg := "" + if p.Name == "err" { + reg = "e1" + ret[2] = reg + doErrno = true + } else { + reg = fmt.Sprintf("r%d", i) + ret[i] = reg + } + if p.Type == "bool" { + reg = fmt.Sprintf("%d != 0", reg) + } + if p.Type == "int64" && endianness != "" { + // 64-bit number in r1:r0 or r0:r1. + if i+2 > len(out) { + fmt.Fprintf(os.Stderr, "%s: not enough registers for int64 return\n", path) + os.Exit(1) + } + if endianness == "big-endian" { + reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i, i+1) + } else { + reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i+1, i) + } + ret[i] = fmt.Sprintf("r%d", i) + ret[i+1] = fmt.Sprintf("r%d", i+1) + } + if reg != "e1" { + body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg) + } + } + if ret[0] == "_" && ret[1] == "_" && ret[2] == "_" { + text += fmt.Sprintf("\t%s\n", call) + } else { + text += fmt.Sprintf("\t%s, %s, %s := %s\n", ret[0], ret[1], ret[2], call) + } + text += body + + if doErrno { + text += "\tif e1 != 0 {\n" + text += "\t\terr = e1\n" + text += "\t}\n" + } + text += "\treturn\n" + text += "}\n" + } + if err := s.Err(); err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + os.Exit(1) + } + file.Close() + } + imp := "" + if pack != "unix" { + imp = "import \"golang.org/x/sys/unix\"\n" + + } + vardecls := "\t" + strings.Join(vars, ",\n\t") + vardecls += " syscallFunc" + fmt.Printf(srcTemplate, cmdLine(), buildTags(), pack, imp, dynimports, linknames, vardecls, text) +} + +const srcTemplate = `// %s +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build %s + +package %s + +import ( + "syscall" + "unsafe" +) +%s +%s +%s +var ( +%s +) + +%s +` diff --git a/vendor/golang.org/x/sys/unix/mksyscall_solaris.pl b/vendor/golang.org/x/sys/unix/mksyscall_solaris.pl deleted file mode 100644 index a354df5a6..000000000 --- a/vendor/golang.org/x/sys/unix/mksyscall_solaris.pl +++ /dev/null @@ -1,294 +0,0 @@ -#!/usr/bin/env perl -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# This program reads a file containing function prototypes -# (like syscall_solaris.go) and generates system call bodies. -# The prototypes are marked by lines beginning with "//sys" -# and read like func declarations if //sys is replaced by func, but: -# * The parameter lists must give a name for each argument. -# This includes return parameters. -# * The parameter lists must give a type for each argument: -# the (x, y, z int) shorthand is not allowed. -# * If the return parameter is an error number, it must be named err. -# * If go func name needs to be different than its libc name, -# * or the function is not in libc, name could be specified -# * at the end, after "=" sign, like -# //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt - -use strict; - -my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV); -my $errors = 0; -my $_32bit = ""; -my $tags = ""; # build tags - -binmode STDOUT; - -if($ARGV[0] eq "-b32") { - $_32bit = "big-endian"; - shift; -} elsif($ARGV[0] eq "-l32") { - $_32bit = "little-endian"; - shift; -} -if($ARGV[0] eq "-tags") { - shift; - $tags = $ARGV[0]; - shift; -} - -if($ARGV[0] =~ /^-/) { - print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [-tags x,y] [file ...]\n"; - exit 1; -} - -sub parseparamlist($) { - my ($list) = @_; - $list =~ s/^\s*//; - $list =~ s/\s*$//; - if($list eq "") { - return (); - } - return split(/\s*,\s*/, $list); -} - -sub parseparam($) { - my ($p) = @_; - if($p !~ /^(\S*) (\S*)$/) { - print STDERR "$ARGV:$.: malformed parameter: $p\n"; - $errors = 1; - return ("xx", "int"); - } - return ($1, $2); -} - -my $package = ""; -my $text = ""; -my $dynimports = ""; -my $linknames = ""; -my @vars = (); -while(<>) { - chomp; - s/\s+/ /g; - s/^\s+//; - s/\s+$//; - $package = $1 if !$package && /^package (\S+)$/; - my $nonblock = /^\/\/sysnb /; - next if !/^\/\/sys / && !$nonblock; - - # Line must be of the form - # func Open(path string, mode int, perm int) (fd int, err error) - # Split into name, in params, out params. - if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) { - print STDERR "$ARGV:$.: malformed //sys declaration\n"; - $errors = 1; - next; - } - my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6); - - # Split argument lists on comma. - my @in = parseparamlist($in); - my @out = parseparamlist($out); - - # Try in vain to keep people from editing this file. - # The theory is that they jump into the middle of the file - # without reading the header. - $text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"; - - # So file name. - if($modname eq "") { - $modname = "libc"; - } - - # System call name. - if($sysname eq "") { - $sysname = "$func"; - } - - # System call pointer variable name. - my $sysvarname = "proc$sysname"; - - my $strconvfunc = "BytePtrFromString"; - my $strconvtype = "*byte"; - - $sysname =~ y/A-Z/a-z/; # All libc functions are lowercase. - - # Runtime import of function to allow cross-platform builds. - $dynimports .= "//go:cgo_import_dynamic libc_${sysname} ${sysname} \"$modname.so\"\n"; - # Link symbol to proc address variable. - $linknames .= "//go:linkname ${sysvarname} libc_${sysname}\n"; - # Library proc address variable. - push @vars, $sysvarname; - - # Go function header. - $out = join(', ', @out); - if($out ne "") { - $out = " ($out)"; - } - if($text ne "") { - $text .= "\n" - } - $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out; - - # Check if err return available - my $errvar = ""; - foreach my $p (@out) { - my ($name, $type) = parseparam($p); - if($type eq "error") { - $errvar = $name; - last; - } - } - - # Prepare arguments to Syscall. - my @args = (); - my $n = 0; - foreach my $p (@in) { - my ($name, $type) = parseparam($p); - if($type =~ /^\*/) { - push @args, "uintptr(unsafe.Pointer($name))"; - } elsif($type eq "string" && $errvar ne "") { - $text .= "\tvar _p$n $strconvtype\n"; - $text .= "\t_p$n, $errvar = $strconvfunc($name)\n"; - $text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; - push @args, "uintptr(unsafe.Pointer(_p$n))"; - $n++; - } elsif($type eq "string") { - print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; - $text .= "\tvar _p$n $strconvtype\n"; - $text .= "\t_p$n, _ = $strconvfunc($name)\n"; - push @args, "uintptr(unsafe.Pointer(_p$n))"; - $n++; - } elsif($type =~ /^\[\](.*)/) { - # Convert slice into pointer, length. - # Have to be careful not to take address of &a[0] if len == 0: - # pass nil in that case. - $text .= "\tvar _p$n *$1\n"; - $text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n"; - push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))"; - $n++; - } elsif($type eq "int64" && $_32bit ne "") { - if($_32bit eq "big-endian") { - push @args, "uintptr($name >> 32)", "uintptr($name)"; - } else { - push @args, "uintptr($name)", "uintptr($name >> 32)"; - } - } elsif($type eq "bool") { - $text .= "\tvar _p$n uint32\n"; - $text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n"; - push @args, "uintptr(_p$n)"; - $n++; - } else { - push @args, "uintptr($name)"; - } - } - my $nargs = @args; - - # Determine which form to use; pad args with zeros. - my $asm = "sysvicall6"; - if ($nonblock) { - $asm = "rawSysvicall6"; - } - if(@args <= 6) { - while(@args < 6) { - push @args, "0"; - } - } else { - print STDERR "$ARGV:$.: too many arguments to system call\n"; - } - - # Actual call. - my $args = join(', ', @args); - my $call = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $args)"; - - # Assign return values. - my $body = ""; - my $failexpr = ""; - my @ret = ("_", "_", "_"); - my @pout= (); - my $do_errno = 0; - for(my $i=0; $i<@out; $i++) { - my $p = $out[$i]; - my ($name, $type) = parseparam($p); - my $reg = ""; - if($name eq "err") { - $reg = "e1"; - $ret[2] = $reg; - $do_errno = 1; - } else { - $reg = sprintf("r%d", $i); - $ret[$i] = $reg; - } - if($type eq "bool") { - $reg = "$reg != 0"; - } - if($type eq "int64" && $_32bit ne "") { - # 64-bit number in r1:r0 or r0:r1. - if($i+2 > @out) { - print STDERR "$ARGV:$.: not enough registers for int64 return\n"; - } - if($_32bit eq "big-endian") { - $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1); - } else { - $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i); - } - $ret[$i] = sprintf("r%d", $i); - $ret[$i+1] = sprintf("r%d", $i+1); - } - if($reg ne "e1") { - $body .= "\t$name = $type($reg)\n"; - } - } - if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") { - $text .= "\t$call\n"; - } else { - $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; - } - $text .= $body; - - if ($do_errno) { - $text .= "\tif e1 != 0 {\n"; - $text .= "\t\terr = e1\n"; - $text .= "\t}\n"; - } - $text .= "\treturn\n"; - $text .= "}\n"; -} - -if($errors) { - exit 1; -} - -print < ../../../github.com/thinkhy/go-adb +github.com/thinkhy/go-adb +github.com/thinkhy/go-adb/wire +github.com/thinkhy/go-adb/internal/errors # github.com/xanzy/ssh-agent v0.2.0 github.com/xanzy/ssh-agent # github.com/yunify/qingstor-sdk-go v2.2.15+incompatible @@ -197,7 +205,7 @@ golang.org/x/oauth2/jws golang.org/x/oauth2/jwt # golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 golang.org/x/sync/errgroup -# golang.org/x/sys v0.0.0-20190204203706-41f3e6584952 +# golang.org/x/sys v0.0.0-20190213121743-983097b1a8a3 golang.org/x/sys/unix golang.org/x/sys/windows # golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2