From dc725bfb3c3f29c7395e088d25ef6bf8dba8f129 Mon Sep 17 00:00:00 2001 From: KimMachineGun Date: Mon, 8 Feb 2021 23:27:52 +0000 Subject: [PATCH 01/47] doc/go1.16: mention new vet check for asn1.Unmarshal This vet check was added in CL 243397. For #40700. Change-Id: Ibff6df9395d37bb2b84a791443578009f23af4fb GitHub-Last-Rev: e47c38f6309f31a6de48d4ffc82078d7ad45b171 GitHub-Pull-Request: golang/go#44147 Reviewed-on: https://go-review.googlesource.com/c/go/+/290330 Trust: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov --- doc/go1.16.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/go1.16.html b/doc/go1.16.html index 878bf0d029..f6f72c3882 100644 --- a/doc/go1.16.html +++ b/doc/go1.16.html @@ -378,6 +378,16 @@ func TestFoo(t *testing.T) { fixes.

+

New warning for asn1.Unmarshal

+ +

+ The vet tool now warns about incorrectly passing a non-pointer or nil argument to + asn1.Unmarshal. + This is like the existing checks for + encoding/json.Unmarshal + and encoding/xml.Unmarshal. +

+

Runtime

From cea4e21b525ad6b465f62741680eaa0a44e9cc3e Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 8 Feb 2021 16:32:39 -0800 Subject: [PATCH 02/47] io/fs: backslash is always a glob meta character Fixes #44171 Change-Id: I2d3437a2f5b9fa0358e4664e1a8eacebed975eed Reviewed-on: https://go-review.googlesource.com/c/go/+/290512 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Rob Pike Reviewed-by: Russ Cox --- src/io/fs/glob.go | 5 ++--- src/io/fs/glob_test.go | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/io/fs/glob.go b/src/io/fs/glob.go index 549f217542..45d9cb61b9 100644 --- a/src/io/fs/glob.go +++ b/src/io/fs/glob.go @@ -6,7 +6,6 @@ package fs import ( "path" - "runtime" ) // A GlobFS is a file system with a Glob method. @@ -111,8 +110,8 @@ func glob(fs FS, dir, pattern string, matches []string) (m []string, e error) { // recognized by path.Match. func hasMeta(path string) bool { for i := 0; i < len(path); i++ { - c := path[i] - if c == '*' || c == '?' || c == '[' || runtime.GOOS == "windows" && c == '\\' { + switch path[i] { + case '*', '?', '[', '\\': return true } } diff --git a/src/io/fs/glob_test.go b/src/io/fs/glob_test.go index f0d791fab5..f19bebed77 100644 --- a/src/io/fs/glob_test.go +++ b/src/io/fs/glob_test.go @@ -17,6 +17,7 @@ var globTests = []struct { }{ {os.DirFS("."), "glob.go", "glob.go"}, {os.DirFS("."), "gl?b.go", "glob.go"}, + {os.DirFS("."), `gl\ob.go`, "glob.go"}, {os.DirFS("."), "*", "glob.go"}, {os.DirFS(".."), "*/glob.go", "fs/glob.go"}, } @@ -32,7 +33,7 @@ func TestGlob(t *testing.T) { t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result) } } - for _, pattern := range []string{"no_match", "../*/no_match"} { + for _, pattern := range []string{"no_match", "../*/no_match", `\*`} { matches, err := Glob(os.DirFS("."), pattern) if err != nil { t.Errorf("Glob error for %q: %s", pattern, err) From c9d6f45fec19a9cb66ddd89d61bfa982f5bf4afe Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 7 Feb 2021 15:25:39 -0800 Subject: [PATCH 03/47] runtime/metrics: fix a couple of documentation typpos Fixes #44150 Change-Id: Ibe5bfba01491dd8c2f0696fab40a1673230d76e9 Reviewed-on: https://go-review.googlesource.com/c/go/+/290349 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov Reviewed-by: Michael Knyszek --- src/runtime/metrics/doc.go | 7 ++++--- src/runtime/metrics/sample.go | 6 +++--- src/runtime/metrics/value.go | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go index 021a0bddca..5da050f973 100644 --- a/src/runtime/metrics/doc.go +++ b/src/runtime/metrics/doc.go @@ -16,13 +16,14 @@ Interface Metrics are designated by a string key, rather than, for example, a field name in a struct. The full list of supported metrics is always available in the slice of Descriptions returned by All. Each Description also includes useful information -about the metric, such as how to display it (e.g. gauge vs. counter) and how difficult -or disruptive it is to obtain it (e.g. do you need to stop the world?). +about the metric, such as how to display it (for example, gauge vs. counter) +and how difficult or disruptive it is to obtain it (for example, do you need to +stop the world?). Thus, users of this API are encouraged to sample supported metrics defined by the slice returned by All to remain compatible across Go versions. Of course, situations arise where reading specific metrics is critical. For these cases, users are -encouranged to use build tags, and although metrics may be deprecated and removed, +encouraged to use build tags, and although metrics may be deprecated and removed, users should consider this to be an exceptional and rare event, coinciding with a very large change in a particular Go implementation. diff --git a/src/runtime/metrics/sample.go b/src/runtime/metrics/sample.go index 35534dd70d..b3933e266e 100644 --- a/src/runtime/metrics/sample.go +++ b/src/runtime/metrics/sample.go @@ -32,9 +32,9 @@ func runtime_readMetrics(unsafe.Pointer, int, int) // // Note that re-use has some caveats. Notably, Values should not be read or // manipulated while a Read with that value is outstanding; that is a data race. -// This property includes pointer-typed Values (e.g. Float64Histogram) whose -// underlying storage will be reused by Read when possible. To safely use such -// values in a concurrent setting, all data must be deep-copied. +// This property includes pointer-typed Values (for example, Float64Histogram) +// whose underlying storage will be reused by Read when possible. To safely use +// such values in a concurrent setting, all data must be deep-copied. // // It is safe to execute multiple Read calls concurrently, but their arguments // must share no underlying memory. When in doubt, create a new []Sample from diff --git a/src/runtime/metrics/value.go b/src/runtime/metrics/value.go index 61e8a192a3..ed9a33d87c 100644 --- a/src/runtime/metrics/value.go +++ b/src/runtime/metrics/value.go @@ -33,7 +33,7 @@ type Value struct { pointer unsafe.Pointer // contains non-scalar values. } -// Kind returns the a tag representing the kind of value this is. +// Kind returns the tag representing the kind of value this is. func (v Value) Kind() ValueKind { return v.kind } From 11d15c171bd25337c1dde25a0f7ce4892cb894bb Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 4 Feb 2021 12:03:53 -0500 Subject: [PATCH 04/47] [dev.regabi] go/types: convert untyped arguments to delete This is a port of CL 285059 to go/types. The error assertion is updated to match go/types error for assignment, which has been improved. Change-Id: Icdd2751edea0abef7c84feadcbf9265d71239ade Reviewed-on: https://go-review.googlesource.com/c/go/+/289716 Run-TryBot: Robert Findley TryBot-Result: Go Bot Trust: Robert Findley Reviewed-by: Robert Griesemer --- src/go/types/builtins.go | 4 ++-- src/go/types/testdata/builtins.src | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index fd35f78676..078ed4488d 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -353,8 +353,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b return } - if ok, code := x.assignableTo(check, m.key, nil); !ok { - check.invalidArg(x, code, "%s is not assignable to %s", x, m.key) + check.assignment(x, m.key, "argument to delete") + if x.mode == invalid { return } diff --git a/src/go/types/testdata/builtins.src b/src/go/types/testdata/builtins.src index 98830eb08c..a7613adc35 100644 --- a/src/go/types/testdata/builtins.src +++ b/src/go/types/testdata/builtins.src @@ -283,7 +283,7 @@ func delete1() { delete() // ERROR not enough arguments delete(1) // ERROR not enough arguments delete(1, 2, 3) // ERROR too many arguments - delete(m, 0 /* ERROR not assignable */) + delete(m, 0 /* ERROR cannot use */) delete(m, s) _ = delete /* ERROR used as value */ (m, s) From 813958f13cee9b2e7587f173e7a5e6cc9ff51850 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 4 Feb 2021 12:10:02 -0500 Subject: [PATCH 05/47] [dev.regabi] go/types: factor out sorting of methods This is a port of CL 285993 to go/types. Change-Id: I7560cf1176fea5de2c54786a086e547c73294a60 Reviewed-on: https://go-review.googlesource.com/c/go/+/289717 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/predicates.go | 6 ++---- src/go/types/type.go | 8 +++----- src/go/types/typexpr.go | 21 +++++++++++++++++++-- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 148edbfb76..954a7ca987 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -6,8 +6,6 @@ package types -import "sort" - func isNamed(typ Type) bool { if _, ok := typ.(*Basic); ok { return ok @@ -273,8 +271,8 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool { p = p.prev } if debug { - assert(sort.IsSorted(byUniqueMethodName(a))) - assert(sort.IsSorted(byUniqueMethodName(b))) + assertSortedMethods(a) + assertSortedMethods(b) } for i, f := range a { g := b[i] diff --git a/src/go/types/type.go b/src/go/types/type.go index 087cda429d..66e194e967 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -4,8 +4,6 @@ package types -import "sort" - // A Type represents a type of Go. // All types implement the Type interface. type Type interface { @@ -301,8 +299,8 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { } // sort for API stability - sort.Sort(byUniqueMethodName(methods)) - sort.Stable(byUniqueTypeName(embeddeds)) + sortMethods(methods) + sortTypes(embeddeds) typ.methods = methods typ.embeddeds = embeddeds @@ -396,7 +394,7 @@ func (t *Interface) Complete() *Interface { } if methods != nil { - sort.Sort(byUniqueMethodName(methods)) + sortMethods(methods) t.allMethods = methods } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 2b398010f4..311a970051 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -518,8 +518,8 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d } // sort for API stability - sort.Sort(byUniqueMethodName(ityp.methods)) - sort.Stable(byUniqueTypeName(ityp.embeddeds)) + sortMethods(ityp.methods) + sortTypes(ityp.embeddeds) check.later(func() { check.completeInterface(ityp) }) } @@ -613,6 +613,10 @@ func (check *Checker) completeInterface(ityp *Interface) { } } +func sortTypes(list []Type) { + sort.Stable(byUniqueTypeName(list)) +} + // byUniqueTypeName named type lists can be sorted by their unique type names. type byUniqueTypeName []Type @@ -627,6 +631,19 @@ func sortName(t Type) string { return "" } +func sortMethods(list []*Func) { + sort.Sort(byUniqueMethodName(list)) +} + +func assertSortedMethods(list []*Func) { + if !debug { + panic("internal error: assertSortedMethods called outside debug mode") + } + if !sort.IsSorted(byUniqueMethodName(list)) { + panic("internal error: methods not sorted") + } +} + // byUniqueMethodName method lists can be sorted by their unique method names. type byUniqueMethodName []*Func From c48d1503ba5d0f74bbc5cae5036bf225c6823a44 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 4 Feb 2021 12:24:10 -0500 Subject: [PATCH 06/47] [dev.regabi] go/types: report unused packages in source order This is a port of CL 287072 to go/types. Change-Id: I08f56995f0323c1f238d1b44703a481d393471d5 Reviewed-on: https://go-review.googlesource.com/c/go/+/289720 Run-TryBot: Robert Findley TryBot-Result: Go Bot Trust: Robert Findley Trust: Robert Griesemer Reviewed-by: Robert Griesemer --- src/go/types/check.go | 36 +++++----- src/go/types/resolver.go | 67 +++++++++---------- .../testdata/importdecl0/importdecl0b.src | 2 +- .../testdata/importdecl1/importdecl1b.src | 2 +- src/go/types/typexpr.go | 8 +-- 5 files changed, 54 insertions(+), 61 deletions(-) diff --git a/src/go/types/check.go b/src/go/types/check.go index 280792e838..03798587e7 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -69,6 +69,12 @@ type importKey struct { path, dir string } +// A dotImportKey describes a dot-imported object in the given scope. +type dotImportKey struct { + scope *Scope + obj Object +} + // A Checker maintains the state of the type checker. // It must be created with NewChecker. type Checker struct { @@ -86,8 +92,9 @@ type Checker struct { // information collected during type-checking of a set of package files // (initialized by Files, valid only for the duration of check.Files; // maps and lists are allocated on demand) - files []*ast.File // package files - unusedDotImports map[*Scope]map[*Package]*ast.ImportSpec // unused dot-imported packages + files []*ast.File // package files + imports []*PkgName // list of imported packages + dotImportMap map[dotImportKey]*PkgName // maps dot-imported objects to the package they were dot-imported through firstErr error // first error encountered methods map[*TypeName][]*Func // maps package scope type names to associated non-blank (non-interface) methods @@ -104,22 +111,6 @@ type Checker struct { indent int // indentation for tracing } -// addUnusedImport adds the position of a dot-imported package -// pkg to the map of dot imports for the given file scope. -func (check *Checker) addUnusedDotImport(scope *Scope, pkg *Package, spec *ast.ImportSpec) { - mm := check.unusedDotImports - if mm == nil { - mm = make(map[*Scope]map[*Package]*ast.ImportSpec) - check.unusedDotImports = mm - } - m := mm[scope] - if m == nil { - m = make(map[*Package]*ast.ImportSpec) - mm[scope] = m - } - m[pkg] = spec -} - // addDeclDep adds the dependency edge (check.decl -> to) if check.decl exists func (check *Checker) addDeclDep(to Object) { from := check.decl @@ -202,7 +193,8 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch func (check *Checker) initFiles(files []*ast.File) { // start with a clean slate (check.Files may be called multiple times) check.files = nil - check.unusedDotImports = nil + check.imports = nil + check.dotImportMap = nil check.firstErr = nil check.methods = nil @@ -272,10 +264,16 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) { if !check.conf.DisableUnusedImportCheck { check.unusedImports() } + // no longer needed - release memory + check.imports = nil + check.dotImportMap = nil check.recordUntyped() check.pkg.complete = true + + // TODO(rFindley) There's more memory we should release at this point. + return } diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index b637f8b8ca..cb66871883 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -275,21 +275,26 @@ func (check *Checker) collectObjects() { } } - obj := NewPkgName(d.spec.Pos(), pkg, name, imp) + pkgName := NewPkgName(d.spec.Pos(), pkg, name, imp) if d.spec.Name != nil { // in a dot-import, the dot represents the package - check.recordDef(d.spec.Name, obj) + check.recordDef(d.spec.Name, pkgName) } else { - check.recordImplicit(d.spec, obj) + check.recordImplicit(d.spec, pkgName) } if path == "C" { // match cmd/compile (not prescribed by spec) - obj.used = true + pkgName.used = true } // add import to file scope + check.imports = append(check.imports, pkgName) if name == "." { + // dot-import + if check.dotImportMap == nil { + check.dotImportMap = make(map[dotImportKey]*PkgName) + } // merge imported scope with file scope for _, obj := range imp.scope.elems { // A package scope may contain non-exported objects, @@ -303,16 +308,15 @@ func (check *Checker) collectObjects() { if alt := fileScope.Insert(obj); alt != nil { check.errorf(d.spec.Name, _DuplicateDecl, "%s redeclared in this block", obj.Name()) check.reportAltDecl(alt) + } else { + check.dotImportMap[dotImportKey{fileScope, obj}] = pkgName } } } - // add position to set of dot-import positions for this file - // (this is only needed for "imported but not used" errors) - check.addUnusedDotImport(fileScope, imp, d.spec) } else { // declare imported package object in file scope // (no need to provide s.Name since we called check.recordDef earlier) - check.declare(fileScope, nil, obj, token.NoPos) + check.declare(fileScope, nil, pkgName, token.NoPos) } case constDecl: // declare all constants @@ -566,39 +570,30 @@ func (check *Checker) unusedImports() { // any of its exported identifiers. To import a package solely for its side-effects // (initialization), use the blank identifier as explicit package name." - // check use of regular imported packages - for _, scope := range check.pkg.scope.children /* file scopes */ { - for _, obj := range scope.elems { - if obj, ok := obj.(*PkgName); ok { - // Unused "blank imports" are automatically ignored - // since _ identifiers are not entered into scopes. - if !obj.used { - path := obj.imported.path - base := pkgName(path) - if obj.name == base { - check.softErrorf(obj, _UnusedImport, "%q imported but not used", path) - } else { - check.softErrorf(obj, _UnusedImport, "%q imported but not used as %s", path, obj.name) - } - } - } - } - } - - // check use of dot-imported packages - for _, unusedDotImports := range check.unusedDotImports { - for pkg, pos := range unusedDotImports { - check.softErrorf(pos, _UnusedImport, "%q imported but not used", pkg.path) + for _, obj := range check.imports { + if !obj.used && obj.name != "_" { + check.errorUnusedPkg(obj) } } } -// pkgName returns the package name (last element) of an import path. -func pkgName(path string) string { - if i := strings.LastIndex(path, "/"); i >= 0 { - path = path[i+1:] +func (check *Checker) errorUnusedPkg(obj *PkgName) { + // If the package was imported with a name other than the final + // import path element, show it explicitly in the error message. + // Note that this handles both renamed imports and imports of + // packages containing unconventional package declarations. + // Note that this uses / always, even on Windows, because Go import + // paths always use forward slashes. + path := obj.imported.path + elem := path + if i := strings.LastIndex(elem, "/"); i >= 0 { + elem = elem[i+1:] + } + if obj.name == "" || obj.name == "." || obj.name == elem { + check.softErrorf(obj, _UnusedImport, "%q imported but not used", path) + } else { + check.softErrorf(obj, _UnusedImport, "%q imported but not used as %s", path, obj.name) } - return path } // dir makes a good-faith attempt to return the directory diff --git a/src/go/types/testdata/importdecl0/importdecl0b.src b/src/go/types/testdata/importdecl0/importdecl0b.src index 6844e70982..55690423b6 100644 --- a/src/go/types/testdata/importdecl0/importdecl0b.src +++ b/src/go/types/testdata/importdecl0/importdecl0b.src @@ -8,7 +8,7 @@ import "math" import m "math" import . "testing" // declares T in file scope -import . /* ERROR "imported but not used" */ "unsafe" +import . /* ERROR .unsafe. imported but not used */ "unsafe" import . "fmt" // declares Println in file scope import ( diff --git a/src/go/types/testdata/importdecl1/importdecl1b.src b/src/go/types/testdata/importdecl1/importdecl1b.src index ee70bbd8e7..43a7bcd753 100644 --- a/src/go/types/testdata/importdecl1/importdecl1b.src +++ b/src/go/types/testdata/importdecl1/importdecl1b.src @@ -4,7 +4,7 @@ package importdecl1 -import . /* ERROR "imported but not used" */ "unsafe" +import . /* ERROR .unsafe. imported but not used */ "unsafe" type B interface { A diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 311a970051..6e89ccb027 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -51,12 +51,12 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool) } assert(typ != nil) - // The object may be dot-imported: If so, remove its package from - // the map of unused dot imports for the respective file scope. + // The object may have been dot-imported. + // If so, mark the respective package as used. // (This code is only needed for dot-imports. Without them, // we only have to mark variables, see *Var case below). - if pkg := obj.Pkg(); pkg != check.pkg && pkg != nil { - delete(check.unusedDotImports[scope], pkg) + if pkgName := check.dotImportMap[dotImportKey{scope, obj}]; pkgName != nil { + pkgName.used = true } switch obj := obj.(type) { From e0ac989cf3e43ec77c7205a66cb1cd63dd4d3043 Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Thu, 4 Feb 2021 01:39:18 -0800 Subject: [PATCH 07/47] archive/tar: detect out of bounds accesses in PAX records resulting from padded lengths Handles the case in which padding of a PAX record's length field violates invariants about the formatting of record, whereby it no longer matches the prescribed format: "%d %s=%s\n", , , as per: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_03 0-padding, and paddings of other sorts weren't handled and we assumed that only non-padded decimal lengths would be passed in. Added test cases to ensure that the parsing still proceeds as expected. The prior crashing repro: 0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319 exposed the fallacy in the code, that assumed that the length would ALWAYS be a non-padded decimal length string. This bug has existed since Go1.1 as per CL 6700047. Thanks to Josh Bleecher Snyder for fuzzing this package, and thanks to Tom Thorogood for advocacy, raising parity with GNU Tar, but for providing more test cases. Fixes #40196 Change-Id: I32e0af4887bc9221481bd9e8a5120a79f177f08c Reviewed-on: https://go-review.googlesource.com/c/go/+/289629 Trust: Emmanuel Odeke Trust: Joe Tsai Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot Reviewed-by: Joe Tsai --- src/archive/tar/strconv.go | 21 ++++++++++++++++++++- src/archive/tar/strconv_test.go | 7 +++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/archive/tar/strconv.go b/src/archive/tar/strconv.go index 6d0a403808..f0b61e6dba 100644 --- a/src/archive/tar/strconv.go +++ b/src/archive/tar/strconv.go @@ -265,8 +265,27 @@ func parsePAXRecord(s string) (k, v, r string, err error) { return "", "", s, ErrHeader } + afterSpace := int64(sp + 1) + beforeLastNewLine := n - 1 + // In some cases, "length" was perhaps padded/malformed, and + // trying to index past where the space supposedly is goes past + // the end of the actual record. + // For example: + // "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319" + // ^ ^ + // | | + // | afterSpace=35 + // | + // beforeLastNewLine=29 + // yet indexOf(firstSpace) MUST BE before endOfRecord. + // + // See https://golang.org/issues/40196. + if afterSpace >= beforeLastNewLine { + return "", "", s, ErrHeader + } + // Extract everything between the space and the final newline. - rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:] + rec, nl, rem := s[afterSpace:beforeLastNewLine], s[beforeLastNewLine:n], s[n:] if nl != "\n" { return "", "", s, ErrHeader } diff --git a/src/archive/tar/strconv_test.go b/src/archive/tar/strconv_test.go index dd3505a758..add65e272a 100644 --- a/src/archive/tar/strconv_test.go +++ b/src/archive/tar/strconv_test.go @@ -368,6 +368,13 @@ func TestParsePAXRecord(t *testing.T) { {"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false}, {"3 somelongkey=\n", "3 somelongkey=\n", "", "", false}, {"50 tooshort=\n", "50 tooshort=\n", "", "", false}, + {"0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319", "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319", "mtime", "1432668921.098285006", false}, + {"06 k=v\n", "06 k=v\n", "", "", false}, + {"00006 k=v\n", "00006 k=v\n", "", "", false}, + {"000006 k=v\n", "000006 k=v\n", "", "", false}, + {"000000 k=v\n", "000000 k=v\n", "", "", false}, + {"0 k=v\n", "0 k=v\n", "", "", false}, + {"+0000005 x=\n", "+0000005 x=\n", "", "", false}, } for _, v := range vectors { From 493363ccff354ab5ed133f6d5fac942ba6cc034a Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 8 Feb 2021 18:24:13 -0500 Subject: [PATCH 08/47] [dev.regabi] go/types: must not import a package called "init" This is a port of CL 287494 to go/types. The additional checks in test/fixedbugs are included, though they won't be executed by go/types. Support for errorcheckdir checks will be added to go/types in a later CL. Change-Id: I37e202ea5daf7d7b8fc6ae93a4c4dbd11762480f Reviewed-on: https://go-review.googlesource.com/c/go/+/290570 Reviewed-by: Robert Griesemer Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot --- src/go/types/resolver.go | 25 ++++++++++--------- .../testdata/importdecl0/importdecl0a.src | 2 +- test/fixedbugs/issue43962.dir/a.go | 5 ++++ test/fixedbugs/issue43962.dir/b.go | 7 ++++++ test/fixedbugs/issue43962.go | 9 +++++++ 5 files changed, 35 insertions(+), 13 deletions(-) create mode 100644 test/fixedbugs/issue43962.dir/a.go create mode 100644 test/fixedbugs/issue43962.dir/b.go create mode 100644 test/fixedbugs/issue43962.go diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index cb66871883..47e165db36 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -252,14 +252,6 @@ func (check *Checker) collectObjects() { return } - // add package to list of explicit imports - // (this functionality is provided as a convenience - // for clients; it is not needed for type-checking) - if !pkgImports[imp] { - pkgImports[imp] = true - pkg.imports = append(pkg.imports, imp) - } - // local name overrides imported package name name := imp.name if d.spec.Name != nil { @@ -269,10 +261,19 @@ func (check *Checker) collectObjects() { check.errorf(d.spec.Name, _ImportCRenamed, `cannot rename import "C"`) return } - if name == "init" { - check.errorf(d.spec.Name, _InvalidInitDecl, "cannot declare init - must be func") - return - } + } + + if name == "init" { + check.errorf(d.spec.Name, _InvalidInitDecl, "cannot import package as init - init must be a func") + return + } + + // add package to list of explicit imports + // (this functionality is provided as a convenience + // for clients; it is not needed for type-checking) + if !pkgImports[imp] { + pkgImports[imp] = true + pkg.imports = append(pkg.imports, imp) } pkgName := NewPkgName(d.spec.Pos(), pkg, name, imp) diff --git a/src/go/types/testdata/importdecl0/importdecl0a.src b/src/go/types/testdata/importdecl0/importdecl0a.src index e96fca3cdd..5ceb96e1fa 100644 --- a/src/go/types/testdata/importdecl0/importdecl0a.src +++ b/src/go/types/testdata/importdecl0/importdecl0a.src @@ -10,7 +10,7 @@ import ( // we can have multiple blank imports (was bug) _ "math" _ "net/rpc" - init /* ERROR "cannot declare init" */ "fmt" + init /* ERROR "cannot import package as init" */ "fmt" // reflect defines a type "flag" which shows up in the gc export data "reflect" . /* ERROR "imported but not used" */ "reflect" diff --git a/test/fixedbugs/issue43962.dir/a.go b/test/fixedbugs/issue43962.dir/a.go new file mode 100644 index 0000000000..168b2063b4 --- /dev/null +++ b/test/fixedbugs/issue43962.dir/a.go @@ -0,0 +1,5 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package init diff --git a/test/fixedbugs/issue43962.dir/b.go b/test/fixedbugs/issue43962.dir/b.go new file mode 100644 index 0000000000..f55fea11c1 --- /dev/null +++ b/test/fixedbugs/issue43962.dir/b.go @@ -0,0 +1,7 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" // ERROR "cannot import package as init" diff --git a/test/fixedbugs/issue43962.go b/test/fixedbugs/issue43962.go new file mode 100644 index 0000000000..dca4d077d5 --- /dev/null +++ b/test/fixedbugs/issue43962.go @@ -0,0 +1,9 @@ +// errorcheckdir + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 43962: Importing a package called "init" is an error. + +package ignored From 1c58fcf7ed917f66e2b7f77f251e7e63ca9630e2 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 8 Feb 2021 18:04:58 -0500 Subject: [PATCH 09/47] [dev.regabi] go/types: handle untyped constant arithmetic overflow This is a port of CL 287832 for go/types. It differs from that CL in its handling of position data. Unlike the syntax package, which has a unified Operation node, go/types checks operations for ast.UnaryExpr, IncDecStmt, and BinaryExpr. It was simpler to keep the existing position logic. Notably, this correctly puts the errors on the operator. Change-Id: Id1e3aefe863da225eb0a9b3628cfc8a5684c0c4f Reviewed-on: https://go-review.googlesource.com/c/go/+/290569 Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Trust: Robert Findley --- src/go/types/expr.go | 133 +++++++++++++++++++------------ src/go/types/stdlib_test.go | 1 - src/go/types/testdata/const0.src | 7 ++ 3 files changed, 88 insertions(+), 53 deletions(-) diff --git a/src/go/types/expr.go b/src/go/types/expr.go index f7fb0caedd..2741cc635d 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -78,13 +78,60 @@ func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool { return true } +// overflow checks that the constant x is representable by its type. +// For untyped constants, it checks that the value doesn't become +// arbitrarily large. +func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) { + assert(x.mode == constant_) + + what := "" // operator description, if any + if int(op) < len(op2str) { + what = op2str[op] + } + + if x.val.Kind() == constant.Unknown { + // TODO(gri) We should report exactly what went wrong. At the + // moment we don't have the (go/constant) API for that. + // See also TODO in go/constant/value.go. + check.errorf(atPos(opPos), _InvalidConstVal, "constant result is not representable") + return + } + + // Typed constants must be representable in + // their type after each constant operation. + if typ, ok := x.typ.Underlying().(*Basic); ok && isTyped(typ) { + check.representable(x, typ) + return + } + + // Untyped integer values must not grow arbitrarily. + const limit = 4 * 512 // 512 is the constant precision - we need more because old tests had no limits + if x.val.Kind() == constant.Int && constant.BitLen(x.val) > limit { + check.errorf(atPos(opPos), _InvalidConstVal, "constant %s overflow", what) + x.val = constant.MakeUnknown() + } +} + +// This is only used for operations that may cause overflow. +var op2str = [...]string{ + token.ADD: "addition", + token.SUB: "subtraction", + token.XOR: "bitwise XOR", + token.MUL: "multiplication", + token.SHL: "shift", +} + // The unary expression e may be nil. It's passed in for better error messages only. -func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) { - switch op { +func (check *Checker) unary(x *operand, e *ast.UnaryExpr) { + check.expr(x, e.X) + if x.mode == invalid { + return + } + switch e.Op { case token.AND: // spec: "As an exception to the addressability // requirement x may also be a composite literal." - if _, ok := unparen(x.expr).(*ast.CompositeLit); !ok && x.mode != variable { + if _, ok := unparen(e.X).(*ast.CompositeLit); !ok && x.mode != variable { check.invalidOp(x, _UnaddressableOperand, "cannot take address of %s", x) x.mode = invalid return @@ -111,26 +158,23 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) { return } - if !check.op(unaryOpPredicates, x, op) { + if !check.op(unaryOpPredicates, x, e.Op) { x.mode = invalid return } if x.mode == constant_ { - typ := x.typ.Underlying().(*Basic) + if x.val.Kind() == constant.Unknown { + // nothing to do (and don't cause an error below in the overflow check) + return + } var prec uint - if isUnsigned(typ) { - prec = uint(check.conf.sizeof(typ) * 8) - } - x.val = constant.UnaryOp(op, x.val, prec) - // Typed constants must be representable in - // their type after each constant operation. - if isTyped(typ) { - if e != nil { - x.expr = e // for better error message - } - check.representable(x, typ) + if isUnsigned(x.typ) { + prec = uint(check.conf.sizeof(x.typ) * 8) } + x.val = constant.UnaryOp(e.Op, x.val, prec) + x.expr = e + check.overflow(x, e.Op, x.Pos()) return } @@ -667,7 +711,8 @@ func (check *Checker) comparison(x, y *operand, op token.Token) { x.typ = Typ[UntypedBool] } -func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) { +// If e != nil, it must be the shift expression; it may be nil for non-constant shifts. +func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) { untypedx := isUntyped(x.typ) var xval constant.Value @@ -735,14 +780,12 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) { } // x is a constant so xval != nil and it must be of Int kind. x.val = constant.Shift(xval, op, uint(s)) - // Typed constants must be representable in - // their type after each constant operation. - if isTyped(x.typ) { - if e != nil { - x.expr = e // for better error message - } - check.representable(x, x.typ.Underlying().(*Basic)) + x.expr = e + opPos := x.Pos() + if b, _ := e.(*ast.BinaryExpr); b != nil { + opPos = b.OpPos } + check.overflow(x, op, opPos) return } @@ -803,8 +846,9 @@ var binaryOpPredicates = opPredicates{ token.LOR: isBoolean, } -// The binary expression e may be nil. It's passed in for better error messages only. -func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, op token.Token, opPos token.Pos) { +// If e != nil, it must be the binary expression; it may be nil for non-constant expressions +// (when invoked for an assignment operation where the binary expression is implicit). +func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token.Token, opPos token.Pos) { var y operand check.expr(x, lhs) @@ -879,30 +923,19 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o } if x.mode == constant_ && y.mode == constant_ { - xval := x.val - yval := y.val - typ := x.typ.Underlying().(*Basic) + // if either x or y has an unknown value, the result is unknown + if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown { + x.val = constant.MakeUnknown() + // x.typ is unchanged + return + } // force integer division of integer operands - if op == token.QUO && isInteger(typ) { + if op == token.QUO && isInteger(x.typ) { op = token.QUO_ASSIGN } - x.val = constant.BinaryOp(xval, op, yval) - // report error if valid operands lead to an invalid result - if xval.Kind() != constant.Unknown && yval.Kind() != constant.Unknown && x.val.Kind() == constant.Unknown { - // TODO(gri) We should report exactly what went wrong. At the - // moment we don't have the (go/constant) API for that. - // See also TODO in go/constant/value.go. - check.errorf(atPos(opPos), _InvalidConstVal, "constant result is not representable") - // TODO(gri) Should we mark operands with unknown values as invalid? - } - // Typed constants must be representable in - // their type after each constant operation. - if isTyped(typ) { - if e != nil { - x.expr = e // for better error message - } - check.representable(x, typ) - } + x.val = constant.BinaryOp(x.val, op, y.val) + x.expr = e + check.overflow(x, op, opPos) return } @@ -1538,11 +1571,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { } case *ast.UnaryExpr: - check.expr(x, e.X) - if x.mode == invalid { - goto Error - } - check.unary(x, e, e.Op) + check.unary(x, e) if x.mode == invalid { goto Error } diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go index 63e31f3d74..8a1e2905a7 100644 --- a/src/go/types/stdlib_test.go +++ b/src/go/types/stdlib_test.go @@ -171,7 +171,6 @@ func TestStdFixed(t *testing.T) { testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"), "bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore "issue6889.go", // gc-specific test - "issue7746.go", // large constants - consumes too much memory "issue11362.go", // canonical import path check "issue16369.go", // go/types handles this correctly - not an issue "issue18459.go", // go/types doesn't check validity of //go:xxx directives diff --git a/src/go/types/testdata/const0.src b/src/go/types/testdata/const0.src index adbbf2863b..2916af5490 100644 --- a/src/go/types/testdata/const0.src +++ b/src/go/types/testdata/const0.src @@ -348,3 +348,10 @@ const _ = unsafe.Sizeof(func() { assert(one == 1) assert(iota == 0) }) + +// untyped constants must not get arbitrarily large +const ( + huge = 1<<1000 + _ = huge * huge * /* ERROR constant multiplication overflow */ huge + _ = huge << 1000 << /* ERROR constant shift overflow */ 1000 +) From 0a62067708938020e10b8142b4017edeac1b1f52 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 8 Feb 2021 21:53:29 -0500 Subject: [PATCH 10/47] [dev.regabi] go/types: adjust importer to match compiler importer This is an exact port of CL 288632 to go/types. Change-Id: Ie46e13355bdd0713b392e042844bab8491a16504 Reviewed-on: https://go-review.googlesource.com/c/go/+/290629 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/internal/gcimporter/iimport.go | 52 +++++++++++---------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/src/go/internal/gcimporter/iimport.go b/src/go/internal/gcimporter/iimport.go index c59dd16533..a3184e7641 100644 --- a/src/go/internal/gcimporter/iimport.go +++ b/src/go/internal/gcimporter/iimport.go @@ -15,6 +15,7 @@ import ( "go/token" "go/types" "io" + "math/big" "sort" ) @@ -320,7 +321,9 @@ func (r *importReader) value() (typ types.Type, val constant.Value) { val = constant.MakeString(r.string()) case types.IsInteger: - val = r.mpint(b) + var x big.Int + r.mpint(&x, b) + val = constant.Make(&x) case types.IsFloat: val = r.mpfloat(b) @@ -365,8 +368,8 @@ func intSize(b *types.Basic) (signed bool, maxBytes uint) { return } -func (r *importReader) mpint(b *types.Basic) constant.Value { - signed, maxBytes := intSize(b) +func (r *importReader) mpint(x *big.Int, typ *types.Basic) { + signed, maxBytes := intSize(typ) maxSmall := 256 - maxBytes if signed { @@ -385,7 +388,8 @@ func (r *importReader) mpint(b *types.Basic) constant.Value { v = ^v } } - return constant.MakeInt64(v) + x.SetInt64(v) + return } v := -n @@ -395,39 +399,23 @@ func (r *importReader) mpint(b *types.Basic) constant.Value { if v < 1 || uint(v) > maxBytes { errorf("weird decoding: %v, %v => %v", n, signed, v) } - - buf := make([]byte, v) - io.ReadFull(&r.declReader, buf) - - // convert to little endian - // TODO(gri) go/constant should have a more direct conversion function - // (e.g., once it supports a big.Float based implementation) - for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 { - buf[i], buf[j] = buf[j], buf[i] - } - - x := constant.MakeFromBytes(buf) + b := make([]byte, v) + io.ReadFull(&r.declReader, b) + x.SetBytes(b) if signed && n&1 != 0 { - x = constant.UnaryOp(token.SUB, x, 0) + x.Neg(x) } - return x } -func (r *importReader) mpfloat(b *types.Basic) constant.Value { - x := r.mpint(b) - if constant.Sign(x) == 0 { - return x +func (r *importReader) mpfloat(typ *types.Basic) constant.Value { + var mant big.Int + r.mpint(&mant, typ) + var f big.Float + f.SetInt(&mant) + if f.Sign() != 0 { + f.SetMantExp(&f, int(r.int64())) } - - exp := r.int64() - switch { - case exp > 0: - x = constant.Shift(x, token.SHL, uint(exp)) - case exp < 0: - d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp)) - x = constant.BinaryOp(x, token.QUO, d) - } - return x + return constant.Make(&f) } func (r *importReader) ident() string { From 168d6a49a5ecbdd6a1eb039b2398c2821b3d3865 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 8 Feb 2021 22:37:48 -0500 Subject: [PATCH 11/47] [dev.regabi] go/types: use 512 bits as max. integer precision This is a port of CL 288633 to go/types. It differs from that CL in the implementation of opName, which now uses ast Exprs. Additionally, a couple tests had to be updated: + TestEvalArith is updated to not overflow. + stmt0.src is updated to have an error positioned on the '<<' operator. Change-Id: I628357c33a1e7b0bb5bb7de5736f1fb10ce404e4 Reviewed-on: https://go-review.googlesource.com/c/go/+/290630 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/eval_test.go | 2 +- src/go/types/expr.go | 46 +++++++++++++++++++++++------- src/go/types/stdlib_test.go | 1 - src/go/types/testdata/builtins.src | 10 +++---- src/go/types/testdata/const0.src | 16 +++++++---- src/go/types/testdata/const1.src | 18 ++++++++++-- src/go/types/testdata/stmt0.src | 2 +- 7 files changed, 69 insertions(+), 26 deletions(-) diff --git a/src/go/types/eval_test.go b/src/go/types/eval_test.go index d940bf0e80..3a97ac0471 100644 --- a/src/go/types/eval_test.go +++ b/src/go/types/eval_test.go @@ -76,7 +76,7 @@ func TestEvalArith(t *testing.T) { `false == false`, `12345678 + 87654321 == 99999999`, `10 * 20 == 200`, - `(1<<1000)*2 >> 100 == 2<<900`, + `(1<<500)*2 >> 100 == 2<<400`, `"foo" + "bar" == "foobar"`, `"abc" <= "bcd"`, `len([10]struct{}{}) == 2*5`, diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 2741cc635d..5e1fe28a43 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -84,11 +84,6 @@ func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool { func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) { assert(x.mode == constant_) - what := "" // operator description, if any - if int(op) < len(op2str) { - what = op2str[op] - } - if x.val.Kind() == constant.Unknown { // TODO(gri) We should report exactly what went wrong. At the // moment we don't have the (go/constant) API for that. @@ -105,15 +100,37 @@ func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) { } // Untyped integer values must not grow arbitrarily. - const limit = 4 * 512 // 512 is the constant precision - we need more because old tests had no limits - if x.val.Kind() == constant.Int && constant.BitLen(x.val) > limit { - check.errorf(atPos(opPos), _InvalidConstVal, "constant %s overflow", what) + const prec = 512 // 512 is the constant precision + if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec { + check.errorf(atPos(opPos), _InvalidConstVal, "constant %s overflow", opName(x.expr)) x.val = constant.MakeUnknown() } } +// opName returns the name of an operation, or the empty string. +// For now, only operations that might overflow are handled. +// TODO(gri) Expand this to a general mechanism giving names to +// nodes? +func opName(e ast.Expr) string { + switch e := e.(type) { + case *ast.BinaryExpr: + if int(e.Op) < len(op2str2) { + return op2str2[e.Op] + } + case *ast.UnaryExpr: + if int(e.Op) < len(op2str1) { + return op2str1[e.Op] + } + } + return "" +} + +var op2str1 = [...]string{ + token.XOR: "bitwise complement", +} + // This is only used for operations that may cause overflow. -var op2str = [...]string{ +var op2str2 = [...]string{ token.ADD: "addition", token.SUB: "subtraction", token.XOR: "bitwise XOR", @@ -763,8 +780,17 @@ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) { if x.mode == constant_ { if y.mode == constant_ { + // if either x or y has an unknown value, the result is unknown + if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown { + x.val = constant.MakeUnknown() + // ensure the correct type - see comment below + if !isInteger(x.typ) { + x.typ = Typ[UntypedInt] + } + return + } // rhs must be within reasonable bounds in constant shifts - const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64 + const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64 (see issue #44057) s, ok := constant.Uint64Val(yval) if !ok || s > shiftBound { check.invalidOp(y, _InvalidShiftCount, "invalid shift count %s", y) diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go index 8a1e2905a7..71e14b85e5 100644 --- a/src/go/types/stdlib_test.go +++ b/src/go/types/stdlib_test.go @@ -175,7 +175,6 @@ func TestStdFixed(t *testing.T) { "issue16369.go", // go/types handles this correctly - not an issue "issue18459.go", // go/types doesn't check validity of //go:xxx directives "issue18882.go", // go/types doesn't check validity of //go:xxx directives - "issue20232.go", // go/types handles larger constants than gc "issue20529.go", // go/types does not have constraints on stack size "issue22200.go", // go/types does not have constraints on stack size "issue22200b.go", // go/types does not have constraints on stack size diff --git a/src/go/types/testdata/builtins.src b/src/go/types/testdata/builtins.src index a7613adc35..6ee28f13b4 100644 --- a/src/go/types/testdata/builtins.src +++ b/src/go/types/testdata/builtins.src @@ -514,7 +514,7 @@ func panic1() { panic("foo") panic(false) panic(1<<10) - panic(1 /* ERROR overflows */ <<1000) + panic(1 << /* ERROR constant shift overflow */ 1000) _ = panic /* ERROR used as value */ (0) var s []byte @@ -538,7 +538,7 @@ func print1() { print(2.718281828) print(false) print(1<<10) - print(1 /* ERROR overflows */ <<1000) + print(1 << /* ERROR constant shift overflow */ 1000) println(nil /* ERROR untyped nil */ ) var s []int @@ -564,7 +564,7 @@ func println1() { println(2.718281828) println(false) println(1<<10) - println(1 /* ERROR overflows */ <<1000) + println(1 << /* ERROR constant shift overflow */ 1000) println(nil /* ERROR untyped nil */ ) var s []int @@ -695,7 +695,7 @@ func Alignof1() { _ = unsafe.Alignof(42) _ = unsafe.Alignof(new(struct{})) _ = unsafe.Alignof(1<<10) - _ = unsafe.Alignof(1 /* ERROR overflows */ <<1000) + _ = unsafe.Alignof(1 << /* ERROR constant shift overflow */ 1000) _ = unsafe.Alignof(nil /* ERROR "untyped nil */ ) unsafe /* ERROR not used */ .Alignof(x) @@ -783,7 +783,7 @@ func Sizeof1() { _ = unsafe.Sizeof(42) _ = unsafe.Sizeof(new(complex128)) _ = unsafe.Sizeof(1<<10) - _ = unsafe.Sizeof(1 /* ERROR overflows */ <<1000) + _ = unsafe.Sizeof(1 << /* ERROR constant shift overflow */ 1000) _ = unsafe.Sizeof(nil /* ERROR untyped nil */ ) unsafe /* ERROR not used */ .Sizeof(x) diff --git a/src/go/types/testdata/const0.src b/src/go/types/testdata/const0.src index 2916af5490..5608b1549b 100644 --- a/src/go/types/testdata/const0.src +++ b/src/go/types/testdata/const0.src @@ -350,8 +350,14 @@ const _ = unsafe.Sizeof(func() { }) // untyped constants must not get arbitrarily large -const ( - huge = 1<<1000 - _ = huge * huge * /* ERROR constant multiplication overflow */ huge - _ = huge << 1000 << /* ERROR constant shift overflow */ 1000 -) +const prec = 512 // internal maximum precision for integers +const maxInt = (1<<(prec/2) - 1) * (1<<(prec/2) + 1) // == 1< Date: Thu, 4 Feb 2021 15:26:52 -0500 Subject: [PATCH 12/47] cmd/go: suppress errors from 'go get -d' for packages that only conditionally exist Fixes #44106 Fixes #29268 Change-Id: Id113f2ced274d43fbf66cb804581448218996f81 Reviewed-on: https://go-review.googlesource.com/c/go/+/289769 TryBot-Result: Go Bot Reviewed-by: Jay Conrod Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills --- src/cmd/go/internal/modget/get.go | 20 ++- .../go/testdata/script/mod_get_pkgtags.txt | 116 ++++++++++++++++++ 2 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 src/cmd/go/testdata/script/mod_get_pkgtags.txt diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 574f3e194d..1a8c9d3725 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -380,10 +380,9 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) { pkgs := load.PackagesAndErrors(ctx, pkgPatterns) load.CheckPackageErrors(pkgs) work.InstallPackages(ctx, pkgPatterns, pkgs) - // TODO(#40276): After Go 1.16, print a deprecation notice when building - // and installing main packages. 'go install pkg' or - // 'go install pkg@version' should be used instead. - // Give the specific argument to use if possible. + // TODO(#40276): After Go 1.16, print a deprecation notice when building and + // installing main packages. 'go install pkg' or 'go install pkg@version' + // should be used instead. Give the specific argument to use if possible. } if !modload.HasModRoot() { @@ -1453,7 +1452,18 @@ func (r *resolver) checkPackagesAndRetractions(ctx context.Context, pkgPatterns } } for _, pkg := range pkgs { - if _, _, err := modload.Lookup("", false, pkg); err != nil { + if dir, _, err := modload.Lookup("", false, pkg); err != nil { + if dir != "" && errors.Is(err, imports.ErrNoGo) { + // Since dir is non-empty, we must have located source files + // associated with either the package or its test — ErrNoGo must + // indicate that none of those source files happen to apply in this + // configuration. If we are actually building the package (no -d + // flag), the compiler will report the problem; otherwise, assume that + // the user is going to build or test it in some other configuration + // and suppress the error. + continue + } + base.SetExitStatus(1) if ambiguousErr := (*modload.AmbiguousImportError)(nil); errors.As(err, &ambiguousErr) { for _, m := range ambiguousErr.Modules { diff --git a/src/cmd/go/testdata/script/mod_get_pkgtags.txt b/src/cmd/go/testdata/script/mod_get_pkgtags.txt new file mode 100644 index 0000000000..c0a57f3fab --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_pkgtags.txt @@ -0,0 +1,116 @@ +# https://golang.org/issue/44106 +# 'go get' should fetch the transitive dependencies of packages regardless of +# tags, but shouldn't error out if the package is missing tag-guarded +# dependencies. + +# Control case: just adding the top-level module to the go.mod file does not +# fetch its dependencies. + +go mod edit -require example.net/tools@v0.1.0 +! go list -deps example.net/cmd/tool +stderr '^module example\.net/cmd provides package example\.net/cmd/tool and is replaced but not required; to add it:\n\tgo get example\.net/cmd@v0\.1\.0$' +go mod edit -droprequire example.net/tools + + +# 'go get -d' makes a best effort to fetch those dependencies, but shouldn't +# error out if dependencies of tag-guarded files are missing. + +go get -d example.net/tools@v0.1.0 + +! go list example.net/tools +stderr '^package example.net/tools: build constraints exclude all Go files in .*[/\\]tools$' + +go list -tags=tools -e -deps example.net/tools +stdout '^example.net/cmd/tool$' +stdout '^example.net/missing$' + +go list -deps example.net/cmd/tool + +! go list example.net/missing +stderr '^no required module provides package example.net/missing; to add it:\n\tgo get example.net/missing$' + + +# https://golang.org/issue/29268 +# 'go get' should fetch modules whose roots contain test-only packages, but +# without the -t flag shouldn't error out if the test has missing dependencies. + +go get -d example.net/testonly@v0.1.0 + +# With the -t flag, the test dependencies must resolve successfully. +! go get -d -t example.net/testonly@v0.1.0 +stderr '^example.net/testonly tested by\n\texample.net/testonly\.test imports\n\texample.net/missing: cannot find module providing package example.net/missing$' + + +# 'go get -d' should succeed for a module path that does not contain a package, +# but fail for a non-package subdirectory of a module. + +! go get -d example.net/missing/subdir@v0.1.0 +stderr '^go get: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$' + +go get -d example.net/missing@v0.1.0 + + +# Getting the subdirectory should continue to fail even if the corresponding +# module is already present in the build list. + +! go get -d example.net/missing/subdir@v0.1.0 +stderr '^go get: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$' + + +-- go.mod -- +module example.net/m + +go 1.15 + +replace ( + example.net/tools v0.1.0 => ./tools + example.net/cmd v0.1.0 => ./cmd + example.net/testonly v0.1.0 => ./testonly + example.net/missing v0.1.0 => ./missing +) + +-- tools/go.mod -- +module example.net/tools + +go 1.15 + +// Requirements intentionally omitted. + +-- tools/tools.go -- +// +build tools + +package tools + +import ( + _ "example.net/cmd/tool" + _ "example.net/missing" +) + +-- cmd/go.mod -- +module example.net/cmd + +go 1.16 +-- cmd/tool/tool.go -- +package main + +func main() {} + +-- testonly/go.mod -- +module example.net/testonly + +go 1.15 +-- testonly/testonly_test.go -- +package testonly_test + +import _ "example.net/missing" + +func Test(t *testing.T) {} + +-- missing/go.mod -- +module example.net/missing + +go 1.15 +-- missing/README.txt -- +There are no Go source files here. +-- missing/subdir/README.txt -- +There are no Go source files here either. From 59703d53e249db738363c3fab9143348ff9559ea Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Fri, 5 Feb 2021 18:07:46 -0500 Subject: [PATCH 13/47] [dev.regabi] cmd/link: stop using ABI aliases if wrapper is enabled If ABI wrappers are enabled, we should not see ABI aliases at link time. Stop resolving them. One exception is shared linkage, where we still use ABI aliases as we don't always know the ABI for symbols from shared libraries. Change-Id: Ia89a788094382adeb4c4ef9b0312aa6e8c2f79ef Reviewed-on: https://go-review.googlesource.com/c/go/+/290032 TryBot-Result: Go Bot Reviewed-by: Than McIntosh Trust: Cherry Zhang Run-TryBot: Cherry Zhang --- src/cmd/link/internal/ld/lib.go | 8 +++++++- src/cmd/link/internal/loader/loader.go | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 71cef0b774..314896824a 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -489,10 +489,16 @@ func (ctxt *Link) loadlib() { case 0: // nothing to do case 1, 2: - flags = loader.FlagStrictDups + flags |= loader.FlagStrictDups default: log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups) } + if !*flagAbiWrap || ctxt.linkShared { + // Use ABI aliases if ABI wrappers are not used. + // TODO: for now we still use ABI aliases in shared linkage, even if + // the wrapper is enabled. + flags |= loader.FlagUseABIAlias + } elfsetstring1 := func(str string, off int) { elfsetstring(ctxt, 0, str, off) } ctxt.loader = loader.NewLoader(flags, elfsetstring1, &ctxt.ErrorReporter.ErrorReporter) ctxt.ErrorReporter.SymName = func(s loader.Sym) string { diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 971cc432ff..98c2131c2b 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -322,6 +322,7 @@ type extSymPayload struct { const ( // Loader.flags FlagStrictDups = 1 << iota + FlagUseABIAlias ) func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorReporter) *Loader { @@ -2270,6 +2271,9 @@ func abiToVer(abi uint16, localSymVersion int) int { // symbol. If the sym in question is not an alias, the sym itself is // returned. func (l *Loader) ResolveABIAlias(s Sym) Sym { + if l.flags&FlagUseABIAlias == 0 { + return s + } if s == 0 { return 0 } From ed8079096fe2e78d6dcb8002758774dca6d24eee Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Wed, 10 Feb 2021 12:43:18 -0500 Subject: [PATCH 14/47] cmd/compile: mark concrete call of reflect.(*rtype).Method as REFLECTMETHOD For functions that call reflect.Type.Method (or MethodByName), we mark it as REFLECTMETHOD, which tells the linker that methods can be retrieved via reflection and the linker keeps all exported methods live. Currently, this marking expects exactly the interface call reflect.Type.Method (or MethodByName). But now the compiler can devirtualize that call to a concrete call reflect.(*rtype).Method (or MethodByName), which is not handled and causing the linker to discard methods too aggressively. Handle the latter in this CL. Fixes #44207. Change-Id: Ia4060472dbff6ab6a83d2ca8e60a3e3f180ee832 Reviewed-on: https://go-review.googlesource.com/c/go/+/290950 Trust: Cherry Zhang Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/walk.go | 16 +++++++++++++++- test/reflectmethod7.go | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 test/reflectmethod7.go diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 2133a160b2..98ebb23991 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -550,8 +550,12 @@ opswitch: case OCLOSUREVAR, OCFUNC: case OCALLINTER, OCALLFUNC, OCALLMETH: - if n.Op == OCALLINTER { + if n.Op == OCALLINTER || n.Op == OCALLMETH { + // We expect both interface call reflect.Type.Method and concrete + // call reflect.(*rtype).Method. usemethod(n) + } + if n.Op == OCALLINTER { markUsedIfaceMethod(n) } @@ -3710,6 +3714,16 @@ func usemethod(n *Node) { } } + // Don't mark reflect.(*rtype).Method, etc. themselves in the reflect package. + // Those functions may be alive via the itab, which should not cause all methods + // alive. We only want to mark their callers. + if myimportpath == "reflect" { + switch Curfn.Func.Nname.Sym.Name { // TODO: is there a better way than hardcoding the names? + case "(*rtype).Method", "(*rtype).MethodByName", "(*interfaceType).Method", "(*interfaceType).MethodByName": + return + } + } + // Note: Don't rely on res0.Type.String() since its formatting depends on multiple factors // (including global variables such as numImports - was issue #19028). // Also need to check for reflect package itself (see Issue #38515). diff --git a/test/reflectmethod7.go b/test/reflectmethod7.go new file mode 100644 index 0000000000..42429978b4 --- /dev/null +++ b/test/reflectmethod7.go @@ -0,0 +1,24 @@ +// run + +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// See issue 44207. + +package main + +import "reflect" + +type S int + +func (s S) M() {} + +func main() { + t := reflect.TypeOf(S(0)) + fn, ok := reflect.PtrTo(t).MethodByName("M") + if !ok { + panic("FAIL") + } + fn.Func.Call([]reflect.Value{reflect.New(t)}) +} From e5b08e6d5cecb646066c0cadddf6300e2a10ffb2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 9 Feb 2021 13:46:53 -0500 Subject: [PATCH 15/47] io/fs: allow backslash in ValidPath, reject in os.DirFS.Open Rejecting backslash introduces problems with presenting underlying OS file systems that contain names with backslash. Rejecting backslash also does not Windows-proof the syntax, because colon can also be a path separator. And we are not going to reject colon from all names. So don't reject backslash either. There is a similar problem on Windows with names containing slashes, but those are more difficult (though not impossible) to create. Also document and enforce that paths must be UTF-8. Fixes #44166. Change-Id: Iac7a9a268025c1fd31010dbaf3f51e1660c7ae2a Reviewed-on: https://go-review.googlesource.com/c/go/+/290709 TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Trust: Russ Cox Run-TryBot: Russ Cox --- src/io/fs/fs.go | 25 +++++++++++++++---------- src/io/fs/fs_test.go | 7 ++++--- src/os/file.go | 13 ++++++++++++- src/os/os_test.go | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/io/fs/fs.go b/src/io/fs/fs.go index c330f123ad..3d2e2ee2ac 100644 --- a/src/io/fs/fs.go +++ b/src/io/fs/fs.go @@ -10,6 +10,7 @@ package fs import ( "internal/oserror" "time" + "unicode/utf8" ) // An FS provides access to a hierarchical file system. @@ -32,15 +33,22 @@ type FS interface { // ValidPath reports whether the given path name // is valid for use in a call to Open. -// Path names passed to open are unrooted, slash-separated -// sequences of path elements, like “x/y/z”. -// Path names must not contain a “.” or “..” or empty element, -// except for the special case that the root directory is named “.”. -// Leading and trailing slashes (like “/x” or “x/”) are not allowed. // -// Paths are slash-separated on all systems, even Windows. -// Backslashes must not appear in path names. +// Path names passed to open are UTF-8-encoded, +// unrooted, slash-separated sequences of path elements, like “x/y/z”. +// Path names must not contain an element that is “.” or “..” or the empty string, +// except for the special case that the root directory is named “.”. +// Paths must not start or end with a slash: “/x” and “x/” are invalid. +// +// Note that paths are slash-separated on all systems, even Windows. +// Paths containing other characters such as backslash and colon +// are accepted as valid, but those characters must never be +// interpreted by an FS implementation as path element separators. func ValidPath(name string) bool { + if !utf8.ValidString(name) { + return false + } + if name == "." { // special case return true @@ -50,9 +58,6 @@ func ValidPath(name string) bool { for { i := 0 for i < len(name) && name[i] != '/' { - if name[i] == '\\' { - return false - } i++ } elem := name[:i] diff --git a/src/io/fs/fs_test.go b/src/io/fs/fs_test.go index 8d395fc0db..aae1a7606f 100644 --- a/src/io/fs/fs_test.go +++ b/src/io/fs/fs_test.go @@ -33,9 +33,10 @@ var isValidPathTests = []struct { {"x/..", false}, {"x/../y", false}, {"x//y", false}, - {`x\`, false}, - {`x\y`, false}, - {`\x`, false}, + {`x\`, true}, + {`x\y`, true}, + {`x:y`, true}, + {`\x`, true}, } func TestValidPath(t *testing.T) { diff --git a/src/os/file.go b/src/os/file.go index 416bc0efa6..52dd94339b 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -620,10 +620,21 @@ func DirFS(dir string) fs.FS { return dirFS(dir) } +func containsAny(s, chars string) bool { + for i := 0; i < len(s); i++ { + for j := 0; j < len(chars); j++ { + if s[i] == chars[j] { + return true + } + } + } + return false +} + type dirFS string func (dir dirFS) Open(name string) (fs.File, error) { - if !fs.ValidPath(name) { + if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) { return nil, &PathError{Op: "open", Path: name, Err: ErrInvalid} } f, err := Open(string(dir) + "/" + name) diff --git a/src/os/os_test.go b/src/os/os_test.go index ee54b4aba1..a32e5fc11e 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -2719,6 +2719,40 @@ func TestDirFS(t *testing.T) { if err := fstest.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err != nil { t.Fatal(err) } + + // Test that Open does not accept backslash as separator. + d := DirFS(".") + _, err := d.Open(`testdata\dirfs`) + if err == nil { + t.Fatalf(`Open testdata\dirfs succeeded`) + } +} + +func TestDirFSPathsValid(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skipf("skipping on Windows") + } + + d := t.TempDir() + if err := os.WriteFile(filepath.Join(d, "control.txt"), []byte(string("Hello, world!")), 0644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(d, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err != nil { + t.Fatal(err) + } + + fsys := os.DirFS(d) + err := fs.WalkDir(fsys, ".", func(path string, e fs.DirEntry, err error) error { + if fs.ValidPath(e.Name()) { + t.Logf("%q ok", e.Name()) + } else { + t.Errorf("%q INVALID", e.Name()) + } + return nil + }) + if err != nil { + t.Fatal(err) + } } func TestReadFileProc(t *testing.T) { From 930c2c9a6810b54d84dc499120219a6cb4563fd7 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 9 Feb 2021 17:34:09 -0500 Subject: [PATCH 16/47] cmd/go: reject embedded files that can't be packed into modules If the file won't be packed into a module, don't put those files into embeds. Otherwise people will be surprised when things work locally but not when imported by another module. Observed on CL 290709 Change-Id: Ia0ef7d0e0f5e42473c2b774e57c843e68a365bc7 Reviewed-on: https://go-review.googlesource.com/c/go/+/290809 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Reviewed-by: Jay Conrod --- src/cmd/go/internal/load/pkg.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 3a274a3ad1..8b12faf4cd 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -36,6 +36,8 @@ import ( "cmd/go/internal/str" "cmd/go/internal/trace" "cmd/internal/sys" + + "golang.org/x/mod/module" ) var IgnoreImports bool // control whether we ignore imports in packages @@ -2090,6 +2092,9 @@ func validEmbedPattern(pattern string) bool { // can't or won't be included in modules and therefore shouldn't be treated // as existing for embedding. func isBadEmbedName(name string) bool { + if err := module.CheckFilePath(name); err != nil { + return true + } switch name { // Empty string should be impossible but make it bad. case "": From 26ceae85a89dc4ea910cc0bfa209c85213a93725 Mon Sep 17 00:00:00 2001 From: DQNEO Date: Wed, 10 Feb 2021 14:46:54 +0900 Subject: [PATCH 17/47] spec: More precise wording in section on function calls. A caller is not always in a function. For example, a call can appear in top level declarations. e.g. var x = f() Change-Id: I29c4c3b7663249434fb2b8a6d0003267c77268cf Reviewed-on: https://go-review.googlesource.com/c/go/+/290849 Reviewed-by: Rob Pike Reviewed-by: Ian Lance Taylor Reviewed-by: Robert Griesemer Trust: Robert Griesemer --- doc/go_spec.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index c9e14a3fec..59c9ce3c43 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -3446,7 +3446,7 @@ In a function call, the function value and arguments are evaluated in After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution. The return parameters of the function are passed by value -back to the calling function when the function returns. +back to the caller when the function returns.

From 864d4f1c6b364e13c0a4008bc203f336b0027f44 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Thu, 11 Feb 2021 10:27:55 -0500 Subject: [PATCH 18/47] cmd/go: multiple small 'go help' fixes * Link to privacy policies for proxy.golang.org and sum.golang.org in 'go help modules'. It's important that both policies are linked from the go command's documentation. * Fix wording and typo in 'go help vcs' following comments in CL 290992, which adds reference documentation for GOVCS. * Fix whitespace on GOVCS in 'go help environment'. For #41730 Change-Id: I86abceacd4962b748361244026f219157c9285e9 Reviewed-on: https://go-review.googlesource.com/c/go/+/291230 Trust: Jay Conrod Run-TryBot: Jay Conrod Reviewed-by: Bryan C. Mills TryBot-Result: Go Bot --- src/cmd/go/alldocs.go | 30 +++++++++++++++++++++-------- src/cmd/go/internal/help/helpdoc.go | 2 +- src/cmd/go/internal/modget/get.go | 17 +++++++++------- src/cmd/go/internal/modload/help.go | 13 +++++++++++-- 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 49d390297c..e7c63f0749 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1808,7 +1808,7 @@ // The directory where the go command will write // temporary source files, packages, and binaries. // GOVCS -// Lists version control commands that may be used with matching servers. +// Lists version control commands that may be used with matching servers. // See 'go help vcs'. // // Environment variables for use with cgo: @@ -2410,6 +2410,17 @@ // // For a detailed reference on modules, see https://golang.org/ref/mod. // +// By default, the go command may download modules from https://proxy.golang.org. +// It may authenticate modules using the checksum database at +// https://sum.golang.org. Both services are operated by the Go team at Google. +// The privacy policies for these services are available at +// https://proxy.golang.org/privacy and https://sum.golang.org/privacy, +// respectively. +// +// The go command's download behavior may be configured using GOPROXY, GOSUMDB, +// GOPRIVATE, and other environment variables. See 'go help environment' +// and https://golang.org/ref/mod#private-module-privacy for more information. +// // // Module authentication using go.sum // @@ -2868,20 +2879,23 @@ // legal reasons). Therefore, clients can still access public code served from // Bazaar, Fossil, or Subversion repositories by default, because those downloads // use the Go module mirror, which takes on the security risk of running the -// version control commands, using a custom sandbox. +// version control commands using a custom sandbox. // // The GOVCS variable can be used to change the allowed version control systems // for specific packages (identified by a module or import path). -// The GOVCS variable applies both when using modules and when using GOPATH. -// When using modules, the patterns match against the module path. -// When using GOPATH, the patterns match against the import path -// corresponding to the root of the version control repository. +// The GOVCS variable applies when building package in both module-aware mode +// and GOPATH mode. When using modules, the patterns match against the module path. +// When using GOPATH, the patterns match against the import path corresponding to +// the root of the version control repository. // // The general form of the GOVCS setting is a comma-separated list of // pattern:vcslist rules. The pattern is a glob pattern that must match // one or more leading elements of the module or import path. The vcslist // is a pipe-separated list of allowed version control commands, or "all" -// to allow use of any known command, or "off" to allow nothing. +// to allow use of any known command, or "off" to disallow all commands. +// Note that if a module matches a pattern with vcslist "off", it may still be +// downloaded if the origin server uses the "mod" scheme, which instructs the +// go command to download the module using the GOPROXY protocol. // The earliest matching pattern in the list applies, even if later patterns // might also match. // @@ -2889,7 +2903,7 @@ // // GOVCS=github.com:git,evil.com:off,*:git|hg // -// With this setting, code with an module or import path beginning with +// With this setting, code with a module or import path beginning with // github.com/ can only use git; paths on evil.com cannot use any version // control command, and all other paths (* matches everything) can use // only git or hg. diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index e07ad0e1db..57cee4ff96 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -542,7 +542,7 @@ General-purpose environment variables: The directory where the go command will write temporary source files, packages, and binaries. GOVCS - Lists version control commands that may be used with matching servers. + Lists version control commands that may be used with matching servers. See 'go help vcs'. Environment variables for use with cgo: diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 1a8c9d3725..dccacd3d1e 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -176,20 +176,23 @@ packages or when the mirror refuses to serve a public package (typically for legal reasons). Therefore, clients can still access public code served from Bazaar, Fossil, or Subversion repositories by default, because those downloads use the Go module mirror, which takes on the security risk of running the -version control commands, using a custom sandbox. +version control commands using a custom sandbox. The GOVCS variable can be used to change the allowed version control systems for specific packages (identified by a module or import path). -The GOVCS variable applies both when using modules and when using GOPATH. -When using modules, the patterns match against the module path. -When using GOPATH, the patterns match against the import path -corresponding to the root of the version control repository. +The GOVCS variable applies when building package in both module-aware mode +and GOPATH mode. When using modules, the patterns match against the module path. +When using GOPATH, the patterns match against the import path corresponding to +the root of the version control repository. The general form of the GOVCS setting is a comma-separated list of pattern:vcslist rules. The pattern is a glob pattern that must match one or more leading elements of the module or import path. The vcslist is a pipe-separated list of allowed version control commands, or "all" -to allow use of any known command, or "off" to allow nothing. +to allow use of any known command, or "off" to disallow all commands. +Note that if a module matches a pattern with vcslist "off", it may still be +downloaded if the origin server uses the "mod" scheme, which instructs the +go command to download the module using the GOPROXY protocol. The earliest matching pattern in the list applies, even if later patterns might also match. @@ -197,7 +200,7 @@ For example, consider: GOVCS=github.com:git,evil.com:off,*:git|hg -With this setting, code with an module or import path beginning with +With this setting, code with a module or import path beginning with github.com/ can only use git; paths on evil.com cannot use any version control command, and all other paths (* matches everything) can use only git or hg. diff --git a/src/cmd/go/internal/modload/help.go b/src/cmd/go/internal/modload/help.go index 1cb58961be..fd39ddd94e 100644 --- a/src/cmd/go/internal/modload/help.go +++ b/src/cmd/go/internal/modload/help.go @@ -6,8 +6,6 @@ package modload import "cmd/go/internal/base" -// TODO(rsc): The "module code layout" section needs to be written. - var HelpModules = &base.Command{ UsageLine: "modules", Short: "modules, module versions, and more", @@ -22,6 +20,17 @@ For a series of tutorials on modules, see https://golang.org/doc/tutorial/create-module. For a detailed reference on modules, see https://golang.org/ref/mod. + +By default, the go command may download modules from https://proxy.golang.org. +It may authenticate modules using the checksum database at +https://sum.golang.org. Both services are operated by the Go team at Google. +The privacy policies for these services are available at +https://proxy.golang.org/privacy and https://sum.golang.org/privacy, +respectively. + +The go command's download behavior may be configured using GOPROXY, GOSUMDB, +GOPRIVATE, and other environment variables. See 'go help environment' +and https://golang.org/ref/mod#private-module-privacy for more information. `, } From 249da7ec020e194208c02c8eb6a04d017bf29fea Mon Sep 17 00:00:00 2001 From: Carlos Amedee Date: Wed, 10 Feb 2021 20:29:50 -0500 Subject: [PATCH 19/47] CONTRIBUTORS: update for the Go 1.16 release This update was created using the updatecontrib command: go get golang.org/x/build/cmd/updatecontrib cd gotip updatecontrib With manual changes based on publicly available information to canonicalize letter case and formatting for a few names. For #12042. Change-Id: I030b77e8ebcc7fe02106f0f264acdfb0b56e20d9 Reviewed-on: https://go-review.googlesource.com/c/go/+/291189 Trust: Carlos Amedee Run-TryBot: Carlos Amedee TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Reviewed-by: Alexander Rakoczy Reviewed-by: Dmitri Shuralyov --- CONTRIBUTORS | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index cebc92f53f..ccbe4627f3 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -30,6 +30,7 @@ Aaron Bieber Aaron Cannon Aaron France Aaron Jacobs +Aaron Jensen Aaron Kemp Aaron Patterson Aaron Stein @@ -71,9 +72,11 @@ Ahmet Alp Balkan Ahmet Soormally Ahmy Yulrizka Ahsun Ahmed +Aidan Coyle Aiden Scandella Ainar Garipov Aishraj Dahal +Ajanthan Balachandran Akhil Indurti Akihiro Suda Akshat Kumar @@ -104,9 +107,11 @@ Alex Buchanan Alex Carol Alex Gaynor Alex Harford +Alex Hays Alex Jin Alex Kohler Alex Myasoedov +Alex Opie Alex Plugaru Alex Schroeder Alex Sergeyev @@ -119,6 +124,7 @@ Alexander F Rødseth Alexander Greim Alexander Guz Alexander Kauer +Alexander Klauer Alexander Kucherenko Alexander Larsson Alexander Lourier @@ -150,16 +156,19 @@ Alexey Naidonov Alexey Neganov Alexey Palazhchenko Alexey Semenyuk +Alexey Vilenskiy Alexis Hildebrandt Alexis Hunt Alexis Imperial-Legrand Ali Farooq Ali Rizvi-Santiago Aliaksandr Valialkin +Alice Merrick Alif Rachmawadi Allan Simon Allen Li Alok Menghrajani +Alwin Doss Aman Gupta Amarjeet Anand Amir Mohammad Saied @@ -168,6 +177,8 @@ Amrut Joshi An Long An Xiao Anand K. Mistry +Ananya Saxena +Anatol Pomozov Anders Pearson Anderson Queiroz André Carvalho @@ -199,6 +210,7 @@ Andrew G. Morgan Andrew Gerrand Andrew Harding Andrew Jackura +Andrew Kemm Andrew Louis Andrew Lutomirski Andrew Medvedev @@ -216,6 +228,7 @@ Andrew Werner Andrew Wilkins Andrew Williams Andrew Z Allen +Andrey Bokhanko Andrey Mirtchovski Andrey Petrov Andrii Soldatenko @@ -230,6 +243,7 @@ Andy Maloney Andy Pan Andy Walker Andy Wang +Andy Williams Andzej Maciusovic Anfernee Yongkun Gui Angelo Bulfone @@ -274,6 +288,7 @@ Arne Hormann Arnout Engelen Aron Nopanen Artem Alekseev +Artem Khvastunov Artem Kolin Arthur Fabre Arthur Khashaev @@ -281,8 +296,10 @@ Artyom Pervukhin Arvindh Rajesh Tamilmani Ashish Gandhi Asim Shankar +Assel Meher Atin Malaviya Ato Araki +Atsushi Toyama Audrey Lim Audrius Butkevicius Augusto Roman @@ -291,6 +308,7 @@ Aurélien Rainone Aurélio A. Heckert Austin Clements Avi Flax +Aviv Klasquin Komissar awaw fumin Awn Umar Axel Wagner @@ -298,6 +316,7 @@ Ayan George Ayanamist Yang Ayke van Laethem Aymerick Jéhanne +Ayzat Sadykov Azat Kaumov Baiju Muthukadan Balaram Makam @@ -308,10 +327,12 @@ Bartosz Grzybowski Bartosz Oler Bastian Ike Ben Burkert +Ben Cartwright-Cox Ben Eitzen Ben Fried Ben Haines Ben Hoyt +Ben Kraft Ben Laurie Ben Lubar Ben Lynn @@ -319,6 +340,7 @@ Ben Olive Ben Schwartz Ben Shi Ben Toews +Benjamin Barenblat Benjamin Black Benjamin Cable Benjamin Hsieh @@ -356,6 +378,7 @@ Bobby Powers Boqin Qin Boris Nagaev Borja Clemente +Boshi Lian Brad Burch Brad Erickson Brad Fitzpatrick @@ -368,10 +391,12 @@ Bradford Lamson-Scribner Bradley Falzon Brady Catherman Brady Sullivan +Branden J. Brown Brandon Bennett Brandon Gilmore Brandon Philips Brandon Ryan +Brave Cow Brayden Cloud Brendan Daniel Tracey Brendan O'Dea @@ -389,6 +414,7 @@ Brian Slesinsky Brian Smith Brian Starke Bryan Alexander +Bryan Boreham Bryan C. Mills Bryan Chan Bryan Ford @@ -407,6 +433,7 @@ Carl Mastrangelo Carl Shapiro Carlisia Campos Carlo Alberto Ferraris +Carlos Alexandro Becker Carlos Amedee Carlos Castillo Carlos Cirello @@ -422,6 +449,7 @@ Casey Callendrello Casey Marshall Catalin Nicutar Catalin Patulea +Cathal O'Callaghan Cedric Staub Cezar Sá Espinola Chad Rosier @@ -434,10 +462,14 @@ Charles Kenney Charles L. Dorian Charles Lee Charles Weill +Charlotte Brandhorst-Satzkorn Chauncy Cullitan +Chen Zhidong Chen Zhihan Cherry Zhang Chew Choon Keat +Chiawen Chen +Chirag Sukhala Cholerae Hu Chotepud Teo Chris Ball @@ -460,6 +492,8 @@ Chris Raynor Chris Roche Chris Smith Chris Stockton +Chris Taylor +Chris Waldon Chris Zou Christian Alexander Christian Couder @@ -467,6 +501,7 @@ Christian Himpel Christian Muehlhaeuser Christian Pellegrin Christian R. Petrin +Christian Svensson Christine Hansmann Christoffer Buchholz Christoph Blecker @@ -474,6 +509,7 @@ Christoph Hack Christopher Cahoon Christopher Guiney Christopher Henderson +Christopher Hlubek Christopher Koch Christopher Loessl Christopher Nelson @@ -506,7 +542,10 @@ Costin Chirvasuta Craig Citro Cristian Staretu Cuihtlauac ALVARADO +Cuong Manh Le +Curtis La Graff Cyrill Schumacher +Dai Jie Daisuke Fujita Daisuke Suzuki Daker Fernandes Pinheiro @@ -525,12 +564,14 @@ Dan Peterson Dan Pupius Dan Scales Dan Sinclair +Daniel Cohen Daniel Cormier Daniël de Kok Daniel Fleischman Daniel Ingram Daniel Johansson Daniel Kerwin +Daniel Kessler Daniel Krech Daniel Kumor Daniel Langner @@ -538,10 +579,12 @@ Daniel Lidén Daniel Lublin Daniel Mangum Daniel Martí +Daniel McCarney Daniel Morsing Daniel Nadasi Daniel Nephin Daniel Ortiz Pereira da Silva +Daniel S. Fava Daniel Skinner Daniel Speichert Daniel Theophanes @@ -563,6 +606,7 @@ Dave Cheney Dave Day Dave Grijalva Dave MacFarlane +Dave Pifke Dave Russell David Anderson David Barnett @@ -593,6 +637,7 @@ David McLeish David Ndungu David NewHamlet David Presotto +David Qu David R. Jenni David Sansome David Stainton @@ -642,6 +687,7 @@ Diwaker Gupta Dmitri Goutnik Dmitri Popov Dmitri Shuralyov +Dmitrii Okunev Dmitriy Cherchenko Dmitriy Dudkin Dmitriy Shelenin @@ -655,6 +701,7 @@ Dmitry Yakunin Doga Fincan Domas Tamašauskas Domen Ipavec +Dominic Della Valle Dominic Green Dominik Honnef Dominik Vogt @@ -696,6 +743,7 @@ Elias Naur Elliot Morrison-Reed Ellison Leão Emerson Lin +Emil Bektimirov Emil Hessman Emil Mursalimov Emilien Kenler @@ -760,6 +808,7 @@ Fatih Arslan Fazal Majid Fazlul Shahriar Federico Bond +Federico Guerinoni Federico Simoncelli Fedor Indutny Fedor Korotkiy @@ -781,6 +830,7 @@ Florin Patan Folke Behrens Ford Hurley Francesc Campoy +Francesco Guardiani Francesco Renzi Francisco Claude Francisco Rojas @@ -811,8 +861,10 @@ Gabriel Russell Gareth Paul Jones Garret Kelly Garrick Evans +Garry McNulty Gary Burd Gary Elliott +Gaurav Singh Gaurish Sharma Gautham Thambidorai Gauthier Jolly @@ -827,6 +879,7 @@ Georg Reinke George Gkirtsou George Hartzell George Shammas +George Tsilias Gerasimos (Makis) Maropoulos Gerasimos Dimitriadis Gergely Brautigam @@ -862,6 +915,7 @@ GitHub User @frennkie (6499251) GitHub User @geedchin (11672310) GitHub User @GrigoriyMikhalkin (3637857) GitHub User @hengwu0 (41297446) <41297446+hengwu0@users.noreply.github.com> +GitHub User @hitzhangjie (3725760) GitHub User @itchyny (375258) GitHub User @jinmiaoluo (39730824) GitHub User @jopbrown (6345470) @@ -873,6 +927,7 @@ GitHub User @LotusFenn (13775899) GitHub User @ly303550688 (11519839) GitHub User @madiganz (18340029) GitHub User @maltalex (10195391) +GitHub User @markruler (38225900) GitHub User @Matts966 (28551465) GitHub User @micnncim (21333876) GitHub User @mkishere (224617) <224617+mkishere@users.noreply.github.com> @@ -886,6 +941,8 @@ GitHub User @ramenjuniti (32011829) GitHub User @saitarunreddy (21041941) GitHub User @shogo-ma (9860598) GitHub User @skanehira (7888591) +GitHub User @soolaugust (10558124) +GitHub User @surechen (7249331) GitHub User @tatsumack (4510569) GitHub User @tell-k (26263) GitHub User @tennashi (10219626) @@ -908,6 +965,7 @@ Gordon Tyler Graham King Graham Miller Grant Griffiths +Green Lightning Greg Poirier Greg Steuck Greg Thelen @@ -920,6 +978,7 @@ Guilherme Garnier Guilherme Goncalves Guilherme Rezende Guillaume J. Charmes +Guillaume Sottas Günther Noack Guobiao Mei Guoliang Wang @@ -936,6 +995,8 @@ HAMANO Tsukasa Han-Wen Nienhuys Hang Qian Hanjun Kim +Hanlin Shi +Haoran Luo Haosdent Huang Harald Nordgren Hari haran @@ -950,9 +1011,11 @@ Håvard Haugen He Liu Hector Chu Hector Martin Cantero +Hein Khant Zaw Henning Schmiedehausen Henrik Edwards Henrik Hodne +Henrique Vicente Henry Adi Sumarto Henry Bubert Henry Chang @@ -969,6 +1032,7 @@ Hironao OTSUBO Hiroshi Ioka Hitoshi Mitake Holden Huang +Songlin Jiang Hong Ruiqi Hongfei Tan Horacio Duran @@ -990,6 +1054,7 @@ Ian Haken Ian Kent Ian Lance Taylor Ian Leue +Ian Tay Ian Zapolsky Ibrahim AshShohail Icarus Sparry @@ -997,9 +1062,11 @@ Iccha Sethi Idora Shinatose Ignacio Hagopian Igor Bernstein +Igor Bolotnikov Igor Dolzhikov Igor Vashyst Igor Zhilianin +Ikko Ashimine Illya Yalovyy Ilya Sinelnikov Ilya Tocar @@ -1037,6 +1104,7 @@ Jacob Blain Christen Jacob H. Haven Jacob Hoffman-Andrews Jacob Walker +Jaden Teng Jae Kwon Jake B Jakob Borg @@ -1044,6 +1112,7 @@ Jakob Weisblat Jakub Čajka Jakub Kaczmarzyk Jakub Ryszard Czarnowicz +Jakub Warczarek Jamal Carvalho James Aguilar James Bardin @@ -1056,9 +1125,11 @@ James Eady James Fysh James Gray James Hartig +James Kasten James Lawrence James Meneghello James Myers +James Naftel James Neve James Nugent James P. Cooper @@ -1108,6 +1179,7 @@ Javier Kohen Javier Revillas Javier Segura Jay Conrod +Jay Lee Jay Taylor Jay Weisskopf Jean de Klerk @@ -1140,14 +1212,17 @@ Jeremy Jay Jeremy Schlatter Jeroen Bobbeldijk Jeroen Simonetti +Jérôme Doucet Jerrin Shaji George Jess Frazelle Jesse Szwedko Jesús Espino Jia Zhan Jiacai Liu +Jiahao Lu Jianing Yu Jianqiao Li +Jiayu Yi Jie Ma Jihyun Yu Jim Cote @@ -1183,6 +1258,7 @@ Joey Geiger Johan Brandhorst Johan Euphrosine Johan Jansson +Johan Knutzen Johan Sageryd John Asmuth John Beisley @@ -1210,6 +1286,7 @@ Johnny Luo Jon Chen Jon Johnson Jonas Bernoulli +Jonathan Albrecht Jonathan Allie Jonathan Amsterdam Jonathan Boulle @@ -1223,6 +1300,7 @@ Jonathan Pentecost Jonathan Pittman Jonathan Rudenberg Jonathan Stacks +Jonathan Swinney Jonathan Wills Jonathon Lacher Jongmin Kim @@ -1233,6 +1311,7 @@ Jordan Krage Jordan Lewis Jordan Liggitt Jordan Rhee +Jordan Rupprecht Jordi Martin Jorge Araya Jorge L. Fatta @@ -1276,6 +1355,7 @@ Julien Salleyron Julien Schmidt Julio Montes Jun Zhang +Junchen Li Junda Liu Jungho Ahn Junya Hayashi @@ -1287,6 +1367,7 @@ Justin Nuß Justyn Temme Kai Backman Kai Dong +Kai Lüke Kai Trukenmüller Kale Blankenship Kaleb Elwert @@ -1314,6 +1395,7 @@ Kazuhiro Sera KB Sriram Keegan Carruthers-Smith Kei Son +Keiichi Hirobe Keiji Yoshida Keisuke Kishimoto Keith Ball @@ -1322,6 +1404,7 @@ Keith Rarick Kelly Heller Kelsey Hightower Kelvin Foo Chuan Lyi +Kemal Elmizan Ken Friedenbach Ken Rockot Ken Sedgwick @@ -1331,6 +1414,7 @@ Kenji Kaneda Kenji Yano Kenneth Shaw Kenny Grant +Kensei Nakada Kenta Mori Kerollos Magdy Ketan Parmar @@ -1342,10 +1426,12 @@ Kevin Gillette Kevin Kirsche Kevin Klues Kevin Malachowski +Kevin Parsons Kevin Ruffin Kevin Vu Kevin Zita Keyan Pishdadian +Keyuan Li Kezhu Wang Khosrow Moossavi Kieran Colford @@ -1358,6 +1444,7 @@ Kirill Smelkov Kirill Tatchihin Kirk Han Kirklin McDonald +KJ Tsanaktsidis Klaus Post Kodie Goodwin Koichi Shiraishi @@ -1371,6 +1458,7 @@ Kris Kwiatkowski Kris Nova Kris Rousey Kristopher Watts +Krzysztof Dąbrowski Kshitij Saraogi Kun Li Kunpei Sakai @@ -1412,8 +1500,10 @@ Leonardo Comelli Leonel Quinteros Lev Shamardin Lewin Bormann +Lewis Waddicor Liam Haworth Lily Chung +Lingchao Xin Lion Yang Liz Rice Lloyd Dewolf @@ -1427,6 +1517,7 @@ Luan Santos Lubomir I. Ivanov Luca Bruno Luca Greco +Luca Spiller Lucas Bremgartner Lucas Clemente Lucien Stuker @@ -1450,6 +1541,8 @@ Maarten Bezemer Maciej Dębski Madhu Rajanna Magnus Hiie +Mahdi Hosseini Moghaddam +Maia Lee Maicon Costa Mak Kolybabi Maksym Trykur @@ -1470,6 +1563,7 @@ Marcel Edmund Franke Marcel van Lohuizen Marcelo Cantos Marcelo E. Magallon +Marco Gazerro Marco Hennings Marcus Weiner Marcus Willock @@ -1481,6 +1575,7 @@ Marius A. Eriksen Marius Nuennerich Mark Adams Mark Bucciarelli +Mark Dain Mark Glines Mark Harrison Mark Percival @@ -1533,6 +1628,7 @@ Máté Gulyás Matej Baćo Mateus Amin Mateusz Czapliński +Matheus Alcantara Mathias Beke Mathias Hall-Andersen Mathias Leppich @@ -1566,6 +1662,7 @@ Matthew Waters Matthieu Hauglustaine Matthieu Olivier Matthijs Kooijman +Max Drosdo.www Max Riveiro Max Schmitt Max Semenik @@ -1603,6 +1700,7 @@ Michael Hudson-Doyle Michael Kasch Michael Käufl Michael Kelly +Michaël Lévesque-Dion Michael Lewis Michael MacInnis Michael Marineau @@ -1624,6 +1722,7 @@ Michael Teichgräber Michael Traver Michael Vetter Michael Vogt +Michail Kargakis Michal Bohuslávek Michal Cierniak Michał Derkacz @@ -1633,6 +1732,7 @@ Michal Pristas Michal Rostecki Michalis Kargakis Michel Lespinasse +Michele Di Pede Mickael Kerjean Mickey Reiss Miek Gieben @@ -1670,6 +1770,7 @@ Miquel Sabaté Solà Mirko Hansen Miroslav Genov Misty De Meo +Mohamed Attahri Mohit Agarwal Mohit kumar Bajoria Mohit Verma @@ -1683,6 +1784,7 @@ Môshe van der Sterre Mostyn Bramley-Moore Mrunal Patel Muhammad Falak R Wani +Muhammad Hamza Farrukh Muhammed Uluyol Muir Manders Mukesh Sharma @@ -1692,6 +1794,7 @@ Naman Aggarwal Nan Deng Nao Yonashiro Naoki Kanatani +Natanael Copa Nate Wilkinson Nathan Cantelmo Nathan Caza @@ -1708,6 +1811,7 @@ Nathaniel Cook Naveen Kumar Sangi Neeilan Selvalingam Neelesh Chandola +Nehal J Wani Neil Lyons Neuman Vong Neven Sajko @@ -1760,6 +1864,7 @@ Noel Georgi Norberto Lopes Norman B. Lancaster Nuno Cruces +Obei Sideg Obeyda Djeffal Odin Ugedal Oleg Bulatov @@ -1769,12 +1874,17 @@ Oling Cat Oliver Hookins Oliver Powell Oliver Stenbom +Oliver Tan Oliver Tonnhofer Olivier Antoine Olivier Duperray Olivier Poitrey Olivier Saingre +Olivier Wulveryck Omar Jarjur +Onkar Jadhav +Ori Bernstein +Ori Rawlings Oryan Moshe Osamu TONOMORI Özgür Kesim @@ -1798,7 +1908,9 @@ Pat Moroney Patrick Barker Patrick Crosby Patrick Gavlin +Patrick Gundlach Patrick Higgins +Patrick Jones Patrick Lee Patrick Mézard Patrick Mylund Nielsen @@ -1811,6 +1923,9 @@ Paul Borman Paul Boyd Paul Chang Paul D. Weber +Paul Davis <43160081+Pawls@users.noreply.github.com> +Paul E. Murphy +Paul Forgey Paul Hammond Paul Hankin Paul Jolly @@ -1836,7 +1951,9 @@ Pavel Zinovkin Pavlo Sumkin Pawel Knap Pawel Szczur +Paweł Szulik Pei Xian Chee +Pei-Ming Wu Percy Wegmann Perry Abbott Petar Dambovaliev @@ -1876,6 +1993,7 @@ Philip Hofer Philip K. Warren Philip Nelson Philipp Stephani +Phillip Campbell <15082+phillc@users.noreply.github.com> Pierre Carru Pierre Durand Pierre Prinetti @@ -1885,6 +2003,7 @@ Pieter Droogendijk Pietro Gagliardi Piyush Mishra Plekhanov Maxim +Poh Zi How Polina Osadcha Pontus Leitzler Povilas Versockas @@ -1904,14 +2023,17 @@ Quentin Perez Quentin Renard Quentin Smith Quey-Liang Kao +Quim Muntal Quinn Slack Quinten Yearsley Quoc-Viet Nguyen +Radek Simko Radek Sohlich Radu Berinde Rafal Jeczalik Raghavendra Nagaraj Rahul Chaudhry +Rahul Wadhwani Raif S. Naffah Rajat Goel Rajath Agasthya @@ -1935,6 +2057,7 @@ Ren Ogaki Rens Rikkerink Rhys Hiltner Ricardo Padilha +Ricardo Pchevuzinske Katz Ricardo Seriani Richard Barnes Richard Crowley @@ -1991,6 +2114,7 @@ Roman Kollár Roman Shchekin Ron Hashimoto Ron Minnich +Ronnie Ebrin Ross Chater Ross Kinsey Ross Light @@ -2010,6 +2134,7 @@ Ryan Brown Ryan Canty Ryan Dahl Ryan Hitchman +Ryan Kohler Ryan Lower Ryan Roden-Corrent Ryan Seys @@ -2023,7 +2148,9 @@ S.Çağlar Onur Sabin Mihai Rapan Sad Pencil Sai Cheemalapati +Sai Kiran Dasika Sakeven Jiang +Salaheddin M. Mahmud Salmān Aljammāz Sam Arnold Sam Boyer @@ -2033,6 +2160,7 @@ Sam Ding Sam Hug Sam Thorogood Sam Whited +Sam Xie Sameer Ajmani Sami Commerot Sami Pönkänen @@ -2042,6 +2170,7 @@ Samuele Pedroni Sander van Harmelen Sanjay Menakuru Santhosh Kumar Tekuri +Santiago De la Cruz <51337247+xhit@users.noreply.github.com> Sarah Adams Sardorbek Pulatov Sascha Brawer @@ -2062,6 +2191,7 @@ Sean Chittenden Sean Christopherson Sean Dolphin Sean Harger +Sean Hildebrand Sean Liao Sean Rees Sebastiaan van Stijn @@ -2094,10 +2224,12 @@ Serhii Aheienko Seth Hoenig Seth Vargo Shahar Kohanim +Shailesh Suryawanshi Shamil Garatuev Shane Hansen Shang Jian Ding Shaozhen Ding +Shaquille Que Shaquille Wyan Que Shaun Dunning Shawn Elliott @@ -2108,8 +2240,11 @@ Shenghou Ma Shengjing Zhu Shengyu Zhang Shi Han Ng +ShihCheng Tu Shijie Hao +Shin Fan Shinji Tanaka +Shinnosuke Sawada <6warashi9@gmail.com> Shintaro Kaneko Shivakumar GN Shivani Singhal @@ -2121,17 +2256,21 @@ Silvan Jegen Simarpreet Singh Simon Drake Simon Ferquel +Simon Frei Simon Jefford Simon Rawet Simon Rozman +Simon Ser Simon Thulbourn Simon Whitehead Sina Siadat Sjoerd Siebinga Sokolov Yura Song Gao +Songjiayang Soojin Nam Søren L. Hansen +Sparrow Li Spencer Kocot Spencer Nelson Spencer Tung @@ -2140,12 +2279,14 @@ Srdjan Petrovic Sridhar Venkatakrishnan Srinidhi Kaushik StalkR +Stan Hu Stan Schwertly Stanislav Afanasev Steeve Morin Stefan Baebler Stefan Nilsson Stepan Shabalin +Stephan Klatt Stephan Renatus Stephan Zuercher Stéphane Travostino @@ -2163,13 +2304,16 @@ Steve Mynott Steve Newman Steve Phillips Steve Streeting +Steve Traut Steven Buss Steven Elliot Harris Steven Erenst Steven Hartland Steven Littiebrant +Steven Maude Steven Wilkin Stuart Jansen +Subham Sarkar Sue Spence Sugu Sougoumarane Suharsh Sivakumar @@ -2193,6 +2337,7 @@ Taesu Pyo Tai Le Taj Khattra Takashi Matsuo +Takashi Mima Takayoshi Nishida Takeshi YAMANASHI <9.nashi@gmail.com> Takuto Ikuta @@ -2221,6 +2366,7 @@ Thanatat Tamtan The Hatsune Daishi Thiago Avelino Thiago Fransosi Farina +Thom Wiggers Thomas Alan Copeland Thomas Bonfort Thomas Bouldin @@ -2245,6 +2391,7 @@ Tim Ebringer Tim Heckman Tim Henderson Tim Hockin +Tim King Tim Möhlmann Tim Swast Tim Wright @@ -2252,8 +2399,10 @@ Tim Xu Timmy Douglas Timo Savola Timo Truyts +Timothy Gu Timothy Studd Tipp Moseley +Tiwei Bie Tobias Assarsson Tobias Columbus Tobias Klauser @@ -2268,11 +2417,13 @@ Tom Lanyon Tom Levy Tom Limoncelli Tom Linford +Tom Panton Tom Parkin Tom Payne Tom Szymanski Tom Thorogood Tom Wilkie +Tom Zierbock Tomas Dabasinskas Tommy Schaefer Tomohiro Kusumoto @@ -2298,6 +2449,7 @@ Tristan Colgate Tristan Ooohry Tristan Rice Troels Thomsen +Trong Bui Trung Nguyen Tsuji Daishiro Tudor Golubenco @@ -2308,6 +2460,7 @@ Tyler Bunnell Tyler Treat Tyson Andre Tzach Shabtay +Tzu-Chiao Yeh Tzu-Jung Lee Udalov Max Ugorji Nwoke @@ -2316,6 +2469,7 @@ Ulrich Kunitz Umang Parmar Uriel Mangado Urvil Patel +Utkarsh Dixit <53217283+utkarsh-extc@users.noreply.github.com> Uttam C Pawar Vadim Grek Vadim Vygonets @@ -2327,6 +2481,7 @@ Venil Noronha Veselkov Konstantin Viacheslav Poturaev Victor Chudnovsky +Victor Michel Victor Vrantchan Vignesh Ramachandra Vikas Kedia @@ -2341,6 +2496,7 @@ Visweswara R Vitaly Zdanevich Vitor De Mario Vivek Sekhar +Vivek V Vivian Liang Vlad Krasnov Vladimir Evgrafov @@ -2392,6 +2548,7 @@ Wu Yunzhou Xi Ruoyao Xia Bin Xiangdong Ji +Xiaodong Liu Xing Xing Xingqang Bai Xu Fei @@ -2459,6 +2616,7 @@ Zhou Peng Ziad Hatahet Ziheng Liu Zorion Arrizabalaga +Zyad A. Ali Максадбек Ахмедов Максим Федосеев Роман Хавроненко From ff0e93ea313e53f08018b90bada2edee267a8f55 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 11 Feb 2021 16:24:26 -0500 Subject: [PATCH 20/47] doc/go1.16: note that package path elements beginning with '.' are disallowed For #43985 Change-Id: I1a16f66800c5c648703f0a0d2ad75024525a710f Reviewed-on: https://go-review.googlesource.com/c/go/+/291389 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- doc/go1.16.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/go1.16.html b/doc/go1.16.html index f6f72c3882..d5de0ee5ce 100644 --- a/doc/go1.16.html +++ b/doc/go1.16.html @@ -174,10 +174,12 @@ Do not send CLs removing the interior tags from such phrases. non-reproducible builds.

-

- The go command now disallows non-ASCII import paths in module - mode. Non-ASCII module paths have already been disallowed so this change - affects module subdirectory paths that contain non-ASCII characters. +

+ In module mode, the go command now disallows import paths that + include non-ASCII characters or path elements with a leading dot character + (.). Module paths with these characters were already disallowed + (see Module paths and versions), + so this change affects only paths within module subdirectories.

Embedding Files

From baa6c75dcef23aa51e95bf7818b7ded5262fbaa8 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Thu, 22 Oct 2020 16:02:14 +0000 Subject: [PATCH 21/47] [dev.regabi] internal/abi: add new internal/abi package for ABI constants This change creates a new internal std package internal/abi which is intended to hold constants with platform-specific values related to our ABI that is useful to different std packages, such as runtime and reflect. For #40724. Change-Id: Ie7ae7f687629cd3d613ba603e9371f0887601fe6 Reviewed-on: https://go-review.googlesource.com/c/go/+/272567 Trust: Michael Knyszek Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Reviewed-by: David Chase Reviewed-by: Than McIntosh Reviewed-by: Austin Clements --- src/go/build/deps_test.go | 4 ++-- src/internal/abi/abi.go | 12 +++++++++++ src/internal/abi/abi_amd64.go | 20 +++++++++++++++++ src/internal/abi/abi_generic.go | 38 +++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 src/internal/abi/abi.go create mode 100644 src/internal/abi/abi_amd64.go create mode 100644 src/internal/abi/abi_generic.go diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index c97c668cc4..02b29f498a 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -71,13 +71,13 @@ var depsRules = ` # No dependencies allowed for any of these packages. NONE < container/list, container/ring, - internal/cfg, internal/cpu, + internal/abi, internal/cfg, internal/cpu, internal/goversion, internal/nettrace, unicode/utf8, unicode/utf16, unicode, unsafe; # RUNTIME is the core runtime group of packages, all of them very light-weight. - internal/cpu, unsafe + internal/abi, internal/cpu, unsafe < internal/bytealg < internal/unsafeheader < runtime/internal/sys diff --git a/src/internal/abi/abi.go b/src/internal/abi/abi.go new file mode 100644 index 0000000000..07ea51df8f --- /dev/null +++ b/src/internal/abi/abi.go @@ -0,0 +1,12 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package abi + +// RegArgs is a struct that has space for each argument +// and return value register on the current architecture. +type RegArgs struct { + Ints [IntArgRegs]uintptr + Floats [FloatArgRegs]uint64 +} diff --git a/src/internal/abi/abi_amd64.go b/src/internal/abi/abi_amd64.go new file mode 100644 index 0000000000..6574d4216d --- /dev/null +++ b/src/internal/abi/abi_amd64.go @@ -0,0 +1,20 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build goexperiment.regabi + +package abi + +const ( + // See abi_generic.go. + + // RAX, RBX, RCX, RDI, RSI, R8, R9, R10, R11. + IntArgRegs = 9 + + // X0 -> X14. + FloatArgRegs = 15 + + // We use SSE2 registers which support 64-bit float operations. + EffectiveFloatRegSize = 8 +) diff --git a/src/internal/abi/abi_generic.go b/src/internal/abi/abi_generic.go new file mode 100644 index 0000000000..5ef9883dc6 --- /dev/null +++ b/src/internal/abi/abi_generic.go @@ -0,0 +1,38 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !goexperiment.regabi + +package abi + +const ( + // ABI-related constants. + // + // In the generic case, these are all zero + // which lets them gracefully degrade to ABI0. + + // IntArgRegs is the number of registers dedicated + // to passing integer argument values. Result registers are identical + // to argument registers, so this number is used for those too. + IntArgRegs = 0 + + // FloatArgRegs is the number of registers dedicated + // to passing floating-point argument values. Result registers are + // identical to argument registers, so this number is used for + // those too. + FloatArgRegs = 0 + + // EffectiveFloatRegSize describes the width of floating point + // registers on the current platform from the ABI's perspective. + // + // Since Go only supports 32-bit and 64-bit floating point primitives, + // this number should be either 0, 4, or 8. 0 indicates no floating + // point registers for the ABI or that floating point values will be + // passed via the softfloat ABI. + // + // For platforms that support larger floating point register widths, + // such as x87's 80-bit "registers" (not that we support x87 currently), + // use 8. + EffectiveFloatRegSize = 0 +) From 060fa49bd23d758a9062f4cb50e65960ec9662f1 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 10 Feb 2021 12:04:31 -0500 Subject: [PATCH 22/47] [dev.regabi] go/types: refuse excessively long constants This is a port of CL 289049 to go/types. In that CL, tests were written using the ability of tests/run.go to generate test packages dynamically. For this CL, similar functionality is added to the go/types errmap tests: tests are refactored to decouple the loading of source code from the filesystem, so that tests for long constants may be generated dynamically rather than checked-in as a large testdata file. Change-Id: I92c7cb61a8d42c6593570ef7ae0af86b501fa34e Reviewed-on: https://go-review.googlesource.com/c/go/+/290949 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/check_test.go | 74 ++++++++++++++++++++++---------------- src/go/types/expr.go | 17 +++++++++ 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index 47d749b3a3..7292f7bcb2 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -68,11 +68,11 @@ func splitError(err error) (pos, msg string) { return } -func parseFiles(t *testing.T, filenames []string) ([]*ast.File, []error) { +func parseFiles(t *testing.T, filenames []string, srcs [][]byte) ([]*ast.File, []error) { var files []*ast.File var errlist []error - for _, filename := range filenames { - file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors) + for i, filename := range filenames { + file, err := parser.ParseFile(fset, filename, srcs[i], parser.AllErrors) if file == nil { t.Fatalf("%s: %s", filename, err) } @@ -101,19 +101,17 @@ var errRx = regexp.MustCompile(`^ *ERROR *(HERE)? *"?([^"]*)"?`) // errMap collects the regular expressions of ERROR comments found // in files and returns them as a map of error positions to error messages. // -func errMap(t *testing.T, testname string, files []*ast.File) map[string][]string { +// srcs must be a slice of the same length as files, containing the original +// source for the parsed AST. +func errMap(t *testing.T, files []*ast.File, srcs [][]byte) map[string][]string { // map of position strings to lists of error message patterns errmap := make(map[string][]string) - for _, file := range files { - filename := fset.Position(file.Package).Filename - src, err := os.ReadFile(filename) - if err != nil { - t.Fatalf("%s: could not read %s", testname, filename) - } - + for i, file := range files { + tok := fset.File(file.Package) + src := srcs[i] var s scanner.Scanner - s.Init(fset.AddFile(filename, -1, len(src)), src, nil, scanner.ScanComments) + s.Init(tok, src, nil, scanner.ScanComments) var prev token.Pos // position of last non-comment, non-semicolon token var here token.Pos // position immediately after the token at position prev @@ -190,13 +188,13 @@ func eliminate(t *testing.T, errmap map[string][]string, errlist []error) { } } -func checkFiles(t *testing.T, sources []string) { - if len(sources) == 0 { +func checkFiles(t *testing.T, filenames []string, srcs [][]byte) { + if len(filenames) == 0 { t.Fatal("no source files") } // parse files and collect parser errors - files, errlist := parseFiles(t, sources) + files, errlist := parseFiles(t, filenames, srcs) pkgName := "" if len(files) > 0 { @@ -214,11 +212,12 @@ func checkFiles(t *testing.T, sources []string) { var conf Config // special case for importC.src - if len(sources) == 1 && strings.HasSuffix(sources[0], "importC.src") { - conf.FakeImportC = true + if len(filenames) == 1 { + if strings.HasSuffix(filenames[0], "importC.src") { + conf.FakeImportC = true + } } - // TODO(rFindley) we may need to use the source importer when adding generics - // tests. + conf.Importer = importer.Default() conf.Error = func(err error) { if *haltOnError { @@ -253,7 +252,7 @@ func checkFiles(t *testing.T, sources []string) { // match and eliminate errors; // we are expecting the following errors - errmap := errMap(t, pkgName, files) + errmap := errMap(t, files, srcs) eliminate(t, errmap, errlist) // there should be no expected errors left @@ -274,7 +273,13 @@ func TestCheck(t *testing.T) { } testenv.MustHaveGoBuild(t) DefPredeclaredTestFuncs() - checkFiles(t, strings.Split(*testFiles, " ")) + testPkg(t, strings.Split(*testFiles, " ")) +} + +func TestLongConstants(t *testing.T) { + format := "package longconst\n\nconst _ = %s\nconst _ = %s // ERROR excessively long constant" + src := fmt.Sprintf(format, strings.Repeat("1", 9999), strings.Repeat("1", 10001)) + checkFiles(t, []string{"longconst.go"}, [][]byte{[]byte(src)}) } func TestTestdata(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, "testdata") } @@ -293,26 +298,33 @@ func testDir(t *testing.T, dir string) { path := filepath.Join(dir, fi.Name()) // if fi is a directory, its files make up a single package - var files []string + var filenames []string if fi.IsDir() { fis, err := ioutil.ReadDir(path) if err != nil { t.Error(err) continue } - files = make([]string, len(fis)) - for i, fi := range fis { - // if fi is a directory, checkFiles below will complain - files[i] = filepath.Join(path, fi.Name()) - if testing.Verbose() { - fmt.Printf("\t%s\n", files[i]) - } + for _, fi := range fis { + filenames = append(filenames, filepath.Join(path, fi.Name())) } } else { - files = []string{path} + filenames = []string{path} } t.Run(filepath.Base(path), func(t *testing.T) { - checkFiles(t, files) + testPkg(t, filenames) }) } } + +func testPkg(t *testing.T, filenames []string) { + srcs := make([][]byte, len(filenames)) + for i, filename := range filenames { + src, err := os.ReadFile(filename) + if err != nil { + t.Fatalf("could not read %s: %v", filename, err) + } + srcs[i] = src + } + checkFiles(t, filenames, srcs) +} diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 5e1fe28a43..1a3c486af7 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -1140,6 +1140,23 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { goto Error case *ast.BasicLit: + switch e.Kind { + case token.INT, token.FLOAT, token.IMAG: + // The max. mantissa precision for untyped numeric values + // is 512 bits, or 4048 bits for each of the two integer + // parts of a fraction for floating-point numbers that are + // represented accurately in the go/constant package. + // Constant literals that are longer than this many bits + // are not meaningful; and excessively long constants may + // consume a lot of space and time for a useless conversion. + // Cap constant length with a generous upper limit that also + // allows for separators between all digits. + const limit = 10000 + if len(e.Value) > limit { + check.errorf(e, _InvalidConstVal, "excessively long constant: %s... (%d chars)", e.Value[:10], len(e.Value)) + goto Error + } + } x.setConst(e.Kind, e.Value) if x.mode == invalid { // The parser already establishes syntactic correctness. From a7e9b4b94804a1fbefc0c012ec510f4ee0837ffa Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 11 Feb 2021 10:17:39 -0500 Subject: [PATCH 23/47] [dev.regabi] go/types: untyped shift counts must fit into uint This is a port of CL 283872 to go/types. It differs from that CL only in added error codes. For #43697 Change-Id: I62277834cef1c0359bcf2c6ee4388731babbc855 Reviewed-on: https://go-review.googlesource.com/c/go/+/291316 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/expr.go | 26 ++++++++++++++++++-------- src/go/types/testdata/shifts.src | 12 +++++++----- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 1a3c486af7..7f8aaed411 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -730,14 +730,14 @@ func (check *Checker) comparison(x, y *operand, op token.Token) { // If e != nil, it must be the shift expression; it may be nil for non-constant shifts. func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) { - untypedx := isUntyped(x.typ) + // TODO(gri) This function seems overly complex. Revisit. var xval constant.Value if x.mode == constant_ { xval = constant.ToInt(x.val) } - if isInteger(x.typ) || untypedx && xval != nil && xval.Kind() == constant.Int { + if isInteger(x.typ) || isUntyped(x.typ) && xval != nil && xval.Kind() == constant.Int { // The lhs is of integer type or an untyped constant representable // as an integer. Nothing to do. } else { @@ -749,16 +749,26 @@ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) { // spec: "The right operand in a shift expression must have integer type // or be an untyped constant representable by a value of type uint." - switch { - case isInteger(y.typ): - // nothing to do - case isUntyped(y.typ): + + // Provide a good error message for negative shift counts. + if y.mode == constant_ { + yval := constant.ToInt(y.val) // consider -1, 1.0, but not -1.1 + if yval.Kind() == constant.Int && constant.Sign(yval) < 0 { + check.invalidOp(y, _InvalidShiftCount, "negative shift count %s", y) + x.mode = invalid + return + } + } + + // Caution: Check for isUntyped first because isInteger includes untyped + // integers (was bug #43697). + if isUntyped(y.typ) { check.convertUntyped(y, Typ[Uint]) if y.mode == invalid { x.mode = invalid return } - default: + } else if !isInteger(y.typ) { check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", y) x.mode = invalid return @@ -816,7 +826,7 @@ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) { } // non-constant shift with constant lhs - if untypedx { + if isUntyped(x.typ) { // spec: "If the left operand of a non-constant shift // expression is an untyped constant, the type of the // constant is what it would be if the shift expression diff --git a/src/go/types/testdata/shifts.src b/src/go/types/testdata/shifts.src index c9a38ae169..4d3c59a50f 100644 --- a/src/go/types/testdata/shifts.src +++ b/src/go/types/testdata/shifts.src @@ -20,7 +20,7 @@ func shifts0() { // This depends on the exact spec wording which is not // done yet. // TODO(gri) revisit and adjust when spec change is done - _ = 1<<- /* ERROR "truncated to uint" */ 1.0 + _ = 1<<- /* ERROR "negative shift count" */ 1.0 _ = 1<<1075 /* ERROR "invalid shift" */ _ = 2.0<<1 _ = 1<<1.0 @@ -60,11 +60,13 @@ func shifts1() { _ uint = 1 << u _ float32 = 1 /* ERROR "must be integer" */ << u - // for issue 14822 + // issue #14822 + _ = 1<<( /* ERROR "overflows uint" */ 1<<64) _ = 1<<( /* ERROR "invalid shift count" */ 1<<64-1) - _ = 1<<( /* ERROR "invalid shift count" */ 1<<64) - _ = u<<(1<<63) // valid - _ = u<<(1<<64) // valid + + // issue #43697 + _ = u<<( /* ERROR "overflows uint" */ 1<<64) + _ = u<<(1<<64-1) ) } From b81efb7ec4348951211058cf4fdfc045c75255d6 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 11 Feb 2021 10:23:41 -0500 Subject: [PATCH 24/47] [dev.regabi] go/types: add support for language version checking This is a port of CL 289509 to go/types. It differs from that CL in codes added to errors, to fit the new factoring of check_test.go, and to allow go/types to import regexp in deps_test.go For #31793 Change-Id: Ia9e4c7f5aac1493001189184227c2ebc79a76e77 Reviewed-on: https://go-review.googlesource.com/c/go/+/291317 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/build/deps_test.go | 2 +- src/go/types/api.go | 7 +++ src/go/types/check.go | 32 ++++++++----- src/go/types/check_test.go | 36 +++++++++++--- src/go/types/expr.go | 5 ++ src/go/types/stdlib_test.go | 10 ++-- src/go/types/testdata/go1_12.src | 35 ++++++++++++++ src/go/types/version.go | 82 ++++++++++++++++++++++++++++++++ 8 files changed, 186 insertions(+), 23 deletions(-) create mode 100644 src/go/types/testdata/go1_12.src create mode 100644 src/go/types/version.go diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 02b29f498a..3fea5ecf0d 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -285,7 +285,7 @@ var depsRules = ` math/big, go/token < go/constant; - container/heap, go/constant, go/parser + container/heap, go/constant, go/parser, regexp < go/types; FMT diff --git a/src/go/types/api.go b/src/go/types/api.go index d625959817..b5bbb2d97d 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -101,6 +101,13 @@ type ImporterFrom interface { // A Config specifies the configuration for type checking. // The zero value for Config is a ready-to-use default configuration. type Config struct { + // GoVersion describes the accepted Go language version. The string + // must follow the format "go%d.%d" (e.g. "go1.12") or it must be + // empty; an empty string indicates the latest language version. + // If the format is invalid, invoking the type checker will cause a + // panic. + GoVersion string + // If IgnoreFuncBodies is set, function bodies are not // type-checked. IgnoreFuncBodies bool diff --git a/src/go/types/check.go b/src/go/types/check.go index 03798587e7..3bc8ee067c 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -8,6 +8,7 @@ package types import ( "errors" + "fmt" "go/ast" "go/constant" "go/token" @@ -84,10 +85,11 @@ type Checker struct { fset *token.FileSet pkg *Package *Info - objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info - impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package - posMap map[*Interface][]token.Pos // maps interface types to lists of embedded interface positions - pkgCnt map[string]int // counts number of imported packages with a given name (for better error messages) + version version // accepted language version + objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info + impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package + posMap map[*Interface][]token.Pos // maps interface types to lists of embedded interface positions + pkgCnt map[string]int // counts number of imported packages with a given name (for better error messages) // information collected during type-checking of a set of package files // (initialized by Files, valid only for the duration of check.Files; @@ -176,15 +178,21 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch info = new(Info) } + version, err := parseGoVersion(conf.GoVersion) + if err != nil { + panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err)) + } + return &Checker{ - conf: conf, - fset: fset, - pkg: pkg, - Info: info, - objMap: make(map[Object]*declInfo), - impMap: make(map[importKey]*Package), - posMap: make(map[*Interface][]token.Pos), - pkgCnt: make(map[string]int), + conf: conf, + fset: fset, + pkg: pkg, + Info: info, + version: version, + objMap: make(map[Object]*declInfo), + impMap: make(map[importKey]*Package), + posMap: make(map[*Interface][]token.Pos), + pkgCnt: make(map[string]int), } } diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index 7292f7bcb2..ca7d926ca9 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -47,7 +47,8 @@ import ( var ( haltOnError = flag.Bool("halt", false, "halt on error") listErrors = flag.Bool("errlist", false, "list errors") - testFiles = flag.String("files", "", "space-separated list of test files") + testFiles = flag.String("files", "", "comma-separated list of test files") + goVersion = flag.String("lang", "", "Go language version (e.g. \"go1.12\"") ) var fset = token.NewFileSet() @@ -188,7 +189,21 @@ func eliminate(t *testing.T, errmap map[string][]string, errlist []error) { } } -func checkFiles(t *testing.T, filenames []string, srcs [][]byte) { +// goVersionRx matches a Go version string using '_', e.g. "go1_12". +var goVersionRx = regexp.MustCompile(`^go[1-9][0-9]*_(0|[1-9][0-9]*)$`) + +// asGoVersion returns a regular Go language version string +// if s is a Go version string using '_' rather than '.' to +// separate the major and minor version numbers (e.g. "go1_12"). +// Otherwise it returns the empty string. +func asGoVersion(s string) string { + if goVersionRx.MatchString(s) { + return strings.Replace(s, "_", ".", 1) + } + return "" +} + +func checkFiles(t *testing.T, goVersion string, filenames []string, srcs [][]byte) { if len(filenames) == 0 { t.Fatal("no source files") } @@ -201,6 +216,11 @@ func checkFiles(t *testing.T, filenames []string, srcs [][]byte) { pkgName = files[0].Name.Name } + // if no Go version is given, consider the package name + if goVersion == "" { + goVersion = asGoVersion(pkgName) + } + if *listErrors && len(errlist) > 0 { t.Errorf("--- %s:", pkgName) for _, err := range errlist { @@ -210,6 +230,7 @@ func checkFiles(t *testing.T, filenames []string, srcs [][]byte) { // typecheck and collect typechecker errors var conf Config + conf.GoVersion = goVersion // special case for importC.src if len(filenames) == 1 { @@ -267,19 +288,20 @@ func checkFiles(t *testing.T, filenames []string, srcs [][]byte) { } // TestCheck is for manual testing of selected input files, provided with -files. +// The accepted Go language version can be controlled with the -lang flag. func TestCheck(t *testing.T) { if *testFiles == "" { return } testenv.MustHaveGoBuild(t) DefPredeclaredTestFuncs() - testPkg(t, strings.Split(*testFiles, " ")) + testPkg(t, strings.Split(*testFiles, ","), *goVersion) } func TestLongConstants(t *testing.T) { format := "package longconst\n\nconst _ = %s\nconst _ = %s // ERROR excessively long constant" src := fmt.Sprintf(format, strings.Repeat("1", 9999), strings.Repeat("1", 10001)) - checkFiles(t, []string{"longconst.go"}, [][]byte{[]byte(src)}) + checkFiles(t, "", []string{"longconst.go"}, [][]byte{[]byte(src)}) } func TestTestdata(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, "testdata") } @@ -312,12 +334,12 @@ func testDir(t *testing.T, dir string) { filenames = []string{path} } t.Run(filepath.Base(path), func(t *testing.T) { - testPkg(t, filenames) + testPkg(t, filenames, "") }) } } -func testPkg(t *testing.T, filenames []string) { +func testPkg(t *testing.T, filenames []string, goVersion string) { srcs := make([][]byte, len(filenames)) for i, filename := range filenames { src, err := os.ReadFile(filename) @@ -326,5 +348,5 @@ func testPkg(t *testing.T, filenames []string) { } srcs[i] = src } - checkFiles(t, filenames, srcs) + checkFiles(t, goVersion, filenames, srcs) } diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 7f8aaed411..aec3172327 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -772,6 +772,10 @@ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) { check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", y) x.mode = invalid return + } else if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) { + check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y) + x.mode = invalid + return } var yval constant.Value @@ -1152,6 +1156,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { case *ast.BasicLit: switch e.Kind { case token.INT, token.FLOAT, token.IMAG: + check.langCompat(e) // The max. mantissa precision for untyped numeric values // is 512 bits, or 4048 bits for each of the two integer // parts of a fraction for floating-point numbers that are diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go index 71e14b85e5..979785de95 100644 --- a/src/go/types/stdlib_test.go +++ b/src/go/types/stdlib_test.go @@ -106,6 +106,7 @@ func testTestDir(t *testing.T, path string, ignore ...string) { // get per-file instructions expectErrors := false filename := filepath.Join(path, f.Name()) + goVersion := "" if comment := firstComment(filename); comment != "" { fields := strings.Fields(comment) switch fields[0] { @@ -115,13 +116,17 @@ func testTestDir(t *testing.T, path string, ignore ...string) { expectErrors = true for _, arg := range fields[1:] { if arg == "-0" || arg == "-+" || arg == "-std" { - // Marked explicitly as not expected errors (-0), + // Marked explicitly as not expecting errors (-0), // or marked as compiling runtime/stdlib, which is only done // to trigger runtime/stdlib-only error output. // In both cases, the code should typecheck. expectErrors = false break } + const prefix = "-lang=" + if strings.HasPrefix(arg, prefix) { + goVersion = arg[len(prefix):] + } } } } @@ -129,7 +134,7 @@ func testTestDir(t *testing.T, path string, ignore ...string) { // parse and type-check file file, err := parser.ParseFile(fset, filename, nil, 0) if err == nil { - conf := Config{Importer: stdLibImporter} + conf := Config{GoVersion: goVersion, Importer: stdLibImporter} _, err = conf.Check(filename, fset, []*ast.File{file}, nil) } @@ -180,7 +185,6 @@ func TestStdFixed(t *testing.T) { "issue22200b.go", // go/types does not have constraints on stack size "issue25507.go", // go/types does not have constraints on stack size "issue20780.go", // go/types does not have constraints on stack size - "issue31747.go", // go/types does not have constraints on language level (-lang=go1.12) (see #31793) "issue34329.go", // go/types does not have constraints on language level (-lang=go1.13) (see #31793) "bug251.go", // issue #34333 which was exposed with fix for #34151 "issue42058a.go", // go/types does not have constraints on channel element size diff --git a/src/go/types/testdata/go1_12.src b/src/go/types/testdata/go1_12.src new file mode 100644 index 0000000000..1e529f18be --- /dev/null +++ b/src/go/types/testdata/go1_12.src @@ -0,0 +1,35 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Check Go language version-specific errors. + +package go1_12 // go1.12 + +// numeric literals +const ( + _ = 1_000 // ERROR "underscores in numeric literals requires go1.13 or later" + _ = 0b111 // ERROR "binary literals requires go1.13 or later" + _ = 0o567 // ERROR "0o/0O-style octal literals requires go1.13 or later" + _ = 0xabc // ok + _ = 0x0p1 // ERROR "hexadecimal floating-point literals requires go1.13 or later" + + _ = 0B111 // ERROR "binary" + _ = 0O567 // ERROR "octal" + _ = 0Xabc // ok + _ = 0X0P1 // ERROR "hexadecimal floating-point" + + _ = 1_000i // ERROR "underscores" + _ = 0b111i // ERROR "binary" + _ = 0o567i // ERROR "octal" + _ = 0xabci // ERROR "hexadecimal floating-point" + _ = 0x0p1i // ERROR "hexadecimal floating-point" +) + +// signed shift counts +var ( + s int + _ = 1 << s // ERROR "invalid operation: signed shift count s \(variable of type int\) requires go1.13 or later" + _ = 1 >> s // ERROR "signed shift count" +) + diff --git a/src/go/types/version.go b/src/go/types/version.go new file mode 100644 index 0000000000..154694169b --- /dev/null +++ b/src/go/types/version.go @@ -0,0 +1,82 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types + +import ( + "fmt" + "go/ast" + "go/token" + "regexp" + "strconv" + "strings" +) + +// langCompat reports an error if the representation of a numeric +// literal is not compatible with the current language version. +func (check *Checker) langCompat(lit *ast.BasicLit) { + s := lit.Value + if len(s) <= 2 || check.allowVersion(check.pkg, 1, 13) { + return + } + // len(s) > 2 + if strings.Contains(s, "_") { + check.errorf(lit, _InvalidLit, "underscores in numeric literals requires go1.13 or later") + return + } + if s[0] != '0' { + return + } + radix := s[1] + if radix == 'b' || radix == 'B' { + check.errorf(lit, _InvalidLit, "binary literals requires go1.13 or later") + return + } + if radix == 'o' || radix == 'O' { + check.errorf(lit, _InvalidLit, "0o/0O-style octal literals requires go1.13 or later") + return + } + if lit.Kind != token.INT && (radix == 'x' || radix == 'X') { + check.errorf(lit, _InvalidLit, "hexadecimal floating-point literals requires go1.13 or later") + } +} + +// allowVersion reports whether the given package +// is allowed to use version major.minor. +func (check *Checker) allowVersion(pkg *Package, major, minor int) bool { + // We assume that imported packages have all been checked, + // so we only have to check for the local package. + if pkg != check.pkg { + return true + } + ma, mi := check.version.major, check.version.minor + return ma == 0 && mi == 0 || ma > major || ma == major && mi >= minor +} + +type version struct { + major, minor int +} + +// parseGoVersion parses a Go version string (such as "go1.12") +// and returns the version, or an error. If s is the empty +// string, the version is 0.0. +func parseGoVersion(s string) (v version, err error) { + if s == "" { + return + } + matches := goVersionRx.FindStringSubmatch(s) + if matches == nil { + err = fmt.Errorf(`should be something like "go1.12"`) + return + } + v.major, err = strconv.Atoi(matches[1]) + if err != nil { + return + } + v.minor, err = strconv.Atoi(matches[2]) + return +} + +// goVersionRx matches a Go version string, e.g. "go1.12". +var goVersionRx = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`) From 66c27093d0df8be8a75b1ae35fe4ab2003fe028e Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Sat, 13 Feb 2021 02:45:51 +0000 Subject: [PATCH 25/47] cmd/link: fix typo in link_test.go specfic -> specific Change-Id: Icad0f70c77c866a1031a2929b90fef61fe92aaee GitHub-Last-Rev: f66b56491c0125f58c47f7f39410e0aeef2539be GitHub-Pull-Request: golang/go#44246 Reviewed-on: https://go-review.googlesource.com/c/go/+/291829 Reviewed-by: Ian Lance Taylor Trust: Matthew Dempsky --- src/cmd/link/link_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 8153c0b31b..08ddd00a0c 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -583,7 +583,7 @@ TEXT ·alignPc(SB),NOSPLIT, $0-0 ` // TestFuncAlign verifies that the address of a function can be aligned -// with a specfic value on arm64. +// with a specific value on arm64. func TestFuncAlign(t *testing.T) { if runtime.GOARCH != "arm64" || runtime.GOOS != "linux" { t.Skip("skipping on non-linux/arm64 platform") From 852ce7c2125ef7d59a24facc2b6c3df30d7f730d Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Sun, 14 Feb 2021 13:22:15 +1100 Subject: [PATCH 26/47] cmd/go: provide a more helpful suggestion for "go vet -?" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the command go vet -? the output was, usage: go vet [-n] [-x] [-vettool prog] [build flags] [vet flags] [packages] Run 'go help vet' for details. Run 'go tool vet -help' for the vet tool's flags. but "go help vet" is perfunctory at best. (That's another issue I'm working on—see https://go-review.googlesource.com/c/tools/+/291909— but vendoring is required to sort that out.) Add another line and rewrite a bit to make it actually helpful: usage: go vet [-n] [-x] [-vettool prog] [build flags] [vet flags] [packages] Run 'go help vet' for details. Run 'go tool vet help' for a full list of flags and analyzers. Run 'go tool vet -help' for an overview. Change-Id: I9d8580f0573321a57d55875ac3185988ce3eaf64 Reviewed-on: https://go-review.googlesource.com/c/go/+/291929 Trust: Rob Pike Run-TryBot: Rob Pike TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/cmd/go/internal/vet/vetflag.go | 3 ++- src/cmd/go/testdata/script/help.txt | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/internal/vet/vetflag.go b/src/cmd/go/internal/vet/vetflag.go index 5bf5cf4446..b5b3c462ff 100644 --- a/src/cmd/go/internal/vet/vetflag.go +++ b/src/cmd/go/internal/vet/vetflag.go @@ -184,7 +184,8 @@ func exitWithUsage() { if vetTool != "" { cmd = vetTool } - fmt.Fprintf(os.Stderr, "Run '%s -help' for the vet tool's flags.\n", cmd) + fmt.Fprintf(os.Stderr, "Run '%s help' for a full list of flags and analyzers.\n", cmd) + fmt.Fprintf(os.Stderr, "Run '%s -help' for an overview.\n", cmd) base.SetExitStatus(2) base.Exit() diff --git a/src/cmd/go/testdata/script/help.txt b/src/cmd/go/testdata/script/help.txt index 9752ede2e3..26a0194be5 100644 --- a/src/cmd/go/testdata/script/help.txt +++ b/src/cmd/go/testdata/script/help.txt @@ -34,9 +34,10 @@ stderr 'Run ''go help mod'' for usage.' # Earlier versions of Go printed the same as 'go -h' here. # Also make sure we print the short help line. ! go vet -h -stderr 'usage: go vet' -stderr 'Run ''go help vet'' for details' -stderr 'Run ''go tool vet -help'' for the vet tool''s flags' +stderr 'usage: go vet .*' +stderr 'Run ''go help vet'' for details.' +stderr 'Run ''go tool vet help'' for a full list of flags and analyzers.' +stderr 'Run ''go tool vet -help'' for an overview.' # Earlier versions of Go printed a large document here, instead of these two # lines. From 33d72fd4122a4b7e31e738d5d9283093966ec14a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 14 Feb 2021 17:21:56 -0800 Subject: [PATCH 27/47] doc/faq: update generics entry to reflect accepted proposal For #43651 Change-Id: Idb511f4c759d9a77de289938c19c2c1d4a542a17 Reviewed-on: https://go-review.googlesource.com/c/go/+/291990 Trust: Ian Lance Taylor Reviewed-by: Rob Pike --- doc/go_faq.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/go_faq.html b/doc/go_faq.html index 23a3080c9b..67dc0b9bd4 100644 --- a/doc/go_faq.html +++ b/doc/go_faq.html @@ -446,8 +446,10 @@ they compensate in interesting ways for the lack of X.

Why does Go not have generic types?

-Generics may well be added at some point. We don't feel an urgency for -them, although we understand some programmers do. +A language proposal +implementing a form of generic types has been accepted for +inclusion in the language. +If all goes well it will be available in the Go 1.18 release.

From 30641e36aa5b547eee48565caa3078b0a2e7c185 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 14 Feb 2021 17:14:41 -0800 Subject: [PATCH 28/47] internal/poll: if copy_file_range returns 0, assume it failed On current Linux kernels copy_file_range does not correctly handle files in certain special file systems, such as /proc. For those file systems it fails to copy any data and returns zero. This breaks Go's io.Copy for those files. Fix the problem by assuming that if copy_file_range returns 0 the first time it is called on a file, that that file is not supported. In that case fall back to just using read. This will force an extra system call when using io.Copy to copy a zero-sized normal file, but at least it will work correctly. For #36817 Fixes #44272 Change-Id: I02e81872cb70fda0ce5485e2ea712f219132e614 Reviewed-on: https://go-review.googlesource.com/c/go/+/291989 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Russ Cox --- src/internal/poll/copy_file_range_linux.go | 10 ++++++- src/os/readfrom_linux_test.go | 32 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/internal/poll/copy_file_range_linux.go b/src/internal/poll/copy_file_range_linux.go index fc34aef4cb..01b242a4ea 100644 --- a/src/internal/poll/copy_file_range_linux.go +++ b/src/internal/poll/copy_file_range_linux.go @@ -112,7 +112,15 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err return 0, false, nil case nil: if n == 0 { - // src is at EOF, which means we are done. + // If we did not read any bytes at all, + // then this file may be in a file system + // where copy_file_range silently fails. + // https://lore.kernel.org/linux-fsdevel/20210126233840.GG4626@dread.disaster.area/T/#m05753578c7f7882f6e9ffe01f981bc223edef2b0 + if written == 0 { + return 0, false, nil + } + // Otherwise src is at EOF, which means + // we are done. return written, true, nil } remain -= n diff --git a/src/os/readfrom_linux_test.go b/src/os/readfrom_linux_test.go index 37047175e6..1d145dadb0 100644 --- a/src/os/readfrom_linux_test.go +++ b/src/os/readfrom_linux_test.go @@ -361,3 +361,35 @@ func (h *copyFileRangeHook) install() { func (h *copyFileRangeHook) uninstall() { *PollCopyFileRangeP = h.original } + +// On some kernels copy_file_range fails on files in /proc. +func TestProcCopy(t *testing.T) { + const cmdlineFile = "/proc/self/cmdline" + cmdline, err := os.ReadFile(cmdlineFile) + if err != nil { + t.Skipf("can't read /proc file: %v", err) + } + in, err := os.Open(cmdlineFile) + if err != nil { + t.Fatal(err) + } + defer in.Close() + outFile := filepath.Join(t.TempDir(), "cmdline") + out, err := os.Create(outFile) + if err != nil { + t.Fatal(err) + } + if _, err := io.Copy(out, in); err != nil { + t.Fatal(err) + } + if err := out.Close(); err != nil { + t.Fatal(err) + } + copy, err := os.ReadFile(outFile) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(cmdline, copy) { + t.Errorf("copy of %q got %q want %q\n", cmdlineFile, copy, cmdline) + } +} From 626ef0812739ac7bb527dbdf4b0ed3a436c90901 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 12 Feb 2021 16:02:12 -0500 Subject: [PATCH 29/47] doc: remove install.html and install-source.html These live in x/website/content/doc now. The copies here just attract edits that have no actual effect. For #40496. For #41861. Change-Id: I2fdd7375e373949eb9a88f4cdca440b6a5d45eea Reviewed-on: https://go-review.googlesource.com/c/go/+/291709 Trust: Russ Cox Reviewed-by: Dmitri Shuralyov --- README.md | 10 +- doc/install-source.html | 777 ---------------------------------------- doc/install.html | 315 ---------------- 3 files changed, 4 insertions(+), 1098 deletions(-) delete mode 100644 doc/install-source.html delete mode 100644 doc/install.html diff --git a/README.md b/README.md index 49231bf25d..4ca3956de8 100644 --- a/README.md +++ b/README.md @@ -19,22 +19,20 @@ BSD-style license found in the LICENSE file. Official binary distributions are available at https://golang.org/dl/. After downloading a binary release, visit https://golang.org/doc/install -or load [doc/install.html](./doc/install.html) in your web browser for installation -instructions. +for installation instructions. #### Install From Source If a binary distribution is not available for your combination of operating system and architecture, visit -https://golang.org/doc/install/source or load [doc/install-source.html](./doc/install-source.html) -in your web browser for source installation instructions. +https://golang.org/doc/install/source +for source installation instructions. ### Contributing Go is the work of thousands of contributors. We appreciate your help! -To contribute, please read the contribution guidelines: - https://golang.org/doc/contribute.html +To contribute, please read the contribution guidelines at https://golang.org/doc/contribute.html. Note that the Go project uses the issue tracker for bug reports and proposals only. See https://golang.org/wiki/Questions for a list of diff --git a/doc/install-source.html b/doc/install-source.html deleted file mode 100644 index f0a909263c..0000000000 --- a/doc/install-source.html +++ /dev/null @@ -1,777 +0,0 @@ - - -

Introduction

- -

-Go is an open source project, distributed under a -BSD-style license. -This document explains how to check out the sources, -build them on your own machine, and run them. -

- -

-Most users don't need to do this, and will instead install -from precompiled binary packages as described in -Getting Started, -a much simpler process. -If you want to help develop what goes into those precompiled -packages, though, read on. -

- -
- -

-There are two official Go compiler toolchains. -This document focuses on the gc Go -compiler and tools. -For information on how to work on gccgo, a more traditional -compiler using the GCC back end, see -Setting up and using gccgo. -

- -

-The Go compilers support the following instruction sets: - -

-
- amd64, 386 -
-
- The x86 instruction set, 64- and 32-bit. -
-
- arm64, arm -
-
- The ARM instruction set, 64-bit (AArch64) and 32-bit. -
-
- mips64, mips64le, mips, mipsle -
-
- The MIPS instruction set, big- and little-endian, 64- and 32-bit. -
-
- ppc64, ppc64le -
-
- The 64-bit PowerPC instruction set, big- and little-endian. -
-
- riscv64 -
-
- The 64-bit RISC-V instruction set. -
-
- s390x -
-
- The IBM z/Architecture. -
-
- wasm -
-
- WebAssembly. -
-
-

- -

-The compilers can target the AIX, Android, DragonFly BSD, FreeBSD, -Illumos, Linux, macOS/iOS (Darwin), NetBSD, OpenBSD, Plan 9, Solaris, -and Windows operating systems (although not all operating systems -support all architectures). -

- -

-A list of ports which are considered "first class" is available at the -first class ports -wiki page. -

- -

-The full set of supported combinations is listed in the -discussion of environment variables below. -

- -

-See the main installation page for the overall system requirements. -The following additional constraints apply to systems that can be built only from source: -

- -
    -
  • For Linux on PowerPC 64-bit, the minimum supported kernel version is 2.6.37, meaning that -Go does not support CentOS 6 on these systems. -
  • -
- -
- -

Install Go compiler binaries for bootstrap

- -

-The Go toolchain is written in Go. To build it, you need a Go compiler installed. -The scripts that do the initial build of the tools look for a "go" command -in $PATH, so as long as you have Go installed in your -system and configured in your $PATH, you are ready to build Go -from source. -Or if you prefer you can set $GOROOT_BOOTSTRAP to the -root of a Go installation to use to build the new Go toolchain; -$GOROOT_BOOTSTRAP/bin/go should be the go command to use.

- -

-There are four possible ways to obtain a bootstrap toolchain: -

- -
    -
  • Download a recent binary release of Go. -
  • Cross-compile a toolchain using a system with a working Go installation. -
  • Use gccgo. -
  • Compile a toolchain from Go 1.4, the last Go release with a compiler written in C. -
- -

-These approaches are detailed below. -

- -

Bootstrap toolchain from binary release

- -

-To use a binary release as a bootstrap toolchain, see -the downloads page or use any other -packaged Go distribution. -

- -

Bootstrap toolchain from cross-compiled source

- -

-To cross-compile a bootstrap toolchain from source, which is -necessary on systems Go 1.4 did not target (for -example, linux/ppc64le), install Go on a different system -and run bootstrap.bash. -

- -

-When run as (for example) -

- -
-$ GOOS=linux GOARCH=ppc64 ./bootstrap.bash
-
- -

-bootstrap.bash cross-compiles a toolchain for that GOOS/GOARCH -combination, leaving the resulting tree in ../../go-${GOOS}-${GOARCH}-bootstrap. -That tree can be copied to a machine of the given target type -and used as GOROOT_BOOTSTRAP to bootstrap a local build. -

- -

Bootstrap toolchain using gccgo

- -

-To use gccgo as the bootstrap toolchain, you need to arrange -for $GOROOT_BOOTSTRAP/bin/go to be the go tool that comes -as part of gccgo 5. For example on Ubuntu Vivid: -

- -
-$ sudo apt-get install gccgo-5
-$ sudo update-alternatives --set go /usr/bin/go-5
-$ GOROOT_BOOTSTRAP=/usr ./make.bash
-
- -

Bootstrap toolchain from C source code

- -

-To build a bootstrap toolchain from C source code, use -either the git branch release-branch.go1.4 or -go1.4-bootstrap-20171003.tar.gz, -which contains the Go 1.4 source code plus accumulated fixes -to keep the tools running on newer operating systems. -(Go 1.4 was the last distribution in which the toolchain was written in C.) -After unpacking the Go 1.4 source, cd to -the src subdirectory, set CGO_ENABLED=0 in -the environment, and run make.bash (or, -on Windows, make.bat). -

- -

-Once the Go 1.4 source has been unpacked into your GOROOT_BOOTSTRAP directory, -you must keep this git clone instance checked out to branch -release-branch.go1.4. Specifically, do not attempt to reuse -this git clone in the later step named "Fetch the repository." The go1.4 -bootstrap toolchain must be able to properly traverse the go1.4 sources -that it assumes are present under this repository root. -

- -

-Note that Go 1.4 does not run on all systems that later versions of Go do. -In particular, Go 1.4 does not support current versions of macOS. -On such systems, the bootstrap toolchain must be obtained using one of the other methods. -

- -

Install Git, if needed

- -

-To perform the next step you must have Git installed. (Check that you -have a git command before proceeding.) -

- -

-If you do not have a working Git installation, -follow the instructions on the -Git downloads page. -

- -

(Optional) Install a C compiler

- -

-To build a Go installation -with cgo support, which permits Go -programs to import C libraries, a C compiler such as gcc -or clang must be installed first. Do this using whatever -installation method is standard on the system. -

- -

-To build without cgo, set the environment variable -CGO_ENABLED=0 before running all.bash or -make.bash. -

- -

Fetch the repository

- -

Change to the directory where you intend to install Go, and make sure -the goroot directory does not exist. Then clone the repository -and check out the latest release tag (go1.12, -for example):

- -
-$ git clone https://go.googlesource.com/go goroot
-$ cd goroot
-$ git checkout <tag>
-
- -

-Where <tag> is the version string of the release. -

- -

Go will be installed in the directory where it is checked out. For example, -if Go is checked out in $HOME/goroot, executables will be installed -in $HOME/goroot/bin. The directory may have any name, but note -that if Go is checked out in $HOME/go, it will conflict with -the default location of $GOPATH. -See GOPATH below.

- -

-Reminder: If you opted to also compile the bootstrap binaries from source (in an -earlier section), you still need to git clone again at this point -(to checkout the latest <tag>), because you must keep your -go1.4 repository distinct. -

- - - -

If you intend to modify the go source code, and -contribute your changes -to the project, then move your repository -off the release branch, and onto the master (development) branch. -Otherwise, skip this step.

- -
-$ git checkout master
-
- -

Install Go

- -

-To build the Go distribution, run -

- -
-$ cd src
-$ ./all.bash
-
- -

-(To build under Windows use all.bat.) -

- -

-If all goes well, it will finish by printing output like: -

- -
-ALL TESTS PASSED
-
----
-Installed Go for linux/amd64 in /home/you/go.
-Installed commands in /home/you/go/bin.
-*** You need to add /home/you/go/bin to your $PATH. ***
-
- -

-where the details on the last few lines reflect the operating system, -architecture, and root directory used during the install. -

- -
-

-For more information about ways to control the build, see the discussion of -environment variables below. -all.bash (or all.bat) runs important tests for Go, -which can take more time than simply building Go. If you do not want to run -the test suite use make.bash (or make.bat) -instead. -

-
- - -

Testing your installation

- -

-Check that Go is installed correctly by building a simple program. -

- -

-Create a file named hello.go and put the following program in it: -

- -
-package main
-
-import "fmt"
-
-func main() {
-	fmt.Printf("hello, world\n")
-}
-
- -

-Then run it with the go tool: -

- -
-$ go run hello.go
-hello, world
-
- -

-If you see the "hello, world" message then Go is installed correctly. -

- -

Set up your work environment

- -

-You're almost done. -You just need to do a little more setup. -

- -

- -How to Write Go Code -Learn how to set up and use the Go tools - -

- -

-The How to Write Go Code document -provides essential setup instructions for using the Go tools. -

- - -

Install additional tools

- -

-The source code for several Go tools (including godoc) -is kept in the go.tools repository. -To install one of the tools (godoc in this case): -

- -
-$ go get golang.org/x/tools/cmd/godoc
-
- -

-To install these tools, the go get command requires -that Git be installed locally. -

- -

-You must also have a workspace (GOPATH) set up; -see How to Write Go Code for the details. -

- -

Community resources

- -

-The usual community resources such as -#go-nuts on the Freenode IRC server -and the -Go Nuts -mailing list have active developers that can help you with problems -with your installation or your development work. -For those who wish to keep up to date, -there is another mailing list, golang-checkins, -that receives a message summarizing each checkin to the Go repository. -

- -

-Bugs can be reported using the Go issue tracker. -

- - -

Keeping up with releases

- -

-New releases are announced on the -golang-announce -mailing list. -Each announcement mentions the latest release tag, for instance, -go1.9. -

- -

-To update an existing tree to the latest release, you can run: -

- -
-$ cd go/src
-$ git fetch
-$ git checkout <tag>
-$ ./all.bash
-
- -

-Where <tag> is the version string of the release. -

- - -

Optional environment variables

- -

-The Go compilation environment can be customized by environment variables. -None is required by the build, but you may wish to set some -to override the defaults. -

- -
    -
  • $GOROOT -

    -The root of the Go tree, often $HOME/go1.X. -Its value is built into the tree when it is compiled, and -defaults to the parent of the directory where all.bash was run. -There is no need to set this unless you want to switch between multiple -local copies of the repository. -

    -
  • - -
  • $GOROOT_FINAL -

    -The value assumed by installed binaries and scripts when -$GOROOT is not set explicitly. -It defaults to the value of $GOROOT. -If you want to build the Go tree in one location -but move it elsewhere after the build, set -$GOROOT_FINAL to the eventual location. -

    -
  • - -
  • $GOPATH -

    -The directory where Go projects outside the Go distribution are typically -checked out. For example, golang.org/x/tools might be checked out -to $GOPATH/src/golang.org/x/tools. Executables outside the -Go distribution are installed in $GOPATH/bin (or -$GOBIN, if set). Modules are downloaded and cached in -$GOPATH/pkg/mod. -

    - -

    The default location of $GOPATH is $HOME/go, -and it's not usually necessary to set GOPATH explicitly. However, -if you have checked out the Go distribution to $HOME/go, -you must set GOPATH to another location to avoid conflicts. -

    -
  • - -
  • $GOBIN -

    -The directory where executables outside the Go distribution are installed -using the go command. For example, -go get golang.org/x/tools/cmd/godoc downloads, builds, and -installs $GOBIN/godoc. By default, $GOBIN is -$GOPATH/bin (or $HOME/go/bin if GOPATH -is not set). After installing, you will want to add this directory to -your $PATH so you can use installed tools. -

    - -

    -Note that the Go distribution's executables are installed in -$GOROOT/bin (for executables invoked by people) or -$GOTOOLDIR (for executables invoked by the go command; -defaults to $GOROOT/pkg/$GOOS_GOARCH) instead of -$GOBIN. -

    -
  • - -
  • $GOOS and $GOARCH -

    -The name of the target operating system and compilation architecture. -These default to the values of $GOHOSTOS and -$GOHOSTARCH respectively (described below). -

  • - -

    -Choices for $GOOS are -android, darwin, dragonfly, -freebsd, illumos, ios, js, -linux, netbsd, openbsd, -plan9, solaris and windows. -

    - -

    -Choices for $GOARCH are -amd64 (64-bit x86, the most mature port), -386 (32-bit x86), arm (32-bit ARM), arm64 (64-bit ARM), -ppc64le (PowerPC 64-bit, little-endian), ppc64 (PowerPC 64-bit, big-endian), -mips64le (MIPS 64-bit, little-endian), mips64 (MIPS 64-bit, big-endian), -mipsle (MIPS 32-bit, little-endian), mips (MIPS 32-bit, big-endian), -s390x (IBM System z 64-bit, big-endian), and -wasm (WebAssembly 32-bit). -

    - -

    -The valid combinations of $GOOS and $GOARCH are: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    $GOOS $GOARCH
    aix ppc64
    android 386
    android amd64
    android arm
    android arm64
    darwin amd64
    darwin arm64
    dragonfly amd64
    freebsd 386
    freebsd amd64
    freebsd arm
    illumos amd64
    ios arm64
    js wasm
    linux 386
    linux amd64
    linux arm
    linux arm64
    linux ppc64
    linux ppc64le
    linux mips
    linux mipsle
    linux mips64
    linux mips64le
    linux riscv64
    linux s390x
    netbsd 386
    netbsd amd64
    netbsd arm
    openbsd 386
    openbsd amd64
    openbsd arm
    openbsd arm64
    plan9 386
    plan9 amd64
    plan9 arm
    solaris amd64
    windows 386
    windows amd64
    -
    - -

  • $GOHOSTOS and $GOHOSTARCH -

    -The name of the host operating system and compilation architecture. -These default to the local system's operating system and -architecture. -

    -
  • - -

    -Valid choices are the same as for $GOOS and -$GOARCH, listed above. -The specified values must be compatible with the local system. -For example, you should not set $GOHOSTARCH to -arm on an x86 system. -

    - -
  • $GO386 (for 386 only, defaults to sse2) -

    -This variable controls how gc implements floating point computations. -

    -
      -
    • GO386=softfloat: use software floating point operations; should support all x86 chips (Pentium MMX or later).
    • -
    • GO386=sse2: use SSE2 for floating point operations; has better performance but only available on Pentium 4/Opteron/Athlon 64 or later.
    • -
    -
  • - -
  • $GOARM (for arm only; default is auto-detected if building -on the target processor, 6 if not) -

    -This sets the ARM floating point co-processor architecture version the run-time -should target. If you are compiling on the target system, its value will be auto-detected. -

    -
      -
    • GOARM=5: use software floating point; when CPU doesn't have VFP co-processor
    • -
    • GOARM=6: use VFPv1 only; default if cross compiling; usually ARM11 or better cores (VFPv2 or better is also supported)
    • -
    • GOARM=7: use VFPv3; usually Cortex-A cores
    • -
    -

    -If in doubt, leave this variable unset, and adjust it if required -when you first run the Go executable. -The GoARM page -on the Go community wiki -contains further details regarding Go's ARM support. -

    -
  • - -
  • $GOMIPS (for mips and mipsle only)
    $GOMIPS64 (for mips64 and mips64le only) -

    - These variables set whether to use floating point instructions. Set to "hardfloat" to use floating point instructions; this is the default. Set to "softfloat" to use soft floating point. -

    -
  • - -
  • $GOPPC64 (for ppc64 and ppc64le only) -

    -This variable sets the processor level (i.e. Instruction Set Architecture version) -for which the compiler will target. The default is power8. -

    -
      -
    • GOPPC64=power8: generate ISA v2.07 instructions
    • -
    • GOPPC64=power9: generate ISA v3.00 instructions
    • -
    -
  • - - -
  • $GOWASM (for wasm only) -

    - This variable is a comma separated list of experimental WebAssembly features that the compiled WebAssembly binary is allowed to use. - The default is to use no experimental features. -

    - -
  • - -
- -

-Note that $GOARCH and $GOOS identify the -target environment, not the environment you are running on. -In effect, you are always cross-compiling. -By architecture, we mean the kind of binaries -that the target environment can run: -an x86-64 system running a 32-bit-only operating system -must set GOARCH to 386, -not amd64. -

- -

-If you choose to override the defaults, -set these variables in your shell profile ($HOME/.bashrc, -$HOME/.profile, or equivalent). The settings might look -something like this: -

- -
-export GOARCH=amd64
-export GOOS=linux
-
- -

-although, to reiterate, none of these variables needs to be set to build, -install, and develop the Go tree. -

diff --git a/doc/install.html b/doc/install.html deleted file mode 100644 index 706d66c007..0000000000 --- a/doc/install.html +++ /dev/null @@ -1,315 +0,0 @@ - - -
- -

Download the Go distribution

- -

- -Download Go -Click here to visit the downloads page - -

- -

-Official binary -distributions are available for the FreeBSD (release 10-STABLE and above), -Linux, macOS (10.11 and above), and Windows operating systems and -the 32-bit (386) and 64-bit (amd64) x86 processor -architectures. -

- -

-If a binary distribution is not available for your combination of operating -system and architecture, try -installing from source or -installing gccgo instead of gc. -

- - -

System requirements

- -

-Go binary distributions are available for these supported operating systems and architectures. -Please ensure your system meets these requirements before proceeding. -If your OS or architecture is not on the list, you may be able to -install from source or -use gccgo instead. -

- - - - - - - - - - - - -
Operating systemArchitecturesNotes

FreeBSD 10.3 or later amd64, 386 Debian GNU/kFreeBSD not supported
Linux 2.6.23 or later with glibc amd64, 386, arm, arm64,
s390x, ppc64le
CentOS/RHEL 5.x not supported.
Install from source for other libc.
macOS 10.11 or later amd64 use the clang or gcc that comes with Xcode for cgo support
Windows 7, Server 2008R2 or later amd64, 386 use MinGW (386) or MinGW-W64 (amd64) gcc.
No need for cygwin or msys.
- -

-A C compiler is required only if you plan to use -cgo.
-You only need to install the command line tools for -Xcode. If you have already -installed Xcode 4.3+, you can install it from the Components tab of the -Downloads preferences panel. -

- -
- - -

Install the Go tools

- -

-If you are upgrading from an older version of Go you must -first remove the existing version. -

- -
- -

Linux, macOS, and FreeBSD tarballs

- -

-Download the archive -and extract it into /usr/local, creating a Go tree in -/usr/local/go. For example: -

- -
-tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz
-
- -

-Choose the archive file appropriate for your installation. -For instance, if you are installing Go version 1.2.1 for 64-bit x86 on Linux, -the archive you want is called go1.2.1.linux-amd64.tar.gz. -

- -

-(Typically these commands must be run as root or through sudo.) -

- -

-Add /usr/local/go/bin to the PATH environment -variable. You can do this by adding this line to your /etc/profile -(for a system-wide installation) or $HOME/.profile: -

- -
-export PATH=$PATH:/usr/local/go/bin
-
- -

-Note: changes made to a profile file may not apply until the -next time you log into your computer. -To apply the changes immediately, just run the shell commands directly -or execute them from the profile using a command such as -source $HOME/.profile. -

- -
- -
- -

macOS package installer

- -

-Download the package file, -open it, and follow the prompts to install the Go tools. -The package installs the Go distribution to /usr/local/go. -

- -

-The package should put the /usr/local/go/bin directory in your -PATH environment variable. You may need to restart any open -Terminal sessions for the change to take effect. -

- -
- -
- -

Windows

- -

-The Go project provides two installation options for Windows users -(besides installing from source): -a zip archive that requires you to set some environment variables and an -MSI installer that configures your installation automatically. -

- -
- -

MSI installer

- -

-Open the MSI file -and follow the prompts to install the Go tools. -By default, the installer puts the Go distribution in c:\Go. -

- -

-The installer should put the c:\Go\bin directory in your -PATH environment variable. You may need to restart any open -command prompts for the change to take effect. -

- -
- -
- -

Zip archive

- -

-Download the zip file and extract it into the directory of your choice (we suggest c:\Go). -

- -

-Add the bin subdirectory of your Go root (for example, c:\Go\bin) to your PATH environment variable. -

- -
- -

Setting environment variables under Windows

- -

-Under Windows, you may set environment variables through the "Environment -Variables" button on the "Advanced" tab of the "System" control panel. Some -versions of Windows provide this control panel through the "Advanced System -Settings" option inside the "System" control panel. -

- -
- - -

Test your installation

- -

-Check that Go is installed correctly by building a simple program, as follows. -

- -

-Create a file named hello.go that looks like: -

- -
-package main
-
-import "fmt"
-
-func main() {
-	fmt.Printf("hello, world\n")
-}
-
- -

-Then build it with the go tool: -

- -
-$ go build hello.go
-
- -
-C:\Users\Gopher\go\src\hello> go build hello.go
-
- -

-The command above will build an executable named -hellohello.exe -in the current directory alongside your source code. -Execute it to see the greeting: -

- -
-$ ./hello
-hello, world
-
- -
-C:\Users\Gopher\go\src\hello> hello
-hello, world
-
- -

-If you see the "hello, world" message then your Go installation is working. -

- -

-Before rushing off to write Go code please read the -How to Write Go Code document, -which describes some essential concepts about using the Go tools. -

- - -

Installing extra Go versions

- -

-It may be useful to have multiple Go versions installed on the same machine, for -example, to ensure that a package's tests pass on multiple Go versions. -Once you have one Go version installed, you can install another (such as 1.10.7) -as follows: -

- -
-$ go get golang.org/dl/go1.10.7
-$ go1.10.7 download
-
- -

-The newly downloaded version can be used like go: -

- -
-$ go1.10.7 version
-go version go1.10.7 linux/amd64
-
- -

-All Go versions available via this method are listed on -the download page. -You can find where each of these extra Go versions is installed by looking -at its GOROOT; for example, go1.10.7 env GOROOT. -To uninstall a downloaded version, just remove its GOROOT directory -and the goX.Y.Z binary. -

- - -

Uninstalling Go

- -

-To remove an existing Go installation from your system delete the -go directory. This is usually /usr/local/go -under Linux, macOS, and FreeBSD or c:\Go -under Windows. -

- -

-You should also remove the Go bin directory from your -PATH environment variable. -Under Linux and FreeBSD you should edit /etc/profile or -$HOME/.profile. -If you installed Go with the macOS package then you -should remove the /etc/paths.d/go file. -Windows users should read the section about setting -environment variables under Windows. -

- - -

Getting help

- -

- For help, see the list of Go mailing lists, forums, and places to chat. -

- -

- Report bugs either by running “go bug”, or - manually at the Go issue tracker. -

From 0cb3415154ff354b42db1d65073e9be71abcc970 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 12 Feb 2021 16:16:25 -0500 Subject: [PATCH 30/47] doc: remove all docs not tied to distribution They have moved to x/website in CL 291693. The docs that are left are the ones that are edited at the same time as development in this repository and are tied to the specific version of Go being developed. Those are: - the language spec - the memory model - the assembler manual - the current release's release notes Change-Id: I437c4d33ada1b1716b1919c3c939c2cacf407e83 Reviewed-on: https://go-review.googlesource.com/c/go/+/291711 Trust: Russ Cox Trust: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov --- doc/articles/go_command.html | 254 -- doc/articles/index.html | 8 - doc/articles/race_detector.html | 440 --- doc/articles/wiki/edit.html | 6 - doc/articles/wiki/final-noclosure.go | 105 - doc/articles/wiki/final-noerror.go | 56 - doc/articles/wiki/final-parsetemplate.go | 94 - doc/articles/wiki/final-template.go | 68 - doc/articles/wiki/final.go | 92 - doc/articles/wiki/final_test.go | 24 - doc/articles/wiki/go.mod | 3 - doc/articles/wiki/http-sample.go | 18 - doc/articles/wiki/index.html | 741 ----- doc/articles/wiki/notemplate.go | 59 - doc/articles/wiki/part1-noerror.go | 35 - doc/articles/wiki/part1.go | 38 - doc/articles/wiki/part2.go | 44 - doc/articles/wiki/part3-errorhandling.go | 76 - doc/articles/wiki/part3.go | 60 - doc/articles/wiki/test_Test.txt.good | 1 - doc/articles/wiki/test_edit.good | 6 - doc/articles/wiki/test_view.good | 5 - doc/articles/wiki/view.html | 5 - doc/articles/wiki/wiki_test.go | 165 - doc/cmd.html | 100 - doc/codewalk/codewalk.css | 234 -- doc/codewalk/codewalk.js | 305 -- doc/codewalk/codewalk.xml | 124 - doc/codewalk/codewalk_test.go | 52 - doc/codewalk/functions.xml | 105 - doc/codewalk/markov.go | 130 - doc/codewalk/markov.xml | 307 -- doc/codewalk/pig.go | 121 - doc/codewalk/popout.png | Bin 213 -> 0 bytes doc/codewalk/sharemem.xml | 181 -- doc/codewalk/urlpoll.go | 116 - doc/contribute.html | 1294 -------- doc/debugging_with_gdb.html | 554 ---- doc/diagnostics.html | 472 --- doc/editors.html | 33 - doc/effective_go.html | 3673 ---------------------- doc/gccgo_contribute.html | 112 - doc/gccgo_install.html | 533 ---- doc/go-logo-black.png | Bin 8843 -> 0 bytes doc/go-logo-blue.png | Bin 9360 -> 0 bytes doc/go-logo-white.png | Bin 21469 -> 0 bytes doc/go1.1.html | 1099 ------- doc/go1.10.html | 1448 --------- doc/go1.11.html | 934 ------ doc/go1.12.html | 949 ------ doc/go1.13.html | 1066 ------- doc/go1.14.html | 924 ------ doc/go1.15.html | 1064 ------- doc/go1.2.html | 979 ------ doc/go1.3.html | 608 ---- doc/go1.4.html | 896 ------ doc/go1.5.html | 1310 -------- doc/go1.6.html | 923 ------ doc/go1.7.html | 1281 -------- doc/go1.8.html | 1666 ---------- doc/go1.9.html | 1024 ------ doc/go1.html | 2038 ------------ doc/go1compat.html | 202 -- doc/go_faq.html | 2477 --------------- doc/gopher/README | 3 - doc/gopher/appenginegopher.jpg | Bin 135882 -> 0 bytes doc/gopher/appenginegophercolor.jpg | Bin 162023 -> 0 bytes doc/gopher/appenginelogo.gif | Bin 2105 -> 0 bytes doc/gopher/biplane.jpg | Bin 203420 -> 0 bytes doc/gopher/bumper.png | Bin 276215 -> 0 bytes doc/gopher/bumper192x108.png | Bin 8432 -> 0 bytes doc/gopher/bumper320x180.png | Bin 15098 -> 0 bytes doc/gopher/bumper480x270.png | Bin 26509 -> 0 bytes doc/gopher/bumper640x360.png | Bin 42013 -> 0 bytes doc/gopher/doc.png | Bin 4395 -> 0 bytes doc/gopher/favicon.svg | 238 -- doc/gopher/fiveyears.jpg | Bin 220526 -> 0 bytes doc/gopher/frontpage.png | Bin 17668 -> 0 bytes doc/gopher/gopherbw.png | Bin 171323 -> 0 bytes doc/gopher/gophercolor.png | Bin 169406 -> 0 bytes doc/gopher/gophercolor16x16.png | Bin 739 -> 0 bytes doc/gopher/help.png | Bin 5729 -> 0 bytes doc/gopher/modelsheet.jpg | Bin 85880 -> 0 bytes doc/gopher/pencil/gopherhat.jpg | Bin 129627 -> 0 bytes doc/gopher/pencil/gopherhelmet.jpg | Bin 151965 -> 0 bytes doc/gopher/pencil/gophermega.jpg | Bin 122348 -> 0 bytes doc/gopher/pencil/gopherrunning.jpg | Bin 86299 -> 0 bytes doc/gopher/pencil/gopherswim.jpg | Bin 158593 -> 0 bytes doc/gopher/pencil/gopherswrench.jpg | Bin 231095 -> 0 bytes doc/gopher/pkg.png | Bin 5409 -> 0 bytes doc/gopher/project.png | Bin 8042 -> 0 bytes doc/gopher/ref.png | Bin 5895 -> 0 bytes doc/gopher/run.png | Bin 9220 -> 0 bytes doc/gopher/talks.png | Bin 4877 -> 0 bytes doc/help.html | 96 - doc/ie.css | 1 - doc/play/fib.go | 19 - doc/play/hello.go | 9 - doc/play/life.go | 113 - doc/play/peano.go | 88 - doc/play/pi.go | 34 - doc/play/sieve.go | 36 - doc/play/solitaire.go | 117 - doc/play/tree.go | 100 - doc/progs/cgo1.go | 22 - doc/progs/cgo2.go | 22 - doc/progs/cgo3.go | 18 - doc/progs/cgo4.go | 18 - doc/progs/defer.go | 64 - doc/progs/defer2.go | 58 - doc/progs/eff_bytesize.go | 47 - doc/progs/eff_qr.go | 50 - doc/progs/eff_sequence.go | 49 - doc/progs/eff_unused1.go | 16 - doc/progs/eff_unused2.go | 20 - doc/progs/error.go | 127 - doc/progs/error2.go | 54 - doc/progs/error3.go | 63 - doc/progs/error4.go | 74 - doc/progs/go1.go | 245 -- doc/progs/gobs1.go | 22 - doc/progs/gobs2.go | 43 - doc/progs/image_draw.go | 142 - doc/progs/image_package1.go | 15 - doc/progs/image_package2.go | 16 - doc/progs/image_package3.go | 15 - doc/progs/image_package4.go | 16 - doc/progs/image_package5.go | 17 - doc/progs/image_package6.go | 17 - doc/progs/interface.go | 62 - doc/progs/interface2.go | 132 - doc/progs/json1.go | 88 - doc/progs/json2.go | 42 - doc/progs/json3.go | 73 - doc/progs/json4.go | 45 - doc/progs/json5.go | 31 - doc/progs/run.go | 229 -- doc/progs/slices.go | 63 - doc/progs/timeout1.go | 29 - doc/progs/timeout2.go | 28 - doc/share.png | Bin 2993 -> 0 bytes doc/tos.html | 11 - src/cmd/dist/test.go | 8 - 143 files changed, 34682 deletions(-) delete mode 100644 doc/articles/go_command.html delete mode 100644 doc/articles/index.html delete mode 100644 doc/articles/race_detector.html delete mode 100644 doc/articles/wiki/edit.html delete mode 100644 doc/articles/wiki/final-noclosure.go delete mode 100644 doc/articles/wiki/final-noerror.go delete mode 100644 doc/articles/wiki/final-parsetemplate.go delete mode 100644 doc/articles/wiki/final-template.go delete mode 100644 doc/articles/wiki/final.go delete mode 100644 doc/articles/wiki/final_test.go delete mode 100644 doc/articles/wiki/go.mod delete mode 100644 doc/articles/wiki/http-sample.go delete mode 100644 doc/articles/wiki/index.html delete mode 100644 doc/articles/wiki/notemplate.go delete mode 100644 doc/articles/wiki/part1-noerror.go delete mode 100644 doc/articles/wiki/part1.go delete mode 100644 doc/articles/wiki/part2.go delete mode 100644 doc/articles/wiki/part3-errorhandling.go delete mode 100644 doc/articles/wiki/part3.go delete mode 100644 doc/articles/wiki/test_Test.txt.good delete mode 100644 doc/articles/wiki/test_edit.good delete mode 100644 doc/articles/wiki/test_view.good delete mode 100644 doc/articles/wiki/view.html delete mode 100644 doc/articles/wiki/wiki_test.go delete mode 100644 doc/cmd.html delete mode 100644 doc/codewalk/codewalk.css delete mode 100644 doc/codewalk/codewalk.js delete mode 100644 doc/codewalk/codewalk.xml delete mode 100644 doc/codewalk/codewalk_test.go delete mode 100644 doc/codewalk/functions.xml delete mode 100644 doc/codewalk/markov.go delete mode 100644 doc/codewalk/markov.xml delete mode 100644 doc/codewalk/pig.go delete mode 100644 doc/codewalk/popout.png delete mode 100644 doc/codewalk/sharemem.xml delete mode 100644 doc/codewalk/urlpoll.go delete mode 100644 doc/contribute.html delete mode 100644 doc/debugging_with_gdb.html delete mode 100644 doc/diagnostics.html delete mode 100644 doc/editors.html delete mode 100644 doc/effective_go.html delete mode 100644 doc/gccgo_contribute.html delete mode 100644 doc/gccgo_install.html delete mode 100644 doc/go-logo-black.png delete mode 100644 doc/go-logo-blue.png delete mode 100644 doc/go-logo-white.png delete mode 100644 doc/go1.1.html delete mode 100644 doc/go1.10.html delete mode 100644 doc/go1.11.html delete mode 100644 doc/go1.12.html delete mode 100644 doc/go1.13.html delete mode 100644 doc/go1.14.html delete mode 100644 doc/go1.15.html delete mode 100644 doc/go1.2.html delete mode 100644 doc/go1.3.html delete mode 100644 doc/go1.4.html delete mode 100644 doc/go1.5.html delete mode 100644 doc/go1.6.html delete mode 100644 doc/go1.7.html delete mode 100644 doc/go1.8.html delete mode 100644 doc/go1.9.html delete mode 100644 doc/go1.html delete mode 100644 doc/go1compat.html delete mode 100644 doc/go_faq.html delete mode 100644 doc/gopher/README delete mode 100644 doc/gopher/appenginegopher.jpg delete mode 100644 doc/gopher/appenginegophercolor.jpg delete mode 100644 doc/gopher/appenginelogo.gif delete mode 100644 doc/gopher/biplane.jpg delete mode 100644 doc/gopher/bumper.png delete mode 100644 doc/gopher/bumper192x108.png delete mode 100644 doc/gopher/bumper320x180.png delete mode 100644 doc/gopher/bumper480x270.png delete mode 100644 doc/gopher/bumper640x360.png delete mode 100644 doc/gopher/doc.png delete mode 100644 doc/gopher/favicon.svg delete mode 100644 doc/gopher/fiveyears.jpg delete mode 100644 doc/gopher/frontpage.png delete mode 100644 doc/gopher/gopherbw.png delete mode 100644 doc/gopher/gophercolor.png delete mode 100644 doc/gopher/gophercolor16x16.png delete mode 100644 doc/gopher/help.png delete mode 100644 doc/gopher/modelsheet.jpg delete mode 100644 doc/gopher/pencil/gopherhat.jpg delete mode 100644 doc/gopher/pencil/gopherhelmet.jpg delete mode 100644 doc/gopher/pencil/gophermega.jpg delete mode 100644 doc/gopher/pencil/gopherrunning.jpg delete mode 100644 doc/gopher/pencil/gopherswim.jpg delete mode 100644 doc/gopher/pencil/gopherswrench.jpg delete mode 100644 doc/gopher/pkg.png delete mode 100644 doc/gopher/project.png delete mode 100644 doc/gopher/ref.png delete mode 100644 doc/gopher/run.png delete mode 100644 doc/gopher/talks.png delete mode 100644 doc/help.html delete mode 100644 doc/ie.css delete mode 100644 doc/play/fib.go delete mode 100644 doc/play/hello.go delete mode 100644 doc/play/life.go delete mode 100644 doc/play/peano.go delete mode 100644 doc/play/pi.go delete mode 100644 doc/play/sieve.go delete mode 100644 doc/play/solitaire.go delete mode 100644 doc/play/tree.go delete mode 100644 doc/progs/cgo1.go delete mode 100644 doc/progs/cgo2.go delete mode 100644 doc/progs/cgo3.go delete mode 100644 doc/progs/cgo4.go delete mode 100644 doc/progs/defer.go delete mode 100644 doc/progs/defer2.go delete mode 100644 doc/progs/eff_bytesize.go delete mode 100644 doc/progs/eff_qr.go delete mode 100644 doc/progs/eff_sequence.go delete mode 100644 doc/progs/eff_unused1.go delete mode 100644 doc/progs/eff_unused2.go delete mode 100644 doc/progs/error.go delete mode 100644 doc/progs/error2.go delete mode 100644 doc/progs/error3.go delete mode 100644 doc/progs/error4.go delete mode 100644 doc/progs/go1.go delete mode 100644 doc/progs/gobs1.go delete mode 100644 doc/progs/gobs2.go delete mode 100644 doc/progs/image_draw.go delete mode 100644 doc/progs/image_package1.go delete mode 100644 doc/progs/image_package2.go delete mode 100644 doc/progs/image_package3.go delete mode 100644 doc/progs/image_package4.go delete mode 100644 doc/progs/image_package5.go delete mode 100644 doc/progs/image_package6.go delete mode 100644 doc/progs/interface.go delete mode 100644 doc/progs/interface2.go delete mode 100644 doc/progs/json1.go delete mode 100644 doc/progs/json2.go delete mode 100644 doc/progs/json3.go delete mode 100644 doc/progs/json4.go delete mode 100644 doc/progs/json5.go delete mode 100644 doc/progs/run.go delete mode 100644 doc/progs/slices.go delete mode 100644 doc/progs/timeout1.go delete mode 100644 doc/progs/timeout2.go delete mode 100644 doc/share.png delete mode 100644 doc/tos.html diff --git a/doc/articles/go_command.html b/doc/articles/go_command.html deleted file mode 100644 index 5b6fd4d24b..0000000000 --- a/doc/articles/go_command.html +++ /dev/null @@ -1,254 +0,0 @@ - - -

The Go distribution includes a command, named -"go", that -automates the downloading, building, installation, and testing of Go packages -and commands. This document talks about why we wrote a new command, what it -is, what it's not, and how to use it.

- -

Motivation

- -

You might have seen early Go talks in which Rob Pike jokes that the idea -for Go arose while waiting for a large Google server to compile. That -really was the motivation for Go: to build a language that worked well -for building the large software that Google writes and runs. It was -clear from the start that such a language must provide a way to -express dependencies between code libraries clearly, hence the package -grouping and the explicit import blocks. It was also clear from the -start that you might want arbitrary syntax for describing the code -being imported; this is why import paths are string literals.

- -

An explicit goal for Go from the beginning was to be able to build Go -code using only the information found in the source itself, not -needing to write a makefile or one of the many modern replacements for -makefiles. If Go needed a configuration file to explain how to build -your program, then Go would have failed.

- -

At first, there was no Go compiler, and the initial development -focused on building one and then building libraries for it. For -expedience, we postponed the automation of building Go code by using -make and writing makefiles. When compiling a single package involved -multiple invocations of the Go compiler, we even used a program to -write the makefiles for us. You can find it if you dig through the -repository history.

- -

The purpose of the new go command is our return to this ideal, that Go -programs should compile without configuration or additional effort on -the part of the developer beyond writing the necessary import -statements.

- -

Configuration versus convention

- -

The way to achieve the simplicity of a configuration-free system is to -establish conventions. The system works only to the extent that those conventions -are followed. When we first launched Go, many people published packages that -had to be installed in certain places, under certain names, using certain build -tools, in order to be used. That's understandable: that's the way it works in -most other languages. Over the last few years we consistently reminded people -about the goinstall command -(now replaced by go get) -and its conventions: first, that the import path is derived in a known way from -the URL of the source code; second, that the place to store the sources in -the local file system is derived in a known way from the import path; third, -that each directory in a source tree corresponds to a single package; and -fourth, that the package is built using only information in the source code. -Today, the vast majority of packages follow these conventions. -The Go ecosystem is simpler and more powerful as a result.

- -

We received many requests to allow a makefile in a package directory to -provide just a little extra configuration beyond what's in the source code. -But that would have introduced new rules. Because we did not accede to such -requests, we were able to write the go command and eliminate our use of make -or any other build system.

- -

It is important to understand that the go command is not a general -build tool. It cannot be configured and it does not attempt to build -anything but Go packages. These are important simplifying -assumptions: they simplify not only the implementation but also, more -important, the use of the tool itself.

- -

Go's conventions

- -

The go command requires that code adheres to a few key, -well-established conventions.

- -

First, the import path is derived in a known way from the URL of the -source code. For Bitbucket, GitHub, Google Code, and Launchpad, the -root directory of the repository is identified by the repository's -main URL, without the http:// prefix. Subdirectories are named by -adding to that path. -For example, the Go example programs are obtained by running

- -
-git clone https://github.com/golang/example
-
- -

and thus the import path for the root directory of that repository is -"github.com/golang/example". -The stringutil -package is stored in a subdirectory, so its import path is -"github.com/golang/example/stringutil".

- -

These paths are on the long side, but in exchange we get an -automatically managed name space for import paths and the ability for -a tool like the go command to look at an unfamiliar import path and -deduce where to obtain the source code.

- -

Second, the place to store sources in the local file system is derived -in a known way from the import path, specifically -$GOPATH/src/<import-path>. -If unset, $GOPATH defaults to a subdirectory -named go in the user's home directory. -If $GOPATH is set to a list of paths, the go command tries -<dir>/src/<import-path> for each of the directories in -that list. -

- -

Each of those trees contains, by convention, a top-level directory named -"bin", for holding compiled executables, and a top-level directory -named "pkg", for holding compiled packages that can be imported, -and the "src" directory, for holding package source files. -Imposing this structure lets us keep each of these directory trees -self-contained: the compiled form and the sources are always near each -other.

- -

These naming conventions also let us work in the reverse direction, -from a directory name to its import path. This mapping is important -for many of the go command's subcommands, as we'll see below.

- -

Third, each directory in a source tree corresponds to a single -package. By restricting a directory to a single package, we don't have -to create hybrid import paths that specify first the directory and -then the package within that directory. Also, most file management -tools and UIs work on directories as fundamental units. Tying the -fundamental Go unit—the package—to file system structure means -that file system tools become Go package tools. Copying, moving, or -deleting a package corresponds to copying, moving, or deleting a -directory.

- -

Fourth, each package is built using only the information present in -the source files. This makes it much more likely that the tool will -be able to adapt to changing build environments and conditions. For -example, if we allowed extra configuration such as compiler flags or -command line recipes, then that configuration would need to be updated -each time the build tools changed; it would also be inherently tied -to the use of a specific toolchain.

- -

Getting started with the go command

- -

Finally, a quick tour of how to use the go command. -As mentioned above, the default $GOPATH on Unix is $HOME/go. -We'll store our programs there. -To use a different location, you can set $GOPATH; -see How to Write Go Code for details. - -

We first add some source code. Suppose we want to use -the indexing library from the codesearch project along with a left-leaning -red-black tree. We can install both with the "go get" -subcommand:

- -
-$ go get github.com/google/codesearch/index
-$ go get github.com/petar/GoLLRB/llrb
-$
-
- -

Both of these projects are now downloaded and installed into $HOME/go, -which contains the two directories -src/github.com/google/codesearch/index/ and -src/github.com/petar/GoLLRB/llrb/, along with the compiled -packages (in pkg/) for those libraries and their dependencies.

- -

Because we used version control systems (Mercurial and Git) to check -out the sources, the source tree also contains the other files in the -corresponding repositories, such as related packages. The "go list" -subcommand lists the import paths corresponding to its arguments, and -the pattern "./..." means start in the current directory -("./") and find all packages below that directory -("..."):

- -
-$ cd $HOME/go/src
-$ go list ./...
-github.com/google/codesearch/cmd/cgrep
-github.com/google/codesearch/cmd/cindex
-github.com/google/codesearch/cmd/csearch
-github.com/google/codesearch/index
-github.com/google/codesearch/regexp
-github.com/google/codesearch/sparse
-github.com/petar/GoLLRB/example
-github.com/petar/GoLLRB/llrb
-$
-
- -

We can also test those packages:

- -
-$ go test ./...
-?   	github.com/google/codesearch/cmd/cgrep	[no test files]
-?   	github.com/google/codesearch/cmd/cindex	[no test files]
-?   	github.com/google/codesearch/cmd/csearch	[no test files]
-ok  	github.com/google/codesearch/index	0.203s
-ok  	github.com/google/codesearch/regexp	0.017s
-?   	github.com/google/codesearch/sparse	[no test files]
-?       github.com/petar/GoLLRB/example          [no test files]
-ok      github.com/petar/GoLLRB/llrb             0.231s
-$
-
- -

If a go subcommand is invoked with no paths listed, it operates on the -current directory:

- -
-$ cd github.com/google/codesearch/regexp
-$ go list
-github.com/google/codesearch/regexp
-$ go test -v
-=== RUN   TestNstateEnc
---- PASS: TestNstateEnc (0.00s)
-=== RUN   TestMatch
---- PASS: TestMatch (0.00s)
-=== RUN   TestGrep
---- PASS: TestGrep (0.00s)
-PASS
-ok  	github.com/google/codesearch/regexp	0.018s
-$ go install
-$
-
- -

That "go install" subcommand installs the latest copy of the -package into the pkg directory. Because the go command can analyze the -dependency graph, "go install" also installs any packages that -this package imports but that are out of date, recursively.

- -

Notice that "go install" was able to determine the name of the -import path for the package in the current directory, because of the convention -for directory naming. It would be a little more convenient if we could pick -the name of the directory where we kept source code, and we probably wouldn't -pick such a long name, but that ability would require additional configuration -and complexity in the tool. Typing an extra directory name or two is a small -price to pay for the increased simplicity and power.

- -

Limitations

- -

As mentioned above, the go command is not a general-purpose build -tool. -In particular, it does not have any facility for generating Go -source files during a build, although it does provide -go -generate, -which can automate the creation of Go files before the build. -For more advanced build setups, you may need to write a -makefile (or a configuration file for the build tool of your choice) -to run whatever tool creates the Go files and then check those generated source files -into your repository. This is more work for you, the package author, -but it is significantly less work for your users, who can use -"go get" without needing to obtain and build -any additional tools.

- -

More information

- -

For more information, read How to Write Go Code -and see the go command documentation.

diff --git a/doc/articles/index.html b/doc/articles/index.html deleted file mode 100644 index 9ddd669731..0000000000 --- a/doc/articles/index.html +++ /dev/null @@ -1,8 +0,0 @@ - - -

-See the Documents page and the -Blog index for a complete list of Go articles. -

diff --git a/doc/articles/race_detector.html b/doc/articles/race_detector.html deleted file mode 100644 index 09188c15d5..0000000000 --- a/doc/articles/race_detector.html +++ /dev/null @@ -1,440 +0,0 @@ - - -

Introduction

- -

-Data races are among the most common and hardest to debug types of bugs in concurrent systems. -A data race occurs when two goroutines access the same variable concurrently and at least one of the accesses is a write. -See the The Go Memory Model for details. -

- -

-Here is an example of a data race that can lead to crashes and memory corruption: -

- -
-func main() {
-	c := make(chan bool)
-	m := make(map[string]string)
-	go func() {
-		m["1"] = "a" // First conflicting access.
-		c <- true
-	}()
-	m["2"] = "b" // Second conflicting access.
-	<-c
-	for k, v := range m {
-		fmt.Println(k, v)
-	}
-}
-
- -

Usage

- -

-To help diagnose such bugs, Go includes a built-in data race detector. -To use it, add the -race flag to the go command: -

- -
-$ go test -race mypkg    // to test the package
-$ go run -race mysrc.go  // to run the source file
-$ go build -race mycmd   // to build the command
-$ go install -race mypkg // to install the package
-
- -

Report Format

- -

-When the race detector finds a data race in the program, it prints a report. -The report contains stack traces for conflicting accesses, as well as stacks where the involved goroutines were created. -Here is an example: -

- -
-WARNING: DATA RACE
-Read by goroutine 185:
-  net.(*pollServer).AddFD()
-      src/net/fd_unix.go:89 +0x398
-  net.(*pollServer).WaitWrite()
-      src/net/fd_unix.go:247 +0x45
-  net.(*netFD).Write()
-      src/net/fd_unix.go:540 +0x4d4
-  net.(*conn).Write()
-      src/net/net.go:129 +0x101
-  net.func·060()
-      src/net/timeout_test.go:603 +0xaf
-
-Previous write by goroutine 184:
-  net.setWriteDeadline()
-      src/net/sockopt_posix.go:135 +0xdf
-  net.setDeadline()
-      src/net/sockopt_posix.go:144 +0x9c
-  net.(*conn).SetDeadline()
-      src/net/net.go:161 +0xe3
-  net.func·061()
-      src/net/timeout_test.go:616 +0x3ed
-
-Goroutine 185 (running) created at:
-  net.func·061()
-      src/net/timeout_test.go:609 +0x288
-
-Goroutine 184 (running) created at:
-  net.TestProlongTimeout()
-      src/net/timeout_test.go:618 +0x298
-  testing.tRunner()
-      src/testing/testing.go:301 +0xe8
-
- -

Options

- -

-The GORACE environment variable sets race detector options. -The format is: -

- -
-GORACE="option1=val1 option2=val2"
-
- -

-The options are: -

- -
    -
  • -log_path (default stderr): The race detector writes -its report to a file named log_path.pid. -The special names stdout -and stderr cause reports to be written to standard output and -standard error, respectively. -
  • - -
  • -exitcode (default 66): The exit status to use when -exiting after a detected race. -
  • - -
  • -strip_path_prefix (default ""): Strip this prefix -from all reported file paths, to make reports more concise. -
  • - -
  • -history_size (default 1): The per-goroutine memory -access history is 32K * 2**history_size elements. -Increasing this value can avoid a "failed to restore the stack" error in reports, at the -cost of increased memory usage. -
  • - -
  • -halt_on_error (default 0): Controls whether the program -exits after reporting first data race. -
  • - -
  • -atexit_sleep_ms (default 1000): Amount of milliseconds -to sleep in the main goroutine before exiting. -
  • -
- -

-Example: -

- -
-$ GORACE="log_path=/tmp/race/report strip_path_prefix=/my/go/sources/" go test -race
-
- -

Excluding Tests

- -

-When you build with -race flag, the go command defines additional -build tag race. -You can use the tag to exclude some code and tests when running the race detector. -Some examples: -

- -
-// +build !race
-
-package foo
-
-// The test contains a data race. See issue 123.
-func TestFoo(t *testing.T) {
-	// ...
-}
-
-// The test fails under the race detector due to timeouts.
-func TestBar(t *testing.T) {
-	// ...
-}
-
-// The test takes too long under the race detector.
-func TestBaz(t *testing.T) {
-	// ...
-}
-
- -

How To Use

- -

-To start, run your tests using the race detector (go test -race). -The race detector only finds races that happen at runtime, so it can't find -races in code paths that are not executed. -If your tests have incomplete coverage, -you may find more races by running a binary built with -race under a realistic -workload. -

- -

Typical Data Races

- -

-Here are some typical data races. All of them can be detected with the race detector. -

- -

Race on loop counter

- -
-func main() {
-	var wg sync.WaitGroup
-	wg.Add(5)
-	for i := 0; i < 5; i++ {
-		go func() {
-			fmt.Println(i) // Not the 'i' you are looking for.
-			wg.Done()
-		}()
-	}
-	wg.Wait()
-}
-
- -

-The variable i in the function literal is the same variable used by the loop, so -the read in the goroutine races with the loop increment. -(This program typically prints 55555, not 01234.) -The program can be fixed by making a copy of the variable: -

- -
-func main() {
-	var wg sync.WaitGroup
-	wg.Add(5)
-	for i := 0; i < 5; i++ {
-		go func(j int) {
-			fmt.Println(j) // Good. Read local copy of the loop counter.
-			wg.Done()
-		}(i)
-	}
-	wg.Wait()
-}
-
- -

Accidentally shared variable

- -
-// ParallelWrite writes data to file1 and file2, returns the errors.
-func ParallelWrite(data []byte) chan error {
-	res := make(chan error, 2)
-	f1, err := os.Create("file1")
-	if err != nil {
-		res <- err
-	} else {
-		go func() {
-			// This err is shared with the main goroutine,
-			// so the write races with the write below.
-			_, err = f1.Write(data)
-			res <- err
-			f1.Close()
-		}()
-	}
-	f2, err := os.Create("file2") // The second conflicting write to err.
-	if err != nil {
-		res <- err
-	} else {
-		go func() {
-			_, err = f2.Write(data)
-			res <- err
-			f2.Close()
-		}()
-	}
-	return res
-}
-
- -

-The fix is to introduce new variables in the goroutines (note the use of :=): -

- -
-			...
-			_, err := f1.Write(data)
-			...
-			_, err := f2.Write(data)
-			...
-
- -

Unprotected global variable

- -

-If the following code is called from several goroutines, it leads to races on the service map. -Concurrent reads and writes of the same map are not safe: -

- -
-var service map[string]net.Addr
-
-func RegisterService(name string, addr net.Addr) {
-	service[name] = addr
-}
-
-func LookupService(name string) net.Addr {
-	return service[name]
-}
-
- -

-To make the code safe, protect the accesses with a mutex: -

- -
-var (
-	service   map[string]net.Addr
-	serviceMu sync.Mutex
-)
-
-func RegisterService(name string, addr net.Addr) {
-	serviceMu.Lock()
-	defer serviceMu.Unlock()
-	service[name] = addr
-}
-
-func LookupService(name string) net.Addr {
-	serviceMu.Lock()
-	defer serviceMu.Unlock()
-	return service[name]
-}
-
- -

Primitive unprotected variable

- -

-Data races can happen on variables of primitive types as well (bool, int, int64, etc.), -as in this example: -

- -
-type Watchdog struct{ last int64 }
-
-func (w *Watchdog) KeepAlive() {
-	w.last = time.Now().UnixNano() // First conflicting access.
-}
-
-func (w *Watchdog) Start() {
-	go func() {
-		for {
-			time.Sleep(time.Second)
-			// Second conflicting access.
-			if w.last < time.Now().Add(-10*time.Second).UnixNano() {
-				fmt.Println("No keepalives for 10 seconds. Dying.")
-				os.Exit(1)
-			}
-		}
-	}()
-}
-
- -

-Even such "innocent" data races can lead to hard-to-debug problems caused by -non-atomicity of the memory accesses, -interference with compiler optimizations, -or reordering issues accessing processor memory . -

- -

-A typical fix for this race is to use a channel or a mutex. -To preserve the lock-free behavior, one can also use the -sync/atomic package. -

- -
-type Watchdog struct{ last int64 }
-
-func (w *Watchdog) KeepAlive() {
-	atomic.StoreInt64(&w.last, time.Now().UnixNano())
-}
-
-func (w *Watchdog) Start() {
-	go func() {
-		for {
-			time.Sleep(time.Second)
-			if atomic.LoadInt64(&w.last) < time.Now().Add(-10*time.Second).UnixNano() {
-				fmt.Println("No keepalives for 10 seconds. Dying.")
-				os.Exit(1)
-			}
-		}
-	}()
-}
-
- -

Unsynchronized send and close operations

- -

-As this example demonstrates, unsynchronized send and close operations -on the same channel can also be a race condition: -

- -
-c := make(chan struct{}) // or buffered channel
-
-// The race detector cannot derive the happens before relation
-// for the following send and close operations. These two operations
-// are unsynchronized and happen concurrently.
-go func() { c <- struct{}{} }()
-close(c)
-
- -

-According to the Go memory model, a send on a channel happens before -the corresponding receive from that channel completes. To synchronize -send and close operations, use a receive operation that guarantees -the send is done before the close: -

- -
-c := make(chan struct{}) // or buffered channel
-
-go func() { c <- struct{}{} }()
-<-c
-close(c)
-
- -

Supported Systems

- -

- The race detector runs on - linux/amd64, linux/ppc64le, - linux/arm64, freebsd/amd64, - netbsd/amd64, darwin/amd64, - darwin/arm64, and windows/amd64. -

- -

Runtime Overhead

- -

-The cost of race detection varies by program, but for a typical program, memory -usage may increase by 5-10x and execution time by 2-20x. -

- -

-The race detector currently allocates an extra 8 bytes per defer -and recover statement. Those extra allocations are not recovered until the goroutine -exits. This means that if you have a long-running goroutine that is -periodically issuing defer and recover calls, -the program memory usage may grow without bound. These memory allocations -will not show up in the output of runtime.ReadMemStats or -runtime/pprof. -

diff --git a/doc/articles/wiki/edit.html b/doc/articles/wiki/edit.html deleted file mode 100644 index 044c3bedea..0000000000 --- a/doc/articles/wiki/edit.html +++ /dev/null @@ -1,6 +0,0 @@ -

Editing {{.Title}}

- -
-
-
-
diff --git a/doc/articles/wiki/final-noclosure.go b/doc/articles/wiki/final-noclosure.go deleted file mode 100644 index d894e7d319..0000000000 --- a/doc/articles/wiki/final-noclosure.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "errors" - "html/template" - "io/ioutil" - "log" - "net/http" - "regexp" -) - -type Page struct { - Title string - Body []byte -} - -func (p *Page) save() error { - filename := p.Title + ".txt" - return ioutil.WriteFile(filename, p.Body, 0600) -} - -func loadPage(title string) (*Page, error) { - filename := title + ".txt" - body, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - return &Page{Title: title, Body: body}, nil -} - -func viewHandler(w http.ResponseWriter, r *http.Request) { - title, err := getTitle(w, r) - if err != nil { - return - } - p, err := loadPage(title) - if err != nil { - http.Redirect(w, r, "/edit/"+title, http.StatusFound) - return - } - renderTemplate(w, "view", p) -} - -func editHandler(w http.ResponseWriter, r *http.Request) { - title, err := getTitle(w, r) - if err != nil { - return - } - p, err := loadPage(title) - if err != nil { - p = &Page{Title: title} - } - renderTemplate(w, "edit", p) -} - -func saveHandler(w http.ResponseWriter, r *http.Request) { - title, err := getTitle(w, r) - if err != nil { - return - } - body := r.FormValue("body") - p := &Page{Title: title, Body: []byte(body)} - err = p.save() - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - http.Redirect(w, r, "/view/"+title, http.StatusFound) -} - -func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { - t, err := template.ParseFiles(tmpl + ".html") - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - err = t.Execute(w, p) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } -} - -var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$") - -func getTitle(w http.ResponseWriter, r *http.Request) (string, error) { - m := validPath.FindStringSubmatch(r.URL.Path) - if m == nil { - http.NotFound(w, r) - return "", errors.New("invalid Page Title") - } - return m[2], nil // The title is the second subexpression. -} - -func main() { - http.HandleFunc("/view/", viewHandler) - http.HandleFunc("/edit/", editHandler) - http.HandleFunc("/save/", saveHandler) - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/doc/articles/wiki/final-noerror.go b/doc/articles/wiki/final-noerror.go deleted file mode 100644 index 250236d42e..0000000000 --- a/doc/articles/wiki/final-noerror.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "html/template" - "io/ioutil" - "log" - "net/http" -) - -type Page struct { - Title string - Body []byte -} - -func (p *Page) save() error { - filename := p.Title + ".txt" - return ioutil.WriteFile(filename, p.Body, 0600) -} - -func loadPage(title string) (*Page, error) { - filename := title + ".txt" - body, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - return &Page{Title: title, Body: body}, nil -} - -func editHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/edit/"):] - p, err := loadPage(title) - if err != nil { - p = &Page{Title: title} - } - t, _ := template.ParseFiles("edit.html") - t.Execute(w, p) -} - -func viewHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/view/"):] - p, _ := loadPage(title) - t, _ := template.ParseFiles("view.html") - t.Execute(w, p) -} - -func main() { - http.HandleFunc("/view/", viewHandler) - http.HandleFunc("/edit/", editHandler) - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/doc/articles/wiki/final-parsetemplate.go b/doc/articles/wiki/final-parsetemplate.go deleted file mode 100644 index 0b90cbd3bc..0000000000 --- a/doc/articles/wiki/final-parsetemplate.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "html/template" - "io/ioutil" - "log" - "net/http" - "regexp" -) - -type Page struct { - Title string - Body []byte -} - -func (p *Page) save() error { - filename := p.Title + ".txt" - return ioutil.WriteFile(filename, p.Body, 0600) -} - -func loadPage(title string) (*Page, error) { - filename := title + ".txt" - body, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - return &Page{Title: title, Body: body}, nil -} - -func viewHandler(w http.ResponseWriter, r *http.Request, title string) { - p, err := loadPage(title) - if err != nil { - http.Redirect(w, r, "/edit/"+title, http.StatusFound) - return - } - renderTemplate(w, "view", p) -} - -func editHandler(w http.ResponseWriter, r *http.Request, title string) { - p, err := loadPage(title) - if err != nil { - p = &Page{Title: title} - } - renderTemplate(w, "edit", p) -} - -func saveHandler(w http.ResponseWriter, r *http.Request, title string) { - body := r.FormValue("body") - p := &Page{Title: title, Body: []byte(body)} - err := p.save() - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - http.Redirect(w, r, "/view/"+title, http.StatusFound) -} - -func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { - t, err := template.ParseFiles(tmpl + ".html") - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - err = t.Execute(w, p) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } -} - -var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$") - -func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - m := validPath.FindStringSubmatch(r.URL.Path) - if m == nil { - http.NotFound(w, r) - return - } - fn(w, r, m[2]) - } -} - -func main() { - http.HandleFunc("/view/", makeHandler(viewHandler)) - http.HandleFunc("/edit/", makeHandler(editHandler)) - http.HandleFunc("/save/", makeHandler(saveHandler)) - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/doc/articles/wiki/final-template.go b/doc/articles/wiki/final-template.go deleted file mode 100644 index 5028664fe8..0000000000 --- a/doc/articles/wiki/final-template.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "html/template" - "io/ioutil" - "log" - "net/http" -) - -type Page struct { - Title string - Body []byte -} - -func (p *Page) save() error { - filename := p.Title + ".txt" - return ioutil.WriteFile(filename, p.Body, 0600) -} - -func loadPage(title string) (*Page, error) { - filename := title + ".txt" - body, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - return &Page{Title: title, Body: body}, nil -} - -func editHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/edit/"):] - p, err := loadPage(title) - if err != nil { - p = &Page{Title: title} - } - renderTemplate(w, "edit", p) -} - -func viewHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/view/"):] - p, _ := loadPage(title) - renderTemplate(w, "view", p) -} - -func saveHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/save/"):] - body := r.FormValue("body") - p := &Page{Title: title, Body: []byte(body)} - p.save() - http.Redirect(w, r, "/view/"+title, http.StatusFound) -} - -func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { - t, _ := template.ParseFiles(tmpl + ".html") - t.Execute(w, p) -} - -func main() { - http.HandleFunc("/view/", viewHandler) - http.HandleFunc("/edit/", editHandler) - http.HandleFunc("/save/", saveHandler) - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/doc/articles/wiki/final.go b/doc/articles/wiki/final.go deleted file mode 100644 index b1439b08a9..0000000000 --- a/doc/articles/wiki/final.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "html/template" - "io/ioutil" - "log" - "net/http" - "regexp" -) - -type Page struct { - Title string - Body []byte -} - -func (p *Page) save() error { - filename := p.Title + ".txt" - return ioutil.WriteFile(filename, p.Body, 0600) -} - -func loadPage(title string) (*Page, error) { - filename := title + ".txt" - body, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - return &Page{Title: title, Body: body}, nil -} - -func viewHandler(w http.ResponseWriter, r *http.Request, title string) { - p, err := loadPage(title) - if err != nil { - http.Redirect(w, r, "/edit/"+title, http.StatusFound) - return - } - renderTemplate(w, "view", p) -} - -func editHandler(w http.ResponseWriter, r *http.Request, title string) { - p, err := loadPage(title) - if err != nil { - p = &Page{Title: title} - } - renderTemplate(w, "edit", p) -} - -func saveHandler(w http.ResponseWriter, r *http.Request, title string) { - body := r.FormValue("body") - p := &Page{Title: title, Body: []byte(body)} - err := p.save() - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - http.Redirect(w, r, "/view/"+title, http.StatusFound) -} - -var templates = template.Must(template.ParseFiles("edit.html", "view.html")) - -func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { - err := templates.ExecuteTemplate(w, tmpl+".html", p) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } -} - -var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$") - -func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - m := validPath.FindStringSubmatch(r.URL.Path) - if m == nil { - http.NotFound(w, r) - return - } - fn(w, r, m[2]) - } -} - -func main() { - http.HandleFunc("/view/", makeHandler(viewHandler)) - http.HandleFunc("/edit/", makeHandler(editHandler)) - http.HandleFunc("/save/", makeHandler(saveHandler)) - - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/doc/articles/wiki/final_test.go b/doc/articles/wiki/final_test.go deleted file mode 100644 index 764469976e..0000000000 --- a/doc/articles/wiki/final_test.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "fmt" - "log" - "net" - "net/http" -) - -func serve() error { - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - log.Fatal(err) - } - fmt.Println(l.Addr().String()) - s := &http.Server{} - return s.Serve(l) -} diff --git a/doc/articles/wiki/go.mod b/doc/articles/wiki/go.mod deleted file mode 100644 index 38153ed79f..0000000000 --- a/doc/articles/wiki/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module doc/articles/wiki - -go 1.14 diff --git a/doc/articles/wiki/http-sample.go b/doc/articles/wiki/http-sample.go deleted file mode 100644 index 803b88c4eb..0000000000 --- a/doc/articles/wiki/http-sample.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build ignore - -package main - -import ( - "fmt" - "log" - "net/http" -) - -func handler(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) -} - -func main() { - http.HandleFunc("/", handler) - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/doc/articles/wiki/index.html b/doc/articles/wiki/index.html deleted file mode 100644 index a74a58e317..0000000000 --- a/doc/articles/wiki/index.html +++ /dev/null @@ -1,741 +0,0 @@ - - -

Introduction

- -

-Covered in this tutorial: -

-
    -
  • Creating a data structure with load and save methods
  • -
  • Using the net/http package to build web applications -
  • Using the html/template package to process HTML templates
  • -
  • Using the regexp package to validate user input
  • -
  • Using closures
  • -
- -

-Assumed knowledge: -

-
    -
  • Programming experience
  • -
  • Understanding of basic web technologies (HTTP, HTML)
  • -
  • Some UNIX/DOS command-line knowledge
  • -
- -

Getting Started

- -

-At present, you need to have a FreeBSD, Linux, OS X, or Windows machine to run Go. -We will use $ to represent the command prompt. -

- -

-Install Go (see the Installation Instructions). -

- -

-Make a new directory for this tutorial inside your GOPATH and cd to it: -

- -
-$ mkdir gowiki
-$ cd gowiki
-
- -

-Create a file named wiki.go, open it in your favorite editor, and -add the following lines: -

- -
-package main
-
-import (
-	"fmt"
-	"io/ioutil"
-)
-
- -

-We import the fmt and ioutil packages from the Go -standard library. Later, as we implement additional functionality, we will -add more packages to this import declaration. -

- -

Data Structures

- -

-Let's start by defining the data structures. A wiki consists of a series of -interconnected pages, each of which has a title and a body (the page content). -Here, we define Page as a struct with two fields representing -the title and body. -

- -{{code "doc/articles/wiki/part1.go" `/^type Page/` `/}/`}} - -

-The type []byte means "a byte slice". -(See Slices: usage and -internals for more on slices.) -The Body element is a []byte rather than -string because that is the type expected by the io -libraries we will use, as you'll see below. -

- -

-The Page struct describes how page data will be stored in memory. -But what about persistent storage? We can address that by creating a -save method on Page: -

- -{{code "doc/articles/wiki/part1.go" `/^func.*Page.*save/` `/}/`}} - -

-This method's signature reads: "This is a method named save that -takes as its receiver p, a pointer to Page . It takes -no parameters, and returns a value of type error." -

- -

-This method will save the Page's Body to a text -file. For simplicity, we will use the Title as the file name. -

- -

-The save method returns an error value because -that is the return type of WriteFile (a standard library function -that writes a byte slice to a file). The save method returns the -error value, to let the application handle it should anything go wrong while -writing the file. If all goes well, Page.save() will return -nil (the zero-value for pointers, interfaces, and some other -types). -

- -

-The octal integer literal 0600, passed as the third parameter to -WriteFile, indicates that the file should be created with -read-write permissions for the current user only. (See the Unix man page -open(2) for details.) -

- -

-In addition to saving pages, we will want to load pages, too: -

- -{{code "doc/articles/wiki/part1-noerror.go" `/^func loadPage/` `/^}/`}} - -

-The function loadPage constructs the file name from the title -parameter, reads the file's contents into a new variable body, and -returns a pointer to a Page literal constructed with the proper -title and body values. -

- -

-Functions can return multiple values. The standard library function -io.ReadFile returns []byte and error. -In loadPage, error isn't being handled yet; the "blank identifier" -represented by the underscore (_) symbol is used to throw away the -error return value (in essence, assigning the value to nothing). -

- -

-But what happens if ReadFile encounters an error? For example, -the file might not exist. We should not ignore such errors. Let's modify the -function to return *Page and error. -

- -{{code "doc/articles/wiki/part1.go" `/^func loadPage/` `/^}/`}} - -

-Callers of this function can now check the second parameter; if it is -nil then it has successfully loaded a Page. If not, it will be an -error that can be handled by the caller (see the -language specification for details). -

- -

-At this point we have a simple data structure and the ability to save to and -load from a file. Let's write a main function to test what we've -written: -

- -{{code "doc/articles/wiki/part1.go" `/^func main/` `/^}/`}} - -

-After compiling and executing this code, a file named TestPage.txt -would be created, containing the contents of p1. The file would -then be read into the struct p2, and its Body element -printed to the screen. -

- -

-You can compile and run the program like this: -

- -
-$ go build wiki.go
-$ ./wiki
-This is a sample Page.
-
- -

-(If you're using Windows you must type "wiki" without the -"./" to run the program.) -

- -

-Click here to view the code we've written so far. -

- -

Introducing the net/http package (an interlude)

- -

-Here's a full working example of a simple web server: -

- -{{code "doc/articles/wiki/http-sample.go"}} - -

-The main function begins with a call to -http.HandleFunc, which tells the http package to -handle all requests to the web root ("/") with -handler. -

- -

-It then calls http.ListenAndServe, specifying that it should -listen on port 8080 on any interface (":8080"). (Don't -worry about its second parameter, nil, for now.) -This function will block until the program is terminated. -

- -

-ListenAndServe always returns an error, since it only returns when an -unexpected error occurs. -In order to log that error we wrap the function call with log.Fatal. -

- -

-The function handler is of the type http.HandlerFunc. -It takes an http.ResponseWriter and an http.Request as -its arguments. -

- -

-An http.ResponseWriter value assembles the HTTP server's response; by writing -to it, we send data to the HTTP client. -

- -

-An http.Request is a data structure that represents the client -HTTP request. r.URL.Path is the path component -of the request URL. The trailing [1:] means -"create a sub-slice of Path from the 1st character to the end." -This drops the leading "/" from the path name. -

- -

-If you run this program and access the URL: -

-
http://localhost:8080/monkeys
-

-the program would present a page containing: -

-
Hi there, I love monkeys!
- -

Using net/http to serve wiki pages

- -

-To use the net/http package, it must be imported: -

- -
-import (
-	"fmt"
-	"io/ioutil"
-	"log"
-	"net/http"
-)
-
- -

-Let's create a handler, viewHandler that will allow users to -view a wiki page. It will handle URLs prefixed with "/view/". -

- -{{code "doc/articles/wiki/part2.go" `/^func viewHandler/` `/^}/`}} - -

-Again, note the use of _ to ignore the error -return value from loadPage. This is done here for simplicity -and generally considered bad practice. We will attend to this later. -

- -

-First, this function extracts the page title from r.URL.Path, -the path component of the request URL. -The Path is re-sliced with [len("/view/"):] to drop -the leading "/view/" component of the request path. -This is because the path will invariably begin with "/view/", -which is not part of the page's title. -

- -

-The function then loads the page data, formats the page with a string of simple -HTML, and writes it to w, the http.ResponseWriter. -

- -

-To use this handler, we rewrite our main function to -initialize http using the viewHandler to handle -any requests under the path /view/. -

- -{{code "doc/articles/wiki/part2.go" `/^func main/` `/^}/`}} - -

-Click here to view the code we've written so far. -

- -

-Let's create some page data (as test.txt), compile our code, and -try serving a wiki page. -

- -

-Open test.txt file in your editor, and save the string "Hello world" (without quotes) -in it. -

- -
-$ go build wiki.go
-$ ./wiki
-
- -

-(If you're using Windows you must type "wiki" without the -"./" to run the program.) -

- -

-With this web server running, a visit to http://localhost:8080/view/test -should show a page titled "test" containing the words "Hello world". -

- -

Editing Pages

- -

-A wiki is not a wiki without the ability to edit pages. Let's create two new -handlers: one named editHandler to display an 'edit page' form, -and the other named saveHandler to save the data entered via the -form. -

- -

-First, we add them to main(): -

- -{{code "doc/articles/wiki/final-noclosure.go" `/^func main/` `/^}/`}} - -

-The function editHandler loads the page -(or, if it doesn't exist, create an empty Page struct), -and displays an HTML form. -

- -{{code "doc/articles/wiki/notemplate.go" `/^func editHandler/` `/^}/`}} - -

-This function will work fine, but all that hard-coded HTML is ugly. -Of course, there is a better way. -

- -

The html/template package

- -

-The html/template package is part of the Go standard library. -We can use html/template to keep the HTML in a separate file, -allowing us to change the layout of our edit page without modifying the -underlying Go code. -

- -

-First, we must add html/template to the list of imports. We -also won't be using fmt anymore, so we have to remove that. -

- -
-import (
-	"html/template"
-	"io/ioutil"
-	"net/http"
-)
-
- -

-Let's create a template file containing the HTML form. -Open a new file named edit.html, and add the following lines: -

- -{{code "doc/articles/wiki/edit.html"}} - -

-Modify editHandler to use the template, instead of the hard-coded -HTML: -

- -{{code "doc/articles/wiki/final-noerror.go" `/^func editHandler/` `/^}/`}} - -

-The function template.ParseFiles will read the contents of -edit.html and return a *template.Template. -

- -

-The method t.Execute executes the template, writing the -generated HTML to the http.ResponseWriter. -The .Title and .Body dotted identifiers refer to -p.Title and p.Body. -

- -

-Template directives are enclosed in double curly braces. -The printf "%s" .Body instruction is a function call -that outputs .Body as a string instead of a stream of bytes, -the same as a call to fmt.Printf. -The html/template package helps guarantee that only safe and -correct-looking HTML is generated by template actions. For instance, it -automatically escapes any greater than sign (>), replacing it -with &gt;, to make sure user data does not corrupt the form -HTML. -

- -

-Since we're working with templates now, let's create a template for our -viewHandler called view.html: -

- -{{code "doc/articles/wiki/view.html"}} - -

-Modify viewHandler accordingly: -

- -{{code "doc/articles/wiki/final-noerror.go" `/^func viewHandler/` `/^}/`}} - -

-Notice that we've used almost exactly the same templating code in both -handlers. Let's remove this duplication by moving the templating code -to its own function: -

- -{{code "doc/articles/wiki/final-template.go" `/^func renderTemplate/` `/^}/`}} - -

-And modify the handlers to use that function: -

- -{{code "doc/articles/wiki/final-template.go" `/^func viewHandler/` `/^}/`}} -{{code "doc/articles/wiki/final-template.go" `/^func editHandler/` `/^}/`}} - -

-If we comment out the registration of our unimplemented save handler in -main, we can once again build and test our program. -Click here to view the code we've written so far. -

- -

Handling non-existent pages

- -

-What if you visit -/view/APageThatDoesntExist? You'll see a page containing -HTML. This is because it ignores the error return value from -loadPage and continues to try and fill out the template -with no data. Instead, if the requested Page doesn't exist, it should -redirect the client to the edit Page so the content may be created: -

- -{{code "doc/articles/wiki/part3-errorhandling.go" `/^func viewHandler/` `/^}/`}} - -

-The http.Redirect function adds an HTTP status code of -http.StatusFound (302) and a Location -header to the HTTP response. -

- -

Saving Pages

- -

-The function saveHandler will handle the submission of forms -located on the edit pages. After uncommenting the related line in -main, let's implement the handler: -

- -{{code "doc/articles/wiki/final-template.go" `/^func saveHandler/` `/^}/`}} - -

-The page title (provided in the URL) and the form's only field, -Body, are stored in a new Page. -The save() method is then called to write the data to a file, -and the client is redirected to the /view/ page. -

- -

-The value returned by FormValue is of type string. -We must convert that value to []byte before it will fit into -the Page struct. We use []byte(body) to perform -the conversion. -

- -

Error handling

- -

-There are several places in our program where errors are being ignored. This -is bad practice, not least because when an error does occur the program will -have unintended behavior. A better solution is to handle the errors and return -an error message to the user. That way if something does go wrong, the server -will function exactly how we want and the user can be notified. -

- -

-First, let's handle the errors in renderTemplate: -

- -{{code "doc/articles/wiki/final-parsetemplate.go" `/^func renderTemplate/` `/^}/`}} - -

-The http.Error function sends a specified HTTP response code -(in this case "Internal Server Error") and error message. -Already the decision to put this in a separate function is paying off. -

- -

-Now let's fix up saveHandler: -

- -{{code "doc/articles/wiki/part3-errorhandling.go" `/^func saveHandler/` `/^}/`}} - -

-Any errors that occur during p.save() will be reported -to the user. -

- -

Template caching

- -

-There is an inefficiency in this code: renderTemplate calls -ParseFiles every time a page is rendered. -A better approach would be to call ParseFiles once at program -initialization, parsing all templates into a single *Template. -Then we can use the -ExecuteTemplate -method to render a specific template. -

- -

-First we create a global variable named templates, and initialize -it with ParseFiles. -

- -{{code "doc/articles/wiki/final.go" `/var templates/`}} - -

-The function template.Must is a convenience wrapper that panics -when passed a non-nil error value, and otherwise returns the -*Template unaltered. A panic is appropriate here; if the templates -can't be loaded the only sensible thing to do is exit the program. -

- -

-The ParseFiles function takes any number of string arguments that -identify our template files, and parses those files into templates that are -named after the base file name. If we were to add more templates to our -program, we would add their names to the ParseFiles call's -arguments. -

- -

-We then modify the renderTemplate function to call the -templates.ExecuteTemplate method with the name of the appropriate -template: -

- -{{code "doc/articles/wiki/final.go" `/func renderTemplate/` `/^}/`}} - -

-Note that the template name is the template file name, so we must -append ".html" to the tmpl argument. -

- -

Validation

- -

-As you may have observed, this program has a serious security flaw: a user -can supply an arbitrary path to be read/written on the server. To mitigate -this, we can write a function to validate the title with a regular expression. -

- -

-First, add "regexp" to the import list. -Then we can create a global variable to store our validation -expression: -

- -{{code "doc/articles/wiki/final-noclosure.go" `/^var validPath/`}} - -

-The function regexp.MustCompile will parse and compile the -regular expression, and return a regexp.Regexp. -MustCompile is distinct from Compile in that it will -panic if the expression compilation fails, while Compile returns -an error as a second parameter. -

- -

-Now, let's write a function that uses the validPath -expression to validate path and extract the page title: -

- -{{code "doc/articles/wiki/final-noclosure.go" `/func getTitle/` `/^}/`}} - -

-If the title is valid, it will be returned along with a nil -error value. If the title is invalid, the function will write a -"404 Not Found" error to the HTTP connection, and return an error to the -handler. To create a new error, we have to import the errors -package. -

- -

-Let's put a call to getTitle in each of the handlers: -

- -{{code "doc/articles/wiki/final-noclosure.go" `/^func viewHandler/` `/^}/`}} -{{code "doc/articles/wiki/final-noclosure.go" `/^func editHandler/` `/^}/`}} -{{code "doc/articles/wiki/final-noclosure.go" `/^func saveHandler/` `/^}/`}} - -

Introducing Function Literals and Closures

- -

-Catching the error condition in each handler introduces a lot of repeated code. -What if we could wrap each of the handlers in a function that does this -validation and error checking? Go's -function -literals provide a powerful means of abstracting functionality -that can help us here. -

- -

-First, we re-write the function definition of each of the handlers to accept -a title string: -

- -
-func viewHandler(w http.ResponseWriter, r *http.Request, title string)
-func editHandler(w http.ResponseWriter, r *http.Request, title string)
-func saveHandler(w http.ResponseWriter, r *http.Request, title string)
-
- -

-Now let's define a wrapper function that takes a function of the above -type, and returns a function of type http.HandlerFunc -(suitable to be passed to the function http.HandleFunc): -

- -
-func makeHandler(fn func (http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
-	return func(w http.ResponseWriter, r *http.Request) {
-		// Here we will extract the page title from the Request,
-		// and call the provided handler 'fn'
-	}
-}
-
- -

-The returned function is called a closure because it encloses values defined -outside of it. In this case, the variable fn (the single argument -to makeHandler) is enclosed by the closure. The variable -fn will be one of our save, edit, or view handlers. -

- -

-Now we can take the code from getTitle and use it here -(with some minor modifications): -

- -{{code "doc/articles/wiki/final.go" `/func makeHandler/` `/^}/`}} - -

-The closure returned by makeHandler is a function that takes -an http.ResponseWriter and http.Request (in other -words, an http.HandlerFunc). -The closure extracts the title from the request path, and -validates it with the validPath regexp. If the -title is invalid, an error will be written to the -ResponseWriter using the http.NotFound function. -If the title is valid, the enclosed handler function -fn will be called with the ResponseWriter, -Request, and title as arguments. -

- -

-Now we can wrap the handler functions with makeHandler in -main, before they are registered with the http -package: -

- -{{code "doc/articles/wiki/final.go" `/func main/` `/^}/`}} - -

-Finally we remove the calls to getTitle from the handler functions, -making them much simpler: -

- -{{code "doc/articles/wiki/final.go" `/^func viewHandler/` `/^}/`}} -{{code "doc/articles/wiki/final.go" `/^func editHandler/` `/^}/`}} -{{code "doc/articles/wiki/final.go" `/^func saveHandler/` `/^}/`}} - -

Try it out!

- -

-Click here to view the final code listing. -

- -

-Recompile the code, and run the app: -

- -
-$ go build wiki.go
-$ ./wiki
-
- -

-Visiting http://localhost:8080/view/ANewPage -should present you with the page edit form. You should then be able to -enter some text, click 'Save', and be redirected to the newly created page. -

- -

Other tasks

- -

-Here are some simple tasks you might want to tackle on your own: -

- -
    -
  • Store templates in tmpl/ and page data in data/. -
  • Add a handler to make the web root redirect to - /view/FrontPage.
  • -
  • Spruce up the page templates by making them valid HTML and adding some - CSS rules.
  • -
  • Implement inter-page linking by converting instances of - [PageName] to
    - <a href="/view/PageName">PageName</a>. - (hint: you could use regexp.ReplaceAllFunc to do this) -
  • -
diff --git a/doc/articles/wiki/notemplate.go b/doc/articles/wiki/notemplate.go deleted file mode 100644 index 4b358f298a..0000000000 --- a/doc/articles/wiki/notemplate.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "fmt" - "io/ioutil" - "log" - "net/http" -) - -type Page struct { - Title string - Body []byte -} - -func (p *Page) save() error { - filename := p.Title + ".txt" - return ioutil.WriteFile(filename, p.Body, 0600) -} - -func loadPage(title string) (*Page, error) { - filename := title + ".txt" - body, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - return &Page{Title: title, Body: body}, nil -} - -func viewHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/view/"):] - p, _ := loadPage(title) - fmt.Fprintf(w, "

%s

%s
", p.Title, p.Body) -} - -func editHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/edit/"):] - p, err := loadPage(title) - if err != nil { - p = &Page{Title: title} - } - fmt.Fprintf(w, "

Editing %s

"+ - "
"+ - "
"+ - ""+ - "
", - p.Title, p.Title, p.Body) -} - -func main() { - http.HandleFunc("/view/", viewHandler) - http.HandleFunc("/edit/", editHandler) - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/doc/articles/wiki/part1-noerror.go b/doc/articles/wiki/part1-noerror.go deleted file mode 100644 index 913c6dce2e..0000000000 --- a/doc/articles/wiki/part1-noerror.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "fmt" - "io/ioutil" -) - -type Page struct { - Title string - Body []byte -} - -func (p *Page) save() error { - filename := p.Title + ".txt" - return ioutil.WriteFile(filename, p.Body, 0600) -} - -func loadPage(title string) *Page { - filename := title + ".txt" - body, _ := ioutil.ReadFile(filename) - return &Page{Title: title, Body: body} -} - -func main() { - p1 := &Page{Title: "TestPage", Body: []byte("This is a sample page.")} - p1.save() - p2 := loadPage("TestPage") - fmt.Println(string(p2.Body)) -} diff --git a/doc/articles/wiki/part1.go b/doc/articles/wiki/part1.go deleted file mode 100644 index 2ff1abd281..0000000000 --- a/doc/articles/wiki/part1.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "fmt" - "io/ioutil" -) - -type Page struct { - Title string - Body []byte -} - -func (p *Page) save() error { - filename := p.Title + ".txt" - return ioutil.WriteFile(filename, p.Body, 0600) -} - -func loadPage(title string) (*Page, error) { - filename := title + ".txt" - body, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - return &Page{Title: title, Body: body}, nil -} - -func main() { - p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")} - p1.save() - p2, _ := loadPage("TestPage") - fmt.Println(string(p2.Body)) -} diff --git a/doc/articles/wiki/part2.go b/doc/articles/wiki/part2.go deleted file mode 100644 index db92f4c710..0000000000 --- a/doc/articles/wiki/part2.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "fmt" - "io/ioutil" - "log" - "net/http" -) - -type Page struct { - Title string - Body []byte -} - -func (p *Page) save() error { - filename := p.Title + ".txt" - return ioutil.WriteFile(filename, p.Body, 0600) -} - -func loadPage(title string) (*Page, error) { - filename := title + ".txt" - body, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - return &Page{Title: title, Body: body}, nil -} - -func viewHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/view/"):] - p, _ := loadPage(title) - fmt.Fprintf(w, "

%s

%s
", p.Title, p.Body) -} - -func main() { - http.HandleFunc("/view/", viewHandler) - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/doc/articles/wiki/part3-errorhandling.go b/doc/articles/wiki/part3-errorhandling.go deleted file mode 100644 index 2c8b42d05a..0000000000 --- a/doc/articles/wiki/part3-errorhandling.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "html/template" - "io/ioutil" - "log" - "net/http" -) - -type Page struct { - Title string - Body []byte -} - -func (p *Page) save() error { - filename := p.Title + ".txt" - return ioutil.WriteFile(filename, p.Body, 0600) -} - -func loadPage(title string) (*Page, error) { - filename := title + ".txt" - body, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - return &Page{Title: title, Body: body}, nil -} - -func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { - t, _ := template.ParseFiles(tmpl + ".html") - t.Execute(w, p) -} - -func viewHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/view/"):] - p, err := loadPage(title) - if err != nil { - http.Redirect(w, r, "/edit/"+title, http.StatusFound) - return - } - renderTemplate(w, "view", p) -} - -func editHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/edit/"):] - p, err := loadPage(title) - if err != nil { - p = &Page{Title: title} - } - renderTemplate(w, "edit", p) -} - -func saveHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/save/"):] - body := r.FormValue("body") - p := &Page{Title: title, Body: []byte(body)} - err := p.save() - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - http.Redirect(w, r, "/view/"+title, http.StatusFound) -} - -func main() { - http.HandleFunc("/view/", viewHandler) - http.HandleFunc("/edit/", editHandler) - http.HandleFunc("/save/", saveHandler) - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/doc/articles/wiki/part3.go b/doc/articles/wiki/part3.go deleted file mode 100644 index 437ea336cb..0000000000 --- a/doc/articles/wiki/part3.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -package main - -import ( - "html/template" - "io/ioutil" - "log" - "net/http" -) - -type Page struct { - Title string - Body []byte -} - -func (p *Page) save() error { - filename := p.Title + ".txt" - return ioutil.WriteFile(filename, p.Body, 0600) -} - -func loadPage(title string) (*Page, error) { - filename := title + ".txt" - body, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - return &Page{Title: title, Body: body}, nil -} - -func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { - t, _ := template.ParseFiles(tmpl + ".html") - t.Execute(w, p) -} - -func viewHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/view/"):] - p, _ := loadPage(title) - renderTemplate(w, "view", p) -} - -func editHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/edit/"):] - p, err := loadPage(title) - if err != nil { - p = &Page{Title: title} - } - renderTemplate(w, "edit", p) -} - -func main() { - http.HandleFunc("/view/", viewHandler) - http.HandleFunc("/edit/", editHandler) - //http.HandleFunc("/save/", saveHandler) - log.Fatal(http.ListenAndServe(":8080", nil)) -} diff --git a/doc/articles/wiki/test_Test.txt.good b/doc/articles/wiki/test_Test.txt.good deleted file mode 100644 index f0eec86f61..0000000000 --- a/doc/articles/wiki/test_Test.txt.good +++ /dev/null @@ -1 +0,0 @@ -some content \ No newline at end of file diff --git a/doc/articles/wiki/test_edit.good b/doc/articles/wiki/test_edit.good deleted file mode 100644 index 36c6dbb732..0000000000 --- a/doc/articles/wiki/test_edit.good +++ /dev/null @@ -1,6 +0,0 @@ -

Editing Test

- -
-
-
-
diff --git a/doc/articles/wiki/test_view.good b/doc/articles/wiki/test_view.good deleted file mode 100644 index 07e8edb22e..0000000000 --- a/doc/articles/wiki/test_view.good +++ /dev/null @@ -1,5 +0,0 @@ -

Test

- -

[edit]

- -
some content
diff --git a/doc/articles/wiki/view.html b/doc/articles/wiki/view.html deleted file mode 100644 index b1e87efe80..0000000000 --- a/doc/articles/wiki/view.html +++ /dev/null @@ -1,5 +0,0 @@ -

{{.Title}}

- -

[edit]

- -
{{printf "%s" .Body}}
diff --git a/doc/articles/wiki/wiki_test.go b/doc/articles/wiki/wiki_test.go deleted file mode 100644 index 1d976fd77e..0000000000 --- a/doc/articles/wiki/wiki_test.go +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main_test - -import ( - "bytes" - "fmt" - "io/ioutil" - "net/http" - "os" - "os/exec" - "path/filepath" - "strings" - "testing" -) - -func TestSnippetsCompile(t *testing.T) { - if testing.Short() { - t.Skip("skipping slow builds in short mode") - } - - goFiles, err := filepath.Glob("*.go") - if err != nil { - t.Fatal(err) - } - - for _, f := range goFiles { - if strings.HasSuffix(f, "_test.go") { - continue - } - f := f - t.Run(f, func(t *testing.T) { - t.Parallel() - - cmd := exec.Command("go", "build", "-o", os.DevNull, f) - out, err := cmd.CombinedOutput() - if err != nil { - t.Errorf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out) - } - }) - } -} - -func TestWikiServer(t *testing.T) { - must := func(err error) { - if err != nil { - t.Helper() - t.Fatal(err) - } - } - - dir, err := ioutil.TempDir("", t.Name()) - must(err) - defer os.RemoveAll(dir) - - // We're testing a walkthrough example of how to write a server. - // - // That server hard-codes a port number to make the walkthrough simpler, but - // we can't assume that the hard-coded port is available on an arbitrary - // builder. So we'll patch out the hard-coded port, and replace it with a - // function that writes the server's address to stdout - // so that we can read it and know where to send the test requests. - - finalGo, err := ioutil.ReadFile("final.go") - must(err) - const patchOld = `log.Fatal(http.ListenAndServe(":8080", nil))` - patched := bytes.ReplaceAll(finalGo, []byte(patchOld), []byte(`log.Fatal(serve())`)) - if bytes.Equal(patched, finalGo) { - t.Fatalf("Can't patch final.go: %q not found.", patchOld) - } - must(ioutil.WriteFile(filepath.Join(dir, "final_patched.go"), patched, 0644)) - - // Build the server binary from the patched sources. - // The 'go' command requires that they all be in the same directory. - // final_test.go provides the implemtation for our serve function. - must(copyFile(filepath.Join(dir, "final_srv.go"), "final_test.go")) - cmd := exec.Command("go", "build", - "-o", filepath.Join(dir, "final.exe"), - filepath.Join(dir, "final_patched.go"), - filepath.Join(dir, "final_srv.go")) - out, err := cmd.CombinedOutput() - if err != nil { - t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out) - } - - // Run the server in our temporary directory so that it can - // write its content there. It also needs a couple of template files, - // and looks for them in the same directory. - must(copyFile(filepath.Join(dir, "edit.html"), "edit.html")) - must(copyFile(filepath.Join(dir, "view.html"), "view.html")) - cmd = exec.Command(filepath.Join(dir, "final.exe")) - cmd.Dir = dir - stderr := bytes.NewBuffer(nil) - cmd.Stderr = stderr - stdout, err := cmd.StdoutPipe() - must(err) - must(cmd.Start()) - - defer func() { - cmd.Process.Kill() - err := cmd.Wait() - if stderr.Len() > 0 { - t.Logf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, stderr) - } - }() - - var addr string - if _, err := fmt.Fscanln(stdout, &addr); err != nil || addr == "" { - t.Fatalf("Failed to read server address: %v", err) - } - - // The server is up and has told us its address. - // Make sure that its HTTP API works as described in the article. - - r, err := http.Get(fmt.Sprintf("http://%s/edit/Test", addr)) - must(err) - responseMustMatchFile(t, r, "test_edit.good") - - r, err = http.Post(fmt.Sprintf("http://%s/save/Test", addr), - "application/x-www-form-urlencoded", - strings.NewReader("body=some%20content")) - must(err) - responseMustMatchFile(t, r, "test_view.good") - - gotTxt, err := ioutil.ReadFile(filepath.Join(dir, "Test.txt")) - must(err) - wantTxt, err := ioutil.ReadFile("test_Test.txt.good") - must(err) - if !bytes.Equal(wantTxt, gotTxt) { - t.Fatalf("Test.txt differs from expected after posting to /save.\ngot:\n%s\nwant:\n%s", gotTxt, wantTxt) - } - - r, err = http.Get(fmt.Sprintf("http://%s/view/Test", addr)) - must(err) - responseMustMatchFile(t, r, "test_view.good") -} - -func responseMustMatchFile(t *testing.T, r *http.Response, filename string) { - t.Helper() - - defer r.Body.Close() - body, err := ioutil.ReadAll(r.Body) - if err != nil { - t.Fatal(err) - } - - wantBody, err := ioutil.ReadFile(filename) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(body, wantBody) { - t.Fatalf("%v: body does not match %s.\ngot:\n%s\nwant:\n%s", r.Request.URL, filename, body, wantBody) - } -} - -func copyFile(dst, src string) error { - buf, err := ioutil.ReadFile(src) - if err != nil { - return err - } - return ioutil.WriteFile(dst, buf, 0644) -} diff --git a/doc/cmd.html b/doc/cmd.html deleted file mode 100644 index c3bd918144..0000000000 --- a/doc/cmd.html +++ /dev/null @@ -1,100 +0,0 @@ - - -

-There is a suite of programs to build and process Go source code. -Instead of being run directly, programs in the suite are usually invoked -by the go program. -

- -

-The most common way to run these programs is as a subcommand of the go program, -for instance as go fmt. Run like this, the command operates on -complete packages of Go source code, with the go program invoking the -underlying binary with arguments appropriate to package-level processing. -

- -

-The programs can also be run as stand-alone binaries, with unmodified arguments, -using the go tool subcommand, such as go tool cgo. -For most commands this is mainly useful for debugging. -Some of the commands, such as pprof, are accessible only through -the go tool subcommand. -

- -

-Finally the fmt and godoc commands are installed -as regular binaries called gofmt and godoc because -they are so often referenced. -

- -

-Click on the links for more documentation, invocation methods, and usage details. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Name    Synopsis
go     -The go program manages Go source code and runs the other -commands listed here. -See the command docs for usage -details. -
cgo    Cgo enables the creation of Go packages that call C code.
cover    Cover is a program for creating and analyzing the coverage profiles -generated by "go test -coverprofile".
fix    Fix finds Go programs that use old features of the language and libraries -and rewrites them to use newer ones.
fmt    Fmt formats Go packages, it is also available as an independent -gofmt command with more general options.
godoc    Godoc extracts and generates documentation for Go packages.
vet    Vet examines Go source code and reports suspicious constructs, such as Printf -calls whose arguments do not align with the format string.
- -

-This is an abridged list. See the full command reference -for documentation of the compilers and more. -

diff --git a/doc/codewalk/codewalk.css b/doc/codewalk/codewalk.css deleted file mode 100644 index a0814e4d2d..0000000000 --- a/doc/codewalk/codewalk.css +++ /dev/null @@ -1,234 +0,0 @@ -/* - Copyright 2010 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. -*/ - -#codewalk-main { - text-align: left; - width: 100%; - overflow: auto; -} - -#code-display { - border: 0; - width: 100%; -} - -.setting { - font-size: 8pt; - color: #888888; - padding: 5px; -} - -.hotkey { - text-decoration: underline; -} - -/* Style for Comments (the left-hand column) */ - -#comment-column { - margin: 0pt; - width: 30%; -} - -#comment-column.right { - float: right; -} - -#comment-column.left { - float: left; -} - -#comment-area { - overflow-x: hidden; - overflow-y: auto; -} - -.comment { - cursor: pointer; - font-size: 16px; - border: 2px solid #ba9836; - margin-bottom: 10px; - margin-right: 10px; /* yes, for both .left and .right */ -} - -.comment:last-child { - margin-bottom: 0px; -} - -.right .comment { - margin-left: 10px; -} - -.right .comment.first { -} - -.right .comment.last { -} - -.left .comment.first { -} - -.left .comment.last { -} - -.comment.selected { - border-color: #99b2cb; -} - -.right .comment.selected { - border-left-width: 12px; - margin-left: 0px; -} - -.left .comment.selected { - border-right-width: 12px; - margin-right: 0px; -} - -.comment-link { - display: none; -} - -.comment-title { - font-size: small; - font-weight: bold; - background-color: #fffff0; - padding-right: 10px; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; -} - -.right .comment-title { -} - -.left .comment-title { -} - -.comment.selected .comment-title { - background-color: #f8f8ff; -} - -.comment-text { - overflow: auto; - padding-left: 10px; - padding-right: 10px; - padding-top: 10px; - padding-bottom: 5px; - font-size: small; - line-height: 1.3em; -} - -.comment-text p { - margin-top: 0em; - margin-bottom: 0.5em; -} - -.comment-text p:last-child { - margin-bottom: 0em; -} - -.file-name { - font-size: x-small; - padding-top: 0px; - padding-bottom: 5px; -} - -.hidden-filepaths .file-name { - display: none; -} - -.path-dir { - color: #555; -} - -.path-file { - color: #555; -} - - -/* Style for Code (the right-hand column) */ - -/* Wrapper for the code column to make widths get calculated correctly */ -#code-column { - display: block; - position: relative; - margin: 0pt; - width: 70%; -} - -#code-column.left { - float: left; -} - -#code-column.right { - float: right; -} - -#code-area { - background-color: #f8f8ff; - border: 2px solid #99b2cb; - padding: 5px; -} - -.left #code-area { - margin-right: -1px; -} - -.right #code-area { - margin-left: -1px; -} - -#code-header { - margin-bottom: 5px; -} - -#code { - background-color: white; -} - -code { - font-size: 100%; -} - -.codewalkhighlight { - font-weight: bold; - background-color: #f8f8ff; -} - -#code-display { - margin-top: 0px; - margin-bottom: 0px; -} - -#sizer { - position: absolute; - cursor: col-resize; - left: 0px; - top: 0px; - width: 8px; -} - -/* Style for options (bottom strip) */ - -#code-options { - display: none; -} - -#code-options > span { - padding-right: 20px; -} - -#code-options .selected { - border-bottom: 1px dotted; -} - -#comment-options { - text-align: center; -} - -div#content { - padding-bottom: 0em; -} diff --git a/doc/codewalk/codewalk.js b/doc/codewalk/codewalk.js deleted file mode 100644 index 4f59a8fc89..0000000000 --- a/doc/codewalk/codewalk.js +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/** - * A class to hold information about the Codewalk Viewer. - * @param {jQuery} context The top element in whose context the viewer should - * operate. It will not touch any elements above this one. - * @constructor - */ - var CodewalkViewer = function(context) { - this.context = context; - - /** - * The div that contains all of the comments and their controls. - */ - this.commentColumn = this.context.find('#comment-column'); - - /** - * The div that contains the comments proper. - */ - this.commentArea = this.context.find('#comment-area'); - - /** - * The div that wraps the iframe with the code, as well as the drop down menu - * listing the different files. - * @type {jQuery} - */ - this.codeColumn = this.context.find('#code-column'); - - /** - * The div that contains the code but excludes the options strip. - * @type {jQuery} - */ - this.codeArea = this.context.find('#code-area'); - - /** - * The iframe that holds the code (from Sourcerer). - * @type {jQuery} - */ - this.codeDisplay = this.context.find('#code-display'); - - /** - * The overlaid div used as a grab handle for sizing the code/comment panes. - * @type {jQuery} - */ - this.sizer = this.context.find('#sizer'); - - /** - * The full-screen overlay that ensures we don't lose track of the mouse - * while dragging. - * @type {jQuery} - */ - this.overlay = this.context.find('#overlay'); - - /** - * The hidden input field that we use to hold the focus so that we can detect - * shortcut keypresses. - * @type {jQuery} - */ - this.shortcutInput = this.context.find('#shortcut-input'); - - /** - * The last comment that was selected. - * @type {jQuery} - */ - this.lastSelected = null; -}; - -/** - * Minimum width of the comments or code pane, in pixels. - * @type {number} - */ -CodewalkViewer.MIN_PANE_WIDTH = 200; - -/** - * Navigate the code iframe to the given url and update the code popout link. - * @param {string} url The target URL. - * @param {Object} opt_window Window dependency injection for testing only. - */ -CodewalkViewer.prototype.navigateToCode = function(url, opt_window) { - if (!opt_window) opt_window = window; - // Each iframe is represented by two distinct objects in the DOM: an iframe - // object and a window object. These do not expose the same capabilities. - // Here we need to get the window representation to get the location member, - // so we access it directly through window[] since jQuery returns the iframe - // representation. - // We replace location rather than set so as not to create a history for code - // navigation. - opt_window['code-display'].location.replace(url); - var k = url.indexOf('&'); - if (k != -1) url = url.slice(0, k); - k = url.indexOf('fileprint='); - if (k != -1) url = url.slice(k+10, url.length); - this.context.find('#code-popout-link').attr('href', url); -}; - -/** - * Selects the first comment from the list and forces a refresh of the code - * view. - */ -CodewalkViewer.prototype.selectFirstComment = function() { - // TODO(rsc): handle case where there are no comments - var firstSourcererLink = this.context.find('.comment:first'); - this.changeSelectedComment(firstSourcererLink); -}; - -/** - * Sets the target on all links nested inside comments to be _blank. - */ -CodewalkViewer.prototype.targetCommentLinksAtBlank = function() { - this.context.find('.comment a[href], #description a[href]').each(function() { - if (!this.target) this.target = '_blank'; - }); -}; - -/** - * Installs event handlers for all the events we care about. - */ -CodewalkViewer.prototype.installEventHandlers = function() { - var self = this; - - this.context.find('.comment') - .click(function(event) { - if (jQuery(event.target).is('a[href]')) return true; - self.changeSelectedComment(jQuery(this)); - return false; - }); - - this.context.find('#code-selector') - .change(function() {self.navigateToCode(jQuery(this).val());}); - - this.context.find('#description-table .quote-feet.setting') - .click(function() {self.toggleDescription(jQuery(this)); return false;}); - - this.sizer - .mousedown(function(ev) {self.startSizerDrag(ev); return false;}); - this.overlay - .mouseup(function(ev) {self.endSizerDrag(ev); return false;}) - .mousemove(function(ev) {self.handleSizerDrag(ev); return false;}); - - this.context.find('#prev-comment') - .click(function() { - self.changeSelectedComment(self.lastSelected.prev()); return false; - }); - - this.context.find('#next-comment') - .click(function() { - self.changeSelectedComment(self.lastSelected.next()); return false; - }); - - // Workaround for Firefox 2 and 3, which steal focus from the main document - // whenever the iframe content is (re)loaded. The input field is not shown, - // but is a way for us to bring focus back to a place where we can detect - // keypresses. - this.context.find('#code-display') - .load(function(ev) {self.shortcutInput.focus();}); - - jQuery(document).keypress(function(ev) { - switch(ev.which) { - case 110: // 'n' - self.changeSelectedComment(self.lastSelected.next()); - return false; - case 112: // 'p' - self.changeSelectedComment(self.lastSelected.prev()); - return false; - default: // ignore - } - }); - - window.onresize = function() {self.updateHeight();}; -}; - -/** - * Starts dragging the pane sizer. - * @param {Object} ev The mousedown event that started us dragging. - */ -CodewalkViewer.prototype.startSizerDrag = function(ev) { - this.initialCodeWidth = this.codeColumn.width(); - this.initialCommentsWidth = this.commentColumn.width(); - this.initialMouseX = ev.pageX; - this.overlay.show(); -}; - -/** - * Handles dragging the pane sizer. - * @param {Object} ev The mousemove event updating dragging position. - */ -CodewalkViewer.prototype.handleSizerDrag = function(ev) { - var delta = ev.pageX - this.initialMouseX; - if (this.codeColumn.is('.right')) delta = -delta; - var proposedCodeWidth = this.initialCodeWidth + delta; - var proposedCommentWidth = this.initialCommentsWidth - delta; - var mw = CodewalkViewer.MIN_PANE_WIDTH; - if (proposedCodeWidth < mw) delta = mw - this.initialCodeWidth; - if (proposedCommentWidth < mw) delta = this.initialCommentsWidth - mw; - proposedCodeWidth = this.initialCodeWidth + delta; - proposedCommentWidth = this.initialCommentsWidth - delta; - // If window is too small, don't even try to resize. - if (proposedCodeWidth < mw || proposedCommentWidth < mw) return; - this.codeColumn.width(proposedCodeWidth); - this.commentColumn.width(proposedCommentWidth); - this.options.codeWidth = parseInt( - this.codeColumn.width() / - (this.codeColumn.width() + this.commentColumn.width()) * 100); - this.context.find('#code-column-width').text(this.options.codeWidth + '%'); -}; - -/** - * Ends dragging the pane sizer. - * @param {Object} ev The mouseup event that caused us to stop dragging. - */ -CodewalkViewer.prototype.endSizerDrag = function(ev) { - this.overlay.hide(); - this.updateHeight(); -}; - -/** - * Toggles the Codewalk description between being shown and hidden. - * @param {jQuery} target The target that was clicked to trigger this function. - */ -CodewalkViewer.prototype.toggleDescription = function(target) { - var description = this.context.find('#description'); - description.toggle(); - target.find('span').text(description.is(':hidden') ? 'show' : 'hide'); - this.updateHeight(); -}; - -/** - * Changes the side of the window on which the code is shown and saves the - * setting in a cookie. - * @param {string?} codeSide The side on which the code should be, either - * 'left' or 'right'. - */ -CodewalkViewer.prototype.changeCodeSide = function(codeSide) { - var commentSide = codeSide == 'left' ? 'right' : 'left'; - this.context.find('#set-code-' + codeSide).addClass('selected'); - this.context.find('#set-code-' + commentSide).removeClass('selected'); - // Remove previous side class and add new one. - this.codeColumn.addClass(codeSide).removeClass(commentSide); - this.commentColumn.addClass(commentSide).removeClass(codeSide); - this.sizer.css(codeSide, 'auto').css(commentSide, 0); - this.options.codeSide = codeSide; -}; - -/** - * Adds selected class to newly selected comment, removes selected style from - * previously selected comment, changes drop down options so that the correct - * file is selected, and updates the code popout link. - * @param {jQuery} target The target that was clicked to trigger this function. - */ -CodewalkViewer.prototype.changeSelectedComment = function(target) { - var currentFile = target.find('.comment-link').attr('href'); - if (!currentFile) return; - - if (!(this.lastSelected && this.lastSelected.get(0) === target.get(0))) { - if (this.lastSelected) this.lastSelected.removeClass('selected'); - target.addClass('selected'); - this.lastSelected = target; - var targetTop = target.position().top; - var parentTop = target.parent().position().top; - if (targetTop + target.height() > parentTop + target.parent().height() || - targetTop < parentTop) { - var delta = targetTop - parentTop; - target.parent().animate( - {'scrollTop': target.parent().scrollTop() + delta}, - Math.max(delta / 2, 200), 'swing'); - } - var fname = currentFile.match(/(?:select=|fileprint=)\/[^&]+/)[0]; - fname = fname.slice(fname.indexOf('=')+2, fname.length); - this.context.find('#code-selector').val(fname); - this.context.find('#prev-comment').toggleClass( - 'disabled', !target.prev().length); - this.context.find('#next-comment').toggleClass( - 'disabled', !target.next().length); - } - - // Force original file even if user hasn't changed comments since they may - // have navigated away from it within the iframe without us knowing. - this.navigateToCode(currentFile); -}; - -/** - * Updates the viewer by changing the height of the comments and code so that - * they fit within the height of the window. The function is typically called - * after the user changes the window size. - */ -CodewalkViewer.prototype.updateHeight = function() { - var windowHeight = jQuery(window).height() - 5 // GOK - var areaHeight = windowHeight - this.codeArea.offset().top - var footerHeight = this.context.find('#footer').outerHeight(true) - this.commentArea.height(areaHeight - footerHeight - this.context.find('#comment-options').outerHeight(true)) - var codeHeight = areaHeight - footerHeight - 15 // GOK - this.codeArea.height(codeHeight) - this.codeDisplay.height(codeHeight - this.codeDisplay.offset().top + this.codeArea.offset().top); - this.sizer.height(codeHeight); -}; - -window.initFuncs.push(function() { - var viewer = new CodewalkViewer(jQuery('#codewalk-main')); - viewer.selectFirstComment(); - viewer.targetCommentLinksAtBlank(); - viewer.installEventHandlers(); - viewer.updateHeight(); -}); diff --git a/doc/codewalk/codewalk.xml b/doc/codewalk/codewalk.xml deleted file mode 100644 index 34e6e91938..0000000000 --- a/doc/codewalk/codewalk.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - A codewalk is a guided tour through a piece of code. - It consists of a sequence of steps, each typically explaining - a highlighted section of code. -

- - The godoc web server translates - an XML file like the one in the main window pane into the HTML - page that you're viewing now. -

- - The codewalk with URL path /doc/codewalk/name - is loaded from the input file $GOROOT/doc/codewalk/name.xml. -

- - This codewalk explains how to write a codewalk by examining - its own source code, - $GOROOT/doc/codewalk/codewalk.xml, - shown in the main window pane to the left. -
- - - The codewalk input file is an XML file containing a single - <codewalk> element. - That element's title attribute gives the title - that is used both on the codewalk page and in the codewalk list. - - - - Each step in the codewalk is a <step> element - nested inside the main <codewalk>. - The step element's title attribute gives the step's title, - which is shown in a shaded bar above the main step text. - The element's src attribute specifies the source - code to show in the main window pane and, optionally, a range of - lines to highlight. -

- - The first step in this codewalk does not highlight any lines: - its src is just a file name. -
- - - The most complex part of the codewalk specification is - saying what lines to highlight. - Instead of ordinary line numbers, - the codewalk uses an address syntax that makes it possible - to describe the match by its content. - As the file gets edited, this descriptive address has a better - chance to continue to refer to the right section of the file. -

- - To specify a source line, use a src attribute of the form - filename:address, - where address is an address in the syntax used by the text editors sam and acme. -

- - The simplest address is a single regular expression. - The highlighted line in the main window pane shows that the - address for the “Title” step was /title=/, - which matches the first instance of that regular expression (title=) in the file. -
- - - To highlight a range of source lines, the simplest address to use is - a pair of regular expressions - /regexp1/,/regexp2/. - The highlight begins with the line containing the first match for regexp1 - and ends with the line containing the first match for regexp2 - after the end of the match for regexp1. - Ignoring the HTML quoting, - The line containing the first match for regexp1 will be the first one highlighted, - and the line containing the first match for regexp2. -

- - The address /<step/,/step>/ looks for the first instance of - <step in the file, and then starting after that point, - looks for the first instance of step>. - (Click on the “Steps” step above to see the highlight in action.) - Note that the < and > had to be written - using XML escapes in order to be valid XML. -
- - - The /regexp/ - and /regexp1/,/regexp2/ - forms suffice for most highlighting. -

- - The full address syntax is summarized in this table - (an excerpt of Table II from - The text editor sam): -

- - - - - - - - - - - - - - - - - - - - -
Simple addresses
#nThe empty string after character n
nLine n
/regexp/The first following match of the regular expression
$The null string at the end of the file
Compound addresses
a1+a2The address a2 evaluated starting at the right of a1
a1-a2The address a2 evaluated in the reverse direction starting at the left of a1
a1,a2From the left of a1 to the right of a2 (default 0,$).
-
- - - -
diff --git a/doc/codewalk/codewalk_test.go b/doc/codewalk/codewalk_test.go deleted file mode 100644 index 31f078ac26..0000000000 --- a/doc/codewalk/codewalk_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main_test - -import ( - "bytes" - "os" - "os/exec" - "strings" - "testing" -) - -// TestMarkov tests the code dependency of markov.xml. -func TestMarkov(t *testing.T) { - cmd := exec.Command("go", "run", "markov.go") - cmd.Stdin = strings.NewReader("foo") - cmd.Stderr = bytes.NewBuffer(nil) - out, err := cmd.Output() - if err != nil { - t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr) - } - - if !bytes.Equal(out, []byte("foo\n")) { - t.Fatalf(`%s with input "foo" did not output "foo":\n%s`, strings.Join(cmd.Args, " "), out) - } -} - -// TestPig tests the code dependency of functions.xml. -func TestPig(t *testing.T) { - cmd := exec.Command("go", "run", "pig.go") - cmd.Stderr = bytes.NewBuffer(nil) - out, err := cmd.Output() - if err != nil { - t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr) - } - - const want = "Wins, losses staying at k = 100: 210/990 (21.2%), 780/990 (78.8%)\n" - if !bytes.Contains(out, []byte(want)) { - t.Fatalf(`%s: unexpected output\ngot:\n%s\nwant output containing:\n%s`, strings.Join(cmd.Args, " "), out, want) - } -} - -// TestURLPoll tests the code dependency of sharemem.xml. -func TestURLPoll(t *testing.T) { - cmd := exec.Command("go", "build", "-o", os.DevNull, "urlpoll.go") - out, err := cmd.CombinedOutput() - if err != nil { - t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out) - } -} diff --git a/doc/codewalk/functions.xml b/doc/codewalk/functions.xml deleted file mode 100644 index db518dcc06..0000000000 --- a/doc/codewalk/functions.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - Go supports first class functions, higher-order functions, user-defined - function types, function literals, closures, and multiple return values. -

- - This rich feature set supports a functional programming style in a strongly - typed language. -

- - In this codewalk we will look at a simple program that simulates a dice game - called Pig and evaluates - basic strategies. -
- - - Pig is a two-player game played with a 6-sided die. Each turn, you may roll or stay. -
    -
  • If you roll a 1, you lose all points for your turn and play passes to - your opponent. Any other roll adds its value to your turn score.
  • -
  • If you stay, your turn score is added to your total score, and play passes - to your opponent.
  • -
- - The first person to reach 100 total points wins. -

- - The score type stores the scores of the current and opposing - players, in addition to the points accumulated during the current turn. -
- - - In Go, functions can be passed around just like any other value. A function's - type signature describes the types of its arguments and return values. -

- - The action type is a function that takes a score - and returns the resulting score and whether the current turn is - over. -

- - If the turn is over, the player and opponent fields - in the resulting score should be swapped, as it is now the other player's - turn. -
- - - Go functions can return multiple values. -

- - The functions roll and stay each return a pair of - values. They also match the action type signature. These - action functions define the rules of Pig. -
- - - A function can use other functions as arguments and return values. -

- - A strategy is a function that takes a score as input - and returns an action to perform.
- (Remember, an action is itself a function.) -
- - - Anonymous functions can be declared in Go, as in this example. Function - literals are closures: they inherit the scope of the function in which they - are declared. -

- - One basic strategy in Pig is to continue rolling until you have accumulated at - least k points in a turn, and then stay. The argument k is - enclosed by this function literal, which matches the strategy type - signature. -
- - - We simulate a game of Pig by calling an action to update the - score until one player reaches 100 points. Each - action is selected by calling the strategy function - associated with the current player. - - - - The roundRobin function simulates a tournament and tallies wins. - Each strategy plays each other strategy gamesPerSeries times. - - - - Variadic functions like ratioString take a variable number of - arguments. These arguments are available as a slice inside the function. - - - - The main function defines 100 basic strategies, simulates a round - robin tournament, and then prints the win/loss record of each strategy. -

- - Among these strategies, staying at 25 is best, but the optimal strategy for - Pig is much more complex. -
- -
diff --git a/doc/codewalk/markov.go b/doc/codewalk/markov.go deleted file mode 100644 index 5f62e05144..0000000000 --- a/doc/codewalk/markov.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Generating random text: a Markov chain algorithm - -Based on the program presented in the "Design and Implementation" chapter -of The Practice of Programming (Kernighan and Pike, Addison-Wesley 1999). -See also Computer Recreations, Scientific American 260, 122 - 125 (1989). - -A Markov chain algorithm generates text by creating a statistical model of -potential textual suffixes for a given prefix. Consider this text: - - I am not a number! I am a free man! - -Our Markov chain algorithm would arrange this text into this set of prefixes -and suffixes, or "chain": (This table assumes a prefix length of two words.) - - Prefix Suffix - - "" "" I - "" I am - I am a - I am not - a free man! - am a free - am not a - a number! I - number! I am - not a number! - -To generate text using this table we select an initial prefix ("I am", for -example), choose one of the suffixes associated with that prefix at random -with probability determined by the input statistics ("a"), -and then create a new prefix by removing the first word from the prefix -and appending the suffix (making the new prefix is "am a"). Repeat this process -until we can't find any suffixes for the current prefix or we exceed the word -limit. (The word limit is necessary as the chain table may contain cycles.) - -Our version of this program reads text from standard input, parsing it into a -Markov chain, and writes generated text to standard output. -The prefix and output lengths can be specified using the -prefix and -words -flags on the command-line. -*/ -package main - -import ( - "bufio" - "flag" - "fmt" - "io" - "math/rand" - "os" - "strings" - "time" -) - -// Prefix is a Markov chain prefix of one or more words. -type Prefix []string - -// String returns the Prefix as a string (for use as a map key). -func (p Prefix) String() string { - return strings.Join(p, " ") -} - -// Shift removes the first word from the Prefix and appends the given word. -func (p Prefix) Shift(word string) { - copy(p, p[1:]) - p[len(p)-1] = word -} - -// Chain contains a map ("chain") of prefixes to a list of suffixes. -// A prefix is a string of prefixLen words joined with spaces. -// A suffix is a single word. A prefix can have multiple suffixes. -type Chain struct { - chain map[string][]string - prefixLen int -} - -// NewChain returns a new Chain with prefixes of prefixLen words. -func NewChain(prefixLen int) *Chain { - return &Chain{make(map[string][]string), prefixLen} -} - -// Build reads text from the provided Reader and -// parses it into prefixes and suffixes that are stored in Chain. -func (c *Chain) Build(r io.Reader) { - br := bufio.NewReader(r) - p := make(Prefix, c.prefixLen) - for { - var s string - if _, err := fmt.Fscan(br, &s); err != nil { - break - } - key := p.String() - c.chain[key] = append(c.chain[key], s) - p.Shift(s) - } -} - -// Generate returns a string of at most n words generated from Chain. -func (c *Chain) Generate(n int) string { - p := make(Prefix, c.prefixLen) - var words []string - for i := 0; i < n; i++ { - choices := c.chain[p.String()] - if len(choices) == 0 { - break - } - next := choices[rand.Intn(len(choices))] - words = append(words, next) - p.Shift(next) - } - return strings.Join(words, " ") -} - -func main() { - // Register command-line flags. - numWords := flag.Int("words", 100, "maximum number of words to print") - prefixLen := flag.Int("prefix", 2, "prefix length in words") - - flag.Parse() // Parse command-line flags. - rand.Seed(time.Now().UnixNano()) // Seed the random number generator. - - c := NewChain(*prefixLen) // Initialize a new Chain. - c.Build(os.Stdin) // Build chains from standard input. - text := c.Generate(*numWords) // Generate text. - fmt.Println(text) // Write text to standard output. -} diff --git a/doc/codewalk/markov.xml b/doc/codewalk/markov.xml deleted file mode 100644 index 7e44840dc4..0000000000 --- a/doc/codewalk/markov.xml +++ /dev/null @@ -1,307 +0,0 @@ - - - - - - This codewalk describes a program that generates random text using - a Markov chain algorithm. The package comment describes the algorithm - and the operation of the program. Please read it before continuing. - - - - A chain consists of a prefix and a suffix. Each prefix is a set - number of words, while a suffix is a single word. - A prefix can have an arbitrary number of suffixes. - To model this data, we use a map[string][]string. - Each map key is a prefix (a string) and its values are - lists of suffixes (a slice of strings, []string). -

- Here is the example table from the package comment - as modeled by this data structure: -
-map[string][]string{
-	" ":          {"I"},
-	" I":         {"am"},
-	"I am":       {"a", "not"},
-	"a free":     {"man!"},
-	"am a":       {"free"},
-	"am not":     {"a"},
-	"a number!":  {"I"},
-	"number! I":  {"am"},
-	"not a":      {"number!"},
-}
- While each prefix consists of multiple words, we - store prefixes in the map as a single string. - It would seem more natural to store the prefix as a - []string, but we can't do this with a map because the - key type of a map must implement equality (and slices do not). -

- Therefore, in most of our code we will model prefixes as a - []string and join the strings together with a space - to generate the map key: -
-Prefix               Map key
-
-[]string{"", ""}     " "
-[]string{"", "I"}    " I"
-[]string{"I", "am"}  "I am"
-
-
- - - The complete state of the chain table consists of the table itself and - the word length of the prefixes. The Chain struct stores - this data. - - - - The Chain struct has two unexported fields (those that - do not begin with an upper case character), and so we write a - NewChain constructor function that initializes the - chain map with make and sets the - prefixLen field. -

- This is constructor function is not strictly necessary as this entire - program is within a single package (main) and therefore - there is little practical difference between exported and unexported - fields. We could just as easily write out the contents of this function - when we want to construct a new Chain. - But using these unexported fields is good practice; it clearly denotes - that only methods of Chain and its constructor function should access - those fields. Also, structuring Chain like this means we - could easily move it into its own package at some later date. -
- - - Since we'll be working with prefixes often, we define a - Prefix type with the concrete type []string. - Defining a named type clearly allows us to be explicit when we are - working with a prefix instead of just a []string. - Also, in Go we can define methods on any named type (not just structs), - so we can add methods that operate on Prefix if we need to. - - - - The first method we define on Prefix is - String. It returns a string representation - of a Prefix by joining the slice elements together with - spaces. We will use this method to generate keys when working with - the chain map. - - - - The Build method reads text from an io.Reader - and parses it into prefixes and suffixes that are stored in the - Chain. -

- The io.Reader is an - interface type that is widely used by the standard library and - other Go code. Our code uses the - fmt.Fscan function, which - reads space-separated values from an io.Reader. -

- The Build method returns once the Reader's - Read method returns io.EOF (end of file) - or some other read error occurs. -
- - - This function does many small reads, which can be inefficient for some - Readers. For efficiency we wrap the provided - io.Reader with - bufio.NewReader to create a - new io.Reader that provides buffering. - - - - At the top of the function we make a Prefix slice - p using the Chain's prefixLen - field as its length. - We'll use this variable to hold the current prefix and mutate it with - each new word we encounter. - - - - In our loop we read words from the Reader into a - string variable s using - fmt.Fscan. Since Fscan uses space to - separate each input value, each call will yield just one word - (including punctuation), which is exactly what we need. -

- Fscan returns an error if it encounters a read error - (io.EOF, for example) or if it can't scan the requested - value (in our case, a single string). In either case we just want to - stop scanning, so we break out of the loop. -
- - - The word stored in s is a new suffix. We add the new - prefix/suffix combination to the chain map by computing - the map key with p.String and appending the suffix - to the slice stored under that key. -

- The built-in append function appends elements to a slice - and allocates new storage when necessary. When the provided slice is - nil, append allocates a new slice. - This behavior conveniently ties in with the semantics of our map: - retrieving an unset key returns the zero value of the value type and - the zero value of []string is nil. - When our program encounters a new prefix (yielding a nil - value in the map) append will allocate a new slice. -

- For more information about the append function and slices - in general see the - Slices: usage and internals article. -
- - - Before reading the next word our algorithm requires us to drop the - first word from the prefix and push the current suffix onto the prefix. -

- When in this state -
-p == Prefix{"I", "am"}
-s == "not" 
- the new value for p would be -
-p == Prefix{"am", "not"}
- This operation is also required during text generation so we put - the code to perform this mutation of the slice inside a method on - Prefix named Shift. -
- - - The Shift method uses the built-in copy - function to copy the last len(p)-1 elements of p to - the start of the slice, effectively moving the elements - one index to the left (if you consider zero as the leftmost index). -
-p := Prefix{"I", "am"}
-copy(p, p[1:])
-// p == Prefix{"am", "am"}
- We then assign the provided word to the last index - of the slice: -
-// suffix == "not"
-p[len(p)-1] = suffix
-// p == Prefix{"am", "not"}
-
- - - The Generate method is similar to Build - except that instead of reading words from a Reader - and storing them in a map, it reads words from the map and - appends them to a slice (words). -

- Generate uses a conditional for loop to generate - up to n words. -
- - - At each iteration of the loop we retrieve a list of potential suffixes - for the current prefix. We access the chain map at key - p.String() and assign its contents to choices. -

- If len(choices) is zero we break out of the loop as there - are no potential suffixes for that prefix. - This test also works if the key isn't present in the map at all: - in that case, choices will be nil and the - length of a nil slice is zero. -
- - - To choose a suffix we use the - rand.Intn function. - It returns a random integer up to (but not including) the provided - value. Passing in len(choices) gives us a random index - into the full length of the list. -

- We use that index to pick our new suffix, assign it to - next and append it to the words slice. -

- Next, we Shift the new suffix onto the prefix just as - we did in the Build method. -
- - - Before returning the generated text as a string, we use the - strings.Join function to join the elements of - the words slice together, separated by spaces. - - - - To make it easy to tweak the prefix and generated text lengths we - use the flag package to parse - command-line flags. -

- These calls to flag.Int register new flags with the - flag package. The arguments to Int are the - flag name, its default value, and a description. The Int - function returns a pointer to an integer that will contain the - user-supplied value (or the default value if the flag was omitted on - the command-line). -
- - - The main function begins by parsing the command-line - flags with flag.Parse and seeding the rand - package's random number generator with the current time. -

- If the command-line flags provided by the user are invalid the - flag.Parse function will print an informative usage - message and terminate the program. -
- - - To create the new Chain we call NewChain - with the value of the prefix flag. -

- To build the chain we call Build with - os.Stdin (which implements io.Reader) so - that it will read its input from standard input. -
- - - Finally, to generate text we call Generate with - the value of the words flag and assigning the result - to the variable text. -

- Then we call fmt.Println to write the text to standard - output, followed by a carriage return. -
- - - To use this program, first build it with the - go command: -
-$ go build markov.go
- And then execute it while piping in some input text: -
-$ echo "a man a plan a canal panama" \
-	| ./markov -prefix=1
-a plan a man a plan a canal panama
- Here's a transcript of generating some text using the Go distribution's - README file as source material: -
-$ ./markov -words=10 < $GOROOT/README
-This is the source code repository for the Go source
-$ ./markov -prefix=1 -words=10 < $GOROOT/README
-This is the go directory (the one containing this README).
-$ ./markov -prefix=1 -words=10 < $GOROOT/README
-This is the variable if you have just untarred a
-
- - - The Generate function does a lot of allocations when it - builds the words slice. As an exercise, modify it to - take an io.Writer to which it incrementally writes the - generated text with Fprint. - Aside from being more efficient this makes Generate - more symmetrical to Build. - - -
diff --git a/doc/codewalk/pig.go b/doc/codewalk/pig.go deleted file mode 100644 index 941daaed16..0000000000 --- a/doc/codewalk/pig.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "fmt" - "math/rand" -) - -const ( - win = 100 // The winning score in a game of Pig - gamesPerSeries = 10 // The number of games per series to simulate -) - -// A score includes scores accumulated in previous turns for each player, -// as well as the points scored by the current player in this turn. -type score struct { - player, opponent, thisTurn int -} - -// An action transitions stochastically to a resulting score. -type action func(current score) (result score, turnIsOver bool) - -// roll returns the (result, turnIsOver) outcome of simulating a die roll. -// If the roll value is 1, then thisTurn score is abandoned, and the players' -// roles swap. Otherwise, the roll value is added to thisTurn. -func roll(s score) (score, bool) { - outcome := rand.Intn(6) + 1 // A random int in [1, 6] - if outcome == 1 { - return score{s.opponent, s.player, 0}, true - } - return score{s.player, s.opponent, outcome + s.thisTurn}, false -} - -// stay returns the (result, turnIsOver) outcome of staying. -// thisTurn score is added to the player's score, and the players' roles swap. -func stay(s score) (score, bool) { - return score{s.opponent, s.player + s.thisTurn, 0}, true -} - -// A strategy chooses an action for any given score. -type strategy func(score) action - -// stayAtK returns a strategy that rolls until thisTurn is at least k, then stays. -func stayAtK(k int) strategy { - return func(s score) action { - if s.thisTurn >= k { - return stay - } - return roll - } -} - -// play simulates a Pig game and returns the winner (0 or 1). -func play(strategy0, strategy1 strategy) int { - strategies := []strategy{strategy0, strategy1} - var s score - var turnIsOver bool - currentPlayer := rand.Intn(2) // Randomly decide who plays first - for s.player+s.thisTurn < win { - action := strategies[currentPlayer](s) - s, turnIsOver = action(s) - if turnIsOver { - currentPlayer = (currentPlayer + 1) % 2 - } - } - return currentPlayer -} - -// roundRobin simulates a series of games between every pair of strategies. -func roundRobin(strategies []strategy) ([]int, int) { - wins := make([]int, len(strategies)) - for i := 0; i < len(strategies); i++ { - for j := i + 1; j < len(strategies); j++ { - for k := 0; k < gamesPerSeries; k++ { - winner := play(strategies[i], strategies[j]) - if winner == 0 { - wins[i]++ - } else { - wins[j]++ - } - } - } - } - gamesPerStrategy := gamesPerSeries * (len(strategies) - 1) // no self play - return wins, gamesPerStrategy -} - -// ratioString takes a list of integer values and returns a string that lists -// each value and its percentage of the sum of all values. -// e.g., ratios(1, 2, 3) = "1/6 (16.7%), 2/6 (33.3%), 3/6 (50.0%)" -func ratioString(vals ...int) string { - total := 0 - for _, val := range vals { - total += val - } - s := "" - for _, val := range vals { - if s != "" { - s += ", " - } - pct := 100 * float64(val) / float64(total) - s += fmt.Sprintf("%d/%d (%0.1f%%)", val, total, pct) - } - return s -} - -func main() { - strategies := make([]strategy, win) - for k := range strategies { - strategies[k] = stayAtK(k + 1) - } - wins, games := roundRobin(strategies) - - for k := range strategies { - fmt.Printf("Wins, losses staying at k =% 4d: %s\n", - k+1, ratioString(wins[k], games-wins[k])) - } -} diff --git a/doc/codewalk/popout.png b/doc/codewalk/popout.png deleted file mode 100644 index 9c0c23638bd536fb1ab1bdc7f11e2d86d7671016..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^u+-DVF~s8Z(xBUd2NZZF#hIP@r)(kocT>9Q`Y5~NCI_ZTxvUqy zFJugA3|-(QH^ISHg~?VdLcZ!z_;1dWMU%63Rmh|)b$t@f614qM+NSVTBH!P3d9+rP zut%1a_fCy}9z3n<>%+E?C47B+FTJ0gZA?9VI{R!sqrBNWQ>R7BKnE~*y85}Sb4q9e E0I<|cI{*Lx diff --git a/doc/codewalk/sharemem.xml b/doc/codewalk/sharemem.xml deleted file mode 100644 index 8b47f12b7a..0000000000 --- a/doc/codewalk/sharemem.xml +++ /dev/null @@ -1,181 +0,0 @@ - - - -Go's approach to concurrency differs from the traditional use of -threads and shared memory. Philosophically, it can be summarized: -

-Don't communicate by sharing memory; share memory by communicating. -

-Channels allow you to pass references to data structures between goroutines. -If you consider this as passing around ownership of the data (the ability to -read and write it), they become a powerful and expressive synchronization -mechanism. -

-In this codewalk we will look at a simple program that polls a list of -URLs, checking their HTTP response codes and periodically printing their state. -
- - -The State type represents the state of a URL. -

-The Pollers send State values to the StateMonitor, -which maintains a map of the current state of each URL. -
- - -A Resource represents the state of a URL to be polled: the URL itself -and the number of errors encountered since the last successful poll. -

-When the program starts, it allocates one Resource for each URL. -The main goroutine and the Poller goroutines send the Resources to -each other on channels. -
- - -Each Poller receives Resource pointers from an input channel. -In this program, the convention is that sending a Resource pointer on -a channel passes ownership of the underlying data from the sender -to the receiver. Because of this convention, we know that -no two goroutines will access this Resource at the same time. -This means we don't have to worry about locking to prevent concurrent -access to these data structures. -

-The Poller processes the Resource by calling its Poll method. -

-It sends a State value to the status channel, to inform the StateMonitor -of the result of the Poll. -

-Finally, it sends the Resource pointer to the out channel. This can be -interpreted as the Poller saying "I'm done with this Resource" and -returning ownership of it to the main goroutine. -

-Several goroutines run Pollers, processing Resources in parallel. -
- - -The Poll method (of the Resource type) performs an HTTP HEAD request -for the Resource's URL and returns the HTTP response's status code. -If an error occurs, Poll logs the message to standard error and returns the -error string instead. - - - -The main function starts the Poller and StateMonitor goroutines -and then loops passing completed Resources back to the pending -channel after appropriate delays. - - - -First, main makes two channels of *Resource, pending and complete. -

-Inside main, a new goroutine sends one Resource per URL to pending -and the main goroutine receives completed Resources from complete. -

-The pending and complete channels are passed to each of the Poller -goroutines, within which they are known as in and out. -
- - -StateMonitor will initialize and launch a goroutine that stores the state -of each Resource. We will look at this function in detail later. -

-For now, the important thing to note is that it returns a channel of State, -which is saved as status and passed to the Poller goroutines. -
- - -Now that it has the necessary channels, main launches a number of -Poller goroutines, passing the channels as arguments. -The channels provide the means of communication between the main, Poller, and -StateMonitor goroutines. - - - -To add the initial work to the system, main starts a new goroutine -that allocates and sends one Resource per URL to pending. -

-The new goroutine is necessary because unbuffered channel sends and -receives are synchronous. That means these channel sends will block until -the Pollers are ready to read from pending. -

-Were these sends performed in the main goroutine with fewer Pollers than -channel sends, the program would reach a deadlock situation, because -main would not yet be receiving from complete. -

-Exercise for the reader: modify this part of the program to read a list of -URLs from a file. (You may want to move this goroutine into its own -named function.) -
- - -When a Poller is done with a Resource, it sends it on the complete channel. -This loop receives those Resource pointers from complete. -For each received Resource, it starts a new goroutine calling -the Resource's Sleep method. Using a new goroutine for each -ensures that the sleeps can happen in parallel. -

-Note that any single Resource pointer may only be sent on either pending or -complete at any one time. This ensures that a Resource is either being -handled by a Poller goroutine or sleeping, but never both simultaneously. -In this way, we share our Resource data by communicating. -
- - -Sleep calls time.Sleep to pause before sending the Resource to done. -The pause will either be of a fixed length (pollInterval) plus an -additional delay proportional to the number of sequential errors (r.errCount). -

-This is an example of a typical Go idiom: a function intended to run inside -a goroutine takes a channel, upon which it sends its return value -(or other indication of completed state). -
- - -The StateMonitor receives State values on a channel and periodically -outputs the state of all Resources being polled by the program. - - - -The variable updates is a channel of State, on which the Poller goroutines -send State values. -

-This channel is returned by the function. -
- - -The variable urlStatus is a map of URLs to their most recent status. - - - -A time.Ticker is an object that repeatedly sends a value on a channel at a -specified interval. -

-In this case, ticker triggers the printing of the current state to -standard output every updateInterval nanoseconds. -
- - -StateMonitor will loop forever, selecting on two channels: -ticker.C and update. The select statement blocks until one of its -communications is ready to proceed. -

-When StateMonitor receives a tick from ticker.C, it calls logState to -print the current state. When it receives a State update from updates, -it records the new status in the urlStatus map. -

-Notice that this goroutine owns the urlStatus data structure, -ensuring that it can only be accessed sequentially. -This prevents memory corruption issues that might arise from parallel reads -and/or writes to a shared map. -
- - -In this codewalk we have explored a simple example of using Go's concurrency -primitives to share memory through communication. -

-This should provide a starting point from which to explore the ways in which -goroutines and channels can be used to write expressive and concise concurrent -programs. -
- -
diff --git a/doc/codewalk/urlpoll.go b/doc/codewalk/urlpoll.go deleted file mode 100644 index 1fb99581f0..0000000000 --- a/doc/codewalk/urlpoll.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "log" - "net/http" - "time" -) - -const ( - numPollers = 2 // number of Poller goroutines to launch - pollInterval = 60 * time.Second // how often to poll each URL - statusInterval = 10 * time.Second // how often to log status to stdout - errTimeout = 10 * time.Second // back-off timeout on error -) - -var urls = []string{ - "http://www.google.com/", - "http://golang.org/", - "http://blog.golang.org/", -} - -// State represents the last-known state of a URL. -type State struct { - url string - status string -} - -// StateMonitor maintains a map that stores the state of the URLs being -// polled, and prints the current state every updateInterval nanoseconds. -// It returns a chan State to which resource state should be sent. -func StateMonitor(updateInterval time.Duration) chan<- State { - updates := make(chan State) - urlStatus := make(map[string]string) - ticker := time.NewTicker(updateInterval) - go func() { - for { - select { - case <-ticker.C: - logState(urlStatus) - case s := <-updates: - urlStatus[s.url] = s.status - } - } - }() - return updates -} - -// logState prints a state map. -func logState(s map[string]string) { - log.Println("Current state:") - for k, v := range s { - log.Printf(" %s %s", k, v) - } -} - -// Resource represents an HTTP URL to be polled by this program. -type Resource struct { - url string - errCount int -} - -// Poll executes an HTTP HEAD request for url -// and returns the HTTP status string or an error string. -func (r *Resource) Poll() string { - resp, err := http.Head(r.url) - if err != nil { - log.Println("Error", r.url, err) - r.errCount++ - return err.Error() - } - r.errCount = 0 - return resp.Status -} - -// Sleep sleeps for an appropriate interval (dependent on error state) -// before sending the Resource to done. -func (r *Resource) Sleep(done chan<- *Resource) { - time.Sleep(pollInterval + errTimeout*time.Duration(r.errCount)) - done <- r -} - -func Poller(in <-chan *Resource, out chan<- *Resource, status chan<- State) { - for r := range in { - s := r.Poll() - status <- State{r.url, s} - out <- r - } -} - -func main() { - // Create our input and output channels. - pending, complete := make(chan *Resource), make(chan *Resource) - - // Launch the StateMonitor. - status := StateMonitor(statusInterval) - - // Launch some Poller goroutines. - for i := 0; i < numPollers; i++ { - go Poller(pending, complete, status) - } - - // Send some Resources to the pending queue. - go func() { - for _, url := range urls { - pending <- &Resource{url: url} - } - }() - - for r := range complete { - go r.Sleep(pending) - } -} diff --git a/doc/contribute.html b/doc/contribute.html deleted file mode 100644 index 66a47eb07e..0000000000 --- a/doc/contribute.html +++ /dev/null @@ -1,1294 +0,0 @@ - - -

-The Go project welcomes all contributors. -

- -

-This document is a guide to help you through the process -of contributing to the Go project, which is a little different -from that used by other open source projects. -We assume you have a basic understanding of Git and Go. -

- -

-In addition to the information here, the Go community maintains a -CodeReview wiki page. -Feel free to contribute to the wiki as you learn the review process. -

- -

-Note that the gccgo front end lives elsewhere; -see Contributing to gccgo. -

- -

Becoming a contributor

- -

Overview

- -

-The first step is registering as a Go contributor and configuring your environment. -Here is a checklist of the required steps to follow: -

- -
    -
  • -Step 0: Decide on a single Google Account you will be using to contribute to Go. -Use that account for all the following steps and make sure that git -is configured to create commits with that account's e-mail address. -
  • -
  • -Step 1: Sign and submit a -CLA (Contributor License Agreement). -
  • -
  • -Step 2: Configure authentication credentials for the Go Git repository. -Visit go.googlesource.com, click -"Generate Password" in the page's top right menu bar, and follow the -instructions. -
  • -
  • -Step 3: Register for Gerrit, the code review tool used by the Go team, -by visiting this page. -The CLA and the registration need to be done only once for your account. -
  • -
  • -Step 4: Install git-codereview by running -go get -u golang.org/x/review/git-codereview -
  • -
- -

-If you prefer, there is an automated tool that walks through these steps. -Just run: -

- -
-$ go get -u golang.org/x/tools/cmd/go-contrib-init
-$ cd /code/to/edit
-$ go-contrib-init
-
- -

-The rest of this chapter elaborates on these instructions. -If you have completed the steps above (either manually or through the tool), jump to -Before contributing code. -

- -

Step 0: Select a Google Account

- -

-A contribution to Go is made through a Google account with a specific -e-mail address. -Make sure to use the same account throughout the process and -for all your subsequent contributions. -You may need to decide whether to use a personal address or a corporate address. -The choice will depend on who -will own the copyright for the code that you will be writing -and submitting. -You might want to discuss this topic with your employer before deciding which -account to use. -

- -

-Google accounts can either be Gmail e-mail accounts, G Suite organization accounts, or -accounts associated with an external e-mail address. -For instance, if you need to use -an existing corporate e-mail that is not managed through G Suite, you can create -an account associated -with your existing -e-mail address. -

- -

-You also need to make sure that your Git tool is configured to create commits -using your chosen e-mail address. -You can either configure Git globally -(as a default for all projects), or locally (for a single specific project). -You can check the current configuration with this command: -

- -
-$ git config --global user.email  # check current global config
-$ git config user.email           # check current local config
-
- -

-To change the configured address: -

- -
-$ git config --global user.email name@example.com   # change global config
-$ git config user.email name@example.com            # change local config
-
- - -

Step 1: Contributor License Agreement

- -

-Before sending your first change to the Go project -you must have completed one of the following two CLAs. -Which CLA you should sign depends on who owns the copyright to your work. -

- - - -

-You can check your currently signed agreements and sign new ones at -the Google Developers -Contributor License Agreements website. -If the copyright holder for your contribution has already completed the -agreement in connection with another Google open source project, -it does not need to be completed again. -

- -

-If the copyright holder for the code you are submitting changes—for example, -if you start contributing code on behalf of a new company—please send mail -to the golang-dev -mailing list. -This will let us know the situation so we can make sure an appropriate agreement is -completed and update the AUTHORS file. -

- - -

Step 2: Configure git authentication

- -

-The main Go repository is located at -go.googlesource.com, -a Git server hosted by Google. -Authentication on the web server is made through your Google account, but -you also need to configure git on your computer to access it. -Follow these steps: -

- -
    -
  1. -Visit go.googlesource.com -and click on "Generate Password" in the page's top right menu bar. -You will be redirected to accounts.google.com to sign in. -
  2. -
  3. -After signing in, you will be taken to a page with the title "Configure Git". -This page contains a personalized script that when run locally will configure Git -to hold your unique authentication key. -This key is paired with one that is generated and stored on the server, -analogous to how SSH keys work. -
  4. -
  5. -Copy and run this script locally in your terminal to store your secret -authentication token in a .gitcookies file. -If you are using a Windows computer and running cmd, -you should instead follow the instructions in the yellow box to run the command; -otherwise run the regular script. -
  6. -
- -

Step 3: Create a Gerrit account

- -

-Gerrit is an open-source tool used by Go maintainers to discuss and review -code submissions. -

- -

-To register your account, visit -go-review.googlesource.com/login/ and sign in once using the same Google Account you used above. -

- -

Step 4: Install the git-codereview command

- -

-Changes to Go must be reviewed before they are accepted, no matter who makes the change. -A custom git command called git-codereview -simplifies sending changes to Gerrit. -

- -

-Install the git-codereview command by running, -

- -
-$ go get -u golang.org/x/review/git-codereview
-
- -

-Make sure git-codereview is installed in your shell path, so that the -git command can find it. -Check that -

- -
-$ git codereview help
-
- -

-prints help text, not an error. If it prints an error, make sure that -$GOPATH/bin is in your $PATH. -

- -

-On Windows, when using git-bash you must make sure that -git-codereview.exe is in your git exec-path. -Run git --exec-path to discover the right location then create a -symbolic link or just copy the executable from $GOPATH/bin to this -directory. -

- - -

Before contributing code

- -

-The project welcomes code patches, but to make sure things are well -coordinated you should discuss any significant change before starting -the work. -It's recommended that you signal your intention to contribute in the -issue tracker, either by filing -a new issue or by claiming -an existing one. -

- -

Where to contribute

- -

-The Go project consists of the main -go repository, which contains the -source code for the Go language, as well as many golang.org/x/... repostories. -These contain the various tools and infrastructure that support Go. For -example, golang.org/x/pkgsite -is for pkg.go.dev, -golang.org/x/playground -is for the Go playground, and -golang.org/x/tools contains -a variety of Go tools, including the Go language server, -gopls. You can see a -list of all the golang.org/x/... repositories on -go.googlesource.com. -

- -

Check the issue tracker

- -

-Whether you already know what contribution to make, or you are searching for -an idea, the issue tracker is -always the first place to go. -Issues are triaged to categorize them and manage the workflow. -

- -

-The majority of the golang.org/x/... repos also use the main Go -issue tracker. However, a few of these repositories manage their issues -separately, so please be sure to check the right tracker for the repository to -which you would like to contribute. -

- -

-Most issues will be marked with one of the following workflow labels: -

- -
    -
  • - NeedsInvestigation: The issue is not fully understood - and requires analysis to understand the root cause. -
  • -
  • - NeedsDecision: the issue is relatively well understood, but the - Go team hasn't yet decided the best way to address it. - It would be better to wait for a decision before writing code. - If you are interested in working on an issue in this state, - feel free to "ping" maintainers in the issue's comments - if some time has passed without a decision. -
  • -
  • - NeedsFix: the issue is fully understood and code can be written - to fix it. -
  • -
- -

-You can use GitHub's search functionality to find issues to help out with. Examples: -

- - - -

Open an issue for any new problem

- -

-Excluding very trivial changes, all contributions should be connected -to an existing issue. -Feel free to open one and discuss your plans. -This process gives everyone a chance to validate the design, -helps prevent duplication of effort, -and ensures that the idea fits inside the goals for the language and tools. -It also checks that the design is sound before code is written; -the code review tool is not the place for high-level discussions. -

- -

-When planning work, please note that the Go project follows a six-month development cycle -for the main Go repository. The latter half of each cycle is a three-month -feature freeze during which only bug fixes and documentation updates are -accepted. New contributions can be sent during a feature freeze, but they will -not be merged until the freeze is over. The freeze applies to the entire main -repository as well as to the code in golang.org/x/... repositories that is -needed to build the binaries included in the release. See the lists of packages -vendored into -the standard library -and the go command. -

- -

-Significant changes to the language, libraries, or tools must go -through the -change proposal process -before they can be accepted. -

- -

-Sensitive security-related issues (only!) should be reported to security@golang.org. -

- -

Sending a change via GitHub

- -

-First-time contributors that are already familiar with the -GitHub flow -are encouraged to use the same process for Go contributions. -Even though Go -maintainers use Gerrit for code review, a bot called Gopherbot has been created to sync -GitHub pull requests to Gerrit. -

- -

-Open a pull request as you normally would. -Gopherbot will create a corresponding Gerrit change and post a link to -it on your GitHub pull request; updates to the pull request will also -get reflected in the Gerrit change. -When somebody comments on the change, their comment will be also -posted in your pull request, so you will get a notification. -

- -

-Some things to keep in mind: -

- -
    -
  • -To update the pull request with new code, just push it to the branch; you can either -add more commits, or rebase and force-push (both styles are accepted). -
  • -
  • -If the request is accepted, all commits will be squashed, and the final -commit description will be composed by concatenating the pull request's -title and description. -The individual commits' descriptions will be discarded. -See Writing good commit messages for some -suggestions. -
  • -
  • -Gopherbot is unable to sync line-by-line codereview into GitHub: only the -contents of the overall comment on the request will be synced. -Remember you can always visit Gerrit to see the fine-grained review. -
  • -
- -

Sending a change via Gerrit

- -

-It is not possible to fully sync Gerrit and GitHub, at least at the moment, -so we recommend learning Gerrit. -It's different but powerful and familiarity with it will help you understand -the flow. -

- -

Overview

- -

-This is an overview of the overall process: -

- -
    -
  • -Step 1: Clone the source code from go.googlesource.com and -make sure it's stable by compiling and testing it once. - -

    If you're making a change to the -main Go repository:

    - -
    -$ git clone https://go.googlesource.com/go
    -$ cd go/src
    -$ ./all.bash                                # compile and test
    -
    - -

    -If you're making a change to one of the golang.org/x/... repositories -(golang.org/x/tools, -in this example): -

    - -
    -$ git clone https://go.googlesource.com/tools
    -$ cd tools
    -$ go test ./...                             # compile and test
    -
    -
  • - -
  • -Step 2: Prepare changes in a new branch, created from the master branch. -To commit the changes, use git codereview change; that -will create or amend a single commit in the branch. -
    -$ git checkout -b mybranch
    -$ [edit files...]
    -$ git add [files...]
    -$ git codereview change   # create commit in the branch
    -$ [edit again...]
    -$ git add [files...]
    -$ git codereview change   # amend the existing commit with new changes
    -$ [etc.]
    -
    -
  • - -
  • -Step 3: Test your changes, either by running the tests in the package -you edited or by re-running all.bash. - -

    In the main Go repository:

    -
    -$ ./all.bash    # recompile and test
    -
    - -

    In a golang.org/x/... repository:

    -
    -$ go test ./... # recompile and test
    -
    -
  • - -
  • -Step 4: Send the changes for review to Gerrit using git -codereview mail (which doesn't use e-mail, despite the name). -
    -$ git codereview mail     # send changes to Gerrit
    -
    -
  • - -
  • -Step 5: After a review, apply changes to the same single commit -and mail them to Gerrit again: -
    -$ [edit files...]
    -$ git add [files...]
    -$ git codereview change   # update same commit
    -$ git codereview mail     # send to Gerrit again
    -
    -
  • -
- -

-The rest of this section describes these steps in more detail. -

- - -

Step 1: Clone the source code

- -

-In addition to a recent Go installation, you need to have a local copy of the source -checked out from the correct repository. -You can check out the Go source repo onto your local file system anywhere -you want as long as it's outside your GOPATH. -Clone from go.googlesource.com (not GitHub): -

- -

Main Go repository:

-
-$ git clone https://go.googlesource.com/go
-$ cd go
-
- -

golang.org/x/... repository

-(golang.org/x/tools in this example): -
-$ git clone https://go.googlesource.com/tools
-$ cd tools
-
- -

Step 2: Prepare changes in a new branch

- -

-Each Go change must be made in a separate branch, created from the master branch. -You can use -the normal git commands to create a branch and add changes to the -staging area: -

- -
-$ git checkout -b mybranch
-$ [edit files...]
-$ git add [files...]
-
- -

-To commit changes, instead of git commit, use git codereview change. -

- -
-$ git codereview change
-(open $EDITOR)
-
- -

-You can edit the commit description in your favorite editor as usual. -The git codereview change command -will automatically add a unique Change-Id line near the bottom. -That line is used by Gerrit to match successive uploads of the same change. -Do not edit or delete it. -A Change-Id looks like this: -

- -
-Change-Id: I2fbdbffb3aab626c4b6f56348861b7909e3e8990
-
- -

-The tool also checks that you've -run go fmt over the source code, and that -the commit message follows the suggested format. -

- -

-If you need to edit the files again, you can stage the new changes and -re-run git codereview change: each subsequent -run will amend the existing commit while preserving the Change-Id. -

- -

-Make sure that you always keep a single commit in each branch. -If you add more -commits by mistake, you can use git rebase to -squash them together -into a single one. -

- - -

Step 3: Test your changes

- -

-You've written and tested your code, but -before sending code out for review, run all the tests for the whole -tree to make sure the changes don't break other packages or programs. -

- -

In the main Go repository

- -

This can be done by running all.bash:

- -
-$ cd go/src
-$ ./all.bash
-
- -

-(To build under Windows use all.bat) -

- -

-After running for a while and printing a lot of testing output, the command should finish -by printing, -

- -
-ALL TESTS PASSED
-
- -

-You can use make.bash instead of all.bash -to just build the compiler and the standard library without running the test suite. -Once the go tool is built, it will be installed as bin/go -under the directory in which you cloned the Go repository, and you can -run it directly from there. -See also -the section on how to test your changes quickly. -

- -

In the golang.org/x/... repositories

- -

-Run the tests for the entire repository -(golang.org/x/tools, -in this example): -

- -
-$ cd tools
-$ go test ./...
-
- -

-If you're concerned about the build status, -you can check the Build Dashboard. -Test failures may also be caught by the TryBots in code review. -

- -

-Some repositories, like -golang.org/x/vscode-go will -have different testing infrastructures, so always check the documentation -for the repository in which you are working. The README file in the root of the -repository will usually have this information. -

- -

Step 4: Send changes for review

- -

-Once the change is ready and tested over the whole tree, send it for review. -This is done with the mail sub-command which, despite its name, doesn't -directly mail anything; it just sends the change to Gerrit: -

- -
-$ git codereview mail
-
- -

-Gerrit assigns your change a number and URL, which git codereview mail will print, something like: -

- -
-remote: New Changes:
-remote:   https://go-review.googlesource.com/99999 math: improved Sin, Cos and Tan precision for very large arguments
-
- -

-If you get an error instead, check the -Troubleshooting mail errors section. -

- -

-If your change relates to an open GitHub issue and you have followed the -suggested commit message format, the issue will be updated in a few minutes by a bot, -linking your Gerrit change to it in the comments. -

- - -

Step 5: Revise changes after a review

- -

-Go maintainers will review your code on Gerrit, and you will get notifications via e-mail. -You can see the review on Gerrit and comment on them there. -You can also reply -using e-mail -if you prefer. -

- -

-If you need to revise your change after the review, edit the files in -the same branch you previously created, add them to the Git staging -area, and then amend the commit with -git codereview change: -

- -
-$ git codereview change     # amend current commit
-(open $EDITOR)
-$ git codereview mail       # send new changes to Gerrit
-
- -

-If you don't need to change the commit description, just save and exit from the editor. -Remember not to touch the special Change-Id line. -

- -

-Again, make sure that you always keep a single commit in each branch. -If you add more -commits by mistake, you can use git rebase to -squash them together -into a single one. -

- -

Good commit messages

- -

-Commit messages in Go follow a specific set of conventions, -which we discuss in this section. -

- -

-Here is an example of a good one: -

- -
-math: improve Sin, Cos and Tan precision for very large arguments
-
-The existing implementation has poor numerical properties for
-large arguments, so use the McGillicutty algorithm to improve
-accuracy above 1e10.
-
-The algorithm is described at https://wikipedia.org/wiki/McGillicutty_Algorithm
-
-Fixes #159
-
- -

First line

- -

-The first line of the change description is conventionally a short one-line -summary of the change, prefixed by the primary affected package. -

- -

-A rule of thumb is that it should be written so to complete the sentence -"This change modifies Go to _____." -That means it does not start with a capital letter, is not a complete sentence, -and actually summarizes the result of the change. -

- -

-Follow the first line by a blank line. -

- -

Main content

- -

-The rest of the description elaborates and should provide context for the -change and explain what it does. -Write in complete sentences with correct punctuation, just like -for your comments in Go. -Don't use HTML, Markdown, or any other markup language. -

- -

-Add any relevant information, such as benchmark data if the change -affects performance. -The benchstat -tool is conventionally used to format -benchmark data for change descriptions. -

- -

Referencing issues

- -

-The special notation "Fixes #12345" associates the change with issue 12345 in the -Go issue tracker. -When this change is eventually applied, the issue -tracker will automatically mark the issue as fixed. -

- -

-If the change is a partial step towards the resolution of the issue, -write "Updates #12345" instead. -This will leave a comment in the issue linking back to the change in -Gerrit, but it will not close the issue when the change is applied. -

- -

-If you are sending a change against a golang.org/x/... repository, you must use -the fully-qualified syntax supported by GitHub to make sure the change is -linked to the issue in the main repository, not the x/ repository. -Most issues are tracked in the main repository's issue tracker. -The correct form is "Fixes golang/go#159". -

- - -

The review process

- -

-This section explains the review process in detail and how to approach -reviews after a change has been mailed. -

- - -

Common beginner mistakes

- -

-When a change is sent to Gerrit, it is usually triaged within a few days. -A maintainer will have a look and provide some initial review that for first-time -contributors usually focuses on basic cosmetics and common mistakes. -These include things like: -

- -
    -
  • -Commit message not following the suggested -format. -
  • - -
  • -The lack of a linked GitHub issue. -The vast majority of changes -require a linked issue that describes the bug or the feature that the change -fixes or implements, and consensus should have been reached on the tracker -before proceeding with it. -Gerrit reviews do not discuss the merit of the change, -just its implementation. -
    -Only trivial or cosmetic changes will be accepted without an associated issue. -
  • - -
  • -Change sent during the freeze phase of the development cycle, when the tree -is closed for general changes. -In this case, -a maintainer might review the code with a line such as R=go1.12, -which means that it will be reviewed later when the tree opens for a new -development window. -You can add R=go1.XX as a comment yourself -if you know that it's not the correct time frame for the change. -
  • -
- -

Trybots

- -

-After an initial reading of your change, maintainers will trigger trybots, -a cluster of servers that will run the full test suite on several different -architectures. -Most trybots complete in a few minutes, at which point a link will -be posted in Gerrit where you can see the results. -

- -

-If the trybot run fails, follow the link and check the full logs of the -platforms on which the tests failed. -Try to understand what broke, update your patch to fix it, and upload again. -Maintainers will trigger a new trybot run to see -if the problem was fixed. -

- -

-Sometimes, the tree can be broken on some platforms for a few hours; if -the failure reported by the trybot doesn't seem related to your patch, go to the -Build Dashboard and check if the same -failure appears in other recent commits on the same platform. -In this case, -feel free to write a comment in Gerrit to mention that the failure is -unrelated to your change, to help maintainers understand the situation. -

- -

Reviews

- -

-The Go community values very thorough reviews. -Think of each review comment like a ticket: you are expected to somehow "close" it -by acting on it, either by implementing the suggestion or convincing the -reviewer otherwise. -

- -

-After you update the change, go through the review comments and make sure -to reply to every one. -You can click the "Done" button to reply -indicating that you've implemented the reviewer's suggestion; otherwise, -click on "Reply" and explain why you have not, or what you have done instead. -

- -

-It is perfectly normal for changes to go through several round of reviews, -with one or more reviewers making new comments every time -and then waiting for an updated change before reviewing again. -This cycle happens even for experienced contributors, so -don't be discouraged by it. -

- -

Voting conventions

- -

-As they near a decision, reviewers will make a "vote" on your change. -The Gerrit voting system involves an integer in the range -2 to +2: -

- -
    -
  • - +2 The change is approved for being merged. - Only Go maintainers can cast a +2 vote. -
  • -
  • - +1 The change looks good, but either the reviewer is requesting - minor changes before approving it, or they are not a maintainer and cannot - approve it, but would like to encourage an approval. -
  • -
  • - -1 The change is not good the way it is but might be fixable. - A -1 vote will always have a comment explaining why the change is unacceptable. -
  • -
  • - -2 The change is blocked by a maintainer and cannot be approved. - Again, there will be a comment explaining the decision. -
  • -
- -

-At least two maintainers must approve of the change, and at least one -of those maintainers must +2 the change. -The second maintainer may cast a vote of Trust+1, meaning that the -change looks basically OK, but that the maintainer hasn't done the -detailed review required for a +2 vote. -

- -

Submitting an approved change

- -

-After the code has been +2'ed and Trust+1'ed, an approver will -apply it to the master branch using the Gerrit user interface. -This is called "submitting the change". -

- -

-The two steps (approving and submitting) are separate because in some cases maintainers -may want to approve it but not to submit it right away (for instance, -the tree could be temporarily frozen). -

- -

-Submitting a change checks it into the repository. -The change description will include a link to the code review, -which will be updated with a link to the change -in the repository. -Since the method used to integrate the changes is Git's "Cherry Pick", -the commit hashes in the repository will be changed by -the submit operation. -

- -

-If your change has been approved for a few days without being -submitted, feel free to write a comment in Gerrit requesting -submission. -

- - -

More information

- -

-In addition to the information here, the Go community maintains a CodeReview wiki page. -Feel free to contribute to this page as you learn more about the review process. -

- - - -

Miscellaneous topics

- -

-This section collects a number of other comments that are -outside the issue/edit/code review/submit process itself. -

- - - - -

-Files in the Go repository don't list author names, both to avoid clutter -and to avoid having to keep the lists up to date. -Instead, your name will appear in the -change log and in the CONTRIBUTORS file and perhaps the AUTHORS file. -These files are automatically generated from the commit logs periodically. -The AUTHORS file defines who “The Go -Authors”—the copyright holders—are. -

- -

-New files that you contribute should use the standard copyright header: -

- -
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
- -

-(Use the current year if you're reading this in 2022 or beyond.) -Files in the repository are copyrighted the year they are added. -Do not update the copyright year on files that you change. -

- - - - -

Troubleshooting mail errors

- -

-The most common way that the git codereview mail -command fails is because the e-mail address in the commit does not match the one -that you used during the registration process. - -
-If you see something like... -

- -
-remote: Processing changes: refs: 1, done
-remote:
-remote: ERROR:  In commit ab13517fa29487dcf8b0d48916c51639426c5ee9
-remote: ERROR:  author email address XXXXXXXXXXXXXXXXXXX
-remote: ERROR:  does not match your user account.
-
- -

-you need to configure Git for this repository to use the -e-mail address that you registered with. -To change the e-mail address to ensure this doesn't happen again, run: -

- -
-$ git config user.email email@address.com
-
- -

-Then change the commit to use this alternative e-mail address with this command: -

- -
-$ git commit --amend --author="Author Name <email@address.com>"
-
- -

-Then retry by running: -

- -
-$ git codereview mail
-
- - -

Quickly testing your changes

- -

-Running all.bash for every single change to the code tree -is burdensome. -Even though it is strongly suggested to run it before -sending a change, during the normal development cycle you may want -to compile and test only the package you are developing. -

- -
    -
  • -In general, you can run make.bash instead of all.bash -to only rebuild the Go tool chain without running the whole test suite. -Or you -can run run.bash to only run the whole test suite without rebuilding -the tool chain. -You can think of all.bash as make.bash -followed by run.bash. -
  • - -
  • -In this section, we'll call the directory into which you cloned the Go repository $GODIR. -The go tool built by $GODIR/src/make.bash will be installed -in $GODIR/bin/go and you -can invoke it to test your code. -For instance, if you -have modified the compiler and you want to test how it affects the -test suite of your own project, just run go test -using it: - -
    -$ cd <MYPROJECTDIR>
    -$ $GODIR/bin/go test
    -
    -
  • - -
  • -If you're changing the standard library, you probably don't need to rebuild -the compiler: you can just run the tests for the package you've changed. -You can do that either with the Go version you normally use, or -with the Go compiler built from your clone (which is -sometimes required because the standard library code you're modifying -might require a newer version than the stable one you have installed). - -
    -$ cd $GODIR/src/crypto/sha1
    -$ [make changes...]
    -$ $GODIR/bin/go test .
    -
    -
  • - -
  • -If you're modifying the compiler itself, you can just recompile -the compile tool (which is the internal binary invoked -by go build to compile each single package). -After that, you will want to test it by compiling or running something. - -
    -$ cd $GODIR/src
    -$ [make changes...]
    -$ $GODIR/bin/go install cmd/compile
    -$ $GODIR/bin/go build [something...]   # test the new compiler
    -$ $GODIR/bin/go run [something...]     # test the new compiler
    -$ $GODIR/bin/go test [something...]    # test the new compiler
    -
    - -The same applies to other internal tools of the Go tool chain, -such as asm, cover, link, and so on. -Just recompile and install the tool using go -install cmd/<TOOL> and then use -the built Go binary to test it. -
  • - -
  • -In addition to the standard per-package tests, there is a top-level -test suite in $GODIR/test that contains -several black-box and regression tests. -The test suite is run -by all.bash but you can also run it manually: - -
    -$ cd $GODIR/test
    -$ $GODIR/bin/go run run.go
    -
    -
- - -

Specifying a reviewer / CCing others

- -

-Unless explicitly told otherwise, such as in the discussion leading -up to sending in the change, it's better not to specify a reviewer. -All changes are automatically CC'ed to the -golang-codereviews@googlegroups.com -mailing list. -If this is your first ever change, there may be a moderation -delay before it appears on the mailing list, to prevent spam. -

- -

-You can specify a reviewer or CC interested parties -using the -r or -cc options. -Both accept a comma-separated list of e-mail addresses: -

- -
-$ git codereview mail -r joe@golang.org -cc mabel@example.com,math-nuts@swtch.com
-
- - -

Synchronize your client

- -

-While you were working, others might have submitted changes to the repository. -To update your local branch, run -

- -
-$ git codereview sync
-
- -

-(Under the covers this runs -git pull -r.) -

- - -

Reviewing code by others

- -

-As part of the review process reviewers can propose changes directly (in the -GitHub workflow this would be someone else attaching commits to a pull request). - -You can import these changes proposed by someone else into your local Git repository. -On the Gerrit review page, click the "Download ▼" link in the upper right -corner, copy the "Checkout" command and run it from your local Git repo. -It will look something like this: -

- -
-$ git fetch https://go.googlesource.com/review refs/changes/21/13245/1 && git checkout FETCH_HEAD
-
- -

-To revert, change back to the branch you were working in. -

- - -

Set up git aliases

- -

-The git-codereview command can be run directly from the shell -by typing, for instance, -

- -
-$ git codereview sync
-
- -

-but it is more convenient to set up aliases for git-codereview's own -subcommands, so that the above becomes, -

- -
-$ git sync
-
- -

-The git-codereview subcommands have been chosen to be distinct from -Git's own, so it's safe to define these aliases. -To install them, copy this text into your -Git configuration file (usually .gitconfig in your home directory): -

- -
-[alias]
-	change = codereview change
-	gofmt = codereview gofmt
-	mail = codereview mail
-	pending = codereview pending
-	submit = codereview submit
-	sync = codereview sync
-
- - -

Sending multiple dependent changes

- -

-Advanced users may want to stack up related commits in a single branch. -Gerrit allows for changes to be dependent on each other, forming such a dependency chain. -Each change will need to be approved and submitted separately but the dependency -will be visible to reviewers. -

- -

-To send out a group of dependent changes, keep each change as a different commit under -the same branch, and then run: -

- -
-$ git codereview mail HEAD
-
- -

-Make sure to explicitly specify HEAD, which is usually not required when sending -single changes. More details can be found in the git-codereview documentation. -

diff --git a/doc/debugging_with_gdb.html b/doc/debugging_with_gdb.html deleted file mode 100644 index e1fb292f06..0000000000 --- a/doc/debugging_with_gdb.html +++ /dev/null @@ -1,554 +0,0 @@ - - - - - -

-The following instructions apply to the standard toolchain -(the gc Go compiler and tools). -Gccgo has native gdb support. -

-

-Note that -Delve is a better -alternative to GDB when debugging Go programs built with the standard -toolchain. It understands the Go runtime, data structures, and -expressions better than GDB. Delve currently supports Linux, OSX, -and Windows on amd64. -For the most up-to-date list of supported platforms, please see - - the Delve documentation. -

-
- -

-GDB does not understand Go programs well. -The stack management, threading, and runtime contain aspects that differ -enough from the execution model GDB expects that they can confuse -the debugger and cause incorrect results even when the program is -compiled with gccgo. -As a consequence, although GDB can be useful in some situations (e.g., -debugging Cgo code, or debugging the runtime itself), it is not -a reliable debugger for Go programs, particularly heavily concurrent -ones. Moreover, it is not a priority for the Go project to address -these issues, which are difficult. -

- -

-In short, the instructions below should be taken only as a guide to how -to use GDB when it works, not as a guarantee of success. - -Besides this overview you might want to consult the -GDB manual. -

- -

-

- -

Introduction

- -

-When you compile and link your Go programs with the gc toolchain -on Linux, macOS, FreeBSD or NetBSD, the resulting binaries contain DWARFv4 -debugging information that recent versions (≥7.5) of the GDB debugger can -use to inspect a live process or a core dump. -

- -

-Pass the '-w' flag to the linker to omit the debug information -(for example, go build -ldflags=-w prog.go). -

- -

-The code generated by the gc compiler includes inlining of -function invocations and registerization of variables. These optimizations -can sometimes make debugging with gdb harder. -If you find that you need to disable these optimizations, -build your program using go build -gcflags=all="-N -l". -

- -

-If you want to use gdb to inspect a core dump, you can trigger a dump -on a program crash, on systems that permit it, by setting -GOTRACEBACK=crash in the environment (see the - runtime package -documentation for more info). -

- -

Common Operations

- -
    -
  • -Show file and line number for code, set breakpoints and disassemble: -
    (gdb) list
    -(gdb) list line
    -(gdb) list file.go:line
    -(gdb) break line
    -(gdb) break file.go:line
    -(gdb) disas
    -
  • -
  • -Show backtraces and unwind stack frames: -
    (gdb) bt
    -(gdb) frame n
    -
  • -
  • -Show the name, type and location on the stack frame of local variables, -arguments and return values: -
    (gdb) info locals
    -(gdb) info args
    -(gdb) p variable
    -(gdb) whatis variable
    -
  • -
  • -Show the name, type and location of global variables: -
    (gdb) info variables regexp
    -
  • -
- - -

Go Extensions

- -

-A recent extension mechanism to GDB allows it to load extension scripts for a -given binary. The toolchain uses this to extend GDB with a handful of -commands to inspect internals of the runtime code (such as goroutines) and to -pretty print the built-in map, slice and channel types. -

- -
    -
  • -Pretty printing a string, slice, map, channel or interface: -
    (gdb) p var
    -
  • -
  • -A $len() and $cap() function for strings, slices and maps: -
    (gdb) p $len(var)
    -
  • -
  • -A function to cast interfaces to their dynamic types: -
    (gdb) p $dtype(var)
    -(gdb) iface var
    -

    Known issue: GDB can’t automatically find the dynamic -type of an interface value if its long name differs from its short name -(annoying when printing stacktraces, the pretty printer falls back to printing -the short type name and a pointer).

    -
  • -
  • -Inspecting goroutines: -
    (gdb) info goroutines
    -(gdb) goroutine n cmd
    -(gdb) help goroutine
    -For example: -
    (gdb) goroutine 12 bt
    -You can inspect all goroutines by passing all instead of a specific goroutine's ID. -For example: -
    (gdb) goroutine all bt
    -
  • -
- -

-If you'd like to see how this works, or want to extend it, take a look at src/runtime/runtime-gdb.py in -the Go source distribution. It depends on some special magic types -(hash<T,U>) and variables (runtime.m and -runtime.g) that the linker -(src/cmd/link/internal/ld/dwarf.go) ensures are described in -the DWARF code. -

- -

-If you're interested in what the debugging information looks like, run -objdump -W a.out and browse through the .debug_* -sections. -

- - -

Known Issues

- -
    -
  1. String pretty printing only triggers for type string, not for types derived -from it.
  2. -
  3. Type information is missing for the C parts of the runtime library.
  4. -
  5. GDB does not understand Go’s name qualifications and treats -"fmt.Print" as an unstructured literal with a "." -that needs to be quoted. It objects even more strongly to method names of -the form pkg.(*MyType).Meth. -
  6. As of Go 1.11, debug information is compressed by default. -Older versions of gdb, such as the one available by default on MacOS, -do not understand the compression. -You can generate uncompressed debug information by using go -build -ldflags=-compressdwarf=false. -(For convenience you can put the -ldflags option in -the GOFLAGS -environment variable so that you don't have to specify it each time.) -
  7. -
- -

Tutorial

- -

-In this tutorial we will inspect the binary of the -regexp package's unit tests. To build the binary, -change to $GOROOT/src/regexp and run go test -c. -This should produce an executable file named regexp.test. -

- - -

Getting Started

- -

-Launch GDB, debugging regexp.test: -

- -
-$ gdb regexp.test
-GNU gdb (GDB) 7.2-gg8
-Copyright (C) 2010 Free Software Foundation, Inc.
-License GPLv  3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
-Type "show copying" and "show warranty" for licensing/warranty details.
-This GDB was configured as "x86_64-linux".
-
-Reading symbols from  /home/user/go/src/regexp/regexp.test...
-done.
-Loading Go Runtime support.
-(gdb) 
-
- -

-The message "Loading Go Runtime support" means that GDB loaded the -extension from $GOROOT/src/runtime/runtime-gdb.py. -

- -

-To help GDB find the Go runtime sources and the accompanying support script, -pass your $GOROOT with the '-d' flag: -

- -
-$ gdb regexp.test -d $GOROOT
-
- -

-If for some reason GDB still can't find that directory or that script, you can load -it by hand by telling gdb (assuming you have the go sources in -~/go/): -

- -
-(gdb) source ~/go/src/runtime/runtime-gdb.py
-Loading Go Runtime support.
-
- -

Inspecting the source

- -

-Use the "l" or "list" command to inspect source code. -

- -
-(gdb) l
-
- -

-List a specific part of the source parameterizing "list" with a -function name (it must be qualified with its package name). -

- -
-(gdb) l main.main
-
- -

-List a specific file and line number: -

- -
-(gdb) l regexp.go:1
-(gdb) # Hit enter to repeat last command. Here, this lists next 10 lines.
-
- - -

Naming

- -

-Variable and function names must be qualified with the name of the packages -they belong to. The Compile function from the regexp -package is known to GDB as 'regexp.Compile'. -

- -

-Methods must be qualified with the name of their receiver types. For example, -the *Regexp type’s String method is known as -'regexp.(*Regexp).String'. -

- -

-Variables that shadow other variables are magically suffixed with a number in the debug info. -Variables referenced by closures will appear as pointers magically prefixed with '&'. -

- -

Setting breakpoints

- -

-Set a breakpoint at the TestFind function: -

- -
-(gdb) b 'regexp.TestFind'
-Breakpoint 1 at 0x424908: file /home/user/go/src/regexp/find_test.go, line 148.
-
- -

-Run the program: -

- -
-(gdb) run
-Starting program: /home/user/go/src/regexp/regexp.test
-
-Breakpoint 1, regexp.TestFind (t=0xf8404a89c0) at /home/user/go/src/regexp/find_test.go:148
-148	func TestFind(t *testing.T) {
-
- -

-Execution has paused at the breakpoint. -See which goroutines are running, and what they're doing: -

- -
-(gdb) info goroutines
-  1  waiting runtime.gosched
-* 13  running runtime.goexit
-
- -

-the one marked with the * is the current goroutine. -

- -

Inspecting the stack

- -

-Look at the stack trace for where we’ve paused the program: -

- -
-(gdb) bt  # backtrace
-#0  regexp.TestFind (t=0xf8404a89c0) at /home/user/go/src/regexp/find_test.go:148
-#1  0x000000000042f60b in testing.tRunner (t=0xf8404a89c0, test=0x573720) at /home/user/go/src/testing/testing.go:156
-#2  0x000000000040df64 in runtime.initdone () at /home/user/go/src/runtime/proc.c:242
-#3  0x000000f8404a89c0 in ?? ()
-#4  0x0000000000573720 in ?? ()
-#5  0x0000000000000000 in ?? ()
-
- -

-The other goroutine, number 1, is stuck in runtime.gosched, blocked on a channel receive: -

- -
-(gdb) goroutine 1 bt
-#0  0x000000000040facb in runtime.gosched () at /home/user/go/src/runtime/proc.c:873
-#1  0x00000000004031c9 in runtime.chanrecv (c=void, ep=void, selected=void, received=void)
- at  /home/user/go/src/runtime/chan.c:342
-#2  0x0000000000403299 in runtime.chanrecv1 (t=void, c=void) at/home/user/go/src/runtime/chan.c:423
-#3  0x000000000043075b in testing.RunTests (matchString={void (struct string, struct string, bool *, error *)}
- 0x7ffff7f9ef60, tests=  []testing.InternalTest = {...}) at /home/user/go/src/testing/testing.go:201
-#4  0x00000000004302b1 in testing.Main (matchString={void (struct string, struct string, bool *, error *)} 
- 0x7ffff7f9ef80, tests= []testing.InternalTest = {...}, benchmarks= []testing.InternalBenchmark = {...})
-at /home/user/go/src/testing/testing.go:168
-#5  0x0000000000400dc1 in main.main () at /home/user/go/src/regexp/_testmain.go:98
-#6  0x00000000004022e7 in runtime.mainstart () at /home/user/go/src/runtime/amd64/asm.s:78
-#7  0x000000000040ea6f in runtime.initdone () at /home/user/go/src/runtime/proc.c:243
-#8  0x0000000000000000 in ?? ()
-
- -

-The stack frame shows we’re currently executing the regexp.TestFind function, as expected. -

- -
-(gdb) info frame
-Stack level 0, frame at 0x7ffff7f9ff88:
- rip = 0x425530 in regexp.TestFind (/home/user/go/src/regexp/find_test.go:148); 
-    saved rip 0x430233
- called by frame at 0x7ffff7f9ffa8
- source language minimal.
- Arglist at 0x7ffff7f9ff78, args: t=0xf840688b60
- Locals at 0x7ffff7f9ff78, Previous frame's sp is 0x7ffff7f9ff88
- Saved registers:
-  rip at 0x7ffff7f9ff80
-
- -

-The command info locals lists all variables local to the function and their values, but is a bit -dangerous to use, since it will also try to print uninitialized variables. Uninitialized slices may cause gdb to try -to print arbitrary large arrays. -

- -

-The function’s arguments: -

- -
-(gdb) info args
-t = 0xf840688b60
-
- -

-When printing the argument, notice that it’s a pointer to a -Regexp value. Note that GDB has incorrectly put the * -on the right-hand side of the type name and made up a 'struct' keyword, in traditional C style. -

- -
-(gdb) p re
-(gdb) p t
-$1 = (struct testing.T *) 0xf840688b60
-(gdb) p t
-$1 = (struct testing.T *) 0xf840688b60
-(gdb) p *t
-$2 = {errors = "", failed = false, ch = 0xf8406f5690}
-(gdb) p *t->ch
-$3 = struct hchan<*testing.T>
-
- -

-That struct hchan<*testing.T> is the -runtime-internal representation of a channel. It is currently empty, -or gdb would have pretty-printed its contents. -

- -

-Stepping forward: -

- -
-(gdb) n  # execute next line
-149             for _, test := range findTests {
-(gdb)    # enter is repeat
-150                     re := MustCompile(test.pat)
-(gdb) p test.pat
-$4 = ""
-(gdb) p re
-$5 = (struct regexp.Regexp *) 0xf84068d070
-(gdb) p *re
-$6 = {expr = "", prog = 0xf840688b80, prefix = "", prefixBytes =  []uint8, prefixComplete = true, 
-  prefixRune = 0, cond = 0 '\000', numSubexp = 0, longest = false, mu = {state = 0, sema = 0}, 
-  machine =  []*regexp.machine}
-(gdb) p *re->prog
-$7 = {Inst =  []regexp/syntax.Inst = {{Op = 5 '\005', Out = 0, Arg = 0, Rune =  []int}, {Op = 
-    6 '\006', Out = 2, Arg = 0, Rune =  []int}, {Op = 4 '\004', Out = 0, Arg = 0, Rune =  []int}}, 
-  Start = 1, NumCap = 2}
-
- - -

-We can step into the Stringfunction call with "s": -

- -
-(gdb) s
-regexp.(*Regexp).String (re=0xf84068d070, noname=void) at /home/user/go/src/regexp/regexp.go:97
-97      func (re *Regexp) String() string {
-
- -

-Get a stack trace to see where we are: -

- -
-(gdb) bt
-#0  regexp.(*Regexp).String (re=0xf84068d070, noname=void)
-    at /home/user/go/src/regexp/regexp.go:97
-#1  0x0000000000425615 in regexp.TestFind (t=0xf840688b60)
-    at /home/user/go/src/regexp/find_test.go:151
-#2  0x0000000000430233 in testing.tRunner (t=0xf840688b60, test=0x5747b8)
-    at /home/user/go/src/testing/testing.go:156
-#3  0x000000000040ea6f in runtime.initdone () at /home/user/go/src/runtime/proc.c:243
-....
-
- -

-Look at the source code: -

- -
-(gdb) l
-92              mu      sync.Mutex
-93              machine []*machine
-94      }
-95
-96      // String returns the source text used to compile the regular expression.
-97      func (re *Regexp) String() string {
-98              return re.expr
-99      }
-100
-101     // Compile parses a regular expression and returns, if successful,
-
- -

Pretty Printing

- -

-GDB's pretty printing mechanism is triggered by regexp matches on type names. An example for slices: -

- -
-(gdb) p utf
-$22 =  []uint8 = {0 '\000', 0 '\000', 0 '\000', 0 '\000'}
-
- -

-Since slices, arrays and strings are not C pointers, GDB can't interpret the subscripting operation for you, but -you can look inside the runtime representation to do that (tab completion helps here): -

-
-
-(gdb) p slc
-$11 =  []int = {0, 0}
-(gdb) p slc-><TAB>
-array  slc    len    
-(gdb) p slc->array
-$12 = (int *) 0xf84057af00
-(gdb) p slc->array[1]
-$13 = 0
- - - -

-The extension functions $len and $cap work on strings, arrays and slices: -

- -
-(gdb) p $len(utf)
-$23 = 4
-(gdb) p $cap(utf)
-$24 = 4
-
- -

-Channels and maps are 'reference' types, which gdb shows as pointers to C++-like types hash<int,string>*. Dereferencing will trigger prettyprinting -

- -

-Interfaces are represented in the runtime as a pointer to a type descriptor and a pointer to a value. The Go GDB runtime extension decodes this and automatically triggers pretty printing for the runtime type. The extension function $dtype decodes the dynamic type for you (examples are taken from a breakpoint at regexp.go line 293.) -

- -
-(gdb) p i
-$4 = {str = "cbb"}
-(gdb) whatis i
-type = regexp.input
-(gdb) p $dtype(i)
-$26 = (struct regexp.inputBytes *) 0xf8400b4930
-(gdb) iface i
-regexp.input: struct regexp.inputBytes *
-
diff --git a/doc/diagnostics.html b/doc/diagnostics.html deleted file mode 100644 index 438cdce45f..0000000000 --- a/doc/diagnostics.html +++ /dev/null @@ -1,472 +0,0 @@ - - - - -

Introduction

- -

-The Go ecosystem provides a large suite of APIs and tools to -diagnose logic and performance problems in Go programs. This page -summarizes the available tools and helps Go users pick the right one -for their specific problem. -

- -

-Diagnostics solutions can be categorized into the following groups: -

- -
    -
  • Profiling: Profiling tools analyze the complexity and costs of a -Go program such as its memory usage and frequently called -functions to identify the expensive sections of a Go program.
  • -
  • Tracing: Tracing is a way to instrument code to analyze latency -throughout the lifecycle of a call or user request. Traces provide an -overview of how much latency each component contributes to the overall -latency in a system. Traces can span multiple Go processes.
  • -
  • Debugging: Debugging allows us to pause a Go program and examine -its execution. Program state and flow can be verified with debugging.
  • -
  • Runtime statistics and events: Collection and analysis of runtime stats and events -provides a high-level overview of the health of Go programs. Spikes/dips of metrics -helps us to identify changes in throughput, utilization, and performance.
  • -
- -

-Note: Some diagnostics tools may interfere with each other. For example, precise -memory profiling skews CPU profiles and goroutine blocking profiling affects scheduler -trace. Use tools in isolation to get more precise info. -

- -

Profiling

- -

-Profiling is useful for identifying expensive or frequently called sections -of code. The Go runtime provides -profiling data in the format expected by the -pprof visualization tool. -The profiling data can be collected during testing -via go test or endpoints made available from the -net/http/pprof package. Users need to collect the profiling data and use pprof tools to filter -and visualize the top code paths. -

- -

Predefined profiles provided by the runtime/pprof package:

- -
    -
  • -cpu: CPU profile determines where a program spends -its time while actively consuming CPU cycles (as opposed to while sleeping or waiting for I/O). -
  • -
  • -heap: Heap profile reports memory allocation samples; -used to monitor current and historical memory usage, and to check for memory leaks. -
  • -
  • -threadcreate: Thread creation profile reports the sections -of the program that lead the creation of new OS threads. -
  • -
  • -goroutine: Goroutine profile reports the stack traces of all current goroutines. -
  • -
  • -block: Block profile shows where goroutines block waiting on synchronization -primitives (including timer channels). Block profile is not enabled by default; -use runtime.SetBlockProfileRate to enable it. -
  • -
  • -mutex: Mutex profile reports the lock contentions. When you think your -CPU is not fully utilized due to a mutex contention, use this profile. Mutex profile -is not enabled by default, see runtime.SetMutexProfileFraction to enable it. -
  • -
- - -

What other profilers can I use to profile Go programs?

- -

-On Linux, perf tools -can be used for profiling Go programs. Perf can profile -and unwind cgo/SWIG code and kernel, so it can be useful to get insights into -native/kernel performance bottlenecks. On macOS, -Instruments -suite can be used profile Go programs. -

- -

Can I profile my production services?

- -

Yes. It is safe to profile programs in production, but enabling -some profiles (e.g. the CPU profile) adds cost. You should expect to -see performance downgrade. The performance penalty can be estimated -by measuring the overhead of the profiler before turning it on in -production. -

- -

-You may want to periodically profile your production services. -Especially in a system with many replicas of a single process, selecting -a random replica periodically is a safe option. -Select a production process, profile it for -X seconds for every Y seconds and save the results for visualization and -analysis; then repeat periodically. Results may be manually and/or automatically -reviewed to find problems. -Collection of profiles can interfere with each other, -so it is recommended to collect only a single profile at a time. -

- -

-What are the best ways to visualize the profiling data? -

- -

-The Go tools provide text, graph, and callgrind -visualization of the profile data using -go tool pprof. -Read Profiling Go programs -to see them in action. -

- -

- -
-Listing of the most expensive calls as text. -

- -

- -
-Visualization of the most expensive calls as a graph. -

- -

Weblist view displays the expensive parts of the source line by line in -an HTML page. In the following example, 530ms is spent in the -runtime.concatstrings and cost of each line is presented -in the listing.

- -

- -
-Visualization of the most expensive calls as weblist. -

- -

-Another way to visualize profile data is a flame graph. -Flame graphs allow you to move in a specific ancestry path, so you can zoom -in/out of specific sections of code. -The upstream pprof -has support for flame graphs. -

- -

- -
-Flame graphs offers visualization to spot the most expensive code-paths. -

- -

Am I restricted to the built-in profiles?

- -

-Additionally to what is provided by the runtime, Go users can create -their custom profiles via pprof.Profile -and use the existing tools to examine them. -

- -

Can I serve the profiler handlers (/debug/pprof/...) on a different path and port?

- -

-Yes. The net/http/pprof package registers its handlers to the default -mux by default, but you can also register them yourself by using the handlers -exported from the package. -

- -

-For example, the following example will serve the pprof.Profile -handler on :7777 at /custom_debug_path/profile: -

- -

-

-package main
-
-import (
-	"log"
-	"net/http"
-	"net/http/pprof"
-)
-
-func main() {
-	mux := http.NewServeMux()
-	mux.HandleFunc("/custom_debug_path/profile", pprof.Profile)
-	log.Fatal(http.ListenAndServe(":7777", mux))
-}
-
-

- -

Tracing

- -

-Tracing is a way to instrument code to analyze latency throughout the -lifecycle of a chain of calls. Go provides -golang.org/x/net/trace -package as a minimal tracing backend per Go node and provides a minimal -instrumentation library with a simple dashboard. Go also provides -an execution tracer to trace the runtime events within an interval. -

- -

Tracing enables us to:

- -
    -
  • Instrument and analyze application latency in a Go process.
  • -
  • Measure the cost of specific calls in a long chain of calls.
  • -
  • Figure out the utilization and performance improvements. -Bottlenecks are not always obvious without tracing data.
  • -
- -

-In monolithic systems, it's relatively easy to collect diagnostic data -from the building blocks of a program. All modules live within one -process and share common resources to report logs, errors, and other -diagnostic information. Once your system grows beyond a single process and -starts to become distributed, it becomes harder to follow a call starting -from the front-end web server to all of its back-ends until a response is -returned back to the user. This is where distributed tracing plays a big -role to instrument and analyze your production systems. -

- -

-Distributed tracing is a way to instrument code to analyze latency throughout -the lifecycle of a user request. When a system is distributed and when -conventional profiling and debugging tools don’t scale, you might want -to use distributed tracing tools to analyze the performance of your user -requests and RPCs. -

- -

Distributed tracing enables us to:

- -
    -
  • Instrument and profile application latency in a large system.
  • -
  • Track all RPCs within the lifecycle of a user request and see integration issues -that are only visible in production.
  • -
  • Figure out performance improvements that can be applied to our systems. -Many bottlenecks are not obvious before the collection of tracing data.
  • -
- -

The Go ecosystem provides various distributed tracing libraries per tracing system -and backend-agnostic ones.

- - -

Is there a way to automatically intercept each function call and create traces?

- -

-Go doesn’t provide a way to automatically intercept every function call and create -trace spans. You need to manually instrument your code to create, end, and annotate spans. -

- -

How should I propagate trace headers in Go libraries?

- -

-You can propagate trace identifiers and tags in the -context.Context. -There is no canonical trace key or common representation of trace headers -in the industry yet. Each tracing provider is responsible for providing propagation -utilities in their Go libraries. -

- -

-What other low-level events from the standard library or -runtime can be included in a trace? -

- -

-The standard library and runtime are trying to expose several additional APIs -to notify on low level internal events. For example, -httptrace.ClientTrace -provides APIs to follow low-level events in the life cycle of an outgoing request. -There is an ongoing effort to retrieve low-level runtime events from -the runtime execution tracer and allow users to define and record their user events. -

- -

Debugging

- -

-Debugging is the process of identifying why a program misbehaves. -Debuggers allow us to understand a program’s execution flow and current state. -There are several styles of debugging; this section will only focus on attaching -a debugger to a program and core dump debugging. -

- -

Go users mostly use the following debuggers:

- -
    -
  • -Delve: -Delve is a debugger for the Go programming language. It has -support for Go’s runtime concepts and built-in types. Delve is -trying to be a fully featured reliable debugger for Go programs. -
  • -
  • -GDB: -Go provides GDB support via the standard Go compiler and Gccgo. -The stack management, threading, and runtime contain aspects that differ -enough from the execution model GDB expects that they can confuse the -debugger, even when the program is compiled with gccgo. Even though -GDB can be used to debug Go programs, it is not ideal and may -create confusion. -
  • -
- -

How well do debuggers work with Go programs?

- -

-The gc compiler performs optimizations such as -function inlining and variable registerization. These optimizations -sometimes make debugging with debuggers harder. There is an ongoing -effort to improve the quality of the DWARF information generated for -optimized binaries. Until those improvements are available, we recommend -disabling optimizations when building the code being debugged. The following -command builds a package with no compiler optimizations: - -

-

-$ go build -gcflags=all="-N -l"
-
-

- -As part of the improvement effort, Go 1.10 introduced a new compiler -flag -dwarflocationlists. The flag causes the compiler to -add location lists that helps debuggers work with optimized binaries. -The following command builds a package with optimizations but with -the DWARF location lists: - -

-

-$ go build -gcflags="-dwarflocationlists=true"
-
-

- -

What’s the recommended debugger user interface?

- -

-Even though both delve and gdb provides CLIs, most editor integrations -and IDEs provides debugging-specific user interfaces. -

- -

Is it possible to do postmortem debugging with Go programs?

- -

-A core dump file is a file that contains the memory dump of a running -process and its process status. It is primarily used for post-mortem -debugging of a program and to understand its state -while it is still running. These two cases make debugging of core -dumps a good diagnostic aid to postmortem and analyze production -services. It is possible to obtain core files from Go programs and -use delve or gdb to debug, see the -core dump debugging -page for a step-by-step guide. -

- -

Runtime statistics and events

- -

-The runtime provides stats and reporting of internal events for -users to diagnose performance and utilization problems at the -runtime level. -

- -

-Users can monitor these stats to better understand the overall -health and performance of Go programs. -Some frequently monitored stats and states: -

- -
    -
  • runtime.ReadMemStats -reports the metrics related to heap -allocation and garbage collection. Memory stats are useful for -monitoring how much memory resources a process is consuming, -whether the process can utilize memory well, and to catch -memory leaks.
  • -
  • debug.ReadGCStats -reads statistics about garbage collection. -It is useful to see how much of the resources are spent on GC pauses. -It also reports a timeline of garbage collector pauses and pause time percentiles.
  • -
  • debug.Stack -returns the current stack trace. Stack trace -is useful to see how many goroutines are currently running, -what they are doing, and whether they are blocked or not.
  • -
  • debug.WriteHeapDump -suspends the execution of all goroutines -and allows you to dump the heap to a file. A heap dump is a -snapshot of a Go process' memory at a given time. It contains all -allocated objects as well as goroutines, finalizers, and more.
  • -
  • runtime.NumGoroutine -returns the number of current goroutines. -The value can be monitored to see whether enough goroutines are -utilized, or to detect goroutine leaks.
  • -
- -

Execution tracer

- -

Go comes with a runtime execution tracer to capture a wide range -of runtime events. Scheduling, syscall, garbage collections, -heap size, and other events are collected by runtime and available -for visualization by the go tool trace. Execution tracer is a tool -to detect latency and utilization problems. You can examine how well -the CPU is utilized, and when networking or syscalls are a cause of -preemption for the goroutines.

- -

Tracer is useful to:

-
    -
  • Understand how your goroutines execute.
  • -
  • Understand some of the core runtime events such as GC runs.
  • -
  • Identify poorly parallelized execution.
  • -
- -

However, it is not great for identifying hot spots such as -analyzing the cause of excessive memory or CPU usage. -Use profiling tools instead first to address them.

- -

- -

- -

Above, the go tool trace visualization shows the execution started -fine, and then it became serialized. It suggests that there might -be lock contention for a shared resource that creates a bottleneck.

- -

See go tool trace -to collect and analyze runtime traces. -

- -

GODEBUG

- -

Runtime also emits events and information if -GODEBUG -environmental variable is set accordingly.

- -
    -
  • GODEBUG=gctrace=1 prints garbage collector events at -each collection, summarizing the amount of memory collected -and the length of the pause.
  • -
  • GODEBUG=inittrace=1 prints a summary of execution time and memory allocation -information for completed package initialization work.
  • -
  • GODEBUG=schedtrace=X prints scheduling events every X milliseconds.
  • -
- -

The GODEBUG environmental variable can be used to disable use of -instruction set extensions in the standard library and runtime.

- -
    -
  • GODEBUG=cpu.all=off disables the use of all optional -instruction set extensions.
  • -
  • GODEBUG=cpu.extension=off disables use of instructions from the -specified instruction set extension.
    -extension is the lower case name for the instruction set extension -such as sse41 or avx.
  • -
diff --git a/doc/editors.html b/doc/editors.html deleted file mode 100644 index e0d0c530e5..0000000000 --- a/doc/editors.html +++ /dev/null @@ -1,33 +0,0 @@ - - -

Introduction

- -

- This document lists commonly used editor plugins and IDEs from the Go ecosystem - that make Go development more productive and seamless. - A comprehensive list of editor support and IDEs for Go development is available at - the wiki. -

- -

Options

-

-The Go ecosystem provides a variety of editor plugins and IDEs to enhance your day-to-day -editing, navigation, testing, and debugging experience. -

- -