1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-19 13:19:43 +02:00

Moved from Dep to Go Modules

We have finally dropped go dep and moved over to go mod !

During the move, some dependencies have been bumped.
This commit is contained in:
HarveyKandola 2019-09-06 11:06:28 +01:00
parent 2c164a135a
commit b826852137
164 changed files with 18268 additions and 10658 deletions

367
Gopkg.lock generated
View file

@ -1,367 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:b62a3c5b37db602bf1158e921da1a762315a4c37855fd418a14498aa87a342d5"
name = "cloud.google.com/go"
packages = ["civil"]
pruneopts = "UT"
revision = "2fa99f4c25c422525316dcb1fd3d5b94e1944cfd"
version = "v0.37.1"
[[projects]]
digest = "1:9f3b30d9f8e0d7040f729b82dcbc8f0dead820a133b3147ce355fc451f32d761"
name = "github.com/BurntSushi/toml"
packages = ["."]
pruneopts = "UT"
revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005"
version = "v0.3.1"
[[projects]]
digest = "1:606d068450c82b9ddaa21de992f73563754077f0f411235cdfe71d0903a268c3"
name = "github.com/codegangsta/negroni"
packages = ["."]
pruneopts = "UT"
revision = "5dbbc83f748fc3ad38585842b0aedab546d0ea1e"
version = "v0.3.0"
[[projects]]
branch = "master"
digest = "1:159f2147aa2b2e5fa020480ab46ab26f3e6c3ebe5d0191632622cc9aa81bcffe"
name = "github.com/denisenkom/go-mssqldb"
packages = [
".",
"internal/cp",
"internal/querytext",
]
pruneopts = "UT"
revision = "db2462fef53bd29c619fe40f73cbfcc12be79d9f"
[[projects]]
digest = "1:217f778e19b8d206112c21d21a7cc72ca3cb493b67631680a2324bc50335d432"
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
pruneopts = "UT"
revision = "dbeaa9332f19a944acb5736b4456cfcc02140e29"
version = "v3.1.0"
[[projects]]
digest = "1:39c2113f3a89585666e6f973650cff186b2d06deb4aa202c88addb87b0a201db"
name = "github.com/documize/blackfriday"
packages = ["."]
pruneopts = "UT"
revision = "cadec560ec52d93835bf2f15bd794700d3a2473b"
version = "v2.0.0"
[[projects]]
branch = "master"
digest = "1:04bfeb11ea882e0a0867828e54374c066a1368f8da53bb1bbc16a9886967303a"
name = "github.com/documize/glick"
packages = ["."]
pruneopts = "UT"
revision = "a8ccbef88237fcafe9cef3c9aee7ad83d0e132f9"
[[projects]]
branch = "master"
digest = "1:2405d7a1e936e015b07c1c88acccc30d7f2e917b1b5acea08d06d116b8657a5c"
name = "github.com/documize/html-diff"
packages = ["."]
pruneopts = "UT"
revision = "f61c192c7796644259832ef705c49259797e7fff"
[[projects]]
digest = "1:0ae2e1b2d4cdff4834aa28ce2e33a7b6de91e10150e3647fe1b9fd63a51b39ce"
name = "github.com/documize/slug"
packages = ["."]
pruneopts = "UT"
revision = "e9f42fa127660e552d0ad2b589868d403a9be7c6"
version = "v1.1.1"
[[projects]]
digest = "1:f4f6279cb37479954644babd8f8ef00584ff9fa63555d2c6718c1c3517170202"
name = "github.com/elazarl/go-bindata-assetfs"
packages = ["."]
pruneopts = "UT"
revision = "30f82fa23fd844bd5bb1e5f216db87fd77b5eb43"
version = "v1.0.0"
[[projects]]
digest = "1:ca82a3b99694824c627573c2a76d0e49719b4a9c02d1d85a2ac91f1c1f52ab9b"
name = "github.com/fatih/structs"
packages = ["."]
pruneopts = "UT"
revision = "a720dfa8df582c51dee1b36feabb906bde1588bd"
version = "v1.0"
[[projects]]
digest = "1:ec6f9bf5e274c833c911923c9193867f3f18788c461f76f05f62bb1510e0ae65"
name = "github.com/go-sql-driver/mysql"
packages = ["."]
pruneopts = "UT"
revision = "72cd26f257d44c1114970e19afddcd812016007e"
version = "v1.4.1"
[[projects]]
branch = "master"
digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467"
name = "github.com/golang/glog"
packages = ["."]
pruneopts = "UT"
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
[[projects]]
digest = "1:ffc060c551980d37ee9e428ef528ee2813137249ccebb0bfc412ef83071cac91"
name = "github.com/golang/protobuf"
packages = ["proto"]
pruneopts = "UT"
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
version = "v1.0.0"
[[projects]]
digest = "1:51bee9f1987dcdb9f9a1b4c20745d78f6bf6f5f14ad4e64ca883eb64df4c0045"
name = "github.com/google/go-github"
packages = ["github"]
pruneopts = "UT"
revision = "e48060a28fac52d0f1cb758bc8b87c07bac4a87d"
version = "v15.0.0"
[[projects]]
branch = "master"
digest = "1:a63cff6b5d8b95638bfe300385d93b2a6d9d687734b863da8e09dc834510a690"
name = "github.com/google/go-querystring"
packages = ["query"]
pruneopts = "UT"
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
[[projects]]
digest = "1:160eabf7a69910fd74f29c692718bc2437c1c1c7d4c9dea9712357752a70e5df"
name = "github.com/gorilla/context"
packages = ["."]
pruneopts = "UT"
revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
version = "v1.1"
[[projects]]
digest = "1:664d37ea261f0fc73dd17f4a1f5f46d01fbb0b0d75f6375af064824424109b7d"
name = "github.com/gorilla/handlers"
packages = ["."]
pruneopts = "UT"
revision = "7e0847f9db758cdebd26c149d0ae9d5d0b9c98ce"
version = "v1.4.0"
[[projects]]
digest = "1:88aa9e326e2bd6045a46e00a922954b3e1a9ac5787109f49ac85366df370e1e5"
name = "github.com/gorilla/mux"
packages = ["."]
pruneopts = "UT"
revision = "53c1911da2b537f792e7cafcb446b05ffe33b996"
version = "v1.6.1"
[[projects]]
branch = "master"
digest = "1:6c41d4f998a03b6604227ccad36edaed6126c397e5d78709ef4814a1145a6757"
name = "github.com/jmoiron/sqlx"
packages = [
".",
"reflectx",
]
pruneopts = "UT"
revision = "d161d7a76b5661016ad0b085869f77fd410f3e6a"
[[projects]]
digest = "1:12cb143f2148bf54bcd9fe622abac17325e85eeb1d84b8ec6caf1c80232108fd"
name = "github.com/lib/pq"
packages = [
".",
"oid",
"scram",
]
pruneopts = "UT"
revision = "3427c32cb71afc948325f299f040e53c1dd78979"
version = "v1.2.0"
[[projects]]
branch = "master"
digest = "1:8213aea9ec57afac7c765f9127bb3a5677866e03c0d3815f236045f16d5bc468"
name = "github.com/mb0/diff"
packages = ["."]
pruneopts = "UT"
revision = "d8d9a906c24d7b0ee77287e0463e5ca7f026032e"
[[projects]]
branch = "master"
digest = "1:0e1e5f960c58fdc677212fcc70e55042a0084d367623e51afbdb568963832f5d"
name = "github.com/nu7hatch/gouuid"
packages = ["."]
pruneopts = "UT"
revision = "179d4d0c4d8d407a32af483c2354df1d2c91e6c3"
[[projects]]
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
name = "github.com/pkg/errors"
packages = ["."]
pruneopts = "UT"
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
branch = "master"
digest = "1:e6a29574542c00bb18adb1bfbe629ff88c468c2af2e2e953d3e58eda07165086"
name = "github.com/rainycape/unidecode"
packages = ["."]
pruneopts = "UT"
revision = "cb7f23ec59bec0d61b19c56cd88cee3d0cc1870c"
[[projects]]
branch = "master"
digest = "1:def689e73e9252f6f7fe66834a76751a41b767e03daab299e607e7226c58a855"
name = "github.com/shurcooL/sanitized_anchor_name"
packages = ["."]
pruneopts = "UT"
revision = "86672fcb3f950f35f2e675df2240550f2a50762f"
[[projects]]
digest = "1:821c90494c34add2aa5f7c3b894f55dd08741acbb390901663050449b777c39a"
name = "github.com/trivago/tgo"
packages = [
"tcontainer",
"treflect",
]
pruneopts = "UT"
revision = "e4d1ddd28c17dd89ed26327cf69fded22060671b"
version = "v1.0.1"
[[projects]]
branch = "master"
digest = "1:68344dbfaa4179bb50a583eb8172ace3f1edaf3aebc24e68c03f549f6e6b60dc"
name = "golang.org/x/crypto"
packages = [
"bcrypt",
"blowfish",
"md4",
]
pruneopts = "UT"
revision = "650f4a345ab4e5b245a3034b110ebc7299e68186"
[[projects]]
branch = "master"
digest = "1:ac7eaa5f1179480f517d32831225215cc20940152d66be29f3d5204ea15d425f"
name = "golang.org/x/net"
packages = [
"context",
"context/ctxhttp",
"html",
"html/atom",
]
pruneopts = "UT"
revision = "f5dfe339be1d06f81b22525fe34671ee7d2c8904"
[[projects]]
branch = "master"
digest = "1:fe84cb4abe7f53047ac44cf10d917d707a718711e146c9239700e4c8cc94a891"
name = "golang.org/x/oauth2"
packages = [
".",
"internal",
]
pruneopts = "UT"
revision = "543e37812f10c46c622c9575afd7ad22f22a12ba"
[[projects]]
digest = "1:f40806967647e80fc51b941a586afefea6058592692c0bbfb3be7ea6b2b2a82d"
name = "google.golang.org/appengine"
packages = [
"cloudsql",
"internal",
"internal/base",
"internal/datastore",
"internal/log",
"internal/remote_api",
"internal/urlfetch",
"urlfetch",
]
pruneopts = "UT"
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
version = "v1.0.0"
[[projects]]
branch = "v3"
digest = "1:7388652e2215a3f45d341d58766ed58317971030eb1cbd75f005f96ace8e9196"
name = "gopkg.in/alexcesaro/quotedprintable.v3"
packages = ["."]
pruneopts = "UT"
revision = "2caba252f4dc53eaf6b553000885530023f54623"
[[projects]]
digest = "1:78e84cebc662378af09d7ebaee20b1b813b4b2afcfb91be41d519ce6454eab1d"
name = "gopkg.in/andygrunwald/go-jira.v1"
packages = ["."]
pruneopts = "UT"
revision = "7966e7f5ed3e453362a4deac213c0e6cf7563f4c"
version = "v1.10.0"
[[projects]]
digest = "1:81e1c5cee195fca5de06e2540cb63eea727a850b7e5c213548e7f81521c97a57"
name = "gopkg.in/asn1-ber.v1"
packages = ["."]
pruneopts = "UT"
revision = "379148ca0225df7a432012b8df0355c2a2063ac0"
version = "v1.2"
[[projects]]
digest = "1:d095b21d330637ad0e1025231ef91023f64c65dda093a437001fe8becfb77099"
name = "gopkg.in/cas.v2"
packages = ["."]
pruneopts = "UT"
revision = "1b87d011d1fc0430cdbdfe3115c9843ec33d9da6"
version = "v2.1.0"
[[projects]]
digest = "1:e9a0fa7c2dfc90e0fae16be5825ad98074d8704f5fcebfdc289a8e8fb0f8e4b5"
name = "gopkg.in/ldap.v3"
packages = ["."]
pruneopts = "UT"
revision = "9f0d712775a0973b7824a1585a86a4ea1d5263d9"
version = "v3.0.3"
[[projects]]
digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = "UT"
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
version = "v2.2.2"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/BurntSushi/toml",
"github.com/codegangsta/negroni",
"github.com/denisenkom/go-mssqldb",
"github.com/dgrijalva/jwt-go",
"github.com/documize/blackfriday",
"github.com/documize/glick",
"github.com/documize/html-diff",
"github.com/documize/slug",
"github.com/elazarl/go-bindata-assetfs",
"github.com/go-sql-driver/mysql",
"github.com/google/go-github/github",
"github.com/gorilla/handlers",
"github.com/gorilla/mux",
"github.com/jmoiron/sqlx",
"github.com/lib/pq",
"github.com/nu7hatch/gouuid",
"github.com/pkg/errors",
"golang.org/x/crypto/bcrypt",
"golang.org/x/net/context",
"golang.org/x/net/html",
"golang.org/x/net/html/atom",
"golang.org/x/oauth2",
"gopkg.in/alexcesaro/quotedprintable.v3",
"gopkg.in/andygrunwald/go-jira.v1",
"gopkg.in/cas.v2",
"gopkg.in/ldap.v3",
]
solver-name = "gps-cdcl"
solver-version = 1

View file

@ -1,102 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
name = "github.com/codegangsta/negroni"
version = "0.3.0"
[[constraint]]
name = "github.com/dgrijalva/jwt-go"
version = "3.1.0"
[[constraint]]
name = "github.com/documize/blackfriday"
version = "2.0.0"
[[constraint]]
branch = "master"
name = "github.com/documize/glick"
[[constraint]]
branch = "master"
name = "github.com/documize/html-diff"
[[constraint]]
name = "github.com/elazarl/go-bindata-assetfs"
version = "1.0.0"
[[constraint]]
name = "github.com/go-sql-driver/mysql"
version = "1.3.0"
[[constraint]]
name = "github.com/google/go-github"
version = "15.0.0"
[[constraint]]
name = "github.com/gorilla/mux"
version = "1.6.1"
[[constraint]]
branch = "master"
name = "github.com/jmoiron/sqlx"
[[constraint]]
branch = "master"
name = "github.com/nu7hatch/gouuid"
[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"
[[constraint]]
branch = "master"
name = "golang.org/x/crypto"
[[constraint]]
branch = "master"
name = "golang.org/x/net"
[[constraint]]
branch = "master"
name = "golang.org/x/oauth2"
[prune]
go-tests = true
unused-packages = true
[[constraint]]
name = "github.com/documize/slug"
version = "1.1.1"
[[constraint]]
name = "gopkg.in/andygrunwald/go-jira.v1"
version = "1.5.0"
[[constraint]]
branch = "master"
name = "github.com/denisenkom/go-mssqldb"

View file

@ -50,15 +50,15 @@ go generate
cd .. cd ..
echo "Compiling for Linux..." echo "Compiling for Linux..."
env GOOS=linux GOARCH=amd64 go build -gcflags="all=-trimpath=$GOPATH" -o bin/documize-community-linux-amd64 ./edition/community.go env GOOS=linux GOARCH=amd64 go build -trimpath -o bin/documize-community-linux-amd64 ./edition/community.go
echo "Compiling for macOS..." echo "Compiling for macOS..."
env GOOS=darwin GOARCH=amd64 go build -gcflags="all=-trimpath=$GOPATH" -o bin/documize-community-darwin-amd64 ./edition/community.go env GOOS=darwin GOARCH=amd64 go build -trimpath -o bin/documize-community-darwin-amd64 ./edition/community.go
echo "Compiling for Windows..." echo "Compiling for Windows..."
env GOOS=windows GOARCH=amd64 go build -gcflags="all=-trimpath=$GOPATH" -o bin/documize-community-windows-amd64.exe ./edition/community.go env GOOS=windows GOARCH=amd64 go build -trimpath -o bin/documize-community-windows-amd64.exe ./edition/community.go
echo "Compiling for ARM..." echo "Compiling for ARM..."
env GOOS=linux GOARCH=arm go build -gcflags="all=-trimpath=$GOPATH" -o bin/documize-community-linux-arm ./edition/community.go env GOOS=linux GOARCH=arm go build -trimpath -o bin/documize-community-linux-arm ./edition/community.go
echo "Compiling for ARM64..." echo "Compiling for ARM64..."
env GOOS=linux GOARCH=arm64 go build -gcflags="all=-trimpath=$GOPATH" -o bin/documize-community-linux-arm64 ./edition/community.go env GOOS=linux GOARCH=arm64 go build -trimpath -o bin/documize-community-linux-arm64 ./edition/community.go
echo "Finished." echo "Finished."

View file

@ -1,155 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
package convert_test
import (
"strings"
"testing"
"github.com/documize/community/core/api/convert"
"github.com/documize/community/core/api/plugins"
api "github.com/documize/community/core/convapi"
"github.com/documize/community/core/log"
"golang.org/x/net/context"
)
func TestConvert(t *testing.T) {
plugins.PluginFile = "" // no file as html is built-in
if lerr := plugins.LibSetup(); lerr == nil {
//t.Error("did not error on plugin.Libsetup() with no plugin.json file")
//return
}
defer log.IfErr(plugins.Lib.KillSubProcs())
ctx := context.Background()
xtn := "html"
fileRequest := new(api.DocumentConversionRequest)
fileRequest.Filedata = []byte(yorkweb)
resp, err := convert.Convert(ctx, xtn, fileRequest)
if err != nil {
t.Error(err)
return
}
if len(resp.Pages) != 3 ||
!strings.HasPrefix(resp.Pages[1].Title, "STARTING") ||
!strings.HasPrefix(resp.Pages[2].Title, "EXERCISE") {
for p, pg := range resp.Pages {
t.Error(p, pg.Level, len(pg.Body), pg.Title)
}
}
exp := "There are lots of ways to create web pages using already coded programmes. … HTML isn' t computer code, but is a language that uses US English to enable texts( words, images, sounds) to be inserted and formatting such as colo( u) r and centre/ erin…"
if resp.Excerpt != exp {
t.Errorf("unexpected excerpt wanted: `%s` got: `%s`", exp, resp.Excerpt)
}
// check errors are caught
resp, err = convert.Convert(ctx, "unknown", fileRequest)
if err == nil {
t.Error("does not error on unknown extension")
}
}
// www.york.ac.uk/teaching/cws/wws/webpage1.html
const yorkweb = `
<HMTL>
<HEAD>
<TITLE>webpage1</TITLE>
</HEAD>
<BODY BGCOLOR="FFFFFf" LINK="006666" ALINK="8B4513" VLINK="006666">
<TABLE WIDTH="75%" ALIGN="center">
<TR>
<TD>
<DIV ALIGN="center"><H1>STARTING . . . </H1></DIV>
<DIV ALIGN="justify"><P>There are lots of ways to create web pages using already coded programmes. These lessons will teach you how to use the underlying HyperText Markup Language - HTML.
<BR>
<P>HTML isn't computer code, but is a language that uses US English to enable texts (words, images, sounds) to be inserted and formatting such as colo(u)r and centre/ering to be written in. The process is fairly simple; the main difficulties often lie in small mistakes - if you slip up while word processing your reader may pick up your typos, but the page will still be legible. However, if your HTML is inaccurate the page may not appear - writing web pages is, at the least, very good practice for proof reading!</P>
<P>Learning HTML will enable you to:
<UL>
<LI>create your own simple pages
<LI>read and appreciate pages created by others
<LI>develop an understanding of the creative and literary implications of web-texts
<LI>have the confidence to branch out into more complex web design
</UL></P>
<P>A HTML web page is made up of tags. Tags are placed in brackets like this <B>< tag > </B>. A tag tells the browser how to display information. Most tags need to be opened < tag > and closed < /tag >.
<P> To make a simple web page you need to know only four tags:
<UL>
<LI>< HTML > tells the browser your page is written in HTML format
<LI>< HEAD > this is a kind of preface of vital information that doesn't appear on the screen.
<LI>< TITLE >Write the title of the web page here - this is the information that viewers see on the upper bar of their screen. (I've given this page the title 'webpage1').
<LI>< BODY >This is where you put the content of your page, the words and pictures that people read on the screen.
</UL>
<P>All these tags need to be closed.
<H4>EXERCISE</H4>
<P>Write a simple web page.</P>
<P> Copy out exactly the HTML below, using a WP program such as Notepad.<BR>
Information in <I>italics</I> indicates where you can insert your own text, other information is HTML and needs to be exact. However, make sure there are no spaces between the tag brackets and the text inside.<BR>
(Find Notepad by going to the START menu\ PROGRAMS\ ACCESSORIES\ NOTEPAD).
<P>
< HTML ><BR>
< HEAD ><BR>
< TITLE ><I> title of page</I>< /TITLE ><BR>
< /HEAD ><BR>
< BODY><BR>
<I> write what you like here: 'my first web page', or a piece about what you are reading, or a few thoughts on the course, or copy out a few words from a book or cornflake packet. Just type in your words using no extras such as bold, or italics, as these have special HTML tags, although you may use upper and lower case letters and single spaces. </I><BR>
< /BODY ><BR>
< /HTML ><BR>
<P>Save the file as 'first.html' (ie. call the file anything at all) It's useful if you start a folder - just as you would for word-processing - and call it something like WEBPAGES, and put your first.html file in the folder.
<P>NOW - open your browser.<BR>
On Netscape the process is: <BR>
Top menu; FILE\ OPEN PAGE\ CHOOSE FILE<BR>
Click on your WEBPAGES folder\ FIRST file<BR>
Click 'open' and your page should appear.
<P>On Internet Explorer: <BR>
Top menu; FILE\ OPEN\ BROWSE <BR>
Click on your WEBPAGES folder\ FIRST file<BR>
Click 'open' and your page should appear.<BR>
<P>If the page doesn't open, go back over your notepad typing and make sure that all the HTML tags are correct. Check there are no spaces between tags and internal text; check that all tags are closed; check that you haven't written < HTLM > or < BDDY >. Your page will work eventually.
<P>
Make another page. Call it somethingdifferent.html and place it in the same WEBPAGES folder as detailed above.
<P>start formatting in <A HREF="webpage2.html">lesson two</A>
<BR><A HREF="col3.html">back to wws index</A> </P>
</P>
</DIV>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>
`

View file

@ -20,10 +20,10 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
jira "github.com/andygrunwald/go-jira"
"github.com/documize/community/core/env" "github.com/documize/community/core/env"
"github.com/documize/community/domain/section/provider" "github.com/documize/community/domain/section/provider"
"github.com/documize/community/domain/store" "github.com/documize/community/domain/store"
jira "gopkg.in/andygrunwald/go-jira.v1"
) )
// //

File diff suppressed because one or more lines are too long

36
go.mod Normal file
View file

@ -0,0 +1,36 @@
module github.com/documize/community
go 1.13
require (
github.com/BurntSushi/toml v0.3.1
github.com/andygrunwald/go-jira v1.10.0
github.com/codegangsta/negroni v0.3.0
github.com/denisenkom/go-mssqldb v0.0.0-20190806190131-db2462fef53b
github.com/dgrijalva/jwt-go v3.1.0+incompatible
github.com/documize/blackfriday v2.0.0+incompatible
github.com/documize/glick v0.0.0-20160503134043-a8ccbef88237
github.com/documize/html-diff v0.0.0-20160503140253-f61c192c7796
github.com/documize/slug v1.1.1
github.com/elazarl/go-bindata-assetfs v1.0.0
github.com/go-sql-driver/mysql v1.4.1
github.com/google/go-github v17.0.0+incompatible
github.com/google/go-querystring v1.0.0 // indirect
github.com/gorilla/handlers v1.4.0
github.com/gorilla/mux v1.6.2
github.com/jmoiron/sqlx v1.2.0
github.com/kr/pretty v0.1.0 // indirect
github.com/lib/pq v1.2.0
github.com/mb0/diff v0.0.0-20131118162322-d8d9a906c24d // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d
github.com/pkg/errors v0.8.0
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be // indirect
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95 // indirect
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc
gopkg.in/asn1-ber.v1 v1.0.0-20170511165959-379148ca0225 // indirect
gopkg.in/cas.v2 v2.1.0
gopkg.in/ldap.v3 v3.0.3
)

195
go.sum Normal file
View file

@ -0,0 +1,195 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andygrunwald/go-jira v1.10.0 h1:+HPPK7++6/hW8ygtr2Yc0wd+Qu139NrWiTD/r1cYxO0=
github.com/andygrunwald/go-jira v1.10.0/go.mod h1:KEsrADP1cEXRxVWTaDtpLyyZN1LM9p6Jn8W5+sDzxhc=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/codegangsta/negroni v0.3.0 h1:ByBtJaE0u71x6Ebli7lm95c8oCkrmF88+s5qB2o6j8I=
github.com/codegangsta/negroni v0.3.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20190806190131-db2462fef53b h1:C8eKel5CV265bq4KKOvyMKyNK4NPPr1mImhqm8xcK7k=
github.com/denisenkom/go-mssqldb v0.0.0-20190806190131-db2462fef53b/go.mod h1:uU0N10vx1abI4qeVe79CxepBP6PPREVTgMS5Gx6/mOk=
github.com/dgrijalva/jwt-go v3.1.0+incompatible h1:FFziAwDQQ2dz1XClWMkwvukur3evtZx7x/wMHKM1i20=
github.com/dgrijalva/jwt-go v3.1.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/documize/blackfriday v2.0.0+incompatible h1:qjRGAIVwZlHBtA/b9u0LtseYM3v3WpIXofPCwNjcUsE=
github.com/documize/blackfriday v2.0.0+incompatible/go.mod h1:89vHw0Rs0jcipRrgirvJJn6hvRgbk4KX6rask9ZQ84Y=
github.com/documize/glick v0.0.0-20160503134043-a8ccbef88237 h1:i9vV99+Zl6G82LGwwk7TBf5WwbniTNZZfYCIrEvqRpY=
github.com/documize/glick v0.0.0-20160503134043-a8ccbef88237/go.mod h1:j8TNQVPnf+2MRQnQdLaQbQXVUEHccrCUCTHElbNWs5g=
github.com/documize/html-diff v0.0.0-20160503140253-f61c192c7796 h1:CuipXymSP8DiNHYVGWak4cF2IbYFQeL5CZ37Y6aDVq4=
github.com/documize/html-diff v0.0.0-20160503140253-f61c192c7796/go.mod h1:GTEVMy1JkyV+k/j8hLGRGHVs/IHJS4s7AtJJ9LSYjRQ=
github.com/documize/slug v1.1.1 h1:OCJRbWxbOgrgiBYSbVzuFwxb9wVu4oy1LxvLJOC2s8Y=
github.com/documize/slug v1.1.1/go.mod h1:Vi7fQ5PzeOpXAiIrk1WCEDRihjTfU/bf4eWUPSD7tkU=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/fatih/structs v1.0.0 h1:BrX964Rv5uQ3wwS+KRUAJCBBw5PQmgJfJ6v4yly5QwU=
github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA=
github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mb0/diff v0.0.0-20131118162322-d8d9a906c24d h1:eAS2t2Vy+6psf9LZ4T5WXWsbkBt3Tu5PWekJy5AGyEU=
github.com/mb0/diff v0.0.0-20131118162322-d8d9a906c24d/go.mod h1:3YMHqrw2Qu3Liy82v4QdAG17e9k91HZ7w3hqlpWqhDo=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95 h1:/vdW8Cb7EXrkqWGufVMES1OH2sU9gKVb2n9/1y5NMBY=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/trivago/tgo v1.0.1 h1:bxatjJIXNIpV18bucU4Uk/LaoxvxuOlp/oowRHyncLQ=
github.com/trivago/tgo v1.0.1/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/asn1-ber.v1 v1.0.0-20170511165959-379148ca0225 h1:JBwmEvLfCqgPcIq8MjVMQxsF3LVL4XG/HH0qiG0+IFY=
gopkg.in/asn1-ber.v1 v1.0.0-20170511165959-379148ca0225/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/cas.v2 v2.1.0 h1:sbYBMWtpanwLH75GAWjIp5JnON9wa3NodLZhouu0G9I=
gopkg.in/cas.v2 v2.1.0/go.mod h1:M291I/o/u3eeMl9SkXMPYpWasHp7weFY9G/pM5DbB+g=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ldap.v3 v3.0.3 h1:YKRHW/2sIl05JsCtx/5ZuUueFuJyoj/6+DGXe3wp6ro=
gopkg.in/ldap.v3 v3.0.3/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View file

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 TOML authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 TOML authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 TOML authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

0
vendor/github.com/documize/glick/gocheck.sh generated vendored Executable file → Normal file
View file

View file

@ -1,7 +1,4 @@
Go support for Protocol Buffers - Google's data interchange format
Copyright 2010 The Go Authors. All rights reserved. Copyright 2010 The Go Authors. All rights reserved.
https://github.com/golang/protobuf
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are

View file

@ -1,43 +0,0 @@
# Go support for Protocol Buffers - Google's data interchange format
#
# Copyright 2010 The Go Authors. All rights reserved.
# https://github.com/golang/protobuf
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
install:
go install
test: install generate-test-pbs
go test
generate-test-pbs:
make install
make -C testdata
protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto
make

View file

@ -35,22 +35,39 @@
package proto package proto
import ( import (
"fmt"
"log" "log"
"reflect" "reflect"
"strings" "strings"
) )
// Clone returns a deep copy of a protocol buffer. // Clone returns a deep copy of a protocol buffer.
func Clone(pb Message) Message { func Clone(src Message) Message {
in := reflect.ValueOf(pb) in := reflect.ValueOf(src)
if in.IsNil() { if in.IsNil() {
return pb return src
} }
out := reflect.New(in.Type().Elem()) out := reflect.New(in.Type().Elem())
// out is empty so a merge is a deep copy. dst := out.Interface().(Message)
mergeStruct(out.Elem(), in.Elem()) Merge(dst, src)
return out.Interface().(Message) return dst
}
// Merger is the interface representing objects that can merge messages of the same type.
type Merger interface {
// Merge merges src into this message.
// Required and optional fields that are set in src will be set to that value in dst.
// Elements of repeated fields will be appended.
//
// Merge may panic if called with a different argument type than the receiver.
Merge(src Message)
}
// generatedMerger is the custom merge method that generated protos will have.
// We must add this method since a generate Merge method will conflict with
// many existing protos that have a Merge data field already defined.
type generatedMerger interface {
XXX_Merge(src Message)
} }
// Merge merges src into dst. // Merge merges src into dst.
@ -58,17 +75,24 @@ func Clone(pb Message) Message {
// Elements of repeated fields will be appended. // Elements of repeated fields will be appended.
// Merge panics if src and dst are not the same type, or if dst is nil. // Merge panics if src and dst are not the same type, or if dst is nil.
func Merge(dst, src Message) { func Merge(dst, src Message) {
if m, ok := dst.(Merger); ok {
m.Merge(src)
return
}
in := reflect.ValueOf(src) in := reflect.ValueOf(src)
out := reflect.ValueOf(dst) out := reflect.ValueOf(dst)
if out.IsNil() { if out.IsNil() {
panic("proto: nil destination") panic("proto: nil destination")
} }
if in.Type() != out.Type() { if in.Type() != out.Type() {
// Explicit test prior to mergeStruct so that mistyped nils will fail panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src))
panic("proto: type mismatch")
} }
if in.IsNil() { if in.IsNil() {
// Merging nil into non-nil is a quiet no-op return // Merge from nil src is a noop
}
if m, ok := dst.(generatedMerger); ok {
m.XXX_Merge(src)
return return
} }
mergeStruct(out.Elem(), in.Elem()) mergeStruct(out.Elem(), in.Elem())
@ -84,7 +108,7 @@ func mergeStruct(out, in reflect.Value) {
mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i])
} }
if emIn, ok := extendable(in.Addr().Interface()); ok { if emIn, err := extendable(in.Addr().Interface()); err == nil {
emOut, _ := extendable(out.Addr().Interface()) emOut, _ := extendable(out.Addr().Interface())
mIn, muIn := emIn.extensionsRead() mIn, muIn := emIn.extensionsRead()
if mIn != nil { if mIn != nil {

View file

@ -39,8 +39,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"os"
"reflect"
) )
// errOverflow is returned when an integer is too large to be represented. // errOverflow is returned when an integer is too large to be represented.
@ -50,10 +48,6 @@ var errOverflow = errors.New("proto: integer overflow")
// wire type is encountered. It does not get returned to user code. // wire type is encountered. It does not get returned to user code.
var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")
// The fundamental decoders that interpret bytes on the wire.
// Those that take integer types all return uint64 and are
// therefore of type valueDecoder.
// DecodeVarint reads a varint-encoded integer from the slice. // DecodeVarint reads a varint-encoded integer from the slice.
// It returns the integer and the number of bytes consumed, or // It returns the integer and the number of bytes consumed, or
// zero if there is not enough. // zero if there is not enough.
@ -267,9 +261,6 @@ func (p *Buffer) DecodeZigzag32() (x uint64, err error) {
return return
} }
// These are not ValueDecoders: they produce an array of bytes or a string.
// bytes, embedded messages
// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. // DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
// This is the format used for the bytes protocol buffer // This is the format used for the bytes protocol buffer
// type and for embedded messages. // type and for embedded messages.
@ -311,81 +302,29 @@ func (p *Buffer) DecodeStringBytes() (s string, err error) {
return string(buf), nil return string(buf), nil
} }
// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
// If the protocol buffer has extensions, and the field matches, add it as an extension.
// Otherwise, if the XXX_unrecognized field exists, append the skipped data there.
func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error {
oi := o.index
err := o.skip(t, tag, wire)
if err != nil {
return err
}
if !unrecField.IsValid() {
return nil
}
ptr := structPointer_Bytes(base, unrecField)
// Add the skipped field to struct field
obuf := o.buf
o.buf = *ptr
o.EncodeVarint(uint64(tag<<3 | wire))
*ptr = append(o.buf, obuf[oi:o.index]...)
o.buf = obuf
return nil
}
// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
func (o *Buffer) skip(t reflect.Type, tag, wire int) error {
var u uint64
var err error
switch wire {
case WireVarint:
_, err = o.DecodeVarint()
case WireFixed64:
_, err = o.DecodeFixed64()
case WireBytes:
_, err = o.DecodeRawBytes(false)
case WireFixed32:
_, err = o.DecodeFixed32()
case WireStartGroup:
for {
u, err = o.DecodeVarint()
if err != nil {
break
}
fwire := int(u & 0x7)
if fwire == WireEndGroup {
break
}
ftag := int(u >> 3)
err = o.skip(t, ftag, fwire)
if err != nil {
break
}
}
default:
err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t)
}
return err
}
// Unmarshaler is the interface representing objects that can // Unmarshaler is the interface representing objects that can
// unmarshal themselves. The method should reset the receiver before // unmarshal themselves. The argument points to data that may be
// decoding starts. The argument points to data that may be
// overwritten, so implementations should not keep references to the // overwritten, so implementations should not keep references to the
// buffer. // buffer.
// Unmarshal implementations should not clear the receiver.
// Any unmarshaled data should be merged into the receiver.
// Callers of Unmarshal that do not want to retain existing data
// should Reset the receiver before calling Unmarshal.
type Unmarshaler interface { type Unmarshaler interface {
Unmarshal([]byte) error Unmarshal([]byte) error
} }
// newUnmarshaler is the interface representing objects that can
// unmarshal themselves. The semantics are identical to Unmarshaler.
//
// This exists to support protoc-gen-go generated messages.
// The proto package will stop type-asserting to this interface in the future.
//
// DO NOT DEPEND ON THIS.
type newUnmarshaler interface {
XXX_Unmarshal([]byte) error
}
// Unmarshal parses the protocol buffer representation in buf and places the // Unmarshal parses the protocol buffer representation in buf and places the
// decoded result in pb. If the struct underlying pb does not match // decoded result in pb. If the struct underlying pb does not match
// the data in buf, the results can be unpredictable. // the data in buf, the results can be unpredictable.
@ -395,7 +334,13 @@ type Unmarshaler interface {
// to preserve and append to existing data. // to preserve and append to existing data.
func Unmarshal(buf []byte, pb Message) error { func Unmarshal(buf []byte, pb Message) error {
pb.Reset() pb.Reset()
return UnmarshalMerge(buf, pb) if u, ok := pb.(newUnmarshaler); ok {
return u.XXX_Unmarshal(buf)
}
if u, ok := pb.(Unmarshaler); ok {
return u.Unmarshal(buf)
}
return NewBuffer(buf).Unmarshal(pb)
} }
// UnmarshalMerge parses the protocol buffer representation in buf and // UnmarshalMerge parses the protocol buffer representation in buf and
@ -405,8 +350,16 @@ func Unmarshal(buf []byte, pb Message) error {
// UnmarshalMerge merges into existing data in pb. // UnmarshalMerge merges into existing data in pb.
// Most code should use Unmarshal instead. // Most code should use Unmarshal instead.
func UnmarshalMerge(buf []byte, pb Message) error { func UnmarshalMerge(buf []byte, pb Message) error {
// If the object can unmarshal itself, let it. if u, ok := pb.(newUnmarshaler); ok {
return u.XXX_Unmarshal(buf)
}
if u, ok := pb.(Unmarshaler); ok { if u, ok := pb.(Unmarshaler); ok {
// NOTE: The history of proto have unfortunately been inconsistent
// whether Unmarshaler should or should not implicitly clear itself.
// Some implementations do, most do not.
// Thus, calling this here may or may not do what people want.
//
// See https://github.com/golang/protobuf/issues/424
return u.Unmarshal(buf) return u.Unmarshal(buf)
} }
return NewBuffer(buf).Unmarshal(pb) return NewBuffer(buf).Unmarshal(pb)
@ -422,12 +375,17 @@ func (p *Buffer) DecodeMessage(pb Message) error {
} }
// DecodeGroup reads a tag-delimited group from the Buffer. // DecodeGroup reads a tag-delimited group from the Buffer.
// StartGroup tag is already consumed. This function consumes
// EndGroup tag.
func (p *Buffer) DecodeGroup(pb Message) error { func (p *Buffer) DecodeGroup(pb Message) error {
typ, base, err := getbase(pb) b := p.buf[p.index:]
if err != nil { x, y := findEndGroup(b)
return err if x < 0 {
return io.ErrUnexpectedEOF
} }
return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) err := Unmarshal(b[:x], pb)
p.index += y
return err
} }
// Unmarshal parses the protocol buffer representation in the // Unmarshal parses the protocol buffer representation in the
@ -438,533 +396,33 @@ func (p *Buffer) DecodeGroup(pb Message) error {
// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. // Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal.
func (p *Buffer) Unmarshal(pb Message) error { func (p *Buffer) Unmarshal(pb Message) error {
// If the object can unmarshal itself, let it. // If the object can unmarshal itself, let it.
if u, ok := pb.(newUnmarshaler); ok {
err := u.XXX_Unmarshal(p.buf[p.index:])
p.index = len(p.buf)
return err
}
if u, ok := pb.(Unmarshaler); ok { if u, ok := pb.(Unmarshaler); ok {
// NOTE: The history of proto have unfortunately been inconsistent
// whether Unmarshaler should or should not implicitly clear itself.
// Some implementations do, most do not.
// Thus, calling this here may or may not do what people want.
//
// See https://github.com/golang/protobuf/issues/424
err := u.Unmarshal(p.buf[p.index:]) err := u.Unmarshal(p.buf[p.index:])
p.index = len(p.buf) p.index = len(p.buf)
return err return err
} }
typ, base, err := getbase(pb) // Slow workaround for messages that aren't Unmarshalers.
if err != nil { // This includes some hand-coded .pb.go files and
return err // bootstrap protos.
} // TODO: fix all of those and then add Unmarshal to
// the Message interface. Then:
err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base) // The cast above and code below can be deleted.
// The old unmarshaler can be deleted.
if collectStats { // Clients can call Unmarshal directly (can already do that, actually).
stats.Decode++ var info InternalMessageInfo
} err := info.Unmarshal(pb, p.buf[p.index:])
p.index = len(p.buf)
return err
}
// unmarshalType does the work of unmarshaling a structure.
func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error {
var state errorState
required, reqFields := prop.reqCount, uint64(0)
var err error
for err == nil && o.index < len(o.buf) {
oi := o.index
var u uint64
u, err = o.DecodeVarint()
if err != nil {
break
}
wire := int(u & 0x7)
if wire == WireEndGroup {
if is_group {
if required > 0 {
// Not enough information to determine the exact field.
// (See below.)
return &RequiredNotSetError{"{Unknown}"}
}
return nil // input is satisfied
}
return fmt.Errorf("proto: %s: wiretype end group for non-group", st)
}
tag := int(u >> 3)
if tag <= 0 {
return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire)
}
fieldnum, ok := prop.decoderTags.get(tag)
if !ok {
// Maybe it's an extension?
if prop.extendable {
if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) {
if err = o.skip(st, tag, wire); err == nil {
extmap := e.extensionsWrite()
ext := extmap[int32(tag)] // may be missing
ext.enc = append(ext.enc, o.buf[oi:o.index]...)
extmap[int32(tag)] = ext
}
continue
}
}
// Maybe it's a oneof?
if prop.oneofUnmarshaler != nil {
m := structPointer_Interface(base, st).(Message)
// First return value indicates whether tag is a oneof field.
ok, err = prop.oneofUnmarshaler(m, tag, wire, o)
if err == ErrInternalBadWireType {
// Map the error to something more descriptive.
// Do the formatting here to save generated code space.
err = fmt.Errorf("bad wiretype for oneof field in %T", m)
}
if ok {
continue
}
}
err = o.skipAndSave(st, tag, wire, base, prop.unrecField)
continue
}
p := prop.Prop[fieldnum]
if p.dec == nil {
fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name)
continue
}
dec := p.dec
if wire != WireStartGroup && wire != p.WireType {
if wire == WireBytes && p.packedDec != nil {
// a packable field
dec = p.packedDec
} else {
err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType)
continue
}
}
decErr := dec(o, p, base)
if decErr != nil && !state.shouldContinue(decErr, p) {
err = decErr
}
if err == nil && p.Required {
// Successfully decoded a required field.
if tag <= 64 {
// use bitmap for fields 1-64 to catch field reuse.
var mask uint64 = 1 << uint64(tag-1)
if reqFields&mask == 0 {
// new required field
reqFields |= mask
required--
}
} else {
// This is imprecise. It can be fooled by a required field
// with a tag > 64 that is encoded twice; that's very rare.
// A fully correct implementation would require allocating
// a data structure, which we would like to avoid.
required--
}
}
}
if err == nil {
if is_group {
return io.ErrUnexpectedEOF
}
if state.err != nil {
return state.err
}
if required > 0 {
// Not enough information to determine the exact field. If we use extra
// CPU, we could determine the field only if the missing required field
// has a tag <= 64 and we check reqFields.
return &RequiredNotSetError{"{Unknown}"}
}
}
return err
}
// Individual type decoders
// For each,
// u is the decoded value,
// v is a pointer to the field (pointer) in the struct
// Sizes of the pools to allocate inside the Buffer.
// The goal is modest amortization and allocation
// on at least 16-byte boundaries.
const (
boolPoolSize = 16
uint32PoolSize = 8
uint64PoolSize = 4
)
// Decode a bool.
func (o *Buffer) dec_bool(p *Properties, base structPointer) error {
u, err := p.valDec(o)
if err != nil {
return err
}
if len(o.bools) == 0 {
o.bools = make([]bool, boolPoolSize)
}
o.bools[0] = u != 0
*structPointer_Bool(base, p.field) = &o.bools[0]
o.bools = o.bools[1:]
return nil
}
func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error {
u, err := p.valDec(o)
if err != nil {
return err
}
*structPointer_BoolVal(base, p.field) = u != 0
return nil
}
// Decode an int32.
func (o *Buffer) dec_int32(p *Properties, base structPointer) error {
u, err := p.valDec(o)
if err != nil {
return err
}
word32_Set(structPointer_Word32(base, p.field), o, uint32(u))
return nil
}
func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error {
u, err := p.valDec(o)
if err != nil {
return err
}
word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u))
return nil
}
// Decode an int64.
func (o *Buffer) dec_int64(p *Properties, base structPointer) error {
u, err := p.valDec(o)
if err != nil {
return err
}
word64_Set(structPointer_Word64(base, p.field), o, u)
return nil
}
func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error {
u, err := p.valDec(o)
if err != nil {
return err
}
word64Val_Set(structPointer_Word64Val(base, p.field), o, u)
return nil
}
// Decode a string.
func (o *Buffer) dec_string(p *Properties, base structPointer) error {
s, err := o.DecodeStringBytes()
if err != nil {
return err
}
*structPointer_String(base, p.field) = &s
return nil
}
func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error {
s, err := o.DecodeStringBytes()
if err != nil {
return err
}
*structPointer_StringVal(base, p.field) = s
return nil
}
// Decode a slice of bytes ([]byte).
func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error {
b, err := o.DecodeRawBytes(true)
if err != nil {
return err
}
*structPointer_Bytes(base, p.field) = b
return nil
}
// Decode a slice of bools ([]bool).
func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error {
u, err := p.valDec(o)
if err != nil {
return err
}
v := structPointer_BoolSlice(base, p.field)
*v = append(*v, u != 0)
return nil
}
// Decode a slice of bools ([]bool) in packed format.
func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error {
v := structPointer_BoolSlice(base, p.field)
nn, err := o.DecodeVarint()
if err != nil {
return err
}
nb := int(nn) // number of bytes of encoded bools
fin := o.index + nb
if fin < o.index {
return errOverflow
}
y := *v
for o.index < fin {
u, err := p.valDec(o)
if err != nil {
return err
}
y = append(y, u != 0)
}
*v = y
return nil
}
// Decode a slice of int32s ([]int32).
func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error {
u, err := p.valDec(o)
if err != nil {
return err
}
structPointer_Word32Slice(base, p.field).Append(uint32(u))
return nil
}
// Decode a slice of int32s ([]int32) in packed format.
func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error {
v := structPointer_Word32Slice(base, p.field)
nn, err := o.DecodeVarint()
if err != nil {
return err
}
nb := int(nn) // number of bytes of encoded int32s
fin := o.index + nb
if fin < o.index {
return errOverflow
}
for o.index < fin {
u, err := p.valDec(o)
if err != nil {
return err
}
v.Append(uint32(u))
}
return nil
}
// Decode a slice of int64s ([]int64).
func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error {
u, err := p.valDec(o)
if err != nil {
return err
}
structPointer_Word64Slice(base, p.field).Append(u)
return nil
}
// Decode a slice of int64s ([]int64) in packed format.
func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error {
v := structPointer_Word64Slice(base, p.field)
nn, err := o.DecodeVarint()
if err != nil {
return err
}
nb := int(nn) // number of bytes of encoded int64s
fin := o.index + nb
if fin < o.index {
return errOverflow
}
for o.index < fin {
u, err := p.valDec(o)
if err != nil {
return err
}
v.Append(u)
}
return nil
}
// Decode a slice of strings ([]string).
func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error {
s, err := o.DecodeStringBytes()
if err != nil {
return err
}
v := structPointer_StringSlice(base, p.field)
*v = append(*v, s)
return nil
}
// Decode a slice of slice of bytes ([][]byte).
func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error {
b, err := o.DecodeRawBytes(true)
if err != nil {
return err
}
v := structPointer_BytesSlice(base, p.field)
*v = append(*v, b)
return nil
}
// Decode a map field.
func (o *Buffer) dec_new_map(p *Properties, base structPointer) error {
raw, err := o.DecodeRawBytes(false)
if err != nil {
return err
}
oi := o.index // index at the end of this map entry
o.index -= len(raw) // move buffer back to start of map entry
mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V
if mptr.Elem().IsNil() {
mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem()))
}
v := mptr.Elem() // map[K]V
// Prepare addressable doubly-indirect placeholders for the key and value types.
// See enc_new_map for why.
keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K
keybase := toStructPointer(keyptr.Addr()) // **K
var valbase structPointer
var valptr reflect.Value
switch p.mtype.Elem().Kind() {
case reflect.Slice:
// []byte
var dummy []byte
valptr = reflect.ValueOf(&dummy) // *[]byte
valbase = toStructPointer(valptr) // *[]byte
case reflect.Ptr:
// message; valptr is **Msg; need to allocate the intermediate pointer
valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
valptr.Set(reflect.New(valptr.Type().Elem()))
valbase = toStructPointer(valptr)
default:
// everything else
valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
valbase = toStructPointer(valptr.Addr()) // **V
}
// Decode.
// This parses a restricted wire format, namely the encoding of a message
// with two fields. See enc_new_map for the format.
for o.index < oi {
// tagcode for key and value properties are always a single byte
// because they have tags 1 and 2.
tagcode := o.buf[o.index]
o.index++
switch tagcode {
case p.mkeyprop.tagcode[0]:
if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil {
return err
}
case p.mvalprop.tagcode[0]:
if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil {
return err
}
default:
// TODO: Should we silently skip this instead?
return fmt.Errorf("proto: bad map data tag %d", raw[0])
}
}
keyelem, valelem := keyptr.Elem(), valptr.Elem()
if !keyelem.IsValid() {
keyelem = reflect.Zero(p.mtype.Key())
}
if !valelem.IsValid() {
valelem = reflect.Zero(p.mtype.Elem())
}
v.SetMapIndex(keyelem, valelem)
return nil
}
// Decode a group.
func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error {
bas := structPointer_GetStructPointer(base, p.field)
if structPointer_IsNil(bas) {
// allocate new nested message
bas = toStructPointer(reflect.New(p.stype))
structPointer_SetStructPointer(base, p.field, bas)
}
return o.unmarshalType(p.stype, p.sprop, true, bas)
}
// Decode an embedded message.
func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) {
raw, e := o.DecodeRawBytes(false)
if e != nil {
return e
}
bas := structPointer_GetStructPointer(base, p.field)
if structPointer_IsNil(bas) {
// allocate new nested message
bas = toStructPointer(reflect.New(p.stype))
structPointer_SetStructPointer(base, p.field, bas)
}
// If the object can unmarshal itself, let it.
if p.isUnmarshaler {
iv := structPointer_Interface(bas, p.stype)
return iv.(Unmarshaler).Unmarshal(raw)
}
obuf := o.buf
oi := o.index
o.buf = raw
o.index = 0
err = o.unmarshalType(p.stype, p.sprop, false, bas)
o.buf = obuf
o.index = oi
return err
}
// Decode a slice of embedded messages.
func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error {
return o.dec_slice_struct(p, false, base)
}
// Decode a slice of embedded groups.
func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error {
return o.dec_slice_struct(p, true, base)
}
// Decode a slice of structs ([]*struct).
func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error {
v := reflect.New(p.stype)
bas := toStructPointer(v)
structPointer_StructPointerSlice(base, p.field).Append(bas)
if is_group {
err := o.unmarshalType(p.stype, p.sprop, is_group, bas)
return err
}
raw, err := o.DecodeRawBytes(false)
if err != nil {
return err
}
// If the object can unmarshal itself, let it.
if p.isUnmarshaler {
iv := v.Interface()
return iv.(Unmarshaler).Unmarshal(raw)
}
obuf := o.buf
oi := o.index
o.buf = raw
o.index = 0
err = o.unmarshalType(p.stype, p.sprop, is_group, bas)
o.buf = obuf
o.index = oi
return err return err
} }

View file

@ -35,8 +35,14 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
"sync"
"sync/atomic"
) )
type generatedDiscarder interface {
XXX_DiscardUnknown()
}
// DiscardUnknown recursively discards all unknown fields from this message // DiscardUnknown recursively discards all unknown fields from this message
// and all embedded messages. // and all embedded messages.
// //
@ -49,9 +55,202 @@ import (
// For proto2 messages, the unknown fields of message extensions are only // For proto2 messages, the unknown fields of message extensions are only
// discarded from messages that have been accessed via GetExtension. // discarded from messages that have been accessed via GetExtension.
func DiscardUnknown(m Message) { func DiscardUnknown(m Message) {
if m, ok := m.(generatedDiscarder); ok {
m.XXX_DiscardUnknown()
return
}
// TODO: Dynamically populate a InternalMessageInfo for legacy messages,
// but the master branch has no implementation for InternalMessageInfo,
// so it would be more work to replicate that approach.
discardLegacy(m) discardLegacy(m)
} }
// DiscardUnknown recursively discards all unknown fields.
func (a *InternalMessageInfo) DiscardUnknown(m Message) {
di := atomicLoadDiscardInfo(&a.discard)
if di == nil {
di = getDiscardInfo(reflect.TypeOf(m).Elem())
atomicStoreDiscardInfo(&a.discard, di)
}
di.discard(toPointer(&m))
}
type discardInfo struct {
typ reflect.Type
initialized int32 // 0: only typ is valid, 1: everything is valid
lock sync.Mutex
fields []discardFieldInfo
unrecognized field
}
type discardFieldInfo struct {
field field // Offset of field, guaranteed to be valid
discard func(src pointer)
}
var (
discardInfoMap = map[reflect.Type]*discardInfo{}
discardInfoLock sync.Mutex
)
func getDiscardInfo(t reflect.Type) *discardInfo {
discardInfoLock.Lock()
defer discardInfoLock.Unlock()
di := discardInfoMap[t]
if di == nil {
di = &discardInfo{typ: t}
discardInfoMap[t] = di
}
return di
}
func (di *discardInfo) discard(src pointer) {
if src.isNil() {
return // Nothing to do.
}
if atomic.LoadInt32(&di.initialized) == 0 {
di.computeDiscardInfo()
}
for _, fi := range di.fields {
sfp := src.offset(fi.field)
fi.discard(sfp)
}
// For proto2 messages, only discard unknown fields in message extensions
// that have been accessed via GetExtension.
if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil {
// Ignore lock since DiscardUnknown is not concurrency safe.
emm, _ := em.extensionsRead()
for _, mx := range emm {
if m, ok := mx.value.(Message); ok {
DiscardUnknown(m)
}
}
}
if di.unrecognized.IsValid() {
*src.offset(di.unrecognized).toBytes() = nil
}
}
func (di *discardInfo) computeDiscardInfo() {
di.lock.Lock()
defer di.lock.Unlock()
if di.initialized != 0 {
return
}
t := di.typ
n := t.NumField()
for i := 0; i < n; i++ {
f := t.Field(i)
if strings.HasPrefix(f.Name, "XXX_") {
continue
}
dfi := discardFieldInfo{field: toField(&f)}
tf := f.Type
// Unwrap tf to get its most basic type.
var isPointer, isSlice bool
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
isSlice = true
tf = tf.Elem()
}
if tf.Kind() == reflect.Ptr {
isPointer = true
tf = tf.Elem()
}
if isPointer && isSlice && tf.Kind() != reflect.Struct {
panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name))
}
switch tf.Kind() {
case reflect.Struct:
switch {
case !isPointer:
panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name))
case isSlice: // E.g., []*pb.T
di := getDiscardInfo(tf)
dfi.discard = func(src pointer) {
sps := src.getPointerSlice()
for _, sp := range sps {
if !sp.isNil() {
di.discard(sp)
}
}
}
default: // E.g., *pb.T
di := getDiscardInfo(tf)
dfi.discard = func(src pointer) {
sp := src.getPointer()
if !sp.isNil() {
di.discard(sp)
}
}
}
case reflect.Map:
switch {
case isPointer || isSlice:
panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name))
default: // E.g., map[K]V
if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T)
dfi.discard = func(src pointer) {
sm := src.asPointerTo(tf).Elem()
if sm.Len() == 0 {
return
}
for _, key := range sm.MapKeys() {
val := sm.MapIndex(key)
DiscardUnknown(val.Interface().(Message))
}
}
} else {
dfi.discard = func(pointer) {} // Noop
}
}
case reflect.Interface:
// Must be oneof field.
switch {
case isPointer || isSlice:
panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name))
default: // E.g., interface{}
// TODO: Make this faster?
dfi.discard = func(src pointer) {
su := src.asPointerTo(tf).Elem()
if !su.IsNil() {
sv := su.Elem().Elem().Field(0)
if sv.Kind() == reflect.Ptr && sv.IsNil() {
return
}
switch sv.Type().Kind() {
case reflect.Ptr: // Proto struct (e.g., *T)
DiscardUnknown(sv.Interface().(Message))
}
}
}
}
default:
continue
}
di.fields = append(di.fields, dfi)
}
di.unrecognized = invalidField
if f, ok := t.FieldByName("XXX_unrecognized"); ok {
if f.Type != reflect.TypeOf([]byte{}) {
panic("expected XXX_unrecognized to be of type []byte")
}
di.unrecognized = toField(&f)
}
atomic.StoreInt32(&di.initialized, 1)
}
func discardLegacy(m Message) { func discardLegacy(m Message) {
v := reflect.ValueOf(m) v := reflect.ValueOf(m)
if v.Kind() != reflect.Ptr || v.IsNil() { if v.Kind() != reflect.Ptr || v.IsNil() {
@ -139,7 +338,7 @@ func discardLegacy(m Message) {
// For proto2 messages, only discard unknown fields in message extensions // For proto2 messages, only discard unknown fields in message extensions
// that have been accessed via GetExtension. // that have been accessed via GetExtension.
if em, ok := extendable(m); ok { if em, err := extendable(m); err == nil {
// Ignore lock since discardLegacy is not concurrency safe. // Ignore lock since discardLegacy is not concurrency safe.
emm, _ := em.extensionsRead() emm, _ := em.extensionsRead()
for _, mx := range emm { for _, mx := range emm {

File diff suppressed because it is too large Load diff

View file

@ -109,15 +109,6 @@ func equalStruct(v1, v2 reflect.Value) bool {
// set/unset mismatch // set/unset mismatch
return false return false
} }
b1, ok := f1.Interface().(raw)
if ok {
b2 := f2.Interface().(raw)
// RawMessage
if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
return false
}
continue
}
f1, f2 = f1.Elem(), f2.Elem() f1, f2 = f1.Elem(), f2.Elem()
} }
if !equalAny(f1, f2, sprop.Prop[i]) { if !equalAny(f1, f2, sprop.Prop[i]) {
@ -146,11 +137,7 @@ func equalStruct(v1, v2 reflect.Value) bool {
u1 := uf.Bytes() u1 := uf.Bytes()
u2 := v2.FieldByName("XXX_unrecognized").Bytes() u2 := v2.FieldByName("XXX_unrecognized").Bytes()
if !bytes.Equal(u1, u2) { return bytes.Equal(u1, u2)
return false
}
return true
} }
// v1 and v2 are known to have the same type. // v1 and v2 are known to have the same type.
@ -261,6 +248,15 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
m1, m2 := e1.value, e2.value m1, m2 := e1.value, e2.value
if m1 == nil && m2 == nil {
// Both have only encoded form.
if bytes.Equal(e1.enc, e2.enc) {
continue
}
// The bytes are different, but the extensions might still be
// equal. We need to decode them to compare.
}
if m1 != nil && m2 != nil { if m1 != nil && m2 != nil {
// Both are unencoded. // Both are unencoded.
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
@ -276,8 +272,12 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
desc = m[extNum] desc = m[extNum]
} }
if desc == nil { if desc == nil {
// If both have only encoded form and the bytes are the same,
// it is handled above. We get here when the bytes are different.
// We don't know how to decode it, so just compare them as byte
// slices.
log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) log.Printf("proto: don't know how to compare extension %d of %v", extNum, base)
continue return false
} }
var err error var err error
if m1 == nil { if m1 == nil {

View file

@ -38,6 +38,7 @@ package proto
import ( import (
"errors" "errors"
"fmt" "fmt"
"io"
"reflect" "reflect"
"strconv" "strconv"
"sync" "sync"
@ -91,14 +92,29 @@ func (n notLocker) Unlock() {}
// extendable returns the extendableProto interface for the given generated proto message. // extendable returns the extendableProto interface for the given generated proto message.
// If the proto message has the old extension format, it returns a wrapper that implements // If the proto message has the old extension format, it returns a wrapper that implements
// the extendableProto interface. // the extendableProto interface.
func extendable(p interface{}) (extendableProto, bool) { func extendable(p interface{}) (extendableProto, error) {
if ep, ok := p.(extendableProto); ok { switch p := p.(type) {
return ep, ok case extendableProto:
if isNilPtr(p) {
return nil, fmt.Errorf("proto: nil %T is not extendable", p)
} }
if ep, ok := p.(extendableProtoV1); ok { return p, nil
return extensionAdapter{ep}, ok case extendableProtoV1:
if isNilPtr(p) {
return nil, fmt.Errorf("proto: nil %T is not extendable", p)
} }
return nil, false return extensionAdapter{p}, nil
}
// Don't allocate a specific error containing %T:
// this is the hot path for Clone and MarshalText.
return nil, errNotExtendable
}
var errNotExtendable = errors.New("proto: not an extendable proto.Message")
func isNilPtr(x interface{}) bool {
v := reflect.ValueOf(x)
return v.Kind() == reflect.Ptr && v.IsNil()
} }
// XXX_InternalExtensions is an internal representation of proto extensions. // XXX_InternalExtensions is an internal representation of proto extensions.
@ -143,9 +159,6 @@ func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Loc
return e.p.extensionMap, &e.p.mu return e.p.extensionMap, &e.p.mu
} }
var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem()
var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem()
// ExtensionDesc represents an extension specification. // ExtensionDesc represents an extension specification.
// Used in generated code from the protocol compiler. // Used in generated code from the protocol compiler.
type ExtensionDesc struct { type ExtensionDesc struct {
@ -179,8 +192,8 @@ type Extension struct {
// SetRawExtension is for testing only. // SetRawExtension is for testing only.
func SetRawExtension(base Message, id int32, b []byte) { func SetRawExtension(base Message, id int32, b []byte) {
epb, ok := extendable(base) epb, err := extendable(base)
if !ok { if err != nil {
return return
} }
extmap := epb.extensionsWrite() extmap := epb.extensionsWrite()
@ -205,7 +218,7 @@ func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error {
pbi = ea.extendableProtoV1 pbi = ea.extendableProtoV1
} }
if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b {
return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String()) return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a)
} }
// Check the range. // Check the range.
if !isExtensionField(pb, extension.Field) { if !isExtensionField(pb, extension.Field) {
@ -250,85 +263,11 @@ func extensionProperties(ed *ExtensionDesc) *Properties {
return prop return prop
} }
// encode encodes any unmarshaled (unencoded) extensions in e.
func encodeExtensions(e *XXX_InternalExtensions) error {
m, mu := e.extensionsRead()
if m == nil {
return nil // fast path
}
mu.Lock()
defer mu.Unlock()
return encodeExtensionsMap(m)
}
// encode encodes any unmarshaled (unencoded) extensions in e.
func encodeExtensionsMap(m map[int32]Extension) error {
for k, e := range m {
if e.value == nil || e.desc == nil {
// Extension is only in its encoded form.
continue
}
// We don't skip extensions that have an encoded form set,
// because the extension value may have been mutated after
// the last time this function was called.
et := reflect.TypeOf(e.desc.ExtensionType)
props := extensionProperties(e.desc)
p := NewBuffer(nil)
// If e.value has type T, the encoder expects a *struct{ X T }.
// Pass a *T with a zero field and hope it all works out.
x := reflect.New(et)
x.Elem().Set(reflect.ValueOf(e.value))
if err := props.enc(p, props, toStructPointer(x)); err != nil {
return err
}
e.enc = p.buf
m[k] = e
}
return nil
}
func extensionsSize(e *XXX_InternalExtensions) (n int) {
m, mu := e.extensionsRead()
if m == nil {
return 0
}
mu.Lock()
defer mu.Unlock()
return extensionsMapSize(m)
}
func extensionsMapSize(m map[int32]Extension) (n int) {
for _, e := range m {
if e.value == nil || e.desc == nil {
// Extension is only in its encoded form.
n += len(e.enc)
continue
}
// We don't skip extensions that have an encoded form set,
// because the extension value may have been mutated after
// the last time this function was called.
et := reflect.TypeOf(e.desc.ExtensionType)
props := extensionProperties(e.desc)
// If e.value has type T, the encoder expects a *struct{ X T }.
// Pass a *T with a zero field and hope it all works out.
x := reflect.New(et)
x.Elem().Set(reflect.ValueOf(e.value))
n += props.size(props, toStructPointer(x))
}
return
}
// HasExtension returns whether the given extension is present in pb. // HasExtension returns whether the given extension is present in pb.
func HasExtension(pb Message, extension *ExtensionDesc) bool { func HasExtension(pb Message, extension *ExtensionDesc) bool {
// TODO: Check types, field numbers, etc.? // TODO: Check types, field numbers, etc.?
epb, ok := extendable(pb) epb, err := extendable(pb)
if !ok { if err != nil {
return false return false
} }
extmap, mu := epb.extensionsRead() extmap, mu := epb.extensionsRead()
@ -336,15 +275,15 @@ func HasExtension(pb Message, extension *ExtensionDesc) bool {
return false return false
} }
mu.Lock() mu.Lock()
_, ok = extmap[extension.Field] _, ok := extmap[extension.Field]
mu.Unlock() mu.Unlock()
return ok return ok
} }
// ClearExtension removes the given extension from pb. // ClearExtension removes the given extension from pb.
func ClearExtension(pb Message, extension *ExtensionDesc) { func ClearExtension(pb Message, extension *ExtensionDesc) {
epb, ok := extendable(pb) epb, err := extendable(pb)
if !ok { if err != nil {
return return
} }
// TODO: Check types, field numbers, etc.? // TODO: Check types, field numbers, etc.?
@ -352,17 +291,27 @@ func ClearExtension(pb Message, extension *ExtensionDesc) {
delete(extmap, extension.Field) delete(extmap, extension.Field)
} }
// GetExtension parses and returns the given extension of pb. // GetExtension retrieves a proto2 extended field from pb.
// If the extension is not present and has no default value it returns ErrMissingExtension. //
// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil),
// then GetExtension parses the encoded field and returns a Go value of the specified type.
// If the field is not present, then the default value is returned (if one is specified),
// otherwise ErrMissingExtension is reported.
//
// If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil),
// then GetExtension returns the raw encoded bytes of the field extension.
func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
epb, ok := extendable(pb) epb, err := extendable(pb)
if !ok { if err != nil {
return nil, errors.New("proto: not an extendable proto") return nil, err
} }
if extension.ExtendedType != nil {
// can only check type if this is a complete descriptor
if err := checkExtensionTypes(epb, extension); err != nil { if err := checkExtensionTypes(epb, extension); err != nil {
return nil, err return nil, err
} }
}
emap, mu := epb.extensionsRead() emap, mu := epb.extensionsRead()
if emap == nil { if emap == nil {
@ -388,6 +337,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
return e.value, nil return e.value, nil
} }
if extension.ExtensionType == nil {
// incomplete descriptor
return e.enc, nil
}
v, err := decodeExtension(e.enc, extension) v, err := decodeExtension(e.enc, extension)
if err != nil { if err != nil {
return nil, err return nil, err
@ -405,6 +359,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
// defaultExtensionValue returns the default value for extension. // defaultExtensionValue returns the default value for extension.
// If no default for an extension is defined ErrMissingExtension is returned. // If no default for an extension is defined ErrMissingExtension is returned.
func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) {
if extension.ExtensionType == nil {
// incomplete descriptor, so no default
return nil, ErrMissingExtension
}
t := reflect.TypeOf(extension.ExtensionType) t := reflect.TypeOf(extension.ExtensionType)
props := extensionProperties(extension) props := extensionProperties(extension)
@ -439,31 +398,28 @@ func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) {
// decodeExtension decodes an extension encoded in b. // decodeExtension decodes an extension encoded in b.
func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
o := NewBuffer(b)
t := reflect.TypeOf(extension.ExtensionType) t := reflect.TypeOf(extension.ExtensionType)
unmarshal := typeUnmarshaler(t, extension.Tag)
props := extensionProperties(extension)
// t is a pointer to a struct, pointer to basic type or a slice. // t is a pointer to a struct, pointer to basic type or a slice.
// Allocate a "field" to store the pointer/slice itself; the // Allocate space to store the pointer/slice.
// pointer/slice will be stored here. We pass
// the address of this field to props.dec.
// This passes a zero field and a *t and lets props.dec
// interpret it as a *struct{ x t }.
value := reflect.New(t).Elem() value := reflect.New(t).Elem()
var err error
for { for {
// Discard wire type and field number varint. It isn't needed. x, n := decodeVarint(b)
if _, err := o.DecodeVarint(); err != nil { if n == 0 {
return nil, io.ErrUnexpectedEOF
}
b = b[n:]
wire := int(x) & 7
b, err = unmarshal(b, valToPointer(value.Addr()), wire)
if err != nil {
return nil, err return nil, err
} }
if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { if len(b) == 0 {
return nil, err
}
if o.index >= len(o.buf) {
break break
} }
} }
@ -473,9 +429,9 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
// GetExtensions returns a slice of the extensions present in pb that are also listed in es. // GetExtensions returns a slice of the extensions present in pb that are also listed in es.
// The returned slice has the same length as es; missing extensions will appear as nil elements. // The returned slice has the same length as es; missing extensions will appear as nil elements.
func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) {
epb, ok := extendable(pb) epb, err := extendable(pb)
if !ok { if err != nil {
return nil, errors.New("proto: not an extendable proto") return nil, err
} }
extensions = make([]interface{}, len(es)) extensions = make([]interface{}, len(es))
for i, e := range es { for i, e := range es {
@ -494,9 +450,9 @@ func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, e
// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing // For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing
// just the Field field, which defines the extension's field number. // just the Field field, which defines the extension's field number.
func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) {
epb, ok := extendable(pb) epb, err := extendable(pb)
if !ok { if err != nil {
return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb) return nil, err
} }
registeredExtensions := RegisteredExtensions(pb) registeredExtensions := RegisteredExtensions(pb)
@ -523,9 +479,9 @@ func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) {
// SetExtension sets the specified extension of pb to the specified value. // SetExtension sets the specified extension of pb to the specified value.
func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error {
epb, ok := extendable(pb) epb, err := extendable(pb)
if !ok { if err != nil {
return errors.New("proto: not an extendable proto") return err
} }
if err := checkExtensionTypes(epb, extension); err != nil { if err := checkExtensionTypes(epb, extension); err != nil {
return err return err
@ -550,8 +506,8 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error
// ClearAllExtensions clears all extensions from pb. // ClearAllExtensions clears all extensions from pb.
func ClearAllExtensions(pb Message) { func ClearAllExtensions(pb Message) {
epb, ok := extendable(pb) epb, err := extendable(pb)
if !ok { if err != nil {
return return
} }
m := epb.extensionsWrite() m := epb.extensionsWrite()

View file

@ -273,6 +273,67 @@ import (
"sync" "sync"
) )
// RequiredNotSetError is an error type returned by either Marshal or Unmarshal.
// Marshal reports this when a required field is not initialized.
// Unmarshal reports this when a required field is missing from the wire data.
type RequiredNotSetError struct{ field string }
func (e *RequiredNotSetError) Error() string {
if e.field == "" {
return fmt.Sprintf("proto: required field not set")
}
return fmt.Sprintf("proto: required field %q not set", e.field)
}
func (e *RequiredNotSetError) RequiredNotSet() bool {
return true
}
type invalidUTF8Error struct{ field string }
func (e *invalidUTF8Error) Error() string {
if e.field == "" {
return "proto: invalid UTF-8 detected"
}
return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field)
}
func (e *invalidUTF8Error) InvalidUTF8() bool {
return true
}
// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8.
// This error should not be exposed to the external API as such errors should
// be recreated with the field information.
var errInvalidUTF8 = &invalidUTF8Error{}
// isNonFatal reports whether the error is either a RequiredNotSet error
// or a InvalidUTF8 error.
func isNonFatal(err error) bool {
if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() {
return true
}
if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() {
return true
}
return false
}
type nonFatal struct{ E error }
// Merge merges err into nf and reports whether it was successful.
// Otherwise it returns false for any fatal non-nil errors.
func (nf *nonFatal) Merge(err error) (ok bool) {
if err == nil {
return true // not an error
}
if !isNonFatal(err) {
return false // fatal error
}
if nf.E == nil {
nf.E = err // store first instance of non-fatal error
}
return true
}
// Message is implemented by generated protocol buffer messages. // Message is implemented by generated protocol buffer messages.
type Message interface { type Message interface {
Reset() Reset()
@ -309,16 +370,7 @@ type Buffer struct {
buf []byte // encode/decode byte stream buf []byte // encode/decode byte stream
index int // read point index int // read point
// pools of basic types to amortize allocation. deterministic bool
bools []bool
uint32s []uint32
uint64s []uint64
// extra pools, only used with pointer_reflect.go
int32s []int32
int64s []int64
float32s []float32
float64s []float64
} }
// NewBuffer allocates a new Buffer and initializes its internal data to // NewBuffer allocates a new Buffer and initializes its internal data to
@ -343,6 +395,30 @@ func (p *Buffer) SetBuf(s []byte) {
// Bytes returns the contents of the Buffer. // Bytes returns the contents of the Buffer.
func (p *Buffer) Bytes() []byte { return p.buf } func (p *Buffer) Bytes() []byte { return p.buf }
// SetDeterministic sets whether to use deterministic serialization.
//
// Deterministic serialization guarantees that for a given binary, equal
// messages will always be serialized to the same bytes. This implies:
//
// - Repeated serialization of a message will return the same bytes.
// - Different processes of the same binary (which may be executing on
// different machines) will serialize equal messages to the same bytes.
//
// Note that the deterministic serialization is NOT canonical across
// languages. It is not guaranteed to remain stable over time. It is unstable
// across different builds with schema changes due to unknown fields.
// Users who need canonical serialization (e.g., persistent storage in a
// canonical form, fingerprinting, etc.) should define their own
// canonicalization specification and implement their own serializer rather
// than relying on this API.
//
// If deterministic serialization is requested, map entries will be sorted
// by keys in lexographical order. This is an implementation detail and
// subject to change.
func (p *Buffer) SetDeterministic(deterministic bool) {
p.deterministic = deterministic
}
/* /*
* Helper routines for simplifying the creation of optional fields of basic type. * Helper routines for simplifying the creation of optional fields of basic type.
*/ */
@ -831,22 +907,12 @@ func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMes
return sf, false, nil return sf, false, nil
} }
// mapKeys returns a sort.Interface to be used for sorting the map keys.
// Map fields may have key types of non-float scalars, strings and enums. // Map fields may have key types of non-float scalars, strings and enums.
// The easiest way to sort them in some deterministic order is to use fmt.
// If this turns out to be inefficient we can always consider other options,
// such as doing a Schwartzian transform.
func mapKeys(vs []reflect.Value) sort.Interface { func mapKeys(vs []reflect.Value) sort.Interface {
s := mapKeySorter{ s := mapKeySorter{vs: vs}
vs: vs,
// default Less function: textual comparison
less: func(a, b reflect.Value) bool {
return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface())
},
}
// Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps.
// numeric keys are sorted numerically.
if len(vs) == 0 { if len(vs) == 0 {
return s return s
} }
@ -855,6 +921,12 @@ func mapKeys(vs []reflect.Value) sort.Interface {
s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() }
case reflect.Uint32, reflect.Uint64: case reflect.Uint32, reflect.Uint64:
s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() }
case reflect.Bool:
s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true
case reflect.String:
s.less = func(a, b reflect.Value) bool { return a.String() < b.String() }
default:
panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind()))
} }
return s return s
@ -895,3 +967,13 @@ const ProtoPackageIsVersion2 = true
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files // ProtoPackageIsVersion1 is referenced from generated protocol buffer files
// to assert that that code is compatible with this version of the proto package. // to assert that that code is compatible with this version of the proto package.
const ProtoPackageIsVersion1 = true const ProtoPackageIsVersion1 = true
// InternalMessageInfo is a type used internally by generated .pb.go files.
// This type is not intended to be used by non-generated code.
// This type is not subject to any compatibility guarantee.
type InternalMessageInfo struct {
marshal *marshalInfo
unmarshal *unmarshalInfo
merge *mergeInfo
discard *discardInfo
}

View file

@ -42,6 +42,7 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"sort" "sort"
"sync"
) )
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. // errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
@ -94,10 +95,7 @@ func (ms *messageSet) find(pb Message) *_MessageSet_Item {
} }
func (ms *messageSet) Has(pb Message) bool { func (ms *messageSet) Has(pb Message) bool {
if ms.find(pb) != nil { return ms.find(pb) != nil
return true
}
return false
} }
func (ms *messageSet) Unmarshal(pb Message) error { func (ms *messageSet) Unmarshal(pb Message) error {
@ -150,46 +148,42 @@ func skipVarint(buf []byte) []byte {
// MarshalMessageSet encodes the extension map represented by m in the message set wire format. // MarshalMessageSet encodes the extension map represented by m in the message set wire format.
// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option. // It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
func MarshalMessageSet(exts interface{}) ([]byte, error) { func MarshalMessageSet(exts interface{}) ([]byte, error) {
var m map[int32]Extension return marshalMessageSet(exts, false)
}
// marshaMessageSet implements above function, with the opt to turn on / off deterministic during Marshal.
func marshalMessageSet(exts interface{}, deterministic bool) ([]byte, error) {
switch exts := exts.(type) { switch exts := exts.(type) {
case *XXX_InternalExtensions: case *XXX_InternalExtensions:
if err := encodeExtensions(exts); err != nil { var u marshalInfo
return nil, err siz := u.sizeMessageSet(exts)
} b := make([]byte, 0, siz)
m, _ = exts.extensionsRead() return u.appendMessageSet(b, exts, deterministic)
case map[int32]Extension: case map[int32]Extension:
if err := encodeExtensionsMap(exts); err != nil { // This is an old-style extension map.
return nil, err // Wrap it in a new-style XXX_InternalExtensions.
ie := XXX_InternalExtensions{
p: &struct {
mu sync.Mutex
extensionMap map[int32]Extension
}{
extensionMap: exts,
},
} }
m = exts
var u marshalInfo
siz := u.sizeMessageSet(&ie)
b := make([]byte, 0, siz)
return u.appendMessageSet(b, &ie, deterministic)
default: default:
return nil, errors.New("proto: not an extension map") return nil, errors.New("proto: not an extension map")
} }
// Sort extension IDs to provide a deterministic encoding.
// See also enc_map in encode.go.
ids := make([]int, 0, len(m))
for id := range m {
ids = append(ids, int(id))
}
sort.Ints(ids)
ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
for _, id := range ids {
e := m[int32(id)]
// Remove the wire type and field number varint, as well as the length varint.
msg := skipVarint(skipVarint(e.enc))
ms.Item = append(ms.Item, &_MessageSet_Item{
TypeId: Int32(int32(id)),
Message: msg,
})
}
return Marshal(ms)
} }
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. // UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option. // It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
func UnmarshalMessageSet(buf []byte, exts interface{}) error { func UnmarshalMessageSet(buf []byte, exts interface{}) error {
var m map[int32]Extension var m map[int32]Extension
switch exts := exts.(type) { switch exts := exts.(type) {
@ -235,7 +229,15 @@ func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
var m map[int32]Extension var m map[int32]Extension
switch exts := exts.(type) { switch exts := exts.(type) {
case *XXX_InternalExtensions: case *XXX_InternalExtensions:
m, _ = exts.extensionsRead() var mu sync.Locker
m, mu = exts.extensionsRead()
if m != nil {
// Keep the extensions map locked until we're done marshaling to prevent
// races between marshaling and unmarshaling the lazily-{en,de}coded
// values.
mu.Lock()
defer mu.Unlock()
}
case map[int32]Extension: case map[int32]Extension:
m = exts m = exts
default: default:
@ -253,15 +255,16 @@ func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
for i, id := range ids { for i, id := range ids {
ext := m[id] ext := m[id]
if i > 0 {
b.WriteByte(',')
}
msd, ok := messageSetMap[id] msd, ok := messageSetMap[id]
if !ok { if !ok {
// Unknown type; we can't render it, so skip it. // Unknown type; we can't render it, so skip it.
continue continue
} }
if i > 0 && b.Len() > 1 {
b.WriteByte(',')
}
fmt.Fprintf(&b, `"[%s]":`, msd.name) fmt.Fprintf(&b, `"[%s]":`, msd.name)
x := ext.value x := ext.value

View file

@ -29,7 +29,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// +build appengine js // +build purego appengine js
// This file contains an implementation of proto field accesses using package reflect. // This file contains an implementation of proto field accesses using package reflect.
// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can // It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can
@ -38,32 +38,13 @@
package proto package proto
import ( import (
"math"
"reflect" "reflect"
"sync"
) )
// A structPointer is a pointer to a struct. const unsafeAllowed = false
type structPointer struct {
v reflect.Value
}
// toStructPointer returns a structPointer equivalent to the given reflect value. // A field identifies a field in a struct, accessible from a pointer.
// The reflect value must itself be a pointer to a struct.
func toStructPointer(v reflect.Value) structPointer {
return structPointer{v}
}
// IsNil reports whether p is nil.
func structPointer_IsNil(p structPointer) bool {
return p.v.IsNil()
}
// Interface returns the struct pointer as an interface value.
func structPointer_Interface(p structPointer, _ reflect.Type) interface{} {
return p.v.Interface()
}
// A field identifies a field in a struct, accessible from a structPointer.
// In this implementation, a field is identified by the sequence of field indices // In this implementation, a field is identified by the sequence of field indices
// passed to reflect's FieldByIndex. // passed to reflect's FieldByIndex.
type field []int type field []int
@ -76,409 +57,301 @@ func toField(f *reflect.StructField) field {
// invalidField is an invalid field identifier. // invalidField is an invalid field identifier.
var invalidField = field(nil) var invalidField = field(nil)
// zeroField is a noop when calling pointer.offset.
var zeroField = field([]int{})
// IsValid reports whether the field identifier is valid. // IsValid reports whether the field identifier is valid.
func (f field) IsValid() bool { return f != nil } func (f field) IsValid() bool { return f != nil }
// field returns the given field in the struct as a reflect value. // The pointer type is for the table-driven decoder.
func structPointer_field(p structPointer, f field) reflect.Value { // The implementation here uses a reflect.Value of pointer type to
// Special case: an extension map entry with a value of type T // create a generic pointer. In pointer_unsafe.go we use unsafe
// passes a *T to the struct-handling code with a zero field, // instead of reflect to implement the same (but faster) interface.
// expecting that it will be treated as equivalent to *struct{ X T }, type pointer struct {
// which has the same memory layout. We have to handle that case
// specially, because reflect will panic if we call FieldByIndex on a
// non-struct.
if f == nil {
return p.v.Elem()
}
return p.v.Elem().FieldByIndex(f)
}
// ifield returns the given field in the struct as an interface value.
func structPointer_ifield(p structPointer, f field) interface{} {
return structPointer_field(p, f).Addr().Interface()
}
// Bytes returns the address of a []byte field in the struct.
func structPointer_Bytes(p structPointer, f field) *[]byte {
return structPointer_ifield(p, f).(*[]byte)
}
// BytesSlice returns the address of a [][]byte field in the struct.
func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
return structPointer_ifield(p, f).(*[][]byte)
}
// Bool returns the address of a *bool field in the struct.
func structPointer_Bool(p structPointer, f field) **bool {
return structPointer_ifield(p, f).(**bool)
}
// BoolVal returns the address of a bool field in the struct.
func structPointer_BoolVal(p structPointer, f field) *bool {
return structPointer_ifield(p, f).(*bool)
}
// BoolSlice returns the address of a []bool field in the struct.
func structPointer_BoolSlice(p structPointer, f field) *[]bool {
return structPointer_ifield(p, f).(*[]bool)
}
// String returns the address of a *string field in the struct.
func structPointer_String(p structPointer, f field) **string {
return structPointer_ifield(p, f).(**string)
}
// StringVal returns the address of a string field in the struct.
func structPointer_StringVal(p structPointer, f field) *string {
return structPointer_ifield(p, f).(*string)
}
// StringSlice returns the address of a []string field in the struct.
func structPointer_StringSlice(p structPointer, f field) *[]string {
return structPointer_ifield(p, f).(*[]string)
}
// Extensions returns the address of an extension map field in the struct.
func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions {
return structPointer_ifield(p, f).(*XXX_InternalExtensions)
}
// ExtMap returns the address of an extension map field in the struct.
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
return structPointer_ifield(p, f).(*map[int32]Extension)
}
// NewAt returns the reflect.Value for a pointer to a field in the struct.
func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value {
return structPointer_field(p, f).Addr()
}
// SetStructPointer writes a *struct field in the struct.
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
structPointer_field(p, f).Set(q.v)
}
// GetStructPointer reads a *struct field in the struct.
func structPointer_GetStructPointer(p structPointer, f field) structPointer {
return structPointer{structPointer_field(p, f)}
}
// StructPointerSlice the address of a []*struct field in the struct.
func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice {
return structPointerSlice{structPointer_field(p, f)}
}
// A structPointerSlice represents the address of a slice of pointers to structs
// (themselves messages or groups). That is, v.Type() is *[]*struct{...}.
type structPointerSlice struct {
v reflect.Value v reflect.Value
} }
func (p structPointerSlice) Len() int { return p.v.Len() } // toPointer converts an interface of pointer type to a pointer
func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} } // that points to the same target.
func (p structPointerSlice) Append(q structPointer) { func toPointer(i *Message) pointer {
p.v.Set(reflect.Append(p.v, q.v)) return pointer{v: reflect.ValueOf(*i)}
} }
var ( // toAddrPointer converts an interface to a pointer that points to
int32Type = reflect.TypeOf(int32(0)) // the interface data.
uint32Type = reflect.TypeOf(uint32(0)) func toAddrPointer(i *interface{}, isptr bool) pointer {
float32Type = reflect.TypeOf(float32(0)) v := reflect.ValueOf(*i)
int64Type = reflect.TypeOf(int64(0)) u := reflect.New(v.Type())
uint64Type = reflect.TypeOf(uint64(0)) u.Elem().Set(v)
float64Type = reflect.TypeOf(float64(0)) return pointer{v: u}
)
// A word32 represents a field of type *int32, *uint32, *float32, or *enum.
// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable.
type word32 struct {
v reflect.Value
} }
// IsNil reports whether p is nil. // valToPointer converts v to a pointer. v must be of pointer type.
func word32_IsNil(p word32) bool { func valToPointer(v reflect.Value) pointer {
return pointer{v: v}
}
// offset converts from a pointer to a structure to a pointer to
// one of its fields.
func (p pointer) offset(f field) pointer {
return pointer{v: p.v.Elem().FieldByIndex(f).Addr()}
}
func (p pointer) isNil() bool {
return p.v.IsNil() return p.v.IsNil()
} }
// Set sets p to point at a newly allocated word with bits set to x. // grow updates the slice s in place to make it one element longer.
func word32_Set(p word32, o *Buffer, x uint32) { // s must be addressable.
t := p.v.Type().Elem() // Returns the (addressable) new element.
switch t { func grow(s reflect.Value) reflect.Value {
case int32Type: n, m := s.Len(), s.Cap()
if len(o.int32s) == 0 {
o.int32s = make([]int32, uint32PoolSize)
}
o.int32s[0] = int32(x)
p.v.Set(reflect.ValueOf(&o.int32s[0]))
o.int32s = o.int32s[1:]
return
case uint32Type:
if len(o.uint32s) == 0 {
o.uint32s = make([]uint32, uint32PoolSize)
}
o.uint32s[0] = x
p.v.Set(reflect.ValueOf(&o.uint32s[0]))
o.uint32s = o.uint32s[1:]
return
case float32Type:
if len(o.float32s) == 0 {
o.float32s = make([]float32, uint32PoolSize)
}
o.float32s[0] = math.Float32frombits(x)
p.v.Set(reflect.ValueOf(&o.float32s[0]))
o.float32s = o.float32s[1:]
return
}
// must be enum
p.v.Set(reflect.New(t))
p.v.Elem().SetInt(int64(int32(x)))
}
// Get gets the bits pointed at by p, as a uint32.
func word32_Get(p word32) uint32 {
elem := p.v.Elem()
switch elem.Kind() {
case reflect.Int32:
return uint32(elem.Int())
case reflect.Uint32:
return uint32(elem.Uint())
case reflect.Float32:
return math.Float32bits(float32(elem.Float()))
}
panic("unreachable")
}
// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct.
func structPointer_Word32(p structPointer, f field) word32 {
return word32{structPointer_field(p, f)}
}
// A word32Val represents a field of type int32, uint32, float32, or enum.
// That is, v.Type() is int32, uint32, float32, or enum and v is assignable.
type word32Val struct {
v reflect.Value
}
// Set sets *p to x.
func word32Val_Set(p word32Val, x uint32) {
switch p.v.Type() {
case int32Type:
p.v.SetInt(int64(x))
return
case uint32Type:
p.v.SetUint(uint64(x))
return
case float32Type:
p.v.SetFloat(float64(math.Float32frombits(x)))
return
}
// must be enum
p.v.SetInt(int64(int32(x)))
}
// Get gets the bits pointed at by p, as a uint32.
func word32Val_Get(p word32Val) uint32 {
elem := p.v
switch elem.Kind() {
case reflect.Int32:
return uint32(elem.Int())
case reflect.Uint32:
return uint32(elem.Uint())
case reflect.Float32:
return math.Float32bits(float32(elem.Float()))
}
panic("unreachable")
}
// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct.
func structPointer_Word32Val(p structPointer, f field) word32Val {
return word32Val{structPointer_field(p, f)}
}
// A word32Slice is a slice of 32-bit values.
// That is, v.Type() is []int32, []uint32, []float32, or []enum.
type word32Slice struct {
v reflect.Value
}
func (p word32Slice) Append(x uint32) {
n, m := p.v.Len(), p.v.Cap()
if n < m { if n < m {
p.v.SetLen(n + 1) s.SetLen(n + 1)
} else { } else {
t := p.v.Type().Elem() s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem())))
p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
}
elem := p.v.Index(n)
switch elem.Kind() {
case reflect.Int32:
elem.SetInt(int64(int32(x)))
case reflect.Uint32:
elem.SetUint(uint64(x))
case reflect.Float32:
elem.SetFloat(float64(math.Float32frombits(x)))
} }
return s.Index(n)
} }
func (p word32Slice) Len() int { func (p pointer) toInt64() *int64 {
return p.v.Len() return p.v.Interface().(*int64)
}
func (p pointer) toInt64Ptr() **int64 {
return p.v.Interface().(**int64)
}
func (p pointer) toInt64Slice() *[]int64 {
return p.v.Interface().(*[]int64)
} }
func (p word32Slice) Index(i int) uint32 { var int32ptr = reflect.TypeOf((*int32)(nil))
elem := p.v.Index(i)
switch elem.Kind() { func (p pointer) toInt32() *int32 {
case reflect.Int32: return p.v.Convert(int32ptr).Interface().(*int32)
return uint32(elem.Int())
case reflect.Uint32:
return uint32(elem.Uint())
case reflect.Float32:
return math.Float32bits(float32(elem.Float()))
}
panic("unreachable")
} }
// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct. // The toInt32Ptr/Slice methods don't work because of enums.
func structPointer_Word32Slice(p structPointer, f field) word32Slice { // Instead, we must use set/get methods for the int32ptr/slice case.
return word32Slice{structPointer_field(p, f)} /*
func (p pointer) toInt32Ptr() **int32 {
return p.v.Interface().(**int32)
}
func (p pointer) toInt32Slice() *[]int32 {
return p.v.Interface().(*[]int32)
}
*/
func (p pointer) getInt32Ptr() *int32 {
if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) {
// raw int32 type
return p.v.Elem().Interface().(*int32)
}
// an enum
return p.v.Elem().Convert(int32PtrType).Interface().(*int32)
}
func (p pointer) setInt32Ptr(v int32) {
// Allocate value in a *int32. Possibly convert that to a *enum.
// Then assign it to a **int32 or **enum.
// Note: we can convert *int32 to *enum, but we can't convert
// **int32 to **enum!
p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem()))
} }
// word64 is like word32 but for 64-bit values. // getInt32Slice copies []int32 from p as a new slice.
type word64 struct { // This behavior differs from the implementation in pointer_unsafe.go.
v reflect.Value func (p pointer) getInt32Slice() []int32 {
if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) {
// raw int32 type
return p.v.Elem().Interface().([]int32)
}
// an enum
// Allocate a []int32, then assign []enum's values into it.
// Note: we can't convert []enum to []int32.
slice := p.v.Elem()
s := make([]int32, slice.Len())
for i := 0; i < slice.Len(); i++ {
s[i] = int32(slice.Index(i).Int())
}
return s
} }
func word64_Set(p word64, o *Buffer, x uint64) { // setInt32Slice copies []int32 into p as a new slice.
t := p.v.Type().Elem() // This behavior differs from the implementation in pointer_unsafe.go.
switch t { func (p pointer) setInt32Slice(v []int32) {
case int64Type: if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) {
if len(o.int64s) == 0 { // raw int32 type
o.int64s = make([]int64, uint64PoolSize) p.v.Elem().Set(reflect.ValueOf(v))
}
o.int64s[0] = int64(x)
p.v.Set(reflect.ValueOf(&o.int64s[0]))
o.int64s = o.int64s[1:]
return
case uint64Type:
if len(o.uint64s) == 0 {
o.uint64s = make([]uint64, uint64PoolSize)
}
o.uint64s[0] = x
p.v.Set(reflect.ValueOf(&o.uint64s[0]))
o.uint64s = o.uint64s[1:]
return
case float64Type:
if len(o.float64s) == 0 {
o.float64s = make([]float64, uint64PoolSize)
}
o.float64s[0] = math.Float64frombits(x)
p.v.Set(reflect.ValueOf(&o.float64s[0]))
o.float64s = o.float64s[1:]
return return
} }
panic("unreachable") // an enum
} // Allocate a []enum, then assign []int32's values into it.
// Note: we can't convert []enum to []int32.
func word64_IsNil(p word64) bool { slice := reflect.MakeSlice(p.v.Type().Elem(), len(v), cap(v))
return p.v.IsNil() for i, x := range v {
} slice.Index(i).SetInt(int64(x))
func word64_Get(p word64) uint64 {
elem := p.v.Elem()
switch elem.Kind() {
case reflect.Int64:
return uint64(elem.Int())
case reflect.Uint64:
return elem.Uint()
case reflect.Float64:
return math.Float64bits(elem.Float())
} }
panic("unreachable") p.v.Elem().Set(slice)
}
func (p pointer) appendInt32Slice(v int32) {
grow(p.v.Elem()).SetInt(int64(v))
} }
func structPointer_Word64(p structPointer, f field) word64 { func (p pointer) toUint64() *uint64 {
return word64{structPointer_field(p, f)} return p.v.Interface().(*uint64)
}
func (p pointer) toUint64Ptr() **uint64 {
return p.v.Interface().(**uint64)
}
func (p pointer) toUint64Slice() *[]uint64 {
return p.v.Interface().(*[]uint64)
}
func (p pointer) toUint32() *uint32 {
return p.v.Interface().(*uint32)
}
func (p pointer) toUint32Ptr() **uint32 {
return p.v.Interface().(**uint32)
}
func (p pointer) toUint32Slice() *[]uint32 {
return p.v.Interface().(*[]uint32)
}
func (p pointer) toBool() *bool {
return p.v.Interface().(*bool)
}
func (p pointer) toBoolPtr() **bool {
return p.v.Interface().(**bool)
}
func (p pointer) toBoolSlice() *[]bool {
return p.v.Interface().(*[]bool)
}
func (p pointer) toFloat64() *float64 {
return p.v.Interface().(*float64)
}
func (p pointer) toFloat64Ptr() **float64 {
return p.v.Interface().(**float64)
}
func (p pointer) toFloat64Slice() *[]float64 {
return p.v.Interface().(*[]float64)
}
func (p pointer) toFloat32() *float32 {
return p.v.Interface().(*float32)
}
func (p pointer) toFloat32Ptr() **float32 {
return p.v.Interface().(**float32)
}
func (p pointer) toFloat32Slice() *[]float32 {
return p.v.Interface().(*[]float32)
}
func (p pointer) toString() *string {
return p.v.Interface().(*string)
}
func (p pointer) toStringPtr() **string {
return p.v.Interface().(**string)
}
func (p pointer) toStringSlice() *[]string {
return p.v.Interface().(*[]string)
}
func (p pointer) toBytes() *[]byte {
return p.v.Interface().(*[]byte)
}
func (p pointer) toBytesSlice() *[][]byte {
return p.v.Interface().(*[][]byte)
}
func (p pointer) toExtensions() *XXX_InternalExtensions {
return p.v.Interface().(*XXX_InternalExtensions)
}
func (p pointer) toOldExtensions() *map[int32]Extension {
return p.v.Interface().(*map[int32]Extension)
}
func (p pointer) getPointer() pointer {
return pointer{v: p.v.Elem()}
}
func (p pointer) setPointer(q pointer) {
p.v.Elem().Set(q.v)
}
func (p pointer) appendPointer(q pointer) {
grow(p.v.Elem()).Set(q.v)
} }
// word64Val is like word32Val but for 64-bit values. // getPointerSlice copies []*T from p as a new []pointer.
type word64Val struct { // This behavior differs from the implementation in pointer_unsafe.go.
v reflect.Value func (p pointer) getPointerSlice() []pointer {
if p.v.IsNil() {
return nil
}
n := p.v.Elem().Len()
s := make([]pointer, n)
for i := 0; i < n; i++ {
s[i] = pointer{v: p.v.Elem().Index(i)}
}
return s
} }
func word64Val_Set(p word64Val, o *Buffer, x uint64) { // setPointerSlice copies []pointer into p as a new []*T.
switch p.v.Type() { // This behavior differs from the implementation in pointer_unsafe.go.
case int64Type: func (p pointer) setPointerSlice(v []pointer) {
p.v.SetInt(int64(x)) if v == nil {
return p.v.Elem().Set(reflect.New(p.v.Elem().Type()).Elem())
case uint64Type:
p.v.SetUint(x)
return
case float64Type:
p.v.SetFloat(math.Float64frombits(x))
return return
} }
panic("unreachable") s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v))
} for _, p := range v {
s = reflect.Append(s, p.v)
func word64Val_Get(p word64Val) uint64 {
elem := p.v
switch elem.Kind() {
case reflect.Int64:
return uint64(elem.Int())
case reflect.Uint64:
return elem.Uint()
case reflect.Float64:
return math.Float64bits(elem.Float())
} }
panic("unreachable") p.v.Elem().Set(s)
} }
func structPointer_Word64Val(p structPointer, f field) word64Val { // getInterfacePointer returns a pointer that points to the
return word64Val{structPointer_field(p, f)} // interface data of the interface pointed by p.
} func (p pointer) getInterfacePointer() pointer {
if p.v.Elem().IsNil() {
type word64Slice struct { return pointer{v: p.v.Elem()}
v reflect.Value
}
func (p word64Slice) Append(x uint64) {
n, m := p.v.Len(), p.v.Cap()
if n < m {
p.v.SetLen(n + 1)
} else {
t := p.v.Type().Elem()
p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
}
elem := p.v.Index(n)
switch elem.Kind() {
case reflect.Int64:
elem.SetInt(int64(int64(x)))
case reflect.Uint64:
elem.SetUint(uint64(x))
case reflect.Float64:
elem.SetFloat(float64(math.Float64frombits(x)))
} }
return pointer{v: p.v.Elem().Elem().Elem().Field(0).Addr()} // *interface -> interface -> *struct -> struct
} }
func (p word64Slice) Len() int { func (p pointer) asPointerTo(t reflect.Type) reflect.Value {
return p.v.Len() // TODO: check that p.v.Type().Elem() == t?
return p.v
} }
func (p word64Slice) Index(i int) uint64 { func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo {
elem := p.v.Index(i) atomicLock.Lock()
switch elem.Kind() { defer atomicLock.Unlock()
case reflect.Int64: return *p
return uint64(elem.Int()) }
case reflect.Uint64: func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) {
return uint64(elem.Uint()) atomicLock.Lock()
case reflect.Float64: defer atomicLock.Unlock()
return math.Float64bits(float64(elem.Float())) *p = v
} }
panic("unreachable") func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo {
atomicLock.Lock()
defer atomicLock.Unlock()
return *p
}
func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) {
atomicLock.Lock()
defer atomicLock.Unlock()
*p = v
}
func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo {
atomicLock.Lock()
defer atomicLock.Unlock()
return *p
}
func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) {
atomicLock.Lock()
defer atomicLock.Unlock()
*p = v
}
func atomicLoadDiscardInfo(p **discardInfo) *discardInfo {
atomicLock.Lock()
defer atomicLock.Unlock()
return *p
}
func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) {
atomicLock.Lock()
defer atomicLock.Unlock()
*p = v
} }
func structPointer_Word64Slice(p structPointer, f field) word64Slice { var atomicLock sync.Mutex
return word64Slice{structPointer_field(p, f)}
}

View file

@ -29,7 +29,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// +build !appengine,!js // +build !purego,!appengine,!js
// This file contains the implementation of the proto field accesses using package unsafe. // This file contains the implementation of the proto field accesses using package unsafe.
@ -37,38 +37,13 @@ package proto
import ( import (
"reflect" "reflect"
"sync/atomic"
"unsafe" "unsafe"
) )
// NOTE: These type_Foo functions would more idiomatically be methods, const unsafeAllowed = true
// but Go does not allow methods on pointer types, and we must preserve
// some pointer type for the garbage collector. We use these
// funcs with clunky names as our poor approximation to methods.
//
// An alternative would be
// type structPointer struct { p unsafe.Pointer }
// but that does not registerize as well.
// A structPointer is a pointer to a struct. // A field identifies a field in a struct, accessible from a pointer.
type structPointer unsafe.Pointer
// toStructPointer returns a structPointer equivalent to the given reflect value.
func toStructPointer(v reflect.Value) structPointer {
return structPointer(unsafe.Pointer(v.Pointer()))
}
// IsNil reports whether p is nil.
func structPointer_IsNil(p structPointer) bool {
return p == nil
}
// Interface returns the struct pointer, assumed to have element type t,
// as an interface value.
func structPointer_Interface(p structPointer, t reflect.Type) interface{} {
return reflect.NewAt(t, unsafe.Pointer(p)).Interface()
}
// A field identifies a field in a struct, accessible from a structPointer.
// In this implementation, a field is identified by its byte offset from the start of the struct. // In this implementation, a field is identified by its byte offset from the start of the struct.
type field uintptr type field uintptr
@ -80,191 +55,254 @@ func toField(f *reflect.StructField) field {
// invalidField is an invalid field identifier. // invalidField is an invalid field identifier.
const invalidField = ^field(0) const invalidField = ^field(0)
// zeroField is a noop when calling pointer.offset.
const zeroField = field(0)
// IsValid reports whether the field identifier is valid. // IsValid reports whether the field identifier is valid.
func (f field) IsValid() bool { func (f field) IsValid() bool {
return f != ^field(0) return f != invalidField
} }
// Bytes returns the address of a []byte field in the struct. // The pointer type below is for the new table-driven encoder/decoder.
func structPointer_Bytes(p structPointer, f field) *[]byte { // The implementation here uses unsafe.Pointer to create a generic pointer.
return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f))) // In pointer_reflect.go we use reflect instead of unsafe to implement
// the same (but slower) interface.
type pointer struct {
p unsafe.Pointer
} }
// BytesSlice returns the address of a [][]byte field in the struct. // size of pointer
func structPointer_BytesSlice(p structPointer, f field) *[][]byte { var ptrSize = unsafe.Sizeof(uintptr(0))
return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f)))
// toPointer converts an interface of pointer type to a pointer
// that points to the same target.
func toPointer(i *Message) pointer {
// Super-tricky - read pointer out of data word of interface value.
// Saves ~25ns over the equivalent:
// return valToPointer(reflect.ValueOf(*i))
return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
} }
// Bool returns the address of a *bool field in the struct. // toAddrPointer converts an interface to a pointer that points to
func structPointer_Bool(p structPointer, f field) **bool { // the interface data.
return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) func toAddrPointer(i *interface{}, isptr bool) pointer {
} // Super-tricky - read or get the address of data word of interface value.
if isptr {
// BoolVal returns the address of a bool field in the struct. // The interface is of pointer type, thus it is a direct interface.
func structPointer_BoolVal(p structPointer, f field) *bool { // The data word is the pointer data itself. We take its address.
return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f))) return pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)}
}
// BoolSlice returns the address of a []bool field in the struct.
func structPointer_BoolSlice(p structPointer, f field) *[]bool {
return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
}
// String returns the address of a *string field in the struct.
func structPointer_String(p structPointer, f field) **string {
return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
}
// StringVal returns the address of a string field in the struct.
func structPointer_StringVal(p structPointer, f field) *string {
return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
}
// StringSlice returns the address of a []string field in the struct.
func structPointer_StringSlice(p structPointer, f field) *[]string {
return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
}
// ExtMap returns the address of an extension map field in the struct.
func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions {
return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f)))
}
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f)))
}
// NewAt returns the reflect.Value for a pointer to a field in the struct.
func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value {
return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f)))
}
// SetStructPointer writes a *struct field in the struct.
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
*(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q
}
// GetStructPointer reads a *struct field in the struct.
func structPointer_GetStructPointer(p structPointer, f field) structPointer {
return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f)))
}
// StructPointerSlice the address of a []*struct field in the struct.
func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice {
return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
}
// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups).
type structPointerSlice []structPointer
func (v *structPointerSlice) Len() int { return len(*v) }
func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] }
func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) }
// A word32 is the address of a "pointer to 32-bit value" field.
type word32 **uint32
// IsNil reports whether *v is nil.
func word32_IsNil(p word32) bool {
return *p == nil
}
// Set sets *v to point at a newly allocated word set to x.
func word32_Set(p word32, o *Buffer, x uint32) {
if len(o.uint32s) == 0 {
o.uint32s = make([]uint32, uint32PoolSize)
} }
o.uint32s[0] = x // The interface is not of pointer type. The data word is the pointer
*p = &o.uint32s[0] // to the data.
o.uint32s = o.uint32s[1:] return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
} }
// Get gets the value pointed at by *v. // valToPointer converts v to a pointer. v must be of pointer type.
func word32_Get(p word32) uint32 { func valToPointer(v reflect.Value) pointer {
return **p return pointer{p: unsafe.Pointer(v.Pointer())}
} }
// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct. // offset converts from a pointer to a structure to a pointer to
func structPointer_Word32(p structPointer, f field) word32 { // one of its fields.
return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f)))) func (p pointer) offset(f field) pointer {
} // For safety, we should panic if !f.IsValid, however calling panic causes
// this to no longer be inlineable, which is a serious performance cost.
// A word32Val is the address of a 32-bit value field. /*
type word32Val *uint32 if !f.IsValid() {
panic("invalid field")
// Set sets *p to x.
func word32Val_Set(p word32Val, x uint32) {
*p = x
}
// Get gets the value pointed at by p.
func word32Val_Get(p word32Val) uint32 {
return *p
}
// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
func structPointer_Word32Val(p structPointer, f field) word32Val {
return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f))))
}
// A word32Slice is a slice of 32-bit values.
type word32Slice []uint32
func (v *word32Slice) Append(x uint32) { *v = append(*v, x) }
func (v *word32Slice) Len() int { return len(*v) }
func (v *word32Slice) Index(i int) uint32 { return (*v)[i] }
// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct.
func structPointer_Word32Slice(p structPointer, f field) *word32Slice {
return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
}
// word64 is like word32 but for 64-bit values.
type word64 **uint64
func word64_Set(p word64, o *Buffer, x uint64) {
if len(o.uint64s) == 0 {
o.uint64s = make([]uint64, uint64PoolSize)
} }
o.uint64s[0] = x */
*p = &o.uint64s[0] return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))}
o.uint64s = o.uint64s[1:]
} }
func word64_IsNil(p word64) bool { func (p pointer) isNil() bool {
return *p == nil return p.p == nil
} }
func word64_Get(p word64) uint64 { func (p pointer) toInt64() *int64 {
return **p return (*int64)(p.p)
}
func (p pointer) toInt64Ptr() **int64 {
return (**int64)(p.p)
}
func (p pointer) toInt64Slice() *[]int64 {
return (*[]int64)(p.p)
}
func (p pointer) toInt32() *int32 {
return (*int32)(p.p)
} }
func structPointer_Word64(p structPointer, f field) word64 { // See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist.
return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) /*
func (p pointer) toInt32Ptr() **int32 {
return (**int32)(p.p)
}
func (p pointer) toInt32Slice() *[]int32 {
return (*[]int32)(p.p)
}
*/
func (p pointer) getInt32Ptr() *int32 {
return *(**int32)(p.p)
}
func (p pointer) setInt32Ptr(v int32) {
*(**int32)(p.p) = &v
} }
// word64Val is like word32Val but for 64-bit values. // getInt32Slice loads a []int32 from p.
type word64Val *uint64 // The value returned is aliased with the original slice.
// This behavior differs from the implementation in pointer_reflect.go.
func word64Val_Set(p word64Val, o *Buffer, x uint64) { func (p pointer) getInt32Slice() []int32 {
*p = x return *(*[]int32)(p.p)
} }
func word64Val_Get(p word64Val) uint64 { // setInt32Slice stores a []int32 to p.
return *p // The value set is aliased with the input slice.
// This behavior differs from the implementation in pointer_reflect.go.
func (p pointer) setInt32Slice(v []int32) {
*(*[]int32)(p.p) = v
} }
func structPointer_Word64Val(p structPointer, f field) word64Val { // TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead?
return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) func (p pointer) appendInt32Slice(v int32) {
s := (*[]int32)(p.p)
*s = append(*s, v)
} }
// word64Slice is like word32Slice but for 64-bit values. func (p pointer) toUint64() *uint64 {
type word64Slice []uint64 return (*uint64)(p.p)
}
func (v *word64Slice) Append(x uint64) { *v = append(*v, x) } func (p pointer) toUint64Ptr() **uint64 {
func (v *word64Slice) Len() int { return len(*v) } return (**uint64)(p.p)
func (v *word64Slice) Index(i int) uint64 { return (*v)[i] } }
func (p pointer) toUint64Slice() *[]uint64 {
func structPointer_Word64Slice(p structPointer, f field) *word64Slice { return (*[]uint64)(p.p)
return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f))) }
func (p pointer) toUint32() *uint32 {
return (*uint32)(p.p)
}
func (p pointer) toUint32Ptr() **uint32 {
return (**uint32)(p.p)
}
func (p pointer) toUint32Slice() *[]uint32 {
return (*[]uint32)(p.p)
}
func (p pointer) toBool() *bool {
return (*bool)(p.p)
}
func (p pointer) toBoolPtr() **bool {
return (**bool)(p.p)
}
func (p pointer) toBoolSlice() *[]bool {
return (*[]bool)(p.p)
}
func (p pointer) toFloat64() *float64 {
return (*float64)(p.p)
}
func (p pointer) toFloat64Ptr() **float64 {
return (**float64)(p.p)
}
func (p pointer) toFloat64Slice() *[]float64 {
return (*[]float64)(p.p)
}
func (p pointer) toFloat32() *float32 {
return (*float32)(p.p)
}
func (p pointer) toFloat32Ptr() **float32 {
return (**float32)(p.p)
}
func (p pointer) toFloat32Slice() *[]float32 {
return (*[]float32)(p.p)
}
func (p pointer) toString() *string {
return (*string)(p.p)
}
func (p pointer) toStringPtr() **string {
return (**string)(p.p)
}
func (p pointer) toStringSlice() *[]string {
return (*[]string)(p.p)
}
func (p pointer) toBytes() *[]byte {
return (*[]byte)(p.p)
}
func (p pointer) toBytesSlice() *[][]byte {
return (*[][]byte)(p.p)
}
func (p pointer) toExtensions() *XXX_InternalExtensions {
return (*XXX_InternalExtensions)(p.p)
}
func (p pointer) toOldExtensions() *map[int32]Extension {
return (*map[int32]Extension)(p.p)
}
// getPointerSlice loads []*T from p as a []pointer.
// The value returned is aliased with the original slice.
// This behavior differs from the implementation in pointer_reflect.go.
func (p pointer) getPointerSlice() []pointer {
// Super-tricky - p should point to a []*T where T is a
// message type. We load it as []pointer.
return *(*[]pointer)(p.p)
}
// setPointerSlice stores []pointer into p as a []*T.
// The value set is aliased with the input slice.
// This behavior differs from the implementation in pointer_reflect.go.
func (p pointer) setPointerSlice(v []pointer) {
// Super-tricky - p should point to a []*T where T is a
// message type. We store it as []pointer.
*(*[]pointer)(p.p) = v
}
// getPointer loads the pointer at p and returns it.
func (p pointer) getPointer() pointer {
return pointer{p: *(*unsafe.Pointer)(p.p)}
}
// setPointer stores the pointer q at p.
func (p pointer) setPointer(q pointer) {
*(*unsafe.Pointer)(p.p) = q.p
}
// append q to the slice pointed to by p.
func (p pointer) appendPointer(q pointer) {
s := (*[]unsafe.Pointer)(p.p)
*s = append(*s, q.p)
}
// getInterfacePointer returns a pointer that points to the
// interface data of the interface pointed by p.
func (p pointer) getInterfacePointer() pointer {
// Super-tricky - read pointer out of data word of interface value.
return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]}
}
// asPointerTo returns a reflect.Value that is a pointer to an
// object of type t stored at p.
func (p pointer) asPointerTo(t reflect.Type) reflect.Value {
return reflect.NewAt(t, p.p)
}
func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo {
return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
}
func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) {
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
}
func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo {
return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
}
func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) {
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
}
func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo {
return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
}
func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) {
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
}
func atomicLoadDiscardInfo(p **discardInfo) *discardInfo {
return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
}
func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) {
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
} }

View file

@ -58,42 +58,6 @@ const (
WireFixed32 = 5 WireFixed32 = 5
) )
const startSize = 10 // initial slice/string sizes
// Encoders are defined in encode.go
// An encoder outputs the full representation of a field, including its
// tag and encoder type.
type encoder func(p *Buffer, prop *Properties, base structPointer) error
// A valueEncoder encodes a single integer in a particular encoding.
type valueEncoder func(o *Buffer, x uint64) error
// Sizers are defined in encode.go
// A sizer returns the encoded size of a field, including its tag and encoder
// type.
type sizer func(prop *Properties, base structPointer) int
// A valueSizer returns the encoded size of a single integer in a particular
// encoding.
type valueSizer func(x uint64) int
// Decoders are defined in decode.go
// A decoder creates a value from its wire representation.
// Unrecognized subelements are saved in unrec.
type decoder func(p *Buffer, prop *Properties, base structPointer) error
// A valueDecoder decodes a single integer in a particular encoding.
type valueDecoder func(o *Buffer) (x uint64, err error)
// A oneofMarshaler does the marshaling for all oneof fields in a message.
type oneofMarshaler func(Message, *Buffer) error
// A oneofUnmarshaler does the unmarshaling for a oneof field in a message.
type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error)
// A oneofSizer does the sizing for all oneof fields in a message.
type oneofSizer func(Message) int
// tagMap is an optimization over map[int]int for typical protocol buffer // tagMap is an optimization over map[int]int for typical protocol buffer
// use-cases. Encoded protocol buffers are often in tag order with small tag // use-cases. Encoded protocol buffers are often in tag order with small tag
// numbers. // numbers.
@ -140,13 +104,6 @@ type StructProperties struct {
decoderTags tagMap // map from proto tag to struct field number decoderTags tagMap // map from proto tag to struct field number
decoderOrigNames map[string]int // map from original name to struct field number decoderOrigNames map[string]int // map from original name to struct field number
order []int // list of struct field numbers in tag order order []int // list of struct field numbers in tag order
unrecField field // field id of the XXX_unrecognized []byte field
extendable bool // is this an extendable proto
oneofMarshaler oneofMarshaler
oneofUnmarshaler oneofUnmarshaler
oneofSizer oneofSizer
stype reflect.Type
// OneofTypes contains information about the oneof fields in this message. // OneofTypes contains information about the oneof fields in this message.
// It is keyed by the original name of a field. // It is keyed by the original name of a field.
@ -182,41 +139,24 @@ type Properties struct {
Repeated bool Repeated bool
Packed bool // relevant for repeated primitives only Packed bool // relevant for repeated primitives only
Enum string // set for enum types only Enum string // set for enum types only
proto3 bool // whether this is known to be a proto3 field; set for []byte only proto3 bool // whether this is known to be a proto3 field
oneof bool // whether this is a oneof field oneof bool // whether this is a oneof field
Default string // default value Default string // default value
HasDefault bool // whether an explicit default was provided HasDefault bool // whether an explicit default was provided
def_uint64 uint64
enc encoder
valEnc valueEncoder // set for bool and numeric types only
field field
tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
tagbuf [8]byte
stype reflect.Type // set for struct types only stype reflect.Type // set for struct types only
sprop *StructProperties // set for struct types only sprop *StructProperties // set for struct types only
isMarshaler bool
isUnmarshaler bool
mtype reflect.Type // set for map types only mtype reflect.Type // set for map types only
mkeyprop *Properties // set for map types only MapKeyProp *Properties // set for map types only
mvalprop *Properties // set for map types only MapValProp *Properties // set for map types only
size sizer
valSize valueSizer // set for bool and numeric types only
dec decoder
valDec valueDecoder // set for bool and numeric types only
// If this is a packable field, this will be the decoder for the packed version of the field.
packedDec decoder
} }
// String formats the properties in the protobuf struct field tag style. // String formats the properties in the protobuf struct field tag style.
func (p *Properties) String() string { func (p *Properties) String() string {
s := p.Wire s := p.Wire
s = "," s += ","
s += strconv.Itoa(p.Tag) s += strconv.Itoa(p.Tag)
if p.Required { if p.Required {
s += ",req" s += ",req"
@ -262,29 +202,14 @@ func (p *Properties) Parse(s string) {
switch p.Wire { switch p.Wire {
case "varint": case "varint":
p.WireType = WireVarint p.WireType = WireVarint
p.valEnc = (*Buffer).EncodeVarint
p.valDec = (*Buffer).DecodeVarint
p.valSize = sizeVarint
case "fixed32": case "fixed32":
p.WireType = WireFixed32 p.WireType = WireFixed32
p.valEnc = (*Buffer).EncodeFixed32
p.valDec = (*Buffer).DecodeFixed32
p.valSize = sizeFixed32
case "fixed64": case "fixed64":
p.WireType = WireFixed64 p.WireType = WireFixed64
p.valEnc = (*Buffer).EncodeFixed64
p.valDec = (*Buffer).DecodeFixed64
p.valSize = sizeFixed64
case "zigzag32": case "zigzag32":
p.WireType = WireVarint p.WireType = WireVarint
p.valEnc = (*Buffer).EncodeZigzag32
p.valDec = (*Buffer).DecodeZigzag32
p.valSize = sizeZigzag32
case "zigzag64": case "zigzag64":
p.WireType = WireVarint p.WireType = WireVarint
p.valEnc = (*Buffer).EncodeZigzag64
p.valDec = (*Buffer).DecodeZigzag64
p.valSize = sizeZigzag64
case "bytes", "group": case "bytes", "group":
p.WireType = WireBytes p.WireType = WireBytes
// no numeric converter for non-numeric types // no numeric converter for non-numeric types
@ -299,6 +224,7 @@ func (p *Properties) Parse(s string) {
return return
} }
outer:
for i := 2; i < len(fields); i++ { for i := 2; i < len(fields); i++ {
f := fields[i] f := fields[i]
switch { switch {
@ -326,256 +252,41 @@ func (p *Properties) Parse(s string) {
if i+1 < len(fields) { if i+1 < len(fields) {
// Commas aren't escaped, and def is always last. // Commas aren't escaped, and def is always last.
p.Default += "," + strings.Join(fields[i+1:], ",") p.Default += "," + strings.Join(fields[i+1:], ",")
break break outer
} }
} }
} }
} }
func logNoSliceEnc(t1, t2 reflect.Type) {
fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
}
var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
// Initialize the fields for encoding and decoding. // setFieldProps initializes the field properties for submessages and maps.
func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
p.enc = nil
p.dec = nil
p.size = nil
switch t1 := typ; t1.Kind() { switch t1 := typ; t1.Kind() {
default:
fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1)
// proto3 scalar types
case reflect.Bool:
p.enc = (*Buffer).enc_proto3_bool
p.dec = (*Buffer).dec_proto3_bool
p.size = size_proto3_bool
case reflect.Int32:
p.enc = (*Buffer).enc_proto3_int32
p.dec = (*Buffer).dec_proto3_int32
p.size = size_proto3_int32
case reflect.Uint32:
p.enc = (*Buffer).enc_proto3_uint32
p.dec = (*Buffer).dec_proto3_int32 // can reuse
p.size = size_proto3_uint32
case reflect.Int64, reflect.Uint64:
p.enc = (*Buffer).enc_proto3_int64
p.dec = (*Buffer).dec_proto3_int64
p.size = size_proto3_int64
case reflect.Float32:
p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits
p.dec = (*Buffer).dec_proto3_int32
p.size = size_proto3_uint32
case reflect.Float64:
p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits
p.dec = (*Buffer).dec_proto3_int64
p.size = size_proto3_int64
case reflect.String:
p.enc = (*Buffer).enc_proto3_string
p.dec = (*Buffer).dec_proto3_string
p.size = size_proto3_string
case reflect.Ptr: case reflect.Ptr:
switch t2 := t1.Elem(); t2.Kind() { if t1.Elem().Kind() == reflect.Struct {
default:
fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2)
break
case reflect.Bool:
p.enc = (*Buffer).enc_bool
p.dec = (*Buffer).dec_bool
p.size = size_bool
case reflect.Int32:
p.enc = (*Buffer).enc_int32
p.dec = (*Buffer).dec_int32
p.size = size_int32
case reflect.Uint32:
p.enc = (*Buffer).enc_uint32
p.dec = (*Buffer).dec_int32 // can reuse
p.size = size_uint32
case reflect.Int64, reflect.Uint64:
p.enc = (*Buffer).enc_int64
p.dec = (*Buffer).dec_int64
p.size = size_int64
case reflect.Float32:
p.enc = (*Buffer).enc_uint32 // can just treat them as bits
p.dec = (*Buffer).dec_int32
p.size = size_uint32
case reflect.Float64:
p.enc = (*Buffer).enc_int64 // can just treat them as bits
p.dec = (*Buffer).dec_int64
p.size = size_int64
case reflect.String:
p.enc = (*Buffer).enc_string
p.dec = (*Buffer).dec_string
p.size = size_string
case reflect.Struct:
p.stype = t1.Elem() p.stype = t1.Elem()
p.isMarshaler = isMarshaler(t1)
p.isUnmarshaler = isUnmarshaler(t1)
if p.Wire == "bytes" {
p.enc = (*Buffer).enc_struct_message
p.dec = (*Buffer).dec_struct_message
p.size = size_struct_message
} else {
p.enc = (*Buffer).enc_struct_group
p.dec = (*Buffer).dec_struct_group
p.size = size_struct_group
}
} }
case reflect.Slice: case reflect.Slice:
switch t2 := t1.Elem(); t2.Kind() { if t2 := t1.Elem(); t2.Kind() == reflect.Ptr && t2.Elem().Kind() == reflect.Struct {
default:
logNoSliceEnc(t1, t2)
break
case reflect.Bool:
if p.Packed {
p.enc = (*Buffer).enc_slice_packed_bool
p.size = size_slice_packed_bool
} else {
p.enc = (*Buffer).enc_slice_bool
p.size = size_slice_bool
}
p.dec = (*Buffer).dec_slice_bool
p.packedDec = (*Buffer).dec_slice_packed_bool
case reflect.Int32:
if p.Packed {
p.enc = (*Buffer).enc_slice_packed_int32
p.size = size_slice_packed_int32
} else {
p.enc = (*Buffer).enc_slice_int32
p.size = size_slice_int32
}
p.dec = (*Buffer).dec_slice_int32
p.packedDec = (*Buffer).dec_slice_packed_int32
case reflect.Uint32:
if p.Packed {
p.enc = (*Buffer).enc_slice_packed_uint32
p.size = size_slice_packed_uint32
} else {
p.enc = (*Buffer).enc_slice_uint32
p.size = size_slice_uint32
}
p.dec = (*Buffer).dec_slice_int32
p.packedDec = (*Buffer).dec_slice_packed_int32
case reflect.Int64, reflect.Uint64:
if p.Packed {
p.enc = (*Buffer).enc_slice_packed_int64
p.size = size_slice_packed_int64
} else {
p.enc = (*Buffer).enc_slice_int64
p.size = size_slice_int64
}
p.dec = (*Buffer).dec_slice_int64
p.packedDec = (*Buffer).dec_slice_packed_int64
case reflect.Uint8:
p.dec = (*Buffer).dec_slice_byte
if p.proto3 {
p.enc = (*Buffer).enc_proto3_slice_byte
p.size = size_proto3_slice_byte
} else {
p.enc = (*Buffer).enc_slice_byte
p.size = size_slice_byte
}
case reflect.Float32, reflect.Float64:
switch t2.Bits() {
case 32:
// can just treat them as bits
if p.Packed {
p.enc = (*Buffer).enc_slice_packed_uint32
p.size = size_slice_packed_uint32
} else {
p.enc = (*Buffer).enc_slice_uint32
p.size = size_slice_uint32
}
p.dec = (*Buffer).dec_slice_int32
p.packedDec = (*Buffer).dec_slice_packed_int32
case 64:
// can just treat them as bits
if p.Packed {
p.enc = (*Buffer).enc_slice_packed_int64
p.size = size_slice_packed_int64
} else {
p.enc = (*Buffer).enc_slice_int64
p.size = size_slice_int64
}
p.dec = (*Buffer).dec_slice_int64
p.packedDec = (*Buffer).dec_slice_packed_int64
default:
logNoSliceEnc(t1, t2)
break
}
case reflect.String:
p.enc = (*Buffer).enc_slice_string
p.dec = (*Buffer).dec_slice_string
p.size = size_slice_string
case reflect.Ptr:
switch t3 := t2.Elem(); t3.Kind() {
default:
fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
break
case reflect.Struct:
p.stype = t2.Elem() p.stype = t2.Elem()
p.isMarshaler = isMarshaler(t2)
p.isUnmarshaler = isUnmarshaler(t2)
if p.Wire == "bytes" {
p.enc = (*Buffer).enc_slice_struct_message
p.dec = (*Buffer).dec_slice_struct_message
p.size = size_slice_struct_message
} else {
p.enc = (*Buffer).enc_slice_struct_group
p.dec = (*Buffer).dec_slice_struct_group
p.size = size_slice_struct_group
}
}
case reflect.Slice:
switch t2.Elem().Kind() {
default:
fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem())
break
case reflect.Uint8:
p.enc = (*Buffer).enc_slice_slice_byte
p.dec = (*Buffer).dec_slice_slice_byte
p.size = size_slice_slice_byte
}
} }
case reflect.Map: case reflect.Map:
p.enc = (*Buffer).enc_new_map
p.dec = (*Buffer).dec_new_map
p.size = size_new_map
p.mtype = t1 p.mtype = t1
p.mkeyprop = &Properties{} p.MapKeyProp = &Properties{}
p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
p.mvalprop = &Properties{} p.MapValProp = &Properties{}
vtype := p.mtype.Elem() vtype := p.mtype.Elem()
if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
// The value type is not a message (*T) or bytes ([]byte), // The value type is not a message (*T) or bytes ([]byte),
// so we need encoders for the pointer to this type. // so we need encoders for the pointer to this type.
vtype = reflect.PtrTo(vtype) vtype = reflect.PtrTo(vtype)
} }
p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
} }
// precalculate tag code
wire := p.WireType
if p.Packed {
wire = WireBytes
}
x := uint32(p.Tag)<<3 | uint32(wire)
i := 0
for i = 0; x > 127; i++ {
p.tagbuf[i] = 0x80 | uint8(x&0x7F)
x >>= 7
}
p.tagbuf[i] = uint8(x)
p.tagcode = p.tagbuf[0 : i+1]
if p.stype != nil { if p.stype != nil {
if lockGetProp { if lockGetProp {
p.sprop = GetProperties(p.stype) p.sprop = GetProperties(p.stype)
@ -587,31 +298,8 @@ func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lock
var ( var (
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
) )
// isMarshaler reports whether type t implements Marshaler.
func isMarshaler(t reflect.Type) bool {
// We're checking for (likely) pointer-receiver methods
// so if t is not a pointer, something is very wrong.
// The calls above only invoke isMarshaler on pointer types.
if t.Kind() != reflect.Ptr {
panic("proto: misuse of isMarshaler")
}
return t.Implements(marshalerType)
}
// isUnmarshaler reports whether type t implements Unmarshaler.
func isUnmarshaler(t reflect.Type) bool {
// We're checking for (likely) pointer-receiver methods
// so if t is not a pointer, something is very wrong.
// The calls above only invoke isUnmarshaler on pointer types.
if t.Kind() != reflect.Ptr {
panic("proto: misuse of isUnmarshaler")
}
return t.Implements(unmarshalerType)
}
// Init populates the properties from a protocol buffer struct tag. // Init populates the properties from a protocol buffer struct tag.
func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
p.init(typ, name, tag, f, true) p.init(typ, name, tag, f, true)
@ -621,14 +309,11 @@ func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructF
// "bytes,49,opt,def=hello!" // "bytes,49,opt,def=hello!"
p.Name = name p.Name = name
p.OrigName = name p.OrigName = name
if f != nil {
p.field = toField(f)
}
if tag == "" { if tag == "" {
return return
} }
p.Parse(tag) p.Parse(tag)
p.setEncAndDec(typ, f, lockGetProp) p.setFieldProps(typ, f, lockGetProp)
} }
var ( var (
@ -678,9 +363,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
propertiesMap[t] = prop propertiesMap[t] = prop
// build properties // build properties
prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) ||
reflect.PtrTo(t).Implements(extendableProtoV1Type)
prop.unrecField = invalidField
prop.Prop = make([]*Properties, t.NumField()) prop.Prop = make([]*Properties, t.NumField())
prop.order = make([]int, t.NumField()) prop.order = make([]int, t.NumField())
@ -690,17 +372,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
name := f.Name name := f.Name
p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
if f.Name == "XXX_InternalExtensions" { // special case
p.enc = (*Buffer).enc_exts
p.dec = nil // not needed
p.size = size_exts
} else if f.Name == "XXX_extensions" { // special case
p.enc = (*Buffer).enc_map
p.dec = nil // not needed
p.size = size_map
} else if f.Name == "XXX_unrecognized" { // special case
prop.unrecField = toField(&f)
}
oneof := f.Tag.Get("protobuf_oneof") // special case oneof := f.Tag.Get("protobuf_oneof") // special case
if oneof != "" { if oneof != "" {
// Oneof fields don't use the traditional protobuf tag. // Oneof fields don't use the traditional protobuf tag.
@ -715,9 +386,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
} }
print("\n") print("\n")
} }
if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" {
fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
}
} }
// Re-order prop.order. // Re-order prop.order.
@ -728,8 +396,7 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
} }
if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
var oots []interface{} var oots []interface{}
prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() _, _, _, oots = om.XXX_OneofFuncs()
prop.stype = t
// Interpret oneof metadata. // Interpret oneof metadata.
prop.OneofTypes = make(map[string]*OneofProperties) prop.OneofTypes = make(map[string]*OneofProperties)
@ -779,30 +446,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
return prop return prop
} }
// Return the Properties object for the x[0]'th field of the structure.
func propByIndex(t reflect.Type, x []int) *Properties {
if len(x) != 1 {
fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
return nil
}
prop := GetProperties(t)
return prop.Prop[x[0]]
}
// Get the address and type of a pointer to a struct from an interface.
func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
if pb == nil {
err = ErrNil
return
}
// get the reflect type of the pointer to the struct.
t = reflect.TypeOf(pb)
// get the address of the struct.
value := reflect.ValueOf(pb)
b = toStructPointer(value)
return
}
// A global registry of enum types. // A global registry of enum types.
// The generated code will register the generated maps by calling RegisterEnum. // The generated code will register the generated maps by calling RegisterEnum.
@ -826,20 +469,42 @@ func EnumValueMap(enumType string) map[string]int32 {
// A registry of all linked message types. // A registry of all linked message types.
// The string is a fully-qualified proto name ("pkg.Message"). // The string is a fully-qualified proto name ("pkg.Message").
var ( var (
protoTypes = make(map[string]reflect.Type) protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers
protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types
revProtoTypes = make(map[reflect.Type]string) revProtoTypes = make(map[reflect.Type]string)
) )
// RegisterType is called from generated code and maps from the fully qualified // RegisterType is called from generated code and maps from the fully qualified
// proto name to the type (pointer to struct) of the protocol buffer. // proto name to the type (pointer to struct) of the protocol buffer.
func RegisterType(x Message, name string) { func RegisterType(x Message, name string) {
if _, ok := protoTypes[name]; ok { if _, ok := protoTypedNils[name]; ok {
// TODO: Some day, make this a panic. // TODO: Some day, make this a panic.
log.Printf("proto: duplicate proto type registered: %s", name) log.Printf("proto: duplicate proto type registered: %s", name)
return return
} }
t := reflect.TypeOf(x) t := reflect.TypeOf(x)
protoTypes[name] = t if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 {
// Generated code always calls RegisterType with nil x.
// This check is just for extra safety.
protoTypedNils[name] = x
} else {
protoTypedNils[name] = reflect.Zero(t).Interface().(Message)
}
revProtoTypes[t] = name
}
// RegisterMapType is called from generated code and maps from the fully qualified
// proto name to the native map type of the proto map definition.
func RegisterMapType(x interface{}, name string) {
if reflect.TypeOf(x).Kind() != reflect.Map {
panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name))
}
if _, ok := protoMapTypes[name]; ok {
log.Printf("proto: duplicate proto type registered: %s", name)
return
}
t := reflect.TypeOf(x)
protoMapTypes[name] = t
revProtoTypes[t] = name revProtoTypes[t] = name
} }
@ -855,7 +520,14 @@ func MessageName(x Message) string {
} }
// MessageType returns the message type (pointer to struct) for a named message. // MessageType returns the message type (pointer to struct) for a named message.
func MessageType(name string) reflect.Type { return protoTypes[name] } // The type is not guaranteed to implement proto.Message if the name refers to a
// map entry.
func MessageType(name string) reflect.Type {
if t, ok := protoTypedNils[name]; ok {
return reflect.TypeOf(t)
}
return protoMapTypes[name]
}
// A registry of all linked proto files. // A registry of all linked proto files.
var ( var (

2767
vendor/github.com/golang/protobuf/proto/table_marshal.go generated vendored Normal file

File diff suppressed because it is too large Load diff

654
vendor/github.com/golang/protobuf/proto/table_merge.go generated vendored Normal file
View file

@ -0,0 +1,654 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
import (
"fmt"
"reflect"
"strings"
"sync"
"sync/atomic"
)
// Merge merges the src message into dst.
// This assumes that dst and src of the same type and are non-nil.
func (a *InternalMessageInfo) Merge(dst, src Message) {
mi := atomicLoadMergeInfo(&a.merge)
if mi == nil {
mi = getMergeInfo(reflect.TypeOf(dst).Elem())
atomicStoreMergeInfo(&a.merge, mi)
}
mi.merge(toPointer(&dst), toPointer(&src))
}
type mergeInfo struct {
typ reflect.Type
initialized int32 // 0: only typ is valid, 1: everything is valid
lock sync.Mutex
fields []mergeFieldInfo
unrecognized field // Offset of XXX_unrecognized
}
type mergeFieldInfo struct {
field field // Offset of field, guaranteed to be valid
// isPointer reports whether the value in the field is a pointer.
// This is true for the following situations:
// * Pointer to struct
// * Pointer to basic type (proto2 only)
// * Slice (first value in slice header is a pointer)
// * String (first value in string header is a pointer)
isPointer bool
// basicWidth reports the width of the field assuming that it is directly
// embedded in the struct (as is the case for basic types in proto3).
// The possible values are:
// 0: invalid
// 1: bool
// 4: int32, uint32, float32
// 8: int64, uint64, float64
basicWidth int
// Where dst and src are pointers to the types being merged.
merge func(dst, src pointer)
}
var (
mergeInfoMap = map[reflect.Type]*mergeInfo{}
mergeInfoLock sync.Mutex
)
func getMergeInfo(t reflect.Type) *mergeInfo {
mergeInfoLock.Lock()
defer mergeInfoLock.Unlock()
mi := mergeInfoMap[t]
if mi == nil {
mi = &mergeInfo{typ: t}
mergeInfoMap[t] = mi
}
return mi
}
// merge merges src into dst assuming they are both of type *mi.typ.
func (mi *mergeInfo) merge(dst, src pointer) {
if dst.isNil() {
panic("proto: nil destination")
}
if src.isNil() {
return // Nothing to do.
}
if atomic.LoadInt32(&mi.initialized) == 0 {
mi.computeMergeInfo()
}
for _, fi := range mi.fields {
sfp := src.offset(fi.field)
// As an optimization, we can avoid the merge function call cost
// if we know for sure that the source will have no effect
// by checking if it is the zero value.
if unsafeAllowed {
if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string
continue
}
if fi.basicWidth > 0 {
switch {
case fi.basicWidth == 1 && !*sfp.toBool():
continue
case fi.basicWidth == 4 && *sfp.toUint32() == 0:
continue
case fi.basicWidth == 8 && *sfp.toUint64() == 0:
continue
}
}
}
dfp := dst.offset(fi.field)
fi.merge(dfp, sfp)
}
// TODO: Make this faster?
out := dst.asPointerTo(mi.typ).Elem()
in := src.asPointerTo(mi.typ).Elem()
if emIn, err := extendable(in.Addr().Interface()); err == nil {
emOut, _ := extendable(out.Addr().Interface())
mIn, muIn := emIn.extensionsRead()
if mIn != nil {
mOut := emOut.extensionsWrite()
muIn.Lock()
mergeExtension(mOut, mIn)
muIn.Unlock()
}
}
if mi.unrecognized.IsValid() {
if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 {
*dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...)
}
}
}
func (mi *mergeInfo) computeMergeInfo() {
mi.lock.Lock()
defer mi.lock.Unlock()
if mi.initialized != 0 {
return
}
t := mi.typ
n := t.NumField()
props := GetProperties(t)
for i := 0; i < n; i++ {
f := t.Field(i)
if strings.HasPrefix(f.Name, "XXX_") {
continue
}
mfi := mergeFieldInfo{field: toField(&f)}
tf := f.Type
// As an optimization, we can avoid the merge function call cost
// if we know for sure that the source will have no effect
// by checking if it is the zero value.
if unsafeAllowed {
switch tf.Kind() {
case reflect.Ptr, reflect.Slice, reflect.String:
// As a special case, we assume slices and strings are pointers
// since we know that the first field in the SliceSlice or
// StringHeader is a data pointer.
mfi.isPointer = true
case reflect.Bool:
mfi.basicWidth = 1
case reflect.Int32, reflect.Uint32, reflect.Float32:
mfi.basicWidth = 4
case reflect.Int64, reflect.Uint64, reflect.Float64:
mfi.basicWidth = 8
}
}
// Unwrap tf to get at its most basic type.
var isPointer, isSlice bool
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
isSlice = true
tf = tf.Elem()
}
if tf.Kind() == reflect.Ptr {
isPointer = true
tf = tf.Elem()
}
if isPointer && isSlice && tf.Kind() != reflect.Struct {
panic("both pointer and slice for basic type in " + tf.Name())
}
switch tf.Kind() {
case reflect.Int32:
switch {
case isSlice: // E.g., []int32
mfi.merge = func(dst, src pointer) {
// NOTE: toInt32Slice is not defined (see pointer_reflect.go).
/*
sfsp := src.toInt32Slice()
if *sfsp != nil {
dfsp := dst.toInt32Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []int64{}
}
}
*/
sfs := src.getInt32Slice()
if sfs != nil {
dfs := dst.getInt32Slice()
dfs = append(dfs, sfs...)
if dfs == nil {
dfs = []int32{}
}
dst.setInt32Slice(dfs)
}
}
case isPointer: // E.g., *int32
mfi.merge = func(dst, src pointer) {
// NOTE: toInt32Ptr is not defined (see pointer_reflect.go).
/*
sfpp := src.toInt32Ptr()
if *sfpp != nil {
dfpp := dst.toInt32Ptr()
if *dfpp == nil {
*dfpp = Int32(**sfpp)
} else {
**dfpp = **sfpp
}
}
*/
sfp := src.getInt32Ptr()
if sfp != nil {
dfp := dst.getInt32Ptr()
if dfp == nil {
dst.setInt32Ptr(*sfp)
} else {
*dfp = *sfp
}
}
}
default: // E.g., int32
mfi.merge = func(dst, src pointer) {
if v := *src.toInt32(); v != 0 {
*dst.toInt32() = v
}
}
}
case reflect.Int64:
switch {
case isSlice: // E.g., []int64
mfi.merge = func(dst, src pointer) {
sfsp := src.toInt64Slice()
if *sfsp != nil {
dfsp := dst.toInt64Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []int64{}
}
}
}
case isPointer: // E.g., *int64
mfi.merge = func(dst, src pointer) {
sfpp := src.toInt64Ptr()
if *sfpp != nil {
dfpp := dst.toInt64Ptr()
if *dfpp == nil {
*dfpp = Int64(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., int64
mfi.merge = func(dst, src pointer) {
if v := *src.toInt64(); v != 0 {
*dst.toInt64() = v
}
}
}
case reflect.Uint32:
switch {
case isSlice: // E.g., []uint32
mfi.merge = func(dst, src pointer) {
sfsp := src.toUint32Slice()
if *sfsp != nil {
dfsp := dst.toUint32Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []uint32{}
}
}
}
case isPointer: // E.g., *uint32
mfi.merge = func(dst, src pointer) {
sfpp := src.toUint32Ptr()
if *sfpp != nil {
dfpp := dst.toUint32Ptr()
if *dfpp == nil {
*dfpp = Uint32(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., uint32
mfi.merge = func(dst, src pointer) {
if v := *src.toUint32(); v != 0 {
*dst.toUint32() = v
}
}
}
case reflect.Uint64:
switch {
case isSlice: // E.g., []uint64
mfi.merge = func(dst, src pointer) {
sfsp := src.toUint64Slice()
if *sfsp != nil {
dfsp := dst.toUint64Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []uint64{}
}
}
}
case isPointer: // E.g., *uint64
mfi.merge = func(dst, src pointer) {
sfpp := src.toUint64Ptr()
if *sfpp != nil {
dfpp := dst.toUint64Ptr()
if *dfpp == nil {
*dfpp = Uint64(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., uint64
mfi.merge = func(dst, src pointer) {
if v := *src.toUint64(); v != 0 {
*dst.toUint64() = v
}
}
}
case reflect.Float32:
switch {
case isSlice: // E.g., []float32
mfi.merge = func(dst, src pointer) {
sfsp := src.toFloat32Slice()
if *sfsp != nil {
dfsp := dst.toFloat32Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []float32{}
}
}
}
case isPointer: // E.g., *float32
mfi.merge = func(dst, src pointer) {
sfpp := src.toFloat32Ptr()
if *sfpp != nil {
dfpp := dst.toFloat32Ptr()
if *dfpp == nil {
*dfpp = Float32(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., float32
mfi.merge = func(dst, src pointer) {
if v := *src.toFloat32(); v != 0 {
*dst.toFloat32() = v
}
}
}
case reflect.Float64:
switch {
case isSlice: // E.g., []float64
mfi.merge = func(dst, src pointer) {
sfsp := src.toFloat64Slice()
if *sfsp != nil {
dfsp := dst.toFloat64Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []float64{}
}
}
}
case isPointer: // E.g., *float64
mfi.merge = func(dst, src pointer) {
sfpp := src.toFloat64Ptr()
if *sfpp != nil {
dfpp := dst.toFloat64Ptr()
if *dfpp == nil {
*dfpp = Float64(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., float64
mfi.merge = func(dst, src pointer) {
if v := *src.toFloat64(); v != 0 {
*dst.toFloat64() = v
}
}
}
case reflect.Bool:
switch {
case isSlice: // E.g., []bool
mfi.merge = func(dst, src pointer) {
sfsp := src.toBoolSlice()
if *sfsp != nil {
dfsp := dst.toBoolSlice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []bool{}
}
}
}
case isPointer: // E.g., *bool
mfi.merge = func(dst, src pointer) {
sfpp := src.toBoolPtr()
if *sfpp != nil {
dfpp := dst.toBoolPtr()
if *dfpp == nil {
*dfpp = Bool(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., bool
mfi.merge = func(dst, src pointer) {
if v := *src.toBool(); v {
*dst.toBool() = v
}
}
}
case reflect.String:
switch {
case isSlice: // E.g., []string
mfi.merge = func(dst, src pointer) {
sfsp := src.toStringSlice()
if *sfsp != nil {
dfsp := dst.toStringSlice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []string{}
}
}
}
case isPointer: // E.g., *string
mfi.merge = func(dst, src pointer) {
sfpp := src.toStringPtr()
if *sfpp != nil {
dfpp := dst.toStringPtr()
if *dfpp == nil {
*dfpp = String(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., string
mfi.merge = func(dst, src pointer) {
if v := *src.toString(); v != "" {
*dst.toString() = v
}
}
}
case reflect.Slice:
isProto3 := props.Prop[i].proto3
switch {
case isPointer:
panic("bad pointer in byte slice case in " + tf.Name())
case tf.Elem().Kind() != reflect.Uint8:
panic("bad element kind in byte slice case in " + tf.Name())
case isSlice: // E.g., [][]byte
mfi.merge = func(dst, src pointer) {
sbsp := src.toBytesSlice()
if *sbsp != nil {
dbsp := dst.toBytesSlice()
for _, sb := range *sbsp {
if sb == nil {
*dbsp = append(*dbsp, nil)
} else {
*dbsp = append(*dbsp, append([]byte{}, sb...))
}
}
if *dbsp == nil {
*dbsp = [][]byte{}
}
}
}
default: // E.g., []byte
mfi.merge = func(dst, src pointer) {
sbp := src.toBytes()
if *sbp != nil {
dbp := dst.toBytes()
if !isProto3 || len(*sbp) > 0 {
*dbp = append([]byte{}, *sbp...)
}
}
}
}
case reflect.Struct:
switch {
case !isPointer:
panic(fmt.Sprintf("message field %s without pointer", tf))
case isSlice: // E.g., []*pb.T
mi := getMergeInfo(tf)
mfi.merge = func(dst, src pointer) {
sps := src.getPointerSlice()
if sps != nil {
dps := dst.getPointerSlice()
for _, sp := range sps {
var dp pointer
if !sp.isNil() {
dp = valToPointer(reflect.New(tf))
mi.merge(dp, sp)
}
dps = append(dps, dp)
}
if dps == nil {
dps = []pointer{}
}
dst.setPointerSlice(dps)
}
}
default: // E.g., *pb.T
mi := getMergeInfo(tf)
mfi.merge = func(dst, src pointer) {
sp := src.getPointer()
if !sp.isNil() {
dp := dst.getPointer()
if dp.isNil() {
dp = valToPointer(reflect.New(tf))
dst.setPointer(dp)
}
mi.merge(dp, sp)
}
}
}
case reflect.Map:
switch {
case isPointer || isSlice:
panic("bad pointer or slice in map case in " + tf.Name())
default: // E.g., map[K]V
mfi.merge = func(dst, src pointer) {
sm := src.asPointerTo(tf).Elem()
if sm.Len() == 0 {
return
}
dm := dst.asPointerTo(tf).Elem()
if dm.IsNil() {
dm.Set(reflect.MakeMap(tf))
}
switch tf.Elem().Kind() {
case reflect.Ptr: // Proto struct (e.g., *T)
for _, key := range sm.MapKeys() {
val := sm.MapIndex(key)
val = reflect.ValueOf(Clone(val.Interface().(Message)))
dm.SetMapIndex(key, val)
}
case reflect.Slice: // E.g. Bytes type (e.g., []byte)
for _, key := range sm.MapKeys() {
val := sm.MapIndex(key)
val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
dm.SetMapIndex(key, val)
}
default: // Basic type (e.g., string)
for _, key := range sm.MapKeys() {
val := sm.MapIndex(key)
dm.SetMapIndex(key, val)
}
}
}
}
case reflect.Interface:
// Must be oneof field.
switch {
case isPointer || isSlice:
panic("bad pointer or slice in interface case in " + tf.Name())
default: // E.g., interface{}
// TODO: Make this faster?
mfi.merge = func(dst, src pointer) {
su := src.asPointerTo(tf).Elem()
if !su.IsNil() {
du := dst.asPointerTo(tf).Elem()
typ := su.Elem().Type()
if du.IsNil() || du.Elem().Type() != typ {
du.Set(reflect.New(typ.Elem())) // Initialize interface if empty
}
sv := su.Elem().Elem().Field(0)
if sv.Kind() == reflect.Ptr && sv.IsNil() {
return
}
dv := du.Elem().Elem().Field(0)
if dv.Kind() == reflect.Ptr && dv.IsNil() {
dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty
}
switch sv.Type().Kind() {
case reflect.Ptr: // Proto struct (e.g., *T)
Merge(dv.Interface().(Message), sv.Interface().(Message))
case reflect.Slice: // E.g. Bytes type (e.g., []byte)
dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...)))
default: // Basic type (e.g., string)
dv.Set(sv)
}
}
}
}
default:
panic(fmt.Sprintf("merger not found for type:%s", tf))
}
mi.fields = append(mi.fields, mfi)
}
mi.unrecognized = invalidField
if f, ok := t.FieldByName("XXX_unrecognized"); ok {
if f.Type != reflect.TypeOf([]byte{}) {
panic("expected XXX_unrecognized to be of type []byte")
}
mi.unrecognized = toField(&f)
}
atomic.StoreInt32(&mi.initialized, 1)
}

File diff suppressed because it is too large Load diff

View file

@ -50,7 +50,6 @@ import (
var ( var (
newline = []byte("\n") newline = []byte("\n")
spaces = []byte(" ") spaces = []byte(" ")
gtNewline = []byte(">\n")
endBraceNewline = []byte("}\n") endBraceNewline = []byte("}\n")
backslashN = []byte{'\\', 'n'} backslashN = []byte{'\\', 'n'}
backslashR = []byte{'\\', 'r'} backslashR = []byte{'\\', 'r'}
@ -170,11 +169,6 @@ func writeName(w *textWriter, props *Properties) error {
return nil return nil
} }
// raw is the interface satisfied by RawMessage.
type raw interface {
Bytes() []byte
}
func requiresQuotes(u string) bool { func requiresQuotes(u string) bool {
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
for _, ch := range u { for _, ch := range u {
@ -269,6 +263,10 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
props := sprops.Prop[i] props := sprops.Prop[i]
name := st.Field(i).Name name := st.Field(i).Name
if name == "XXX_NoUnkeyedLiteral" {
continue
}
if strings.HasPrefix(name, "XXX_") { if strings.HasPrefix(name, "XXX_") {
// There are two XXX_ fields: // There are two XXX_ fields:
// XXX_unrecognized []byte // XXX_unrecognized []byte
@ -355,7 +353,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
return err return err
} }
} }
if err := tm.writeAny(w, key, props.mkeyprop); err != nil { if err := tm.writeAny(w, key, props.MapKeyProp); err != nil {
return err return err
} }
if err := w.WriteByte('\n'); err != nil { if err := w.WriteByte('\n'); err != nil {
@ -372,7 +370,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
return err return err
} }
} }
if err := tm.writeAny(w, val, props.mvalprop); err != nil { if err := tm.writeAny(w, val, props.MapValProp); err != nil {
return err return err
} }
if err := w.WriteByte('\n'); err != nil { if err := w.WriteByte('\n'); err != nil {
@ -436,12 +434,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
return err return err
} }
} }
if b, ok := fv.Interface().(raw); ok {
if err := writeRaw(w, b.Bytes()); err != nil {
return err
}
continue
}
// Enums have a String method, so writeAny will work fine. // Enums have a String method, so writeAny will work fine.
if err := tm.writeAny(w, fv, props); err != nil { if err := tm.writeAny(w, fv, props); err != nil {
@ -455,7 +447,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
// Extensions (the XXX_extensions field). // Extensions (the XXX_extensions field).
pv := sv.Addr() pv := sv.Addr()
if _, ok := extendable(pv.Interface()); ok { if _, err := extendable(pv.Interface()); err == nil {
if err := tm.writeExtensions(w, pv); err != nil { if err := tm.writeExtensions(w, pv); err != nil {
return err return err
} }
@ -464,27 +456,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
return nil return nil
} }
// writeRaw writes an uninterpreted raw message.
func writeRaw(w *textWriter, b []byte) error {
if err := w.WriteByte('<'); err != nil {
return err
}
if !w.compact {
if err := w.WriteByte('\n'); err != nil {
return err
}
}
w.indent()
if err := writeUnknownStruct(w, b); err != nil {
return err
}
w.unindent()
if err := w.WriteByte('>'); err != nil {
return err
}
return nil
}
// writeAny writes an arbitrary field. // writeAny writes an arbitrary field.
func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {
v = reflect.Indirect(v) v = reflect.Indirect(v)
@ -535,6 +506,19 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert
} }
} }
w.indent() w.indent()
if v.CanAddr() {
// Calling v.Interface on a struct causes the reflect package to
// copy the entire struct. This is racy with the new Marshaler
// since we atomically update the XXX_sizecache.
//
// Thus, we retrieve a pointer to the struct if possible to avoid
// a race since v.Interface on the pointer doesn't copy the struct.
//
// If v is not addressable, then we are not worried about a race
// since it implies that the binary Marshaler cannot possibly be
// mutating this value.
v = v.Addr()
}
if etm, ok := v.Interface().(encoding.TextMarshaler); ok { if etm, ok := v.Interface().(encoding.TextMarshaler); ok {
text, err := etm.MarshalText() text, err := etm.MarshalText()
if err != nil { if err != nil {
@ -543,9 +527,14 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert
if _, err = w.Write(text); err != nil { if _, err = w.Write(text); err != nil {
return err return err
} }
} else if err := tm.writeStruct(w, v); err != nil { } else {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if err := tm.writeStruct(w, v); err != nil {
return err return err
} }
}
w.unindent() w.unindent()
if err := w.WriteByte(ket); err != nil { if err := w.WriteByte(ket); err != nil {
return err return err

View file

@ -206,7 +206,6 @@ func (p *textParser) advance() {
var ( var (
errBadUTF8 = errors.New("proto: bad UTF-8") errBadUTF8 = errors.New("proto: bad UTF-8")
errBadHex = errors.New("proto: bad hexadecimal")
) )
func unquoteC(s string, quote rune) (string, error) { func unquoteC(s string, quote rune) (string, error) {
@ -277,60 +276,47 @@ func unescape(s string) (ch string, tail string, err error) {
return "?", s, nil // trigraph workaround return "?", s, nil // trigraph workaround
case '\'', '"', '\\': case '\'', '"', '\\':
return string(r), s, nil return string(r), s, nil
case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': case '0', '1', '2', '3', '4', '5', '6', '7':
if len(s) < 2 { if len(s) < 2 {
return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
} }
base := 8 ss := string(r) + s[:2]
ss := s[:2]
s = s[2:] s = s[2:]
if r == 'x' || r == 'X' { i, err := strconv.ParseUint(ss, 8, 8)
base = 16
} else {
ss = string(r) + ss
}
i, err := strconv.ParseUint(ss, base, 8)
if err != nil { if err != nil {
return "", "", err return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss)
} }
return string([]byte{byte(i)}), s, nil return string([]byte{byte(i)}), s, nil
case 'u', 'U': case 'x', 'X', 'u', 'U':
n := 4 var n int
if r == 'U' { switch r {
case 'x', 'X':
n = 2
case 'u':
n = 4
case 'U':
n = 8 n = 8
} }
if len(s) < n { if len(s) < n {
return "", "", fmt.Errorf(`\%c requires %d digits`, r, n) return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n)
}
bs := make([]byte, n/2)
for i := 0; i < n; i += 2 {
a, ok1 := unhex(s[i])
b, ok2 := unhex(s[i+1])
if !ok1 || !ok2 {
return "", "", errBadHex
}
bs[i/2] = a<<4 | b
} }
ss := s[:n]
s = s[n:] s = s[n:]
return string(bs), s, nil i, err := strconv.ParseUint(ss, 16, 64)
if err != nil {
return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss)
}
if r == 'x' || r == 'X' {
return string([]byte{byte(i)}), s, nil
}
if i > utf8.MaxRune {
return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss)
}
return string(i), s, nil
} }
return "", "", fmt.Errorf(`unknown escape \%c`, r) return "", "", fmt.Errorf(`unknown escape \%c`, r)
} }
// Adapted from src/pkg/strconv/quote.go.
func unhex(b byte) (v byte, ok bool) {
switch {
case '0' <= b && b <= '9':
return b - '0', true
case 'a' <= b && b <= 'f':
return b - 'a' + 10, true
case 'A' <= b && b <= 'F':
return b - 'A' + 10, true
}
return 0, false
}
// Back off the parser by one token. Can only be done between calls to next(). // Back off the parser by one token. Can only be done between calls to next().
// It makes the next advance() a no-op. // It makes the next advance() a no-op.
func (p *textParser) back() { p.backed = true } func (p *textParser) back() { p.backed = true }
@ -644,17 +630,17 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
if err := p.consumeToken(":"); err != nil { if err := p.consumeToken(":"); err != nil {
return err return err
} }
if err := p.readAny(key, props.mkeyprop); err != nil { if err := p.readAny(key, props.MapKeyProp); err != nil {
return err return err
} }
if err := p.consumeOptionalSeparator(); err != nil { if err := p.consumeOptionalSeparator(); err != nil {
return err return err
} }
case "value": case "value":
if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil {
return err return err
} }
if err := p.readAny(val, props.mvalprop); err != nil { if err := p.readAny(val, props.MapValProp); err != nil {
return err return err
} }
if err := p.consumeOptionalSeparator(); err != nil { if err := p.consumeOptionalSeparator(); err != nil {
@ -728,6 +714,9 @@ func (p *textParser) consumeExtName() (string, error) {
if tok.err != nil { if tok.err != nil {
return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) return "", p.errorf("unrecognized type_url or extension name: %s", tok.err)
} }
if p.done && tok.value != "]" {
return "", p.errorf("unclosed type_url or extension name")
}
} }
return strings.Join(parts, ""), nil return strings.Join(parts, ""), nil
} }
@ -865,7 +854,7 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error {
return p.readStruct(fv, terminator) return p.readStruct(fv, terminator)
case reflect.Uint32: case reflect.Uint32:
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
fv.SetUint(x) fv.SetUint(uint64(x))
return nil return nil
} }
case reflect.Uint64: case reflect.Uint64:
@ -883,13 +872,9 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error {
// UnmarshalText returns *RequiredNotSetError. // UnmarshalText returns *RequiredNotSetError.
func UnmarshalText(s string, pb Message) error { func UnmarshalText(s string, pb Message) error {
if um, ok := pb.(encoding.TextUnmarshaler); ok { if um, ok := pb.(encoding.TextUnmarshaler); ok {
err := um.UnmarshalText([]byte(s)) return um.UnmarshalText([]byte(s))
return err
} }
pb.Reset() pb.Reset()
v := reflect.ValueOf(pb) v := reflect.ValueOf(pb)
if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { return newTextParser(s).readStruct(v.Elem(), "")
return pe
}
return nil
} }

View file

@ -40,6 +40,7 @@ Bryan Boreham <bryan@weave.works>
Cami Diez <diezcami@gmail.com> Cami Diez <diezcami@gmail.com>
Carlos Alexandro Becker <caarlos0@gmail.com> Carlos Alexandro Becker <caarlos0@gmail.com>
chandresh-pancholi <chandreshpancholi007@gmail.com> chandresh-pancholi <chandreshpancholi007@gmail.com>
Charles Fenwick Elliott <Charles@FenwickElliott.io>
Charlie Yan <charlieyan08@gmail.com> Charlie Yan <charlieyan08@gmail.com>
Chris King <chriskingnet@gmail.com> Chris King <chriskingnet@gmail.com>
Chris Roche <chris@vsco.co> Chris Roche <chris@vsco.co>
@ -133,6 +134,7 @@ Pierre Carrier <pierre@meteor.com>
Piotr Zurek <p.zurek@gmail.com> Piotr Zurek <p.zurek@gmail.com>
Quinn Slack <qslack@qslack.com> Quinn Slack <qslack@qslack.com>
Rackspace US, Inc. Rackspace US, Inc.
Rajendra arora <rajendraarora16@yahoo.com>
RaviTeja Pothana <ravi-teja@live.com> RaviTeja Pothana <ravi-teja@live.com>
rc1140 <jameel@republiccommandos.co.za> rc1140 <jameel@republiccommandos.co.za>
Red Hat, Inc. Red Hat, Inc.
@ -144,6 +146,7 @@ Sahil Dua <sahildua2305@gmail.com>
saisi <saisi@users.noreply.github.com> saisi <saisi@users.noreply.github.com>
Sam Minnée <sam@silverstripe.com> Sam Minnée <sam@silverstripe.com>
Sander van Harmelen <svanharmelen@schubergphilis.com> Sander van Harmelen <svanharmelen@schubergphilis.com>
Sanket Payghan <sanket.payghan8@gmail.com>
Sarasa Kisaragi <lingsamuelgrace@gmail.com> Sarasa Kisaragi <lingsamuelgrace@gmail.com>
Sean Wang <sean@decrypted.org> Sean Wang <sean@decrypted.org>
Sebastian Mandrean <sebastian.mandrean@gmail.com> Sebastian Mandrean <sebastian.mandrean@gmail.com>

View file

@ -25,317 +25,3 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------
Some documentation is taken from the GitHub Developer site
<https://developer.github.com/>, which is available under the following Creative
Commons Attribution 3.0 License. This applies only to the go-github source
code and would not apply to any compiled binaries.
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
CONDITIONS.
1. Definitions
a. "Adaptation" means a work based upon the Work, or upon the Work and
other pre-existing works, such as a translation, adaptation,
derivative work, arrangement of music or other alterations of a
literary or artistic work, or phonogram or performance and includes
cinematographic adaptations or any other form in which the Work may be
recast, transformed, or adapted including in any form recognizably
derived from the original, except that a work that constitutes a
Collection will not be considered an Adaptation for the purpose of
this License. For the avoidance of doubt, where the Work is a musical
work, performance or phonogram, the synchronization of the Work in
timed-relation with a moving image ("synching") will be considered an
Adaptation for the purpose of this License.
b. "Collection" means a collection of literary or artistic works, such as
encyclopedias and anthologies, or performances, phonograms or
broadcasts, or other works or subject matter other than works listed
in Section 1(f) below, which, by reason of the selection and
arrangement of their contents, constitute intellectual creations, in
which the Work is included in its entirety in unmodified form along
with one or more other contributions, each constituting separate and
independent works in themselves, which together are assembled into a
collective whole. A work that constitutes a Collection will not be
considered an Adaptation (as defined above) for the purposes of this
License.
c. "Distribute" means to make available to the public the original and
copies of the Work or Adaptation, as appropriate, through sale or
other transfer of ownership.
d. "Licensor" means the individual, individuals, entity or entities that
offer(s) the Work under the terms of this License.
e. "Original Author" means, in the case of a literary or artistic work,
the individual, individuals, entity or entities who created the Work
or if no individual or entity can be identified, the publisher; and in
addition (i) in the case of a performance the actors, singers,
musicians, dancers, and other persons who act, sing, deliver, declaim,
play in, interpret or otherwise perform literary or artistic works or
expressions of folklore; (ii) in the case of a phonogram the producer
being the person or legal entity who first fixes the sounds of a
performance or other sounds; and, (iii) in the case of broadcasts, the
organization that transmits the broadcast.
f. "Work" means the literary and/or artistic work offered under the terms
of this License including without limitation any production in the
literary, scientific and artistic domain, whatever may be the mode or
form of its expression including digital form, such as a book,
pamphlet and other writing; a lecture, address, sermon or other work
of the same nature; a dramatic or dramatico-musical work; a
choreographic work or entertainment in dumb show; a musical
composition with or without words; a cinematographic work to which are
assimilated works expressed by a process analogous to cinematography;
a work of drawing, painting, architecture, sculpture, engraving or
lithography; a photographic work to which are assimilated works
expressed by a process analogous to photography; a work of applied
art; an illustration, map, plan, sketch or three-dimensional work
relative to geography, topography, architecture or science; a
performance; a broadcast; a phonogram; a compilation of data to the
extent it is protected as a copyrightable work; or a work performed by
a variety or circus performer to the extent it is not otherwise
considered a literary or artistic work.
g. "You" means an individual or entity exercising rights under this
License who has not previously violated the terms of this License with
respect to the Work, or who has received express permission from the
Licensor to exercise rights under this License despite a previous
violation.
h. "Publicly Perform" means to perform public recitations of the Work and
to communicate to the public those public recitations, by any means or
process, including by wire or wireless means or public digital
performances; to make available to the public Works in such a way that
members of the public may access these Works from a place and at a
place individually chosen by them; to perform the Work to the public
by any means or process and the communication to the public of the
performances of the Work, including by public digital performance; to
broadcast and rebroadcast the Work by any means including signs,
sounds or images.
i. "Reproduce" means to make copies of the Work by any means including
without limitation by sound or visual recordings and the right of
fixation and reproducing fixations of the Work, including storage of a
protected performance or phonogram in digital form or other electronic
medium.
2. Fair Dealing Rights. Nothing in this License is intended to reduce,
limit, or restrict any uses free from copyright or rights arising from
limitations or exceptions that are provided for in connection with the
copyright protection under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License,
Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
perpetual (for the duration of the applicable copyright) license to
exercise the rights in the Work as stated below:
a. to Reproduce the Work, to incorporate the Work into one or more
Collections, and to Reproduce the Work as incorporated in the
Collections;
b. to create and Reproduce Adaptations provided that any such Adaptation,
including any translation in any medium, takes reasonable steps to
clearly label, demarcate or otherwise identify that changes were made
to the original Work. For example, a translation could be marked "The
original work was translated from English to Spanish," or a
modification could indicate "The original work has been modified.";
c. to Distribute and Publicly Perform the Work including as incorporated
in Collections; and,
d. to Distribute and Publicly Perform Adaptations.
e. For the avoidance of doubt:
i. Non-waivable Compulsory License Schemes. In those jurisdictions in
which the right to collect royalties through any statutory or
compulsory licensing scheme cannot be waived, the Licensor
reserves the exclusive right to collect such royalties for any
exercise by You of the rights granted under this License;
ii. Waivable Compulsory License Schemes. In those jurisdictions in
which the right to collect royalties through any statutory or
compulsory licensing scheme can be waived, the Licensor waives the
exclusive right to collect such royalties for any exercise by You
of the rights granted under this License; and,
iii. Voluntary License Schemes. The Licensor waives the right to
collect royalties, whether individually or, in the event that the
Licensor is a member of a collecting society that administers
voluntary licensing schemes, via that society, from any exercise
by You of the rights granted under this License.
The above rights may be exercised in all media and formats whether now
known or hereafter devised. The above rights include the right to make
such modifications as are technically necessary to exercise the rights in
other media and formats. Subject to Section 8(f), all rights not expressly
granted by Licensor are hereby reserved.
4. Restrictions. The license granted in Section 3 above is expressly made
subject to and limited by the following restrictions:
a. You may Distribute or Publicly Perform the Work only under the terms
of this License. You must include a copy of, or the Uniform Resource
Identifier (URI) for, this License with every copy of the Work You
Distribute or Publicly Perform. You may not offer or impose any terms
on the Work that restrict the terms of this License or the ability of
the recipient of the Work to exercise the rights granted to that
recipient under the terms of the License. You may not sublicense the
Work. You must keep intact all notices that refer to this License and
to the disclaimer of warranties with every copy of the Work You
Distribute or Publicly Perform. When You Distribute or Publicly
Perform the Work, You may not impose any effective technological
measures on the Work that restrict the ability of a recipient of the
Work from You to exercise the rights granted to that recipient under
the terms of the License. This Section 4(a) applies to the Work as
incorporated in a Collection, but this does not require the Collection
apart from the Work itself to be made subject to the terms of this
License. If You create a Collection, upon notice from any Licensor You
must, to the extent practicable, remove from the Collection any credit
as required by Section 4(b), as requested. If You create an
Adaptation, upon notice from any Licensor You must, to the extent
practicable, remove from the Adaptation any credit as required by
Section 4(b), as requested.
b. If You Distribute, or Publicly Perform the Work or any Adaptations or
Collections, You must, unless a request has been made pursuant to
Section 4(a), keep intact all copyright notices for the Work and
provide, reasonable to the medium or means You are utilizing: (i) the
name of the Original Author (or pseudonym, if applicable) if supplied,
and/or if the Original Author and/or Licensor designate another party
or parties (e.g., a sponsor institute, publishing entity, journal) for
attribution ("Attribution Parties") in Licensor's copyright notice,
terms of service or by other reasonable means, the name of such party
or parties; (ii) the title of the Work if supplied; (iii) to the
extent reasonably practicable, the URI, if any, that Licensor
specifies to be associated with the Work, unless such URI does not
refer to the copyright notice or licensing information for the Work;
and (iv) , consistent with Section 3(b), in the case of an Adaptation,
a credit identifying the use of the Work in the Adaptation (e.g.,
"French translation of the Work by Original Author," or "Screenplay
based on original Work by Original Author"). The credit required by
this Section 4 (b) may be implemented in any reasonable manner;
provided, however, that in the case of a Adaptation or Collection, at
a minimum such credit will appear, if a credit for all contributing
authors of the Adaptation or Collection appears, then as part of these
credits and in a manner at least as prominent as the credits for the
other contributing authors. For the avoidance of doubt, You may only
use the credit required by this Section for the purpose of attribution
in the manner set out above and, by exercising Your rights under this
License, You may not implicitly or explicitly assert or imply any
connection with, sponsorship or endorsement by the Original Author,
Licensor and/or Attribution Parties, as appropriate, of You or Your
use of the Work, without the separate, express prior written
permission of the Original Author, Licensor and/or Attribution
Parties.
c. Except as otherwise agreed in writing by the Licensor or as may be
otherwise permitted by applicable law, if You Reproduce, Distribute or
Publicly Perform the Work either by itself or as part of any
Adaptations or Collections, You must not distort, mutilate, modify or
take other derogatory action in relation to the Work which would be
prejudicial to the Original Author's honor or reputation. Licensor
agrees that in those jurisdictions (e.g. Japan), in which any exercise
of the right granted in Section 3(b) of this License (the right to
make Adaptations) would be deemed to be a distortion, mutilation,
modification or other derogatory action prejudicial to the Original
Author's honor and reputation, the Licensor will waive or not assert,
as appropriate, this Section, to the fullest extent permitted by the
applicable national law, to enable You to reasonably exercise Your
right under Section 3(b) of this License (right to make Adaptations)
but not otherwise.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,
WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION
OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
a. This License and the rights granted hereunder will terminate
automatically upon any breach by You of the terms of this License.
Individuals or entities who have received Adaptations or Collections
from You under this License, however, will not have their licenses
terminated provided such individuals or entities remain in full
compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
survive any termination of this License.
b. Subject to the above terms and conditions, the license granted here is
perpetual (for the duration of the applicable copyright in the Work).
Notwithstanding the above, Licensor reserves the right to release the
Work under different license terms or to stop distributing the Work at
any time; provided, however that any such election will not serve to
withdraw this License (or any other license that has been, or is
required to be, granted under the terms of this License), and this
License will continue in full force and effect unless terminated as
stated above.
8. Miscellaneous
a. Each time You Distribute or Publicly Perform the Work or a Collection,
the Licensor offers to the recipient a license to the Work on the same
terms and conditions as the license granted to You under this License.
b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
offers to the recipient a license to the original Work on the same
terms and conditions as the license granted to You under this License.
c. If any provision of this License is invalid or unenforceable under
applicable law, it shall not affect the validity or enforceability of
the remainder of the terms of this License, and without further action
by the parties to this agreement, such provision shall be reformed to
the minimum extent necessary to make such provision valid and
enforceable.
d. No term or provision of this License shall be deemed waived and no
breach consented to unless such waiver or consent shall be in writing
and signed by the party to be charged with such waiver or consent.
e. This License constitutes the entire agreement between the parties with
respect to the Work licensed here. There are no understandings,
agreements or representations with respect to the Work not specified
here. Licensor shall not be bound by any additional provisions that
may appear in any communication from You. This License may not be
modified without the mutual written agreement of the Licensor and You.
f. The rights granted under, and the subject matter referenced, in this
License were drafted utilizing the terminology of the Berne Convention
for the Protection of Literary and Artistic Works (as amended on
September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996
and the Universal Copyright Convention (as revised on July 24, 1971).
These rights and subject matter take effect in the relevant
jurisdiction in which the License terms are sought to be enforced
according to the corresponding provisions of the implementation of
those treaty provisions in the applicable national law. If the
standard suite of rights granted under applicable copyright law
includes additional rights not granted under this License, such
additional rights are deemed to be included in the License; this
License is not intended to restrict the license of any rights under
applicable law.
Creative Commons Notice
Creative Commons is not a party to this License, and makes no warranty
whatsoever in connection with the Work. Creative Commons will not be
liable to You or any party on any legal theory for any damages
whatsoever, including without limitation any general, special,
incidental or consequential damages arising in connection to this
license. Notwithstanding the foregoing two (2) sentences, if Creative
Commons has expressly identified itself as the Licensor hereunder, it
shall have all rights and obligations of Licensor.
Except for the limited purpose of indicating to the public that the
Work is licensed under the CCPL, Creative Commons does not authorize
the use by either party of the trademark "Creative Commons" or any
related trademark or logo of Creative Commons without the prior
written consent of Creative Commons. Any permitted use will be in
compliance with Creative Commons' then-current trademark usage
guidelines, as may be published on its website or otherwise made
available upon request from time to time. For the avoidance of doubt,
this trademark restriction does not form part of this License.
Creative Commons may be contacted at http://creativecommons.org/.

View file

@ -32,6 +32,10 @@ func (e Event) String() string {
// a value of the corresponding struct type will be returned. // a value of the corresponding struct type will be returned.
func (e *Event) ParsePayload() (payload interface{}, err error) { func (e *Event) ParsePayload() (payload interface{}, err error) {
switch *e.Type { switch *e.Type {
case "CheckRunEvent":
payload = &CheckRunEvent{}
case "CheckSuiteEvent":
payload = &CheckSuiteEvent{}
case "CommitCommentEvent": case "CommitCommentEvent":
payload = &CommitCommentEvent{} payload = &CommitCommentEvent{}
case "CreateEvent": case "CreateEvent":

View file

@ -108,7 +108,7 @@ func (s UserStats) String() string {
return Stringify(s) return Stringify(s)
} }
//GistStats represents the number of total, private and public gists. // GistStats represents the number of total, private and public gists.
type GistStats struct { type GistStats struct {
TotalGists *int `json:"total_gists,omitempty"` TotalGists *int `json:"total_gists,omitempty"`
PrivateGists *int `json:"private_gists,omitempty"` PrivateGists *int `json:"private_gists,omitempty"`

View file

@ -20,6 +20,7 @@ type AppsService service
// App represents a GitHub App. // App represents a GitHub App.
type App struct { type App struct {
ID *int64 `json:"id,omitempty"` ID *int64 `json:"id,omitempty"`
NodeID *string `json:"node_id,omitempty"`
Owner *User `json:"owner,omitempty"` Owner *User `json:"owner,omitempty"`
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"` Description *string `json:"description,omitempty"`
@ -35,6 +36,36 @@ type InstallationToken struct {
ExpiresAt *time.Time `json:"expires_at,omitempty"` ExpiresAt *time.Time `json:"expires_at,omitempty"`
} }
// InstallationPermissions lists the permissions for metadata, contents, issues and single file for an installation.
type InstallationPermissions struct {
Metadata *string `json:"metadata,omitempty"`
Contents *string `json:"contents,omitempty"`
Issues *string `json:"issues,omitempty"`
SingleFile *string `json:"single_file,omitempty"`
}
// Installation represents a GitHub Apps installation.
type Installation struct {
ID *int64 `json:"id,omitempty"`
AppID *int64 `json:"app_id,omitempty"`
TargetID *int64 `json:"target_id,omitempty"`
Account *User `json:"account,omitempty"`
AccessTokensURL *string `json:"access_tokens_url,omitempty"`
RepositoriesURL *string `json:"repositories_url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
TargetType *string `json:"target_type,omitempty"`
SingleFileName *string `json:"single_file_name,omitempty"`
RepositorySelection *string `json:"repository_selection,omitempty"`
Events []string `json:"events,omitempty"`
Permissions *InstallationPermissions `json:"permissions,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
}
func (i Installation) String() string {
return Stringify(i)
}
// Get a single GitHub App. Passing the empty string will get // Get a single GitHub App. Passing the empty string will get
// the authenticated GitHub App. // the authenticated GitHub App.
// //
@ -98,23 +129,7 @@ func (s *AppsService) ListInstallations(ctx context.Context, opt *ListOptions) (
// //
// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-installation // GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-installation
func (s *AppsService) GetInstallation(ctx context.Context, id int64) (*Installation, *Response, error) { func (s *AppsService) GetInstallation(ctx context.Context, id int64) (*Installation, *Response, error) {
u := fmt.Sprintf("app/installations/%v", id) return s.getInstallation(ctx, fmt.Sprintf("app/installations/%v", id))
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeIntegrationPreview)
i := new(Installation)
resp, err := s.client.Do(ctx, req, i)
if err != nil {
return nil, resp, err
}
return i, resp, nil
} }
// ListUserInstallations lists installations that are accessible to the authenticated user. // ListUserInstallations lists installations that are accessible to the authenticated user.
@ -167,3 +182,42 @@ func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64) (*I
return t, resp, nil return t, resp, nil
} }
// FindOrganizationInstallation finds the organization's installation information.
//
// GitHub API docs: https://developer.github.com/v3/apps/#find-organization-installation
func (s *AppsService) FindOrganizationInstallation(ctx context.Context, org string) (*Installation, *Response, error) {
return s.getInstallation(ctx, fmt.Sprintf("orgs/%v/installation", org))
}
// FindRepositoryInstallation finds the repository's installation information.
//
// GitHub API docs: https://developer.github.com/v3/apps/#find-repository-installation
func (s *AppsService) FindRepositoryInstallation(ctx context.Context, owner, repo string) (*Installation, *Response, error) {
return s.getInstallation(ctx, fmt.Sprintf("repos/%v/%v/installation", owner, repo))
}
// FindUserInstallation finds the user's installation information.
//
// GitHub API docs: https://developer.github.com/v3/apps/#find-repository-installation
func (s *AppsService) FindUserInstallation(ctx context.Context, user string) (*Installation, *Response, error) {
return s.getInstallation(ctx, fmt.Sprintf("users/%v/installation", user))
}
func (s *AppsService) getInstallation(ctx context.Context, url string) (*Installation, *Response, error) {
req, err := s.client.NewRequest("GET", url, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeIntegrationPreview)
i := new(Installation)
resp, err := s.client.Do(ctx, req, i)
if err != nil {
return nil, resp, err
}
return i, resp, nil
}

View file

@ -10,19 +10,6 @@ import (
"fmt" "fmt"
) )
// Installation represents a GitHub Apps installation.
type Installation struct {
ID *int64 `json:"id,omitempty"`
Account *User `json:"account,omitempty"`
AccessTokensURL *string `json:"access_tokens_url,omitempty"`
RepositoriesURL *string `json:"repositories_url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
}
func (i Installation) String() string {
return Stringify(i)
}
// ListRepos lists the repositories that are accessible to the authenticated installation. // ListRepos lists the repositories that are accessible to the authenticated installation.
// //
// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories // GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories

View file

@ -74,9 +74,6 @@ func (s *MarketplaceService) ListPlans(ctx context.Context, opt *ListOptions) ([
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMarketplacePreview)
var plans []*MarketplacePlan var plans []*MarketplacePlan
resp, err := s.client.Do(ctx, req, &plans) resp, err := s.client.Do(ctx, req, &plans)
if err != nil { if err != nil {
@ -101,9 +98,6 @@ func (s *MarketplaceService) ListPlanAccountsForPlan(ctx context.Context, planID
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMarketplacePreview)
var accounts []*MarketplacePlanAccount var accounts []*MarketplacePlanAccount
resp, err := s.client.Do(ctx, req, &accounts) resp, err := s.client.Do(ctx, req, &accounts)
if err != nil { if err != nil {
@ -128,9 +122,6 @@ func (s *MarketplaceService) ListPlanAccountsForAccount(ctx context.Context, acc
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMarketplacePreview)
var accounts []*MarketplacePlanAccount var accounts []*MarketplacePlanAccount
resp, err := s.client.Do(ctx, req, &accounts) resp, err := s.client.Do(ctx, req, &accounts)
if err != nil { if err != nil {
@ -159,9 +150,6 @@ func (s *MarketplaceService) ListMarketplacePurchasesForUser(ctx context.Context
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMarketplacePreview)
var purchases []*MarketplacePurchase var purchases []*MarketplacePurchase
resp, err := s.client.Do(ctx, req, &purchases) resp, err := s.client.Do(ctx, req, &purchases)
if err != nil { if err != nil {

428
vendor/github.com/google/go-github/github/checks.go generated vendored Normal file
View file

@ -0,0 +1,428 @@
// Copyright 2018 The go-github 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 github
import (
"context"
"fmt"
)
// ChecksService provides access to the Checks API in the
// GitHub API.
//
// GitHub API docs: https://developer.github.com/v3/checks/
type ChecksService service
// CheckRun represents a GitHub check run on a repository associated with a GitHub app.
type CheckRun struct {
ID *int64 `json:"id,omitempty"`
HeadSHA *string `json:"head_sha,omitempty"`
ExternalID *string `json:"external_id,omitempty"`
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
Status *string `json:"status,omitempty"`
Conclusion *string `json:"conclusion,omitempty"`
StartedAt *Timestamp `json:"started_at,omitempty"`
CompletedAt *Timestamp `json:"completed_at,omitempty"`
Output *CheckRunOutput `json:"output,omitempty"`
Name *string `json:"name,omitempty"`
CheckSuite *CheckSuite `json:"check_suite,omitempty"`
App *App `json:"app,omitempty"`
PullRequests []*PullRequest `json:"pull_requests,omitempty"`
}
// CheckRunOutput represents the output of a CheckRun.
type CheckRunOutput struct {
Title *string `json:"title,omitempty"`
Summary *string `json:"summary,omitempty"`
Text *string `json:"text,omitempty"`
AnnotationsCount *int `json:"annotations_count,omitempty"`
AnnotationsURL *string `json:"annotations_url,omitempty"`
Annotations []*CheckRunAnnotation `json:"annotations,omitempty"`
Images []*CheckRunImage `json:"images,omitempty"`
}
// CheckRunAnnotation represents an annotation object for a CheckRun output.
type CheckRunAnnotation struct {
FileName *string `json:"filename,omitempty"`
BlobHRef *string `json:"blob_href,omitempty"`
StartLine *int `json:"start_line,omitempty"`
EndLine *int `json:"end_line,omitempty"`
WarningLevel *string `json:"warning_level,omitempty"`
Message *string `json:"message,omitempty"`
Title *string `json:"title,omitempty"`
RawDetails *string `json:"raw_details,omitempty"`
}
// CheckRunImage represents an image object for a CheckRun output.
type CheckRunImage struct {
Alt *string `json:"alt,omitempty"`
ImageURL *string `json:"image_url,omitempty"`
Caption *string `json:"caption,omitempty"`
}
// CheckSuite represents a suite of check runs.
type CheckSuite struct {
ID *int64 `json:"id,omitempty"`
HeadBranch *string `json:"head_branch,omitempty"`
HeadSHA *string `json:"head_sha,omitempty"`
URL *string `json:"url,omitempty"`
BeforeSHA *string `json:"before,omitempty"`
AfterSHA *string `json:"after,omitempty"`
Status *string `json:"status,omitempty"`
Conclusion *string `json:"conclusion,omitempty"`
App *App `json:"app,omitempty"`
Repository *Repository `json:"repository,omitempty"`
PullRequests []*PullRequest `json:"pull_requests,omitempty"`
}
func (c CheckRun) String() string {
return Stringify(c)
}
func (c CheckSuite) String() string {
return Stringify(c)
}
// GetCheckRun gets a check-run for a repository.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#get-a-single-check-run
func (s *ChecksService) GetCheckRun(ctx context.Context, owner, repo string, checkRunID int64) (*CheckRun, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
checkRun := new(CheckRun)
resp, err := s.client.Do(ctx, req, checkRun)
if err != nil {
return nil, resp, err
}
return checkRun, resp, nil
}
// GetCheckSuite gets a single check suite.
//
// GitHub API docs: https://developer.github.com/v3/checks/suites/#get-a-single-check-suite
func (s *ChecksService) GetCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*CheckSuite, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-suites/%v", owner, repo, checkSuiteID)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
checkSuite := new(CheckSuite)
resp, err := s.client.Do(ctx, req, checkSuite)
if err != nil {
return nil, resp, err
}
return checkSuite, resp, nil
}
// CreateCheckRunOptions sets up parameters needed to create a CheckRun.
type CreateCheckRunOptions struct {
Name string `json:"name"` // The name of the check (e.g., "code-coverage"). (Required.)
HeadBranch string `json:"head_branch"` // The name of the branch to perform a check against. (Required.)
HeadSHA string `json:"head_sha"` // The SHA of the commit. (Required.)
DetailsURL *string `json:"details_url,omitempty"` // The URL of the integrator's site that has the full details of the check. (Optional.)
ExternalID *string `json:"external_id,omitempty"` // A reference for the run on the integrator's system. (Optional.)
Status *string `json:"status,omitempty"` // The current status. Can be one of "queued", "in_progress", or "completed". Default: "queued". (Optional.)
Conclusion *string `json:"conclusion,omitempty"` // Can be one of "success", "failure", "neutral", "cancelled", "timed_out", or "action_required". (Optional. Required if you provide a status of "completed".)
StartedAt *Timestamp `json:"started_at,omitempty"` // The time that the check run began. (Optional.)
CompletedAt *Timestamp `json:"completed_at,omitempty"` // The time the check completed. (Optional. Required if you provide conclusion.)
Output *CheckRunOutput `json:"output,omitempty"` // Provide descriptive details about the run. (Optional)
}
// CreateCheckRun creates a check run for repository.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#create-a-check-run
func (s *ChecksService) CreateCheckRun(ctx context.Context, owner, repo string, opt CreateCheckRunOptions) (*CheckRun, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-runs", owner, repo)
req, err := s.client.NewRequest("POST", u, opt)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
checkRun := new(CheckRun)
resp, err := s.client.Do(ctx, req, checkRun)
if err != nil {
return nil, resp, err
}
return checkRun, resp, nil
}
// UpdateCheckRunOptions sets up parameters needed to update a CheckRun.
type UpdateCheckRunOptions struct {
Name string `json:"name"` // The name of the check (e.g., "code-coverage"). (Required.)
HeadBranch *string `json:"head_branch,omitempty"` // The name of the branch to perform a check against. (Optional.)
HeadSHA *string `json:"head_sha,omitempty"` // The SHA of the commit. (Optional.)
DetailsURL *string `json:"details_url,omitempty"` // The URL of the integrator's site that has the full details of the check. (Optional.)
ExternalID *string `json:"external_id,omitempty"` // A reference for the run on the integrator's system. (Optional.)
Status *string `json:"status,omitempty"` // The current status. Can be one of "queued", "in_progress", or "completed". Default: "queued". (Optional.)
Conclusion *string `json:"conclusion,omitempty"` // Can be one of "success", "failure", "neutral", "cancelled", "timed_out", or "action_required". (Optional. Required if you provide a status of "completed".)
CompletedAt *Timestamp `json:"completed_at,omitempty"` // The time the check completed. (Optional. Required if you provide conclusion.)
Output *CheckRunOutput `json:"output,omitempty"` // Provide descriptive details about the run. (Optional)
}
// UpdateCheckRun updates a check run for a specific commit in a repository.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#update-a-check-run
func (s *ChecksService) UpdateCheckRun(ctx context.Context, owner, repo string, checkRunID int64, opt UpdateCheckRunOptions) (*CheckRun, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID)
req, err := s.client.NewRequest("PATCH", u, opt)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
checkRun := new(CheckRun)
resp, err := s.client.Do(ctx, req, checkRun)
if err != nil {
return nil, resp, err
}
return checkRun, resp, nil
}
// ListCheckRunAnnotations lists the annotations for a check run.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-annotations-for-a-check-run
func (s *ChecksService) ListCheckRunAnnotations(ctx context.Context, owner, repo string, checkRunID int64, opt *ListOptions) ([]*CheckRunAnnotation, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-runs/%v/annotations", owner, repo, checkRunID)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
var checkRunAnnotations []*CheckRunAnnotation
resp, err := s.client.Do(ctx, req, &checkRunAnnotations)
if err != nil {
return nil, resp, err
}
return checkRunAnnotations, resp, nil
}
// ListCheckRunsOptions represents parameters to list check runs.
type ListCheckRunsOptions struct {
CheckName *string `url:"check_name,omitempty"` // Returns check runs with the specified name.
Status *string `url:"status,omitempty"` // Returns check runs with the specified status. Can be one of "queued", "in_progress", or "completed".
Filter *string `url:"filter,omitempty"` // Filters check runs by their completed_at timestamp. Can be one of "latest" (returning the most recent check runs) or "all". Default: "latest"
ListOptions
}
// ListCheckRunsResults represents the result of a check run list.
type ListCheckRunsResults struct {
Total *int `json:"total_count,omitempty"`
CheckRuns []*CheckRun `json:"check_runs,omitempty"`
}
// ListCheckRunsForRef lists check runs for a specific ref.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref
func (s *ChecksService) ListCheckRunsForRef(ctx context.Context, owner, repo, ref string, opt *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/commits/%v/check-runs", owner, repo, ref)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
var checkRunResults *ListCheckRunsResults
resp, err := s.client.Do(ctx, req, &checkRunResults)
if err != nil {
return nil, resp, err
}
return checkRunResults, resp, nil
}
// ListCheckRunsCheckSuite lists check runs for a check suite.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-check-runs-in-a-check-suite
func (s *ChecksService) ListCheckRunsCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64, opt *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-suites/%v/check-runs", owner, repo, checkSuiteID)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
var checkRunResults *ListCheckRunsResults
resp, err := s.client.Do(ctx, req, &checkRunResults)
if err != nil {
return nil, resp, err
}
return checkRunResults, resp, nil
}
// ListCheckSuiteOptions represents parameters to list check suites.
type ListCheckSuiteOptions struct {
CheckName *string `url:"check_name,omitempty"` // Filters checks suites by the name of the check run.
AppID *int `url:"app_id,omitempty"` // Filters check suites by GitHub App id.
ListOptions
}
// ListCheckSuiteResults represents the result of a check run list.
type ListCheckSuiteResults struct {
Total *int `json:"total_count,omitempty"`
CheckSuites []*CheckSuite `json:"check_suites,omitempty"`
}
// ListCheckSuitesForRef lists check suite for a specific ref.
//
// GitHub API docs: https://developer.github.com/v3/checks/suites/#list-check-suites-for-a-specific-ref
func (s *ChecksService) ListCheckSuitesForRef(ctx context.Context, owner, repo, ref string, opt *ListCheckSuiteOptions) (*ListCheckSuiteResults, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/commits/%v/check-suites", owner, repo, ref)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
var checkSuiteResults *ListCheckSuiteResults
resp, err := s.client.Do(ctx, req, &checkSuiteResults)
if err != nil {
return nil, resp, err
}
return checkSuiteResults, resp, nil
}
// AutoTriggerCheck enables or disables automatic creation of CheckSuite events upon pushes to the repository.
type AutoTriggerCheck struct {
AppID *int64 `json:"app_id,omitempty"` // The id of the GitHub App. (Required.)
Setting *bool `json:"setting,omitempty"` // Set to "true" to enable automatic creation of CheckSuite events upon pushes to the repository, or "false" to disable them. Default: "true" (Required.)
}
// CheckSuitePreferenceOptions set options for check suite preferences for a repository.
type CheckSuitePreferenceOptions struct {
PreferenceList *PreferenceList `json:"auto_trigger_checks,omitempty"` // A list of auto trigger checks that can be set for a check suite in a repository.
}
// CheckSuitePreferenceResults represents the results of the preference set operation.
type CheckSuitePreferenceResults struct {
Preferences *PreferenceList `json:"preferences,omitempty"`
Repository *Repository `json:"repository,omitempty"`
}
// PreferenceList represents a list of auto trigger checks for repository
type PreferenceList struct {
AutoTriggerChecks []*AutoTriggerCheck `json:"auto_trigger_checks,omitempty"` // A slice of auto trigger checks that can be set for a check suite in a repository.
}
// SetCheckSuitePreferences changes the default automatic flow when creating check suites.
//
// GitHub API docs: https://developer.github.com/v3/checks/suites/#set-preferences-for-check-suites-on-a-repository
func (s *ChecksService) SetCheckSuitePreferences(ctx context.Context, owner, repo string, opt CheckSuitePreferenceOptions) (*CheckSuitePreferenceResults, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-suites/preferences", owner, repo)
req, err := s.client.NewRequest("PATCH", u, opt)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
var checkSuitePrefResults *CheckSuitePreferenceResults
resp, err := s.client.Do(ctx, req, &checkSuitePrefResults)
if err != nil {
return nil, resp, err
}
return checkSuitePrefResults, resp, nil
}
// CreateCheckSuiteOptions sets up parameters to manually create a check suites
type CreateCheckSuiteOptions struct {
HeadSHA string `json:"head_sha"` // The sha of the head commit. (Required.)
HeadBranch *string `json:"head_branch,omitempty"` // The name of the head branch where the code changes are implemented.
}
// CreateCheckSuite manually creates a check suite for a repository.
//
// GitHub API docs: https://developer.github.com/v3/checks/suites/#create-a-check-suite
func (s *ChecksService) CreateCheckSuite(ctx context.Context, owner, repo string, opt CreateCheckSuiteOptions) (*CheckSuite, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-suites", owner, repo)
req, err := s.client.NewRequest("POST", u, opt)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
checkSuite := new(CheckSuite)
resp, err := s.client.Do(ctx, req, checkSuite)
if err != nil {
return nil, resp, err
}
return checkSuite, resp, nil
}
// RequestCheckSuiteOptions sets up the parameters for a request check suite endpoint.
type RequestCheckSuiteOptions struct {
HeadSHA string `json:"head_sha"` // The sha of the head commit. (Required.)
}
// RequestCheckSuite triggers GitHub to create a new check suite, without pushing new code to a repository.
//
// GitHub API docs: https://developer.github.com/v3/checks/suites/#request-check-suites
func (s *ChecksService) RequestCheckSuite(ctx context.Context, owner, repo string, opt RequestCheckSuiteOptions) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-suite-requests", owner, repo)
u, err := addOptions(u, opt)
if err != nil {
return nil, err
}
req, err := s.client.NewRequest("POST", u, nil)
if err != nil {
return nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
resp, err := s.client.Do(ctx, req, nil)
return resp, err
}

View file

@ -30,6 +30,13 @@ The services of a client divide the API into logical chunks and correspond to
the structure of the GitHub API documentation at the structure of the GitHub API documentation at
https://developer.github.com/v3/. https://developer.github.com/v3/.
NOTE: Using the https://godoc.org/context package, one can easily
pass cancelation signals and deadlines to various services of the client for
handling a request. In case there is no context available, then context.Background()
can be used as a starting point.
For more sample code snippets, head over to the https://github.com/google/go-github/tree/master/example directory.
Authentication Authentication
The go-github library does not directly handle authentication. Instead, when The go-github library does not directly handle authentication. Instead, when
@ -176,16 +183,5 @@ github.Response struct.
opt.Page = resp.NextPage opt.Page = resp.NextPage
} }
Google App Engine
Go on App Engine Classic (which as of this writing uses Go 1.6) can not use
the "context" import and still relies on "golang.org/x/net/context".
As a result, if you wish to continue to use "go-github" on App Engine Classic,
you will need to rewrite all the "context" imports using the following command:
gofmt -w -r '"context" -> "golang.org/x/net/context"' *.go
See "with_appengine.go" for more details.
*/ */
package github package github

View file

@ -7,6 +7,38 @@
package github package github
// CheckRunEvent is triggered when a check run is "created", "updated", or "re-requested".
// The Webhook event name is "check_run".
//
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#checkrunevent
type CheckRunEvent struct {
CheckRun *CheckRun `json:"check_run,omitempty"`
// The action performed. Can be "created", "updated" or "re-requested".
Action *string `json:"action,omitempty"`
// The following fields are only populated by Webhook events.
Repo *Repository `json:"repository,omitempty"`
Org *Organization `json:"organization,omitempty"`
Sender *User `json:"sender,omitempty"`
Installation *Installation `json:"installation,omitempty"`
}
// CheckSuiteEvent is triggered when a check suite is "completed", "requested", or "re-requested".
// The Webhook event name is "check_suite".
//
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#checksuiteevent
type CheckSuiteEvent struct {
CheckSuite *CheckSuite `json:"check_suite,omitempty"`
// The action performed. Can be "completed", "requested" or "re-requested".
Action *string `json:"action,omitempty"`
// The following fields are only populated by Webhook events.
Repo *Repository `json:"repository,omitempty"`
Org *Organization `json:"organization,omitempty"`
Sender *User `json:"sender,omitempty"`
Installation *Installation `json:"installation,omitempty"`
}
// CommitCommentEvent is triggered when a commit comment is created. // CommitCommentEvent is triggered when a commit comment is created.
// The Webhook event name is "commit_comment". // The Webhook event name is "commit_comment".
// //
@ -194,6 +226,7 @@ type TeamChange struct {
type InstallationEvent struct { type InstallationEvent struct {
// The action that was performed. Can be either "created" or "deleted". // The action that was performed. Can be either "created" or "deleted".
Action *string `json:"action,omitempty"` Action *string `json:"action,omitempty"`
Repositories []*Repository `json:"repositories,omitempty"`
Sender *User `json:"sender,omitempty"` Sender *User `json:"sender,omitempty"`
Installation *Installation `json:"installation,omitempty"` Installation *Installation `json:"installation,omitempty"`
} }
@ -491,10 +524,14 @@ type PullRequestEvent struct {
// The following fields are only populated by Webhook events. // The following fields are only populated by Webhook events.
Changes *EditChange `json:"changes,omitempty"` Changes *EditChange `json:"changes,omitempty"`
RequestedReviewers []*User `json:"requested_reviewers,omitempty"` // Populated in "review_requested", "review_request_removed" event deliveries. // RequestedReviewer is populated in "review_requested", "review_request_removed" event deliveries.
// A request affecting multiple reviewers at once is split into multiple
// such event deliveries, each with a single, different RequestedReviewer.
RequestedReviewer *User `json:"requested_reviewer,omitempty"`
Repo *Repository `json:"repository,omitempty"` Repo *Repository `json:"repository,omitempty"`
Sender *User `json:"sender,omitempty"` Sender *User `json:"sender,omitempty"`
Installation *Installation `json:"installation,omitempty"` Installation *Installation `json:"installation,omitempty"`
Label *Label `json:"label,omitempty"` // Populated in "labeled" event deliveries.
} }
// PullRequestReviewEvent is triggered when a review is submitted on a pull // PullRequestReviewEvent is triggered when a review is submitted on a pull
@ -594,6 +631,7 @@ func (p PushEventCommit) String() string {
// PushEventRepository represents the repo object in a PushEvent payload. // PushEventRepository represents the repo object in a PushEvent payload.
type PushEventRepository struct { type PushEventRepository struct {
ID *int64 `json:"id,omitempty"` ID *int64 `json:"id,omitempty"`
NodeID *string `json:"node_id,omitempty"`
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
FullName *string `json:"full_name,omitempty"` FullName *string `json:"full_name,omitempty"`
Owner *PushEventRepoOwner `json:"owner,omitempty"` Owner *PushEventRepoOwner `json:"owner,omitempty"`

View file

@ -1,332 +0,0 @@
// Copyright 2017 The go-github 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
// gen-accessors generates accessor methods for structs with pointer fields.
//
// It is meant to be used by the go-github authors in conjunction with the
// go generate tool before sending a commit to GitHub.
package main
import (
"bytes"
"flag"
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/token"
"io/ioutil"
"log"
"os"
"sort"
"strings"
"text/template"
)
const (
fileSuffix = "-accessors.go"
)
var (
verbose = flag.Bool("v", false, "Print verbose log messages")
sourceTmpl = template.Must(template.New("source").Parse(source))
// blacklistStructMethod lists "struct.method" combos to skip.
blacklistStructMethod = map[string]bool{
"RepositoryContent.GetContent": true,
"Client.GetBaseURL": true,
"Client.GetUploadURL": true,
"ErrorResponse.GetResponse": true,
"RateLimitError.GetResponse": true,
"AbuseRateLimitError.GetResponse": true,
}
// blacklistStruct lists structs to skip.
blacklistStruct = map[string]bool{
"Client": true,
}
)
func logf(fmt string, args ...interface{}) {
if *verbose {
log.Printf(fmt, args...)
}
}
func main() {
flag.Parse()
fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, ".", sourceFilter, 0)
if err != nil {
log.Fatal(err)
return
}
for pkgName, pkg := range pkgs {
t := &templateData{
filename: pkgName + fileSuffix,
Year: 2017,
Package: pkgName,
Imports: map[string]string{},
}
for filename, f := range pkg.Files {
logf("Processing %v...", filename)
if err := t.processAST(f); err != nil {
log.Fatal(err)
}
}
if err := t.dump(); err != nil {
log.Fatal(err)
}
}
logf("Done.")
}
func (t *templateData) processAST(f *ast.File) error {
for _, decl := range f.Decls {
gd, ok := decl.(*ast.GenDecl)
if !ok {
continue
}
for _, spec := range gd.Specs {
ts, ok := spec.(*ast.TypeSpec)
if !ok {
continue
}
// Skip unexported identifiers.
if !ts.Name.IsExported() {
logf("Struct %v is unexported; skipping.", ts.Name)
continue
}
// Check if the struct is blacklisted.
if blacklistStruct[ts.Name.Name] {
logf("Struct %v is blacklisted; skipping.", ts.Name)
continue
}
st, ok := ts.Type.(*ast.StructType)
if !ok {
continue
}
for _, field := range st.Fields.List {
se, ok := field.Type.(*ast.StarExpr)
if len(field.Names) == 0 || !ok {
continue
}
fieldName := field.Names[0]
// Skip unexported identifiers.
if !fieldName.IsExported() {
logf("Field %v is unexported; skipping.", fieldName)
continue
}
// Check if "struct.method" is blacklisted.
if key := fmt.Sprintf("%v.Get%v", ts.Name, fieldName); blacklistStructMethod[key] {
logf("Method %v is blacklisted; skipping.", key)
continue
}
switch x := se.X.(type) {
case *ast.ArrayType:
t.addArrayType(x, ts.Name.String(), fieldName.String())
case *ast.Ident:
t.addIdent(x, ts.Name.String(), fieldName.String())
case *ast.MapType:
t.addMapType(x, ts.Name.String(), fieldName.String())
case *ast.SelectorExpr:
t.addSelectorExpr(x, ts.Name.String(), fieldName.String())
default:
logf("processAST: type %q, field %q, unknown %T: %+v", ts.Name, fieldName, x, x)
}
}
}
}
return nil
}
func sourceFilter(fi os.FileInfo) bool {
return !strings.HasSuffix(fi.Name(), "_test.go") && !strings.HasSuffix(fi.Name(), fileSuffix)
}
func (t *templateData) dump() error {
if len(t.Getters) == 0 {
logf("No getters for %v; skipping.", t.filename)
return nil
}
// Sort getters by ReceiverType.FieldName.
sort.Sort(byName(t.Getters))
var buf bytes.Buffer
if err := sourceTmpl.Execute(&buf, t); err != nil {
return err
}
clean, err := format.Source(buf.Bytes())
if err != nil {
return err
}
logf("Writing %v...", t.filename)
return ioutil.WriteFile(t.filename, clean, 0644)
}
func newGetter(receiverType, fieldName, fieldType, zeroValue string, namedStruct bool) *getter {
return &getter{
sortVal: strings.ToLower(receiverType) + "." + strings.ToLower(fieldName),
ReceiverVar: strings.ToLower(receiverType[:1]),
ReceiverType: receiverType,
FieldName: fieldName,
FieldType: fieldType,
ZeroValue: zeroValue,
NamedStruct: namedStruct,
}
}
func (t *templateData) addArrayType(x *ast.ArrayType, receiverType, fieldName string) {
var eltType string
switch elt := x.Elt.(type) {
case *ast.Ident:
eltType = elt.String()
default:
logf("addArrayType: type %q, field %q: unknown elt type: %T %+v; skipping.", receiverType, fieldName, elt, elt)
return
}
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, "[]"+eltType, "nil", false))
}
func (t *templateData) addIdent(x *ast.Ident, receiverType, fieldName string) {
var zeroValue string
var namedStruct = false
switch x.String() {
case "int", "int64":
zeroValue = "0"
case "string":
zeroValue = `""`
case "bool":
zeroValue = "false"
case "Timestamp":
zeroValue = "Timestamp{}"
default:
zeroValue = "nil"
namedStruct = true
}
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, x.String(), zeroValue, namedStruct))
}
func (t *templateData) addMapType(x *ast.MapType, receiverType, fieldName string) {
var keyType string
switch key := x.Key.(type) {
case *ast.Ident:
keyType = key.String()
default:
logf("addMapType: type %q, field %q: unknown key type: %T %+v; skipping.", receiverType, fieldName, key, key)
return
}
var valueType string
switch value := x.Value.(type) {
case *ast.Ident:
valueType = value.String()
default:
logf("addMapType: type %q, field %q: unknown value type: %T %+v; skipping.", receiverType, fieldName, value, value)
return
}
fieldType := fmt.Sprintf("map[%v]%v", keyType, valueType)
zeroValue := fmt.Sprintf("map[%v]%v{}", keyType, valueType)
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue, false))
}
func (t *templateData) addSelectorExpr(x *ast.SelectorExpr, receiverType, fieldName string) {
if strings.ToLower(fieldName[:1]) == fieldName[:1] { // Non-exported field.
return
}
var xX string
if xx, ok := x.X.(*ast.Ident); ok {
xX = xx.String()
}
switch xX {
case "time", "json":
if xX == "json" {
t.Imports["encoding/json"] = "encoding/json"
} else {
t.Imports[xX] = xX
}
fieldType := fmt.Sprintf("%v.%v", xX, x.Sel.Name)
zeroValue := fmt.Sprintf("%v.%v{}", xX, x.Sel.Name)
if xX == "time" && x.Sel.Name == "Duration" {
zeroValue = "0"
}
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue, false))
default:
logf("addSelectorExpr: xX %q, type %q, field %q: unknown x=%+v; skipping.", xX, receiverType, fieldName, x)
}
}
type templateData struct {
filename string
Year int
Package string
Imports map[string]string
Getters []*getter
}
type getter struct {
sortVal string // Lower-case version of "ReceiverType.FieldName".
ReceiverVar string // The one-letter variable name to match the ReceiverType.
ReceiverType string
FieldName string
FieldType string
ZeroValue string
NamedStruct bool // Getter for named struct.
}
type byName []*getter
func (b byName) Len() int { return len(b) }
func (b byName) Less(i, j int) bool { return b[i].sortVal < b[j].sortVal }
func (b byName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
const source = `// Copyright {{.Year}} The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Code generated by gen-accessors; DO NOT EDIT.
package {{.Package}}
{{with .Imports}}
import (
{{- range . -}}
"{{.}}"
{{end -}}
)
{{end}}
{{range .Getters}}
{{if .NamedStruct}}
// Get{{.FieldName}} returns the {{.FieldName}} field.
func ({{.ReceiverVar}} *{{.ReceiverType}}) Get{{.FieldName}}() *{{.FieldType}} {
if {{.ReceiverVar}} == nil {
return {{.ZeroValue}}
}
return {{.ReceiverVar}}.{{.FieldName}}
}
{{else}}
// Get{{.FieldName}} returns the {{.FieldName}} field if it's non-nil, zero value otherwise.
func ({{.ReceiverVar}} *{{.ReceiverType}}) Get{{.FieldName}}() {{.FieldType}} {
if {{.ReceiverVar}} == nil || {{.ReceiverVar}}.{{.FieldName}} == nil {
return {{.ZeroValue}}
}
return *{{.ReceiverVar}}.{{.FieldName}}
}
{{end}}
{{end}}
`

View file

@ -114,9 +114,6 @@ func (s *GistsService) List(ctx context.Context, user string, opt *GistListOptio
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
var gists []*Gist var gists []*Gist
resp, err := s.client.Do(ctx, req, &gists) resp, err := s.client.Do(ctx, req, &gists)
if err != nil { if err != nil {
@ -140,9 +137,6 @@ func (s *GistsService) ListAll(ctx context.Context, opt *GistListOptions) ([]*Gi
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
var gists []*Gist var gists []*Gist
resp, err := s.client.Do(ctx, req, &gists) resp, err := s.client.Do(ctx, req, &gists)
if err != nil { if err != nil {
@ -166,9 +160,6 @@ func (s *GistsService) ListStarred(ctx context.Context, opt *GistListOptions) ([
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
var gists []*Gist var gists []*Gist
resp, err := s.client.Do(ctx, req, &gists) resp, err := s.client.Do(ctx, req, &gists)
if err != nil { if err != nil {
@ -188,9 +179,6 @@ func (s *GistsService) Get(ctx context.Context, id string) (*Gist, *Response, er
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
gist := new(Gist) gist := new(Gist)
resp, err := s.client.Do(ctx, req, gist) resp, err := s.client.Do(ctx, req, gist)
if err != nil { if err != nil {
@ -210,9 +198,6 @@ func (s *GistsService) GetRevision(ctx context.Context, id, sha string) (*Gist,
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
gist := new(Gist) gist := new(Gist)
resp, err := s.client.Do(ctx, req, gist) resp, err := s.client.Do(ctx, req, gist)
if err != nil { if err != nil {
@ -232,9 +217,6 @@ func (s *GistsService) Create(ctx context.Context, gist *Gist) (*Gist, *Response
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
g := new(Gist) g := new(Gist)
resp, err := s.client.Do(ctx, req, g) resp, err := s.client.Do(ctx, req, g)
if err != nil { if err != nil {
@ -254,9 +236,6 @@ func (s *GistsService) Edit(ctx context.Context, id string, gist *Gist) (*Gist,
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
g := new(Gist) g := new(Gist)
resp, err := s.client.Do(ctx, req, g) resp, err := s.client.Do(ctx, req, g)
if err != nil { if err != nil {
@ -281,9 +260,6 @@ func (s *GistsService) ListCommits(ctx context.Context, id string, opt *ListOpti
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
var gistCommits []*GistCommit var gistCommits []*GistCommit
resp, err := s.client.Do(ctx, req, &gistCommits) resp, err := s.client.Do(ctx, req, &gistCommits)
if err != nil { if err != nil {
@ -353,9 +329,6 @@ func (s *GistsService) Fork(ctx context.Context, id string) (*Gist, *Response, e
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
g := new(Gist) g := new(Gist)
resp, err := s.client.Do(ctx, req, g) resp, err := s.client.Do(ctx, req, g)
if err != nil { if err != nil {
@ -375,9 +348,6 @@ func (s *GistsService) ListForks(ctx context.Context, id string) ([]*GistFork, *
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
var gistForks []*GistFork var gistForks []*GistFork
resp, err := s.client.Do(ctx, req, &gistForks) resp, err := s.client.Do(ctx, req, &gistForks)
if err != nil { if err != nil {

View file

@ -6,6 +6,7 @@
package github package github
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
) )
@ -20,7 +21,7 @@ type Blob struct {
NodeID *string `json:"node_id,omitempty"` NodeID *string `json:"node_id,omitempty"`
} }
// GetBlob fetchs a blob from a repo given a SHA. // GetBlob fetches a blob from a repo given a SHA.
// //
// GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob // GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob
func (s *GitService) GetBlob(ctx context.Context, owner string, repo string, sha string) (*Blob, *Response, error) { func (s *GitService) GetBlob(ctx context.Context, owner string, repo string, sha string) (*Blob, *Response, error) {
@ -30,14 +31,28 @@ func (s *GitService) GetBlob(ctx context.Context, owner string, repo string, sha
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
blob := new(Blob) blob := new(Blob)
resp, err := s.client.Do(ctx, req, blob) resp, err := s.client.Do(ctx, req, blob)
return blob, resp, err return blob, resp, err
} }
// GetBlobRaw fetches a blob's contents from a repo.
// Unlike GetBlob, it returns the raw bytes rather than the base64-encoded data.
//
// GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob
func (s *GitService) GetBlobRaw(ctx context.Context, owner, repo, sha string) ([]byte, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", "application/vnd.github.v3.raw")
var buf bytes.Buffer
resp, err := s.client.Do(ctx, req, &buf)
return buf.Bytes(), resp, err
}
// CreateBlob creates a blob object. // CreateBlob creates a blob object.
// //
// GitHub API docs: https://developer.github.com/v3/git/blobs/#create-a-blob // GitHub API docs: https://developer.github.com/v3/git/blobs/#create-a-blob
@ -48,9 +63,6 @@ func (s *GitService) CreateBlob(ctx context.Context, owner string, repo string,
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
t := new(Blob) t := new(Blob)
resp, err := s.client.Do(ctx, req, t) resp, err := s.client.Do(ctx, req, t)
return t, resp, err return t, resp, err

View file

@ -8,7 +8,6 @@ package github
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"time" "time"
) )
@ -70,8 +69,7 @@ func (s *GitService) GetCommit(ctx context.Context, owner string, repo string, s
} }
// TODO: remove custom Accept headers when APIs fully launch. // TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeGitSigningPreview, mediaTypeGraphQLNodeIDPreview} req.Header.Set("Accept", mediaTypeGitSigningPreview)
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
c := new(Commit) c := new(Commit)
resp, err := s.client.Do(ctx, req, c) resp, err := s.client.Do(ctx, req, c)
@ -126,9 +124,6 @@ func (s *GitService) CreateCommit(ctx context.Context, owner string, repo string
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
c := new(Commit) c := new(Commit)
resp, err := s.client.Do(ctx, req, c) resp, err := s.client.Do(ctx, req, c)
if err != nil { if err != nil {

View file

@ -63,9 +63,6 @@ func (s *GitService) GetRef(ctx context.Context, owner string, repo string, ref
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
r := new(Reference) r := new(Reference)
resp, err := s.client.Do(ctx, req, r) resp, err := s.client.Do(ctx, req, r)
if _, ok := err.(*json.UnmarshalTypeError); ok { if _, ok := err.(*json.UnmarshalTypeError); ok {
@ -97,9 +94,6 @@ func (s *GitService) GetRefs(ctx context.Context, owner string, repo string, ref
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
var rawJSON json.RawMessage var rawJSON json.RawMessage
resp, err := s.client.Do(ctx, req, &rawJSON) resp, err := s.client.Do(ctx, req, &rawJSON)
if err != nil { if err != nil {
@ -154,9 +148,6 @@ func (s *GitService) ListRefs(ctx context.Context, owner, repo string, opt *Refe
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
var rs []*Reference var rs []*Reference
resp, err := s.client.Do(ctx, req, &rs) resp, err := s.client.Do(ctx, req, &rs)
if err != nil { if err != nil {
@ -180,9 +171,6 @@ func (s *GitService) CreateRef(ctx context.Context, owner string, repo string, r
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
r := new(Reference) r := new(Reference)
resp, err := s.client.Do(ctx, req, r) resp, err := s.client.Do(ctx, req, r)
if err != nil { if err != nil {
@ -206,9 +194,6 @@ func (s *GitService) UpdateRef(ctx context.Context, owner string, repo string, r
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
r := new(Reference) r := new(Reference)
resp, err := s.client.Do(ctx, req, r) resp, err := s.client.Do(ctx, req, r)
if err != nil { if err != nil {

View file

@ -8,7 +8,6 @@ package github
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
) )
// Tag represents a tag object. // Tag represents a tag object.
@ -45,8 +44,7 @@ func (s *GitService) GetTag(ctx context.Context, owner string, repo string, sha
} }
// TODO: remove custom Accept headers when APIs fully launch. // TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeGitSigningPreview, mediaTypeGraphQLNodeIDPreview} req.Header.Set("Accept", mediaTypeGitSigningPreview)
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
tag := new(Tag) tag := new(Tag)
resp, err := s.client.Do(ctx, req, tag) resp, err := s.client.Do(ctx, req, tag)
@ -75,9 +73,6 @@ func (s *GitService) CreateTag(ctx context.Context, owner string, repo string, t
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
t := new(Tag) t := new(Tag)
resp, err := s.client.Do(ctx, req, t) resp, err := s.client.Do(ctx, req, t)
return t, resp, err return t, resp, err

View file

@ -14,6 +14,12 @@ import (
type Tree struct { type Tree struct {
SHA *string `json:"sha,omitempty"` SHA *string `json:"sha,omitempty"`
Entries []TreeEntry `json:"tree,omitempty"` Entries []TreeEntry `json:"tree,omitempty"`
// Truncated is true if the number of items in the tree
// exceeded GitHub's maximum limit and the Entries were truncated
// in the response. Only populated for requests that fetch
// trees like Git.GetTree.
Truncated *bool `json:"truncated,omitempty"`
} }
func (t Tree) String() string { func (t Tree) String() string {

File diff suppressed because it is too large Load diff

View file

@ -27,10 +27,9 @@ import (
) )
const ( const (
libraryVersion = "15"
defaultBaseURL = "https://api.github.com/" defaultBaseURL = "https://api.github.com/"
uploadBaseURL = "https://uploads.github.com/" uploadBaseURL = "https://uploads.github.com/"
userAgent = "go-github/" + libraryVersion userAgent = "go-github"
headerRateLimit = "X-RateLimit-Limit" headerRateLimit = "X-RateLimit-Limit"
headerRateRemaining = "X-RateLimit-Remaining" headerRateRemaining = "X-RateLimit-Remaining"
@ -46,15 +45,9 @@ const (
// Media Type values to access preview APIs // Media Type values to access preview APIs
// https://developer.github.com/changes/2015-03-09-licenses-api/
mediaTypeLicensesPreview = "application/vnd.github.drax-preview+json"
// https://developer.github.com/changes/2014-12-09-new-attributes-for-stars-api/ // https://developer.github.com/changes/2014-12-09-new-attributes-for-stars-api/
mediaTypeStarringPreview = "application/vnd.github.v3.star+json" mediaTypeStarringPreview = "application/vnd.github.v3.star+json"
// https://developer.github.com/changes/2015-11-11-protected-branches-api/
mediaTypeProtectedBranchesPreview = "application/vnd.github.loki-preview+json"
// https://help.github.com/enterprise/2.4/admin/guides/migrations/exporting-the-github-com-organization-s-repositories/ // https://help.github.com/enterprise/2.4/admin/guides/migrations/exporting-the-github-com-organization-s-repositories/
mediaTypeMigrationsPreview = "application/vnd.github.wyandotte-preview+json" mediaTypeMigrationsPreview = "application/vnd.github.wyandotte-preview+json"
@ -100,20 +93,35 @@ const (
// https://developer.github.com/changes/2017-07-17-update-topics-on-repositories/ // https://developer.github.com/changes/2017-07-17-update-topics-on-repositories/
mediaTypeTopicsPreview = "application/vnd.github.mercy-preview+json" mediaTypeTopicsPreview = "application/vnd.github.mercy-preview+json"
// https://developer.github.com/changes/2017-07-26-team-review-request-thor-preview/
mediaTypeTeamReviewPreview = "application/vnd.github.thor-preview+json"
// https://developer.github.com/v3/apps/marketplace/
mediaTypeMarketplacePreview = "application/vnd.github.valkyrie-preview+json"
// https://developer.github.com/changes/2017-08-30-preview-nested-teams/ // https://developer.github.com/changes/2017-08-30-preview-nested-teams/
mediaTypeNestedTeamsPreview = "application/vnd.github.hellcat-preview+json" mediaTypeNestedTeamsPreview = "application/vnd.github.hellcat-preview+json"
// https://developer.github.com/changes/2017-11-09-repository-transfer-api-preview/ // https://developer.github.com/changes/2017-11-09-repository-transfer-api-preview/
mediaTypeRepositoryTransferPreview = "application/vnd.github.nightshade-preview+json" mediaTypeRepositoryTransferPreview = "application/vnd.github.nightshade-preview+json"
// https://developer.github.com/changes/2017-12-19-graphql-node-id/ // https://developer.github.com/changes/2018-01-25-organization-invitation-api-preview/
mediaTypeGraphQLNodeIDPreview = "application/vnd.github.jean-grey-preview+json" mediaTypeOrganizationInvitationPreview = "application/vnd.github.dazzler-preview+json"
// https://developer.github.com/changes/2018-03-16-protected-branches-required-approving-reviews/
mediaTypeRequiredApprovingReviewsPreview = "application/vnd.github.luke-cage-preview+json"
// https://developer.github.com/changes/2018-02-22-label-description-search-preview/
mediaTypeLabelDescriptionSearchPreview = "application/vnd.github.symmetra-preview+json"
// https://developer.github.com/changes/2018-02-07-team-discussions-api/
mediaTypeTeamDiscussionsPreview = "application/vnd.github.echo-preview+json"
// https://developer.github.com/changes/2018-03-21-hovercard-api-preview/
mediaTypeHovercardPreview = "application/vnd.github.hagar-preview+json"
// https://developer.github.com/changes/2018-01-10-lock-reason-api-preview/
mediaTypeLockReasonPreview = "application/vnd.github.sailor-v-preview+json"
// https://developer.github.com/changes/2018-05-07-new-checks-api-public-beta/
mediaTypeCheckRunsPreview = "application/vnd.github.antiope-preview+json"
// https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/
mediaTypePreReceiveHooksPreview = "application/vnd.github.eye-scream-preview"
) )
// A Client manages communication with the GitHub API. // A Client manages communication with the GitHub API.
@ -142,6 +150,7 @@ type Client struct {
Admin *AdminService Admin *AdminService
Apps *AppsService Apps *AppsService
Authorizations *AuthorizationsService Authorizations *AuthorizationsService
Checks *ChecksService
Gists *GistsService Gists *GistsService
Git *GitService Git *GitService
Gitignores *GitignoresService Gitignores *GitignoresService
@ -155,6 +164,7 @@ type Client struct {
Reactions *ReactionsService Reactions *ReactionsService
Repositories *RepositoriesService Repositories *RepositoriesService
Search *SearchService Search *SearchService
Teams *TeamsService
Users *UsersService Users *UsersService
} }
@ -232,6 +242,7 @@ func NewClient(httpClient *http.Client) *Client {
c.Admin = (*AdminService)(&c.common) c.Admin = (*AdminService)(&c.common)
c.Apps = (*AppsService)(&c.common) c.Apps = (*AppsService)(&c.common)
c.Authorizations = (*AuthorizationsService)(&c.common) c.Authorizations = (*AuthorizationsService)(&c.common)
c.Checks = (*ChecksService)(&c.common)
c.Gists = (*GistsService)(&c.common) c.Gists = (*GistsService)(&c.common)
c.Git = (*GitService)(&c.common) c.Git = (*GitService)(&c.common)
c.Gitignores = (*GitignoresService)(&c.common) c.Gitignores = (*GitignoresService)(&c.common)
@ -245,6 +256,7 @@ func NewClient(httpClient *http.Client) *Client {
c.Reactions = (*ReactionsService)(&c.common) c.Reactions = (*ReactionsService)(&c.common)
c.Repositories = (*RepositoriesService)(&c.common) c.Repositories = (*RepositoriesService)(&c.common)
c.Search = (*SearchService)(&c.common) c.Search = (*SearchService)(&c.common)
c.Teams = (*TeamsService)(&c.common)
c.Users = (*UsersService)(&c.common) c.Users = (*UsersService)(&c.common)
return c return c
} }
@ -478,12 +490,7 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res
return nil, err return nil, err
} }
defer resp.Body.Close()
defer func() {
// Drain up to 512 bytes and close the body to let the Transport reuse the connection
io.CopyN(ioutil.Discard, resp.Body, 512)
resp.Body.Close()
}()
response := newResponse(resp) response := newResponse(resp)
@ -493,18 +500,25 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res
err = CheckResponse(resp) err = CheckResponse(resp)
if err != nil { if err != nil {
// even though there was an error, we still return the response // Even though there was an error, we still return the response
// in case the caller wants to inspect it further // in case the caller wants to inspect it further.
// However, if the error is AcceptedError, decode it below before
// returning from this function and closing the response body.
if _, ok := err.(*AcceptedError); !ok {
return response, err return response, err
} }
}
if v != nil { if v != nil {
if w, ok := v.(io.Writer); ok { if w, ok := v.(io.Writer); ok {
io.Copy(w, resp.Body) io.Copy(w, resp.Body)
} else { } else {
err = json.NewDecoder(resp.Body).Decode(v) decErr := json.NewDecoder(resp.Body).Decode(v)
if err == io.EOF { if decErr == io.EOF {
err = nil // ignore EOF errors caused by empty response body decErr = nil // ignore EOF errors caused by empty response body
}
if decErr != nil {
err = decErr
} }
} }
} }
@ -693,7 +707,7 @@ func CheckResponse(r *http.Response) error {
Response: errorResponse.Response, Response: errorResponse.Response,
Message: errorResponse.Message, Message: errorResponse.Message,
} }
case r.StatusCode == http.StatusForbidden && errorResponse.DocumentationURL == "https://developer.github.com/v3/#abuse-rate-limits": case r.StatusCode == http.StatusForbidden && strings.HasSuffix(errorResponse.DocumentationURL, "/v3/#abuse-rate-limits"):
abuseRateLimitError := &AbuseRateLimitError{ abuseRateLimitError := &AbuseRateLimitError{
Response: errorResponse.Response, Response: errorResponse.Response,
Message: errorResponse.Message, Message: errorResponse.Message,

View file

@ -56,6 +56,10 @@ type Issue struct {
// TextMatches is only populated from search results that request text matches // TextMatches is only populated from search results that request text matches
// See: search.go and https://developer.github.com/v3/search/#text-match-metadata // See: search.go and https://developer.github.com/v3/search/#text-match-metadata
TextMatches []TextMatch `json:"text_matches,omitempty"` TextMatches []TextMatch `json:"text_matches,omitempty"`
// ActiveLockReason is populated only when LockReason is provided while locking the issue.
// Possible values are: "off-topic", "too heated", "resolved", and "spam".
ActiveLockReason *string `json:"active_lock_reason,omitempty"`
} }
func (i Issue) String() string { func (i Issue) String() string {
@ -156,7 +160,7 @@ func (s *IssuesService) listIssues(ctx context.Context, u string, opt *IssueList
} }
// TODO: remove custom Accept headers when APIs fully launch. // TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview} acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var issues []*Issue var issues []*Issue
@ -224,7 +228,7 @@ func (s *IssuesService) ListByRepo(ctx context.Context, owner string, repo strin
} }
// TODO: remove custom Accept headers when APIs fully launch. // TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview} acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var issues []*Issue var issues []*Issue
@ -247,7 +251,7 @@ func (s *IssuesService) Get(ctx context.Context, owner string, repo string, numb
} }
// TODO: remove custom Accept headers when APIs fully launch. // TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview} acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
issue := new(Issue) issue := new(Issue)
@ -270,7 +274,7 @@ func (s *IssuesService) Create(ctx context.Context, owner string, repo string, i
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
i := new(Issue) i := new(Issue)
resp, err := s.client.Do(ctx, req, i) resp, err := s.client.Do(ctx, req, i)
@ -292,7 +296,7 @@ func (s *IssuesService) Edit(ctx context.Context, owner string, repo string, num
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
i := new(Issue) i := new(Issue)
resp, err := s.client.Do(ctx, req, i) resp, err := s.client.Do(ctx, req, i)
@ -303,16 +307,29 @@ func (s *IssuesService) Edit(ctx context.Context, owner string, repo string, num
return i, resp, nil return i, resp, nil
} }
// LockIssueOptions specifies the optional parameters to the
// IssuesService.Lock method.
type LockIssueOptions struct {
// LockReason specifies the reason to lock this issue.
// Providing a lock reason can help make it clearer to contributors why an issue
// was locked. Possible values are: "off-topic", "too heated", "resolved", and "spam".
LockReason string `json:"lock_reason,omitempty"`
}
// Lock an issue's conversation. // Lock an issue's conversation.
// //
// GitHub API docs: https://developer.github.com/v3/issues/#lock-an-issue // GitHub API docs: https://developer.github.com/v3/issues/#lock-an-issue
func (s *IssuesService) Lock(ctx context.Context, owner string, repo string, number int) (*Response, error) { func (s *IssuesService) Lock(ctx context.Context, owner string, repo string, number int, opt *LockIssueOptions) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number) u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number)
req, err := s.client.NewRequest("PUT", u, nil) req, err := s.client.NewRequest("PUT", u, opt)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if opt != nil {
req.Header.Set("Accept", mediaTypeLockReasonPreview)
}
return s.client.Do(ctx, req, nil) return s.client.Do(ctx, req, nil)
} }

View file

@ -19,6 +19,9 @@ type IssueComment struct {
Reactions *Reactions `json:"reactions,omitempty"` Reactions *Reactions `json:"reactions,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"` CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"` UpdatedAt *time.Time `json:"updated_at,omitempty"`
// AuthorAssociation is the comment author's relationship to the issue's repository.
// Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE".
AuthorAssociation *string `json:"author_association,omitempty"`
URL *string `json:"url,omitempty"` URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"` HTMLURL *string `json:"html_url,omitempty"`
IssueURL *string `json:"issue_url,omitempty"` IssueURL *string `json:"issue_url,omitempty"`
@ -79,8 +82,8 @@ func (s *IssuesService) ListComments(ctx context.Context, owner string, repo str
// GetComment fetches the specified issue comment. // GetComment fetches the specified issue comment.
// //
// GitHub API docs: https://developer.github.com/v3/issues/comments/#get-a-single-comment // GitHub API docs: https://developer.github.com/v3/issues/comments/#get-a-single-comment
func (s *IssuesService) GetComment(ctx context.Context, owner string, repo string, id int) (*IssueComment, *Response, error) { func (s *IssuesService) GetComment(ctx context.Context, owner string, repo string, commentID int64) (*IssueComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id) u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("GET", u, nil) req, err := s.client.NewRequest("GET", u, nil)
if err != nil { if err != nil {
@ -118,10 +121,11 @@ func (s *IssuesService) CreateComment(ctx context.Context, owner string, repo st
} }
// EditComment updates an issue comment. // EditComment updates an issue comment.
// A non-nil comment.Body must be provided. Other comment fields should be left nil.
// //
// GitHub API docs: https://developer.github.com/v3/issues/comments/#edit-a-comment // GitHub API docs: https://developer.github.com/v3/issues/comments/#edit-a-comment
func (s *IssuesService) EditComment(ctx context.Context, owner string, repo string, id int, comment *IssueComment) (*IssueComment, *Response, error) { func (s *IssuesService) EditComment(ctx context.Context, owner string, repo string, commentID int64, comment *IssueComment) (*IssueComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id) u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("PATCH", u, comment) req, err := s.client.NewRequest("PATCH", u, comment)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -138,8 +142,8 @@ func (s *IssuesService) EditComment(ctx context.Context, owner string, repo stri
// DeleteComment deletes an issue comment. // DeleteComment deletes an issue comment.
// //
// GitHub API docs: https://developer.github.com/v3/issues/comments/#delete-a-comment // GitHub API docs: https://developer.github.com/v3/issues/comments/#delete-a-comment
func (s *IssuesService) DeleteComment(ctx context.Context, owner string, repo string, id int) (*Response, error) { func (s *IssuesService) DeleteComment(ctx context.Context, owner string, repo string, commentID int64) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id) u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("DELETE", u, nil) req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -34,9 +34,13 @@ type IssueEvent struct {
// The Actor committed to master a commit mentioning the issue in its commit message. // The Actor committed to master a commit mentioning the issue in its commit message.
// CommitID holds the SHA1 of the commit. // CommitID holds the SHA1 of the commit.
// //
// reopened, locked, unlocked // reopened, unlocked
// The Actor did that to the issue. // The Actor did that to the issue.
// //
// locked
// The Actor locked the issue.
// LockReason holds the reason of locking the issue (if provided while locking).
//
// renamed // renamed
// The Actor changed the issue title from Rename.From to Rename.To. // The Actor changed the issue title from Rename.From to Rename.To.
// //
@ -70,6 +74,7 @@ type IssueEvent struct {
Milestone *Milestone `json:"milestone,omitempty"` Milestone *Milestone `json:"milestone,omitempty"`
Label *Label `json:"label,omitempty"` Label *Label `json:"label,omitempty"`
Rename *Rename `json:"rename,omitempty"` Rename *Rename `json:"rename,omitempty"`
LockReason *string `json:"lock_reason,omitempty"`
} }
// ListIssueEvents lists events for the specified issue. // ListIssueEvents lists events for the specified issue.
@ -87,6 +92,8 @@ func (s *IssuesService) ListIssueEvents(ctx context.Context, owner, repo string,
return nil, nil, err return nil, nil, err
} }
req.Header.Set("Accept", mediaTypeLockReasonPreview)
var events []*IssueEvent var events []*IssueEvent
resp, err := s.client.Do(ctx, req, &events) resp, err := s.client.Do(ctx, req, &events)
if err != nil { if err != nil {

View file

@ -16,6 +16,8 @@ type Label struct {
URL *string `json:"url,omitempty"` URL *string `json:"url,omitempty"`
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
Color *string `json:"color,omitempty"` Color *string `json:"color,omitempty"`
Description *string `json:"description,omitempty"`
Default *bool `json:"default,omitempty"`
NodeID *string `json:"node_id,omitempty"` NodeID *string `json:"node_id,omitempty"`
} }
@ -39,7 +41,7 @@ func (s *IssuesService) ListLabels(ctx context.Context, owner string, repo strin
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
var labels []*Label var labels []*Label
resp, err := s.client.Do(ctx, req, &labels) resp, err := s.client.Do(ctx, req, &labels)
@ -61,7 +63,7 @@ func (s *IssuesService) GetLabel(ctx context.Context, owner string, repo string,
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
label := new(Label) label := new(Label)
resp, err := s.client.Do(ctx, req, label) resp, err := s.client.Do(ctx, req, label)
@ -83,7 +85,7 @@ func (s *IssuesService) CreateLabel(ctx context.Context, owner string, repo stri
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
l := new(Label) l := new(Label)
resp, err := s.client.Do(ctx, req, l) resp, err := s.client.Do(ctx, req, l)
@ -105,7 +107,7 @@ func (s *IssuesService) EditLabel(ctx context.Context, owner string, repo string
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
l := new(Label) l := new(Label)
resp, err := s.client.Do(ctx, req, l) resp, err := s.client.Do(ctx, req, l)
@ -144,7 +146,7 @@ func (s *IssuesService) ListLabelsByIssue(ctx context.Context, owner string, rep
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
var labels []*Label var labels []*Label
resp, err := s.client.Do(ctx, req, &labels) resp, err := s.client.Do(ctx, req, &labels)
@ -166,7 +168,7 @@ func (s *IssuesService) AddLabelsToIssue(ctx context.Context, owner string, repo
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
var l []*Label var l []*Label
resp, err := s.client.Do(ctx, req, &l) resp, err := s.client.Do(ctx, req, &l)
@ -186,6 +188,10 @@ func (s *IssuesService) RemoveLabelForIssue(ctx context.Context, owner string, r
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
return s.client.Do(ctx, req, nil) return s.client.Do(ctx, req, nil)
} }
@ -200,7 +206,7 @@ func (s *IssuesService) ReplaceLabelsForIssue(ctx context.Context, owner string,
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
var l []*Label var l []*Label
resp, err := s.client.Do(ctx, req, &l) resp, err := s.client.Do(ctx, req, &l)
@ -220,6 +226,10 @@ func (s *IssuesService) RemoveLabelsForIssue(ctx context.Context, owner string,
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
return s.client.Do(ctx, req, nil) return s.client.Do(ctx, req, nil)
} }
@ -239,7 +249,7 @@ func (s *IssuesService) ListLabelsForMilestone(ctx context.Context, owner string
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
var labels []*Label var labels []*Label
resp, err := s.client.Do(ctx, req, &labels) resp, err := s.client.Do(ctx, req, &labels)

View file

@ -68,9 +68,6 @@ func (s *IssuesService) ListMilestones(ctx context.Context, owner string, repo s
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
var milestones []*Milestone var milestones []*Milestone
resp, err := s.client.Do(ctx, req, &milestones) resp, err := s.client.Do(ctx, req, &milestones)
if err != nil { if err != nil {
@ -90,9 +87,6 @@ func (s *IssuesService) GetMilestone(ctx context.Context, owner string, repo str
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
milestone := new(Milestone) milestone := new(Milestone)
resp, err := s.client.Do(ctx, req, milestone) resp, err := s.client.Do(ctx, req, milestone)
if err != nil { if err != nil {
@ -112,9 +106,6 @@ func (s *IssuesService) CreateMilestone(ctx context.Context, owner string, repo
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
m := new(Milestone) m := new(Milestone)
resp, err := s.client.Do(ctx, req, m) resp, err := s.client.Do(ctx, req, m)
if err != nil { if err != nil {
@ -134,9 +125,6 @@ func (s *IssuesService) EditMilestone(ctx context.Context, owner string, repo st
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
m := new(Milestone) m := new(Milestone)
resp, err := s.client.Do(ctx, req, m) resp, err := s.client.Do(ctx, req, m)
if err != nil { if err != nil {

View file

@ -67,9 +67,6 @@ func (s *LicensesService) List(ctx context.Context) ([]*License, *Response, erro
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeLicensesPreview)
var licenses []*License var licenses []*License
resp, err := s.client.Do(ctx, req, &licenses) resp, err := s.client.Do(ctx, req, &licenses)
if err != nil { if err != nil {
@ -90,9 +87,6 @@ func (s *LicensesService) Get(ctx context.Context, licenseName string) (*License
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeLicensesPreview)
license := new(License) license := new(License)
resp, err := s.client.Do(ctx, req, license) resp, err := s.client.Do(ctx, req, license)
if err != nil { if err != nil {

View file

@ -41,6 +41,8 @@ const (
var ( var (
// eventTypeMapping maps webhooks types to their corresponding go-github struct types. // eventTypeMapping maps webhooks types to their corresponding go-github struct types.
eventTypeMapping = map[string]string{ eventTypeMapping = map[string]string{
"check_run": "CheckRunEvent",
"check_suite": "CheckSuiteEvent",
"commit_comment": "CommitCommentEvent", "commit_comment": "CommitCommentEvent",
"create": "CreateEvent", "create": "CreateEvent",
"delete": "DeleteEvent", "delete": "DeleteEvent",

View file

@ -0,0 +1,214 @@
// Copyright 2018 The go-github 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 github
import (
"context"
"errors"
"fmt"
"net/http"
)
// UserMigration represents a GitHub migration (archival).
type UserMigration struct {
ID *int64 `json:"id,omitempty"`
GUID *string `json:"guid,omitempty"`
// State is the current state of a migration.
// Possible values are:
// "pending" which means the migration hasn't started yet,
// "exporting" which means the migration is in progress,
// "exported" which means the migration finished successfully, or
// "failed" which means the migration failed.
State *string `json:"state,omitempty"`
// LockRepositories indicates whether repositories are locked (to prevent
// manipulation) while migrating data.
LockRepositories *bool `json:"lock_repositories,omitempty"`
// ExcludeAttachments indicates whether attachments should be excluded from
// the migration (to reduce migration archive file size).
ExcludeAttachments *bool `json:"exclude_attachments,omitempty"`
URL *string `json:"url,omitempty"`
CreatedAt *string `json:"created_at,omitempty"`
UpdatedAt *string `json:"updated_at,omitempty"`
Repositories []*Repository `json:"repositories,omitempty"`
}
func (m UserMigration) String() string {
return Stringify(m)
}
// UserMigrationOptions specifies the optional parameters to Migration methods.
type UserMigrationOptions struct {
// LockRepositories indicates whether repositories should be locked (to prevent
// manipulation) while migrating data.
LockRepositories bool
// ExcludeAttachments indicates whether attachments should be excluded from
// the migration (to reduce migration archive file size).
ExcludeAttachments bool
}
// startUserMigration represents the body of a StartMigration request.
type startUserMigration struct {
// Repositories is a slice of repository names to migrate.
Repositories []string `json:"repositories,omitempty"`
// LockRepositories indicates whether repositories should be locked (to prevent
// manipulation) while migrating data.
LockRepositories *bool `json:"lock_repositories,omitempty"`
// ExcludeAttachments indicates whether attachments should be excluded from
// the migration (to reduce migration archive file size).
ExcludeAttachments *bool `json:"exclude_attachments,omitempty"`
}
// StartUserMigration starts the generation of a migration archive.
// repos is a slice of repository names to migrate.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#start-a-user-migration
func (s *MigrationService) StartUserMigration(ctx context.Context, repos []string, opt *UserMigrationOptions) (*UserMigration, *Response, error) {
u := "user/migrations"
body := &startUserMigration{Repositories: repos}
if opt != nil {
body.LockRepositories = Bool(opt.LockRepositories)
body.ExcludeAttachments = Bool(opt.ExcludeAttachments)
}
req, err := s.client.NewRequest("POST", u, body)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
m := &UserMigration{}
resp, err := s.client.Do(ctx, req, m)
if err != nil {
return nil, resp, err
}
return m, resp, nil
}
// ListUserMigrations lists the most recent migrations.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#get-a-list-of-user-migrations
func (s *MigrationService) ListUserMigrations(ctx context.Context) ([]*UserMigration, *Response, error) {
u := "user/migrations"
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
var m []*UserMigration
resp, err := s.client.Do(ctx, req, &m)
if err != nil {
return nil, resp, err
}
return m, resp, nil
}
// UserMigrationStatus gets the status of a specific migration archive.
// id is the migration ID.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#get-the-status-of-a-user-migration
func (s *MigrationService) UserMigrationStatus(ctx context.Context, id int64) (*UserMigration, *Response, error) {
u := fmt.Sprintf("user/migrations/%v", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
m := &UserMigration{}
resp, err := s.client.Do(ctx, req, m)
if err != nil {
return nil, resp, err
}
return m, resp, nil
}
// UserMigrationArchiveURL gets the URL for a specific migration archive.
// id is the migration ID.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#download-a-user-migration-archive
func (s *MigrationService) UserMigrationArchiveURL(ctx context.Context, id int64) (string, error) {
url := fmt.Sprintf("user/migrations/%v/archive", id)
req, err := s.client.NewRequest("GET", url, nil)
if err != nil {
return "", err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
m := &UserMigration{}
var loc string
originalRedirect := s.client.client.CheckRedirect
s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
loc = req.URL.String()
return http.ErrUseLastResponse
}
defer func() {
s.client.client.CheckRedirect = originalRedirect
}()
resp, err := s.client.Do(ctx, req, m)
if err == nil {
return "", errors.New("expected redirect, none provided")
}
loc = resp.Header.Get("Location")
return loc, nil
}
// DeleteUserMigration will delete a previous migration archive.
// id is the migration ID.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#delete-a-user-migration-archive
func (s *MigrationService) DeleteUserMigration(ctx context.Context, id int64) (*Response, error) {
url := fmt.Sprintf("user/migrations/%v/archive", id)
req, err := s.client.NewRequest("DELETE", url, nil)
if err != nil {
return nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
return s.client.Do(ctx, req, nil)
}
// UnlockUserRepository will unlock a repo that was locked for migration.
// id is migration ID.
// You should unlock each migrated repository and delete them when the migration
// is complete and you no longer need the source data.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#unlock-a-user-repository
func (s *MigrationService) UnlockUserRepo(ctx context.Context, id int64, repo string) (*Response, error) {
url := fmt.Sprintf("user/migrations/%v/repos/%v/lock", id, repo)
req, err := s.client.NewRequest("DELETE", url, nil)
if err != nil {
return nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
return s.client.Do(ctx, req, nil)
}

View file

@ -158,6 +158,10 @@ type APIMeta struct {
// An array of IP addresses in CIDR format specifying the addresses // An array of IP addresses in CIDR format specifying the addresses
// which serve GitHub Pages websites. // which serve GitHub Pages websites.
Pages []string `json:"pages,omitempty"` Pages []string `json:"pages,omitempty"`
// An Array of IP addresses specifying the addresses that source imports
// will originate from on GitHub.com.
Importer []string `json:"importer,omitempty"`
} }
// APIMeta returns information about GitHub.com, the service. Or, if you access // APIMeta returns information about GitHub.com, the service. Or, if you access

View file

@ -21,6 +21,7 @@ type OrganizationsService service
type Organization struct { type Organization struct {
Login *string `json:"login,omitempty"` Login *string `json:"login,omitempty"`
ID *int64 `json:"id,omitempty"` ID *int64 `json:"id,omitempty"`
NodeID *string `json:"node_id,omitempty"`
AvatarURL *string `json:"avatar_url,omitempty"` AvatarURL *string `json:"avatar_url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"` HTMLURL *string `json:"html_url,omitempty"`
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
@ -43,7 +44,6 @@ type Organization struct {
BillingEmail *string `json:"billing_email,omitempty"` BillingEmail *string `json:"billing_email,omitempty"`
Type *string `json:"type,omitempty"` Type *string `json:"type,omitempty"`
Plan *Plan `json:"plan,omitempty"` Plan *Plan `json:"plan,omitempty"`
NodeID *string `json:"node_id,omitempty"`
// API URLs // API URLs
URL *string `json:"url,omitempty"` URL *string `json:"url,omitempty"`
@ -75,8 +75,11 @@ func (p Plan) String() string {
// OrganizationsService.ListAll method. // OrganizationsService.ListAll method.
type OrganizationsListOptions struct { type OrganizationsListOptions struct {
// Since filters Organizations by ID. // Since filters Organizations by ID.
Since int `url:"since,omitempty"` Since int64 `url:"since,omitempty"`
// Note: Pagination is powered exclusively by the Since parameter,
// ListOptions.Page has no effect.
// ListOptions.PerPage controls an undocumented GitHub API parameter.
ListOptions ListOptions
} }
@ -98,9 +101,6 @@ func (s *OrganizationsService) ListAll(ctx context.Context, opt *OrganizationsLi
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
orgs := []*Organization{} orgs := []*Organization{}
resp, err := s.client.Do(ctx, req, &orgs) resp, err := s.client.Do(ctx, req, &orgs)
if err != nil { if err != nil {
@ -130,9 +130,6 @@ func (s *OrganizationsService) List(ctx context.Context, user string, opt *ListO
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
var orgs []*Organization var orgs []*Organization
resp, err := s.client.Do(ctx, req, &orgs) resp, err := s.client.Do(ctx, req, &orgs)
if err != nil { if err != nil {
@ -152,9 +149,6 @@ func (s *OrganizationsService) Get(ctx context.Context, org string) (*Organizati
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
organization := new(Organization) organization := new(Organization)
resp, err := s.client.Do(ctx, req, organization) resp, err := s.client.Do(ctx, req, organization)
if err != nil { if err != nil {
@ -174,9 +168,6 @@ func (s *OrganizationsService) GetByID(ctx context.Context, id int64) (*Organiza
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
organization := new(Organization) organization := new(Organization)
resp, err := s.client.Do(ctx, req, organization) resp, err := s.client.Do(ctx, req, organization)
if err != nil { if err != nil {
@ -196,9 +187,6 @@ func (s *OrganizationsService) Edit(ctx context.Context, name string, org *Organ
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
o := new(Organization) o := new(Organization)
resp, err := s.client.Do(ctx, req, o) resp, err := s.client.Do(ctx, req, o)
if err != nil { if err != nil {

View file

@ -37,7 +37,7 @@ func (s *OrganizationsService) ListHooks(ctx context.Context, org string, opt *L
// GetHook returns a single specified Hook. // GetHook returns a single specified Hook.
// //
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#get-single-hook // GitHub API docs: https://developer.github.com/v3/orgs/hooks/#get-single-hook
func (s *OrganizationsService) GetHook(ctx context.Context, org string, id int) (*Hook, *Response, error) { func (s *OrganizationsService) GetHook(ctx context.Context, org string, id int64) (*Hook, *Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) u := fmt.Sprintf("orgs/%v/hooks/%d", org, id)
req, err := s.client.NewRequest("GET", u, nil) req, err := s.client.NewRequest("GET", u, nil)
if err != nil { if err != nil {
@ -71,7 +71,7 @@ func (s *OrganizationsService) CreateHook(ctx context.Context, org string, hook
// EditHook updates a specified Hook. // EditHook updates a specified Hook.
// //
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#edit-a-hook // GitHub API docs: https://developer.github.com/v3/orgs/hooks/#edit-a-hook
func (s *OrganizationsService) EditHook(ctx context.Context, org string, id int, hook *Hook) (*Hook, *Response, error) { func (s *OrganizationsService) EditHook(ctx context.Context, org string, id int64, hook *Hook) (*Hook, *Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) u := fmt.Sprintf("orgs/%v/hooks/%d", org, id)
req, err := s.client.NewRequest("PATCH", u, hook) req, err := s.client.NewRequest("PATCH", u, hook)
if err != nil { if err != nil {
@ -85,7 +85,7 @@ func (s *OrganizationsService) EditHook(ctx context.Context, org string, id int,
// PingHook triggers a 'ping' event to be sent to the Hook. // PingHook triggers a 'ping' event to be sent to the Hook.
// //
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#ping-a-hook // GitHub API docs: https://developer.github.com/v3/orgs/hooks/#ping-a-hook
func (s *OrganizationsService) PingHook(ctx context.Context, org string, id int) (*Response, error) { func (s *OrganizationsService) PingHook(ctx context.Context, org string, id int64) (*Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d/pings", org, id) u := fmt.Sprintf("orgs/%v/hooks/%d/pings", org, id)
req, err := s.client.NewRequest("POST", u, nil) req, err := s.client.NewRequest("POST", u, nil)
if err != nil { if err != nil {
@ -97,7 +97,7 @@ func (s *OrganizationsService) PingHook(ctx context.Context, org string, id int)
// DeleteHook deletes a specified Hook. // DeleteHook deletes a specified Hook.
// //
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#delete-a-hook // GitHub API docs: https://developer.github.com/v3/orgs/hooks/#delete-a-hook
func (s *OrganizationsService) DeleteHook(ctx context.Context, org string, id int) (*Response, error) { func (s *OrganizationsService) DeleteHook(ctx context.Context, org string, id int64) (*Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) u := fmt.Sprintf("orgs/%v/hooks/%d", org, id)
req, err := s.client.NewRequest("DELETE", u, nil) req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil { if err != nil {

View file

@ -59,7 +59,7 @@ type ListMembersOptions struct {
// Possible values are: // Possible values are:
// all - all members of the organization, regardless of role // all - all members of the organization, regardless of role
// admin - organization owners // admin - organization owners
// member - non-organization members // member - non-owner organization members
// //
// Default is "all". // Default is "all".
Role string `url:"role,omitempty"` Role string `url:"role,omitempty"`
@ -297,3 +297,74 @@ func (s *OrganizationsService) ListPendingOrgInvitations(ctx context.Context, or
} }
return pendingInvitations, resp, nil return pendingInvitations, resp, nil
} }
// CreateOrgInvitationOptions specifies the parameters to the OrganizationService.Invite
// method.
type CreateOrgInvitationOptions struct {
// GitHub user ID for the person you are inviting. Not required if you provide Email.
InviteeID *int64 `json:"invitee_id,omitempty"`
// Email address of the person you are inviting, which can be an existing GitHub user.
// Not required if you provide InviteeID
Email *string `json:"email,omitempty"`
// Specify role for new member. Can be one of:
// * admin - Organization owners with full administrative rights to the
// organization and complete access to all repositories and teams.
// * direct_member - Non-owner organization members with ability to see
// other members and join teams by invitation.
// * billing_manager - Non-owner organization members with ability to
// manage the billing settings of your organization.
// Default is "direct_member".
Role *string `json:"role"`
TeamID []int64 `json:"team_ids"`
}
// CreateOrgInvitation invites people to an organization by using their GitHub user ID or their email address.
// In order to create invitations in an organization,
// the authenticated user must be an organization owner.
//
// https://developer.github.com/v3/orgs/members/#create-organization-invitation
func (s *OrganizationsService) CreateOrgInvitation(ctx context.Context, org string, opt *CreateOrgInvitationOptions) (*Invitation, *Response, error) {
u := fmt.Sprintf("orgs/%v/invitations", org)
req, err := s.client.NewRequest("POST", u, opt)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeOrganizationInvitationPreview)
var invitation *Invitation
resp, err := s.client.Do(ctx, req, &invitation)
if err != nil {
return nil, resp, err
}
return invitation, resp, nil
}
// ListOrgInvitationTeams lists all teams associated with an invitation. In order to see invitations in an organization,
// the authenticated user must be an organization owner.
//
// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-organization-invitation-teams
func (s *OrganizationsService) ListOrgInvitationTeams(ctx context.Context, org, invitationID string, opt *ListOptions) ([]*Team, *Response, error) {
u := fmt.Sprintf("orgs/%v/invitations/%v/teams", org, invitationID)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeOrganizationInvitationPreview)
var orgInvitationTeams []*Team
resp, err := s.client.Do(ctx, req, &orgInvitationTeams)
if err != nil {
return nil, resp, err
}
return orgInvitationTeams, resp, nil
}

View file

@ -26,6 +26,7 @@ type Project struct {
Number *int `json:"number,omitempty"` Number *int `json:"number,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"` CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"` UpdatedAt *Timestamp `json:"updated_at,omitempty"`
NodeID *string `json:"node_id,omitempty"`
// The User object that generated the project. // The User object that generated the project.
Creator *User `json:"creator,omitempty"` Creator *User `json:"creator,omitempty"`
@ -45,7 +46,7 @@ func (s *ProjectsService) GetProject(ctx context.Context, id int64) (*Project, *
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview) req.Header.Set("Accept", mediaTypeProjectsPreview)
project := &Project{} project := &Project{}
@ -83,7 +84,7 @@ func (s *ProjectsService) UpdateProject(ctx context.Context, id int64, opt *Proj
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview) req.Header.Set("Accept", mediaTypeProjectsPreview)
project := &Project{} project := &Project{}
@ -120,6 +121,7 @@ type ProjectColumn struct {
ProjectURL *string `json:"project_url,omitempty"` ProjectURL *string `json:"project_url,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"` CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"` UpdatedAt *Timestamp `json:"updated_at,omitempty"`
NodeID *string `json:"node_id,omitempty"`
} }
// ListProjectColumns lists the columns of a GitHub Project for a repo. // ListProjectColumns lists the columns of a GitHub Project for a repo.
@ -137,7 +139,7 @@ func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID int6
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview) req.Header.Set("Accept", mediaTypeProjectsPreview)
columns := []*ProjectColumn{} columns := []*ProjectColumn{}
@ -159,7 +161,7 @@ func (s *ProjectsService) GetProjectColumn(ctx context.Context, id int64) (*Proj
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview) req.Header.Set("Accept", mediaTypeProjectsPreview)
column := &ProjectColumn{} column := &ProjectColumn{}
@ -189,7 +191,7 @@ func (s *ProjectsService) CreateProjectColumn(ctx context.Context, projectID int
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview) req.Header.Set("Accept", mediaTypeProjectsPreview)
column := &ProjectColumn{} column := &ProjectColumn{}
@ -211,7 +213,7 @@ func (s *ProjectsService) UpdateProjectColumn(ctx context.Context, columnID int6
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview) req.Header.Set("Accept", mediaTypeProjectsPreview)
column := &ProjectColumn{} column := &ProjectColumn{}
@ -275,15 +277,27 @@ type ProjectCard struct {
Creator *User `json:"creator,omitempty"` Creator *User `json:"creator,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"` CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"` UpdatedAt *Timestamp `json:"updated_at,omitempty"`
NodeID *string `json:"node_id,omitempty"`
Archived *bool `json:"archived,omitempty"`
// The following fields are only populated by Webhook events. // The following fields are only populated by Webhook events.
ColumnID *int64 `json:"column_id,omitempty"` ColumnID *int64 `json:"column_id,omitempty"`
} }
// ProjectCardListOptions specifies the optional parameters to the
// ProjectsService.ListProjectCards method.
type ProjectCardListOptions struct {
// ArchivedState is used to list all, archived, or not_archived project cards.
// Defaults to not_archived when you omit this parameter.
ArchivedState *string `url:"archived_state,omitempty"`
ListOptions
}
// ListProjectCards lists the cards in a column of a GitHub Project. // ListProjectCards lists the cards in a column of a GitHub Project.
// //
// GitHub API docs: https://developer.github.com/v3/projects/cards/#list-project-cards // GitHub API docs: https://developer.github.com/v3/projects/cards/#list-project-cards
func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int64, opt *ListOptions) ([]*ProjectCard, *Response, error) { func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int64, opt *ProjectCardListOptions) ([]*ProjectCard, *Response, error) {
u := fmt.Sprintf("projects/columns/%v/cards", columnID) u := fmt.Sprintf("projects/columns/%v/cards", columnID)
u, err := addOptions(u, opt) u, err := addOptions(u, opt)
if err != nil { if err != nil {
@ -295,7 +309,7 @@ func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int64,
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview) req.Header.Set("Accept", mediaTypeProjectsPreview)
cards := []*ProjectCard{} cards := []*ProjectCard{}
@ -317,7 +331,7 @@ func (s *ProjectsService) GetProjectCard(ctx context.Context, columnID int64) (*
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview) req.Header.Set("Accept", mediaTypeProjectsPreview)
card := &ProjectCard{} card := &ProjectCard{}
@ -340,6 +354,9 @@ type ProjectCardOptions struct {
ContentID int64 `json:"content_id,omitempty"` ContentID int64 `json:"content_id,omitempty"`
// The type of content to associate with this card. Possible values are: "Issue". // The type of content to associate with this card. Possible values are: "Issue".
ContentType string `json:"content_type,omitempty"` ContentType string `json:"content_type,omitempty"`
// Use true to archive a project card.
// Specify false if you need to restore a previously archived project card.
Archived *bool `json:"archived,omitempty"`
} }
// CreateProjectCard creates a card in the specified column of a GitHub Project. // CreateProjectCard creates a card in the specified column of a GitHub Project.
@ -352,7 +369,7 @@ func (s *ProjectsService) CreateProjectCard(ctx context.Context, columnID int64,
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview) req.Header.Set("Accept", mediaTypeProjectsPreview)
card := &ProjectCard{} card := &ProjectCard{}
@ -374,7 +391,7 @@ func (s *ProjectsService) UpdateProjectCard(ctx context.Context, cardID int64, o
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview) req.Header.Set("Accept", mediaTypeProjectsPreview)
card := &ProjectCard{} card := &ProjectCard{}

View file

@ -9,6 +9,7 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"strings"
"time" "time"
) )
@ -29,6 +30,7 @@ type PullRequest struct {
UpdatedAt *time.Time `json:"updated_at,omitempty"` UpdatedAt *time.Time `json:"updated_at,omitempty"`
ClosedAt *time.Time `json:"closed_at,omitempty"` ClosedAt *time.Time `json:"closed_at,omitempty"`
MergedAt *time.Time `json:"merged_at,omitempty"` MergedAt *time.Time `json:"merged_at,omitempty"`
Labels []*Label `json:"labels,omitempty"`
User *User `json:"user,omitempty"` User *User `json:"user,omitempty"`
Merged *bool `json:"merged,omitempty"` Merged *bool `json:"merged,omitempty"`
Mergeable *bool `json:"mergeable,omitempty"` Mergeable *bool `json:"mergeable,omitempty"`
@ -46,6 +48,8 @@ type PullRequest struct {
StatusesURL *string `json:"statuses_url,omitempty"` StatusesURL *string `json:"statuses_url,omitempty"`
DiffURL *string `json:"diff_url,omitempty"` DiffURL *string `json:"diff_url,omitempty"`
PatchURL *string `json:"patch_url,omitempty"` PatchURL *string `json:"patch_url,omitempty"`
CommitsURL *string `json:"commits_url,omitempty"`
CommentsURL *string `json:"comments_url,omitempty"`
ReviewCommentsURL *string `json:"review_comments_url,omitempty"` ReviewCommentsURL *string `json:"review_comments_url,omitempty"`
ReviewCommentURL *string `json:"review_comment_url,omitempty"` ReviewCommentURL *string `json:"review_comment_url,omitempty"`
Assignee *User `json:"assignee,omitempty"` Assignee *User `json:"assignee,omitempty"`
@ -54,9 +58,14 @@ type PullRequest struct {
MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"`
AuthorAssociation *string `json:"author_association,omitempty"` AuthorAssociation *string `json:"author_association,omitempty"`
NodeID *string `json:"node_id,omitempty"` NodeID *string `json:"node_id,omitempty"`
RequestedReviewers []*User `json:"requested_reviewers,omitempty"`
Head *PullRequestBranch `json:"head,omitempty"` Head *PullRequestBranch `json:"head,omitempty"`
Base *PullRequestBranch `json:"base,omitempty"` Base *PullRequestBranch `json:"base,omitempty"`
// ActiveLockReason is populated only when LockReason is provided while locking the pull request.
// Possible values are: "off-topic", "too heated", "resolved", and "spam".
ActiveLockReason *string `json:"active_lock_reason,omitempty"`
} }
func (p PullRequest) String() string { func (p PullRequest) String() string {
@ -114,7 +123,8 @@ func (s *PullRequestsService) List(ctx context.Context, owner string, repo strin
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) acceptHeaders := []string{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var pulls []*PullRequest var pulls []*PullRequest
resp, err := s.client.Do(ctx, req, &pulls) resp, err := s.client.Do(ctx, req, &pulls)
@ -136,7 +146,8 @@ func (s *PullRequestsService) Get(ctx context.Context, owner string, repo string
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) acceptHeaders := []string{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
pull := new(PullRequest) pull := new(PullRequest)
resp, err := s.client.Do(ctx, req, pull) resp, err := s.client.Do(ctx, req, pull)
@ -194,7 +205,7 @@ func (s *PullRequestsService) Create(ctx context.Context, owner string, repo str
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
p := new(PullRequest) p := new(PullRequest)
resp, err := s.client.Do(ctx, req, p) resp, err := s.client.Do(ctx, req, p)
@ -243,7 +254,8 @@ func (s *PullRequestsService) Edit(ctx context.Context, owner string, repo strin
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) acceptHeaders := []string{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
p := new(PullRequest) p := new(PullRequest)
resp, err := s.client.Do(ctx, req, p) resp, err := s.client.Do(ctx, req, p)

View file

@ -14,10 +14,11 @@ import (
// PullRequestComment represents a comment left on a pull request. // PullRequestComment represents a comment left on a pull request.
type PullRequestComment struct { type PullRequestComment struct {
ID *int64 `json:"id,omitempty"` ID *int64 `json:"id,omitempty"`
InReplyTo *int64 `json:"in_reply_to,omitempty"` InReplyTo *int64 `json:"in_reply_to_id,omitempty"`
Body *string `json:"body,omitempty"` Body *string `json:"body,omitempty"`
Path *string `json:"path,omitempty"` Path *string `json:"path,omitempty"`
DiffHunk *string `json:"diff_hunk,omitempty"` DiffHunk *string `json:"diff_hunk,omitempty"`
PullRequestReviewID *int64 `json:"pull_request_review_id,omitempty"`
Position *int `json:"position,omitempty"` Position *int `json:"position,omitempty"`
OriginalPosition *int `json:"original_position,omitempty"` OriginalPosition *int `json:"original_position,omitempty"`
CommitID *string `json:"commit_id,omitempty"` CommitID *string `json:"commit_id,omitempty"`
@ -26,6 +27,9 @@ type PullRequestComment struct {
Reactions *Reactions `json:"reactions,omitempty"` Reactions *Reactions `json:"reactions,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"` CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"` UpdatedAt *time.Time `json:"updated_at,omitempty"`
// AuthorAssociation is the comment author's relationship to the pull request's repository.
// Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE".
AuthorAssociation *string `json:"author_association,omitempty"`
URL *string `json:"url,omitempty"` URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"` HTMLURL *string `json:"html_url,omitempty"`
PullRequestURL *string `json:"pull_request_url,omitempty"` PullRequestURL *string `json:"pull_request_url,omitempty"`
@ -87,8 +91,8 @@ func (s *PullRequestsService) ListComments(ctx context.Context, owner string, re
// GetComment fetches the specified pull request comment. // GetComment fetches the specified pull request comment.
// //
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#get-a-single-comment // GitHub API docs: https://developer.github.com/v3/pulls/comments/#get-a-single-comment
func (s *PullRequestsService) GetComment(ctx context.Context, owner string, repo string, number int) (*PullRequestComment, *Response, error) { func (s *PullRequestsService) GetComment(ctx context.Context, owner string, repo string, commentID int64) (*PullRequestComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, number) u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("GET", u, nil) req, err := s.client.NewRequest("GET", u, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -125,11 +129,38 @@ func (s *PullRequestsService) CreateComment(ctx context.Context, owner string, r
return c, resp, nil return c, resp, nil
} }
// CreateCommentInReplyTo creates a new comment as a reply to an existing pull request comment.
//
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#alternative-input
func (s *PullRequestsService) CreateCommentInReplyTo(ctx context.Context, owner string, repo string, number int, body string, commentID int64) (*PullRequestComment, *Response, error) {
comment := &struct {
Body string `json:"body,omitempty"`
InReplyTo int64 `json:"in_reply_to,omitempty"`
}{
Body: body,
InReplyTo: commentID,
}
u := fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number)
req, err := s.client.NewRequest("POST", u, comment)
if err != nil {
return nil, nil, err
}
c := new(PullRequestComment)
resp, err := s.client.Do(ctx, req, c)
if err != nil {
return nil, resp, err
}
return c, resp, nil
}
// EditComment updates a pull request comment. // EditComment updates a pull request comment.
// A non-nil comment.Body must be provided. Other comment fields should be left nil.
// //
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#edit-a-comment // GitHub API docs: https://developer.github.com/v3/pulls/comments/#edit-a-comment
func (s *PullRequestsService) EditComment(ctx context.Context, owner string, repo string, number int, comment *PullRequestComment) (*PullRequestComment, *Response, error) { func (s *PullRequestsService) EditComment(ctx context.Context, owner string, repo string, commentID int64, comment *PullRequestComment) (*PullRequestComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, number) u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("PATCH", u, comment) req, err := s.client.NewRequest("PATCH", u, comment)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -147,8 +178,8 @@ func (s *PullRequestsService) EditComment(ctx context.Context, owner string, rep
// DeleteComment deletes a pull request comment. // DeleteComment deletes a pull request comment.
// //
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#delete-a-comment // GitHub API docs: https://developer.github.com/v3/pulls/comments/#delete-a-comment
func (s *PullRequestsService) DeleteComment(ctx context.Context, owner string, repo string, number int) (*Response, error) { func (s *PullRequestsService) DeleteComment(ctx context.Context, owner string, repo string, commentID int64) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, number) u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("DELETE", u, nil) req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -32,9 +32,6 @@ func (s *PullRequestsService) RequestReviewers(ctx context.Context, owner, repo
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeTeamReviewPreview)
r := new(PullRequest) r := new(PullRequest)
resp, err := s.client.Do(ctx, req, r) resp, err := s.client.Do(ctx, req, r)
if err != nil { if err != nil {
@ -59,9 +56,6 @@ func (s *PullRequestsService) ListReviewers(ctx context.Context, owner, repo str
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeTeamReviewPreview)
reviewers := new(Reviewers) reviewers := new(Reviewers)
resp, err := s.client.Do(ctx, req, reviewers) resp, err := s.client.Do(ctx, req, reviewers)
if err != nil { if err != nil {
@ -81,8 +75,5 @@ func (s *PullRequestsService) RemoveReviewers(ctx context.Context, owner, repo s
return nil, err return nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeTeamReviewPreview)
return s.client.Do(ctx, req, nil) return s.client.Do(ctx, req, nil)
} }

View file

@ -94,7 +94,7 @@ func (s *PullRequestsService) ListReviews(ctx context.Context, owner, repo strin
// Read more about it here - https://github.com/google/go-github/issues/540 // Read more about it here - https://github.com/google/go-github/issues/540
// //
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-a-single-review // GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-a-single-review
func (s *PullRequestsService) GetReview(ctx context.Context, owner, repo string, number, reviewID int64) (*PullRequestReview, *Response, error) { func (s *PullRequestsService) GetReview(ctx context.Context, owner, repo string, number int, reviewID int64) (*PullRequestReview, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID)
req, err := s.client.NewRequest("GET", u, nil) req, err := s.client.NewRequest("GET", u, nil)
@ -118,7 +118,7 @@ func (s *PullRequestsService) GetReview(ctx context.Context, owner, repo string,
// Read more about it here - https://github.com/google/go-github/issues/540 // Read more about it here - https://github.com/google/go-github/issues/540
// //
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#delete-a-pending-review // GitHub API docs: https://developer.github.com/v3/pulls/reviews/#delete-a-pending-review
func (s *PullRequestsService) DeletePendingReview(ctx context.Context, owner, repo string, number, reviewID int64) (*PullRequestReview, *Response, error) { func (s *PullRequestsService) DeletePendingReview(ctx context.Context, owner, repo string, number int, reviewID int64) (*PullRequestReview, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID)
req, err := s.client.NewRequest("DELETE", u, nil) req, err := s.client.NewRequest("DELETE", u, nil)
@ -142,7 +142,7 @@ func (s *PullRequestsService) DeletePendingReview(ctx context.Context, owner, re
// Read more about it here - https://github.com/google/go-github/issues/540 // Read more about it here - https://github.com/google/go-github/issues/540
// //
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-comments-for-a-single-review // GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-comments-for-a-single-review
func (s *PullRequestsService) ListReviewComments(ctx context.Context, owner, repo string, number, reviewID int64, opt *ListOptions) ([]*PullRequestComment, *Response, error) { func (s *PullRequestsService) ListReviewComments(ctx context.Context, owner, repo string, number int, reviewID int64, opt *ListOptions) ([]*PullRequestComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/comments", owner, repo, number, reviewID) u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/comments", owner, repo, number, reviewID)
u, err := addOptions(u, opt) u, err := addOptions(u, opt)
if err != nil { if err != nil {
@ -194,7 +194,7 @@ func (s *PullRequestsService) CreateReview(ctx context.Context, owner, repo stri
// Read more about it here - https://github.com/google/go-github/issues/540 // Read more about it here - https://github.com/google/go-github/issues/540
// //
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#submit-a-pull-request-review // GitHub API docs: https://developer.github.com/v3/pulls/reviews/#submit-a-pull-request-review
func (s *PullRequestsService) SubmitReview(ctx context.Context, owner, repo string, number, reviewID int64, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) { func (s *PullRequestsService) SubmitReview(ctx context.Context, owner, repo string, number int, reviewID int64, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/events", owner, repo, number, reviewID) u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/events", owner, repo, number, reviewID)
req, err := s.client.NewRequest("POST", u, review) req, err := s.client.NewRequest("POST", u, review)
@ -218,7 +218,7 @@ func (s *PullRequestsService) SubmitReview(ctx context.Context, owner, repo stri
// Read more about it here - https://github.com/google/go-github/issues/540 // Read more about it here - https://github.com/google/go-github/issues/540
// //
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#dismiss-a-pull-request-review // GitHub API docs: https://developer.github.com/v3/pulls/reviews/#dismiss-a-pull-request-review
func (s *PullRequestsService) DismissReview(ctx context.Context, owner, repo string, number, reviewID int64, review *PullRequestReviewDismissalRequest) (*PullRequestReview, *Response, error) { func (s *PullRequestsService) DismissReview(ctx context.Context, owner, repo string, number int, reviewID int64, review *PullRequestReviewDismissalRequest) (*PullRequestReview, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/dismissals", owner, repo, number, reviewID) u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/dismissals", owner, repo, number, reviewID)
req, err := s.client.NewRequest("PUT", u, review) req, err := s.client.NewRequest("PUT", u, review)

View file

@ -21,6 +21,7 @@ type Reaction struct {
// ID is the Reaction ID. // ID is the Reaction ID.
ID *int64 `json:"id,omitempty"` ID *int64 `json:"id,omitempty"`
User *User `json:"user,omitempty"` User *User `json:"user,omitempty"`
NodeID *string `json:"node_id,omitempty"`
// Content is the type of reaction. // Content is the type of reaction.
// Possible values are: // Possible values are:
// "+1", "-1", "laugh", "confused", "heart", "hooray". // "+1", "-1", "laugh", "confused", "heart", "hooray".
@ -58,7 +59,7 @@ func (s *ReactionsService) ListCommentReactions(ctx context.Context, owner, repo
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview) req.Header.Set("Accept", mediaTypeReactionsPreview)
var m []*Reaction var m []*Reaction
@ -84,7 +85,7 @@ func (s ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview) req.Header.Set("Accept", mediaTypeReactionsPreview)
m := &Reaction{} m := &Reaction{}
@ -111,7 +112,7 @@ func (s *ReactionsService) ListIssueReactions(ctx context.Context, owner, repo s
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview) req.Header.Set("Accept", mediaTypeReactionsPreview)
var m []*Reaction var m []*Reaction
@ -137,7 +138,7 @@ func (s ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo s
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview) req.Header.Set("Accept", mediaTypeReactionsPreview)
m := &Reaction{} m := &Reaction{}
@ -164,7 +165,7 @@ func (s *ReactionsService) ListIssueCommentReactions(ctx context.Context, owner,
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview) req.Header.Set("Accept", mediaTypeReactionsPreview)
var m []*Reaction var m []*Reaction
@ -190,7 +191,7 @@ func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner,
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview) req.Header.Set("Accept", mediaTypeReactionsPreview)
m := &Reaction{} m := &Reaction{}
@ -217,7 +218,7 @@ func (s *ReactionsService) ListPullRequestCommentReactions(ctx context.Context,
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview) req.Header.Set("Accept", mediaTypeReactionsPreview)
var m []*Reaction var m []*Reaction
@ -243,7 +244,7 @@ func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context,
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches. // TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview) req.Header.Set("Accept", mediaTypeReactionsPreview)
m := &Reaction{} m := &Reaction{}

View file

@ -7,7 +7,6 @@ package github
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"strings" "strings"
) )
@ -21,6 +20,7 @@ type RepositoriesService service
// Repository represents a GitHub repository. // Repository represents a GitHub repository.
type Repository struct { type Repository struct {
ID *int64 `json:"id,omitempty"` ID *int64 `json:"id,omitempty"`
NodeID *string `json:"node_id,omitempty"`
Owner *User `json:"owner,omitempty"` Owner *User `json:"owner,omitempty"`
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
FullName *string `json:"full_name,omitempty"` FullName *string `json:"full_name,omitempty"`
@ -179,7 +179,7 @@ func (s *RepositoriesService) List(ctx context.Context, user string, opt *Reposi
} }
// TODO: remove custom Accept headers when APIs fully launch. // TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeLicensesPreview, mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview} acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var repos []*Repository var repos []*Repository
@ -217,7 +217,7 @@ func (s *RepositoriesService) ListByOrg(ctx context.Context, org string, opt *Re
} }
// TODO: remove custom Accept headers when APIs fully launch. // TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeLicensesPreview, mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview} acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var repos []*Repository var repos []*Repository
@ -298,7 +298,7 @@ func (s *RepositoriesService) Get(ctx context.Context, owner, repo string) (*Rep
// TODO: remove custom Accept header when the license support fully launches // TODO: remove custom Accept header when the license support fully launches
// https://developer.github.com/v3/licenses/#get-a-repositorys-license // https://developer.github.com/v3/licenses/#get-a-repositorys-license
acceptHeaders := []string{mediaTypeLicensesPreview, mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview} acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
repository := new(Repository) repository := new(Repository)
@ -342,10 +342,6 @@ func (s *RepositoriesService) GetByID(ctx context.Context, id int64) (*Repositor
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when the license support fully launches
// https://developer.github.com/v3/licenses/#get-a-repositorys-license
req.Header.Set("Accept", mediaTypeLicensesPreview)
repository := new(Repository) repository := new(Repository)
resp, err := s.client.Do(ctx, req, repository) resp, err := s.client.Do(ctx, req, repository)
if err != nil { if err != nil {
@ -558,6 +554,12 @@ type RequiredStatusChecks struct {
Contexts []string `json:"contexts"` Contexts []string `json:"contexts"`
} }
// RequiredStatusChecksRequest represents a request to edit a protected branch's status checks.
type RequiredStatusChecksRequest struct {
Strict *bool `json:"strict,omitempty"`
Contexts []string `json:"contexts,omitempty"`
}
// PullRequestReviewsEnforcement represents the pull request reviews enforcement of a protected branch. // PullRequestReviewsEnforcement represents the pull request reviews enforcement of a protected branch.
type PullRequestReviewsEnforcement struct { type PullRequestReviewsEnforcement struct {
// Specifies which users and teams can dismiss pull request reviews. // Specifies which users and teams can dismiss pull request reviews.
@ -566,45 +568,26 @@ type PullRequestReviewsEnforcement struct {
DismissStaleReviews bool `json:"dismiss_stale_reviews"` DismissStaleReviews bool `json:"dismiss_stale_reviews"`
// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner. // RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"` RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"`
// RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged.
// Valid values are 1-6.
RequiredApprovingReviewCount int `json:"required_approving_review_count"`
} }
// PullRequestReviewsEnforcementRequest represents request to set the pull request review // PullRequestReviewsEnforcementRequest represents request to set the pull request review
// enforcement of a protected branch. It is separate from PullRequestReviewsEnforcement above // enforcement of a protected branch. It is separate from PullRequestReviewsEnforcement above
// because the request structure is different from the response structure. // because the request structure is different from the response structure.
type PullRequestReviewsEnforcementRequest struct { type PullRequestReviewsEnforcementRequest struct {
// Specifies which users and teams should be allowed to dismiss pull request reviews. Can be nil to disable the restrictions. // Specifies which users and teams should be allowed to dismiss pull request reviews.
DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions"` // User and team dismissal restrictions are only available for
// organization-owned repositories. Must be nil for personal repositories.
DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions,omitempty"`
// Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. (Required) // Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. (Required)
DismissStaleReviews bool `json:"dismiss_stale_reviews"` DismissStaleReviews bool `json:"dismiss_stale_reviews"`
// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner. // RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"` RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"`
} // RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged.
// Valid values are 1-6.
// MarshalJSON implements the json.Marshaler interface. RequiredApprovingReviewCount int `json:"required_approving_review_count"`
// Converts nil value of PullRequestReviewsEnforcementRequest.DismissalRestrictionsRequest to empty array
func (req PullRequestReviewsEnforcementRequest) MarshalJSON() ([]byte, error) {
if req.DismissalRestrictionsRequest == nil {
newReq := struct {
R []interface{} `json:"dismissal_restrictions"`
D bool `json:"dismiss_stale_reviews"`
O bool `json:"require_code_owner_reviews"`
}{
R: []interface{}{},
D: req.DismissStaleReviews,
O: req.RequireCodeOwnerReviews,
}
return json.Marshal(newReq)
}
newReq := struct {
R *DismissalRestrictionsRequest `json:"dismissal_restrictions"`
D bool `json:"dismiss_stale_reviews"`
O bool `json:"require_code_owner_reviews"`
}{
R: req.DismissalRestrictionsRequest,
D: req.DismissStaleReviews,
O: req.RequireCodeOwnerReviews,
}
return json.Marshal(newReq)
} }
// PullRequestReviewsEnforcementUpdate represents request to patch the pull request review // PullRequestReviewsEnforcementUpdate represents request to patch the pull request review
@ -617,6 +600,9 @@ type PullRequestReviewsEnforcementUpdate struct {
DismissStaleReviews *bool `json:"dismiss_stale_reviews,omitempty"` DismissStaleReviews *bool `json:"dismiss_stale_reviews,omitempty"`
// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner. // RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
RequireCodeOwnerReviews bool `json:"require_code_owner_reviews,omitempty"` RequireCodeOwnerReviews bool `json:"require_code_owner_reviews,omitempty"`
// RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged.
// Valid values are 1 - 6.
RequiredApprovingReviewCount int `json:"required_approving_review_count"`
} }
// AdminEnforcement represents the configuration to enforce required status checks for repository administrators. // AdminEnforcement represents the configuration to enforce required status checks for repository administrators.
@ -657,11 +643,12 @@ type DismissalRestrictions struct {
// restriction to allows only specific users or teams to dimiss pull request reviews. It is // restriction to allows only specific users or teams to dimiss pull request reviews. It is
// separate from DismissalRestrictions above because the request structure is // separate from DismissalRestrictions above because the request structure is
// different from the response structure. // different from the response structure.
// Note: Both Users and Teams must be nil, or both must be non-nil.
type DismissalRestrictionsRequest struct { type DismissalRestrictionsRequest struct {
// The list of user logins who can dismiss pull request reviews. (Required; use []string{} instead of nil for empty list.) // The list of user logins who can dismiss pull request reviews. (Required; use nil to disable dismissal_restrictions or &[]string{} otherwise.)
Users []string `json:"users"` Users *[]string `json:"users,omitempty"`
// The list of team slugs which can dismiss pull request reviews. (Required; use []string{} instead of nil for empty list.) // The list of team slugs which can dismiss pull request reviews. (Required; use nil to disable dismissal_restrictions or &[]string{} otherwise.)
Teams []string `json:"teams"` Teams *[]string `json:"teams,omitempty"`
} }
// ListBranches lists branches for the specified repository. // ListBranches lists branches for the specified repository.
@ -680,7 +667,7 @@ func (s *RepositoriesService) ListBranches(ctx context.Context, owner string, re
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
var branches []*Branch var branches []*Branch
resp, err := s.client.Do(ctx, req, &branches) resp, err := s.client.Do(ctx, req, &branches)
@ -702,7 +689,7 @@ func (s *RepositoriesService) GetBranch(ctx context.Context, owner, repo, branch
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
b := new(Branch) b := new(Branch)
resp, err := s.client.Do(ctx, req, b) resp, err := s.client.Do(ctx, req, b)
@ -724,7 +711,7 @@ func (s *RepositoriesService) GetBranchProtection(ctx context.Context, owner, re
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
p := new(Protection) p := new(Protection)
resp, err := s.client.Do(ctx, req, p) resp, err := s.client.Do(ctx, req, p)
@ -746,7 +733,7 @@ func (s *RepositoriesService) GetRequiredStatusChecks(ctx context.Context, owner
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
p := new(RequiredStatusChecks) p := new(RequiredStatusChecks)
resp, err := s.client.Do(ctx, req, p) resp, err := s.client.Do(ctx, req, p)
@ -768,7 +755,7 @@ func (s *RepositoriesService) ListRequiredStatusChecksContexts(ctx context.Conte
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
resp, err = s.client.Do(ctx, req, &contexts) resp, err = s.client.Do(ctx, req, &contexts)
if err != nil { if err != nil {
@ -789,7 +776,7 @@ func (s *RepositoriesService) UpdateBranchProtection(ctx context.Context, owner,
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
p := new(Protection) p := new(Protection)
resp, err := s.client.Do(ctx, req, p) resp, err := s.client.Do(ctx, req, p)
@ -811,11 +798,30 @@ func (s *RepositoriesService) RemoveBranchProtection(ctx context.Context, owner,
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
return s.client.Do(ctx, req, nil) return s.client.Do(ctx, req, nil)
} }
// UpdateRequiredStatusChecks updates the required status checks for a given protected branch.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-required-status-checks-of-protected-branch
func (s *RepositoriesService) UpdateRequiredStatusChecks(ctx context.Context, owner, repo, branch string, sreq *RequiredStatusChecksRequest) (*RequiredStatusChecks, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch)
req, err := s.client.NewRequest("PATCH", u, sreq)
if err != nil {
return nil, nil, err
}
sc := new(RequiredStatusChecks)
resp, err := s.client.Do(ctx, req, sc)
if err != nil {
return nil, resp, err
}
return sc, resp, nil
}
// License gets the contents of a repository's license if one is detected. // License gets the contents of a repository's license if one is detected.
// //
// GitHub API docs: https://developer.github.com/v3/licenses/#get-the-contents-of-a-repositorys-license // GitHub API docs: https://developer.github.com/v3/licenses/#get-the-contents-of-a-repositorys-license
@ -846,7 +852,7 @@ func (s *RepositoriesService) GetPullRequestReviewEnforcement(ctx context.Contex
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
r := new(PullRequestReviewsEnforcement) r := new(PullRequestReviewsEnforcement)
resp, err := s.client.Do(ctx, req, r) resp, err := s.client.Do(ctx, req, r)
@ -869,7 +875,7 @@ func (s *RepositoriesService) UpdatePullRequestReviewEnforcement(ctx context.Con
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
r := new(PullRequestReviewsEnforcement) r := new(PullRequestReviewsEnforcement)
resp, err := s.client.Do(ctx, req, r) resp, err := s.client.Do(ctx, req, r)
@ -897,7 +903,7 @@ func (s *RepositoriesService) DisableDismissalRestrictions(ctx context.Context,
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
r := new(PullRequestReviewsEnforcement) r := new(PullRequestReviewsEnforcement)
resp, err := s.client.Do(ctx, req, r) resp, err := s.client.Do(ctx, req, r)
@ -919,7 +925,7 @@ func (s *RepositoriesService) RemovePullRequestReviewEnforcement(ctx context.Con
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
return s.client.Do(ctx, req, nil) return s.client.Do(ctx, req, nil)
} }
@ -935,7 +941,7 @@ func (s *RepositoriesService) GetAdminEnforcement(ctx context.Context, owner, re
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
r := new(AdminEnforcement) r := new(AdminEnforcement)
resp, err := s.client.Do(ctx, req, r) resp, err := s.client.Do(ctx, req, r)
@ -958,7 +964,7 @@ func (s *RepositoriesService) AddAdminEnforcement(ctx context.Context, owner, re
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
r := new(AdminEnforcement) r := new(AdminEnforcement)
resp, err := s.client.Do(ctx, req, r) resp, err := s.client.Do(ctx, req, r)
@ -980,7 +986,7 @@ func (s *RepositoriesService) RemoveAdminEnforcement(ctx context.Context, owner,
} }
// TODO: remove custom Accept header when this API fully launches // TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
return s.client.Do(ctx, req, nil) return s.client.Do(ctx, req, nil)
} }
@ -1043,7 +1049,7 @@ func (s *RepositoriesService) ReplaceAllTopics(ctx context.Context, owner, repo
// TransferRequest represents a request to transfer a repository. // TransferRequest represents a request to transfer a repository.
type TransferRequest struct { type TransferRequest struct {
NewOwner string `json:"new_owner"` NewOwner string `json:"new_owner"`
TeamID []int64 `json:"team_id,omitempty"` TeamID []int64 `json:"team_ids,omitempty"`
} }
// Transfer transfers a repository from one account or organization to another. // Transfer transfers a repository from one account or organization to another.

View file

@ -218,7 +218,7 @@ func (s *RepositoriesService) GetCommitSHA1(ctx context.Context, owner, repo, re
// CompareCommits compares a range of commits with each other. // CompareCommits compares a range of commits with each other.
// todo: support media formats - https://github.com/google/go-github/issues/6 // todo: support media formats - https://github.com/google/go-github/issues/6
// //
// GitHub API docs: https://developer.github.com/v3/repos/commits/index.html#compare-two-commits // GitHub API docs: https://developer.github.com/v3/repos/commits/#compare-two-commits
func (s *RepositoriesService) CompareCommits(ctx context.Context, owner, repo string, base, head string) (*CommitsComparison, *Response, error) { func (s *RepositoriesService) CompareCommits(ctx context.Context, owner, repo string, base, head string) (*CommitsComparison, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, base, head) u := fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, base, head)

View file

@ -23,6 +23,8 @@ type Metric struct {
type CommunityHealthFiles struct { type CommunityHealthFiles struct {
CodeOfConduct *Metric `json:"code_of_conduct"` CodeOfConduct *Metric `json:"code_of_conduct"`
Contributing *Metric `json:"contributing"` Contributing *Metric `json:"contributing"`
IssueTemplate *Metric `json:"issue_template"`
PullRequestTemplate *Metric `json:"pull_request_template"`
License *Metric `json:"license"` License *Metric `json:"license"`
Readme *Metric `json:"readme"` Readme *Metric `json:"readme"`
} }

View file

@ -9,7 +9,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings"
) )
// Deployment represents a deployment in a repo // Deployment represents a deployment in a repo
@ -76,9 +75,6 @@ func (s *RepositoriesService) ListDeployments(ctx context.Context, owner, repo s
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
var deployments []*Deployment var deployments []*Deployment
resp, err := s.client.Do(ctx, req, &deployments) resp, err := s.client.Do(ctx, req, &deployments)
if err != nil { if err != nil {
@ -99,9 +95,6 @@ func (s *RepositoriesService) GetDeployment(ctx context.Context, owner, repo str
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
deployment := new(Deployment) deployment := new(Deployment)
resp, err := s.client.Do(ctx, req, deployment) resp, err := s.client.Do(ctx, req, deployment)
if err != nil { if err != nil {
@ -123,8 +116,7 @@ func (s *RepositoriesService) CreateDeployment(ctx context.Context, owner, repo
} }
// TODO: remove custom Accept headers when APIs fully launch. // TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeGraphQLNodeIDPreview} req.Header.Set("Accept", mediaTypeDeploymentStatusPreview)
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
d := new(Deployment) d := new(Deployment)
resp, err := s.client.Do(ctx, req, d) resp, err := s.client.Do(ctx, req, d)
@ -176,9 +168,6 @@ func (s *RepositoriesService) ListDeploymentStatuses(ctx context.Context, owner,
return nil, nil, err return nil, nil, err
} }
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview)
var statuses []*DeploymentStatus var statuses []*DeploymentStatus
resp, err := s.client.Do(ctx, req, &statuses) resp, err := s.client.Do(ctx, req, &statuses)
if err != nil { if err != nil {
@ -200,8 +189,7 @@ func (s *RepositoriesService) GetDeploymentStatus(ctx context.Context, owner, re
} }
// TODO: remove custom Accept headers when APIs fully launch. // TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeGraphQLNodeIDPreview} req.Header.Set("Accept", mediaTypeDeploymentStatusPreview)
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
d := new(DeploymentStatus) d := new(DeploymentStatus)
resp, err := s.client.Do(ctx, req, d) resp, err := s.client.Do(ctx, req, d)
@ -224,8 +212,7 @@ func (s *RepositoriesService) CreateDeploymentStatus(ctx context.Context, owner,
} }
// TODO: remove custom Accept headers when APIs fully launch. // TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeGraphQLNodeIDPreview} req.Header.Set("Accept", mediaTypeDeploymentStatusPreview)
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
d := new(DeploymentStatus) d := new(DeploymentStatus)
resp, err := s.client.Do(ctx, req, d) resp, err := s.client.Do(ctx, req, d)

View file

@ -58,7 +58,8 @@ type RepositoryCreateForkOptions struct {
// //
// This method might return an *AcceptedError and a status code of // This method might return an *AcceptedError and a status code of
// 202. This is because this is the status that GitHub returns to signify that // 202. This is because this is the status that GitHub returns to signify that
// it is now computing creating the fork in a background task. // it is now computing creating the fork in a background task. In this event,
// the Repository value will be returned, which includes the details about the pending fork.
// A follow up request, after a delay of a second or so, should result // A follow up request, after a delay of a second or so, should result
// in a successful request. // in a successful request.
// //
@ -77,6 +78,9 @@ func (s *RepositoriesService) CreateFork(ctx context.Context, owner, repo string
fork := new(Repository) fork := new(Repository)
resp, err := s.client.Do(ctx, req, fork) resp, err := s.client.Do(ctx, req, fork)
if _, ok := err.(*AcceptedError); ok {
return fork, resp, err
}
if err != nil { if err != nil {
return nil, resp, err return nil, resp, err
} }

View file

@ -136,9 +136,13 @@ func (s *RepositoriesService) GetHook(ctx context.Context, owner, repo string, i
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
hook := new(Hook) h := new(Hook)
resp, err := s.client.Do(ctx, req, hook) resp, err := s.client.Do(ctx, req, h)
return hook, resp, err if err != nil {
return nil, resp, err
}
return h, resp, nil
} }
// EditHook updates a specified Hook. // EditHook updates a specified Hook.
@ -152,7 +156,11 @@ func (s *RepositoriesService) EditHook(ctx context.Context, owner, repo string,
} }
h := new(Hook) h := new(Hook)
resp, err := s.client.Do(ctx, req, h) resp, err := s.client.Do(ctx, req, h)
return h, resp, err if err != nil {
return nil, resp, err
}
return h, resp, nil
} }
// DeleteHook deletes a specified Hook. // DeleteHook deletes a specified Hook.

View file

@ -79,7 +79,7 @@ func (s *RepositoriesService) CreateKey(ctx context.Context, owner string, repo
// EditKey edits a deploy key. // EditKey edits a deploy key.
// //
// GitHub API docs: https://developer.github.com/v3/repos/keys/#edit // GitHub API docs: https://developer.github.com/v3/repos/keys/#edit
func (s *RepositoriesService) EditKey(ctx context.Context, owner string, repo string, id int, key *Key) (*Key, *Response, error) { func (s *RepositoriesService) EditKey(ctx context.Context, owner string, repo string, id int64, key *Key) (*Key, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id)
req, err := s.client.NewRequest("PATCH", u, key) req, err := s.client.NewRequest("PATCH", u, key)
@ -99,7 +99,7 @@ func (s *RepositoriesService) EditKey(ctx context.Context, owner string, repo st
// DeleteKey deletes a deploy key. // DeleteKey deletes a deploy key.
// //
// GitHub API docs: https://developer.github.com/v3/repos/keys/#delete // GitHub API docs: https://developer.github.com/v3/repos/keys/#delete
func (s *RepositoriesService) DeleteKey(ctx context.Context, owner string, repo string, id int) (*Response, error) { func (s *RepositoriesService) DeleteKey(ctx context.Context, owner string, repo string, id int64) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id)
req, err := s.client.NewRequest("DELETE", u, nil) req, err := s.client.NewRequest("DELETE", u, nil)

Some files were not shown because too many files have changed in this diff Show more