Uses a real go project to showcase vendor example so glide works (#828)
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"go/vendordir/test"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/example/stringutil"
|
||||
)
|
||||
|
||||
// Handler is the entry point for this fission function
|
||||
func Handler(w http.ResponseWriter, r *http.Request) {
|
||||
msg := test.Test()
|
||||
msg := stringutil.Reverse(stringutil.Reverse("Vendor Example Test"))
|
||||
w.Write([]byte(msg))
|
||||
}
|
||||
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
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.
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
# Go example projects
|
||||
|
||||
This repository contains a collection of Go programs and libraries that
|
||||
demonstrate the language, standard libraries, and tools.
|
||||
|
||||
## The examples
|
||||
|
||||
### [hello](hello/) ([godoc](//godoc.org/github.com/golang/example/hello)) and [stringutil](stringutil/) ([godoc](//godoc.org/github.com/golang/example/stringutil))
|
||||
|
||||
go get github.com/golang/example/hello
|
||||
|
||||
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/) ([godoc](//godoc.org/github.com/golang/example/outyet))
|
||||
|
||||
go get github.com/golang/example/outyet
|
||||
|
||||
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/) ([godoc](//godoc.org/github.com/golang/example/appengine-hello))
|
||||
|
||||
goapp get github.com/golang/example/appengine-hello
|
||||
|
||||
A trivial "Hello, world" App Engine application intended to be used as the
|
||||
starting point for your own code.
|
||||
|
||||
_Note_: The `goapp` tool is part of the [Google App Engine SDK for Go](https://cloud.google.com/appengine/downloads#Google_App_Engine_SDK_for_Go).
|
||||
|
||||
### [gotypes](gotypes/) ([godoc](//godoc.org/github.com/golang/example/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/) ([godoc](//godoc.org/github.com/golang/example/template))
|
||||
|
||||
A trivial web server that demonstrates the use of the
|
||||
[`template` package](https://golang.org/pkg/text/template/)'s `block` feature.
|
||||
Generated
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
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.
|
||||
Generated
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
// 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")
|
||||
}
|
||||
Generated
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
# 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
|
||||
Generated
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Generated
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Hello, world</title>
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<script src="/script.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Hello, world</h1>
|
||||
|
||||
<button onclick="fetchMessage()">Fetch Message</button>
|
||||
<p id="message">Click on the button to fetch the message.</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Generated
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
Generated
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
|
||||
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)
|
||||
|
||||
+2554
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+68
@@ -0,0 +1,68 @@
|
||||
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 <nil>
|
||||
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
|
||||
*/
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
// 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 <package> <object>")
|
||||
}
|
||||
//!+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
|
||||
*/
|
||||
+2055
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
//!+
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("Hello, 世界")
|
||||
}
|
||||
|
||||
//!-
|
||||
Generated
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
// 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
|
||||
*/
|
||||
Generated
Vendored
+77
@@ -0,0 +1,77 @@
|
||||
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
|
||||
*/
|
||||
Generated
Vendored
+77
@@ -0,0 +1,77 @@
|
||||
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
|
||||
*/
|
||||
Generated
Vendored
+104
@@ -0,0 +1,104 @@
|
||||
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
|
||||
*/
|
||||
Generated
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
//!+
|
||||
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
|
||||
*/
|
||||
Generated
Vendored
+115
@@ -0,0 +1,115 @@
|
||||
// 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 <package> <interface> <concrete>"
|
||||
|
||||
//!+
|
||||
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
|
||||
*/
|
||||
Generated
Vendored
+134
@@ -0,0 +1,134 @@
|
||||
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
|
||||
*/
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
// 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("<!-- Autogenerated by weave; DO NOT EDIT -->")
|
||||
|
||||
// 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 github.com/golang/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
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
"github.com/golang/example/stringutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(stringutil.Reverse("!selpmaxe oG ,olleH"))
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
FROM golang:onbuild
|
||||
EXPOSE 8080
|
||||
Generated
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
version: v1beta2
|
||||
containers:
|
||||
- name: outyet
|
||||
image: adg1/outyet
|
||||
ports:
|
||||
- name: http
|
||||
hostPort: 80
|
||||
containerPort: 8080
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
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(`
|
||||
<!DOCTYPE html><html><body><center>
|
||||
<h2>Is Go {{.Version}} out yet?</h2>
|
||||
<h1>
|
||||
{{if .Yes}}
|
||||
<a href="{{.URL}}">YES!</a>
|
||||
{{else}}
|
||||
No. :-(
|
||||
{{end}}
|
||||
</h1>
|
||||
</center></body></html>
|
||||
`))
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
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)
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
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)
|
||||
}
|
||||
Generated
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{{define "content"}}
|
||||
<div id="image">
|
||||
<img src="{{.URL}}" title="{{.Title}}" alt="{{.Title}}">
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "sidebar"}}
|
||||
<a href="/">Back</a>
|
||||
{{end}}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{.Title}}</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
h1 {
|
||||
background: #ddd;
|
||||
}
|
||||
#sidebar {
|
||||
float: right;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{.Title}}</h1>
|
||||
|
||||
<div id="sidebar">
|
||||
{{block "sidebar" .}}
|
||||
<h2>Links</h2>
|
||||
{{/* The dashes in the following template directives
|
||||
ensure the generated HTML of this list contains no
|
||||
extraneous spaces or line breaks. */}}
|
||||
<ul>
|
||||
{{- range .Links}}
|
||||
<li><a href="{{.URL}}">{{.Title}}</a></li>
|
||||
{{- end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{block "content" .}}
|
||||
<div id="content">
|
||||
{{.Body}}
|
||||
</div>
|
||||
{{end}}
|
||||
</body>
|
||||
</html>
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
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"},
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package test
|
||||
|
||||
func Test() string {
|
||||
return "vendor hello world"
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
package: github.com/fission/fission
|
||||
excludeDirs:
|
||||
- examples
|
||||
- hack
|
||||
- test
|
||||
import:
|
||||
- package: github.com/sirupsen/logrus
|
||||
version: 68cec9f21fbf3ea8d8f98c044bc6ce05f17b267a
|
||||
|
||||
Reference in New Issue
Block a user