From 1c01375f5050189bb0cf9681b4d04e7dad2adab6 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Oct 2021 14:02:06 +0200 Subject: [PATCH 01/49] Initial jenkins pipe --- Jenkinsfile | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..304d271c --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,6 @@ +node("test_node") { + + stage('first') { // for display purposes + echo "Its work" + } +} From 39a9f090d2e8a3e77e49ea313c4cc7392d54c89e Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Oct 2021 14:25:04 +0200 Subject: [PATCH 02/49] pull code --- Jenkinsfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 304d271c..3a167cca 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,6 +1,8 @@ node("test_node") { stage('first') { // for display purposes + checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'ssh-hetzner', url: 'git@github.com:h34dl355/example.git']]]) echo "Its work" + sh 'ls -la' } } From 5cb4afaace92dbccc478bf5231b7d23a6816391b Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Oct 2021 14:39:58 +0200 Subject: [PATCH 03/49] pull code --- Jenkinsfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 3a167cca..9aabe15a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,7 +2,10 @@ node("test_node") { stage('first') { // for display purposes checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'ssh-hetzner', url: 'git@github.com:h34dl355/example.git']]]) - echo "Its work" sh 'ls -la' + echo "Git clone done!" + } + stage('second') { + sh 'docker run -v ~/root/example/hello/:/go/src/ golang:latest go build' } } From 3d407de9654edf86b8b9737001327fb4d2492137 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Oct 2021 14:59:40 +0200 Subject: [PATCH 04/49] Fix --- LICENSE | 202 --- README.md | 75 - appengine-hello/README.md | 11 - appengine-hello/app.go | 32 - appengine-hello/app.yaml | 32 - appengine-hello/static/favicon.ico | Bin 1150 -> 0 bytes appengine-hello/static/index.html | 34 - appengine-hello/static/script.js | 24 - appengine-hello/static/style.css | 19 - go.mod | 5 - go.sum | 24 - gotypes/Makefile | 13 - gotypes/README.md | 2554 ---------------------------- gotypes/defsuses/main.go | 68 - gotypes/doc/main.go | 77 - gotypes/go-types.md | 2055 ---------------------- gotypes/hello/hello.go | 10 - gotypes/hugeparam/main.go | 81 - gotypes/implements/main.go | 77 - gotypes/lookup/lookup.go | 77 - gotypes/nilfunc/main.go | 104 -- gotypes/pkginfo/main.go | 64 - gotypes/skeleton/main.go | 115 -- gotypes/typeandvalue/main.go | 134 -- gotypes/weave.go | 191 --- hello/hello.go | 27 - main.go | 42 + outyet/Dockerfile | 2 - outyet/containers.yaml | 8 - outyet/main.go | 140 -- outyet/main_test.go | 99 -- stringutil/reverse.go | 27 - stringutil/reverse_test.go | 34 - template/image.tmpl | 9 - template/index.tmpl | 41 - template/main.go | 97 -- 36 files changed, 42 insertions(+), 6562 deletions(-) delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 appengine-hello/README.md delete mode 100644 appengine-hello/app.go delete mode 100644 appengine-hello/app.yaml delete mode 100644 appengine-hello/static/favicon.ico delete mode 100644 appengine-hello/static/index.html delete mode 100644 appengine-hello/static/script.js delete mode 100644 appengine-hello/static/style.css delete mode 100644 go.mod delete mode 100644 go.sum delete mode 100644 gotypes/Makefile delete mode 100644 gotypes/README.md delete mode 100644 gotypes/defsuses/main.go delete mode 100644 gotypes/doc/main.go delete mode 100644 gotypes/go-types.md delete mode 100644 gotypes/hello/hello.go delete mode 100644 gotypes/hugeparam/main.go delete mode 100644 gotypes/implements/main.go delete mode 100644 gotypes/lookup/lookup.go delete mode 100644 gotypes/nilfunc/main.go delete mode 100644 gotypes/pkginfo/main.go delete mode 100644 gotypes/skeleton/main.go delete mode 100644 gotypes/typeandvalue/main.go delete mode 100644 gotypes/weave.go delete mode 100644 hello/hello.go create mode 100644 main.go delete mode 100644 outyet/Dockerfile delete mode 100644 outyet/containers.yaml delete mode 100644 outyet/main.go delete mode 100644 outyet/main_test.go delete mode 100644 stringutil/reverse.go delete mode 100644 stringutil/reverse_test.go delete mode 100644 template/image.tmpl delete mode 100644 template/index.tmpl delete mode 100644 template/main.go diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d6456956..00000000 --- a/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - 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. diff --git a/README.md b/README.md deleted file mode 100644 index 13b9972f..00000000 --- a/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# Go example projects - -[![Go Reference](https://pkg.go.dev/badge/golang.org/x/example.svg)](https://pkg.go.dev/golang.org/x/example) - -This repository contains a collection of Go programs and libraries that -demonstrate the language, standard libraries, and tools. - -## Clone the project - -``` -$ git clone https://go.googlesource.com/example -$ cd example -``` -https://go.googlesource.com/example is the canonical Git repository. -It is mirrored at https://github.com/golang/example. -## [hello](hello/) and [stringutil](stringutil/) - -``` -$ cd hello -$ go build -``` -A trivial "Hello, world" program that uses a stringutil package. - -Command [hello](hello/) covers: - -* The basic form of an executable command -* Importing packages (from the standard library and the local repository) -* Printing strings ([fmt](//golang.org/pkg/fmt/)) - -Library [stringutil](stringutil/) covers: - -* The basic form of a library -* Conversion between string and []rune -* Table-driven unit tests ([testing](//golang.org/pkg/testing/)) - -## [outyet](outyet/) - -``` -$ cd outyet -$ go build -``` -A web server that answers the question: "Is Go 1.x out yet?" - -Topics covered: - -* Command-line flags ([flag](//golang.org/pkg/flag/)) -* Web servers ([net/http](//golang.org/pkg/net/http/)) -* HTML Templates ([html/template](//golang.org/pkg/html/template/)) -* Logging ([log](//golang.org/pkg/log/)) -* Long-running background processes -* Synchronizing data access between goroutines ([sync](//golang.org/pkg/sync/)) -* Exporting server state for monitoring ([expvar](//golang.org/pkg/expvar/)) -* Unit and integration tests ([testing](//golang.org/pkg/testing/)) -* Dependency injection -* Time ([time](//golang.org/pkg/time/)) - -## [appengine-hello](appengine-hello/) - -A trivial "Hello, world" App Engine application intended to be used as the -starting point for your own code. Please see -[Google App Engine SDK for Go](https://cloud.google.com/appengine/downloads#Google_App_Engine_SDK_for_Go) -and [Quickstart for Go in the App Engine Standard Environment](https://cloud.google.com/appengine/docs/standard/go/quickstart). - -## [gotypes](gotypes/) - -The `go/types` package is a type-checker for Go programs. It is one of the most -complex packages in Go's standard library, so we have provided this tutorial to -help you find your bearings. It comes with several example programs that you -can obtain using `go get` and play with as you learn to build tools that analyze -or manipulate Go programs. - -## [template](template/) - -A trivial web server that demonstrates the use of the -[`template` package](https://golang.org/pkg/text/template/)'s `block` feature. diff --git a/appengine-hello/README.md b/appengine-hello/README.md deleted file mode 100644 index ace365ea..00000000 --- a/appengine-hello/README.md +++ /dev/null @@ -1,11 +0,0 @@ -This code is a starting point for your Google App Engine application in -Go. - -To run the application locally you need the install the [Go Cloud -SDK](https://cloud.google.com/appengine/docs/go/#Go_tools) and execute the next -command from the directory containing this file: - - $ goapp serve app.yaml - -To deploy the application you have to first create an App Engine project -and use it as the application file in all the yaml files. diff --git a/appengine-hello/app.go b/appengine-hello/app.go deleted file mode 100644 index 49b3a4f1..00000000 --- a/appengine-hello/app.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015 Google Inc. -// -// 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. - -// Package hello is a simple App Engine application that replies to requests -// on /hello with a welcoming message. -package hello - -import ( - "fmt" - "net/http" -) - -// init is run before the application starts serving. -func init() { - // Handle all requests with path /hello with the helloHandler function. - http.HandleFunc("/hello", helloHandler) -} - -func helloHandler(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, "Hello from the Go app") -} diff --git a/appengine-hello/app.yaml b/appengine-hello/app.yaml deleted file mode 100644 index f8fa15c2..00000000 --- a/appengine-hello/app.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2015 Google Inc. All rights reserved. -# 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 writing, software distributed -# under the License is distributed on a "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. - -application: you-application-id -version: 1 -runtime: go -api_version: go1 - -handlers: -- url: /hello - script: _go_app - -- url: /favicon.ico - static_files: static/favicon.ico - upload: static/favicon.ico - -- url: / - static_files: static/index.html - upload: static/index.html - -- url: / - static_dir: static diff --git a/appengine-hello/static/favicon.ico b/appengine-hello/static/favicon.ico deleted file mode 100644 index d287722d806eed6369720b3cb073ce678e9390bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmZQzU<5(|0R|wcz>vYhz#zuJz@P!dKp~(AL>x$A1^@s5X9)4L`2X)=8A%wV2c&mY zKkdTr{O-#Chc;D#`g_y6y|{)5@Dut0V{hz(W?)PwAX>SCxFKyi?HFugGP%)x2@ zPwnsjzjRW_e~?<3UZA_cdFbJzr~ens=>f}u - - - - - - - Hello, world - - - - - -

Hello, world

- - -

Click on the button to fetch the message.

- - - diff --git a/appengine-hello/static/script.js b/appengine-hello/static/script.js deleted file mode 100644 index 7bf47578..00000000 --- a/appengine-hello/static/script.js +++ /dev/null @@ -1,24 +0,0 @@ -/* -Copyright 2015 Google Inc. - -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. -*/ - -"use strict"; - -function fetchMessage() { - var xmlHttp = new XMLHttpRequest(); - xmlHttp.open("GET", "/hello", false); - xmlHttp.send(null); - document.getElementById("message").innerHTML = xmlHttp.responseText; -} \ No newline at end of file diff --git a/appengine-hello/static/style.css b/appengine-hello/static/style.css deleted file mode 100644 index 9169ad58..00000000 --- a/appengine-hello/static/style.css +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2015 Google Inc. - -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. -*/ - -h1 { - text-align: center; -} \ No newline at end of file diff --git a/go.mod b/go.mod deleted file mode 100644 index c6b3f6b0..00000000 --- a/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module golang.org/x/example - -go 1.15 - -require golang.org/x/tools v0.0.0-20210112183307-1e6ecd4bf1b0 diff --git a/go.sum b/go.sum deleted file mode 100644 index 18a9ad7a..00000000 --- a/go.sum +++ /dev/null @@ -1,24 +0,0 @@ -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20210112183307-1e6ecd4bf1b0 h1:iZhiQWrjyEuXG495d9MXkcmhrlxbQyGp0uNBY+YBZDk= -golang.org/x/tools v0.0.0-20210112183307-1e6ecd4bf1b0/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/gotypes/Makefile b/gotypes/Makefile deleted file mode 100644 index 8d40c92e..00000000 --- a/gotypes/Makefile +++ /dev/null @@ -1,13 +0,0 @@ - -all: README.md - go build ./... - -README.md: go-types.md weave.go $(wildcard */*.go) - go run weave.go go-types.md >README.md - -# This is for previewing using github. -# $HOME/markdown must be a github client. -test: README.md - cp README.md $$HOME/markdown/ - (cd $$HOME/markdown/ && git commit -m . README.md && git push) - diff --git a/gotypes/README.md b/gotypes/README.md deleted file mode 100644 index e6883f51..00000000 --- a/gotypes/README.md +++ /dev/null @@ -1,2554 +0,0 @@ - - -# `go/types`: The Go Type Checker - -This document is maintained by Alan Donovan `adonovan@google.com`. - -[October 2015 GothamGo talk on go/types](https://docs.google.com/presentation/d/13OvHYozAUBeISPRoLgG7kMBuja1NsU1D_mMlmbaYojk/view) - - -# Contents - -1. [Introduction](#introduction) -1. [An Example](#an-example) -1. [Objects](#objects) -1. [Identifier Resolution](#identifier-resolution) -1. [Scopes](#scopes) -1. [Initialization Order](#initialization-order) -1. [Types](#types) - 1. [Basic types](#basic-types) - 1. [Simple Composite Types](#simple-composite-types) - 1. [Struct Types](#struct-types) - 1. [Tuple Types](#tuple-types) - 1. [Function and Method Types](#function-and-method-types) - 1. [Named Types](#named-types) - 1. [Interface Types](#interface-types) - 1. [TypeAndValue](#typeandvalue) -1. [Selections](#selections) -1. [Ids](#ids) -1. [Method Sets](#method-sets) -1. [Constants](#constants) -1. [Size and Alignment](#size-and-alignment) -1. [Imports](#imports) -1. [Formatting support](#formatting-support) -1. [Getting from A to B](#getting-from-a-to-b) - -# Introduction - - -The [`go/types` package]('https://golang.org/pkg/go/types) is a -type-checker for Go programs, designed by Robert Griesemer. -It became part of Go's standard library in Go 1.5. -Measured by lines of code and by API surface area, it is one of the -most complex packages in Go's standard library, and using it requires -a firm grasp of the structure of Go programs. -This tutorial will help you find your bearings. -It comes with several example programs that you can obtain with `go get` and play with. -We assume you are a proficient Go programmer who wants to build tools -to analyze or manipulate Go programs and that you have some knowledge -of how a typical compiler works. - -The type checker complements several existing -standard packages for analyzing Go programs. -We've listed them below. - - - → go/types - go/constant - go/parser - go/ast - go/scanner - go/token - - -Starting at the bottom, the -[`go/token` package](http://golang.org/pkg/go/token) -defines the lexical tokens of Go. -The [`go/scanner` package](http://golang.org/pkg/go/scanner) tokenizes an input stream and records -file position information for use in diagnostics -or for file surgery in a refactoring tool. -The [`go/ast` package](http://golang.org/pkg/go/ast) -defines the data types of the abstract syntax tree (AST). -The [`go/parser` package](http://golang.org/pkg/go/parser) -provides a robust recursive-descent parser that constructs the AST. -And [`go/constant`](http://golang.org/pkg/go/constant) -provides representations and arithmetic operations for the values of compile-time -constant expressions, as we'll see in -[Constants](#constants). - - - -The [`golang.org/x/tools/go/loader` package](https://pkg.go.dev/golang.org/x/tools/go/loader) -from the `x/tools` repository is a client of the type -checker that loads, parses, and type-checks a complete Go program from -source code. -We use it in some of our examples and you may find it useful too. - - - -The Go type checker does three main things. -First, for every name in the program, it determines which declaration -the name refers to; this is known as _identifier resolution_. -Second, for every expression in the program, it determines what type -that expression has, or reports an error if the expression has no -type, or has an inappropriate type for its context; this is known as -_type deduction_. -Third, for every constant expression in the program, it determines the -value of that constant; this is known as _constant evaluation_. - - - -Superficially, it appears that these three processes could be done -sequentially, in the order above, but perhaps surprisingly, they must -be done together. -For example, the value of a constant may depend on the type of an -expression due to operators like `unsafe.Sizeof`. -Conversely, the type of an expression may depend on the value of a -constant, since array types contain constants. -As a result, type deduction and constant evaluation must be done -together. - - - -As another example, we cannot resolve the identifier `k` in the composite -literal `T{k: 0}` until we know whether `T` is a struct type. -If it is, then `k` must be found among `T`'s fields. -If not, then `k` is an ordinary reference -to a constant or variable in the lexical environment. -Consequently, identifier resolution and type deduction are also -inseparable in the general case. - - - -Nonetheless, the three processes of identifier resolution, type -deduction, and constant evaluation can be separated for the purpose of -explanation. - - -# An Example - - -The code below shows the most basic use of the type checker to check -the _hello, world_ program, supplied as a string. -Later examples will be variations on this one, and we'll often omit -boilerplate details such as parsing. -To check out and build the examples, -run `go get golang.org/x/example/gotypes/...`. - - - // go get golang.org/x/example/gotypes/pkginfo - -``` -package main - -import ( - "fmt" - "go/ast" - "go/importer" - "go/parser" - "go/token" - "go/types" - "log" -) - -const hello = `package main - -import "fmt" - -func main() { - fmt.Println("Hello, world") -}` - -func main() { - fset := token.NewFileSet() - - // Parse the input string, []byte, or io.Reader, - // recording position information in fset. - // ParseFile returns an *ast.File, a syntax tree. - f, err := parser.ParseFile(fset, "hello.go", hello, 0) - if err != nil { - log.Fatal(err) // parse error - } - - // A Config controls various options of the type checker. - // The defaults work fine except for one setting: - // we must specify how to deal with imports. - conf := types.Config{Importer: importer.Default()} - - // Type-check the package containing only file f. - // Check returns a *types.Package. - pkg, err := conf.Check("cmd/hello", fset, []*ast.File{f}, nil) - if err != nil { - log.Fatal(err) // type error - } - - fmt.Printf("Package %q\n", pkg.Path()) - fmt.Printf("Name: %s\n", pkg.Name()) - fmt.Printf("Imports: %s\n", pkg.Imports()) - fmt.Printf("Scope: %s\n", pkg.Scope()) -} -``` - - -First, the program creates a -[`token.FileSet`](http://golang.org/pkg/go/token/#FileSet). -To avoid the need to store file names and line and column -numbers in every node of the syntax tree, the `go/token` package -provides `FileSet`, a data structure that stores this information -compactly for a sequence of files. -A `FileSet` records each file name only once, and records -only the byte offsets of each newline, allowing a position within -any file to be identified using a small integer called a -`token.Pos`. -Many tools create a single `FileSet` at startup. -Any part of the program that needs to convert a `token.Pos` into -an intelligible location---as part of an error message, for -instance---must have access to the `FileSet`. - - - -Second, the program parses the input string. -More realistic packages contain several source files, so the parsing -step must be repeated for each one, or better, done in parallel. -Third, it creates a `Config` that specifies type-checking options. -Since the _hello, world_ program uses imports, we must indicate -how to locate the imported packages. -Here we use `importer.Default()`, which loads compiler-generated -export data, but we'll explore alternatives in [Imports](#imports). - - - -Fourth, the program calls `Check`. -This creates a `Package` whose path is `"cmd/hello"`, and -type-checks each of the specified files---just one in this example. -The final (nil) argument is a pointer to an optional `Info` -struct that returns additional deductions from the type checker; more -on that later. -`Check` returns a `Package` even when it also returns an error. -The type checker is robust to ill-formed input, -and goes to great lengths to report accurate -partial information even in the vicinity of syntax or type errors. -`Package` has this definition: - - - type Package struct{ ... } - func (*Package) Path() string - func (*Package) Name() string - func (*Package) Scope() *Scope - func (*Package) Imports() []*Package - - -Finally, the program prints the attributes of the package, shown below. -(The hexadecimal number may vary from one run to the next.) - - -``` -$ go build golang.org/x/example/gotypes/pkginfo -$ ./pkginfo -Package "cmd/hello" -Name: main -Imports: [package fmt ("fmt")] -Scope: package "cmd/hello" scope 0x820533590 { -. func cmd/hello.main() -} -``` - - -A package's `Path`, such as `"encoding/json"`, is the string -by which import declarations identify it. -It is unique within a `$GOPATH` workspace, -and for published packages it must be globally unique. - - -A package's `Name` is the identifier in the `package` -declaration of each source file within the package, such as `json`. -The type checker reports an error if not all the package declarations in -the package agree. -The package name determines how the package is known when it is -imported into a file (unless a renaming import is used), -but is otherwise not visible to a program. - - -`Scope` returns the package's [_lexical block_](#scopes), -which provides access to all the named entities or -[_objects_](#objects) declared at package level. -`Imports` returns the set of packages directly imported by this -one, and may be useful for computing dependencies -([Initialization Order](#initialization-order)). - - - -# Objects - - -The task of identifier resolution is to map every identifier in the -syntax tree, that is, every `ast.Ident`, to an object. -For our purposes, an _object_ is a named entity created by a -declaration, such as a `var`, `type`, or `func` -declaration. -(This is different from the everyday meaning of object in -object-oriented programming.) - - - -Objects are represented by the `Object` interface: - - - type Object interface { - Name() string // package-local object name - Exported() bool // reports whether the name starts with a capital letter - Type() Type // object type - Pos() token.Pos // position of object identifier in declaration - - Parent() *Scope // scope in which this object is declared - Pkg() *Package // nil for objects in the Universe scope and labels - Id() string // object id (see Ids section below) - } - - -The first four methods are straightforward; we'll explain the other -three later. -`Name` returns the object's name---an identifier. -`Exported` is a convenience method that reports whether the first -letter of `Name` is a capital, indicating that the object may be -visible from outside the package. -It's a shorthand for `ast.IsExported(obj.Name())`. -`Type` returns the object's type; we'll come back to that in -[Types](#types). - - - -`Pos` returns the source position of the object's declaring identifier. -To make sense of a `token.Pos`, we need to call the -`(*token.FileSet).Position` method, which returns a struct with -individual fields for the file name, line number, column, and byte -offset, though usually we just call its `String` method: - - - fmt.Println(fset.Position(obj.Pos())) // "hello.go:10:6" - - -Not all objects carry position information. -Since the file format for compiler export data ([Imports](#imports)) -does not record position information, calling `Pos` on an object -imported from such a file returns zero, also known as -`token.NoPos`. - - - -There are eight kinds of objects in the Go type checker. -Most familiar are the kinds that can be declared at package level: -constants, variables, functions, and types. -Less familiar are statement labels, imported package names -(such as `json` in a file containing an `import "encoding/json"` -declaration), built-in functions (such as `append` and -`len`), and the pre-declared `nil`. -The eight types shown below are the only concrete types that satisfy -the `Object` interface. -In other words, `Object` is a _discriminated union_ of 8 -possible types, and we commonly use a type switch to distinguish them. - - - Object = *Func // function, concrete method, or abstract method - | *Var // variable, parameter, result, or struct field - | *Const // constant - | *TypeName // type name - | *Label // statement label - | *PkgName // package name, e.g. json after import "encoding/json" - | *Builtin // predeclared function such as append or len - | *Nil // predeclared nil - - -`Object`s are canonical. -That is, two `Object`s `x` and `y` denote the same -entity if and only if `x==y`. -Object identity is significant, and objects are routinely compared by -the addresses of the underlying pointers. -Although a package-level object is uniquely identified by its name -and enclosing package, for other objects there is no simple way to -obtain a string that uniquely identifies it. - - - -The `Parent` method returns the `Scope` (lexical block) in -which the object was declared; we'll come back to this in -[Scopes](#scopes). -Fields and methods are not found in the lexical environment, so -their objects have no `Parent`. - - - - -The `Pkg` method returns the `Package` to which this object -belongs, even for objects not declared at package level. -Only predeclared objects have no package. -The `Id` method will be explained in [Ids](#ids). - - - -Not all methods make sense for each kind of object. For instance, -the last four kinds above have no meaningful `Type` method. -And some kinds of objects have methods in addition to those required by the -`Object` interface: - - - func (*Func) Scope() *Scope - func (*Var) Anonymous() bool - func (*Var) IsField() bool - func (*Const) Val() constant.Value - func (*TypeName) IsAlias() bool - func (*PkgName) Imported() *Package - - -`(*Func).Scope` returns the [lexical block](#scopes) -containing the function's parameters, results, -and other local declarations. -`(*Var).IsField` distinguishes struct fields from ordinary -variables, and `(*Var).Anonymous` discriminates named fields like -the one in `struct{T T}` from anonymous fields like the one in `struct{T}`. -`(*Const).Val` returns the value of a named [constant](#constants). - - -`(*TypeName).IsAlias`, introduced in Go 1.9, reports whether the -type name is simply an alias for a type (as in `type I = int`), -as opposed to a definition of a [`Named`](#named-types) type, as -in `type Celsius float64`. - - -`(*PkgName).Imported` returns the package (for instance, -`encoding/json`) denoted by a given import name such as `json`. -Each time a package is imported, a new `PkgName` object is -created, usually with the same name as the `Package` it -denotes, but not always, as in the case of a renaming import. -`PkgName`s are objects, but `Package`s are not. -We'll look more closely at this in [Imports](#imports). - - - -All relationships between the syntax trees (`ast.Node`s) and type -checker data structures such as `Object`s and `Type`s are -stored in mappings outside the syntax tree itself. -Be aware that the `go/ast` package also defines a type called -`Object` that resembles---and predates---the type checker's -`Object`, and that `ast.Object`s are held directly by -identifiers in the AST. -They are created by the parser, which has a necessarily limited view -of the package, so the information they represent is at best partial and -in some cases wrong, as in the `T{k: 0}` example mentioned above. -If you are using the type checker, there is no reason to use the older -`ast.Object` mechanism. - - - -# Identifier Resolution - - -Identifier resolution computes the relationship between -identifiers and objects. -Its results are recorded in the `Info` struct optionally passed -to `Check`. -The fields related to identifier resolution are shown below. - - - type Info struct { - Defs map[*ast.Ident]Object - Uses map[*ast.Ident]Object - Implicits map[ast.Node]Object - Selections map[*ast.SelectorExpr]*Selection - Scopes map[ast.Node]*Scope - ... - } - - -Since not all facts computed by the type checker are needed by every -client, the API lets clients control which components of the result -should be recorded and which discarded: only fields that hold a -non-nil map will be populated during the call to `Check`. - - - -The two fields of type `map[*ast.Ident]Object` are the most important: -`Defs` records _declaring_ identifiers and -`Uses` records _referring_ identifiers. -In the example below, the comments indicate which identifiers are of -which kind. - - - var x int // def of x, use of int - fmt.Println(x) // uses of fmt, Println, and x - type T struct{U} // def of T, use of U (type), def of U (field) - - -The final line above illustrates why we don't combine `Defs` and -`Uses` into one map. -In the anonymous field declaration `struct{U}`, the -identifier `U` is both a use of the type `U` (a -`TypeName`) and a definition of the anonymous field (a -`Var`). - - - -The function below prints the location of each referring and defining -identifier in the input program, and the object it refers to. - - - // go get golang.org/x/example/gotypes/defsuses - -``` -func PrintDefsUses(fset *token.FileSet, files ...*ast.File) error { - conf := types.Config{Importer: importer.Default()} - info := &types.Info{ - Defs: make(map[*ast.Ident]types.Object), - Uses: make(map[*ast.Ident]types.Object), - } - _, err := conf.Check("hello", fset, files, info) - if err != nil { - return err // type error - } - - for id, obj := range info.Defs { - fmt.Printf("%s: %q defines %v\n", - fset.Position(id.Pos()), id.Name, obj) - } - for id, obj := range info.Uses { - fmt.Printf("%s: %q uses %v\n", - fset.Position(id.Pos()), id.Name, obj) - } - return nil -} -``` - - -Let's use the _hello, world_ program again as the input: - - - // go get golang.org/x/example/gotypes/hello - -``` -package main - -import "fmt" - -func main() { - fmt.Println("Hello, 世界") -} -``` - - -This is what it prints: - - -``` -$ go build golang.org/x/example/gotypes/defsuses -$ ./defsuses -hello.go:1:9: "main" defines -hello.go:5:6: "main" defines func hello.main() -hello.go:6:9: "fmt" uses package fmt -hello.go:6:13: "Println" uses func fmt.Println(a ...interface{}) (n int, err error) -``` - - -Notice that the `Defs` mapping may contain nil entries in a few -cases. -The first line of output reports that the package identifier -`main` is present in the `Defs` mapping, but has no -associated object. - - - -The `Implicits` mapping handles two cases of the syntax in -which an `Object` is declared without an `ast.Ident`, namely type -switches and import declarations. - -In the type switch below, which declares a local variable `y`, -the type of `y` is different in each case of the switch: - - - switch y := x.(type) { - case int: - fmt.Printf("%d", y) - case string: - fmt.Printf("%q", y) - default: - fmt.Print(y) - } - - -To represent this, for each single-type case, the type checker creates -a separate `Var` object for `y` with the appropriate type, -and `Implicits` maps each `ast.CaseClause` to the `Var` -for that case. -The `default` case, the `nil` case, and cases with more than one -type all use the regular `Var` object that is associated with the -identifier `y`, which is found in the `Defs` mapping. - - - -The import declaration below defines the name `json` without an -`ast.Ident`: - - - import "encoding/json" - - -`Implicits` maps this `ast.ImportSpec` to the `PkgName` -object named `json` that it implicitly declares. - - - -The `Selections` mapping, of type -`map[*ast.SelectorExpr]*Selection`, records the meaning of each -expression of the form _`expr`_`.f`, where _`expr`_ is -an expression or type and `f` is the name of a field or method. -These expressions, called _selections_, are represented by -`ast.SelectorExpr` nodes in the AST. -We'll talk more about the `Selection` type in [Selections](#selections). - - - -Not all `ast.SelectorExpr` nodes represent selections. -Expressions like `fmt.Println`, in which a package name precedes -the dot, are _qualified identifiers_. -They do not appear in the `Selections` mapping, but their -constituent identifiers (such as `fmt` and `Println`) both -appear in `Uses`. - - - -Referring identifiers that are not part of an `ast.SelectorExpr` -are _lexical references_. -That is, they are resolved to an object by searching for the -innermost enclosing lexical declaration of that name. -We'll see how that search works in the next section. - - -# Scopes - - -The `Scope` type is a mapping from names to objects. - - - type Scope struct{ ... } - - func (s *Scope) Names() []string - func (s *Scope) Lookup(name string) Object - - -`Names` returns the set of names in the mapping, in sorted order. -(It is not a simple accessor though, so call it sparingly.) -The `Lookup ` method returns the object for a given name, so we -can print all the entries or _bindings_ in a scope like this: - - - for _, name := range scope.Names() { - fmt.Println(scope.Lookup(name)) - } - - -The _scope_ of a declaration of a name is the region of -program source in which a reference to the name resolves to that -declaration. That is, scope is a property of a declaration. -However, in the `go/types` API, the `Scope` type represents -a _lexical block_, which is one component of the lexical -environment. -Consider the _hello, world_ program again: - - - package main - - import "fmt" - - func main() { - const message = "hello, world" - fmt.Println(message) - } - - -There are four lexical blocks in this program. -The outermost one is the _universe block_, which maps the -pre-declared names like `int`, `true`, and `append` to -their objects---a `TypeName`, a `Const`, and a -`Builtin`, respectively. -The universe block is represented by the global variable -`Universe`, of type `*Scope`, although it's logically a -constant so you shouldn't modify it. - - - -Next is the _package block_, which maps `"main"` to the -`main` function. -Following that is the _file block_, which maps `"fmt"` to -the `PkgName` object for this import of the `fmt` package. -And finally, the innermost block is that of function `main`, a -local block, which contains the declaration of `message`, a `Const`. -The `main` function is trivial, but many functions contain -several blocks since each `if`, `for`, `switch`, -`case`, or `select` statement creates at least one -additional block. -Local blocks nest to arbitrary depths. - - - -The structure of the lexical environment thus forms a tree, with the -universe block at the root, the package blocks beneath it, the file -blocks beneath them, and then any number of local blocks beneath the -files. -We can access and navigate this tree structure with the following -methods of `Scope`: - - - func (s *Scope) Parent() *Scope - func (s *Scope) NumChildren() int - func (s *Scope) Child(i int) *Scope - - -`Parent` lets us walk up the tree, and `Child` -lets us walk down it. -Note that although the `Parent` of every package `Scope` is -`Universe`, `Universe` has no children. -This asymmetry is a consequence of using a global variable to hold -`Universe`. - - - -To obtain the universe block, we use the `Universe` global variable. -To obtain the lexical block of a `Package`, we call its -`Scope` method. -To obtain the scope of a file (`*ast.File`), or any smaller piece -of syntax such as an `*ast.IfStmt`, we consult the `Scopes` -mapping in the `Info` struct, which maps each block-creating -syntax node to its block. -The lexical block of a named function or method can also be obtained -by calling its `(*Func).Scope` method. - - - - - -To look up a name in the lexical environment, we must search the tree -of lexical blocks, starting at a particular `Scope` and walking -up to the root until a declaration of the name is found. -For convenience, the `LookupParent` method does this, returning -not just the object, if found, but also the `Scope` in which it was -declared, which may be an ancestor of the initial one: - - - func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) - - -The `pos` parameter determines the position in the source code at -which the name should be resolved. -The effective lexical environment is different at each point in the -block because it depends on which local declarations appear -before or after that point. -(We'll see an illustration in a moment.) - - - -`Scope` has several other methods relating to source positions: - - - func (s *Scope) Pos() token.Pos - func (s *Scope) End() token.Pos - func (s *Scope) Contains(pos token.Pos) bool - func (s *Scope) Innermost(pos token.Pos) *Scope - - -`Pos` and `End` report the `Scope`'s start and end -position which, for explicit blocks, coincide with its curly -braces. -`Contains` is a convenience method that reports whether a -position lies in this interval. -`Innermost` returns the innermost scope containing the specified -position, which may be a child or other descendent of the initial -scope. - - - -These features are useful for tools that wish to resolve names or -evaluate constant expressions as if they had appeared at a particular -point within the program. -The next example program finds all the comments in the input, -treating the contents of each one as a name. It looks up each name in -the environment at the position of the comment, and prints what it -finds. -Observe that the `ParseComments` flag directs the parser to -preserve comments in the input. - - - // go get golang.org/x/example/gotypes/lookup - -``` -func main() { - fset := token.NewFileSet() - f, err := parser.ParseFile(fset, "hello.go", hello, parser.ParseComments) - if err != nil { - log.Fatal(err) // parse error - } - - conf := types.Config{Importer: importer.Default()} - pkg, err := conf.Check("cmd/hello", fset, []*ast.File{f}, nil) - if err != nil { - log.Fatal(err) // type error - } - - // Each comment contains a name. - // Look up that name in the innermost scope enclosing the comment. - for _, comment := range f.Comments { - pos := comment.Pos() - name := strings.TrimSpace(comment.Text()) - fmt.Printf("At %s,\t%q = ", fset.Position(pos), name) - inner := pkg.Scope().Innermost(pos) - if _, obj := inner.LookupParent(name, pos); obj != nil { - fmt.Println(obj) - } else { - fmt.Println("not found") - } - } -} -``` - - -The expression `pkg.Scope().Innermost(pos)` finds the innermost -`Scope` that encloses the comment, and `LookupParent(name, pos)` -does a name lookup at a specific position in that lexical block. - - - -A typical input is shown below. -The first comment causes a lookup of `"append"` in the file block. -The second comment looks up `"fmt"` in the `main` function's block, -and so on. - - -``` -const hello = ` -package main - -import "fmt" - -// append -func main() { - // fmt - fmt.Println("Hello, world") - // main - main, x := 1, 2 - // main - print(main, x) - // x -} -// x -` -``` - - -Here's the output: - - -``` -$ go build golang.org/x/example/gotypes/lookup -$ ./lookup -At hello.go:6:1, "append" = builtin append -At hello.go:8:9, "fmt" = package fmt -At hello.go:10:9, "main" = func cmd/hello.main() -At hello.go:12:9, "main" = var main int -At hello.go:14:9, "x" = var x int -At hello.go:16:1, "x" = not found -``` - - -Notice how the two lookups of `main` return different results, -even though they occur in the same block, because one precedes the -declaration of the local variable named `main` and the other -follows it. -Also notice that there are two lookups of the name `x` but only -the first one, in the function block, succeeds. - - - -Download the program and modify both the input program and -the set of comments to get a better feel for how name resolution works. - - - -The table below summarizes which kinds of objects may be declared at -each level of the tree of lexical blocks. - - - Universe File Package Local - Builtin ✔ - Nil ✔ - Const ✔ ✔ ✔ - TypeName ✔ ✔ ✔ - Func ✔ - Var ✔ ✔ - PkgName ✔ - Label ✔ - - -# Initialization Order - - -In the course of identifier resolution, the type checker constructs a -graph of references among declarations of package-level variables and -functions. -The type checker reports an error if the initializer expression for a -variable refers to that variable, whether directly or indirectly. - - - -The reference graph determines the initialization order of the -package-level variables, as required by the Go spec, using a -breadth-first algorithm. -First, variables in the graph with no successors are removed, sorted -into the order in which they appear in the source code, then added -to a list. This creates more variables that have no successors. -The process repeats until they have all been removed. - - - -The result is available in the `InitOrder` field of the -`Info` struct, whose type is `[]Initializer`. - - - type Info struct { - ... - InitOrder []Initializer - ... - } - - type Initializer struct { - Lhs []*Var // var Lhs = Rhs - Rhs ast.Expr - } - - -Each element of the list represents a single initializer expression -that must be executed, and the variables to which it is assigned. -The variables may number zero, one, or more, as in these examples: - - - var _ io.Writer = new(bytes.Buffer) - var rx = regexp.MustCompile("^b(an)*a$") - var cwd, cwdErr = os.Getwd() - - -This process governs the initialization order of variables within a -package. -Across packages, dependencies must be initialized first, although the -order among them is not specified. -That is, any topological order of the import graph will do. -The `(*Package).Imports` method returns the set of direct -dependencies of a package. - - -# Types - - -The main job of the type checker is, of course, to deduce the type -of each expression and to report type errors. -Like `Object`, `Type` is an interface type used as a -discriminated union of several concrete types but, unlike -`Object`, `Type` has very few methods because types have -little in common with each other. -Here is the interface: - - - type Type interface { - Underlying() Type - } - - -And here are the eleven concrete types that satisfy it: - - - Type = *Basic - | *Pointer - | *Array - | *Slice - | *Map - | *Chan - | *Struct - | *Tuple - | *Signature - | *Named - | *Interface - - -With the exception of `Named` types, instances of `Type` are -not canonical. -That is, it is usually a mistake to compare types using `t1==t2` -since this equivalence is not the same as the -[type identity relation](https://golang.org/ref/spec#Type_identity) -defined by the Go spec. -Use this function instead: - - - func Identical(t1, t2 Type) bool - - -For the same reason, you should not use a `Type` as a key in a map. -The [`golang.org/x/tools/go/types/typeutil` package](https://godoc.org/golang.org/x/tools/go/types/typeutil) -provides a map keyed by types that uses the correct -equivalence relation. - - -The Go spec defines three relations over types. -[_Assignability_](https://golang.org/ref/spec#Assignability) -governs which pairs of types may appear on the -left- and right-hand side of an assignment, including implicit -assignments such as function calls, map and channel operations, and so -on. -[_Comparability_](https://golang.org/ref/spec#Comparison_operators) -determines which types may appear in a comparison `x==y` or a -switch case or may be used as a map key. -[_Convertibility_](https://golang.org/ref/spec#Conversions) -governs which pairs of types are allowed in a conversion operation -`T(v)`. -You can query these relations with the following predicate functions: - - - func AssignableTo(V, T Type) bool - func Comparable(T Type) bool - func ConvertibleTo(V, T Type) bool - - -Let's take a look at each kind of type. - - -## Basic types - - -`Basic` represents all types that are not composed from simpler -types. -This is essentially the set of underlying types that a constant expression is -permitted to have--strings, booleans, and numbers---but it also -includes `unsafe.Pointer` and untyped nil. - - - type Basic struct{...} - func (*Basic) Kind() BasicKind - func (*Basic) Name() string - func (*Basic) Info() BasicInfo - - -The `Kind` method returns an "enum" value that indicates which -basic type this is. -The kinds `Bool`, `String`, `Int16`, and so on, -represent the corresponding predeclared boolean, string, or numeric -types. -There are two synonyms: `Byte` is equivalent to `Uint8` -and `Rune` is equivalent to `Int32`. -The kind `UnsafePointer` represents `unsafe.Pointer`. -The kinds `UntypedBool`, `UntypedInt` and so on represent -the six kinds of "untyped" constant types: boolean, integer, rune, -float, complex, and string. -The kind `UntypedNil` represents the type of the predeclared -`nil` value. -And the kind `Invalid` indicates the invalid type, which is used -for expressions containing errors, or for objects without types, like -`Label`, `Builtin`, or `PkgName`. - - - -The `Name` method returns the name of the type, such as -`"float64"`, and the `Info` method returns a bitfield that -encodes information about the type, such as whether it is signed or -unsigned, integer or floating point, or real or complex. - - - -`Typ` is a table of canonical basic types, indexed by -kind, so `Typ[String]` returns the `*Basic` that represents -`string`, for instance. -Like `Universe`, `Typ` is logically a constant, so don't -modify it. - - - -A few minor subtleties: -According to the Go spec, pre-declared types such as `int` are -named types for the purposes of assignability, even though the type -checker does not represent them using `Named`. -And `unsafe.Pointer` is a pointer type for the purpose of -determining whether the receiver type of a method is legal, even -though the type checker does not represent it using `Pointer`. - - - -The "untyped" types are usually only ascribed to constant expressions, -but there is one exception. -A comparison `x==y` has type "untyped bool", so the result of -this expression may be assigned to a variable of type `bool` or -any other named boolean type. - - - -## Simple Composite Types - - -The types `Pointer`, `Array`, `Slice`, `Map`, -and `Chan` are pretty self-explanatory. -All have an `Elem` method that returns the element type `T` -for a pointer `*T`, an array `[n]T`, a slice `[]T`, a -map `map[K]T`, or a channel `chan T`. -This should feel familiar if you've used the `reflect.Value` API. - - - -In addition, the `*Map`, `*Chan`, and `*Array` types -have accessor methods that return their key type, direction, and -length, respectively: - - - func (*Map) Key() Type - func (*Chan) Dir() ChanDir // = Send | Recv | SendRecv - func (*Array) Len() int64 - - - -## Struct Types - - -A struct type has an ordered list of fields and a corresponding -ordered list of field tags. - - - type Struct struct{ ... } - func (*Struct) NumFields() int - func (*Struct) Field(i int) *Var - func (*Struct) Tag(i int) string - - -Each field is a `Var` object whose `IsField` method returns true. -Field objects have no `Parent` scope, because they are -resolved through selections, not through the lexical environment. - - - - -Thanks to embedding, the expression `new(S).f` may be a shorthand -for a longer expression such as `new(S).d.e.f`, but in the -representation of `Struct` types, these field selection -operations are explicit. -That is, the set of fields of struct type `S` does not include `f`. -An anonymous field is represented like a regular field, but its -`Anonymous` method returns true. - - - -One subtlety is relevant to tools that generate documentation. -When analyzing a declaration such as this, - - - type T struct{x int} - - -it may be tempting to consider the `Var` object for field `x` as if it -had the name `"T.x"`, but beware: field objects do not have -canonical names and there is no way to obtain the name `"T"` -from the `Var` for `x`. -That's because several types may have the same underlying struct type, -as in this code: - - - type T struct{x int} - type U T - - -Here, the `Var` for field `x` belongs equally to `T` -and to `U`, and short of inspecting source positions or walking -the AST---neither of which is possible for objects loaded from compiler -export data---it is not possible to ascertain that `x` was declared as -part of `T`. -The type checker builds the exact same data structures given this input: - - - type T U - type U struct{x int} - - -A similar issue applies to the methods of named interface types. - - -## Tuple Types - - -Like a struct, a tuple type has an ordered list of fields, and fields -may be named. - - - type Tuple struct{ ... } - func (*Tuple) Len() int - func (*Tuple) At(i int) *Var - - -Although tuples are not the type of any variable in Go, they are -the type of some expressions, such as the right-hand sides of these -assignments: - - - v, ok = m[key] - v, ok = <-ch - v, ok = x.(T) - f, err = os.Open(filename) - - -Tuples also represent the types of the parameter list and the result -list of a function, as we will see. - - - -Since empty tuples are common, the nil `*Tuple` pointer is a valid empty tuple. - - - -## Function and Method Types - - -The types of functions and methods are represented by a `Signature`, -which has a tuple of parameter types and a tuple of result types. - - - type Signature struct{ ... } - func (*Signature) Recv() *Var - func (*Signature) Params() *Tuple - func (*Signature) Results() *Tuple - func (*Signature) Variadic() bool - - -Variadic functions such as `fmt.Println` have the `Variadic` -flag set. -The final parameter of such functions is always a slice, or in the -special case of certain calls to `append`, a string. - - - -A `Signature` for a method, whether concrete or abstract, has a -non-nil receiver parameter, `Recv`. -The type of the receiver is usually a named type or a pointer to a named type, -but it may be an unnamed struct or interface type in some cases. -Method types are rather second-class: they are only used for the -`Func` objects created by method declarations, and no Go -expression has a method type. -When printing a method type, the receiver does not appear, and the -`Identical` predicate ignores the receiver. - - - -The types of `Builtin` objects like `append` cannot be -expressed as a `Signature` since those types require parametric -polymorphism. -`Builtin` objects are thus ascribed the `Invalid` basic type. -However, the type of each _call_ to a built-in function has a specific -and expressible Go type. -These types are recorded during type checking for later use -([TypeAndValue](#typeandvalue)). - - - -## Named Types - - -Type declarations come in two forms. -The simplest kind, introduced in Go 1.9, -merely declares a (possibly alternative) name for an existing type. -Type names used in this way are informally called _type aliases_. -For example, this declaration lets you use the type -`Dictionary` as an alias for `map[string]string`: - - type Dictionary = map[string]string - -The declaration creates a `TypeName` object for `Dictionary`. The -object's `IsAlias` method returns true, and its `Type` method returns -a `Map` type that represents `map[string]string`. - - -The second form of type declaration, and the only kind prior to Go -1.9, does not use an equals sign: - - type Celsius float64 - -This declaration does more than just give a name to a type. -It first defines a new `Named` type -whose underlying type is `float64`; this `Named` type is different -from any other type, including `float64`. The declaration binds the -`TypeName` object to the `Named` type. - -Since Go 1.9, the Go language specification has used the term _defined -types_ instead of named types; -the essential property of a defined type is not that it has a name, -but that it is a distinct type with its own method set. -However, the type checker API predates that -change and instead calls defined types "named" types. - - type Named struct{ ... } - func (*Named) NumMethods() int - func (*Named) Method(i int) *Func - func (*Named) Obj() *TypeName - func (*Named) Underlying() Type - -The `Named` type's `Obj` method returns the `TypeName` object, which -provides the name, position, and other properties of the declaration. -Conversely, the `TypeName` object's `Type` method returns the `Named` type. - -A `Named` type may appear as the receiver type in a method declaration. -Methods are associated with the `Named` type, not the name (the -`TypeName` object); it's possible---though cryptic---to declare a -method on a `Named` type using one of its aliases. -The `NumMethods` and `Method` methods enumerate the declared -methods associated with this `Named` type (or a pointer to it), -in the order they were declared. -However, due to the subtleties of anonymous fields and the difference -between value and pointer receivers, a named type may have more or fewer -methods than this list. We'll return to this in [Method Sets](#method-sets). - - - -Every `Type` has an `Underlying` method, but for all of them -except `*Named`, it is simply the identity function. -For a named type, `Underlying` returns its underlying type, which -is always an unnamed type. -Thus `Underlying` returns `int` for both `T` and -`U` below. - - - type T int - type U T - - -Clients of the type checker often use type assertions or type switches -with a `Type` operand. -When doing so, it is often necessary to switch on the type that -_underlies_ the type of interest, and failure to do so may be a -bug. - -This is a common pattern: - - - // handle types of composite literal - switch u := t.Underlying().(type) { - case *Struct: // ... - case *Map: // ... - case *Array, *Slice: // ... - default: - panic("impossible") - } - -## Interface Types - - -Interface types are represented by `Interface`. - - - type Interface struct{ ... } - func (*Interface) Empty() bool - func (*Interface) NumMethods() int - func (*Interface) Method(i int) *Func - func (*Interface) NumEmbeddeds() int - func (*Interface) Embedded(i int) *Named - func (*Interface) NumExplicitMethods() int - func (*Interface) ExplicitMethod(i int) *Func - - -Syntactically, an interface type has a list of explicitly declared -methods (`ExplicitMethod`), and a list of embedded named -interface types (`Embedded`), but many clients care only about -the complete set of methods, which can be enumerated via -`Method`. -All three lists are ordered by name. -Since the empty interface is an important special case, the -`Empty` predicate provides a shorthand for `NumMethods() == -0`. - - - -As with the fields of structs (see above), the methods of interfaces -may belong equally to more than one interface type. -The `Func` object for method `f` in the code below is shared -by `I` and `J`: - - - type I interface { f() } - type J I - - -Because the difference between interface (abstract) and -non-interface (concrete) types is so important in Go, the -`IsInterface` predicate is provided for convenience. - - - func IsInterface(Type) bool - - -The type checker provides three utility methods relating to interface -satisfaction: - - - func Implements(V Type, T *Interface) bool - func AssertableTo(V *Interface, T Type) bool - func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) - - -The `Implements` predicate reports whether a type satisfies an -interface type. -`MissingMethod` is like `Implements`, but instead of -returning false, it explains why a type does not satisfy the -interface, for use in diagnostics. - - - -`AssertableTo` reports whether a type assertion `v.(T)` is legal. -If `T` is a concrete type that doesn't have all the methods of -interface `v`, then the type assertion is not legal, as in this example: - - - // error: io.Writer is not assertible to int - func f(w io.Writer) int { return w.(int) } - - - -## TypeAndValue - - -The type checker records the type of each expression in another field -of the `Info` struct, namely `Types`: - - - type Info struct { - ... - Types map[ast.Expr]TypeAndValue - } - - -No entries are recorded for identifiers since the `Defs` and -`Uses` maps provide more information about them. -Also, no entries are recorded for pseudo-expressions like -`*ast.KeyValuePair` or `*ast.Ellipsis`. - - - -The value of the `Types` map is a `TypeAndValue`, which -(unsurprisingly) holds the type and value of the expression, and in -addition, its _mode_. -The mode is opaque, but has predicates to answer questions such as: -Does this expression denote a value or a type? Does this value have an -address? Does this expression appear on the left-hand side of an -assignment? Does this expression appear in a context that expects two -results? -The comments in the code below give examples of expressions that -satisfy each predicate. - - - type TypeAndValue struct { - Type Type - Value constant.Value // for constant expressions only - ... - } - - func (TypeAndValue) IsVoid() bool // e.g. "main()" - func (TypeAndValue) IsType() bool // e.g. "*os.File" - func (TypeAndValue) IsBuiltin() bool // e.g. "len(x)" - func (TypeAndValue) IsValue() bool // e.g. "*os.Stdout" - func (TypeAndValue) IsNil() bool // e.g. "nil" - func (TypeAndValue) Addressable() bool // e.g. "a[i]" but not "f()", "m[key]" - func (TypeAndValue) Assignable() bool // e.g. "a[i]", "m[key]" - func (TypeAndValue) HasOk() bool // e.g. "<-ch", "m[key]" - - -The statement below inspects every expression within the AST of a single -type-checked file and prints its type, value, and mode: - - - // go get golang.org/x/example/gotypes/typeandvalue - -``` -// f is a parsed, type-checked *ast.File. -ast.Inspect(f, func(n ast.Node) bool { - if expr, ok := n.(ast.Expr); ok { - if tv, ok := info.Types[expr]; ok { - fmt.Printf("%-24s\tmode: %s\n", nodeString(expr), mode(tv)) - fmt.Printf("\t\t\t\ttype: %v\n", tv.Type) - if tv.Value != nil { - fmt.Printf("\t\t\t\tvalue: %v\n", tv.Value) - } - } - } - return true -}) -``` - - -It makes use of these two helper functions, which are not shown: - - - // nodeString formats a syntax tree in the style of gofmt. - func nodeString(n ast.Node) string - - // mode returns a string describing the mode of an expression. - func mode(tv types.TypeAndValue) string - - -Given this input: - - -``` -const input = ` -package main - -var m = make(map[string]int) - -func main() { - v, ok := m["hello, " + "world"] - print(rune(v), ok) -} -` -``` - - -the program prints: - - -``` -$ go build golang.org/x/example/gotypes/typeandvalue -$ ./typeandvalue -make(map[string]int) mode: value - type: map[string]int -make mode: builtin - type: func(map[string]int) map[string]int -map[string]int mode: type - type: map[string]int -string mode: type - type: string -int mode: type - type: int -m["hello, "+"world"] mode: value,assignable,ok - type: (int, bool) -m mode: value,addressable,assignable - type: map[string]int -"hello, " + "world" mode: value - type: string - value: "hello, world" -"hello, " mode: value - type: untyped string - value: "hello, " -"world" mode: value - type: untyped string - value: "world" -print(rune(v), ok) mode: void - type: () -print mode: builtin - type: func(rune, bool) -rune(v) mode: value - type: rune -rune mode: type - type: rune -...more not shown... -``` - - -Notice that the identifiers for the built-ins `make` and -`print` have types that are specific to the particular calls in -which they appear. -Also notice `m["hello"]` has a 2-tuple type `(int, bool)` -and that it is assignable, but unlike the variable `m`, it is not -addressable. - - - -Download the example and vary the inputs and see what the program prints. - - - -Here's another example, adapted from the `govet` static checking tool. -It checks for accidental uses of a method value `x.f` when a -call `x.f()` was intended; -comparing a method `x.f` against nil is a common mistake. - - - // go get golang.org/x/example/gotypes/nilfunc - -``` -// CheckNilFuncComparison reports unintended comparisons -// of functions against nil, e.g., "if x.Method == nil {". -func CheckNilFuncComparison(info *types.Info, n ast.Node) { - e, ok := n.(*ast.BinaryExpr) - if !ok { - return // not a binary operation - } - if e.Op != token.EQL && e.Op != token.NEQ { - return // not a comparison - } - - // If this is a comparison against nil, find the other operand. - var other ast.Expr - if info.Types[e.X].IsNil() { - other = e.Y - } else if info.Types[e.Y].IsNil() { - other = e.X - } else { - return // not a comparison against nil - } - - // Find the object. - var obj types.Object - switch v := other.(type) { - case *ast.Ident: - obj = info.Uses[v] - case *ast.SelectorExpr: - obj = info.Uses[v.Sel] - default: - return // not an identifier or selection - } - - if _, ok := obj.(*types.Func); !ok { - return // not a function or method - } - - fmt.Printf("%s: comparison of function %v %v nil is always %v\n", - fset.Position(e.Pos()), obj.Name(), e.Op, e.Op == token.NEQ) -} -``` - - -Given this input, - - -``` -const input = `package main - -import "bytes" - -func main() { - var buf bytes.Buffer - if buf.Bytes == nil && bytes.Repeat != nil && main == nil { - // ... - } -} -` -``` - - -the program reports these errors: - - -``` -$ go build golang.org/x/example/gotypes/nilfunc -$ ./nilfunc -input.go:7:5: comparison of function Bytes == nil is always false -input.go:7:25: comparison of function Repeat != nil is always true -input.go:7:48: comparison of function main == nil is always false -``` - -# Selections - - -A _selection_ is an expression _`expr`_`.f` in which -`f` denotes either a struct field or a method. -A selection is resolved not by looking for a name in the lexical -environment, but by looking within a _type_. -The type checker ascertains the meaning of each selection in the -package---a surprisingly tricky business---and records it in the -`Selections` mapping of the `Info` struct, whose values are -of type `Selection`: - - - type Selection struct{ ... } - func (s *Selection) Kind() SelectionKind // = FieldVal | MethodVal | MethodExpr - func (s *Selection) Recv() Type - func (s *Selection) Obj() Object - func (s *Selection) Type() Type - func (s *Selection) Index() []int - func (s *Selection) Indirect() bool - - -The `Kind` method discriminates between the three (legal) kinds -of selections, as indicated by the comments below. - - - type T struct{Field int} - func (T) Method() {} - var v T - - // Kind Type - var _ = v.Field // FieldVal int - var _ = v.Method // MethodVal func() - var _ = T.Method // MethodExpr func(T) - - -Because of embedding, a selection may denote more than one field or -method, in which case it is ambiguous, and no `Selection` is -recorded for it. - - - -The `Obj` method returns the `Object` for the selected field -(`*Var`) or method (`*Func`). -Due to embedding, the object may belong to a different type than that -of the receiver expression _`expr`_. -The `Type` method returns the type of the selection. For a field -selection, this is the type of the field, but for method selections, -the result is a function type that is not the same as the type of the -method. -For a `MethodVal`, the receiver parameter is dropped, and -for a `MethodExpr`, the receiver parameter becomes a regular -parameter, as shown in the example above. - - - -The `Index` and `Indirect` methods report information about -implicit operations occurring during the selection that a compiler -would need to know about. -Because of embedding, a selection _`expr`_`.f` may be -shorthand for a sequence containing several implicit field selections, -_`expr`_`.d.e.f`, and `Index` reports the complete -sequence. -And because of automatic pointer dereferencing during struct field -accesses and method calls, a selection may imply one or more indirect -loads from memory; `Indirect` reports whether this occurs. - - - -Clients of the type checker can call `LookupFieldOrMethod` to -look up a name within a type, as if by a selection. -This function has an intimidating signature, but conceptually it -accepts just a `Type` and a name, and returns a `Selection`: - - - func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) \ - (obj Object, index []int, indirect bool) - - -The result is not actually a `Selection`, but it contains the -three main components of one: `Obj`, `Index`, -and `Indirect`. - - - -The `addressable` flag should be set if the receiver is a -_variable_ of type `T`, since in a method selection on a -variable, an implicit address-of operation (`&`) may occur. -The flag indicates whether the methods of type `*T` should be -considered during the lookup. -(You may wonder why this parameter is necessary. Couldn't clients -instead call `LookupFieldOrMethod` on the pointer type `*T` -if the receiver is a `T` variable? The answer is that if -`T` is an interface type, the type `*T` has no methods at -all.) - - - -The final two parameters of `LookupFieldOrMethod` are `(pkg -*Package, name string)`. -Together they specify the name of the field or method to look up. -This brings us to `Id`s. - - - -# Ids - - -`LookupFieldOrMethod`'s need for a `Package` parameter -is a subtle consequence of the -[_Uniqueness of identifiers_](https://golang.org/ref/spec#Uniqueness_of_identifiers) -section in the Go spec: "Two -identifiers are different if they are spelled differently, or if they -appear in different packages and are not exported." -In practical terms, this means that a type may have two methods -(or two fields, or one of each) both named `f` so long as those -methods are defined in different packages, as in this example: - - - package a - type A int - func (A) f() - - package b - type B int - func (B) f() - - package c - import ( "a"; "b" ) - type C struct{a.A; b.B} // C has two methods called f - - -The type `c.C` has two methods named `f`, but there is -no ambiguity because the two `f`s are distinct -identifiers---think of them as `fᵃ` and `fᵇ`. -For an exported method, this situation _would_ be ambiguous -because there is no distinction between `Fᵃ` and `Fᵇ`; there -is only `F`. - - - -Despite having two methods called `f`, neither of them can be -called from within package `c` because `c` has no way to -identify them. -Within `c`, `f` is the identifier `fᶜ`, and -type `C` has no method of that name. -But if we pass an instance of `C` to code in package `a` -and call its `f` method via an interface, `fᵃ` is called. - - - -The practical consequence for tool builders is that any time you need -to look up a field or method by name, or construct a map of fields and/or -methods keyed by name, it is not sufficient to use the object's name -as a key. -Instead, you must call the `Object.Id` method, which returns -a string that incorporates the object name, and for unexported -objects, the package path too. -There is also a standalone function `Id` that combines a name and -the package path in the same way: - - - func Id(pkg *Package, name string) string - - -This distinction applies to selections _`expr`_`.f`, but not -to lexical references `x` because for unexported identifiers, -declarations and references always appear in the same package. - - - -Fun fact: the `reflect.StructField` type records both the -`Name` and the `PkgPath` strings for the same reason. -The `FieldByName` methods of `reflect.Value` and -`reflect.Type` match field names without regard to the package. -If there is more than one match, they return an invalid value. - - - - -# Method Sets - - -The _method set_ of a type is the set of methods that can be -called on any value of that type. -(A variable of type `T` has access to all the methods of type -`*T` as well, due to the implicit address-of operation during -method calls, but those extra methods are not part of the method set -of `T`.) - - - -Clients can request the method set of a type `T` by calling -`NewMethodSet(T)`: - - - type MethodSet struct{ ... } - func NewMethodSet(T Type) *MethodSet - func (s *MethodSet) Len() int - func (s *MethodSet) At(i int) *Selection - func (s *MethodSet) Lookup(pkg *Package, name string) *Selection - - -The `Len` and `At` methods access a list of -`Selections`, all of kind `MethodVal`, ordered by `Id`. -The `Lookup` function allows lookup of a single method by -name (and package path, as explained in the previous section). - - - -`NewMethodSet` can be expensive, so for applications that compute -method sets repeatedly, `golang.org/x/tools/go/types/typeutil` -provides a `MethodSetCache` type that records previous results. -If you only need a single method, don't construct the -`MethodSet` at all; it's cheaper to use -`LookupFieldOrMethod`. - - - -The next program generates a boilerplate -declaration of a new concrete type that satisfies an existing -interface. -Here's an example: - - -``` -$ ./skeleton io ReadWriteCloser buffer -// *buffer implements io.ReadWriteCloser. -type buffer struct{} -func (b *buffer) Close() error { - panic("unimplemented") -} -func (b *buffer) Read(p []byte) (n int, err error) { - panic("unimplemented") -} -func (b *buffer) Write(p []byte) (n int, err error) { - panic("unimplemented") -} -``` - - -The three arguments are the package and the name of the existing -interface type, and the name of the new concrete type. -The `main` function (not shown) loads the specified package and -calls `PrintSkeleton` with the remaining two arguments: - - - // go get golang.org/x/example/gotypes/skeleton - -``` -func PrintSkeleton(pkg *types.Package, ifacename, concname string) error { - obj := pkg.Scope().Lookup(ifacename) - if obj == nil { - return fmt.Errorf("%s.%s not found", pkg.Path(), ifacename) - } - if _, ok := obj.(*types.TypeName); !ok { - return fmt.Errorf("%v is not a named type", obj) - } - iface, ok := obj.Type().Underlying().(*types.Interface) - if !ok { - return fmt.Errorf("type %v is a %T, not an interface", - obj, obj.Type().Underlying()) - } - // Use first letter of type name as receiver parameter. - if !isValidIdentifier(concname) { - return fmt.Errorf("invalid concrete type name: %q", concname) - } - r, _ := utf8.DecodeRuneInString(concname) - - fmt.Printf("// *%s implements %s.%s.\n", concname, pkg.Path(), ifacename) - fmt.Printf("type %s struct{}\n", concname) - mset := types.NewMethodSet(iface) - for i := 0; i < mset.Len(); i++ { - meth := mset.At(i).Obj() - sig := types.TypeString(meth.Type(), (*types.Package).Name) - fmt.Printf("func (%c *%s) %s%s {\n\tpanic(\"unimplemented\")\n}\n", - r, concname, meth.Name(), - strings.TrimPrefix(sig, "func")) - } - return nil -} -``` - - -First, `PrintSkeleton` locates the package-level named interface -type, handling various error cases. -Then it chooses the name for the receiver of the new methods: the -first letter of the concrete type. -Finally, it iterates over the method set of the interface, printing -the corresponding concrete method declarations. - - - -There's a subtlety in the declaration of `sig`, which is the -string form of the method signature. -We could have obtained this string from `meth.Type().String()`, -but this would cause any named types within it to be formatted with -the complete package path, for instance -`net/http.ResponseWriter`, which is informative in diagnostics -but not legal Go syntax. -The `TypeString` function (explained in [Formatting Values](#formatting-values)) allows the -caller to control how packages are printed. -Passing `(*types.Package).Name` causes only the package name -`http` to be printed, not the complete path. -Here's another example that illustrates it: - - -``` -$ ./skeleton net/http Handler myHandler -// *myHandler implements net/http.Handler. -type myHandler struct{} -func (m *myHandler) ServeHTTP(http.ResponseWriter, *http.Request) { - panic("unimplemented") -} -``` - - -The following program inspects all pairs of package-level named types -in `pkg`, and reports the types that satisfy each interface type. - - - // go get golang.org/x/example/gotypes/implements - -``` -// Find all named types at package level. -var allNamed []*types.Named -for _, name := range pkg.Scope().Names() { - if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok { - allNamed = append(allNamed, obj.Type().(*types.Named)) - } -} - -// Test assignability of all distinct pairs of -// named types (T, U) where U is an interface. -for _, T := range allNamed { - for _, U := range allNamed { - if T == U || !types.IsInterface(U) { - continue - } - if types.AssignableTo(T, U) { - fmt.Printf("%s satisfies %s\n", T, U) - } else if !types.IsInterface(T) && - types.AssignableTo(types.NewPointer(T), U) { - fmt.Printf("%s satisfies %s\n", types.NewPointer(T), U) - } - } -} -``` - - -Given this input, - - - // go get golang.org/x/example/gotypes/implements - -``` -const input = `package main - -type A struct{} -func (*A) f() - -type B int -func (B) f() -func (*B) g() - -type I interface { f() } -type J interface { g() } -` -``` - - -the program prints: - - -``` -$ go build golang.org/x/example/gotypes/implements -$ ./implements -*hello.A satisfies hello.I -hello.B satisfies hello.I -*hello.B satisfies hello.J -``` - - -Notice that the method set of `B` does not include `g`, but -the method set of `*B` does. -That's why we needed the second assignability check, using the pointer -type `types.NewPointer(T)`. - - - -# Constants - - -A constant expression is one whose value is guaranteed to be computed at -compile time. -Constant expressions may appear in types, specifically as the length -of an array type such as `[16]byte`, so one of the jobs of the -type checker is to compute the value of each constant expression. - - - -As we saw in the `typeandvalue` example, the type checker records -the value of each constant expression like `"Hello, " + "world"`, -storing it in the `Value` field of the `TypeAndValue` struct. -Constants are represented using the `Value` interface from the -`go/constant` package. - - - package constant // go/constant - - type Value interface { - Kind() Kind - } - - type Kind int // one of Unknown, Bool, String, Int, Float, Complex - - -The interface has only one method, for discriminating the various -kinds of constants, but the package provides many functions for -inspecting a value of a known kind, - - - // Accessors - func BoolVal(x Value) bool - func Float32Val(x Value) (float32, bool) - func Float64Val(x Value) (float64, bool) - func Int64Val(x Value) (int64, bool) - func StringVal(x Value) string - func Uint64Val(x Value) (uint64, bool) - func Bytes(x Value) []byte - func BitLen(x Value) int - func Sign(x Value) int - - -for performing arithmetic on values, - - - // Operations - func Compare(x Value, op token.Token, y Value) bool - func UnaryOp(op token.Token, y Value, prec uint) Value - func BinaryOp(x Value, op token.Token, y Value) Value - func Shift(x Value, op token.Token, s uint) Value - func Denom(x Value) Value - func Num(x Value) Value - func Real(x Value) Value - func Imag(x Value) Value - - -and for constructing new values: - - - // Constructors - func MakeBool(b bool) Value - func MakeFloat64(x float64) Value - func MakeFromBytes(bytes []byte) Value - func MakeFromLiteral(lit string, tok token.Token, prec uint) Value - func MakeImag(x Value) Value - func MakeInt64(x int64) Value - func MakeString(s string) Value - func MakeUint64(x uint64) Value - func MakeUnknown() Value - - -All numeric `Value`s, whether integer or floating-point, signed or -unsigned, or real or complex, are represented more precisely than -ordinary Go types like `int64` and `float64`. -Internally, the `go/constant` package uses multi-precision data types -like `Int`, `Rat`, and `Float` from the `math/big` package so that -`Values` and their arithmetic operations are accurate to at least 256 -bits, as required by the Go specification. - - - - - -# Size and Alignment - - -Because the calls `unsafe.Sizeof(v)`, `unsafe.Alignof(v)`, -and `unsafe.Offsetof(v.f)` are all constant expressions, the type -checker must be able to compute the memory layout of any value -`v`. - - - -By default, the type checker uses the same layout algorithm as the Go -1.5 `gc` compiler targeting `amd64`. -Clients can configure the type checker to use a different algorithm by -providing an instance of the `types.Sizes` interface in the -`types.Config` struct: - - - package types - - type Sizes interface { - Alignof(T Type) int64 - Offsetsof(fields []*Var) []int64 - Sizeof(T Type) int64 - } - - - -For common changes, like reducing the word size to 32 bits, clients -can use an instance of `StdSizes`: - - - type StdSizes struct { - WordSize int64 - MaxAlign int64 - } - - -This type has two basic size and alignment parameters from which it -derives all the other values using common assumptions. -For example, pointers, functions, maps, and channels fit in one word, -strings and interfaces require two words, and slices need three. -The default behaviour is equivalent to `StdSizes{8, 8}`. -For more esoteric layout changes, you'll need to write a new -implementation of the `Sizes` interface. - - - -The `hugeparam` program below prints all function parameters and -results whose size exceeds a threshold. -By default, the threshold is 48 bytes, but you can set it via the -`-bytes` command-line flag. -Such a tool could help identify inefficient parameter passing in your -programs. - - - // go get golang.org/x/example/gotypes/hugeparam - -``` -var bytesFlag = flag.Int("bytes", 48, "maximum parameter size in bytes") - -var sizeof = (&types.StdSizes{8, 8}).Sizeof // the sizeof function - -func PrintHugeParams(fset *token.FileSet, info *types.Info, files []*ast.File) { - checkTuple := func(descr string, tuple *types.Tuple) { - for i := 0; i < tuple.Len(); i++ { - v := tuple.At(i) - if sz := sizeof(v.Type()); sz > int64(*bytesFlag) { - fmt.Printf("%s: %q %s: %s = %d bytes\n", - fset.Position(v.Pos()), - v.Name(), descr, v.Type(), sz) - } - } - } - checkSig := func(sig *types.Signature) { - checkTuple("parameter", sig.Params()) - checkTuple("result", sig.Results()) - } - for _, file := range files { - ast.Inspect(file, func(n ast.Node) bool { - switch n := n.(type) { - case *ast.FuncDecl: - checkSig(info.Defs[n.Name].Type().(*types.Signature)) - case *ast.FuncLit: - checkSig(info.Types[n.Type].Type.(*types.Signature)) - } - return true - }) - } -} -``` - - -As before, `Inspect` applies a function to every node in the AST. -The function cares about two kinds of nodes: declarations of named -functions and methods (`*ast.FuncDecl`) and function literals -(`*ast.FuncLit`). -Observe the two cases' different logic to obtain the type of each -function. - - - -Here's a typical invocation on the standard `encoding/xml` package. -It reports a number of places where the 7-word -[`StartElement` type](https://godoc.org/encoding/xml#StartElement) -is copied. - - -``` -% ./hugeparam encoding/xml -/go/src/encoding/xml/marshal.go:167:50: "start" parameter: encoding/xml.StartElement = 56 bytes -/go/src/encoding/xml/marshal.go:734:97: "" result: encoding/xml.StartElement = 56 bytes -/go/src/encoding/xml/marshal.go:761:51: "start" parameter: encoding/xml.StartElement = 56 bytes -/go/src/encoding/xml/marshal.go:781:68: "start" parameter: encoding/xml.StartElement = 56 bytes -/go/src/encoding/xml/xml.go:72:30: "" result: encoding/xml.StartElement = 56 bytes -``` - -# Imports - - -The type checker's `Check` function processes a slice of parsed -files (`[]*ast.File`) that make up one package. -When the type checker encounters an import declaration, it needs the -type information for the objects in the imported package. -It gets it by calling the `Import` method of the `Importer` -interface shown below, an instance of which must be provided by the -`Config`. -This separation of concerns relieves the type checker from having to -know any of the details of Go workspace organization, `GOPATH`, -compiler file formats, and so on. - - - type Importer interface { - Import(path string) (*Package, error) - } - - -Most of our examples used the simplest `Importer` implementation, -`importer.Default()`, provided by the `go/importer` package. -This importer looks in `$GOROOT` and `$GOPATH` for `.a` -files written by the compiler (`gc` or `gccgo`) -that was used to build the program. -In addition to object code, these files contain _export data_, -that is, a description of all the objects declared by the package, and -also of any objects from other packages that were referred to indirectly. -Because export data includes information about dependencies, the type -checker need load at most one file per import, instead of one per -transitive dependency. - - - -Compiler export data is compact and efficient to locate, load, and -parse, but it has several shortcomings. -First, it does not contain position information for imported -objects, reducing the quality of certain diagnostic messages. -Second, it does not contain complete syntax trees nor semantic information -about the contents of function bodies, so it is not suitable for -interprocedural analyses. -Third, compiler object data may be stale. Nothing detects or ensures -that the object files are more recent than the source files from which -they were derived. -Generally, object data for standard packages is likely to be -up-to-date, but for user packages, it depends on how recently the user -ran a `go install` or `go build -i` command. - - - -The [`golang.org/tools/x/go/loader` package](https://godoc.org/golang.org/x/tools/go/loader) -provides an alternative `Importer` that addresses -some of these problems. -It loads a complete program from source, performing -[`cgo`](https://golang.org/cmd/cgo/cgo) preprocessing if -necessary, followed by parsing and type-checking. -It loads independent packages in parallel to hide I/O latency, and -detects and reports import cycles. -For each package, it provides the `types.Package` containing the -package's lexical environment, the list of `ast.File` syntax -trees for each file in the package, the `types.Info` containing -type information for each syntax node, and a list of type errors -associated with that package. -(Please be aware that the `go/loader` package's API is likely to -change before it finally stabilizes.) - - - -The `doc` program below demonstrates a simple use of the loader. -It is a rudimentary implementation of `go doc` that prints the type, -methods, and documentation of the package-level object specified on -the command line. -Here's an example: - - -``` -$ ./doc net/http File -type net/http.File interface{Readdir(count int) ([]os.FileInfo, error); Seek(offset int64, whence int) (int64, error); Stat() (os.FileInfo, error); io.Closer; io.Reader} -/go/src/io/io.go:92:2: method (net/http.File) Close() error -/go/src/io/io.go:71:2: method (net/http.File) Read(p []byte) (n int, err error) -/go/src/net/http/fs.go:65:2: method (net/http.File) Readdir(count int) ([]os.FileInfo, error) -/go/src/net/http/fs.go:66:2: method (net/http.File) Seek(offset int64, whence int) (int64, error) -/go/src/net/http/fs.go:67:2: method (net/http.File) Stat() (os.FileInfo, error) - - A File is returned by a FileSystem's Open method and can be -served by the FileServer implementation. - -The methods should behave the same as those on an *os.File. -``` - - -Observe that it prints the correct location of each method -declaration, even though, due to embedding, some of -`http.File`'s methods were declared in another package. -Here's the first part of the program, showing how to load an entire -program starting from the single package, `pkgpath`: - - - // go get golang.org/x/example/gotypes/doc - -``` -pkgpath, name := os.Args[1], os.Args[2] - -// The loader loads a complete Go program from source code. -conf := loader.Config{ParserMode: parser.ParseComments} -conf.Import(pkgpath) -lprog, err := conf.Load() -if err != nil { - log.Fatal(err) // load error -} - -// Find the package and package-level object. -pkg := lprog.Package(pkgpath).Pkg -obj := pkg.Scope().Lookup(name) -if obj == nil { - log.Fatalf("%s.%s not found", pkg.Path(), name) -} -``` - - -Notice that we instructed the parser to retain comments during parsing. -The rest of the program prints the output: - - - // go get golang.org/x/example/gotypes/doc - -``` -// Print the object and its methods (incl. location of definition). -fmt.Println(obj) -for _, sel := range typeutil.IntuitiveMethodSet(obj.Type(), nil) { - fmt.Printf("%s: %s\n", lprog.Fset.Position(sel.Obj().Pos()), sel) -} - -// Find the path from the root of the AST to the object's position. -// Walk up to the enclosing ast.Decl for the doc comment. -_, path, _ := lprog.PathEnclosingInterval(obj.Pos(), obj.Pos()) -for _, n := range path { - switch n := n.(type) { - case *ast.GenDecl: - fmt.Println("\n", n.Doc.Text()) - return - case *ast.FuncDecl: - fmt.Println("\n", n.Doc.Text()) - return - } -} -``` - - -We used `IntuitiveMethodSet` to compute the method set, instead -of `NewMethodSet`. -The result of this convenience function, which is intended for use in -user interfaces, includes methods of `*T` as well as those of -`T`, since that matches most users' intuition about the method -set of a type. -(Our example, `http.File`, didn't illustrate the difference, but try -running it on a type with both value and pointer methods.) - - - -Also notice `PathEnclosingInterval`, which finds the set of AST -nodes that enclose a particular point, in this case, the object's -declaring identifier. -By walking up with path, we find the enclosing declaration, to which -the documentation is attached. - - - -# Formatting support - - -All types that satisfy `Type` or `Object` define a -`String` method that formats the type or object in a readable -notation. `Selection` also provides a `String` method. -All package-level objects within these data structures are -printed with the complete package path, as in these examples: - - - []encoding/json.Marshaler // a *Slice type - encoding/json.Marshal // a *Func object - (*encoding/json.Encoder).Encode // a *Func object (method) - func (enc *encoding/json.Encoder) Encode(v interface{}) error // a method *Signature - func NewEncoder(w io.Writer) *encoding/json.Encoder // a function *Signature - - -This notation is unambiguous, but it is not legal Go syntax. -Also, package paths may be long, and the same package path may appear -many times in a single string, for instance, when formatting a -function of several parameters. -Because these strings often form part of a tool's user interface---as -with the diagnostic messages of `hugeparam` or the code generated -by `skeleton`---many clients want more control over the -formatting of package names. - - - -The `go/types` package provides these alternatives to the -`String` methods: - - - func ObjectString(obj Object, qf Qualifier) string - func TypeString(typ Type, qf Qualifier) string - func SelectionString(s *Selection, qf Qualifier) string - - type Qualifier func(*Package) string - - -The `TypeString`, `ObjectString`, and `SelectionString` -functions are like the `String` methods of the respective types, -but they accept an additional argument, a `Qualifier`. - - - -A `Qualifier` is a client-provided function that determines how a -package name is rendered as a string. -If it is nil, the default behavior is to print the package's -path, just like the `String` methods do. -If a caller passes `(*Package).Name` as the qualifier, that is, a -function that accepts a package and returns its `Name`, then -objects are qualified only by the package name. -The above examples would look like this: - - - []json.Marshaler - json.Marshal - (*json.Encoder).Encode - func (enc *json.Encoder) Encode(v interface{}) error - func NewEncoder(w io.Writer) *json.Encoder - - -Often when a tool prints some output, it is implicitly in the -context of a particular package, perhaps one specified by the -command line or HTTP request. -In that case, it is more natural to omit the package qualification -altogether for objects belonging to that package, but to qualify all -other objects by their package's path. -That's what the `RelativeTo(pkg)` qualifier does: - - - func RelativeTo(pkg *Package) Qualifier - - -The examples below show how `json.NewEncoder` would be printed -using three qualifiers, each relative to a different package: - - - // RelativeTo "encoding/json": - func NewEncoder(w io.Writer) *Encoder - - // RelativeTo "io": - func NewEncoder(w Writer) *encoding/json.Encoder - - // RelativeTo any other package: - func NewEncoder(w io.Writer) *encoding/json.Encoder - - -Another qualifier that may be relevant to refactoring tools (but is -not currently provided by the type checker) is one that renders each -package name using the locally appropriate name within a given source -file. -Its behavior would depend on the set of import declarations, including -renaming imports, within that source file. - - - -# Getting from A to B - - -The type checker and its related packages represent many aspects of a -Go program in many different ways, and analysis tools must often map -between them. -For instance, a named entity may be identified by its `Object`; -by its declaring identifier (`ast.Ident`) or by any referring -identifier; by its declaring `ast.Node`; by the position -(`token.Pos`) of any those nodes; or by the filename and -line/column number (or byte offset) of those `token.Pos` values. - - - -In this section, we'll list solutions to a number of common problems -of the form "I have an A; I need the corresponding B". - - - -To map **from a `token.Pos` to an `ast.Node`**, call the -helper function -[`astutil.PathEnclosingInterval`](https://godoc.org/golang.org/x/tools/go/ast/astutil#PathEnclosingInterval). -It returns the enclosing `ast.Node`, and all its ancestors up to -the root of the file. -You must know which file `*ast.File` the `token.Pos` belongs to. -Alternatively, you can search an entire program loaded by the -`loader` package, using -[`(*loader.Program).PathEnclosingInterval`](https://godoc.org/golang.org/x/tools/go/loader#Program.PathEnclosingInterval). - - - -To map **from an `Object` to its declaring syntax**, call -`Pos` to get its position, then use `PathEnclosingInterval` as before. -This approach is suitable for a one-off query. For repeated use, it -may be more efficient to visit the syntax tree and construct the -mapping between declarations and objects. - - - -To map **from an `ast.Ident` to the `Object`** it refers to (or -declares), consult the `Uses` or `Defs` map for the -package, as shown in [Identifier Resolution](#identifier-resolution). - - - -To map **from an `Object` to its documentation**, find the -object's declaration, and look at the attached `Doc` field. -You must have set the parser's `ParseComments` flag. -See the `doc` example in [Imports](#imports). diff --git a/gotypes/defsuses/main.go b/gotypes/defsuses/main.go deleted file mode 100644 index 608c529a..00000000 --- a/gotypes/defsuses/main.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -import ( - "fmt" - "go/ast" - "go/importer" - "go/parser" - "go/token" - "go/types" - "log" -) - -const hello = `package main - -import "fmt" - -func main() { - fmt.Println("Hello, world") -} -` - -//!+ -func PrintDefsUses(fset *token.FileSet, files ...*ast.File) error { - conf := types.Config{Importer: importer.Default()} - info := &types.Info{ - Defs: make(map[*ast.Ident]types.Object), - Uses: make(map[*ast.Ident]types.Object), - } - _, err := conf.Check("hello", fset, files, info) - if err != nil { - return err // type error - } - - for id, obj := range info.Defs { - fmt.Printf("%s: %q defines %v\n", - fset.Position(id.Pos()), id.Name, obj) - } - for id, obj := range info.Uses { - fmt.Printf("%s: %q uses %v\n", - fset.Position(id.Pos()), id.Name, obj) - } - return nil -} - -//!- - -func main() { - // Parse one file. - fset := token.NewFileSet() - f, err := parser.ParseFile(fset, "hello.go", hello, 0) - if err != nil { - log.Fatal(err) // parse error - } - if err := PrintDefsUses(fset, f); err != nil { - log.Fatal(err) // type error - } -} - -/* -//!+output -$ go build github.com/golang/example/gotypes/defsuses -$ ./defsuses -hello.go:1:9: "main" defines -hello.go:5:6: "main" defines func hello.main() -hello.go:6:9: "fmt" uses package fmt -hello.go:6:13: "Println" uses func fmt.Println(a ...interface{}) (n int, err error) -//!-output -*/ diff --git a/gotypes/doc/main.go b/gotypes/doc/main.go deleted file mode 100644 index 3140f473..00000000 --- a/gotypes/doc/main.go +++ /dev/null @@ -1,77 +0,0 @@ -// The doc command prints the doc comment of a package-level object. -package main - -import ( - "fmt" - "go/ast" - "go/parser" - "log" - "os" - - // TODO: these will use std go/types after Feb 2016 - "golang.org/x/tools/go/loader" - "golang.org/x/tools/go/types/typeutil" -) - -func main() { - if len(os.Args) != 3 { - log.Fatal("Usage: doc ") - } - //!+part1 - pkgpath, name := os.Args[1], os.Args[2] - - // The loader loads a complete Go program from source code. - conf := loader.Config{ParserMode: parser.ParseComments} - conf.Import(pkgpath) - lprog, err := conf.Load() - if err != nil { - log.Fatal(err) // load error - } - - // Find the package and package-level object. - pkg := lprog.Package(pkgpath).Pkg - obj := pkg.Scope().Lookup(name) - if obj == nil { - log.Fatalf("%s.%s not found", pkg.Path(), name) - } - //!-part1 - //!+part2 - - // Print the object and its methods (incl. location of definition). - fmt.Println(obj) - for _, sel := range typeutil.IntuitiveMethodSet(obj.Type(), nil) { - fmt.Printf("%s: %s\n", lprog.Fset.Position(sel.Obj().Pos()), sel) - } - - // Find the path from the root of the AST to the object's position. - // Walk up to the enclosing ast.Decl for the doc comment. - _, path, _ := lprog.PathEnclosingInterval(obj.Pos(), obj.Pos()) - for _, n := range path { - switch n := n.(type) { - case *ast.GenDecl: - fmt.Println("\n", n.Doc.Text()) - return - case *ast.FuncDecl: - fmt.Println("\n", n.Doc.Text()) - return - } - } - //!-part2 -} - -/* -//!+output -$ ./doc net/http File -type net/http.File interface{Readdir(count int) ([]os.FileInfo, error); Seek(offset int64, whence int) (int64, error); Stat() (os.FileInfo, error); io.Closer; io.Reader} -/go/src/io/io.go:92:2: method (net/http.File) Close() error -/go/src/io/io.go:71:2: method (net/http.File) Read(p []byte) (n int, err error) -/go/src/net/http/fs.go:65:2: method (net/http.File) Readdir(count int) ([]os.FileInfo, error) -/go/src/net/http/fs.go:66:2: method (net/http.File) Seek(offset int64, whence int) (int64, error) -/go/src/net/http/fs.go:67:2: method (net/http.File) Stat() (os.FileInfo, error) - - A File is returned by a FileSystem's Open method and can be -served by the FileServer implementation. - -The methods should behave the same as those on an *os.File. -//!-output -*/ diff --git a/gotypes/go-types.md b/gotypes/go-types.md deleted file mode 100644 index d59516ae..00000000 --- a/gotypes/go-types.md +++ /dev/null @@ -1,2055 +0,0 @@ - -# `go/types`: The Go Type Checker - -This document is maintained by Alan Donovan `adonovan@google.com`. - -[October 2015 GothamGo talk on go/types](https://docs.google.com/presentation/d/13OvHYozAUBeISPRoLgG7kMBuja1NsU1D_mMlmbaYojk/view) - - -# Contents - -%toc - -# Introduction - - -The [`go/types` package]('https://golang.org/pkg/go/types) is a -type-checker for Go programs, designed by Robert Griesemer. -It became part of Go's standard library in Go 1.5. -Measured by lines of code and by API surface area, it is one of the -most complex packages in Go's standard library, and using it requires -a firm grasp of the structure of Go programs. -This tutorial will help you find your bearings. -It comes with several example programs that you can obtain with `go get` and play with. -We assume you are a proficient Go programmer who wants to build tools -to analyze or manipulate Go programs and that you have some knowledge -of how a typical compiler works. - -The type checker complements several existing -standard packages for analyzing Go programs. -We've listed them below. - - - → go/types - go/constant - go/parser - go/ast - go/scanner - go/token - - -Starting at the bottom, the -[`go/token` package](http://golang.org/pkg/go/token) -defines the lexical tokens of Go. -The [`go/scanner` package](http://golang.org/pkg/go/scanner) tokenizes an input stream and records -file position information for use in diagnostics -or for file surgery in a refactoring tool. -The [`go/ast` package](http://golang.org/pkg/go/ast) -defines the data types of the abstract syntax tree (AST). -The [`go/parser` package](http://golang.org/pkg/go/parser) -provides a robust recursive-descent parser that constructs the AST. -And [`go/constant`](http://golang.org/pkg/go/constant) -provides representations and arithmetic operations for the values of compile-time -constant expressions, as we'll see in -[Constants](#constants). - - - -The [`golang.org/x/tools/go/loader` package](https://godoc.org/golang.org/x/tools/go/loader) -from the `x/tools` repository is a client of the type -checker that loads, parses, and type-checks a complete Go program from -source code. -We use it in some of our examples and you may find it useful too. - - - -The Go type checker does three main things. -First, for every name in the program, it determines which declaration -the name refers to; this is known as _identifier resolution_. -Second, for every expression in the program, it determines what type -that expression has, or reports an error if the expression has no -type, or has an inappropriate type for its context; this is known as -_type deduction_. -Third, for every constant expression in the program, it determines the -value of that constant; this is known as _constant evaluation_. - - - -Superficially, it appears that these three processes could be done -sequentially, in the order above, but perhaps surprisingly, they must -be done together. -For example, the value of a constant may depend on the type of an -expression due to operators like `unsafe.Sizeof`. -Conversely, the type of an expression may depend on the value of a -constant, since array types contain constants. -As a result, type deduction and constant evaluation must be done -together. - - - -As another example, we cannot resolve the identifier `k` in the composite -literal `T{k: 0}` until we know whether `T` is a struct type. -If it is, then `k` must be found among `T`'s fields. -If not, then `k` is an ordinary reference -to a constant or variable in the lexical environment. -Consequently, identifier resolution and type deduction are also -inseparable in the general case. - - - -Nonetheless, the three processes of identifier resolution, type -deduction, and constant evaluation can be separated for the purpose of -explanation. - - -# An Example - - -The code below shows the most basic use of the type checker to check -the _hello, world_ program, supplied as a string. -Later examples will be variations on this one, and we'll often omit -boilerplate details such as parsing. -To check out and build the examples, -run `go get github.com/golang/example/gotypes/...`. - - -%include pkginfo/main.go - - -First, the program creates a -[`token.FileSet`](http://golang.org/pkg/go/token/#FileSet). -To avoid the need to store file names and line and column -numbers in every node of the syntax tree, the `go/token` package -provides `FileSet`, a data structure that stores this information -compactly for a sequence of files. -A `FileSet` records each file name only once, and records -only the byte offsets of each newline, allowing a position within -any file to be identified using a small integer called a -`token.Pos`. -Many tools create a single `FileSet` at startup. -Any part of the program that needs to convert a `token.Pos` into -an intelligible location---as part of an error message, for -instance---must have access to the `FileSet`. - - - -Second, the program parses the input string. -More realistic packages contain several source files, so the parsing -step must be repeated for each one, or better, done in parallel. -Third, it creates a `Config` that specifies type-checking options. -Since the _hello, world_ program uses imports, we must indicate -how to locate the imported packages. -Here we use `importer.Default()`, which loads compiler-generated -export data, but we'll explore alternatives in [Imports](#imports). - - - -Fourth, the program calls `Check`. -This creates a `Package` whose path is `"cmd/hello"`, and -type-checks each of the specified files---just one in this example. -The final (nil) argument is a pointer to an optional `Info` -struct that returns additional deductions from the type checker; more -on that later. -`Check` returns a `Package` even when it also returns an error. -The type checker is robust to ill-formed input, -and goes to great lengths to report accurate -partial information even in the vicinity of syntax or type errors. -`Package` has this definition: - - - type Package struct{ ... } - func (*Package) Path() string - func (*Package) Name() string - func (*Package) Scope() *Scope - func (*Package) Imports() []*Package - - -Finally, the program prints the attributes of the package, shown below. -(The hexadecimal number may vary from one run to the next.) - - -%include pkginfo/main.go output - - - -A package's `Path`, such as `"encoding/json"`, is the string -by which import declarations identify it. -It is unique within a `$GOPATH` workspace, -and for published packages it must be globally unique. - - -A package's `Name` is the identifier in the `package` -declaration of each source file within the package, such as `json`. -The type checker reports an error if not all the package declarations in -the package agree. -The package name determines how the package is known when it is -imported into a file (unless a renaming import is used), -but is otherwise not visible to a program. - - -`Scope` returns the package's [_lexical block_](#scopes), -which provides access to all the named entities or -[_objects_](#objects) declared at package level. -`Imports` returns the set of packages directly imported by this -one, and may be useful for computing dependencies -([Initialization Order](#initialization-order)). - - - -# Objects - - -The task of identifier resolution is to map every identifier in the -syntax tree, that is, every `ast.Ident`, to an object. -For our purposes, an _object_ is a named entity created by a -declaration, such as a `var`, `type`, or `func` -declaration. -(This is different from the everyday meaning of object in -object-oriented programming.) - - - -Objects are represented by the `Object` interface: - - - type Object interface { - Name() string // package-local object name - Exported() bool // reports whether the name starts with a capital letter - Type() Type // object type - Pos() token.Pos // position of object identifier in declaration - - Parent() *Scope // scope in which this object is declared - Pkg() *Package // nil for objects in the Universe scope and labels - Id() string // object id (see Ids section below) - } - - -The first four methods are straightforward; we'll explain the other -three later. -`Name` returns the object's name---an identifier. -`Exported` is a convenience method that reports whether the first -letter of `Name` is a capital, indicating that the object may be -visible from outside the package. -It's a shorthand for `ast.IsExported(obj.Name())`. -`Type` returns the object's type; we'll come back to that in -[Types](#types). - - - -`Pos` returns the source position of the object's declaring identifier. -To make sense of a `token.Pos`, we need to call the -`(*token.FileSet).Position` method, which returns a struct with -individual fields for the file name, line number, column, and byte -offset, though usually we just call its `String` method: - - - fmt.Println(fset.Position(obj.Pos())) // "hello.go:10:6" - - -Not all objects carry position information. -Since the file format for compiler export data ([Imports](#imports)) -does not record position information, calling `Pos` on an object -imported from such a file returns zero, also known as -`token.NoPos`. - - - -There are eight kinds of objects in the Go type checker. -Most familiar are the kinds that can be declared at package level: -constants, variables, functions, and types. -Less familiar are statement labels, imported package names -(such as `json` in a file containing an `import "encoding/json"` -declaration), built-in functions (such as `append` and -`len`), and the pre-declared `nil`. -The eight types shown below are the only concrete types that satisfy -the `Object` interface. -In other words, `Object` is a _discriminated union_ of 8 -possible types, and we commonly use a type switch to distinguish them. - - - Object = *Func // function, concrete method, or abstract method - | *Var // variable, parameter, result, or struct field - | *Const // constant - | *TypeName // type name - | *Label // statement label - | *PkgName // package name, e.g. json after import "encoding/json" - | *Builtin // predeclared function such as append or len - | *Nil // predeclared nil - - -`Object`s are canonical. -That is, two `Object`s `x` and `y` denote the same -entity if and only if `x==y`. -Object identity is significant, and objects are routinely compared by -the addresses of the underlying pointers. -Although a package-level object is uniquely identified by its name -and enclosing package, for other objects there is no simple way to -obtain a string that uniquely identifies it. - - - -The `Parent` method returns the `Scope` (lexical block) in -which the object was declared; we'll come back to this in -[Scopes](#scopes). -Fields and methods are not found in the lexical environment, so -their objects have no `Parent`. - - - - -The `Pkg` method returns the `Package` to which this object -belongs, even for objects not declared at package level. -Only predeclared objects have no package. -The `Id` method will be explained in [Ids](#ids). - - - -Not all methods make sense for each kind of object. For instance, -the last four kinds above have no meaningful `Type` method. -And some kinds of objects have methods in addition to those required by the -`Object` interface: - - - func (*Func) Scope() *Scope - func (*Var) Anonymous() bool - func (*Var) IsField() bool - func (*Const) Val() constant.Value - func (*TypeName) IsAlias() bool - func (*PkgName) Imported() *Package - - -`(*Func).Scope` returns the [lexical block](#scopes) -containing the function's parameters, results, -and other local declarations. -`(*Var).IsField` distinguishes struct fields from ordinary -variables, and `(*Var).Anonymous` discriminates named fields like -the one in `struct{T T}` from anonymous fields like the one in `struct{T}`. -`(*Const).Val` returns the value of a named [constant](#constants). - - -`(*TypeName).IsAlias`, introduced in Go 1.9, reports whether the -type name is simply an alias for a type (as in `type I = int`), -as opposed to a definition of a [`Named`](#named-types) type, as -in `type Celsius float64`. - - -`(*PkgName).Imported` returns the package (for instance, -`encoding/json`) denoted by a given import name such as `json`. -Each time a package is imported, a new `PkgName` object is -created, usually with the same name as the `Package` it -denotes, but not always, as in the case of a renaming import. -`PkgName`s are objects, but `Package`s are not. -We'll look more closely at this in [Imports](#imports). - - - -All relationships between the syntax trees (`ast.Node`s) and type -checker data structures such as `Object`s and `Type`s are -stored in mappings outside the syntax tree itself. -Be aware that the `go/ast` package also defines a type called -`Object` that resembles---and predates---the type checker's -`Object`, and that `ast.Object`s are held directly by -identifiers in the AST. -They are created by the parser, which has a necessarily limited view -of the package, so the information they represent is at best partial and -in some cases wrong, as in the `T{k: 0}` example mentioned above. -If you are using the type checker, there is no reason to use the older -`ast.Object` mechanism. - - - -# Identifier Resolution - - -Identifier resolution computes the relationship between -identifiers and objects. -Its results are recorded in the `Info` struct optionally passed -to `Check`. -The fields related to identifier resolution are shown below. - - - type Info struct { - Defs map[*ast.Ident]Object - Uses map[*ast.Ident]Object - Implicits map[ast.Node]Object - Selections map[*ast.SelectorExpr]*Selection - Scopes map[ast.Node]*Scope - ... - } - - -Since not all facts computed by the type checker are needed by every -client, the API lets clients control which components of the result -should be recorded and which discarded: only fields that hold a -non-nil map will be populated during the call to `Check`. - - - -The two fields of type `map[*ast.Ident]Object` are the most important: -`Defs` records _declaring_ identifiers and -`Uses` records _referring_ identifiers. -In the example below, the comments indicate which identifiers are of -which kind. - - - var x int // def of x, use of int - fmt.Println(x) // uses of fmt, Println, and x - type T struct{U} // def of T, use of U (type), def of U (field) - - -The final line above illustrates why we don't combine `Defs` and -`Uses` into one map. -In the anonymous field declaration `struct{U}`, the -identifier `U` is both a use of the type `U` (a -`TypeName`) and a definition of the anonymous field (a -`Var`). - - - -The function below prints the location of each referring and defining -identifier in the input program, and the object it refers to. - - -%include defsuses/main.go - - -Let's use the _hello, world_ program again as the input: - - -%include hello/hello.go - - -This is what it prints: - - -%include defsuses/main.go output - - - -Notice that the `Defs` mapping may contain nil entries in a few -cases. -The first line of output reports that the package identifier -`main` is present in the `Defs` mapping, but has no -associated object. - - - -The `Implicits` mapping handles two cases of the syntax in -which an `Object` is declared without an `ast.Ident`, namely type -switches and import declarations. - -In the type switch below, which declares a local variable `y`, -the type of `y` is different in each case of the switch: - - - switch y := x.(type) { - case int: - fmt.Printf("%d", y) - case string: - fmt.Printf("%q", y) - default: - fmt.Print(y) - } - - -To represent this, for each single-type case, the type checker creates -a separate `Var` object for `y` with the appropriate type, -and `Implicits` maps each `ast.CaseClause` to the `Var` -for that case. -The `default` case, the `nil` case, and cases with more than one -type all use the regular `Var` object that is associated with the -identifier `y`, which is found in the `Defs` mapping. - - - -The import declaration below defines the name `json` without an -`ast.Ident`: - - - import "encoding/json" - - -`Implicits` maps this `ast.ImportSpec` to the `PkgName` -object named `json` that it implicitly declares. - - - -The `Selections` mapping, of type -`map[*ast.SelectorExpr]*Selection`, records the meaning of each -expression of the form _`expr`_`.f`, where _`expr`_ is -an expression or type and `f` is the name of a field or method. -These expressions, called _selections_, are represented by -`ast.SelectorExpr` nodes in the AST. -We'll talk more about the `Selection` type in [Selections](#selections). - - - -Not all `ast.SelectorExpr` nodes represent selections. -Expressions like `fmt.Println`, in which a package name precedes -the dot, are _qualified identifiers_. -They do not appear in the `Selections` mapping, but their -constituent identifiers (such as `fmt` and `Println`) both -appear in `Uses`. - - - -Referring identifiers that are not part of an `ast.SelectorExpr` -are _lexical references_. -That is, they are resolved to an object by searching for the -innermost enclosing lexical declaration of that name. -We'll see how that search works in the next section. - - -# Scopes - - -The `Scope` type is a mapping from names to objects. - - - type Scope struct{ ... } - - func (s *Scope) Names() []string - func (s *Scope) Lookup(name string) Object - - -`Names` returns the set of names in the mapping, in sorted order. -(It is not a simple accessor though, so call it sparingly.) -The `Lookup ` method returns the object for a given name, so we -can print all the entries or _bindings_ in a scope like this: - - - for _, name := range scope.Names() { - fmt.Println(scope.Lookup(name)) - } - - -The _scope_ of a declaration of a name is the region of -program source in which a reference to the name resolves to that -declaration. That is, scope is a property of a declaration. -However, in the `go/types` API, the `Scope` type represents -a _lexical block_, which is one component of the lexical -environment. -Consider the _hello, world_ program again: - - - package main - - import "fmt" - - func main() { - const message = "hello, world" - fmt.Println(message) - } - - -There are four lexical blocks in this program. -The outermost one is the _universe block_, which maps the -pre-declared names like `int`, `true`, and `append` to -their objects---a `TypeName`, a `Const`, and a -`Builtin`, respectively. -The universe block is represented by the global variable -`Universe`, of type `*Scope`, although it's logically a -constant so you shouldn't modify it. - - - -Next is the _package block_, which maps `"main"` to the -`main` function. -Following that is the _file block_, which maps `"fmt"` to -the `PkgName` object for this import of the `fmt` package. -And finally, the innermost block is that of function `main`, a -local block, which contains the declaration of `message`, a `Const`. -The `main` function is trivial, but many functions contain -several blocks since each `if`, `for`, `switch`, -`case`, or `select` statement creates at least one -additional block. -Local blocks nest to arbitrary depths. - - - -The structure of the lexical environment thus forms a tree, with the -universe block at the root, the package blocks beneath it, the file -blocks beneath them, and then any number of local blocks beneath the -files. -We can access and navigate this tree structure with the following -methods of `Scope`: - - - func (s *Scope) Parent() *Scope - func (s *Scope) NumChildren() int - func (s *Scope) Child(i int) *Scope - - -`Parent` lets us walk up the tree, and `Child` -lets us walk down it. -Note that although the `Parent` of every package `Scope` is -`Universe`, `Universe` has no children. -This asymmetry is a consequence of using a global variable to hold -`Universe`. - - - -To obtain the universe block, we use the `Universe` global variable. -To obtain the lexical block of a `Package`, we call its -`Scope` method. -To obtain the scope of a file (`*ast.File`), or any smaller piece -of syntax such as an `*ast.IfStmt`, we consult the `Scopes` -mapping in the `Info` struct, which maps each block-creating -syntax node to its block. -The lexical block of a named function or method can also be obtained -by calling its `(*Func).Scope` method. - - - - - -To look up a name in the lexical environment, we must search the tree -of lexical blocks, starting at a particular `Scope` and walking -up to the root until a declaration of the name is found. -For convenience, the `LookupParent` method does this, returning -not just the object, if found, but also the `Scope` in which it was -declared, which may be an ancestor of the initial one: - - - func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) - - -The `pos` parameter determines the position in the source code at -which the name should be resolved. -The effective lexical environment is different at each point in the -block because it depends on which local declarations appear -before or after that point. -(We'll see an illustration in a moment.) - - - -`Scope` has several other methods relating to source positions: - - - func (s *Scope) Pos() token.Pos - func (s *Scope) End() token.Pos - func (s *Scope) Contains(pos token.Pos) bool - func (s *Scope) Innermost(pos token.Pos) *Scope - - -`Pos` and `End` report the `Scope`'s start and end -position which, for explicit blocks, coincide with its curly -braces. -`Contains` is a convenience method that reports whether a -position lies in this interval. -`Innermost` returns the innermost scope containing the specified -position, which may be a child or other descendent of the initial -scope. - - - -These features are useful for tools that wish to resolve names or -evaluate constant expressions as if they had appeared at a particular -point within the program. -The next example program finds all the comments in the input, -treating the contents of each one as a name. It looks up each name in -the environment at the position of the comment, and prints what it -finds. -Observe that the `ParseComments` flag directs the parser to -preserve comments in the input. - - -%include lookup/lookup.go main - - -The expression `pkg.Scope().Innermost(pos)` finds the innermost -`Scope` that encloses the comment, and `LookupParent(name, pos)` -does a name lookup at a specific position in that lexical block. - - - -A typical input is shown below. -The first comment causes a lookup of `"append"` in the file block. -The second comment looks up `"fmt"` in the `main` function's block, -and so on. - - -%include lookup/lookup.go input - - - -Here's the output: - - -%include lookup/lookup.go output - - - -Notice how the two lookups of `main` return different results, -even though they occur in the same block, because one precedes the -declaration of the local variable named `main` and the other -follows it. -Also notice that there are two lookups of the name `x` but only -the first one, in the function block, succeeds. - - - -Download the program and modify both the input program and -the set of comments to get a better feel for how name resolution works. - - - -The table below summarizes which kinds of objects may be declared at -each level of the tree of lexical blocks. - - - Universe File Package Local - Builtin ✔ - Nil ✔ - Const ✔ ✔ ✔ - TypeName ✔ ✔ ✔ - Func ✔ - Var ✔ ✔ - PkgName ✔ - Label ✔ - - -# Initialization Order - - -In the course of identifier resolution, the type checker constructs a -graph of references among declarations of package-level variables and -functions. -The type checker reports an error if the initializer expression for a -variable refers to that variable, whether directly or indirectly. - - - -The reference graph determines the initialization order of the -package-level variables, as required by the Go spec, using a -breadth-first algorithm. -First, variables in the graph with no successors are removed, sorted -into the order in which they appear in the source code, then added -to a list. This creates more variables that have no successors. -The process repeats until they have all been removed. - - - -The result is available in the `InitOrder` field of the -`Info` struct, whose type is `[]Initializer`. - - - type Info struct { - ... - InitOrder []Initializer - ... - } - - type Initializer struct { - Lhs []*Var // var Lhs = Rhs - Rhs ast.Expr - } - - -Each element of the list represents a single initializer expression -that must be executed, and the variables to which it is assigned. -The variables may number zero, one, or more, as in these examples: - - - var _ io.Writer = new(bytes.Buffer) - var rx = regexp.MustCompile("^b(an)*a$") - var cwd, cwdErr = os.Getwd() - - -This process governs the initialization order of variables within a -package. -Across packages, dependencies must be initialized first, although the -order among them is not specified. -That is, any topological order of the import graph will do. -The `(*Package).Imports` method returns the set of direct -dependencies of a package. - - -# Types - - -The main job of the type checker is, of course, to deduce the type -of each expression and to report type errors. -Like `Object`, `Type` is an interface type used as a -discriminated union of several concrete types but, unlike -`Object`, `Type` has very few methods because types have -little in common with each other. -Here is the interface: - - - type Type interface { - Underlying() Type - } - - -And here are the eleven concrete types that satisfy it: - - - Type = *Basic - | *Pointer - | *Array - | *Slice - | *Map - | *Chan - | *Struct - | *Tuple - | *Signature - | *Named - | *Interface - - -With the exception of `Named` types, instances of `Type` are -not canonical. -That is, it is usually a mistake to compare types using `t1==t2` -since this equivalence is not the same as the -[type identity relation](https://golang.org/ref/spec#Type_identity) -defined by the Go spec. -Use this function instead: - - - func Identical(t1, t2 Type) bool - - -For the same reason, you should not use a `Type` as a key in a map. -The [`golang.org/x/tools/go/types/typeutil` package](https://godoc.org/golang.org/x/tools/go/types/typeutil) -provides a map keyed by types that uses the correct -equivalence relation. - - -The Go spec defines three relations over types. -[_Assignability_](https://golang.org/ref/spec#Assignability) -governs which pairs of types may appear on the -left- and right-hand side of an assignment, including implicit -assignments such as function calls, map and channel operations, and so -on. -[_Comparability_](https://golang.org/ref/spec#Comparison_operators) -determines which types may appear in a comparison `x==y` or a -switch case or may be used as a map key. -[_Convertibility_](https://golang.org/ref/spec#Conversions) -governs which pairs of types are allowed in a conversion operation -`T(v)`. -You can query these relations with the following predicate functions: - - - func AssignableTo(V, T Type) bool - func Comparable(T Type) bool - func ConvertibleTo(V, T Type) bool - - -Let's take a look at each kind of type. - - -## Basic types - - -`Basic` represents all types that are not composed from simpler -types. -This is essentially the set of underlying types that a constant expression is -permitted to have--strings, booleans, and numbers---but it also -includes `unsafe.Pointer` and untyped nil. - - - type Basic struct{...} - func (*Basic) Kind() BasicKind - func (*Basic) Name() string - func (*Basic) Info() BasicInfo - - -The `Kind` method returns an "enum" value that indicates which -basic type this is. -The kinds `Bool`, `String`, `Int16`, and so on, -represent the corresponding predeclared boolean, string, or numeric -types. -There are two synonyms: `Byte` is equivalent to `Uint8` -and `Rune` is equivalent to `Int32`. -The kind `UnsafePointer` represents `unsafe.Pointer`. -The kinds `UntypedBool`, `UntypedInt` and so on represent -the six kinds of "untyped" constant types: boolean, integer, rune, -float, complex, and string. -The kind `UntypedNil` represents the type of the predeclared -`nil` value. -And the kind `Invalid` indicates the invalid type, which is used -for expressions containing errors, or for objects without types, like -`Label`, `Builtin`, or `PkgName`. - - - -The `Name` method returns the name of the type, such as -`"float64"`, and the `Info` method returns a bitfield that -encodes information about the type, such as whether it is signed or -unsigned, integer or floating point, or real or complex. - - - -`Typ` is a table of canonical basic types, indexed by -kind, so `Typ[String]` returns the `*Basic` that represents -`string`, for instance. -Like `Universe`, `Typ` is logically a constant, so don't -modify it. - - - -A few minor subtleties: -According to the Go spec, pre-declared types such as `int` are -named types for the purposes of assignability, even though the type -checker does not represent them using `Named`. -And `unsafe.Pointer` is a pointer type for the purpose of -determining whether the receiver type of a method is legal, even -though the type checker does not represent it using `Pointer`. - - - -The "untyped" types are usually only ascribed to constant expressions, -but there is one exception. -A comparison `x==y` has type "untyped bool", so the result of -this expression may be assigned to a variable of type `bool` or -any other named boolean type. - - - -## Simple Composite Types - - -The types `Pointer`, `Array`, `Slice`, `Map`, -and `Chan` are pretty self-explanatory. -All have an `Elem` method that returns the element type `T` -for a pointer `*T`, an array `[n]T`, a slice `[]T`, a -map `map[K]T`, or a channel `chan T`. -This should feel familiar if you've used the `reflect.Value` API. - - - -In addition, the `*Map`, `*Chan`, and `*Array` types -have accessor methods that return their key type, direction, and -length, respectively: - - - func (*Map) Key() Type - func (*Chan) Dir() ChanDir // = Send | Recv | SendRecv - func (*Array) Len() int64 - - - -## Struct Types - - -A struct type has an ordered list of fields and a corresponding -ordered list of field tags. - - - type Struct struct{ ... } - func (*Struct) NumFields() int - func (*Struct) Field(i int) *Var - func (*Struct) Tag(i int) string - - -Each field is a `Var` object whose `IsField` method returns true. -Field objects have no `Parent` scope, because they are -resolved through selections, not through the lexical environment. - - - - -Thanks to embedding, the expression `new(S).f` may be a shorthand -for a longer expression such as `new(S).d.e.f`, but in the -representation of `Struct` types, these field selection -operations are explicit. -That is, the set of fields of struct type `S` does not include `f`. -An anonymous field is represented like a regular field, but its -`Anonymous` method returns true. - - - -One subtlety is relevant to tools that generate documentation. -When analyzing a declaration such as this, - - - type T struct{x int} - - -it may be tempting to consider the `Var` object for field `x` as if it -had the name `"T.x"`, but beware: field objects do not have -canonical names and there is no way to obtain the name `"T"` -from the `Var` for `x`. -That's because several types may have the same underlying struct type, -as in this code: - - - type T struct{x int} - type U T - - -Here, the `Var` for field `x` belongs equally to `T` -and to `U`, and short of inspecting source positions or walking -the AST---neither of which is possible for objects loaded from compiler -export data---it is not possible to ascertain that `x` was declared as -part of `T`. -The type checker builds the exact same data structures given this input: - - - type T U - type U struct{x int} - - -A similar issue applies to the methods of named interface types. - - -## Tuple Types - - -Like a struct, a tuple type has an ordered list of fields, and fields -may be named. - - - type Tuple struct{ ... } - func (*Tuple) Len() int - func (*Tuple) At(i int) *Var - - -Although tuples are not the type of any variable in Go, they are -the type of some expressions, such as the right-hand sides of these -assignments: - - - v, ok = m[key] - v, ok = <-ch - v, ok = x.(T) - f, err = os.Open(filename) - - -Tuples also represent the types of the parameter list and the result -list of a function, as we will see. - - - -Since empty tuples are common, the nil `*Tuple` pointer is a valid empty tuple. - - - -## Function and Method Types - - -The types of functions and methods are represented by a `Signature`, -which has a tuple of parameter types and a tuple of result types. - - - type Signature struct{ ... } - func (*Signature) Recv() *Var - func (*Signature) Params() *Tuple - func (*Signature) Results() *Tuple - func (*Signature) Variadic() bool - - -Variadic functions such as `fmt.Println` have the `Variadic` -flag set. -The final parameter of such functions is always a slice, or in the -special case of certain calls to `append`, a string. - - - -A `Signature` for a method, whether concrete or abstract, has a -non-nil receiver parameter, `Recv`. -The type of the receiver is usually a named type or a pointer to a named type, -but it may be an unnamed struct or interface type in some cases. -Method types are rather second-class: they are only used for the -`Func` objects created by method declarations, and no Go -expression has a method type. -When printing a method type, the receiver does not appear, and the -`Identical` predicate ignores the receiver. - - - -The types of `Builtin` objects like `append` cannot be -expressed as a `Signature` since those types require parametric -polymorphism. -`Builtin` objects are thus ascribed the `Invalid` basic type. -However, the type of each _call_ to a built-in function has a specific -and expressible Go type. -These types are recorded during type checking for later use -([TypeAndValue](#typeandvalue)). - - - -## Named Types - - -Type declarations come in two forms. -The simplest kind, introduced in Go 1.9, -merely declares a (possibly alternative) name for an existing type. -Type names used in this way are informally called _type aliases_. -For example, this declaration lets you use the type -`Dictionary` as an alias for `map[string]string`: - - type Dictionary = map[string]string - -The declaration creates a `TypeName` object for `Dictionary`. The -object's `IsAlias` method returns true, and its `Type` method returns -a `Map` type that represents `map[string]string`. - - -The second form of type declaration, and the only kind prior to Go -1.9, does not use an equals sign: - - type Celsius float64 - -This declaration does more than just give a name to a type. -It first defines a new `Named` type -whose underlying type is `float64`; this `Named` type is different -from any other type, including `float64`. The declaration binds the -`TypeName` object to the `Named` type. - -Since Go 1.9, the Go language specification has used the term _defined -types_ instead of named types; -the essential property of a defined type is not that it has a name, -but that it is a distinct type with its own method set. -However, the type checker API predates that -change and instead calls defined types "named" types. - - type Named struct{ ... } - func (*Named) NumMethods() int - func (*Named) Method(i int) *Func - func (*Named) Obj() *TypeName - func (*Named) Underlying() Type - -The `Named` type's `Obj` method returns the `TypeName` object, which -provides the name, position, and other properties of the declaration. -Conversely, the `TypeName` object's `Type` method returns the `Named` type. - -A `Named` type may appear as the receiver type in a method declaration. -Methods are associated with the `Named` type, not the name (the -`TypeName` object); it's possible---though cryptic---to declare a -method on a `Named` type using one of its aliases. -The `NumMethods` and `Method` methods enumerate the declared -methods associated with this `Named` type (or a pointer to it), -in the order they were declared. -However, due to the subtleties of anonymous fields and the difference -between value and pointer receivers, a named type may have more or fewer -methods than this list. We'll return to this in [Method Sets](#method-sets). - - - -Every `Type` has an `Underlying` method, but for all of them -except `*Named`, it is simply the identity function. -For a named type, `Underlying` returns its underlying type, which -is always an unnamed type. -Thus `Underlying` returns `int` for both `T` and -`U` below. - - - type T int - type U T - - -Clients of the type checker often use type assertions or type switches -with a `Type` operand. -When doing so, it is often necessary to switch on the type that -_underlies_ the type of interest, and failure to do so may be a -bug. - -This is a common pattern: - - - // handle types of composite literal - switch u := t.Underlying().(type) { - case *Struct: // ... - case *Map: // ... - case *Array, *Slice: // ... - default: - panic("impossible") - } - -## Interface Types - - -Interface types are represented by `Interface`. - - - type Interface struct{ ... } - func (*Interface) Empty() bool - func (*Interface) NumMethods() int - func (*Interface) Method(i int) *Func - func (*Interface) NumEmbeddeds() int - func (*Interface) Embedded(i int) *Named - func (*Interface) NumExplicitMethods() int - func (*Interface) ExplicitMethod(i int) *Func - - -Syntactically, an interface type has a list of explicitly declared -methods (`ExplicitMethod`), and a list of embedded named -interface types (`Embedded`), but many clients care only about -the complete set of methods, which can be enumerated via -`Method`. -All three lists are ordered by name. -Since the empty interface is an important special case, the -`Empty` predicate provides a shorthand for `NumMethods() == -0`. - - - -As with the fields of structs (see above), the methods of interfaces -may belong equally to more than one interface type. -The `Func` object for method `f` in the code below is shared -by `I` and `J`: - - - type I interface { f() } - type J I - - -Because the difference between interface (abstract) and -non-interface (concrete) types is so important in Go, the -`IsInterface` predicate is provided for convenience. - - - func IsInterface(Type) bool - - -The type checker provides three utility methods relating to interface -satisfaction: - - - func Implements(V Type, T *Interface) bool - func AssertableTo(V *Interface, T Type) bool - func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) - - -The `Implements` predicate reports whether a type satisfies an -interface type. -`MissingMethod` is like `Implements`, but instead of -returning false, it explains why a type does not satisfy the -interface, for use in diagnostics. - - - -`AssertableTo` reports whether a type assertion `v.(T)` is legal. -If `T` is a concrete type that doesn't have all the methods of -interface `v`, then the type assertion is not legal, as in this example: - - - // error: io.Writer is not assertible to int - func f(w io.Writer) int { return w.(int) } - - - -## TypeAndValue - - -The type checker records the type of each expression in another field -of the `Info` struct, namely `Types`: - - - type Info struct { - ... - Types map[ast.Expr]TypeAndValue - } - - -No entries are recorded for identifiers since the `Defs` and -`Uses` maps provide more information about them. -Also, no entries are recorded for pseudo-expressions like -`*ast.KeyValuePair` or `*ast.Ellipsis`. - - - -The value of the `Types` map is a `TypeAndValue`, which -(unsurprisingly) holds the type and value of the expression, and in -addition, its _mode_. -The mode is opaque, but has predicates to answer questions such as: -Does this expression denote a value or a type? Does this value have an -address? Does this expression appear on the left-hand side of an -assignment? Does this expression appear in a context that expects two -results? -The comments in the code below give examples of expressions that -satisfy each predicate. - - - type TypeAndValue struct { - Type Type - Value constant.Value // for constant expressions only - ... - } - - func (TypeAndValue) IsVoid() bool // e.g. "main()" - func (TypeAndValue) IsType() bool // e.g. "*os.File" - func (TypeAndValue) IsBuiltin() bool // e.g. "len(x)" - func (TypeAndValue) IsValue() bool // e.g. "*os.Stdout" - func (TypeAndValue) IsNil() bool // e.g. "nil" - func (TypeAndValue) Addressable() bool // e.g. "a[i]" but not "f()", "m[key]" - func (TypeAndValue) Assignable() bool // e.g. "a[i]", "m[key]" - func (TypeAndValue) HasOk() bool // e.g. "<-ch", "m[key]" - - -The statement below inspects every expression within the AST of a single -type-checked file and prints its type, value, and mode: - - -%include typeandvalue/main.go inspect - - -It makes use of these two helper functions, which are not shown: - - - // nodeString formats a syntax tree in the style of gofmt. - func nodeString(n ast.Node) string - - // mode returns a string describing the mode of an expression. - func mode(tv types.TypeAndValue) string - - -Given this input: - - -%include typeandvalue/main.go input - - - -the program prints: - - -%include typeandvalue/main.go output - - - -Notice that the identifiers for the built-ins `make` and -`print` have types that are specific to the particular calls in -which they appear. -Also notice `m["hello"]` has a 2-tuple type `(int, bool)` -and that it is assignable, but unlike the variable `m`, it is not -addressable. - - - -Download the example and vary the inputs and see what the program prints. - - - -Here's another example, adapted from the `govet` static checking tool. -It checks for accidental uses of a method value `x.f` when a -call `x.f()` was intended; -comparing a method `x.f` against nil is a common mistake. - - -%include nilfunc/main.go - - -Given this input, - - -%include nilfunc/main.go input - - - -the program reports these errors: - - -%include nilfunc/main.go output - - -# Selections - - -A _selection_ is an expression _`expr`_`.f` in which -`f` denotes either a struct field or a method. -A selection is resolved not by looking for a name in the lexical -environment, but by looking within a _type_. -The type checker ascertains the meaning of each selection in the -package---a surprisingly tricky business---and records it in the -`Selections` mapping of the `Info` struct, whose values are -of type `Selection`: - - - type Selection struct{ ... } - func (s *Selection) Kind() SelectionKind // = FieldVal | MethodVal | MethodExpr - func (s *Selection) Recv() Type - func (s *Selection) Obj() Object - func (s *Selection) Type() Type - func (s *Selection) Index() []int - func (s *Selection) Indirect() bool - - -The `Kind` method discriminates between the three (legal) kinds -of selections, as indicated by the comments below. - - - type T struct{Field int} - func (T) Method() {} - var v T - - // Kind Type - var _ = v.Field // FieldVal int - var _ = v.Method // MethodVal func() - var _ = T.Method // MethodExpr func(T) - - -Because of embedding, a selection may denote more than one field or -method, in which case it is ambiguous, and no `Selection` is -recorded for it. - - - -The `Obj` method returns the `Object` for the selected field -(`*Var`) or method (`*Func`). -Due to embedding, the object may belong to a different type than that -of the receiver expression _`expr`_. -The `Type` method returns the type of the selection. For a field -selection, this is the type of the field, but for method selections, -the result is a function type that is not the same as the type of the -method. -For a `MethodVal`, the receiver parameter is dropped, and -for a `MethodExpr`, the receiver parameter becomes a regular -parameter, as shown in the example above. - - - -The `Index` and `Indirect` methods report information about -implicit operations occurring during the selection that a compiler -would need to know about. -Because of embedding, a selection _`expr`_`.f` may be -shorthand for a sequence containing several implicit field selections, -_`expr`_`.d.e.f`, and `Index` reports the complete -sequence. -And because of automatic pointer dereferencing during struct field -accesses and method calls, a selection may imply one or more indirect -loads from memory; `Indirect` reports whether this occurs. - - - -Clients of the type checker can call `LookupFieldOrMethod` to -look up a name within a type, as if by a selection. -This function has an intimidating signature, but conceptually it -accepts just a `Type` and a name, and returns a `Selection`: - - - func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) \ - (obj Object, index []int, indirect bool) - - -The result is not actually a `Selection`, but it contains the -three main components of one: `Obj`, `Index`, -and `Indirect`. - - - -The `addressable` flag should be set if the receiver is a -_variable_ of type `T`, since in a method selection on a -variable, an implicit address-of operation (`&`) may occur. -The flag indicates whether the methods of type `*T` should be -considered during the lookup. -(You may wonder why this parameter is necessary. Couldn't clients -instead call `LookupFieldOrMethod` on the pointer type `*T` -if the receiver is a `T` variable? The answer is that if -`T` is an interface type, the type `*T` has no methods at -all.) - - - -The final two parameters of `LookupFieldOrMethod` are `(pkg -*Package, name string)`. -Together they specify the name of the field or method to look up. -This brings us to `Id`s. - - - -# Ids - - -`LookupFieldOrMethod`'s need for a `Package` parameter -is a subtle consequence of the -[_Uniqueness of identifiers_](https://golang.org/ref/spec#Uniqueness_of_identifiers) -section in the Go spec: "Two -identifiers are different if they are spelled differently, or if they -appear in different packages and are not exported." -In practical terms, this means that a type may have two methods -(or two fields, or one of each) both named `f` so long as those -methods are defined in different packages, as in this example: - - - package a - type A int - func (A) f() - - package b - type B int - func (B) f() - - package c - import ( "a"; "b" ) - type C struct{a.A; b.B} // C has two methods called f - - -The type `c.C` has two methods named `f`, but there is -no ambiguity because the two `f`s are distinct -identifiers---think of them as `fᵃ` and `fᵇ`. -For an exported method, this situation _would_ be ambiguous -because there is no distinction between `Fᵃ` and `Fᵇ`; there -is only `F`. - - - -Despite having two methods called `f`, neither of them can be -called from within package `c` because `c` has no way to -identify them. -Within `c`, `f` is the identifier `fᶜ`, and -type `C` has no method of that name. -But if we pass an instance of `C` to code in package `a` -and call its `f` method via an interface, `fᵃ` is called. - - - -The practical consequence for tool builders is that any time you need -to look up a field or method by name, or construct a map of fields and/or -methods keyed by name, it is not sufficient to use the object's name -as a key. -Instead, you must call the `Object.Id` method, which returns -a string that incorporates the object name, and for unexported -objects, the package path too. -There is also a standalone function `Id` that combines a name and -the package path in the same way: - - - func Id(pkg *Package, name string) string - - -This distinction applies to selections _`expr`_`.f`, but not -to lexical references `x` because for unexported identifiers, -declarations and references always appear in the same package. - - - -Fun fact: the `reflect.StructField` type records both the -`Name` and the `PkgPath` strings for the same reason. -The `FieldByName` methods of `reflect.Value` and -`reflect.Type` match field names without regard to the package. -If there is more than one match, they return an invalid value. - - - - -# Method Sets - - -The _method set_ of a type is the set of methods that can be -called on any value of that type. -(A variable of type `T` has access to all the methods of type -`*T` as well, due to the implicit address-of operation during -method calls, but those extra methods are not part of the method set -of `T`.) - - - -Clients can request the method set of a type `T` by calling -`NewMethodSet(T)`: - - - type MethodSet struct{ ... } - func NewMethodSet(T Type) *MethodSet - func (s *MethodSet) Len() int - func (s *MethodSet) At(i int) *Selection - func (s *MethodSet) Lookup(pkg *Package, name string) *Selection - - -The `Len` and `At` methods access a list of -`Selections`, all of kind `MethodVal`, ordered by `Id`. -The `Lookup` function allows lookup of a single method by -name (and package path, as explained in the previous section). - - - -`NewMethodSet` can be expensive, so for applications that compute -method sets repeatedly, `golang.org/x/tools/go/types/typeutil` -provides a `MethodSetCache` type that records previous results. -If you only need a single method, don't construct the -`MethodSet` at all; it's cheaper to use -`LookupFieldOrMethod`. - - - -The next program generates a boilerplate -declaration of a new concrete type that satisfies an existing -interface. -Here's an example: - - -%include skeleton/main.go output1 - - - -The three arguments are the package and the name of the existing -interface type, and the name of the new concrete type. -The `main` function (not shown) loads the specified package and -calls `PrintSkeleton` with the remaining two arguments: - - -%include skeleton/main.go - - -First, `PrintSkeleton` locates the package-level named interface -type, handling various error cases. -Then it chooses the name for the receiver of the new methods: the -first letter of the concrete type. -Finally, it iterates over the method set of the interface, printing -the corresponding concrete method declarations. - - - -There's a subtlety in the declaration of `sig`, which is the -string form of the method signature. -We could have obtained this string from `meth.Type().String()`, -but this would cause any named types within it to be formatted with -the complete package path, for instance -`net/http.ResponseWriter`, which is informative in diagnostics -but not legal Go syntax. -The `TypeString` function (explained in [Formatting Values](#formatting-values)) allows the -caller to control how packages are printed. -Passing `(*types.Package).Name` causes only the package name -`http` to be printed, not the complete path. -Here's another example that illustrates it: - - -%include skeleton/main.go output2 - - - -The following program inspects all pairs of package-level named types -in `pkg`, and reports the types that satisfy each interface type. - - -%include implements/main.go implements - - -Given this input, - - -%include implements/main.go input - - -the program prints: - - -%include implements/main.go output - - - -Notice that the method set of `B` does not include `g`, but -the method set of `*B` does. -That's why we needed the second assignability check, using the pointer -type `types.NewPointer(T)`. - - - -# Constants - - -A constant expression is one whose value is guaranteed to be computed at -compile time. -Constant expressions may appear in types, specifically as the length -of an array type such as `[16]byte`, so one of the jobs of the -type checker is to compute the value of each constant expression. - - - -As we saw in the `typeandvalue` example, the type checker records -the value of each constant expression like `"Hello, " + "world"`, -storing it in the `Value` field of the `TypeAndValue` struct. -Constants are represented using the `Value` interface from the -`go/constant` package. - - - package constant // go/constant - - type Value interface { - Kind() Kind - } - - type Kind int // one of Unknown, Bool, String, Int, Float, Complex - - -The interface has only one method, for discriminating the various -kinds of constants, but the package provides many functions for -inspecting a value of a known kind, - - - // Accessors - func BoolVal(x Value) bool - func Float32Val(x Value) (float32, bool) - func Float64Val(x Value) (float64, bool) - func Int64Val(x Value) (int64, bool) - func StringVal(x Value) string - func Uint64Val(x Value) (uint64, bool) - func Bytes(x Value) []byte - func BitLen(x Value) int - func Sign(x Value) int - - -for performing arithmetic on values, - - - // Operations - func Compare(x Value, op token.Token, y Value) bool - func UnaryOp(op token.Token, y Value, prec uint) Value - func BinaryOp(x Value, op token.Token, y Value) Value - func Shift(x Value, op token.Token, s uint) Value - func Denom(x Value) Value - func Num(x Value) Value - func Real(x Value) Value - func Imag(x Value) Value - - -and for constructing new values: - - - // Constructors - func MakeBool(b bool) Value - func MakeFloat64(x float64) Value - func MakeFromBytes(bytes []byte) Value - func MakeFromLiteral(lit string, tok token.Token, prec uint) Value - func MakeImag(x Value) Value - func MakeInt64(x int64) Value - func MakeString(s string) Value - func MakeUint64(x uint64) Value - func MakeUnknown() Value - - -All numeric `Value`s, whether integer or floating-point, signed or -unsigned, or real or complex, are represented more precisely than -ordinary Go types like `int64` and `float64`. -Internally, the `go/constant` package uses multi-precision data types -like `Int`, `Rat`, and `Float` from the `math/big` package so that -`Values` and their arithmetic operations are accurate to at least 256 -bits, as required by the Go specification. - - - - - -# Size and Alignment - - -Because the calls `unsafe.Sizeof(v)`, `unsafe.Alignof(v)`, -and `unsafe.Offsetof(v.f)` are all constant expressions, the type -checker must be able to compute the memory layout of any value -`v`. - - - -By default, the type checker uses the same layout algorithm as the Go -1.5 `gc` compiler targeting `amd64`. -Clients can configure the type checker to use a different algorithm by -providing an instance of the `types.Sizes` interface in the -`types.Config` struct: - - - package types - - type Sizes interface { - Alignof(T Type) int64 - Offsetsof(fields []*Var) []int64 - Sizeof(T Type) int64 - } - - - -For common changes, like reducing the word size to 32 bits, clients -can use an instance of `StdSizes`: - - - type StdSizes struct { - WordSize int64 - MaxAlign int64 - } - - -This type has two basic size and alignment parameters from which it -derives all the other values using common assumptions. -For example, pointers, functions, maps, and channels fit in one word, -strings and interfaces require two words, and slices need three. -The default behaviour is equivalent to `StdSizes{8, 8}`. -For more esoteric layout changes, you'll need to write a new -implementation of the `Sizes` interface. - - - -The `hugeparam` program below prints all function parameters and -results whose size exceeds a threshold. -By default, the threshold is 48 bytes, but you can set it via the -`-bytes` command-line flag. -Such a tool could help identify inefficient parameter passing in your -programs. - - -%include hugeparam/main.go - - -As before, `Inspect` applies a function to every node in the AST. -The function cares about two kinds of nodes: declarations of named -functions and methods (`*ast.FuncDecl`) and function literals -(`*ast.FuncLit`). -Observe the two cases' different logic to obtain the type of each -function. - - - -Here's a typical invocation on the standard `encoding/xml` package. -It reports a number of places where the 7-word -[`StartElement` type](https://godoc.org/encoding/xml#StartElement) -is copied. - - -%include hugeparam/main.go output - - -# Imports - - -The type checker's `Check` function processes a slice of parsed -files (`[]*ast.File`) that make up one package. -When the type checker encounters an import declaration, it needs the -type information for the objects in the imported package. -It gets it by calling the `Import` method of the `Importer` -interface shown below, an instance of which must be provided by the -`Config`. -This separation of concerns relieves the type checker from having to -know any of the details of Go workspace organization, `GOPATH`, -compiler file formats, and so on. - - - type Importer interface { - Import(path string) (*Package, error) - } - - -Most of our examples used the simplest `Importer` implementation, -`importer.Default()`, provided by the `go/importer` package. -This importer looks in `$GOROOT` and `$GOPATH` for `.a` -files written by the compiler (`gc` or `gccgo`) -that was used to build the program. -In addition to object code, these files contain _export data_, -that is, a description of all the objects declared by the package, and -also of any objects from other packages that were referred to indirectly. -Because export data includes information about dependencies, the type -checker need load at most one file per import, instead of one per -transitive dependency. - - - -Compiler export data is compact and efficient to locate, load, and -parse, but it has several shortcomings. -First, it does not contain position information for imported -objects, reducing the quality of certain diagnostic messages. -Second, it does not contain complete syntax trees nor semantic information -about the contents of function bodies, so it is not suitable for -interprocedural analyses. -Third, compiler object data may be stale. Nothing detects or ensures -that the object files are more recent than the source files from which -they were derived. -Generally, object data for standard packages is likely to be -up-to-date, but for user packages, it depends on how recently the user -ran a `go install` or `go build -i` command. - - - -The [`golang.org/tools/x/go/loader` package](https://godoc.org/golang.org/x/tools/go/loader) -provides an alternative `Importer` that addresses -some of these problems. -It loads a complete program from source, performing -[`cgo`](https://golang.org/cmd/cgo/cgo) preprocessing if -necessary, followed by parsing and type-checking. -It loads independent packages in parallel to hide I/O latency, and -detects and reports import cycles. -For each package, it provides the `types.Package` containing the -package's lexical environment, the list of `ast.File` syntax -trees for each file in the package, the `types.Info` containing -type information for each syntax node, and a list of type errors -associated with that package. -(Please be aware that the `go/loader` package's API is likely to -change before it finally stabilizes.) - - - -The `doc` program below demonstrates a simple use of the loader. -It is a rudimentary implementation of `go doc` that prints the type, -methods, and documentation of the package-level object specified on -the command line. -Here's an example: - - -%include doc/main.go output - - - -Observe that it prints the correct location of each method -declaration, even though, due to embedding, some of -`http.File`'s methods were declared in another package. -Here's the first part of the program, showing how to load an entire -program starting from the single package, `pkgpath`: - - -%include doc/main.go part1 - - -Notice that we instructed the parser to retain comments during parsing. -The rest of the program prints the output: - - -%include doc/main.go part2 - - -We used `IntuitiveMethodSet` to compute the method set, instead -of `NewMethodSet`. -The result of this convenience function, which is intended for use in -user interfaces, includes methods of `*T` as well as those of -`T`, since that matches most users' intuition about the method -set of a type. -(Our example, `http.File`, didn't illustrate the difference, but try -running it on a type with both value and pointer methods.) - - - -Also notice `PathEnclosingInterval`, which finds the set of AST -nodes that enclose a particular point, in this case, the object's -declaring identifier. -By walking up with path, we find the enclosing declaration, to which -the documentation is attached. - - - -# Formatting support - - -All types that satisfy `Type` or `Object` define a -`String` method that formats the type or object in a readable -notation. `Selection` also provides a `String` method. -All package-level objects within these data structures are -printed with the complete package path, as in these examples: - - - []encoding/json.Marshaler // a *Slice type - encoding/json.Marshal // a *Func object - (*encoding/json.Encoder).Encode // a *Func object (method) - func (enc *encoding/json.Encoder) Encode(v interface{}) error // a method *Signature - func NewEncoder(w io.Writer) *encoding/json.Encoder // a function *Signature - - -This notation is unambiguous, but it is not legal Go syntax. -Also, package paths may be long, and the same package path may appear -many times in a single string, for instance, when formatting a -function of several parameters. -Because these strings often form part of a tool's user interface---as -with the diagnostic messages of `hugeparam` or the code generated -by `skeleton`---many clients want more control over the -formatting of package names. - - - -The `go/types` package provides these alternatives to the -`String` methods: - - - func ObjectString(obj Object, qf Qualifier) string - func TypeString(typ Type, qf Qualifier) string - func SelectionString(s *Selection, qf Qualifier) string - - type Qualifier func(*Package) string - - -The `TypeString`, `ObjectString`, and `SelectionString` -functions are like the `String` methods of the respective types, -but they accept an additional argument, a `Qualifier`. - - - -A `Qualifier` is a client-provided function that determines how a -package name is rendered as a string. -If it is nil, the default behavior is to print the package's -path, just like the `String` methods do. -If a caller passes `(*Package).Name` as the qualifier, that is, a -function that accepts a package and returns its `Name`, then -objects are qualified only by the package name. -The above examples would look like this: - - - []json.Marshaler - json.Marshal - (*json.Encoder).Encode - func (enc *json.Encoder) Encode(v interface{}) error - func NewEncoder(w io.Writer) *json.Encoder - - -Often when a tool prints some output, it is implicitly in the -context of a particular package, perhaps one specified by the -command line or HTTP request. -In that case, it is more natural to omit the package qualification -altogether for objects belonging to that package, but to qualify all -other objects by their package's path. -That's what the `RelativeTo(pkg)` qualifier does: - - - func RelativeTo(pkg *Package) Qualifier - - -The examples below show how `json.NewEncoder` would be printed -using three qualifiers, each relative to a different package: - - - // RelativeTo "encoding/json": - func NewEncoder(w io.Writer) *Encoder - - // RelativeTo "io": - func NewEncoder(w Writer) *encoding/json.Encoder - - // RelativeTo any other package: - func NewEncoder(w io.Writer) *encoding/json.Encoder - - -Another qualifier that may be relevant to refactoring tools (but is -not currently provided by the type checker) is one that renders each -package name using the locally appropriate name within a given source -file. -Its behavior would depend on the set of import declarations, including -renaming imports, within that source file. - - - -# Getting from A to B - - -The type checker and its related packages represent many aspects of a -Go program in many different ways, and analysis tools must often map -between them. -For instance, a named entity may be identified by its `Object`; -by its declaring identifier (`ast.Ident`) or by any referring -identifier; by its declaring `ast.Node`; by the position -(`token.Pos`) of any those nodes; or by the filename and -line/column number (or byte offset) of those `token.Pos` values. - - - -In this section, we'll list solutions to a number of common problems -of the form "I have an A; I need the corresponding B". - - - -To map **from a `token.Pos` to an `ast.Node`**, call the -helper function -[`astutil.PathEnclosingInterval`](https://godoc.org/golang.org/x/tools/go/ast/astutil#PathEnclosingInterval). -It returns the enclosing `ast.Node`, and all its ancestors up to -the root of the file. -You must know which file `*ast.File` the `token.Pos` belongs to. -Alternatively, you can search an entire program loaded by the -`loader` package, using -[`(*loader.Program).PathEnclosingInterval`](https://godoc.org/golang.org/x/tools/go/loader#Program.PathEnclosingInterval). - - - -To map **from an `Object` to its declaring syntax**, call -`Pos` to get its position, then use `PathEnclosingInterval` as before. -This approach is suitable for a one-off query. For repeated use, it -may be more efficient to visit the syntax tree and construct the -mapping between declarations and objects. - - - -To map **from an `ast.Ident` to the `Object`** it refers to (or -declares), consult the `Uses` or `Defs` map for the -package, as shown in [Identifier Resolution](#identifier-resolution). - - - -To map **from an `Object` to its documentation**, find the -object's declaration, and look at the attached `Doc` field. -You must have set the parser's `ParseComments` flag. -See the `doc` example in [Imports](#imports). diff --git a/gotypes/hello/hello.go b/gotypes/hello/hello.go deleted file mode 100644 index 01a28623..00000000 --- a/gotypes/hello/hello.go +++ /dev/null @@ -1,10 +0,0 @@ -//!+ -package main - -import "fmt" - -func main() { - fmt.Println("Hello, 世界") -} - -//!- diff --git a/gotypes/hugeparam/main.go b/gotypes/hugeparam/main.go deleted file mode 100644 index 1474403a..00000000 --- a/gotypes/hugeparam/main.go +++ /dev/null @@ -1,81 +0,0 @@ -// The hugeparam command identifies by-value parameters that are larger than n bytes. -// -// Example: -// $ ./hugeparams encoding/xml -package main - -import ( - "flag" - "fmt" - "go/ast" - "go/token" - "go/types" - "log" - - "golang.org/x/tools/go/loader" -) - -//!+ -var bytesFlag = flag.Int("bytes", 48, "maximum parameter size in bytes") - -var sizeof = (&types.StdSizes{8, 8}).Sizeof // the sizeof function - -func PrintHugeParams(fset *token.FileSet, info *types.Info, files []*ast.File) { - checkTuple := func(descr string, tuple *types.Tuple) { - for i := 0; i < tuple.Len(); i++ { - v := tuple.At(i) - if sz := sizeof(v.Type()); sz > int64(*bytesFlag) { - fmt.Printf("%s: %q %s: %s = %d bytes\n", - fset.Position(v.Pos()), - v.Name(), descr, v.Type(), sz) - } - } - } - checkSig := func(sig *types.Signature) { - checkTuple("parameter", sig.Params()) - checkTuple("result", sig.Results()) - } - for _, file := range files { - ast.Inspect(file, func(n ast.Node) bool { - switch n := n.(type) { - case *ast.FuncDecl: - checkSig(info.Defs[n.Name].Type().(*types.Signature)) - case *ast.FuncLit: - checkSig(info.Types[n.Type].Type.(*types.Signature)) - } - return true - }) - } -} - -//!- - -func main() { - flag.Parse() - - // The loader loads a complete Go program from source code. - var conf loader.Config - _, err := conf.FromArgs(flag.Args(), false) - if err != nil { - log.Fatal(err) // command syntax error - } - lprog, err := conf.Load() - if err != nil { - log.Fatal(err) // load error - } - - for _, info := range lprog.InitialPackages() { - PrintHugeParams(lprog.Fset, &info.Info, info.Files) - } -} - -/* -//!+output -% ./hugeparam encoding/xml -/go/src/encoding/xml/marshal.go:167:50: "start" parameter: encoding/xml.StartElement = 56 bytes -/go/src/encoding/xml/marshal.go:734:97: "" result: encoding/xml.StartElement = 56 bytes -/go/src/encoding/xml/marshal.go:761:51: "start" parameter: encoding/xml.StartElement = 56 bytes -/go/src/encoding/xml/marshal.go:781:68: "start" parameter: encoding/xml.StartElement = 56 bytes -/go/src/encoding/xml/xml.go:72:30: "" result: encoding/xml.StartElement = 56 bytes -//!-output -*/ diff --git a/gotypes/implements/main.go b/gotypes/implements/main.go deleted file mode 100644 index d7e5701b..00000000 --- a/gotypes/implements/main.go +++ /dev/null @@ -1,77 +0,0 @@ -package main - -import ( - "fmt" - "go/ast" - "go/importer" - "go/parser" - "go/token" - "go/types" - "log" -) - -//!+input -const input = `package main - -type A struct{} -func (*A) f() - -type B int -func (B) f() -func (*B) g() - -type I interface { f() } -type J interface { g() } -` - -//!-input - -func main() { - // Parse one file. - fset := token.NewFileSet() - f, err := parser.ParseFile(fset, "input.go", input, 0) - if err != nil { - log.Fatal(err) // parse error - } - conf := types.Config{Importer: importer.Default()} - pkg, err := conf.Check("hello", fset, []*ast.File{f}, nil) - if err != nil { - log.Fatal(err) // type error - } - - //!+implements - // Find all named types at package level. - var allNamed []*types.Named - for _, name := range pkg.Scope().Names() { - if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok { - allNamed = append(allNamed, obj.Type().(*types.Named)) - } - } - - // Test assignability of all distinct pairs of - // named types (T, U) where U is an interface. - for _, T := range allNamed { - for _, U := range allNamed { - if T == U || !types.IsInterface(U) { - continue - } - if types.AssignableTo(T, U) { - fmt.Printf("%s satisfies %s\n", T, U) - } else if !types.IsInterface(T) && - types.AssignableTo(types.NewPointer(T), U) { - fmt.Printf("%s satisfies %s\n", types.NewPointer(T), U) - } - } - } - //!-implements -} - -/* -//!+output -$ go build github.com/golang/example/gotypes/implements -$ ./implements -*hello.A satisfies hello.I -hello.B satisfies hello.I -*hello.B satisfies hello.J -//!-output -*/ diff --git a/gotypes/lookup/lookup.go b/gotypes/lookup/lookup.go deleted file mode 100644 index 9bdc97d2..00000000 --- a/gotypes/lookup/lookup.go +++ /dev/null @@ -1,77 +0,0 @@ -package main - -import ( - "fmt" - "go/ast" - "go/importer" - "go/parser" - "go/token" - "go/types" - "log" - "strings" -) - -//!+input -const hello = ` -package main - -import "fmt" - -// append -func main() { - // fmt - fmt.Println("Hello, world") - // main - main, x := 1, 2 - // main - print(main, x) - // x -} -// x -` - -//!-input - -//!+main -func main() { - fset := token.NewFileSet() - f, err := parser.ParseFile(fset, "hello.go", hello, parser.ParseComments) - if err != nil { - log.Fatal(err) // parse error - } - - conf := types.Config{Importer: importer.Default()} - pkg, err := conf.Check("cmd/hello", fset, []*ast.File{f}, nil) - if err != nil { - log.Fatal(err) // type error - } - - // Each comment contains a name. - // Look up that name in the innermost scope enclosing the comment. - for _, comment := range f.Comments { - pos := comment.Pos() - name := strings.TrimSpace(comment.Text()) - fmt.Printf("At %s,\t%q = ", fset.Position(pos), name) - inner := pkg.Scope().Innermost(pos) - if _, obj := inner.LookupParent(name, pos); obj != nil { - fmt.Println(obj) - } else { - fmt.Println("not found") - } - } -} - -//!-main - -/* -//!+output -$ go build github.com/golang/example/gotypes/lookup -$ ./lookup -At hello.go:6:1, "append" = builtin append -At hello.go:8:9, "fmt" = package fmt -At hello.go:10:9, "main" = func cmd/hello.main() -At hello.go:12:9, "main" = var main int -At hello.go:14:9, "x" = var x int -At hello.go:16:1, "x" = not found -//!-output -*/ diff --git a/gotypes/nilfunc/main.go b/gotypes/nilfunc/main.go deleted file mode 100644 index da4b79b7..00000000 --- a/gotypes/nilfunc/main.go +++ /dev/null @@ -1,104 +0,0 @@ -package main - -import ( - "fmt" - "go/ast" - "go/importer" - "go/parser" - "go/token" - "go/types" - "log" -) - -//!+input -const input = `package main - -import "bytes" - -func main() { - var buf bytes.Buffer - if buf.Bytes == nil && bytes.Repeat != nil && main == nil { - // ... - } -} -` - -//!-input - -var fset = token.NewFileSet() - -func main() { - f, err := parser.ParseFile(fset, "input.go", input, 0) - if err != nil { - log.Fatal(err) // parse error - } - conf := types.Config{Importer: importer.Default()} - info := &types.Info{ - Defs: make(map[*ast.Ident]types.Object), - Uses: make(map[*ast.Ident]types.Object), - Types: make(map[ast.Expr]types.TypeAndValue), - } - if _, err = conf.Check("cmd/hello", fset, []*ast.File{f}, info); err != nil { - log.Fatal(err) // type error - } - - ast.Inspect(f, func(n ast.Node) bool { - if n != nil { - CheckNilFuncComparison(info, n) - } - return true - }) -} - -//!+ -// CheckNilFuncComparison reports unintended comparisons -// of functions against nil, e.g., "if x.Method == nil {". -func CheckNilFuncComparison(info *types.Info, n ast.Node) { - e, ok := n.(*ast.BinaryExpr) - if !ok { - return // not a binary operation - } - if e.Op != token.EQL && e.Op != token.NEQ { - return // not a comparison - } - - // If this is a comparison against nil, find the other operand. - var other ast.Expr - if info.Types[e.X].IsNil() { - other = e.Y - } else if info.Types[e.Y].IsNil() { - other = e.X - } else { - return // not a comparison against nil - } - - // Find the object. - var obj types.Object - switch v := other.(type) { - case *ast.Ident: - obj = info.Uses[v] - case *ast.SelectorExpr: - obj = info.Uses[v.Sel] - default: - return // not an identifier or selection - } - - if _, ok := obj.(*types.Func); !ok { - return // not a function or method - } - - fmt.Printf("%s: comparison of function %v %v nil is always %v\n", - fset.Position(e.Pos()), obj.Name(), e.Op, e.Op == token.NEQ) -} - -//!- - -/* -//!+output -$ go build github.com/golang/example/gotypes/nilfunc -$ ./nilfunc -input.go:7:5: comparison of function Bytes == nil is always false -input.go:7:25: comparison of function Repeat != nil is always true -input.go:7:48: comparison of function main == nil is always false -//!-output -*/ diff --git a/gotypes/pkginfo/main.go b/gotypes/pkginfo/main.go deleted file mode 100644 index 3050f80d..00000000 --- a/gotypes/pkginfo/main.go +++ /dev/null @@ -1,64 +0,0 @@ -//!+ -package main - -import ( - "fmt" - "go/ast" - "go/importer" - "go/parser" - "go/token" - "go/types" - "log" -) - -const hello = `package main - -import "fmt" - -func main() { - fmt.Println("Hello, world") -}` - -func main() { - fset := token.NewFileSet() - - // Parse the input string, []byte, or io.Reader, - // recording position information in fset. - // ParseFile returns an *ast.File, a syntax tree. - f, err := parser.ParseFile(fset, "hello.go", hello, 0) - if err != nil { - log.Fatal(err) // parse error - } - - // A Config controls various options of the type checker. - // The defaults work fine except for one setting: - // we must specify how to deal with imports. - conf := types.Config{Importer: importer.Default()} - - // Type-check the package containing only file f. - // Check returns a *types.Package. - pkg, err := conf.Check("cmd/hello", fset, []*ast.File{f}, nil) - if err != nil { - log.Fatal(err) // type error - } - - fmt.Printf("Package %q\n", pkg.Path()) - fmt.Printf("Name: %s\n", pkg.Name()) - fmt.Printf("Imports: %s\n", pkg.Imports()) - fmt.Printf("Scope: %s\n", pkg.Scope()) -} - -//!- - -/* -//!+output -$ go build github.com/golang/example/gotypes/pkginfo -$ ./pkginfo -Package "cmd/hello" -Name: main -Imports: [package fmt ("fmt")] -Scope: package "cmd/hello" scope 0x820533590 { -. func cmd/hello.main() -} -//!-output -*/ diff --git a/gotypes/skeleton/main.go b/gotypes/skeleton/main.go deleted file mode 100644 index c3961e20..00000000 --- a/gotypes/skeleton/main.go +++ /dev/null @@ -1,115 +0,0 @@ -// The skeleton command prints the boilerplate for a concrete type -// that implements the specified interface type. -// -// Example: -// $ ./skeleton io ReadWriteCloser buffer -// // *buffer implements io.ReadWriteCloser. -// type buffer struct{ /* ... */ } -// func (b *buffer) Close() error { panic("unimplemented") } -// func (b *buffer) Read(p []byte) (n int, err error) { panic("unimplemented") } -// func (b *buffer) Write(p []byte) (n int, err error) { panic("unimplemented") } -package main - -import ( - "fmt" - "go/types" - "log" - "os" - "strings" - "unicode" - "unicode/utf8" - - "golang.org/x/tools/go/loader" -) - -const usage = "Usage: skeleton " - -//!+ -func PrintSkeleton(pkg *types.Package, ifacename, concname string) error { - obj := pkg.Scope().Lookup(ifacename) - if obj == nil { - return fmt.Errorf("%s.%s not found", pkg.Path(), ifacename) - } - if _, ok := obj.(*types.TypeName); !ok { - return fmt.Errorf("%v is not a named type", obj) - } - iface, ok := obj.Type().Underlying().(*types.Interface) - if !ok { - return fmt.Errorf("type %v is a %T, not an interface", - obj, obj.Type().Underlying()) - } - // Use first letter of type name as receiver parameter. - if !isValidIdentifier(concname) { - return fmt.Errorf("invalid concrete type name: %q", concname) - } - r, _ := utf8.DecodeRuneInString(concname) - - fmt.Printf("// *%s implements %s.%s.\n", concname, pkg.Path(), ifacename) - fmt.Printf("type %s struct{}\n", concname) - mset := types.NewMethodSet(iface) - for i := 0; i < mset.Len(); i++ { - meth := mset.At(i).Obj() - sig := types.TypeString(meth.Type(), (*types.Package).Name) - fmt.Printf("func (%c *%s) %s%s {\n\tpanic(\"unimplemented\")\n}\n", - r, concname, meth.Name(), - strings.TrimPrefix(sig, "func")) - } - return nil -} - -//!- - -func isValidIdentifier(id string) bool { - for i, r := range id { - if !unicode.IsLetter(r) && - !(i > 0 && unicode.IsDigit(r)) { - return false - } - } - return id != "" -} - -func main() { - if len(os.Args) != 4 { - log.Fatal(usage) - } - pkgpath, ifacename, concname := os.Args[1], os.Args[2], os.Args[3] - - // The loader loads a complete Go program from source code. - var conf loader.Config - conf.Import(pkgpath) - lprog, err := conf.Load() - if err != nil { - log.Fatal(err) // load error - } - pkg := lprog.Package(pkgpath).Pkg - if err := PrintSkeleton(pkg, ifacename, concname); err != nil { - log.Fatal(err) - } -} - -/* -//!+output1 -$ ./skeleton io ReadWriteCloser buffer -// *buffer implements io.ReadWriteCloser. -type buffer struct{} -func (b *buffer) Close() error { - panic("unimplemented") -} -func (b *buffer) Read(p []byte) (n int, err error) { - panic("unimplemented") -} -func (b *buffer) Write(p []byte) (n int, err error) { - panic("unimplemented") -} -//!-output1 - -//!+output2 -$ ./skeleton net/http Handler myHandler -// *myHandler implements net/http.Handler. -type myHandler struct{} -func (m *myHandler) ServeHTTP(http.ResponseWriter, *http.Request) { - panic("unimplemented") -} -//!-output2 -*/ diff --git a/gotypes/typeandvalue/main.go b/gotypes/typeandvalue/main.go deleted file mode 100644 index 8a6fc798..00000000 --- a/gotypes/typeandvalue/main.go +++ /dev/null @@ -1,134 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "go/ast" - "go/format" - "go/importer" - "go/parser" - "go/token" - "go/types" - "log" -) - -//!+input -const input = ` -package main - -var m = make(map[string]int) - -func main() { - v, ok := m["hello, " + "world"] - print(rune(v), ok) -} -` - -//!-input - -var fset = token.NewFileSet() - -func main() { - f, err := parser.ParseFile(fset, "hello.go", input, 0) - if err != nil { - log.Fatal(err) // parse error - } - - conf := types.Config{Importer: importer.Default()} - info := &types.Info{Types: make(map[ast.Expr]types.TypeAndValue)} - if _, err := conf.Check("cmd/hello", fset, []*ast.File{f}, info); err != nil { - log.Fatal(err) // type error - } - - //!+inspect - // f is a parsed, type-checked *ast.File. - ast.Inspect(f, func(n ast.Node) bool { - if expr, ok := n.(ast.Expr); ok { - if tv, ok := info.Types[expr]; ok { - fmt.Printf("%-24s\tmode: %s\n", nodeString(expr), mode(tv)) - fmt.Printf("\t\t\t\ttype: %v\n", tv.Type) - if tv.Value != nil { - fmt.Printf("\t\t\t\tvalue: %v\n", tv.Value) - } - } - } - return true - }) - //!-inspect -} - -// nodeString formats a syntax tree in the style of gofmt. -func nodeString(n ast.Node) string { - var buf bytes.Buffer - format.Node(&buf, fset, n) - return buf.String() -} - -// mode returns a string describing the mode of an expression. -func mode(tv types.TypeAndValue) string { - s := "" - if tv.IsVoid() { - s += ",void" - } - if tv.IsType() { - s += ",type" - } - if tv.IsBuiltin() { - s += ",builtin" - } - if tv.IsValue() { - s += ",value" - } - if tv.IsNil() { - s += ",nil" - } - if tv.Addressable() { - s += ",addressable" - } - if tv.Assignable() { - s += ",assignable" - } - if tv.HasOk() { - s += ",ok" - } - return s[1:] -} - -/* -//!+output -$ go build github.com/golang/example/gotypes/typeandvalue -$ ./typeandvalue -make(map[string]int) mode: value - type: map[string]int -make mode: builtin - type: func(map[string]int) map[string]int -map[string]int mode: type - type: map[string]int -string mode: type - type: string -int mode: type - type: int -m["hello, "+"world"] mode: value,assignable,ok - type: (int, bool) -m mode: value,addressable,assignable - type: map[string]int -"hello, " + "world" mode: value - type: string - value: "hello, world" -"hello, " mode: value - type: untyped string - value: "hello, " -"world" mode: value - type: untyped string - value: "world" -print(rune(v), ok) mode: void - type: () -print mode: builtin - type: func(rune, bool) -rune(v) mode: value - type: rune -rune mode: type - type: rune -...more not shown... -//!-output -*/ diff --git a/gotypes/weave.go b/gotypes/weave.go deleted file mode 100644 index cfaa57b9..00000000 --- a/gotypes/weave.go +++ /dev/null @@ -1,191 +0,0 @@ -// The weave command is a simple preprocessor for markdown files. -// It builds a table of contents and processes %include directives. -// -// Example usage: -// $ go run weave.go go-types.md > README.md -package main - -import ( - "bufio" - "bytes" - "fmt" - "log" - "os" - "path/filepath" - "regexp" - "strings" -) - -func main() { - log.SetFlags(0) - log.SetPrefix("weave: ") - if len(os.Args) != 2 { - log.Fatal("usage: weave input.md\n") - } - - f, err := os.Open(os.Args[1]) - if err != nil { - log.Fatal(err) - } - defer f.Close() - - fmt.Println("") - - // Pass 1. - var toc []string - in := bufio.NewScanner(f) - for in.Scan() { - line := in.Text() - if line == "" || (line[0] != '#' && line[0] != '%') { - continue - } - line = strings.TrimSpace(line) - if line == "%toc" { - toc = nil - } else if strings.HasPrefix(line, "# ") || strings.HasPrefix(line, "## ") { - words := strings.Fields(line) - depth := len(words[0]) - words = words[1:] - text := strings.Join(words, " ") - for i := range words { - words[i] = strings.ToLower(words[i]) - } - line = fmt.Sprintf("%s1. [%s](#%s)", - strings.Repeat("\t", depth-1), text, strings.Join(words, "-")) - toc = append(toc, line) - } - } - - // Pass 2. - if _, err := f.Seek(0, os.SEEK_SET); err != nil { - log.Fatalf("can't rewind input: %v", err) - } - in = bufio.NewScanner(f) - for in.Scan() { - line := in.Text() - switch { - case strings.HasPrefix(line, "%toc"): // ToC - for _, h := range toc { - fmt.Println(h) - } - case strings.HasPrefix(line, "%include"): - words := strings.Fields(line) - if len(words) < 2 { - log.Fatal(line) - } - filename := words[1] - - // Show caption unless '-' follows. - if len(words) < 4 || words[3] != "-" { - fmt.Printf(" // go get golang.org/x/example/gotypes/%s\n\n", - filepath.Dir(filename)) - } - - section := "" - if len(words) > 2 { - section = words[2] - } - s, err := include(filename, section) - if err != nil { - log.Fatal(err) - } - fmt.Println("```") - fmt.Println(cleanListing(s)) // TODO(adonovan): escape /^```/ in s - fmt.Println("```") - default: - fmt.Println(line) - } - - } -} - -// include processes an included file, and returns the included text. -// Only lines between those matching !+tag and !-tag will be returned. -// This is true even if tag=="". -func include(file, tag string) (string, error) { - f, err := os.Open(file) - if err != nil { - return "", err - } - defer f.Close() - - startre, err := regexp.Compile("!\\+" + tag + "$") - if err != nil { - return "", err - } - endre, err := regexp.Compile("!\\-" + tag + "$") - if err != nil { - return "", err - } - - var text bytes.Buffer - in := bufio.NewScanner(f) - var on bool - for in.Scan() { - line := in.Text() - switch { - case startre.MatchString(line): - on = true - case endre.MatchString(line): - on = false - case on: - text.WriteByte('\t') - text.WriteString(line) - text.WriteByte('\n') - } - } - if text.Len() == 0 { - return "", fmt.Errorf("no lines of %s matched tag %q", file, tag) - } - return text.String(), nil -} - -func isBlank(line string) bool { return strings.TrimSpace(line) == "" } - -func indented(line string) bool { - return strings.HasPrefix(line, " ") || strings.HasPrefix(line, "\t") -} - -// cleanListing removes entirely blank leading and trailing lines from -// text, and removes n leading tabs. -func cleanListing(text string) string { - lines := strings.Split(text, "\n") - - // remove minimum number of leading tabs from all non-blank lines - tabs := 999 - for i, line := range lines { - if strings.TrimSpace(line) == "" { - lines[i] = "" - } else { - if n := leadingTabs(line); n < tabs { - tabs = n - } - } - } - for i, line := range lines { - if line != "" { - line := line[tabs:] - lines[i] = line // remove leading tabs - } - } - - // remove leading blank lines - for len(lines) > 0 && lines[0] == "" { - lines = lines[1:] - } - // remove trailing blank lines - for len(lines) > 0 && lines[len(lines)-1] == "" { - lines = lines[:len(lines)-1] - } - return strings.Join(lines, "\n") -} - -func leadingTabs(s string) int { - var i int - for i = 0; i < len(s); i++ { - if s[i] != '\t' { - break - } - } - return i -} diff --git a/hello/hello.go b/hello/hello.go deleted file mode 100644 index e76ed81b..00000000 --- a/hello/hello.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright 2014 Google Inc. - -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. -*/ - -package main - -import ( - "fmt" - - "golang.org/x/example/stringutil" -) - -func main() { - fmt.Println(stringutil.Reverse("!selpmaxe oG ,olleH")) -} diff --git a/main.go b/main.go new file mode 100644 index 00000000..85210dd0 --- /dev/null +++ b/main.go @@ -0,0 +1,42 @@ +package main + +import "fmt" + +func main() { + asciiArt := +` + .... + .'' .''' +. .' : +\\ .: : + \\ _: : ..----.._ + \\ .:::.....:::.. .' ''. + \\ .' #-. .-######' # '. + \\ '.##'/ ' ################ : + \\ ##################### : + \\ ..##.-.#### .''''###'.._ : + \\ :--:########: '. .' : + \\..__...--.. :--:#######.' '. '. : + : : : : '':'-:'':':: . '. .' + '---'''..: : ': '..'''. '. :' + \\ :: : : ' ''''''. '. .: + \\ :: : : ' '. ' : + \\:: : : ....' ..: ' '. + \\:: : : .....####\\ .~~.:. : + \\':.:.:.:'#########.===. ~ |.'-. . '''.. : + \\ .' ########## \ \ _.' '. '-. '''. + :\\ : ######## \ \ '. '-. : + : \\' ' #### : \ \ :. '-. : + : .'\\ :' : : \ \ : '-. : + : .' .\\ ' : : :\ \ : '. : + :: : \\' :. : : \ \ : '. : + ::. : \\ : : : ; \ \ : '.: + : ': '\\ : : : : \:\ : ..' + : ' \\ : : ; \| : .''' + '. ' \\: :.'' + .:..... \\: : ..'' + '._____|'.\\......'''''''.:..''' + \\ +` + fmt.Println(asciiArt) +} diff --git a/outyet/Dockerfile b/outyet/Dockerfile deleted file mode 100644 index 3fa58ff7..00000000 --- a/outyet/Dockerfile +++ /dev/null @@ -1,2 +0,0 @@ -FROM golang:onbuild -EXPOSE 8080 diff --git a/outyet/containers.yaml b/outyet/containers.yaml deleted file mode 100644 index 44ba78a6..00000000 --- a/outyet/containers.yaml +++ /dev/null @@ -1,8 +0,0 @@ -version: v1beta2 -containers: -- name: outyet - image: adg1/outyet - ports: - - name: http - hostPort: 80 - containerPort: 8080 diff --git a/outyet/main.go b/outyet/main.go deleted file mode 100644 index 96f77673..00000000 --- a/outyet/main.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 2014 Google Inc. - -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. -*/ - -// outyet is a web server that announces whether or not a particular Go version -// has been tagged. -package main - -import ( - "expvar" - "flag" - "fmt" - "html/template" - "log" - "net/http" - "sync" - "time" -) - -// Command-line flags. -var ( - httpAddr = flag.String("http", ":8080", "Listen address") - pollPeriod = flag.Duration("poll", 5*time.Second, "Poll period") - version = flag.String("version", "1.4", "Go version") -) - -const baseChangeURL = "https://go.googlesource.com/go/+/" - -func main() { - flag.Parse() - changeURL := fmt.Sprintf("%sgo%s", baseChangeURL, *version) - http.Handle("/", NewServer(*version, changeURL, *pollPeriod)) - log.Fatal(http.ListenAndServe(*httpAddr, nil)) -} - -// Exported variables for monitoring the server. -// These are exported via HTTP as a JSON object at /debug/vars. -var ( - hitCount = expvar.NewInt("hitCount") - pollCount = expvar.NewInt("pollCount") - pollError = expvar.NewString("pollError") - pollErrorCount = expvar.NewInt("pollErrorCount") -) - -// Server implements the outyet server. -// It serves the user interface (it's an http.Handler) -// and polls the remote repository for changes. -type Server struct { - version string - url string - period time.Duration - - mu sync.RWMutex // protects the yes variable - yes bool -} - -// NewServer returns an initialized outyet server. -func NewServer(version, url string, period time.Duration) *Server { - s := &Server{version: version, url: url, period: period} - go s.poll() - return s -} - -// poll polls the change URL for the specified period until the tag exists. -// Then it sets the Server's yes field true and exits. -func (s *Server) poll() { - for !isTagged(s.url) { - pollSleep(s.period) - } - s.mu.Lock() - s.yes = true - s.mu.Unlock() - pollDone() -} - -// Hooks that may be overridden for integration tests. -var ( - pollSleep = time.Sleep - pollDone = func() {} -) - -// isTagged makes an HTTP HEAD request to the given URL and reports whether it -// returned a 200 OK response. -func isTagged(url string) bool { - pollCount.Add(1) - r, err := http.Head(url) - if err != nil { - log.Print(err) - pollError.Set(err.Error()) - pollErrorCount.Add(1) - return false - } - return r.StatusCode == http.StatusOK -} - -// ServeHTTP implements the HTTP user interface. -func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { - hitCount.Add(1) - s.mu.RLock() - data := struct { - URL string - Version string - Yes bool - }{ - s.url, - s.version, - s.yes, - } - s.mu.RUnlock() - err := tmpl.Execute(w, data) - if err != nil { - log.Print(err) - } -} - -// tmpl is the HTML template that drives the user interface. -var tmpl = template.Must(template.New("tmpl").Parse(` -
-

Is Go {{.Version}} out yet?

-

- {{if .Yes}} - YES! - {{else}} - No. :-( - {{end}} -

-
-`)) diff --git a/outyet/main_test.go b/outyet/main_test.go deleted file mode 100644 index d21a22ce..00000000 --- a/outyet/main_test.go +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright 2014 Google Inc. - -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. -*/ - -package main - -import ( - "net/http" - "net/http/httptest" - "strings" - "testing" - "time" -) - -// statusHandler is an http.Handler that writes an empty response using itself -// as the response status code. -type statusHandler int - -func (h *statusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(int(*h)) -} - -func TestIsTagged(t *testing.T) { - // Set up a fake "Google Code" web server reporting 404 not found. - status := statusHandler(http.StatusNotFound) - s := httptest.NewServer(&status) - defer s.Close() - - if isTagged(s.URL) { - t.Fatal("isTagged == true, want false") - } - - // Change fake server status to 200 OK and try again. - status = http.StatusOK - - if !isTagged(s.URL) { - t.Fatal("isTagged == false, want true") - } -} - -func TestIntegration(t *testing.T) { - status := statusHandler(http.StatusNotFound) - ts := httptest.NewServer(&status) - defer ts.Close() - - // Replace the pollSleep with a closure that we can block and unblock. - sleep := make(chan bool) - pollSleep = func(time.Duration) { - sleep <- true - sleep <- true - } - - // Replace pollDone with a closure that will tell us when the poller is - // exiting. - done := make(chan bool) - pollDone = func() { done <- true } - - // Put things as they were when the test finishes. - defer func() { - pollSleep = time.Sleep - pollDone = func() {} - }() - - s := NewServer("1.x", ts.URL, 1*time.Millisecond) - - <-sleep // Wait for poll loop to start sleeping. - - // Make first request to the server. - r, _ := http.NewRequest("GET", "/", nil) - w := httptest.NewRecorder() - s.ServeHTTP(w, r) - if b := w.Body.String(); !strings.Contains(b, "No.") { - t.Fatalf("body = %s, want no", b) - } - - status = http.StatusOK - - <-sleep // Permit poll loop to stop sleeping. - <-done // Wait for poller to see the "OK" status and exit. - - // Make second request to the server. - w = httptest.NewRecorder() - s.ServeHTTP(w, r) - if b := w.Body.String(); !strings.Contains(b, "YES!") { - t.Fatalf("body = %q, want yes", b) - } -} diff --git a/stringutil/reverse.go b/stringutil/reverse.go deleted file mode 100644 index d0bfd614..00000000 --- a/stringutil/reverse.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright 2014 Google Inc. - -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. -*/ - -// Package stringutil contains utility functions for working with strings. -package stringutil - -// Reverse returns its argument string reversed rune-wise left to right. -func Reverse(s string) string { - r := []rune(s) - for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { - r[i], r[j] = r[j], r[i] - } - return string(r) -} diff --git a/stringutil/reverse_test.go b/stringutil/reverse_test.go deleted file mode 100644 index 3a2337f1..00000000 --- a/stringutil/reverse_test.go +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright 2014 Google Inc. - -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. -*/ - -package stringutil - -import "testing" - -func TestReverse(t *testing.T) { - for _, c := range []struct { - in, want string - }{ - {"Hello, world", "dlrow ,olleH"}, - {"Hello, 世界", "界世 ,olleH"}, - {"", ""}, - } { - got := Reverse(c.in) - if got != c.want { - t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want) - } - } -} diff --git a/template/image.tmpl b/template/image.tmpl deleted file mode 100644 index 14d1097c..00000000 --- a/template/image.tmpl +++ /dev/null @@ -1,9 +0,0 @@ -{{define "content"}} -
- {{.Title}} -
-{{end}} - -{{define "sidebar"}} -Back -{{end}} diff --git a/template/index.tmpl b/template/index.tmpl deleted file mode 100644 index 24ed3ffb..00000000 --- a/template/index.tmpl +++ /dev/null @@ -1,41 +0,0 @@ - - - - - {{.Title}} - - - -

{{.Title}}

- - - - {{block "content" .}} -
- {{.Body}} -
- {{end}} - - diff --git a/template/main.go b/template/main.go deleted file mode 100644 index 5da54752..00000000 --- a/template/main.go +++ /dev/null @@ -1,97 +0,0 @@ -/* -Copyright 2016 Google Inc. - -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. -*/ - -// Command template is a trivial web server that uses the text/template (and -// html/template) package's "block" feature to implement a kind of template -// inheritance. -// -// It should be executed from the directory in which the source resides, -// as it will look for its template files in the current directory. -package main - -import ( - "html/template" - "log" - "net/http" - "strings" -) - -func main() { - http.HandleFunc("/", indexHandler) - http.HandleFunc("/image/", imageHandler) - log.Fatal(http.ListenAndServe("localhost:8080", nil)) -} - -// indexTemplate is the main site template. -// The default template includes two template blocks ("sidebar" and "content") -// that may be replaced in templates derived from this one. -var indexTemplate = template.Must(template.ParseFiles("index.tmpl")) - -// Index is a data structure used to populate an indexTemplate. -type Index struct { - Title string - Body string - Links []Link -} - -type Link struct { - URL, Title string -} - -// indexHandler is an HTTP handler that serves the index page. -func indexHandler(w http.ResponseWriter, r *http.Request) { - data := &Index{ - Title: "Image gallery", - Body: "Welcome to the image gallery.", - } - for name, img := range images { - data.Links = append(data.Links, Link{ - URL: "/image/" + name, - Title: img.Title, - }) - } - if err := indexTemplate.Execute(w, data); err != nil { - log.Println(err) - } -} - -// imageTemplate is a clone of indexTemplate that provides -// alternate "sidebar" and "content" templates. -var imageTemplate = template.Must(template.Must(indexTemplate.Clone()).ParseFiles("image.tmpl")) - -// Image is a data structure used to populate an imageTemplate. -type Image struct { - Title string - URL string -} - -// imageHandler is an HTTP handler that serves the image pages. -func imageHandler(w http.ResponseWriter, r *http.Request) { - data, ok := images[strings.TrimPrefix(r.URL.Path, "/image/")] - if !ok { - http.NotFound(w, r) - return - } - if err := imageTemplate.Execute(w, data); err != nil { - log.Println(err) - } -} - -// images specifies the site content: a collection of images. -var images = map[string]*Image{ - "go": {"The Go Gopher", "https://golang.org/doc/gopher/frontpage.png"}, - "google": {"The Google Logo", "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"}, -} From 261785b6b8f7b493a801968fff06c425400cebdb Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Oct 2021 15:45:29 +0200 Subject: [PATCH 05/49] fix --- Dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..46c351ba --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM golang:latest +WORKDIR /root/ + +COPY main.go . + +RUN go mod init example.com/m && \ + go get && \ + go build main.go && ls +ENTRYPOINT ["./main"] From 72a8a9a468613e6e18c5f901bce7a8347bcbdf23 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Oct 2021 15:49:53 +0200 Subject: [PATCH 06/49] fix --- Jenkinsfile | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 9aabe15a..8557d943 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,11 +1,16 @@ node("test_node") { - stage('first') { // for display purposes + stage('git clone') { // for display purposes checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'ssh-hetzner', url: 'git@github.com:h34dl355/example.git']]]) sh 'ls -la' echo "Git clone done!" } - stage('second') { - sh 'docker run -v ~/root/example/hello/:/go/src/ golang:latest go build' + stage('build') { + sh 'docker build . -t gendalf' + echo "Build done!" + } + stage('docker run') { + docker run gendalf + echo "End of pipeline" } } From 17bc143471495dcbf877d0645621e6a9fd6377b0 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Oct 2021 16:23:15 +0200 Subject: [PATCH 07/49] fix --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index 8557d943..00ccc189 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -3,6 +3,7 @@ node("test_node") { stage('git clone') { // for display purposes checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'ssh-hetzner', url: 'git@github.com:h34dl355/example.git']]]) sh 'ls -la' + sh 'id' echo "Git clone done!" } stage('build') { From efd9e07aafbd524792234a1fa0a7bdb8fbf89f82 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Oct 2021 16:28:42 +0200 Subject: [PATCH 08/49] fix --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 00ccc189..9cf2aa0a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,7 +11,7 @@ node("test_node") { echo "Build done!" } stage('docker run') { - docker run gendalf + sh 'docker run gendalf' echo "End of pipeline" } } From d574c96272c3404613c34da91ca7f25bd4e4a690 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 09:48:25 +0200 Subject: [PATCH 09/49] add stage --- Jenkinsfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 9cf2aa0a..63bd63c3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,6 +5,9 @@ node("test_node") { sh 'ls -la' sh 'id' echo "Git clone done!" + stage('test job') { + echo "test" + } } stage('build') { sh 'docker build . -t gendalf' From 080816aa611bc33b8cf22bf1d831a8c742a4d9b0 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 11:35:01 +0200 Subject: [PATCH 10/49] add buildname --- Jenkinsfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 63bd63c3..73189b18 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -16,5 +16,8 @@ node("test_node") { stage('docker run') { sh 'docker run gendalf' echo "End of pipeline" + wrappers { + buildName('#${BUILD_NUMBER} on ${ENV,var="BRANCH"}') + } } } From be6bb1f19c426d184fef4f1b7115592e1e3f6b57 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 11:52:44 +0200 Subject: [PATCH 11/49] add buildname --- Jenkinsfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 73189b18..d2e0b21e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,4 @@ +buildName('#${BUILD_NUMBER} on ${ENV,var="BRANCH"}') node("test_node") { stage('git clone') { // for display purposes @@ -16,8 +17,5 @@ node("test_node") { stage('docker run') { sh 'docker run gendalf' echo "End of pipeline" - wrappers { - buildName('#${BUILD_NUMBER} on ${ENV,var="BRANCH"}') - } } } From a36d6ad24c8361f06c799f3ae6c02788073de5db Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 12:02:04 +0200 Subject: [PATCH 12/49] add buildname --- Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index d2e0b21e..8f9b7183 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,5 @@ -buildName('#${BUILD_NUMBER} on ${ENV,var="BRANCH"}') +currentBuild.displayName = currentBuild.number+"#"+" testcase:"+currentBuild.number + node("test_node") { stage('git clone') { // for display purposes From 54a6787d5df1124da10ccdeaaf04fe6d3af4e65a Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 12:03:10 +0200 Subject: [PATCH 13/49] add buildname --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 8f9b7183..bfe358db 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -currentBuild.displayName = currentBuild.number+"#"+" testcase:"+currentBuild.number +currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:"+currentBuild.number node("test_node") { From f5f080d20e0c48574c659c112051f0a2a15113ba Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 12:05:36 +0200 Subject: [PATCH 14/49] add buildname --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index bfe358db..6a6fbb7e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,5 @@ currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:"+currentBuild.number - +currentBuild.description = "test desc" node("test_node") { stage('git clone') { // for display purposes From 08ba0a6701a00c8f900d17d74b57cf5fc07e1bed Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 13:09:39 +0200 Subject: [PATCH 15/49] add buildname --- Jenkinsfile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6a6fbb7e..697bdad1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,9 @@ -currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:"+currentBuild.number -currentBuild.description = "test desc" +\\currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:"+currentBuild.number +\\currentBuild.description = "test desc" +currentBuild.description = "" +if (currentBuild.rawBuild.getCause(Cause).properties.upstreamRun != null) currentBuild.description = "Started by: ${currentBuild.rawBuild.getCause(Cause).properties.upstreamRun}
" +else if (currentBuild.rawBuild.getCause(Cause).properties.userName != null) currentBuild.description = "Started by: ${currentBuild.rawBuild.getCause(Cause).properties.userName}
" + node("test_node") { stage('git clone') { // for display purposes From 50b0ae5b4b58f380199125683d8ddede3a8f7de5 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 13:10:08 +0200 Subject: [PATCH 16/49] add buildname --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 697bdad1..c9f3b7bb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,5 @@ -\\currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:"+currentBuild.number -\\currentBuild.description = "test desc" +//currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:"+currentBuild.number +//currentBuild.description = "test desc" currentBuild.description = "" if (currentBuild.rawBuild.getCause(Cause).properties.upstreamRun != null) currentBuild.description = "Started by: ${currentBuild.rawBuild.getCause(Cause).properties.upstreamRun}
" else if (currentBuild.rawBuild.getCause(Cause).properties.userName != null) currentBuild.description = "Started by: ${currentBuild.rawBuild.getCause(Cause).properties.userName}
" From 97ac90b144c5bf7c1e0455ffc1448e029aa85a4d Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 13:11:06 +0200 Subject: [PATCH 17/49] add buildname --- Jenkinsfile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index c9f3b7bb..2fa04c8d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,8 +1,5 @@ -//currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:"+currentBuild.number -//currentBuild.description = "test desc" -currentBuild.description = "" -if (currentBuild.rawBuild.getCause(Cause).properties.upstreamRun != null) currentBuild.description = "Started by: ${currentBuild.rawBuild.getCause(Cause).properties.upstreamRun}
" -else if (currentBuild.rawBuild.getCause(Cause).properties.userName != null) currentBuild.description = "Started by: ${currentBuild.rawBuild.getCause(Cause).properties.userName}
" +currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:
"+currentBuild.number +currentBuild.description = "test desc" node("test_node") { From 7248cbe6a008e690233d8f0a9d1cc60c99a08a14 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 13:46:11 +0200 Subject: [PATCH 18/49] add buildname --- Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 2fa04c8d..a05704d4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,5 @@ -currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:
"+currentBuild.number +//currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:"+currentBuild.number +currentBuild.displayName = currentBuild.number+"#"+$BRANCH_NAME currentBuild.description = "test desc" node("test_node") { From b1cde1a62bdc97f739a5dfbc8a716337b2582a45 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 13:49:04 +0200 Subject: [PATCH 19/49] add buildname --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index a05704d4..570df9ba 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,4 @@ -//currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:"+currentBuild.number -currentBuild.displayName = currentBuild.number+"#"+$BRANCH_NAME +currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:"+currentBuild.number currentBuild.description = "test desc" node("test_node") { @@ -9,6 +8,7 @@ node("test_node") { sh 'ls -la' sh 'id' echo "Git clone done!" + echo "${BRANCH_NAME} stage('test job') { echo "test" } From 4eaa591ce336ca4232ffdb7d37c3ba48b6c9cb3f Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 16:22:24 +0200 Subject: [PATCH 20/49] fix --- Jenkinsfile | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 570df9ba..0071384f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,24 +1,3 @@ -currentBuild.displayName = currentBuild.number+"#"+" testcase/coloraize/log_parser/build_name:"+currentBuild.number -currentBuild.description = "test desc" +@Library('shared-library@master') _ +pipeline() -node("test_node") { - - stage('git clone') { // for display purposes - checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'ssh-hetzner', url: 'git@github.com:h34dl355/example.git']]]) - sh 'ls -la' - sh 'id' - echo "Git clone done!" - echo "${BRANCH_NAME} - stage('test job') { - echo "test" - } - } - stage('build') { - sh 'docker build . -t gendalf' - echo "Build done!" - } - stage('docker run') { - sh 'docker run gendalf' - echo "End of pipeline" - } -} From 1b446b1e4ee70365cadff60171a5b687de0e381d Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 Oct 2021 16:24:16 +0200 Subject: [PATCH 21/49] fix --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0071384f..e9e17f7c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,3 @@ -@Library('shared-library@master') _ +@Library('shared-pipeline@master') _ pipeline() From 5b229df57267fa1b762d61da2307c4d7077d0e74 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 Oct 2021 13:04:50 +0200 Subject: [PATCH 22/49] fix --- Jenkinsfile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index e9e17f7c..e42420da 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,9 @@ @Library('shared-pipeline@master') _ -pipeline() +test.paintLog 'error some text 1234 lorem' +test.paintLog 'fatal some text 1234 lorem' +test.paintLog 'invalid some text 1234 lorem' +test.paintLog 'warning some text 1234 lorem' +test.paintLog 'success some text 1234 lorem' +test.paintLog 'changed some text 1234 lorem' +test.paintLog 'created some text 1234 lorem' From 9bce71355d941e768f6e7b3ef04d867b309c1cdb Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 Oct 2021 13:08:21 +0200 Subject: [PATCH 23/49] fix --- Jenkinsfile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index e42420da..4d873781 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,9 +1,9 @@ @Library('shared-pipeline@master') _ -test.paintLog 'error some text 1234 lorem' -test.paintLog 'fatal some text 1234 lorem' -test.paintLog 'invalid some text 1234 lorem' -test.paintLog 'warning some text 1234 lorem' -test.paintLog 'success some text 1234 lorem' -test.paintLog 'changed some text 1234 lorem' -test.paintLog 'created some text 1234 lorem' +colorize.paintLog 'error some text 1234 lorem' +colorize.paintLog 'fatal some text 1234 lorem' +colorize.paintLog 'invalid some text 1234 lorem' +colorize.paintLog 'warning some text 1234 lorem' +colorize.paintLog 'success some text 1234 lorem' +colorize.paintLog 'changed some text 1234 lorem' +colorize.paintLog 'created some text 1234 lorem' From 898901eea3d8565742464cf70ba0dcfb0fca150f Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 Oct 2021 13:14:39 +0200 Subject: [PATCH 24/49] fix --- Jenkinsfile | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4d873781..f7bea805 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,9 +1,11 @@ @Library('shared-pipeline@master') _ -colorize.paintLog 'error some text 1234 lorem' -colorize.paintLog 'fatal some text 1234 lorem' -colorize.paintLog 'invalid some text 1234 lorem' -colorize.paintLog 'warning some text 1234 lorem' -colorize.paintLog 'success some text 1234 lorem' -colorize.paintLog 'changed some text 1234 lorem' -colorize.paintLog 'created some text 1234 lorem' +colorize.paintLog("error some text 1234 lorem") +colorize.paintLog("fatal some text 1234 lorem" +colorize.paintLog("invalid some text 1234 lorem") +colorize.paintLog("warning some text 1234 lorem") +colorize.paintLog("success some text 1234 lorem") +colorize.paintLog("changed some text 1234 lorem") +colorize.paintLog("created some text 1234 lorem") +colorize.paintLog("just a string") + From 026882027e50a6c423fd24693fb9910d748f7ece Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 Oct 2021 13:16:14 +0200 Subject: [PATCH 25/49] fix --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index f7bea805..b6edbd72 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,7 +1,7 @@ @Library('shared-pipeline@master') _ colorize.paintLog("error some text 1234 lorem") -colorize.paintLog("fatal some text 1234 lorem" +colorize.paintLog("fatal some text 1234 lorem") colorize.paintLog("invalid some text 1234 lorem") colorize.paintLog("warning some text 1234 lorem") colorize.paintLog("success some text 1234 lorem") From 1702e6c1478cfff32e106a37c8e5a28c1d37d3cf Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 Oct 2021 14:40:08 +0200 Subject: [PATCH 26/49] fix --- Jenkinsfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index b6edbd72..ed03d843 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,7 @@ @Library('shared-pipeline@master') _ +pipeline() + colorize.paintLog("error some text 1234 lorem") colorize.paintLog("fatal some text 1234 lorem") colorize.paintLog("invalid some text 1234 lorem") From e88b95eee8b734f73648e94a55df15af6323f22a Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 Oct 2021 15:00:10 +0200 Subject: [PATCH 27/49] fix --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index ed03d843..d270fda2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,6 +1,6 @@ @Library('shared-pipeline@master') _ -pipeline() +testCD() colorize.paintLog("error some text 1234 lorem") colorize.paintLog("fatal some text 1234 lorem") From 0f478c741ff579875be5fc83751ed5565a09458d Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 21 Oct 2021 09:10:37 +0200 Subject: [PATCH 28/49] fix --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index d270fda2..1cc24b53 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,7 +2,7 @@ testCD() -colorize.paintLog("error some text 1234 lorem") +colorize.paintLog("${BUILD_NUMBER}") colorize.paintLog("fatal some text 1234 lorem") colorize.paintLog("invalid some text 1234 lorem") colorize.paintLog("warning some text 1234 lorem") From 7bb2384be0c078cf42c18f776d78bcaf6ca100d0 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 21 Oct 2021 10:02:48 +0200 Subject: [PATCH 29/49] fix --- Jenkinsfile | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 1cc24b53..cba52fd6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,12 +2,3 @@ testCD() -colorize.paintLog("${BUILD_NUMBER}") -colorize.paintLog("fatal some text 1234 lorem") -colorize.paintLog("invalid some text 1234 lorem") -colorize.paintLog("warning some text 1234 lorem") -colorize.paintLog("success some text 1234 lorem") -colorize.paintLog("changed some text 1234 lorem") -colorize.paintLog("created some text 1234 lorem") -colorize.paintLog("just a string") - From a64a1d380c0ee14246dd4043a32515c8511f959a Mon Sep 17 00:00:00 2001 From: h34dl355 <39599052+h34dl355@users.noreply.github.com> Date: Wed, 27 Oct 2021 17:36:27 +0300 Subject: [PATCH 30/49] Update Jenkinsfile --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index cba52fd6..a773c75c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -@Library('shared-pipeline@master') _ +@Library('shared-pipeline@ee002c') _ testCD() From f66960cf1b320e5c47026f938d57aab03e10c0fd Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 10 Jan 2022 10:04:39 +0100 Subject: [PATCH 31/49] fix version --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index a773c75c..cba52fd6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -@Library('shared-pipeline@ee002c') _ +@Library('shared-pipeline@master') _ testCD() From 8ae65fd2eae523f4eabf5c2f9f655f1ab0a1374b Mon Sep 17 00:00:00 2001 From: h34dl355 <39599052+h34dl355@users.noreply.github.com> Date: Tue, 25 Oct 2022 12:03:14 +0300 Subject: [PATCH 32/49] Update Jenkinsfile --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index cba52fd6..adadcbd7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -@Library('shared-pipeline@master') _ +@Library('shared-pipeline@test_params') _ testCD() From 023c10f064fe02cb84c9c3ce864b26bf05b98fb5 Mon Sep 17 00:00:00 2001 From: h34dl355 <39599052+h34dl355@users.noreply.github.com> Date: Tue, 25 Oct 2022 13:50:50 +0300 Subject: [PATCH 33/49] Update Jenkinsfile n --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index adadcbd7..6bbb19c2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,3 +2,4 @@ testCD() +env.SOME From 38f9289eaf112166c6a35033b89b913b0e1d95c9 Mon Sep 17 00:00:00 2001 From: h34dl355 <39599052+h34dl355@users.noreply.github.com> Date: Tue, 25 Oct 2022 13:51:08 +0300 Subject: [PATCH 34/49] Update Jenkinsfile fix --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6bbb19c2..fb50b0f8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,5 @@ @Library('shared-pipeline@test_params') _ +env.SOME testCD() -env.SOME From 3eca46c0de5a654759925876c22c0af5ad66de65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Sun, 11 Dec 2022 15:24:53 +0300 Subject: [PATCH 35/49] New Jenkinsfile --- Jenkinsfile | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index fb50b0f8..b6434f6b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,14 @@ -@Library('shared-pipeline@test_params') _ -env.SOME - -testCD() +@Library('shared-pipeline@feature/rewrite') _ + node(jenkinsAgent) { + timestamps { + stage('Checkout project') { + println "Executing example pipeline.." + cleanWs() + checkoutProject() + } + stage('Test stage') { + sh 'ls -la' + } + } + } \ No newline at end of file From f72342f6dc674bd008c9c07dacae4e73757ee7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Sun, 11 Dec 2022 15:33:41 +0300 Subject: [PATCH 36/49] New Jenkinsfile --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index b6434f6b..b3cd2551 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,6 +1,6 @@ @Library('shared-pipeline@feature/rewrite') _ - node(jenkinsAgent) { + node("slave-vm") { timestamps { stage('Checkout project') { println "Executing example pipeline.." From 47e4893e789ba5e665f17f764307b82e2915eb43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Sun, 11 Dec 2022 15:49:15 +0300 Subject: [PATCH 37/49] New Jenkinsfile --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index b3cd2551..61c603e8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -10,5 +10,6 @@ stage('Test stage') { sh 'ls -la' } + println "End example pipeline." } } \ No newline at end of file From b0aa7140e0e6208e447ea80a52dadeccf3f3a5b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Sun, 11 Dec 2022 16:35:21 +0300 Subject: [PATCH 38/49] New Jenkinsfile --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 61c603e8..5604f098 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -10,6 +10,6 @@ stage('Test stage') { sh 'ls -la' } - println "End example pipeline." + println "Ended example pipeline." } } \ No newline at end of file From 1023502b09d3d240a9d279cc918b13d0ecbfb636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Sun, 11 Dec 2022 16:57:23 +0300 Subject: [PATCH 39/49] New Jenkinsfile --- Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 5604f098..6ac07d3c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,7 +8,8 @@ checkoutProject() } stage('Test stage') { - sh 'ls -la' + dockerBuildPush() + sh 'docker images' } println "Ended example pipeline." } From 85b3a6e9e936c084cc10e2d9b9739cda26974cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Sun, 11 Dec 2022 16:59:17 +0300 Subject: [PATCH 40/49] New Jenkinsfile --- Jenkinsfile | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6ac07d3c..5b20deb4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,16 +1,3 @@ @Library('shared-pipeline@feature/rewrite') _ - node("slave-vm") { - timestamps { - stage('Checkout project') { - println "Executing example pipeline.." - cleanWs() - checkoutProject() - } - stage('Test stage') { - dockerBuildPush() - sh 'docker images' - } - println "Ended example pipeline." - } - } \ No newline at end of file +golangCI-CD() \ No newline at end of file From 8dc8abd34df93d25d30f3ea95cf0480460a9f8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Sun, 11 Dec 2022 17:02:24 +0300 Subject: [PATCH 41/49] New Jenkinsfile --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 5b20deb4..e0ad5551 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,3 @@ @Library('shared-pipeline@feature/rewrite') _ -golangCI-CD() \ No newline at end of file +golangCI-CD-pipeline() \ No newline at end of file From 92e88399e262dd4b9270a647f47fe306614b904b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Sun, 11 Dec 2022 17:06:26 +0300 Subject: [PATCH 42/49] New Jenkinsfile --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index e0ad5551..46e8447a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,3 @@ @Library('shared-pipeline@feature/rewrite') _ -golangCI-CD-pipeline() \ No newline at end of file +golangPipeline() \ No newline at end of file From 014a8032baff25b17062e1b3ac615d8e0fefb5d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Sun, 11 Dec 2022 18:30:02 +0300 Subject: [PATCH 43/49] fix dockerfile --- Dockerfile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 46c351ba..c3d1216f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ -FROM golang:latest -WORKDIR /root/ - -COPY main.go . - -RUN go mod init example.com/m && \ - go get && \ - go build main.go && ls -ENTRYPOINT ["./main"] +FROM golang:1.16-alpine as builder +WORKDIR /build +COPY . . +#RUN go mod download +RUN go build -o /example ./main.go +FROM alpine:3 +WORKDIR /app +COPY --from=builder /example /app/example +ENTRYPOINT ["/app/example"] \ No newline at end of file From 19f55318e43dc33515d7c90a38211e076d7b8c75 Mon Sep 17 00:00:00 2001 From: h34dl355 <39599052+h34dl355@users.noreply.github.com> Date: Fri, 7 Apr 2023 17:49:32 +0300 Subject: [PATCH 44/49] Create Dockerfile2 --- Dockerfile2 | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 Dockerfile2 diff --git a/Dockerfile2 b/Dockerfile2 new file mode 100644 index 00000000..9b6fbb2a --- /dev/null +++ b/Dockerfile2 @@ -0,0 +1,172 @@ +# syntax=docker/dockerfile:1 + +ARG BASE_IMAGE=alpine:3.17 +ARG JS_IMAGE=node:18-alpine3.17 +ARG JS_PLATFORM=linux/amd64 +ARG GO_IMAGE=golang:1.20.1-alpine3.17 + +ARG GO_SRC=go-builder +ARG JS_SRC=js-builder + +FROM --platform=${JS_PLATFORM} ${JS_IMAGE} as js-builder + +ENV NODE_OPTIONS=--max_old_space_size=8000 + +WORKDIR /tmp/grafana + +COPY package.json yarn.lock .yarnrc.yml ./ +COPY .yarn .yarn +COPY packages packages +COPY plugins-bundled plugins-bundled + +RUN yarn install --immutable + +COPY tsconfig.json .eslintrc .editorconfig .browserslistrc .prettierrc.js babel.config.json .linguirc ./ +COPY public public +COPY scripts scripts +COPY emails emails + +ENV NODE_ENV production +RUN yarn build + +FROM ${GO_IMAGE} as go-builder + +ARG GO_BUILD_TAGS="oss" +ARG WIRE_TAGS="oss" +ARG BINGO="true" + +# Install build dependencies +RUN if grep -i -q alpine /etc/issue; then \ + apk add --no-cache gcc g++ make git; \ + fi + +WORKDIR /tmp/grafana + +COPY go.* ./ +COPY .bingo .bingo + +RUN go mod download +RUN if [[ "$BINGO" = "true" ]]; then \ + go install github.com/bwplotka/bingo@latest && \ + bingo get -v; \ + fi + +COPY embed.go Makefile build.go package.json ./ +COPY cue.mod cue.mod +COPY kinds kinds +COPY local local +COPY packages/grafana-schema packages/grafana-schema +COPY public/app/plugins public/app/plugins +COPY public/api-merged.json public/api-merged.json +COPY pkg pkg +COPY scripts scripts +COPY conf conf +COPY .github .github +COPY .git .git + +RUN make build-go GO_BUILD_TAGS=${GO_BUILD_TAGS} WIRE_TAGS=${WIRE_TAGS} + +FROM ${BASE_IMAGE} as tgz-builder + +WORKDIR /tmp/grafana + +ARG GRAFANA_TGZ="grafana-latest.linux-x64-musl.tar.gz" + +COPY ${GRAFANA_TGZ} /tmp/grafana.tar.gz + +# add -v to make tar print every file it extracts +RUN tar x -z -f /tmp/grafana.tar.gz --strip-components=1 + +# helpers for COPY --from +FROM ${GO_SRC} as go-src +FROM ${JS_SRC} as js-src + +# Final stage +FROM ${BASE_IMAGE} + +LABEL maintainer="Grafana Labs " + +ARG GF_UID="472" +ARG GF_GID="0" + +ENV PATH="/usr/share/grafana/bin:$PATH" \ + GF_PATHS_CONFIG="/etc/grafana/grafana.ini" \ + GF_PATHS_DATA="/var/lib/grafana" \ + GF_PATHS_HOME="/usr/share/grafana" \ + GF_PATHS_LOGS="/var/log/grafana" \ + GF_PATHS_PLUGINS="/var/lib/grafana/plugins" \ + GF_PATHS_PROVISIONING="/etc/grafana/provisioning" + +WORKDIR $GF_PATHS_HOME + +# Install dependencies +RUN if grep -i -q alpine /etc/issue; then \ + apk add --no-cache ca-certificates bash curl tzdata musl-utils && \ + apk info -vv | sort; \ + elif grep -i -q ubuntu /etc/issue; then \ + DEBIAN_FRONTEND=noninteractive && \ + apt-get update && \ + apt-get install -y ca-certificates curl tzdata && \ + apt-get autoremove -y && \ + rm -rf /var/lib/apt/lists/*; \ + else \ + echo 'ERROR: Unsupported base image' && /bin/false; \ + fi + +# glibc support for alpine x86_64 only +RUN if grep -i -q alpine /etc/issue && [ `arch` = "x86_64" ]; then \ + wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub && \ + wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.35-r0/glibc-2.35-r0.apk \ + -O /tmp/glibc-2.35-r0.apk && \ + wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.35-r0/glibc-bin-2.35-r0.apk \ + -O /tmp/glibc-bin-2.35-r0.apk && \ + apk add --force-overwrite --no-cache /tmp/glibc-2.35-r0.apk /tmp/glibc-bin-2.35-r0.apk && \ + rm -f /lib64/ld-linux-x86-64.so.2 && \ + ln -s /usr/glibc-compat/lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2 && \ + rm -f /tmp/glibc-2.35-r0.apk && \ + rm -f /tmp/glibc-bin-2.35-r0.apk && \ + rm -f /lib/ld-linux-x86-64.so.2 && \ + rm -f /etc/ld.so.cache; \ + fi + +COPY --from=go-src /tmp/grafana/conf ./conf + +RUN if [ ! $(getent group "$GF_GID") ]; then \ + if grep -i -q alpine /etc/issue; then \ + addgroup -S -g $GF_GID grafana; \ + else \ + addgroup --system --gid $GF_GID grafana; \ + fi; \ + fi && \ + GF_GID_NAME=$(getent group $GF_GID | cut -d':' -f1) && \ + mkdir -p "$GF_PATHS_HOME/.aws" && \ + if grep -i -q alpine /etc/issue; then \ + adduser -S -u $GF_UID -G "$GF_GID_NAME" grafana; \ + else \ + adduser --system --uid $GF_UID --ingroup "$GF_GID_NAME" grafana; \ + fi && \ + mkdir -p "$GF_PATHS_PROVISIONING/datasources" \ + "$GF_PATHS_PROVISIONING/dashboards" \ + "$GF_PATHS_PROVISIONING/notifiers" \ + "$GF_PATHS_PROVISIONING/plugins" \ + "$GF_PATHS_PROVISIONING/access-control" \ + "$GF_PATHS_PROVISIONING/alerting" \ + "$GF_PATHS_LOGS" \ + "$GF_PATHS_PLUGINS" \ + "$GF_PATHS_DATA" && \ + cp conf/sample.ini "$GF_PATHS_CONFIG" && \ + cp conf/ldap.toml /etc/grafana/ldap.toml && \ + chown -R "grafana:$GF_GID_NAME" "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING" && \ + chmod -R 777 "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING" + +COPY --from=go-src /tmp/grafana/bin/grafana* /tmp/grafana/bin/*/grafana* ./bin/ +COPY --from=js-src /tmp/grafana/public ./public + +EXPOSE 3000 + +ARG RUN_SH=./packaging/docker/run.sh + +COPY ${RUN_SH} /run.sh + +USER "$GF_UID" +ENTRYPOINT [ "/run.sh" ] From 0f6f3dab3c1362178943d3c10740058cf168d701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Mon, 10 Apr 2023 14:41:32 +0300 Subject: [PATCH 45/49] new pipe --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 46e8447a..73156119 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,3 @@ -@Library('shared-pipeline@feature/rewrite') _ +@Library('shared-pipeline@feature/test') _ golangPipeline() \ No newline at end of file From 95708b91e85376ca2b8a704843ff5aaac8094943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Mon, 10 Apr 2023 14:42:00 +0300 Subject: [PATCH 46/49] new pipe --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 73156119..453cabe1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,3 @@ @Library('shared-pipeline@feature/test') _ -golangPipeline() \ No newline at end of file +testpipe() \ No newline at end of file From 1452c11d8e381196b75e7437cb132a673169c017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Mon, 10 Apr 2023 21:17:47 +0300 Subject: [PATCH 47/49] new --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index 453cabe1..ca28cb68 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,4 @@ @Library('shared-pipeline@feature/test') _ + testpipe() \ No newline at end of file From 88d66eb7d9be1fd1beadc867837aeb0e074893d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Mon, 10 Apr 2023 21:21:19 +0300 Subject: [PATCH 48/49] new --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index ca28cb68..04db6776 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,5 @@ @Library('shared-pipeline@feature/test') _ + testpipe() \ No newline at end of file From f88dc0157d87d29954e3cbb3af25f3e53a53726e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=BB=D1=8C=D0=B4=D0=B0=D1=80=20=D0=93=D1=83=D1=81?= =?UTF-8?q?=D0=B5=D0=B9=D0=BD=D0=BE=D0=B2?= Date: Mon, 24 Apr 2023 12:34:53 +0300 Subject: [PATCH 49/49] fix --- photo_2023-04-24_12-34-10.jpg | Bin 0 -> 94383 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 photo_2023-04-24_12-34-10.jpg diff --git a/photo_2023-04-24_12-34-10.jpg b/photo_2023-04-24_12-34-10.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f268e07190770f12f6a5b42a1ad248f60a916204 GIT binary patch literal 94383 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 literal 0 HcmV?d00001