Skip to content

Commit

Permalink
feat(internal/godocfx): HTML-ify package summary (#2986)
Browse files Browse the repository at this point in the history
This makes GoDoc headers actual headers. The other changes _should_ be
minimal in appearance.

The golden diff is a bit difficult to read -- try searching for `<h3`.
  • Loading branch information
tbpg authored Oct 8, 2020
1 parent 251d525 commit 9e64b01
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 2 deletions.
8 changes: 7 additions & 1 deletion internal/godocfx/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func parse(glob string, optionalExtraFiles []string) (*result, error) {
UID: docPkg.ImportPath,
Name: docPkg.ImportPath,
ID: docPkg.Name,
Summary: docPkg.Doc,
Summary: toHTML(docPkg.Doc),
Langs: onlyGo,
Type: "package",
Examples: processExamples(docPkg.Examples, fset),
Expand Down Expand Up @@ -456,3 +456,9 @@ func buildTOC(mod string, pkgs []string, extraFiles []string) tableOfContents {

return toc
}

func toHTML(s string) string {
buf := &bytes.Buffer{}
doc.ToHTML(buf, s, nil)
return buf.String()
}
2 changes: 1 addition & 1 deletion internal/godocfx/testdata/golden/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ items:
- uid: cloud.google.com/go/storage
name: cloud.google.com/go/storage
id: storage
summary: "Package storage provides an easy way to work with Google Cloud Storage.\nGoogle Cloud Storage stores data in named objects, which are grouped into buckets.\n\nMore information about Google Cloud Storage is available at\nhttps://cloud.google.com/storage/docs.\n\nSee https://godoc.org/cloud.google.com/go for authentication, timeouts,\nconnection pooling and similar aspects of this package.\n\nAll of the methods of this package use exponential backoff to retry calls that fail\nwith certain errors, as described in\nhttps://cloud.google.com/storage/docs/exponential-backoff. Retrying continues\nindefinitely unless the controlling context is canceled or the client is closed. See\ncontext.WithTimeout and context.WithCancel.\n\nCreating a Client\n\nTo start working with this package, create a client:\n\n ctx := context.Background()\n client, err := storage.NewClient(ctx)\n if err != nil {\n // TODO: Handle error.\n }\n\nThe client will use your default application credentials. Clients should be\nreused instead of created as needed. The methods of Client are safe for\nconcurrent use by multiple goroutines.\n\nIf you only wish to access public data, you can create\nan unauthenticated client with\n\n client, err := storage.NewClient(ctx, option.WithoutAuthentication())\n\nBuckets\n\nA Google Cloud Storage bucket is a collection of objects. To work with a\nbucket, make a bucket handle:\n\n bkt := client.Bucket(bucketName)\n\nA handle is a reference to a bucket. You can have a handle even if the\nbucket doesn't exist yet. To create a bucket in Google Cloud Storage,\ncall Create on the handle:\n\n if err := bkt.Create(ctx, projectID, nil); err != nil {\n // TODO: Handle error.\n }\n\nNote that although buckets are associated with projects, bucket names are\nglobal across all projects.\n\nEach bucket has associated metadata, represented in this package by\nBucketAttrs. The third argument to BucketHandle.Create allows you to set\nthe initial BucketAttrs of a bucket. To retrieve a bucket's attributes, use\nAttrs:\n\n attrs, err := bkt.Attrs(ctx)\n if err != nil {\n // TODO: Handle error.\n }\n fmt.Printf(\"bucket %s, created at %s, is located in %s with storage class %s\\n\",\n attrs.Name, attrs.Created, attrs.Location, attrs.StorageClass)\n\nObjects\n\nAn object holds arbitrary data as a sequence of bytes, like a file. You\nrefer to objects using a handle, just as with buckets, but unlike buckets\nyou don't explicitly create an object. Instead, the first time you write\nto an object it will be created. You can use the standard Go io.Reader\nand io.Writer interfaces to read and write object data:\n\n obj := bkt.Object(\"data\")\n // Write something to obj.\n // w implements io.Writer.\n w := obj.NewWriter(ctx)\n // Write some text to obj. This will either create the object or overwrite whatever is there already.\n if _, err := fmt.Fprintf(w, \"This object contains text.\\n\"); err != nil {\n // TODO: Handle error.\n }\n // Close, just like writing a file.\n if err := w.Close(); err != nil {\n // TODO: Handle error.\n }\n\n // Read it back.\n r, err := obj.NewReader(ctx)\n if err != nil {\n // TODO: Handle error.\n }\n defer r.Close()\n if _, err := io.Copy(os.Stdout, r); err != nil {\n // TODO: Handle error.\n }\n // Prints \"This object contains text.\"\n\nObjects also have attributes, which you can fetch with Attrs:\n\n objAttrs, err := obj.Attrs(ctx)\n if err != nil {\n // TODO: Handle error.\n }\n fmt.Printf(\"object %s has size %d and can be read using %s\\n\",\n objAttrs.Name, objAttrs.Size, objAttrs.MediaLink)\n\nListing objects\n\nListing objects in a bucket is done with the Bucket.Objects method:\n\n query := &storage.Query{Prefix: \"\"}\n\n var names []string\n it := bkt.Objects(ctx, query)\n for {\n attrs, err := it.Next()\n if err == iterator.Done {\n break\n }\n if err != nil {\n log.Fatal(err)\n }\n names = append(names, attrs.Name)\n }\n\nIf only a subset of object attributes is needed when listing, specifying this\nsubset using Query.SetAttrSelection may speed up the listing process:\n\n query := &storage.Query{Prefix: \"\"}\n query.SetAttrSelection([]string{\"Name\"})\n\n // ... as before\n\nACLs\n\nBoth objects and buckets have ACLs (Access Control Lists). An ACL is a list of\nACLRules, each of which specifies the role of a user, group or project. ACLs\nare suitable for fine-grained control, but you may prefer using IAM to control\naccess at the project level (see\nhttps://cloud.google.com/storage/docs/access-control/iam).\n\nTo list the ACLs of a bucket or object, obtain an ACLHandle and call its List method:\n\n acls, err := obj.ACL().List(ctx)\n if err != nil {\n // TODO: Handle error.\n }\n for _, rule := range acls {\n fmt.Printf(\"%s has role %s\\n\", rule.Entity, rule.Role)\n }\n\nYou can also set and delete ACLs.\n\nConditions\n\nEvery object has a generation and a metageneration. The generation changes\nwhenever the content changes, and the metageneration changes whenever the\nmetadata changes. Conditions let you check these values before an operation;\nthe operation only executes if the conditions match. You can use conditions to\nprevent race conditions in read-modify-write operations.\n\nFor example, say you've read an object's metadata into objAttrs. Now\nyou want to write to that object, but only if its contents haven't changed\nsince you read it. Here is how to express that:\n\n w = obj.If(storage.Conditions{GenerationMatch: objAttrs.Generation}).NewWriter(ctx)\n // Proceed with writing as above.\n\nSigned URLs\n\nYou can obtain a URL that lets anyone read or write an object for a limited time.\nYou don't need to create a client to do this. See the documentation of\nSignedURL for details.\n\n url, err := storage.SignedURL(bucketName, \"shared-object\", opts)\n if err != nil {\n // TODO: Handle error.\n }\n fmt.Println(url)\n\nPost Policy V4 Signed Request\n\nA type of signed request that allows uploads through HTML forms directly to Cloud Storage with\ntemporary permission. Conditions can be applied to restrict how the HTML form is used and exercised\nby a user.\n\nFor more information, please see https://cloud.google.com/storage/docs/xml-api/post-object as well\nas the documentation of GenerateSignedPostPolicyV4.\n\n pv4, err := storage.GenerateSignedPostPolicyV4(bucketName, objectName, opts)\n if err != nil {\n // TODO: Handle error.\n }\n fmt.Printf(\"URL: %s\\nFields; %v\\n\", pv4.URL, pv4.Fields)\n\nErrors\n\nErrors returned by this client are often of the type [`googleapi.Error`](https://godoc.org/google.golang.org/api/googleapi#Error).\nThese errors can be introspected for more information by type asserting to the richer `googleapi.Error` type. For example:\n\n\tif e, ok := err.(*googleapi.Error); ok {\n\t\t if e.Code == 409 { ... }\n\t}\n"
summary: "<p>\nPackage storage provides an easy way to work with Google Cloud Storage.\nGoogle Cloud Storage stores data in named objects, which are grouped into buckets.\n</p>\n<p>\nMore information about Google Cloud Storage is available at\n<a href=\"https://cloud.google.com/storage/docs\">https://cloud.google.com/storage/docs</a>.\n</p>\n<p>\nSee <a href=\"https://godoc.org/cloud.google.com/go\">https://godoc.org/cloud.google.com/go</a> for authentication, timeouts,\nconnection pooling and similar aspects of this package.\n</p>\n<p>\nAll of the methods of this package use exponential backoff to retry calls that fail\nwith certain errors, as described in\n<a href=\"https://cloud.google.com/storage/docs/exponential-backoff\">https://cloud.google.com/storage/docs/exponential-backoff</a>. Retrying continues\nindefinitely unless the controlling context is canceled or the client is closed. See\ncontext.WithTimeout and context.WithCancel.\n</p>\n<h3 id=\"hdr-Creating_a_Client\">Creating a Client</h3>\n<p>\nTo start working with this package, create a client:\n</p>\n<pre>ctx := context.Background()\nclient, err := storage.NewClient(ctx)\nif err != nil {\n // TODO: Handle error.\n}\n</pre>\n<p>\nThe client will use your default application credentials. Clients should be\nreused instead of created as needed. The methods of Client are safe for\nconcurrent use by multiple goroutines.\n</p>\n<p>\nIf you only wish to access public data, you can create\nan unauthenticated client with\n</p>\n<pre>client, err := storage.NewClient(ctx, option.WithoutAuthentication())\n</pre>\n<h3 id=\"hdr-Buckets\">Buckets</h3>\n<p>\nA Google Cloud Storage bucket is a collection of objects. To work with a\nbucket, make a bucket handle:\n</p>\n<pre>bkt := client.Bucket(bucketName)\n</pre>\n<p>\nA handle is a reference to a bucket. You can have a handle even if the\nbucket doesn&#39;t exist yet. To create a bucket in Google Cloud Storage,\ncall Create on the handle:\n</p>\n<pre>if err := bkt.Create(ctx, projectID, nil); err != nil {\n // TODO: Handle error.\n}\n</pre>\n<p>\nNote that although buckets are associated with projects, bucket names are\nglobal across all projects.\n</p>\n<p>\nEach bucket has associated metadata, represented in this package by\nBucketAttrs. The third argument to BucketHandle.Create allows you to set\nthe initial BucketAttrs of a bucket. To retrieve a bucket&#39;s attributes, use\nAttrs:\n</p>\n<pre>attrs, err := bkt.Attrs(ctx)\nif err != nil {\n // TODO: Handle error.\n}\nfmt.Printf(&#34;bucket %s, created at %s, is located in %s with storage class %s\\n&#34;,\n attrs.Name, attrs.Created, attrs.Location, attrs.StorageClass)\n</pre>\n<h3 id=\"hdr-Objects\">Objects</h3>\n<p>\nAn object holds arbitrary data as a sequence of bytes, like a file. You\nrefer to objects using a handle, just as with buckets, but unlike buckets\nyou don&#39;t explicitly create an object. Instead, the first time you write\nto an object it will be created. You can use the standard Go io.Reader\nand io.Writer interfaces to read and write object data:\n</p>\n<pre>obj := bkt.Object(&#34;data&#34;)\n// Write something to obj.\n// w implements io.Writer.\nw := obj.NewWriter(ctx)\n// Write some text to obj. This will either create the object or overwrite whatever is there already.\nif _, err := fmt.Fprintf(w, &#34;This object contains text.\\n&#34;); err != nil {\n // TODO: Handle error.\n}\n// Close, just like writing a file.\nif err := w.Close(); err != nil {\n // TODO: Handle error.\n}\n\n// Read it back.\nr, err := obj.NewReader(ctx)\nif err != nil {\n // TODO: Handle error.\n}\ndefer r.Close()\nif _, err := io.Copy(os.Stdout, r); err != nil {\n // TODO: Handle error.\n}\n// Prints &#34;This object contains text.&#34;\n</pre>\n<p>\nObjects also have attributes, which you can fetch with Attrs:\n</p>\n<pre>objAttrs, err := obj.Attrs(ctx)\nif err != nil {\n // TODO: Handle error.\n}\nfmt.Printf(&#34;object %s has size %d and can be read using %s\\n&#34;,\n objAttrs.Name, objAttrs.Size, objAttrs.MediaLink)\n</pre>\n<h3 id=\"hdr-Listing_objects\">Listing objects</h3>\n<p>\nListing objects in a bucket is done with the Bucket.Objects method:\n</p>\n<pre>query := &amp;storage.Query{Prefix: &#34;&#34;}\n\nvar names []string\nit := bkt.Objects(ctx, query)\nfor {\n attrs, err := it.Next()\n if err == iterator.Done {\n break\n }\n if err != nil {\n log.Fatal(err)\n }\n names = append(names, attrs.Name)\n}\n</pre>\n<p>\nIf only a subset of object attributes is needed when listing, specifying this\nsubset using Query.SetAttrSelection may speed up the listing process:\n</p>\n<pre>query := &amp;storage.Query{Prefix: &#34;&#34;}\nquery.SetAttrSelection([]string{&#34;Name&#34;})\n\n// ... as before\n</pre>\n<h3 id=\"hdr-ACLs\">ACLs</h3>\n<p>\nBoth objects and buckets have ACLs (Access Control Lists). An ACL is a list of\nACLRules, each of which specifies the role of a user, group or project. ACLs\nare suitable for fine-grained control, but you may prefer using IAM to control\naccess at the project level (see\n<a href=\"https://cloud.google.com/storage/docs/access-control/iam\">https://cloud.google.com/storage/docs/access-control/iam</a>).\n</p>\n<p>\nTo list the ACLs of a bucket or object, obtain an ACLHandle and call its List method:\n</p>\n<pre>acls, err := obj.ACL().List(ctx)\nif err != nil {\n // TODO: Handle error.\n}\nfor _, rule := range acls {\n fmt.Printf(&#34;%s has role %s\\n&#34;, rule.Entity, rule.Role)\n}\n</pre>\n<p>\nYou can also set and delete ACLs.\n</p>\n<h3 id=\"hdr-Conditions\">Conditions</h3>\n<p>\nEvery object has a generation and a metageneration. The generation changes\nwhenever the content changes, and the metageneration changes whenever the\nmetadata changes. Conditions let you check these values before an operation;\nthe operation only executes if the conditions match. You can use conditions to\nprevent race conditions in read-modify-write operations.\n</p>\n<p>\nFor example, say you&#39;ve read an object&#39;s metadata into objAttrs. Now\nyou want to write to that object, but only if its contents haven&#39;t changed\nsince you read it. Here is how to express that:\n</p>\n<pre>w = obj.If(storage.Conditions{GenerationMatch: objAttrs.Generation}).NewWriter(ctx)\n// Proceed with writing as above.\n</pre>\n<h3 id=\"hdr-Signed_URLs\">Signed URLs</h3>\n<p>\nYou can obtain a URL that lets anyone read or write an object for a limited time.\nYou don&#39;t need to create a client to do this. See the documentation of\nSignedURL for details.\n</p>\n<pre>url, err := storage.SignedURL(bucketName, &#34;shared-object&#34;, opts)\nif err != nil {\n // TODO: Handle error.\n}\nfmt.Println(url)\n</pre>\n<h3 id=\"hdr-Post_Policy_V4_Signed_Request\">Post Policy V4 Signed Request</h3>\n<p>\nA type of signed request that allows uploads through HTML forms directly to Cloud Storage with\ntemporary permission. Conditions can be applied to restrict how the HTML form is used and exercised\nby a user.\n</p>\n<p>\nFor more information, please see <a href=\"https://cloud.google.com/storage/docs/xml-api/post-object\">https://cloud.google.com/storage/docs/xml-api/post-object</a> as well\nas the documentation of GenerateSignedPostPolicyV4.\n</p>\n<pre>pv4, err := storage.GenerateSignedPostPolicyV4(bucketName, objectName, opts)\nif err != nil {\n // TODO: Handle error.\n}\nfmt.Printf(&#34;URL: %s\\nFields; %v\\n&#34;, pv4.URL, pv4.Fields)\n</pre>\n<h3 id=\"hdr-Errors\">Errors</h3>\n<p>\nErrors returned by this client are often of the type [`googleapi.Error`](<a href=\"https://godoc.org/google.golang.org/api/googleapi#Error\">https://godoc.org/google.golang.org/api/googleapi#Error</a>).\nThese errors can be introspected for more information by type asserting to the richer `googleapi.Error` type. For example:\n</p>\n<pre>if e, ok := err.(*googleapi.Error); ok {\n\t if e.Code == 409 { ... }\n}\n</pre>\n"
type: package
langs:
- go
Expand Down

0 comments on commit 9e64b01

Please sign in to comment.