1
0
mirror of https://github.com/taigrr/wtf synced 2025-01-18 04:03:14 -08:00

Update dependencies

This commit is contained in:
Anand Sudhir Prayaga 2018-11-12 12:10:36 +01:00
parent 748ad82967
commit 08ad5d55d9
96 changed files with 2549 additions and 1864 deletions

56
Gopkg.lock generated
View File

@ -6,8 +6,8 @@
name = "cloud.google.com/go" name = "cloud.google.com/go"
packages = ["compute/metadata"] packages = ["compute/metadata"]
pruneopts = "UT" pruneopts = "UT"
revision = "dfffe386c33fb24c34ee501e5723df5b97b98514" revision = "1fd54cf41e6e0e178ffe3c52b0e2260281f603e3"
version = "v0.30.0" version = "v0.32.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
@ -18,7 +18,7 @@
revision = "e4cc07c871d0ee17c5579131fc1c786efbb5fe2a" revision = "e4cc07c871d0ee17c5579131fc1c786efbb5fe2a"
[[projects]] [[projects]]
digest = "1:9253f97cfbbe049b631877c80badecc69620711b3e335f6cf97a7809681da388" digest = "1:26777bf96d1c96d9be38c7c9795196b088c91c597ec5dae5bf6c02dc3c3520e9"
name = "github.com/alecthomas/chroma" name = "github.com/alecthomas/chroma"
packages = [ packages = [
".", ".",
@ -54,16 +54,16 @@
"styles", "styles",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "5d7fef2ae60b501bbf28d476c3f273b8017d8261" revision = "5a473179cfe450c6d80407452c241428de387f6b"
version = "v0.5.0" version = "v0.6.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:579829cc9bf515e2f9e39f91df03b9333c311402bac5a4935dc8ef81e3a57160" digest = "1:e36f3589964f8aa50b1a446c5e239c75f9f58abc3154d6317e17dbc5426b336f"
name = "github.com/andygrunwald/go-gerrit" name = "github.com/andygrunwald/go-gerrit"
packages = ["."] packages = ["."]
pruneopts = "UT" pruneopts = "UT"
revision = "30ce279197661497040ec81c4b64539562eb2d4b" revision = "43cfd7a94eb4c4005ddfaa44afec1f41fc49c07d"
[[projects]] [[projects]]
branch = "master" branch = "master"
@ -134,22 +134,22 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:490cf9d7deec1b0dcac6cc8b17f307c48c4821bc2140d46e48175a83acbfe40d" digest = "1:f769a2e5907124c30242e05687ace7a2d433257746fb0c4d6f35e3edf9ef11df"
name = "github.com/gdamore/tcell" name = "github.com/gdamore/tcell"
packages = [ packages = [
".", ".",
"terminfo", "terminfo",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "493f3b46b3c20880afc8e04ceeb1c6d5aa3363d7" revision = "017915a4d77dabd7af10ab539e618a735d4b9c0a"
[[projects]] [[projects]]
digest = "1:57fa4c058c21ce25d0b7272518dd746065117abf6cc706158b0d361202024520" digest = "1:dae52e85e2f3d0a734799e74ec0711d3ddd673b21a9e83be6c899af64c3a98f6"
name = "github.com/godbus/dbus" name = "github.com/godbus/dbus"
packages = ["."] packages = ["."]
pruneopts = "UT" pruneopts = "UT"
revision = "a389bdde4dd695d414e47b755e95e72b7826432c" revision = "66d97aec3384421e393c2a76b770a1b5c31d07a8"
version = "v4.1.0" version = "v5.0"
[[projects]] [[projects]]
digest = "1:97df918963298c287643883209a2c3f642e6593379f97ab400c2a2e219ab647d" digest = "1:97df918963298c287643883209a2c3f642e6593379f97ab400c2a2e219ab647d"
@ -161,11 +161,11 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:8c90219e8a1f5f7cad019b77697aaae2b236db5a1a46ae688e5ede406e109182" digest = "1:d226d0f3f08498c5965527df6b78d9e3a89a60057a4743c2a3ab4b349f9382f9"
name = "github.com/google/go-github" name = "github.com/google/go-github"
packages = ["github"] packages = ["github"]
pruneopts = "UT" pruneopts = "UT"
revision = "68a79fc6a32bab9406083545e667a65ba67b0a3e" revision = "99760a16213d6fdde13f4e477438f876b6c9c6eb"
[[projects]] [[projects]]
digest = "1:a63cff6b5d8b95638bfe300385d93b2a6d9d687734b863da8e09dc834510a690" digest = "1:a63cff6b5d8b95638bfe300385d93b2a6d9d687734b863da8e09dc834510a690"
@ -241,11 +241,11 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:00d9f4017b55d590139b77fbd851aef56f179479fc40a4afdedaf187e828f99d" digest = "1:da25b5c66f6ae8790c5da9a8750457a3d82ce873d72e10a5f8cb5525d1a7ea8c"
name = "github.com/rivo/tview" name = "github.com/rivo/tview"
packages = ["."] packages = ["."]
pruneopts = "UT" pruneopts = "UT"
revision = "a7c1880d62d37422830f0a15823b51301ca9f354" revision = "8cf347b745d04cc4dc106c22368b37b8018d33b7"
[[projects]] [[projects]]
branch = "master" branch = "master"
@ -265,11 +265,11 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:afc7e1c726a88e6cd5689cca19fbc86128dffe86fd37e3e0841767f3a951182e" digest = "1:544fdb64daa40fbd603be86318d443047408dc1b5d3c4c08f44ec56a66e9e7e0"
name = "github.com/xanzy/go-gitlab" name = "github.com/xanzy/go-gitlab"
packages = ["."] packages = ["."]
pruneopts = "UT" pruneopts = "UT"
revision = "1444249c1b2a8e4cdb5a76dc9c8d02d1133180be" revision = "3f3acb6af00137585629f7ebcc93e8f9f9cd07aa"
[[projects]] [[projects]]
branch = "master" branch = "master"
@ -289,11 +289,11 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:02a2f8f0718f239866000d2d1bca016d14f0f6de37615c315f34da17dc630259" digest = "1:9161fc348532a8eb2b05bbc126c02f6d3cbdeaa9074e04a5ce8cef65145654ed"
name = "github.com/zorkian/go-datadog-api" name = "github.com/zorkian/go-datadog-api"
packages = ["."] packages = ["."]
pruneopts = "UT" pruneopts = "UT"
revision = "dc324c09cf05eef3e3a82bde06ae0c4dd349a767" revision = "456ae6c2a362f4edc4661d535e5827cb4582375f"
[[projects]] [[projects]]
branch = "master" branch = "master"
@ -304,11 +304,11 @@
"context/ctxhttp", "context/ctxhttp",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "04a2e542c03f1d053ab3e4d6e5abcd4b66e2be8e" revision = "03003ca0c849e57b6ea29a4bab8d3cb6e4d568fe"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:faa25cb78cf9c8cec9345d4ed07322cdef6a8c968b3d0a6b6c3609067c7386eb" digest = "1:d71cf3891adad6f2d608396a8da36e90ac46cd51e34d5a75a31385d2682b43ce"
name = "golang.org/x/oauth2" name = "golang.org/x/oauth2"
packages = [ packages = [
".", ".",
@ -318,7 +318,7 @@
"jwt", "jwt",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "9dcd33a902f40452422c2367fefcb95b54f9f8f8" revision = "f42d05182288abf10faef86d16c0d07b8d40ea2d"
[[projects]] [[projects]]
digest = "1:37672ad5821719e2df8509c2edd4ba5ae192463237c73c3a2d24ef8b2bc9e36f" digest = "1:37672ad5821719e2df8509c2edd4ba5ae192463237c73c3a2d24ef8b2bc9e36f"
@ -336,7 +336,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:a1d58b7c9eeceeac201a6f6b10092cd2a5985791a45843c838151ee3f751d3c3" digest = "1:41dda3c734540a7ce6dea54f6c870306dd2676c60abef2333ac1692f2a14371d"
name = "google.golang.org/api" name = "google.golang.org/api"
packages = [ packages = [
"calendar/v3", "calendar/v3",
@ -346,10 +346,10 @@
"sheets/v4", "sheets/v4",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "a2651947f503a1793446d4058bb073a6fdf99e53" revision = "cfbc873f6b93790282bed8e31e7f7df417caee1b"
[[projects]] [[projects]]
digest = "1:193950893ea275f89ed92e5da11ed8fa1436872f755a9ea5d4afa83dc9d9c3a8" digest = "1:d2a8db567a76203e3b41c1f632d86485ffd57f8e650a0d1b19d240671c2fddd7"
name = "google.golang.org/appengine" name = "google.golang.org/appengine"
packages = [ packages = [
".", ".",
@ -364,8 +364,8 @@
"urlfetch", "urlfetch",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "ae0ab99deb4dc413a2b4bd6c8bdd0eb67f1e4d06" revision = "4a4468ece617fc8205e99368fa2200e9d1fad421"
version = "v1.2.0" version = "v1.3.0"
[[projects]] [[projects]]
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202" digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"

View File

@ -29,7 +29,32 @@ translators for Pygments lexers and styles.
## Supported languages ## Supported languages
ABNF, ANTLR, APL, ActionScript, ActionScript 3, Ada, Angular2, ApacheConf, AppleScript, Awk, BNF, Ballerina, Base Makefile, Bash, Batchfile, BlitzBasic, Brainfuck, C, C#, C++, CFEngine3, CMake, COBOL, CSS, Cap'n Proto, Ceylon, ChaiScript, Cheetah, Clojure, CoffeeScript, Common Lisp, Coq, Crystal, Cython, DTD, Dart, Diff, Django/Jinja, Docker, EBNF, Elixir, Elm, EmacsLisp, Erlang, FSharp, Factor, Fish, Forth, Fortran, GAS, GDScript, GLSL, Genshi, Genshi HTML, Genshi Text, Gnuplot, Go, Go HTML Template, Go Text Template, Groovy, HTML, HTTP, Handlebars, Haskell, Haxe, Hexdump, Hy, INI, Idris, Io, JSON, JSX, Java, JavaScript, Julia, Kotlin, LLVM, Lighttpd configuration file, Lua, Mako, Mason, Mathematica, MiniZinc, Modula-2, MorrowindScript, MySQL, Myghty, NASM, Newspeak, Nginx configuration file, Nim, Nix, OCaml, Objective-C, Octave, Org Mode, PHP, PL/pgSQL, POVRay, PacmanConf, Perl, Pig, PkgConfig, PostScript, PostgreSQL SQL dialect, PowerShell, Prolog, Protocol Buffer, Puppet, Python, Python 3, QBasic, R, Racket, Ragel, Rexx, Ruby, Rust, SCSS, SPARQL, SQL, Sass, Scala, Scheme, Scilab, Smalltalk, Smarty, Snobol, Solidity, SquidConf, Swift, TASM, TOML, Tcl, Tcsh, TeX, Termcap, Terminfo, Terraform, Thrift, Transact-SQL, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData, VHDL, VimL, WDTE, XML, Xorg, YAML, cfstatement, markdown, reStructuredText, reg, systemverilog, verilog Prefix | Language
:----: | --------
A | ABNF, ActionScript, ActionScript 3, Ada, Angular2, ANTLR, ApacheConf, APL, AppleScript, Awk
B | Ballerina, Base Makefile, Bash, Batchfile, BlitzBasic, BNF, Brainfuck
C | C, C#, C++, Cassandra CQL, CFEngine3, cfstatement/ColdFusion, CMake, COBOL, CSS, Cap'n Proto, Ceylon, ChaiScript, Cheetah, Clojure, CoffeeScript, Common Lisp, Coq, Crystal, Cython
D | Dart, Diff, Django/Jinja, Docker, DTD
E | EBNF, Elixir, Elm, EmacsLisp, Erlang
F | Factor, Fish, Forth, Fortran, FSharp
G | GAS, GDScript, GLSL, Genshi, Genshi HTML, Genshi Text, Gnuplot, Go, Go HTML Template, Go Text Template, Groovy
H | Handlebars, Haskell, Haxe, Hexdump, HTML, HTTP, Hy
I | Idris, INI, Io
J | Java, JavaScript, JSON, Jsx, Julia, Jungle
K | Kotlin
L | Lighttpd configuration file, LLVM, Lua
M | Mako, Markdown, Mason, Mathematica, MiniZinc, Modula-2, MonkeyC, MorrowindScript, Myghty, MySQL
N | NASM, Newspeak, Nginx configuration file, Nim, Nix
O | Objective-C, OCaml, Octave, OpenSCAD, Org Mode
P | PacmanConf, Perl, PHP, Pig, PkgConfig, Plaintext, PL/pgSQL, PostgreSQL SQL dialect, PostScript, POVRay, PowerShell, Prolog, Protocol Buffer, Puppet, Python, Python 3
Q | QBasic
R | R, Racket, Ragel, reg, reStructuredText, Rexx, Ruby, Rust
S | Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, Snobol, Solidity, SPARQL, SQL, SquidConf, Swift, systemd, Systemverilog
T | TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData
V | verilog, VHDL, VimL
W | WDTE
X | XML, Xorg
Y | YAML
_I will attempt to keep this section up to date, but an authoritative list can be _I will attempt to keep this section up to date, but an authoritative list can be
displayed with `chroma --list`._ displayed with `chroma --list`._

View File

@ -25,6 +25,9 @@ func WithClasses() Option { return func(f *Formatter) { f.Classes = true } }
// TabWidth sets the number of characters for a tab. Defaults to 8. // TabWidth sets the number of characters for a tab. Defaults to 8.
func TabWidth(width int) Option { return func(f *Formatter) { f.tabWidth = width } } func TabWidth(width int) Option { return func(f *Formatter) { f.tabWidth = width } }
// PreventSurroundingPre prevents the surrounding pre tags around the generated code
func PreventSurroundingPre() Option { return func(f *Formatter) { f.preventSurroundingPre = true } }
// WithLineNumbers formats output with line numbers. // WithLineNumbers formats output with line numbers.
func WithLineNumbers() Option { func WithLineNumbers() Option {
return func(f *Formatter) { return func(f *Formatter) {
@ -70,14 +73,15 @@ func New(options ...Option) *Formatter {
// Formatter that generates HTML. // Formatter that generates HTML.
type Formatter struct { type Formatter struct {
standalone bool standalone bool
prefix string prefix string
Classes bool // Exported field to detect when classes are being used Classes bool // Exported field to detect when classes are being used
tabWidth int preventSurroundingPre bool
lineNumbers bool tabWidth int
lineNumbersInTable bool lineNumbers bool
highlightRanges highlightRanges lineNumbersInTable bool
baseLineNumber int highlightRanges highlightRanges
baseLineNumber int
} }
type highlightRanges [][2]int type highlightRanges [][2]int
@ -158,7 +162,9 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []*chroma
fmt.Fprintf(w, "<div%s>\n", f.styleAttr(css, chroma.Background)) fmt.Fprintf(w, "<div%s>\n", f.styleAttr(css, chroma.Background))
fmt.Fprintf(w, "<table%s><tr>", f.styleAttr(css, chroma.LineTable)) fmt.Fprintf(w, "<table%s><tr>", f.styleAttr(css, chroma.LineTable))
fmt.Fprintf(w, "<td%s>\n", f.styleAttr(css, chroma.LineTableTD)) fmt.Fprintf(w, "<td%s>\n", f.styleAttr(css, chroma.LineTableTD))
fmt.Fprintf(w, "<pre%s>", f.styleAttr(css, chroma.Background)) if !f.preventSurroundingPre {
fmt.Fprintf(w, "<pre%s>", f.styleAttr(css, chroma.Background))
}
for index := range lines { for index := range lines {
line := f.baseLineNumber + index line := f.baseLineNumber + index
highlight, next := f.shouldHighlight(highlightIndex, line) highlight, next := f.shouldHighlight(highlightIndex, line)
@ -175,11 +181,16 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []*chroma
fmt.Fprintf(w, "</span>") fmt.Fprintf(w, "</span>")
} }
} }
fmt.Fprint(w, "</pre></td>\n") if !f.preventSurroundingPre {
fmt.Fprint(w, "</pre>")
}
fmt.Fprint(w, "</td>\n")
fmt.Fprintf(w, "<td%s>\n", f.styleAttr(css, chroma.LineTableTD)) fmt.Fprintf(w, "<td%s>\n", f.styleAttr(css, chroma.LineTableTD))
} }
fmt.Fprintf(w, "<pre%s>", f.styleAttr(css, chroma.Background)) if !f.preventSurroundingPre {
fmt.Fprintf(w, "<pre%s>", f.styleAttr(css, chroma.Background))
}
highlightIndex = 0 highlightIndex = 0
for index, tokens := range lines { for index, tokens := range lines {
// 1-based line number. // 1-based line number.
@ -209,7 +220,9 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []*chroma
} }
} }
fmt.Fprint(w, "</pre>") if !f.preventSurroundingPre {
fmt.Fprint(w, "</pre>")
}
if wrapInTable { if wrapInTable {
fmt.Fprint(w, "</td></tr></table>\n") fmt.Fprint(w, "</td></tr></table>\n")

View File

@ -36,7 +36,7 @@ var Bash = internal.Register(MustNewLexer(
{`\b(if|fi|else|while|do|done|for|then|return|function|case|select|continue|until|esac|elif)(\s*)\b`, ByGroups(Keyword, Text), nil}, {`\b(if|fi|else|while|do|done|for|then|return|function|case|select|continue|until|esac|elif)(\s*)\b`, ByGroups(Keyword, Text), nil},
{"\\b(alias|bg|bind|break|builtin|caller|cd|command|compgen|complete|declare|dirs|disown|echo|enable|eval|exec|exit|export|false|fc|fg|getopts|hash|help|history|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|set|shift|shopt|source|suspend|test|time|times|trap|true|type|typeset|ulimit|umask|unalias|unset|wait)(?=[\\s)`])", NameBuiltin, nil}, {"\\b(alias|bg|bind|break|builtin|caller|cd|command|compgen|complete|declare|dirs|disown|echo|enable|eval|exec|exit|export|false|fc|fg|getopts|hash|help|history|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|set|shift|shopt|source|suspend|test|time|times|trap|true|type|typeset|ulimit|umask|unalias|unset|wait)(?=[\\s)`])", NameBuiltin, nil},
{`\A#!.+\n`, CommentPreproc, nil}, {`\A#!.+\n`, CommentPreproc, nil},
{`#.*\n`, CommentSingle, nil}, {`#.*\S`, CommentSingle, nil},
{`\\[\w\W]`, LiteralStringEscape, nil}, {`\\[\w\W]`, LiteralStringEscape, nil},
{`(\b\w+)(\s*)(\+?=)`, ByGroups(NameVariable, Text, Operator), nil}, {`(\b\w+)(\s*)(\+?=)`, ByGroups(NameVariable, Text, Operator), nil},
{`[\[\]{}()=]`, Operator, nil}, {`[\[\]{}()=]`, Operator, nil},

View File

@ -36,9 +36,9 @@ var Elixir = internal.Register(MustNewLexer(
{`\\\\|\<\<|\>\>|\=\>|\(|\)|\:|\;|\,|\[|\]`, Punctuation, nil}, {`\\\\|\<\<|\>\>|\=\>|\(|\)|\:|\;|\,|\[|\]`, Punctuation, nil},
{`&\d`, NameEntity, nil}, {`&\d`, NameEntity, nil},
{`\<|\>|\+|\-|\*|\/|\!|\^|\&`, Operator, nil}, {`\<|\>|\+|\-|\*|\/|\!|\^|\&`, Operator, nil},
{`0b[01]+`, LiteralNumberBin, nil}, {`0b[01](_?[01])*`, LiteralNumberBin, nil},
{`0o[0-7]+`, LiteralNumberOct, nil}, {`0o[0-7](_?[0-7])*`, LiteralNumberOct, nil},
{`0x[\da-fA-F]+`, LiteralNumberHex, nil}, {`0x[\da-fA-F](_?[\dA-Fa-f])*`, LiteralNumberHex, nil},
{`\d(_?\d)*\.\d(_?\d)*([eE][-+]?\d(_?\d)*)?`, LiteralNumberFloat, nil}, {`\d(_?\d)*\.\d(_?\d)*([eE][-+]?\d(_?\d)*)?`, LiteralNumberFloat, nil},
{`\d(_?\d)*`, LiteralNumberInteger, nil}, {`\d(_?\d)*`, LiteralNumberInteger, nil},
{`"""\s*`, LiteralStringHeredoc, Push("heredoc_double")}, {`"""\s*`, LiteralStringHeredoc, Push("heredoc_double")},

View File

@ -42,6 +42,7 @@ var Go = internal.Register(MustNewLexer(
{"(`)([^`]*)(`)", ByGroups(LiteralString, Using(TypeRemappingLexer(GoTextTemplate, TypeMapping{{Other, LiteralString, nil}})), LiteralString), nil}, {"(`)([^`]*)(`)", ByGroups(LiteralString, Using(TypeRemappingLexer(GoTextTemplate, TypeMapping{{Other, LiteralString, nil}})), LiteralString), nil},
{`"(\\\\|\\"|[^"])*"`, LiteralString, nil}, {`"(\\\\|\\"|[^"])*"`, LiteralString, nil},
{`(<<=|>>=|<<|>>|<=|>=|&\^=|&\^|\+=|-=|\*=|/=|%=|&=|\|=|&&|\|\||<-|\+\+|--|==|!=|:=|\.\.\.|[+\-*/%&])`, Operator, nil}, {`(<<=|>>=|<<|>>|<=|>=|&\^=|&\^|\+=|-=|\*=|/=|%=|&=|\|=|&&|\|\||<-|\+\+|--|==|!=|:=|\.\.\.|[+\-*/%&])`, Operator, nil},
{`([a-zA-Z_]\w*)(\s*)(\()`, ByGroups(NameFunction, UsingSelf("root"), Punctuation), nil},
{`[|^<>=!()\[\]{}.,;:]`, Punctuation, nil}, {`[|^<>=!()\[\]{}.,;:]`, Punctuation, nil},
{`[^\W\d]\w*`, NameOther, nil}, {`[^\W\d]\w*`, NameOther, nil},
}, },

View File

@ -85,6 +85,7 @@ func (d *httpBodyContentTyper) Tokenise(options *TokeniseOptions, text string) (
} }
case token.Type == Literal && isContentType: case token.Type == Literal && isContentType:
{ {
isContentType = false
contentType = strings.TrimSpace(token.Value) contentType = strings.TrimSpace(token.Value)
pos := strings.Index(contentType, ";") pos := strings.Index(contentType, ";")
if pos > 0 { if pos > 0 {

View File

@ -0,0 +1,29 @@
package s
import (
. "github.com/alecthomas/chroma" // nolint
"github.com/alecthomas/chroma/lexers/internal"
)
var SYSTEMD = internal.Register(MustNewLexer(
&Config{
Name: "SYSTEMD",
Aliases: []string{"systemd"},
Filenames: []string{"*.service"},
MimeTypes: []string{"text/plain"},
},
Rules {
"root": {
{`\s+`, Text, nil},
{`[;#].*`, Comment, nil},
{`\[.*?\]$`, Keyword, nil},
{`(.*?)(=)(.*)(\\\n)`, ByGroups(NameAttribute, Operator, LiteralString, Text), Push("continuation")},
{`(.*?)(=)(.*)`, ByGroups(NameAttribute, Operator, LiteralString), nil},
},
"continuation": {
{`(.*?)(\\\n)`, ByGroups(LiteralString, Text), nil},
{`(.*)`, LiteralString, Pop(1)},
},
},
))

View File

@ -0,0 +1,36 @@
package t
import (
. "github.com/alecthomas/chroma" // nolint
"github.com/alecthomas/chroma/lexers/internal"
)
// TradingView lexer.
var TradingView = internal.Register(MustNewLexer(
&Config{
Name: "TradingView",
Aliases: []string{"tradingview", "tv"},
Filenames: []string{"*.tv"},
MimeTypes: []string{"text/x-tradingview"},
DotAll: true,
},
Rules{
"root": {
{`[^\S\n]+|\n|[()]`, Text, nil},
{`(//.*?)(\n)`, ByGroups(CommentSingle, Text), nil},
{`>=|<=|==|!=|>|<|\?|-|\+|\*|\/|%|\[|\]`, Operator, nil},
{`[:,.]`, Punctuation, nil},
{`=`, KeywordPseudo, nil},
{`"(\\\\|\\"|[^"\n])*["\n]`, LiteralString, nil},
{`'\\.'|'[^\\]'`, LiteralString, nil},
{`[0-9](\.[0-9]*)?([eE][+-][0-9]+)?`, LiteralNumber, nil},
{`(abs|acos|alertcondition|alma|asin|atan|atr|avg|barcolor|barssince|bgcolor|cci|ceil|change|cog|correlation|cos|crossover|crossunder|cum|dev|ema|exp|falling|fill|fixnan|floor|heikinashi|highest|highestbars|hline|iff|input|kagi|linebreak|linreg|log|log10|lowest|lowestbars|macd|max|min|mom|nz|percentile_linear_interpolation|percentile_nearest_rank|percentrank|pivothigh|pivotlow|plot|plotarrow|plotbar|plotcandle|plotchar|plotshape|pointfigure|pow|renko|rising|rma|roc|round|rsi|sar|security|sign|sin|sma|sqrt|stdev|stoch|study|sum|swma|tan|tostring|tsi|valuewhen|variance|vwma|wma|strategy\.(cancel|cancel_all|close|close_all|entry|exit|order)|strategy\.risk\.(allow_entry_in|max_cons_loss_days|max_drawdown|max_intraday_filled_orders|max_intraday_loss|max_position_size))\b`, NameFunction, nil},
{`\b(cross|dayofmonth|dayofweek|hour|minute|month|na|offset|second|tickerid|time|tr|vwap|weekofyear|year)(\()`, ByGroups(NameFunction, Text), nil}, // functions that can also be variable
{`(accdist|aqua|area|areabr|black|blue|bool|circles|close|columns|currency\.(AUD|CAD|CHF|EUR|GBP|HKD|JPY|NOK|NONE|NZD|SEK|SGD|TRY|USD|ZAR)|dashed|dotted|float|friday|fuchsia|gray|green|high|histogram|hl2|hlc3|integer|interval|isdaily|isdwm|isintraday|ismonthly|isweekly|lime|line|linebr|location\.(abovebar|belowbar|bottom|top)|low|maroon|monday|n|navy|ohlc4|olive|open|orange|period|purple|red|resolution|saturday|scale\.(left|none|right)|session|session\.(extended|regular)|silver|size\.(auto|huge|large|normal|small|tiny)|solid|source|string|sunday|symbol|syminfo\.(mintick|pointvalue|prefix|root|session)|teal|thursday|ticker|tuesday|volume|wednesday|white|yellow|strategy\.(cash|position_size|closedtrades|direction\.(all|long|short)|equity|eventrades|fixed|grossloss|grossprofit|initial_capital|long|losstrades|max_contracts_held_all|max_contracts_held_long|max_contracts_held_short|max_drawdown|netprofit|oca\.(cancel|none|reduce)|openprofit|opentrades|percent_of_equity|position_avg_price|position_entry_name|short|wintrades)|shape\.(arrowdown|arrowup|circle|cross|diamond|flag|labeldown|labelup|square|triangledown|triangleup|xcross)|barstate\.is(first|history|last|new|realtime)|barmerge\.(gaps_on|gaps_off|lookahead_on|lookahead_off)|strategy\.commission\.(cash_per_contract|cash_per_order|percent))\b`, NameVariable, nil},
{`(cross|dayofmonth|dayofweek|hour|minute|month|na|second|tickerid|time|tr|vwap|weekofyear|year)(\b[^\(])`, ByGroups(NameVariable, Text), nil}, // variables that can also be function
{`(true|false)\b`, KeywordConstant, nil},
{`(and|or|not|if|else|for|to)\b`, OperatorWord, nil},
{`@?[_a-zA-Z]\w*`, Text, nil},
},
},
))

View File

@ -26,11 +26,11 @@ func (s *ProjectsService) GetCommit(projectName, commitID string) (*CommitInfo,
return v, resp, err return v, resp, err
} }
// GetCommitContent gets the content of a file from the HEAD revision of a certain branch. // GetCommitContent gets the content of a file from a certain commit.
// The content is returned as base64 encoded string. // The content is returned as base64 encoded string.
// //
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#get-content // Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html##get-content-from-commit
func (s *ProjectsService) GetCommitContent(projectName, branchID, fileID string) (string, *Response, error) { func (s *ProjectsService) GetCommitContent(projectName, commitID, fileID string) (string, *Response, error) {
u := fmt.Sprintf("projects/%s/branches/%s/files/%s/content", url.QueryEscape(projectName), branchID, fileID) u := fmt.Sprintf("projects/%s/commits/%s/files/%s/content", url.QueryEscape(projectName), commitID, fileID)
return getStringResponseWithoutOptions(s.client, u) return getStringResponseWithoutOptions(s.client, u)
} }

270
vendor/github.com/gdamore/tcell/README.adoc generated vendored Normal file
View File

@ -0,0 +1,270 @@
= tcell
image:https://img.shields.io/travis/gdamore/tcell.svg?label=linux[Linux Status,link="https://travis-ci.org/gdamore/tcell"]
image:https://img.shields.io/appveyor/ci/gdamore/tcell.svg?label=windows[Windows Status,link="https://ci.appveyor.com/project/gdamore/tcell"]
image:https://img.shields.io/badge/license-APACHE2-blue.svg[Apache License,link="https://github.com/gdamore/tcell/blob/master/LICENSE"]
image:https://img.shields.io/badge/gitter-join-brightgreen.svg[Gitter,link="https://gitter.im/gdamore/tcell"]
image:https://img.shields.io/badge/godoc-reference-blue.svg[GoDoc,link="https://godoc.org/github.com/gdamore/tcell"]
image:http://goreportcard.com/badge/gdamore/tcell[Go Report Card,link="http://goreportcard.com/report/gdamore/tcell"]
image:https://codecov.io/gh/gdamore/tcell/branch/master/graph/badge.svg[codecov,link="https://codecov.io/gh/gdamore/tcell"]
image:https://tidelift.com/badges/github/gdamore/tcell?style=flat[Dependencies]
[cols="2",grid="none"]
|===
|_Tcell_ is a _Go_ package that provides a cell based view for text terminals, like _xterm_.
It was inspired by _termbox_, but includes many additional improvements.
a|[.right]
image::logos/tcell.png[float="right"]
|===
## Examples
* https://github.com/gdamore/proxima5[proxima5] - space shooter (https://youtu.be/jNxKTCmY_bQ[video])
* https://github.com/gdamore/govisor[govisor] - service management UI (http://2.bp.blogspot.com/--OsvnfzSNow/Vf7aqMw3zXI/AAAAAAAAARo/uOMtOvw4Sbg/s1600/Screen%2BShot%2B2015-09-20%2Bat%2B9.08.41%2BAM.png[screenshot])
* mouse demo - included mouse test (http://2.bp.blogspot.com/-fWvW5opT0es/VhIdItdKqJI/AAAAAAAAATE/7Ojc0L1SpB0/s1600/Screen%2BShot%2B2015-10-04%2Bat%2B11.47.13%2BPM.png[screenshot])
* https://github.com/gdamore/gomatrix[gomatrix] - converted from Termbox
* https://github.com/zyedidia/micro/[micro] - lightweight text editor with syntax-highlighting and themes
* https://github.com/viktomas/godu[godu] - simple golang utility helping to discover large files/folders.
* https://github.com/rivo/tview[tview] - rich interactive widgets for terminal UIs
* https://github.com/marcusolsson/tui-go[tui-go] - UI library for terminal apps
* https://github.com/rgm3/gomandelbrot[gomandelbrot] - Mandelbrot!
* https://github.com/senorprogrammer/wtf[WTF]- Personal information dashboard for your terminal
* https://github.com/browsh-org/browsh[browsh] - A fully-modern text-based browser, rendering to TTY and browsers (https://www.youtube.com/watch?v=HZq86XfBoRo[video])
* https://github.com/sachaos/go-life[go-life] - Conway's Game of Life.
## Pure Go Terminfo Database
_Tcell_ includes a full parser and expander for terminfo capability strings,
so that it can avoid hard coding escape strings for formatting. It also favors
portability, and includes support for all POSIX systems.
The database is also flexible & extensible, and can modified by either running
a program to build the entire database, or an entry for just a single terminal.
## More Portable
_Tcell_ is portable to a wide variety of systems.
_Tcell_ is believed
to work with all of the systems officially supported by golang with
the exception of nacl (which lacks any kind of a terminal interface).
(Plan9 is not supported by _Tcell_, but it is experimental status only
in golang.) For all of these systems *except Solaris/illumos*, _Tcell_
is pure Go, with no need for CGO.
## No Async IO
_Tcell_ is able to operate without requiring `SIGIO` signals (unlike _termbox_),
or asynchronous I/O, and can instead use standard Go file
objects and Go routines.
This means it should be safe, especially for
use with programs that use exec, or otherwise need to manipulate the
tty streams.
This model is also much closer to idiomatic Go, leading
to fewer surprises.
## Rich Unicode & non-Unicode support
_Tcell_ includes enhanced support for Unicode, including wide characters and
combining characters, provided your terminal can support them.
Note that
Windows terminals generally don't support the full Unicode repertoire.
It will also convert to and from Unicode locales, so that the program
can work with UTF-8 internally, and get reasonable output in other locales.
_Tcell_ tries hard to convert to native characters on both input and output, and
on output _Tcell_ even makes use of the alternate character set to facilitate
drawing certain characters.
## More Function Keys
_Tcell_ also has richer support for a larger number of special keys that some terminals can send.
## Better Color Handling
_Tcell_ will respect your terminal's color space as specified within your terminfo
entries, so that for example attempts to emit color sequences on VT100 terminals
won't result in unintended consequences.
In Windows mode, _Tcell_ supports 16 colors, bold, dim, and reverse,
instead of just termbox's 8 colors with reverse. (Note that there is some
conflation with bold/dim and colors.)
_Tcell_ maps 16 colors down to 8, for terminals that need it.
(The upper 8 colors are just brighter versions of the lower 8.)
## Better Mouse Support
_Tcell_ supports enhanced mouse tracking mode, so your application can receive
regular mouse motion events, and wheel events, if your terminal supports it.
## _Termbox_ Compatibility
A compatibility layer for _termbox_ is provided in the `compat` directory.
To use it, try importing `github.com/gdamore/tcell/termbox`
instead. Most _termbox-go_ programs will probably work without further
modification.
## Working With Unicode
Internally Tcell uses UTF-8, just like Go.
However, Tcell understands how to
convert to and from other character sets, using the capabilities of
the `golang.org/x/text/encoding packages`.
Your application must supply
them, as the full set of the most common ones bloats the program by about 2MB.
If you're lazy, and want them all anyway, see the `encoding` sub-directory.
## Wide & Combining Characters
The `SetContent()` API takes a primary rune, and an optional list of combining runes.
If any of the runes is a wide (East Asian) rune occupying two cells,
then the library will skip output from the following cell, but care must be
taken in the application to avoid explicitly attempting to set content in the
next cell, otherwise the results are undefined. (Normally wide character
is displayed, and the other character is not; do not depend on that behavior.)
Experience has shown that the vanilla Windows 8 console application does not
support any of these characters properly, but at least some options like
_ConEmu_ do support Wide characters.
## Colors
_Tcell_ assumes the ANSI/XTerm color model, including the 256 color map that
XTerm uses when it supports 256 colors. The terminfo guidance will be
honored, with respect to the number of colors supported. Also, only
terminals which expose ANSI style `setaf` and `setab` will support color;
if you have a color terminal that only has `setf` and `setb`, please let me
know; it wouldn't be hard to add that if there is need.
## 24-bit Color
_Tcell_ _supports true color_! (That is, if your terminal can support it,
_Tcell_ can accurately display 24-bit color.)
To use 24-bit color, you need to use a terminal that supports it. Modern
xterm and similar teminal emulators can support this. As terminfo lacks any
way to describe this capability, we fabricate the capability for
terminals with names ending in `*-truecolor`. The stock distribution ships
with a database that defines `xterm-truecolor`.
To try it out, set your
`TERM` variable to `xterm-truecolor`.
When using TrueColor, programs will display the colors that the programmer
intended, overriding any "`themes`" you may have set in your terminal
emulator. (For some cases, accurate color fidelity is more important
than respecting themes. For other cases, such as typical text apps that
only use a few colors, its more desirable to respect the themes that
the user has established.)
If you find this undesirable, you can either use a `TERM` variable
that lacks the `TRUECOLOR` setting, or set `TCELL_TRUECOLOR=disable` in your
environment.
## Performance
Reasonable attempts have been made to minimize sending data to terminals,
avoiding repeated sequences or drawing the same cell on refresh updates.
## Terminfo
(Not relevent for Windows users.)
The Terminfo implementation operates with two forms of database. The first
is the built-in go database, which contains a number of real database entries
that are compiled into the program directly. This should minimize calling
out to database file searches.
The second is in the form of JSON files, that contain the same information,
which can be located either by the `$TCELLDB` environment file, `$HOME/.tcelldb`,
or is located in the Go source directory as `database.json`.
These files (both the Go and the JSON files) can be generated using the
mkinfo.go program. If you need to regnerate the entire set for some reason,
run the mkdatabase.sh file. The generation uses the infocmp(1) program on
the system to collect the necessary information.
The `mkinfo.go` program can also be used to generate specific database entries
for named terminals, in case your favorite terminal is missing. (If you
find that this is the case, please let me know and I'll try to add it!)
_Tcell_ requires that the terminal support the `cup` mode of cursor addressing.
Terminals without absolute cursor addressability are not supported.
This is unlikely to be a problem; such terminals have not been mass produced
since the early 1970s.
## Mouse Support
Mouse support is detected via the `kmous` terminfo variable, however,
enablement/disablement and decoding mouse events is done using hard coded
sequences based on the XTerm X11 model. As of this writing all popular
terminals with mouse tracking support this model. (Full terminfo support
is not possible as terminfo sequences are not defined.)
On Windows, the mouse works normally.
Mouse wheel buttons on various terminals are known to work, but the support
in terminal emulators, as well as support for various buttons and
live mouse tracking, varies widely. Modern _xterm_, macOS _Terminal_, and _iTerm_ all work well.
## Testablity
There is a `SimulationScreen`, that can be used to simulate a real screen
for automated testing. The supplied tests do this. The simulation contains
event delivery, screen resizing support, and capabilities to inject events
and examine "`physical`" screen contents.
## Platforms
### POSIX (Linux, FreeBSD, macOS, Solaris, etc.)
For mainstream systems with a suitably well defined system call interface
to tty settings, everything works using pure Go.
For the remainder (right now means only Solaris/illumos) we use POSIX function
calls to manage termios, which implies that CGO is required on those platforms.
### Windows
Windows console mode applications are supported. Unfortunately _mintty_
and other _cygwin_ style applications are not supported.
Modern console applications like ConEmu, as well as the Windows 10
console itself, support all the good features (resize, mouse tracking, etc.)
I haven't figured out how to cleanly resolve the dichotomy between cygwin
style termios and the Windows Console API; it seems that perhaps nobody else
has either. If anyone has suggestions, let me know! Really, if you're
using a Windows application, you should use the native Windows console or a
fully compatible console implementation.
### Plan9 and Native Client (Nacl)
The nacl and plan9 platforms won't work, but compilation stubs are supplied
for folks that want to include parts of this in software targetting those
platforms. The Simulation screen works, but as Tcell doesn't know how to
allocate a real screen object on those platforms, `NewScreen()` will fail.
If anyone has wisdom about how to improve support for either of these,
please let me know. PRs are especially welcome.
### Commercial Support
_Tcell_ is absolutely free, but if you want to obtain commercial, professional support, there are options.
[cols="2",align="center",frame="none", grid="none"]
|===
^.^|
image:logos/tidelift.png[100,100]
a|
https://tidelift.com/[Tidelift] subscriptions include support for _Tcell_, as well as many other open source packages.
^.^|
image:logos/staysail.png[100,100]
a|
mailto:info@staysail.tech[Staysail Systems, Inc.] offers direct support, and custom development around _Tcell_ on an hourly basis.
^.^|
image:logos/patreon.png[100,100]
a|I also welcome donations at https://www.patron.com/gedamore/[Patreon], if you just want to make a contribution.
|===

View File

@ -1,255 +0,0 @@
## tcell <img src=tcell.png align=right>
[![Linux Status](https://img.shields.io/travis/gdamore/tcell.svg?label=linux)](https://travis-ci.org/gdamore/tcell)
[![Windows Status](https://img.shields.io/appveyor/ci/gdamore/tcell.svg?label=windows)](https://ci.appveyor.com/project/gdamore/tcell)
[![Apache License](https://img.shields.io/badge/license-APACHE2-blue.svg)](https://github.com/gdamore/tcell/blob/master/LICENSE)
[![Gitter](https://img.shields.io/badge/gitter-join-brightgreen.svg)](https://gitter.im/gdamore/tcell)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/gdamore/tcell)
[![Go Report Card](http://goreportcard.com/badge/gdamore/tcell)](http://goreportcard.com/report/gdamore/tcell)
[![codecov](https://codecov.io/gh/gdamore/tcell/branch/master/graph/badge.svg)](https://codecov.io/gh/gdamore/tcell)
Package tcell provides a cell based view for text terminals, like xterm.
It was inspired by termbox, but differs from termbox in some important
ways. It also adds substantial functionality beyond termbox.
## Examples
* [proxima5](https://github.com/gdamore/proxima5) - space shooter ([video](https://youtu.be/jNxKTCmY_bQ))
* [govisor](https://github.com/gdamore/govisor) - service management UI ([screenshot](http://2.bp.blogspot.com/--OsvnfzSNow/Vf7aqMw3zXI/AAAAAAAAARo/uOMtOvw4Sbg/s1600/Screen%2BShot%2B2015-09-20%2Bat%2B9.08.41%2BAM.png))
* mouse demo - [screenshot](http://2.bp.blogspot.com/-fWvW5opT0es/VhIdItdKqJI/AAAAAAAAATE/7Ojc0L1SpB0/s1600/Screen%2BShot%2B2015-10-04%2Bat%2B11.47.13%2BPM.png) - included mouse test
* [gomatrix](https://github.com/gdamore/gomatrix) - converted from Termbox
* [micro](https://github.com/zyedidia/micro/) - lightweight text editor with syntax-highlighting and themes
* [godu](https://github.com/viktomas/godu) - simple golang utility helping to discover large files/folders.
* [tview](https://github.com/rivo/tview) - rich interactive widgets for terminal UIs
* [tui-go](https://github.com/marcusolsson/tui-go) - UI library for terminal apps
* [gomandelbrot](https://github.com/rgm3/gomandelbrot) - Mandelbrot!
* [WTF](https://github.com/senorprogrammer/wtf)- Personal information dashboard for your terminal
* [browsh](https://github.com/browsh-org/browsh) - A fully-modern text-based browser, rendering to TTY and browsers ([video](https://www.youtube.com/watch?v=HZq86XfBoRo))
## Pure Go Terminfo Database
First, it includes a full parser and expander for terminfo capability strings,
so that it can avoid hard coding escape strings for formatting. It also favors
portability, and includes support for all POSIX systems.
The database is also flexible & extensible, and can modified by either running
a program to build the entire database, or an entry for just a single terminal.
## More Portable
Tcell is portable to a wider variety of systems. Tcell is believed
to work with all of the systems officially supported by golang with
the exception of nacl (which lacks any kind of a terminal interface).
(Plan9 is not supported by Tcell, but it is experimental status only
in golang.) For all of these systems *except Solaris/illumos*, Tcell
is pure Go, with no need for CGO.
## No Async IO
Tcell is able to operate without requiring SIGIO signals (unlike Termbox),
or asynchronous I/O, and can instead use standard Go file
objects and Go routines. This means it should be safe, especially for
use with programs that use exec, or otherwise need to manipulate the
tty streams. This model is also much closer to idiomatic Go, leading
to fewer surprises.
## Richer Unicode & non-Unicode support
Tcell includes enhanced support for Unicode, including wide characters and
combining characters, provided your terminal can support them. Note that
Windows terminals generally don't support the full Unicode repertoire.
It will also convert to and from Unicode locales, so that the program
can work with UTF-8 internally, and get reasonable output in other locales.
We try hard to convert to native characters on both input and output, and
on output Tcell even makes use of the alternate character set to facilitate
drawing certain characters.
## More Function Keys
It also has richer support for a larger number of special keys that some
terminals can send.
## Better Color Handling
Tcell will respect your terminal's color space as specified within your terminfo
entries, so that for example attempts to emit color sequences on VT100 terminals
won't result in unintended consequences.
In Windows mode, Tcell supports 16 colors, bold, dim, and reverse,
instead of just termbox's 8 colors with reverse. (Note that there is some
conflation with bold/dim and colors.)
Tcell maps 16 colors down to 8, for terminals that need it. (The upper
8 colors are just brighter versions of the lower 8.)
## Better Mouse Support
Tcell supports enhanced mouse tracking mode, so your application can receive
regular mouse motion events, and wheel events, if your terminal supports it.
## Termbox Compatibility
A compatibility layer for termbox is provided in the compat
directory. To use it, try importing "github.com/gdamore/tcell/termbox"
instead. Most termbox-go programs will probably work without further
modification.
## Working With Unicode
Internally Tcell uses UTF-8, just like Go. However, Tcell understands how to
convert to and from other character sets, using the capabilities of
the golang.org/x/text/encoding packages. Your application must supply
them, as the full set of the most common ones bloats the program by about
2MB. If you're lazy, and want them all anyway, see the encoding
sub-directory.
## Wide & Combining Characters
The SetContent() API takes a primary rune, and an optional list of combining
runes. If any of the runes is a wide (East Asian) rune occupying two cells,
then the library will skip output from the following cell, but care must be
taken in the application to avoid explicitly attempting to set content in the
next cell, otherwise the results are undefined. (Normally wide character
is displayed, and the other character is not; do not depend on that behavior.)
Experience has shown that the vanilla Windows 8 console application does not
support any of these characters properly, but at least some options like
ConEmu do support Wide characters at least.
## Colors
Tcell assumes the ANSI/XTerm color model, including the 256 color map that
XTerm uses when it supports 256 colors. The terminfo guidance will be
honored, with respect to the number of colors supported. Also, only
terminals which expose ANSI style setaf and setab will support color;
if you have a color terminal that only has setf and setb, please let me
know; it wouldn't be hard to add that if there is need.
## 24-bit Color
Tcell _supports true color_! (That is, if your terminal can support it,
Tcell can accurately display 24-bit color.)
To use 24-bit color, you need to use a terminal that supports it. Modern
xterm and similar teminal emulators can support this. As terminfo lacks any
way to describe this capability, we fabricate the capability for
terminals with names ending in *-truecolor. The stock distribution ships
with a database that defines xterm-truecolor. To try it out, set your
TERM variable to xterm-truecolor.
When using TrueColor, programs will display the colors that the programmer
intended, overriding any "themes" you may have set in your terminal
emulator. (For some cases, accurate color fidelity is more important
than respecting themes. For other cases, such as typical text apps that
only use a few colors, its more desirable to respect the themes that
the user has established.)
If you find this undesirable, you can either use a TERM variable
that lacks the TRUECOLOR setting, or set TCELL_TRUECOLOR=disable in your
environment.
## Performance
Reasonable attempts have been made to minimize sending data to terminals,
avoiding repeated sequences or drawing the same cell on refresh updates.
## Terminfo
(Not relevent for Windows users.)
The Terminfo implementation operates with two forms of database. The first
is the built-in go database, which contains a number of real database entries
that are compiled into the program directly. This should minimize calling
out to database file searches.
The second is in the form of JSON files, that contain the same information,
which can be located either by the $TCELLDB environment file, $HOME/.tcelldb,
or is located in the Go source directory as database.json.
These files (both the Go and the JSON files) can be generated using the
mkinfo.go program. If you need to regnerate the entire set for some reason,
run the mkdatabase.sh file. The generation uses the infocmp(1) program on
the system to collect the necessary information.
The mkinfo.go program can also be used to generate specific database entries
for named terminals, in case your favorite terminal is missing. (If you
find that this is the case, please let me know and I'll try to add it!)
Tcell requires that the terminal support the 'cup' mode of cursor addressing.
Terminals without absolute cursor addressability are not supported.
This is unlikely to be a problem; such terminals have not been mass produced
since the early 1970s.
## Mouse Support
Mouse support is detected via the "kmous" terminfo variable, however,
enablement/disablement and decoding mouse events is done using hard coded
sequences based on the XTerm X11 model. As of this writing all popular
terminals with mouse tracking support this model. (Full terminfo support
is not possible as terminfo sequences are not defined.)
On Windows, the mouse works normally.
Mouse wheel buttons on various terminals are known to work, but the support
in terminal emulators, as well as support for various buttons and
live mouse tracking, varies widely. As a particular datum, MacOS X Terminal
does not support Mouse events at all (as of MacOS 10.10, aka Yosemite.) The
excellent iTerm application is fully supported, as is vanilla XTerm.
Mouse tracking with live tracking also varies widely. Current XTerm
implementations, as well as current Screen and iTerm2, and Windows
consoles, all support this quite nicely. On other platforms you might
find that only mouse click and release events are reported, with
no intervening motion events. It really depends on your terminal.
## Testablity
There is a SimulationScreen, that can be used to simulate a real screen
for automated testing. The supplied tests do this. The simulation contains
event delivery, screen resizing support, and capabilities to inject events
and examine "physical" screen contents.
## Platforms
### POSIX (Linux, FreeBSD, MacOS, Solaris, etc.)
For mainstream systems with a suitably well defined system call interface
to tty settings, everything works using pure Go.
For the remainder (right now means only Solaris/illumos) we use POSIX function
calls to manage termios, which implies that CGO is required on those platforms.
### Windows
Windows console mode applications are supported. Unfortunately mintty
and other cygwin style applications are not supported.
Modern console applications like ConEmu, as well as the Windows 10
console itself, support all the good features (resize, mouse tracking, etc.)
I haven't figured out how to cleanly resolve the dichotomy between cygwin
style termios and the Windows Console API; it seems that perhaps nobody else
has either. If anyone has suggestions, let me know! Really, if you're
using a Windows application, you should use the native Windows console or a
fully compatible console implementation.
### Plan9 and Native Client (Nacl)
The nacl and plan9 platforms won't work, but compilation stubs are supplied
for folks that want to include parts of this in software targetting those
platforms. The Simulation screen works, but as Tcell doesn't know how to
allocate a real screen object on those platforms, NewScreen() will fail.
If anyone has wisdom about how to improve support for either of these,
please let me know. PRs are especially welcome.
### Commercial Support
This software is absolutely free, but if you want to obtain commercial
support (giving prioritized access to the developer, etc. on an hourly
rate), please drop a line to info@staysail.tech
I also welcome donations at Patreon, if you just want to feel good about
defraying development costs: https://www.patreon.com/gedamore

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
id="svg8"
version="1.1"
viewBox="0 0 210 297"
height="297mm"
width="210mm">
<defs
id="defs2">
<linearGradient
id="linearGradient2680">
<stop
id="stop2676"
offset="0"
style="stop-color:#ababab;stop-opacity:1;" />
<stop
id="stop2678"
offset="1"
style="stop-color:#ababab;stop-opacity:0;" />
</linearGradient>
<marker
style="overflow:visible"
id="Arrow1Lstart"
refX="0.0"
refY="0.0"
orient="auto">
<path
transform="scale(0.8) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path848" />
</marker>
<radialGradient
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.28804762,0,94.764912)"
r="19.622099"
fy="133.10568"
fx="111.58373"
cy="133.10568"
cx="111.58373"
id="radialGradient2684"
xlink:href="#linearGradient2680" />
</defs>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1">
<rect
y="99.44445"
x="31.750006"
height="86.430557"
width="129.64584"
id="rect1130"
style="opacity:1;fill:#5d6c53;fill-opacity:1;stroke:#244f24;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
transform="scale(0.99941234,1.000588)"
id="text1128"
y="160.47581"
x="44.689861"
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:46.0962944px;line-height:1.25;font-family:'Glass TTY VT220';-inkscape-font-specification:'Glass TTY VT220, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#5ef86d;fill-opacity:1;stroke:#59ff32;stroke-width:0.80994618;stroke-opacity:0.94520545;"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:46.0962944px;font-family:'Glass TTY VT220';-inkscape-font-specification:'Glass TTY VT220, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#5ef86d;fill-opacity:1;stroke:#59ff32;stroke-width:0.80994618;stroke-opacity:0.94520545;"
y="160.47581"
x="44.689861"
id="tspan1126">tcell</tspan></text>
<flowRoot
style="fill:black;fill-opacity:1;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;letter-spacing:0px;word-spacing:0px"
id="flowRoot1132"
xml:space="preserve"><flowRegion
id="flowRegion1134"><rect
y="432.51968"
x="290"
height="160"
width="330"
id="rect1136" /></flowRegion><flowPara
id="flowPara1138"></flowPara></flowRoot> </g>
</svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -4,8 +4,10 @@ go_import_path: github.com/godbus/dbus
sudo: true sudo: true
go: go:
- 1.6.3
- 1.7.3 - 1.7.3
- 1.8.7
- 1.9.5
- 1.10.1
- tip - tip
env: env:
@ -38,3 +40,7 @@ addons:
- dbus-x11 - dbus-x11
before_install: before_install:
script:
- go test -v -race ./... # Run all the tests with the race detector enabled
- go vet ./... # go vet is the official Go static analyzer

View File

@ -14,7 +14,7 @@ D-Bus message bus system.
### Installation ### Installation
This packages requires Go 1.1. If you installed it and set up your GOPATH, just run: This packages requires Go 1.7. If you installed it and set up your GOPATH, just run:
``` ```
go get github.com/godbus/dbus go get github.com/godbus/dbus

View File

@ -116,7 +116,6 @@ func (conn *Conn) Auth(methods []Auth) error {
return err return err
} }
go conn.inWorker() go conn.inWorker()
go conn.outWorker()
return nil return nil
} }
} }

16
vendor/github.com/godbus/dbus/auth_anonymous.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
package dbus
// AuthAnonymous returns an Auth that uses the ANONYMOUS mechanism.
func AuthAnonymous() Auth {
return &authAnonymous{}
}
type authAnonymous struct{}
func (a *authAnonymous) FirstData() (name, resp []byte, status AuthStatus) {
return []byte("ANONYMOUS"), nil, AuthOk
}
func (a *authAnonymous) HandleData(data []byte) (resp []byte, status AuthStatus) {
return nil, AuthError
}

View File

@ -1,9 +1,12 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
) )
var errSignature = errors.New("dbus: mismatched signature")
// Call represents a pending or completed method call. // Call represents a pending or completed method call.
type Call struct { type Call struct {
Destination string Destination string
@ -20,9 +23,25 @@ type Call struct {
// Holds the response once the call is done. // Holds the response once the call is done.
Body []interface{} Body []interface{}
// tracks context and canceler
ctx context.Context
ctxCanceler context.CancelFunc
} }
var errSignature = errors.New("dbus: mismatched signature") func (c *Call) Context() context.Context {
if c.ctx == nil {
return context.Background()
}
return c.ctx
}
func (c *Call) ContextCancel() {
if c.ctxCanceler != nil {
c.ctxCanceler()
}
}
// Store stores the body of the reply into the provided pointers. It returns // Store stores the body of the reply into the provided pointers. It returns
// an error if the signatures of the body and retvalues don't match, or if // an error if the signatures of the body and retvalues don't match, or if
@ -34,3 +53,8 @@ func (c *Call) Store(retvalues ...interface{}) error {
return Store(c.Body, retvalues...) return Store(c.Body, retvalues...)
} }
func (c *Call) done() {
c.Done <- c
c.ContextCancel()
}

616
vendor/github.com/godbus/dbus/conn.go generated vendored
View File

@ -1,6 +1,7 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
"io" "io"
"os" "os"
@ -14,7 +15,6 @@ var (
systemBusLck sync.Mutex systemBusLck sync.Mutex
sessionBus *Conn sessionBus *Conn
sessionBusLck sync.Mutex sessionBusLck sync.Mutex
sessionEnvLck sync.Mutex
) )
// ErrClosed is the error returned by calls on a closed connection. // ErrClosed is the error returned by calls on a closed connection.
@ -35,23 +35,13 @@ type Conn struct {
unixFD bool unixFD bool
uuid string uuid string
names []string handler Handler
namesLck sync.RWMutex
serialLck sync.Mutex
nextSerial uint32
serialUsed map[uint32]bool
calls map[uint32]*Call
callsLck sync.RWMutex
handler Handler
out chan *Message
closed bool
outLck sync.RWMutex
signalHandler SignalHandler signalHandler SignalHandler
serialGen SerialGenerator
names *nameTracker
calls *callTracker
outHandler *outputHandler
eavesdropped chan<- *Message eavesdropped chan<- *Message
eavesdroppedLck sync.Mutex eavesdroppedLck sync.Mutex
@ -87,32 +77,31 @@ func SessionBus() (conn *Conn, err error) {
} }
func getSessionBusAddress() (string, error) { func getSessionBusAddress() (string, error) {
sessionEnvLck.Lock() if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" {
defer sessionEnvLck.Unlock() return address, nil
address := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
if address != "" && address != "autolaunch:" { } else if address := tryDiscoverDbusSessionBusAddress(); address != "" {
os.Setenv("DBUS_SESSION_BUS_ADDRESS", address)
return address, nil return address, nil
} }
return getSessionBusPlatformAddress() return getSessionBusPlatformAddress()
} }
// SessionBusPrivate returns a new private connection to the session bus. // SessionBusPrivate returns a new private connection to the session bus.
func SessionBusPrivate() (*Conn, error) { func SessionBusPrivate(opts ...ConnOption) (*Conn, error) {
address, err := getSessionBusAddress() address, err := getSessionBusAddress()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return Dial(address) return Dial(address, opts...)
} }
// SessionBusPrivate returns a new private connection to the session bus. // SessionBusPrivate returns a new private connection to the session bus.
//
// Deprecated: use SessionBusPrivate with options instead.
func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
address, err := getSessionBusAddress() return SessionBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
if err != nil {
return nil, err
}
return DialHandler(address, handler, signalHandler)
} }
// SystemBus returns a shared connection to the system bus, connecting to it if // SystemBus returns a shared connection to the system bus, connecting to it if
@ -145,53 +134,93 @@ func SystemBus() (conn *Conn, err error) {
} }
// SystemBusPrivate returns a new private connection to the system bus. // SystemBusPrivate returns a new private connection to the system bus.
func SystemBusPrivate() (*Conn, error) { func SystemBusPrivate(opts ...ConnOption) (*Conn, error) {
return Dial(getSystemBusPlatformAddress()) return Dial(getSystemBusPlatformAddress(), opts...)
} }
// SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers. // SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers.
//
// Deprecated: use SystemBusPrivate with options instead.
func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
return DialHandler(getSystemBusPlatformAddress(), handler, signalHandler) return SystemBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
} }
// Dial establishes a new private connection to the message bus specified by address. // Dial establishes a new private connection to the message bus specified by address.
func Dial(address string) (*Conn, error) { func Dial(address string, opts ...ConnOption) (*Conn, error) {
tr, err := getTransport(address) tr, err := getTransport(address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newConn(tr, NewDefaultHandler(), NewDefaultSignalHandler()) return newConn(tr, opts...)
} }
// DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers. // DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers.
//
// Deprecated: use Dial with options instead.
func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) { func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) {
tr, err := getTransport(address) return Dial(address, WithSignalHandler(signalHandler))
if err != nil { }
return nil, err
// ConnOption is a connection option.
type ConnOption func(conn *Conn) error
// WithHandler overrides the default handler.
func WithHandler(handler Handler) ConnOption {
return func(conn *Conn) error {
conn.handler = handler
return nil
}
}
// WithSignalHandler overrides the default signal handler.
func WithSignalHandler(handler SignalHandler) ConnOption {
return func(conn *Conn) error {
conn.signalHandler = handler
return nil
}
}
// WithSerialGenerator overrides the default signals generator.
func WithSerialGenerator(gen SerialGenerator) ConnOption {
return func(conn *Conn) error {
conn.serialGen = gen
return nil
} }
return newConn(tr, handler, signalHandler)
} }
// NewConn creates a new private *Conn from an already established connection. // NewConn creates a new private *Conn from an already established connection.
func NewConn(conn io.ReadWriteCloser) (*Conn, error) { func NewConn(conn io.ReadWriteCloser, opts ...ConnOption) (*Conn, error) {
return NewConnHandler(conn, NewDefaultHandler(), NewDefaultSignalHandler()) return newConn(genericTransport{conn}, opts...)
} }
// NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers. // NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers.
//
// Deprecated: use NewConn with options instead.
func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) { func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) {
return newConn(genericTransport{conn}, handler, signalHandler) return NewConn(genericTransport{conn}, WithHandler(handler), WithSignalHandler(signalHandler))
} }
// newConn creates a new *Conn from a transport. // newConn creates a new *Conn from a transport.
func newConn(tr transport, handler Handler, signalHandler SignalHandler) (*Conn, error) { func newConn(tr transport, opts ...ConnOption) (*Conn, error) {
conn := new(Conn) conn := new(Conn)
conn.transport = tr conn.transport = tr
conn.calls = make(map[uint32]*Call) for _, opt := range opts {
conn.out = make(chan *Message, 10) if err := opt(conn); err != nil {
conn.handler = handler return nil, err
conn.signalHandler = signalHandler }
conn.nextSerial = 1 }
conn.serialUsed = map[uint32]bool{0: true} conn.calls = newCallTracker()
if conn.handler == nil {
conn.handler = NewDefaultHandler()
}
if conn.signalHandler == nil {
conn.signalHandler = NewDefaultSignalHandler()
}
if conn.serialGen == nil {
conn.serialGen = newSerialGenerator()
}
conn.outHandler = &outputHandler{conn: conn}
conn.names = newNameTracker()
conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
return conn, nil return conn, nil
} }
@ -206,18 +235,7 @@ func (conn *Conn) BusObject() BusObject {
// and the channels passed to Eavesdrop and Signal are closed. This method must // and the channels passed to Eavesdrop and Signal are closed. This method must
// not be called on shared connections. // not be called on shared connections.
func (conn *Conn) Close() error { func (conn *Conn) Close() error {
conn.outLck.Lock() conn.outHandler.close()
if conn.closed {
// inWorker calls Close on read error, the read error may
// be caused by another caller calling Close to shutdown the
// dbus connection, a double-close scenario we prevent here.
conn.outLck.Unlock()
return nil
}
close(conn.out)
conn.closed = true
conn.outLck.Unlock()
if term, ok := conn.signalHandler.(Terminator); ok { if term, ok := conn.signalHandler.(Terminator); ok {
term.Terminate() term.Terminate()
} }
@ -249,17 +267,9 @@ func (conn *Conn) Eavesdrop(ch chan<- *Message) {
conn.eavesdroppedLck.Unlock() conn.eavesdroppedLck.Unlock()
} }
// getSerial returns an unused serial. // GetSerial returns an unused serial.
func (conn *Conn) getSerial() uint32 { func (conn *Conn) getSerial() uint32 {
conn.serialLck.Lock() return conn.serialGen.GetSerial()
defer conn.serialLck.Unlock()
n := conn.nextSerial
for conn.serialUsed[n] {
n++
}
conn.serialUsed[n] = true
conn.nextSerial = n + 1
return n
} }
// Hello sends the initial org.freedesktop.DBus.Hello call. This method must be // Hello sends the initial org.freedesktop.DBus.Hello call. This method must be
@ -271,10 +281,7 @@ func (conn *Conn) Hello() error {
if err != nil { if err != nil {
return err return err
} }
conn.namesLck.Lock() conn.names.acquireUniqueConnectionName(s)
conn.names = make([]string, 1)
conn.names[0] = s
conn.namesLck.Unlock()
return nil return nil
} }
@ -283,109 +290,48 @@ func (conn *Conn) Hello() error {
func (conn *Conn) inWorker() { func (conn *Conn) inWorker() {
for { for {
msg, err := conn.ReadMessage() msg, err := conn.ReadMessage()
if err == nil { if err != nil {
conn.eavesdroppedLck.Lock() if _, ok := err.(InvalidMessageError); !ok {
if conn.eavesdropped != nil { // Some read error occured (usually EOF); we can't really do
select { // anything but to shut down all stuff and returns errors to all
case conn.eavesdropped <- msg: // pending replies.
default: conn.Close()
} conn.calls.finalizeAllWithError(err)
conn.eavesdroppedLck.Unlock() return
continue }
// invalid messages are ignored
continue
}
conn.eavesdroppedLck.Lock()
if conn.eavesdropped != nil {
select {
case conn.eavesdropped <- msg:
default:
} }
conn.eavesdroppedLck.Unlock() conn.eavesdroppedLck.Unlock()
dest, _ := msg.Headers[FieldDestination].value.(string) continue
found := false
if dest == "" {
found = true
} else {
conn.namesLck.RLock()
if len(conn.names) == 0 {
found = true
}
for _, v := range conn.names {
if dest == v {
found = true
break
}
}
conn.namesLck.RUnlock()
}
if !found {
// Eavesdropped a message, but no channel for it is registered.
// Ignore it.
continue
}
switch msg.Type {
case TypeMethodReply, TypeError:
serial := msg.Headers[FieldReplySerial].value.(uint32)
conn.callsLck.Lock()
if c, ok := conn.calls[serial]; ok {
if msg.Type == TypeError {
name, _ := msg.Headers[FieldErrorName].value.(string)
c.Err = Error{name, msg.Body}
} else {
c.Body = msg.Body
}
c.Done <- c
conn.serialLck.Lock()
delete(conn.serialUsed, serial)
conn.serialLck.Unlock()
delete(conn.calls, serial)
}
conn.callsLck.Unlock()
case TypeSignal:
iface := msg.Headers[FieldInterface].value.(string)
member := msg.Headers[FieldMember].value.(string)
// as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
// sender is optional for signals.
sender, _ := msg.Headers[FieldSender].value.(string)
if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" {
if member == "NameLost" {
// If we lost the name on the bus, remove it from our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the lost name")
}
conn.namesLck.Lock()
for i, v := range conn.names {
if v == name {
conn.names = append(conn.names[:i],
conn.names[i+1:]...)
}
}
conn.namesLck.Unlock()
} else if member == "NameAcquired" {
// If we acquired the name on the bus, add it to our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the acquired name")
}
conn.namesLck.Lock()
conn.names = append(conn.names, name)
conn.namesLck.Unlock()
}
}
conn.handleSignal(msg)
case TypeMethodCall:
go conn.handleCall(msg)
}
} else if _, ok := err.(InvalidMessageError); !ok {
// Some read error occured (usually EOF); we can't really do
// anything but to shut down all stuff and returns errors to all
// pending replies.
conn.Close()
conn.callsLck.RLock()
for _, v := range conn.calls {
v.Err = err
v.Done <- v
}
conn.callsLck.RUnlock()
return
} }
// invalid messages are ignored conn.eavesdroppedLck.Unlock()
dest, _ := msg.Headers[FieldDestination].value.(string)
found := dest == "" ||
!conn.names.uniqueNameIsKnown() ||
conn.names.isKnownName(dest)
if !found {
// Eavesdropped a message, but no channel for it is registered.
// Ignore it.
continue
}
switch msg.Type {
case TypeError:
conn.serialGen.RetireSerial(conn.calls.handleDBusError(msg))
case TypeMethodReply:
conn.serialGen.RetireSerial(conn.calls.handleReply(msg))
case TypeSignal:
conn.handleSignal(msg)
case TypeMethodCall:
go conn.handleCall(msg)
}
} }
} }
@ -395,6 +341,25 @@ func (conn *Conn) handleSignal(msg *Message) {
// as per http://dbus.freedesktop.org/doc/dbus-specification.html , // as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
// sender is optional for signals. // sender is optional for signals.
sender, _ := msg.Headers[FieldSender].value.(string) sender, _ := msg.Headers[FieldSender].value.(string)
if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" {
if member == "NameLost" {
// If we lost the name on the bus, remove it from our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the lost name")
}
conn.names.loseName(name)
} else if member == "NameAcquired" {
// If we acquired the name on the bus, add it to our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the acquired name")
}
conn.names.acquireName(name)
}
}
signal := &Signal{ signal := &Signal{
Sender: sender, Sender: sender,
Path: msg.Headers[FieldPath].value.(ObjectPath), Path: msg.Headers[FieldPath].value.(ObjectPath),
@ -408,12 +373,7 @@ func (conn *Conn) handleSignal(msg *Message) {
// connection. The slice is always at least one element long, the first element // connection. The slice is always at least one element long, the first element
// being the unique name of the connection. // being the unique name of the connection.
func (conn *Conn) Names() []string { func (conn *Conn) Names() []string {
conn.namesLck.RLock() return conn.names.listKnownNames()
// copy the slice so it can't be modified
s := make([]string, len(conn.names))
copy(s, conn.names)
conn.namesLck.RUnlock()
return s
} }
// Object returns the object identified by the given destination name and path. // Object returns the object identified by the given destination name and path.
@ -423,24 +383,17 @@ func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
// outWorker runs in an own goroutine, encoding and sending messages that are // outWorker runs in an own goroutine, encoding and sending messages that are
// sent to conn.out. // sent to conn.out.
func (conn *Conn) outWorker() { func (conn *Conn) sendMessage(msg *Message) {
for msg := range conn.out { conn.sendMessageAndIfClosed(msg, func() {})
err := conn.SendMessage(msg) }
conn.callsLck.RLock()
if err != nil { func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
if c := conn.calls[msg.serial]; c != nil { err := conn.outHandler.sendAndIfClosed(msg, ifClosed)
c.Err = err conn.calls.handleSendError(msg, err)
c.Done <- c if err != nil {
} conn.serialGen.RetireSerial(msg.serial)
conn.serialLck.Lock() } else if msg.Type != TypeMethodCall {
delete(conn.serialUsed, msg.serial) conn.serialGen.RetireSerial(msg.serial)
conn.serialLck.Unlock()
} else if msg.Type != TypeMethodCall {
conn.serialLck.Lock()
delete(conn.serialUsed, msg.serial)
conn.serialLck.Unlock()
}
conn.callsLck.RUnlock()
} }
} }
@ -451,8 +404,21 @@ func (conn *Conn) outWorker() {
// once the call is complete. Otherwise, ch is ignored and a Call structure is // once the call is complete. Otherwise, ch is ignored and a Call structure is
// returned of which only the Err member is valid. // returned of which only the Err member is valid.
func (conn *Conn) Send(msg *Message, ch chan *Call) *Call { func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
var call *Call return conn.send(context.Background(), msg, ch)
}
// SendWithContext acts like Send but takes a context
func (conn *Conn) SendWithContext(ctx context.Context, msg *Message, ch chan *Call) *Call {
return conn.send(ctx, msg, ch)
}
func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
if ctx == nil {
panic("nil context")
}
var call *Call
ctx, canceler := context.WithCancel(ctx)
msg.serial = conn.getSerial() msg.serial = conn.getSerial()
if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 { if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 {
if ch == nil { if ch == nil {
@ -468,26 +434,23 @@ func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
call.Method = iface + "." + member call.Method = iface + "." + member
call.Args = msg.Body call.Args = msg.Body
call.Done = ch call.Done = ch
conn.callsLck.Lock() call.ctx = ctx
conn.calls[msg.serial] = call call.ctxCanceler = canceler
conn.callsLck.Unlock() conn.calls.track(msg.serial, call)
conn.outLck.RLock() go func() {
if conn.closed { <-ctx.Done()
call.Err = ErrClosed conn.calls.handleSendError(msg, ctx.Err())
call.Done <- call }()
} else { conn.sendMessageAndIfClosed(msg, func() {
conn.out <- msg conn.calls.handleSendError(msg, ErrClosed)
} canceler()
conn.outLck.RUnlock() })
} else { } else {
conn.outLck.RLock() canceler()
if conn.closed { call = &Call{Err: nil}
conn.sendMessageAndIfClosed(msg, func() {
call = &Call{Err: ErrClosed} call = &Call{Err: ErrClosed}
} else { })
conn.out <- msg
call = &Call{Err: nil}
}
conn.outLck.RUnlock()
} }
return call return call
} }
@ -520,11 +483,7 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
if len(e.Body) > 0 { if len(e.Body) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...))
} }
conn.outLck.RLock() conn.sendMessage(msg)
if !conn.closed {
conn.out <- msg
}
conn.outLck.RUnlock()
} }
// sendReply creates a method reply message corresponding to the parameters and // sendReply creates a method reply message corresponding to the parameters and
@ -542,11 +501,7 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
if len(values) > 0 { if len(values) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
} }
conn.outLck.RLock() conn.sendMessage(msg)
if !conn.closed {
conn.out <- msg
}
conn.outLck.RUnlock()
} }
func (conn *Conn) defaultSignalAction(fn func(h *defaultSignalHandler, ch chan<- *Signal), ch chan<- *Signal) { func (conn *Conn) defaultSignalAction(fn func(h *defaultSignalHandler, ch chan<- *Signal), ch chan<- *Signal) {
@ -681,3 +636,212 @@ func getKey(s, key string) string {
} }
return "" return ""
} }
type outputHandler struct {
conn *Conn
sendLck sync.Mutex
closed struct {
isClosed bool
lck sync.RWMutex
}
}
func (h *outputHandler) sendAndIfClosed(msg *Message, ifClosed func()) error {
h.closed.lck.RLock()
defer h.closed.lck.RUnlock()
if h.closed.isClosed {
ifClosed()
return nil
}
h.sendLck.Lock()
defer h.sendLck.Unlock()
return h.conn.SendMessage(msg)
}
func (h *outputHandler) close() {
h.closed.lck.Lock()
defer h.closed.lck.Unlock()
h.closed.isClosed = true
}
type serialGenerator struct {
lck sync.Mutex
nextSerial uint32
serialUsed map[uint32]bool
}
func newSerialGenerator() *serialGenerator {
return &serialGenerator{
serialUsed: map[uint32]bool{0: true},
nextSerial: 1,
}
}
func (gen *serialGenerator) GetSerial() uint32 {
gen.lck.Lock()
defer gen.lck.Unlock()
n := gen.nextSerial
for gen.serialUsed[n] {
n++
}
gen.serialUsed[n] = true
gen.nextSerial = n + 1
return n
}
func (gen *serialGenerator) RetireSerial(serial uint32) {
gen.lck.Lock()
defer gen.lck.Unlock()
delete(gen.serialUsed, serial)
}
type nameTracker struct {
lck sync.RWMutex
unique string
names map[string]struct{}
}
func newNameTracker() *nameTracker {
return &nameTracker{names: map[string]struct{}{}}
}
func (tracker *nameTracker) acquireUniqueConnectionName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
tracker.unique = name
}
func (tracker *nameTracker) acquireName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
tracker.names[name] = struct{}{}
}
func (tracker *nameTracker) loseName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
delete(tracker.names, name)
}
func (tracker *nameTracker) uniqueNameIsKnown() bool {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
return tracker.unique != ""
}
func (tracker *nameTracker) isKnownName(name string) bool {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
_, ok := tracker.names[name]
return ok || name == tracker.unique
}
func (tracker *nameTracker) listKnownNames() []string {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
out := make([]string, 0, len(tracker.names)+1)
out = append(out, tracker.unique)
for k := range tracker.names {
out = append(out, k)
}
return out
}
type callTracker struct {
calls map[uint32]*Call
lck sync.RWMutex
}
func newCallTracker() *callTracker {
return &callTracker{calls: map[uint32]*Call{}}
}
func (tracker *callTracker) track(sn uint32, call *Call) {
tracker.lck.Lock()
tracker.calls[sn] = call
tracker.lck.Unlock()
}
func (tracker *callTracker) handleReply(msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock()
_, ok := tracker.calls[serial]
tracker.lck.RUnlock()
if ok {
tracker.finalizeWithBody(serial, msg.Body)
}
return serial
}
func (tracker *callTracker) handleDBusError(msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock()
_, ok := tracker.calls[serial]
tracker.lck.RUnlock()
if ok {
name, _ := msg.Headers[FieldErrorName].value.(string)
tracker.finalizeWithError(serial, Error{name, msg.Body})
}
return serial
}
func (tracker *callTracker) handleSendError(msg *Message, err error) {
if err == nil {
return
}
tracker.lck.RLock()
_, ok := tracker.calls[msg.serial]
tracker.lck.RUnlock()
if ok {
tracker.finalizeWithError(msg.serial, err)
}
}
// finalize was the only func that did not strobe Done
func (tracker *callTracker) finalize(sn uint32) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
c.ContextCancel()
}
return
}
func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) {
tracker.lck.Lock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
}
tracker.lck.Unlock()
if ok {
c.Body = body
c.done()
}
return
}
func (tracker *callTracker) finalizeWithError(sn uint32, err error) {
tracker.lck.Lock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
}
tracker.lck.Unlock()
if ok {
c.Err = err
c.done()
}
return
}
func (tracker *callTracker) finalizeAllWithError(err error) {
tracker.lck.Lock()
closedCalls := make([]*Call, 0, len(tracker.calls))
for sn := range tracker.calls {
closedCalls = append(closedCalls, tracker.calls[sn])
}
tracker.calls = map[uint32]*Call{}
tracker.lck.Unlock()
for _, call := range closedCalls {
call.Err = err
call.done()
}
}

View File

@ -6,12 +6,14 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"os/user"
"path"
"strings"
) )
const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
func getSessionBusPlatformAddress() (string, error) { func getSessionBusPlatformAddress() (string, error) {
cmd := exec.Command("dbus-launch") cmd := exec.Command("dbus-launch")
b, err := cmd.CombinedOutput() b, err := cmd.CombinedOutput()
@ -33,10 +35,57 @@ func getSessionBusPlatformAddress() (string, error) {
return addr, nil return addr, nil
} }
func getSystemBusPlatformAddress() string { // tryDiscoverDbusSessionBusAddress tries to discover an existing dbus session
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") // and return the value of its DBUS_SESSION_BUS_ADDRESS.
if address != "" { // It tries different techniques employed by different operating systems,
return fmt.Sprintf("unix:path=%s", address) // returning the first valid address it finds, or an empty string.
//
// * /run/user/<uid>/bus if this exists, it *is* the bus socket. present on
// Ubuntu 18.04
// * /run/user/<uid>/dbus-session: if this exists, it can be parsed for the bus
// address. present on Ubuntu 16.04
//
// See https://dbus.freedesktop.org/doc/dbus-launch.1.html
func tryDiscoverDbusSessionBusAddress() string {
if runtimeDirectory, err := getRuntimeDirectory(); err == nil {
if runUserBusFile := path.Join(runtimeDirectory, "bus"); fileExists(runUserBusFile) {
// if /run/user/<uid>/bus exists, that file itself
// *is* the unix socket, so return its path
return fmt.Sprintf("unix:path=%s", runUserBusFile)
}
if runUserSessionDbusFile := path.Join(runtimeDirectory, "dbus-session"); fileExists(runUserSessionDbusFile) {
// if /run/user/<uid>/dbus-session exists, it's a
// text file // containing the address of the socket, e.g.:
// DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-E1c73yNqrG
if f, err := ioutil.ReadFile(runUserSessionDbusFile); err == nil {
fileContent := string(f)
prefix := "DBUS_SESSION_BUS_ADDRESS="
if strings.HasPrefix(fileContent, prefix) {
address := strings.TrimRight(strings.TrimPrefix(fileContent, prefix), "\n\r")
return address
}
}
}
}
return ""
}
func getRuntimeDirectory() (string, error) {
if currentUser, err := user.Current(); err != nil {
return "", err
} else {
return fmt.Sprintf("/run/user/%s", currentUser.Uid), nil
}
}
func fileExists(filename string) bool {
if _, err := os.Stat(filename); !os.IsNotExist(err) {
return true
} else {
return false
} }
return defaultSystemBusAddress
} }

18
vendor/github.com/godbus/dbus/conn_unix.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
//+build !windows,!solaris,!darwin
package dbus
import (
"os"
"fmt"
)
const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
func getSystemBusPlatformAddress() string {
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
if address != "" {
return fmt.Sprintf("unix:path=%s", address)
}
return defaultSystemBusAddress
}

15
vendor/github.com/godbus/dbus/conn_windows.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
//+build windows
package dbus
import "os"
const defaultSystemBusAddress = "tcp:host=127.0.0.1,port=12434"
func getSystemBusPlatformAddress() string {
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
if address != "" {
return address
}
return defaultSystemBusAddress
}

View File

@ -191,7 +191,14 @@ func (dec *decoder) decode(s string, depth int) interface{} {
length := dec.decode("u", depth).(uint32) length := dec.decode("u", depth).(uint32)
v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length)) v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length))
// Even for empty arrays, the correct padding must be included // Even for empty arrays, the correct padding must be included
dec.align(alignment(typeFor(s[1:]))) align := alignment(typeFor(s[1:]))
if len(s) > 1 && s[1] == '(' {
//Special case for arrays of structs
//structs decode as a slice of interface{} values
//but the dbus alignment does not match this
align = 8
}
dec.align(align)
spos := dec.pos spos := dec.pos
for dec.pos < spos+int(length) { for dec.pos < spos+int(length) {
ev := dec.decode(s[1:], depth+1) ev := dec.decode(s[1:], depth+1)

View File

@ -21,6 +21,8 @@ func newIntrospectIntf(h *defaultHandler) *exportedIntf {
//NewDefaultHandler returns an instance of the default //NewDefaultHandler returns an instance of the default
//call handler. This is useful if you want to implement only //call handler. This is useful if you want to implement only
//one of the two handlers but not both. //one of the two handlers but not both.
//
// Deprecated: this is the default value, don't use it, it will be unexported.
func NewDefaultHandler() *defaultHandler { func NewDefaultHandler() *defaultHandler {
h := &defaultHandler{ h := &defaultHandler{
objects: make(map[ObjectPath]*exportedObj), objects: make(map[ObjectPath]*exportedObj),
@ -161,6 +163,7 @@ func newExportedObject() *exportedObj {
} }
type exportedObj struct { type exportedObj struct {
mu sync.RWMutex
interfaces map[string]*exportedIntf interfaces map[string]*exportedIntf
} }
@ -168,19 +171,27 @@ func (obj *exportedObj) LookupInterface(name string) (Interface, bool) {
if name == "" { if name == "" {
return obj, true return obj, true
} }
obj.mu.RLock()
defer obj.mu.RUnlock()
intf, exists := obj.interfaces[name] intf, exists := obj.interfaces[name]
return intf, exists return intf, exists
} }
func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) { func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) {
obj.mu.Lock()
defer obj.mu.Unlock()
obj.interfaces[name] = iface obj.interfaces[name] = iface
} }
func (obj *exportedObj) DeleteInterface(name string) { func (obj *exportedObj) DeleteInterface(name string) {
obj.mu.Lock()
defer obj.mu.Unlock()
delete(obj.interfaces, name) delete(obj.interfaces, name)
} }
func (obj *exportedObj) LookupMethod(name string) (Method, bool) { func (obj *exportedObj) LookupMethod(name string) (Method, bool) {
obj.mu.RLock()
defer obj.mu.RUnlock()
for _, intf := range obj.interfaces { for _, intf := range obj.interfaces {
method, exists := intf.LookupMethod(name) method, exists := intf.LookupMethod(name)
if exists { if exists {
@ -220,8 +231,12 @@ func (obj *exportedIntf) isFallbackInterface() bool {
//NewDefaultSignalHandler returns an instance of the default //NewDefaultSignalHandler returns an instance of the default
//signal handler. This is useful if you want to implement only //signal handler. This is useful if you want to implement only
//one of the two handlers but not both. //one of the two handlers but not both.
//
// Deprecated: this is the default value, don't use it, it will be unexported.
func NewDefaultSignalHandler() *defaultSignalHandler { func NewDefaultSignalHandler() *defaultSignalHandler {
return &defaultSignalHandler{} return &defaultSignalHandler{
closeChan: make(chan struct{}),
}
} }
func isDefaultSignalHandler(handler SignalHandler) bool { func isDefaultSignalHandler(handler SignalHandler) bool {
@ -231,32 +246,47 @@ func isDefaultSignalHandler(handler SignalHandler) bool {
type defaultSignalHandler struct { type defaultSignalHandler struct {
sync.RWMutex sync.RWMutex
closed bool closed bool
signals []chan<- *Signal signals []chan<- *Signal
closeChan chan struct{}
} }
func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) { func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
go func() { sh.RLock()
sh.RLock() defer sh.RUnlock()
defer sh.RUnlock() if sh.closed {
if sh.closed { return
}
for _, ch := range sh.signals {
select {
case ch <- signal:
case <-sh.closeChan:
return return
default:
go func() {
select {
case ch <- signal:
case <-sh.closeChan:
return
}
}()
} }
for _, ch := range sh.signals { }
ch <- signal
}
}()
} }
func (sh *defaultSignalHandler) Init() error { func (sh *defaultSignalHandler) Init() error {
sh.Lock() sh.Lock()
sh.signals = make([]chan<- *Signal, 0) sh.signals = make([]chan<- *Signal, 0)
sh.closeChan = make(chan struct{})
sh.Unlock() sh.Unlock()
return nil return nil
} }
func (sh *defaultSignalHandler) Terminate() { func (sh *defaultSignalHandler) Terminate() {
sh.Lock() sh.Lock()
if !sh.closed {
close(sh.closeChan)
}
sh.closed = true sh.closed = true
for _, ch := range sh.signals { for _, ch := range sh.signals {
close(ch) close(ch)

View File

@ -170,11 +170,8 @@ func (conn *Conn) handleCall(msg *Message) {
reply.Body[i] = ret[i] reply.Body[i] = ret[i]
} }
reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...)) reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
conn.outLck.RLock()
if !conn.closed { conn.sendMessage(reply)
conn.out <- reply
}
conn.outLck.RUnlock()
} }
} }
@ -207,12 +204,14 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro
if len(values) > 0 { if len(values) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
} }
conn.outLck.RLock()
defer conn.outLck.RUnlock() var closed bool
if conn.closed { conn.sendMessageAndIfClosed(msg, func() {
closed = true
})
if closed {
return ErrClosed return ErrClosed
} }
conn.out <- msg
return nil return nil
} }

1
vendor/github.com/godbus/dbus/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/godbus/dbus

View File

@ -1,6 +1,7 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
"strings" "strings"
) )
@ -9,7 +10,11 @@ import (
// invoked. // invoked.
type BusObject interface { type BusObject interface {
Call(method string, flags Flags, args ...interface{}) *Call Call(method string, flags Flags, args ...interface{}) *Call
CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call
Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call
GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call
AddMatchSignal(iface, member string, options ...MatchOption) *Call
RemoveMatchSignal(iface, member string, options ...MatchOption) *Call
GetProperty(p string) (Variant, error) GetProperty(p string) (Variant, error)
Destination() string Destination() string
Path() ObjectPath Path() ObjectPath
@ -24,16 +29,73 @@ type Object struct {
// Call calls a method with (*Object).Go and waits for its reply. // Call calls a method with (*Object).Go and waits for its reply.
func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call {
return <-o.Go(method, flags, make(chan *Call, 1), args...).Done return <-o.createCall(context.Background(), method, flags, make(chan *Call, 1), args...).Done
} }
// AddMatchSignal subscribes BusObject to signals from specified interface and // CallWithContext acts like Call but takes a context
// method (member). func (o *Object) CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call {
func (o *Object) AddMatchSignal(iface, member string) *Call { return <-o.createCall(ctx, method, flags, make(chan *Call, 1), args...).Done
return o.Call( }
// MatchOption specifies option for dbus routing match rule. Options can be constructed with WithMatch* helpers.
// For full list of available options consult
// https://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules
type MatchOption struct {
key string
value string
}
// WithMatchOption creates match option with given key and value
func WithMatchOption(key, value string) MatchOption {
return MatchOption{key, value}
}
// WithMatchObjectPath creates match option that filters events based on given path
func WithMatchObjectPath(path ObjectPath) MatchOption {
return MatchOption{"path", string(path)}
}
func formatMatchOptions(options []MatchOption) string {
items := make([]string, 0, len(options))
for _, option := range options {
items = append(items, option.key+"='"+option.value+"'")
}
return strings.Join(items, ",")
}
// AddMatchSignal subscribes BusObject to signals from specified interface,
// method (member). Additional filter rules can be added via WithMatch* option constructors.
// Note: To filter events by object path you have to specify this path via an option.
func (o *Object) AddMatchSignal(iface, member string, options ...MatchOption) *Call {
base := []MatchOption{
{"type", "signal"},
{"interface", iface},
{"member", member},
}
options = append(base, options...)
return o.conn.BusObject().Call(
"org.freedesktop.DBus.AddMatch", "org.freedesktop.DBus.AddMatch",
0, 0,
"type='signal',interface='"+iface+"',member='"+member+"'", formatMatchOptions(options),
)
}
// RemoveMatchSignal unsubscribes BusObject from signals from specified interface,
// method (member). Additional filter rules can be added via WithMatch* option constructors
func (o *Object) RemoveMatchSignal(iface, member string, options ...MatchOption) *Call {
base := []MatchOption{
{"type", "signal"},
{"interface", iface},
{"member", member},
}
options = append(base, options...)
return o.conn.BusObject().Call(
"org.freedesktop.DBus.RemoveMatch",
0,
formatMatchOptions(options),
) )
} }
@ -49,6 +111,18 @@ func (o *Object) AddMatchSignal(iface, member string) *Call {
// If the method parameter contains a dot ('.'), the part before the last dot // If the method parameter contains a dot ('.'), the part before the last dot
// specifies the interface on which the method is called. // specifies the interface on which the method is called.
func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
return o.createCall(context.Background(), method, flags, ch, args...)
}
// GoWithContext acts like Go but takes a context
func (o *Object) GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
return o.createCall(ctx, method, flags, ch, args...)
}
func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
if ctx == nil {
panic("nil context")
}
iface := "" iface := ""
i := strings.LastIndex(method, ".") i := strings.LastIndex(method, ".")
if i != -1 { if i != -1 {
@ -76,28 +150,28 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface
} else if cap(ch) == 0 { } else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Object).Go") panic("dbus: unbuffered channel passed to (*Object).Go")
} }
ctx, cancel := context.WithCancel(ctx)
call := &Call{ call := &Call{
Destination: o.dest, Destination: o.dest,
Path: o.path, Path: o.path,
Method: method, Method: method,
Args: args, Args: args,
Done: ch, Done: ch,
ctxCanceler: cancel,
ctx: ctx,
} }
o.conn.callsLck.Lock() o.conn.calls.track(msg.serial, call)
o.conn.calls[msg.serial] = call o.conn.sendMessageAndIfClosed(msg, func() {
o.conn.callsLck.Unlock() o.conn.calls.handleSendError(msg, ErrClosed)
o.conn.outLck.RLock() cancel()
if o.conn.closed { })
call.Err = ErrClosed go func() {
call.Done <- call <-ctx.Done()
} else { o.conn.calls.handleSendError(msg, ctx.Err())
o.conn.out <- msg }()
}
o.conn.outLck.RUnlock()
return call return call
} }
o.conn.outLck.RLock()
defer o.conn.outLck.RUnlock()
done := make(chan *Call, 1) done := make(chan *Call, 1)
call := &Call{ call := &Call{
Err: nil, Err: nil,
@ -107,11 +181,9 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface
call.Done <- call call.Done <- call
close(done) close(done)
}() }()
if o.conn.closed { o.conn.sendMessageAndIfClosed(msg, func() {
call.Err = ErrClosed call.Err = ErrClosed
return call })
}
o.conn.out <- msg
return call return call
} }

View File

@ -87,3 +87,13 @@ type SignalHandler interface {
type DBusError interface { type DBusError interface {
DBusError() (string, []interface{}) DBusError() (string, []interface{})
} }
// SerialGenerator is responsible for serials generation.
//
// Different approaches for the serial generation can be used,
// maintaining a map guarded with a mutex (the standard way) or
// simply increment an atomic counter.
type SerialGenerator interface {
GetSerial() uint32
RetireSerial(serial uint32)
}

View File

@ -11,7 +11,7 @@ var nativeEndian binary.ByteOrder
func detectEndianness() binary.ByteOrder { func detectEndianness() binary.ByteOrder {
var x uint32 = 0x01020304 var x uint32 = 0x01020304
if *(*byte)(unsafe.Pointer(&x)) == 0x01 { if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
return binary.BigEndian return binary.BigEndian
} }
return binary.LittleEndian return binary.LittleEndian

39
vendor/github.com/godbus/dbus/transport_nonce_tcp.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
//+build !windows
package dbus
import (
"errors"
"io/ioutil"
"net"
)
func init() {
transports["nonce-tcp"] = newNonceTcpTransport
}
func newNonceTcpTransport(keys string) (transport, error) {
host := getKey(keys, "host")
port := getKey(keys, "port")
noncefile := getKey(keys, "noncefile")
if host == "" || port == "" || noncefile == "" {
return nil, errors.New("dbus: unsupported address (must set host, port and noncefile)")
}
protocol, err := tcpFamily(keys)
if err != nil {
return nil, err
}
socket, err := net.Dial(protocol, net.JoinHostPort(host, port))
if err != nil {
return nil, err
}
b, err := ioutil.ReadFile(noncefile)
if err != nil {
return nil, err
}
_, err = socket.Write(b)
if err != nil {
return nil, err
}
return NewConn(socket)
}

View File

@ -31,6 +31,7 @@ func (o *oobReader) Read(b []byte) (n int, err error) {
type unixTransport struct { type unixTransport struct {
*net.UnixConn *net.UnixConn
rdr *oobReader
hasUnixFDs bool hasUnixFDs bool
} }
@ -79,10 +80,15 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// To be sure that all bytes of out-of-band data are read, we use a special // To be sure that all bytes of out-of-band data are read, we use a special
// reader that uses ReadUnix on the underlying connection instead of Read // reader that uses ReadUnix on the underlying connection instead of Read
// and gathers the out-of-band data in a buffer. // and gathers the out-of-band data in a buffer.
rd := &oobReader{conn: t.UnixConn} if t.rdr == nil {
t.rdr = &oobReader{conn: t.UnixConn}
} else {
t.rdr.oob = nil
}
// read the first 16 bytes (the part of the header that has a constant size), // read the first 16 bytes (the part of the header that has a constant size),
// from which we can figure out the length of the rest of the message // from which we can figure out the length of the rest of the message
if _, err := io.ReadFull(rd, csheader[:]); err != nil { if _, err := io.ReadFull(t.rdr, csheader[:]); err != nil {
return nil, err return nil, err
} }
switch csheader[0] { switch csheader[0] {
@ -104,7 +110,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// decode headers and look for unix fds // decode headers and look for unix fds
headerdata := make([]byte, hlen+4) headerdata := make([]byte, hlen+4)
copy(headerdata, csheader[12:]) copy(headerdata, csheader[12:])
if _, err := io.ReadFull(t, headerdata[4:]); err != nil { if _, err := io.ReadFull(t.rdr, headerdata[4:]); err != nil {
return nil, err return nil, err
} }
dec := newDecoder(bytes.NewBuffer(headerdata), order) dec := newDecoder(bytes.NewBuffer(headerdata), order)
@ -122,7 +128,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
all := make([]byte, 16+hlen+blen) all := make([]byte, 16+hlen+blen)
copy(all, csheader[:]) copy(all, csheader[:])
copy(all[16:], headerdata[4:]) copy(all[16:], headerdata[4:])
if _, err := io.ReadFull(rd, all[16+hlen:]); err != nil { if _, err := io.ReadFull(t.rdr, all[16+hlen:]); err != nil {
return nil, err return nil, err
} }
if unixfds != 0 { if unixfds != 0 {
@ -130,7 +136,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
return nil, errors.New("dbus: got unix fds on unsupported transport") return nil, errors.New("dbus: got unix fds on unsupported transport")
} }
// read the fds from the OOB data // read the fds from the OOB data
scms, err := syscall.ParseSocketControlMessage(rd.oob) scms, err := syscall.ParseSocketControlMessage(t.rdr.oob)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -148,11 +154,23 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// substitute the values in the message body (which are indices for the // substitute the values in the message body (which are indices for the
// array receiver via OOB) with the actual values // array receiver via OOB) with the actual values
for i, v := range msg.Body { for i, v := range msg.Body {
if j, ok := v.(UnixFDIndex); ok { switch v.(type) {
case UnixFDIndex:
j := v.(UnixFDIndex)
if uint32(j) >= unixfds { if uint32(j) >= unixfds {
return nil, InvalidMessageError("invalid index for unix fd") return nil, InvalidMessageError("invalid index for unix fd")
} }
msg.Body[i] = UnixFD(fds[j]) msg.Body[i] = UnixFD(fds[j])
case []UnixFDIndex:
idxArray := v.([]UnixFDIndex)
fdArray := make([]UnixFD, len(idxArray))
for k, j := range idxArray {
if uint32(j) >= unixfds {
return nil, InvalidMessageError("invalid index for unix fd")
}
fdArray[k] = UnixFD(fds[j])
}
msg.Body[i] = fdArray
} }
} }
return msg, nil return msg, nil

View File

@ -1292,6 +1292,14 @@ func (c *CommitFile) GetPatch() string {
return *c.Patch return *c.Patch
} }
// GetPreviousFilename returns the PreviousFilename field if it's non-nil, zero value otherwise.
func (c *CommitFile) GetPreviousFilename() string {
if c == nil || c.PreviousFilename == nil {
return ""
}
return *c.PreviousFilename
}
// GetRawURL returns the RawURL field if it's non-nil, zero value otherwise. // GetRawURL returns the RawURL field if it's non-nil, zero value otherwise.
func (c *CommitFile) GetRawURL() string { func (c *CommitFile) GetRawURL() string {
if c == nil || c.RawURL == nil { if c == nil || c.RawURL == nil {
@ -2292,6 +2300,14 @@ func (d *DeploymentStatusRequest) GetDescription() string {
return *d.Description return *d.Description
} }
// GetEnvironment returns the Environment field if it's non-nil, zero value otherwise.
func (d *DeploymentStatusRequest) GetEnvironment() string {
if d == nil || d.Environment == nil {
return ""
}
return *d.Environment
}
// GetEnvironmentURL returns the EnvironmentURL field if it's non-nil, zero value otherwise. // GetEnvironmentURL returns the EnvironmentURL field if it's non-nil, zero value otherwise.
func (d *DeploymentStatusRequest) GetEnvironmentURL() string { func (d *DeploymentStatusRequest) GetEnvironmentURL() string {
if d == nil || d.EnvironmentURL == nil { if d == nil || d.EnvironmentURL == nil {
@ -10100,6 +10116,22 @@ func (s *ServiceHook) GetName() string {
return *s.Name return *s.Name
} }
// GetEnabled returns the Enabled field if it's non-nil, zero value otherwise.
func (s *SignaturesProtectedBranch) GetEnabled() bool {
if s == nil || s.Enabled == nil {
return false
}
return *s.Enabled
}
// GetURL returns the URL field if it's non-nil, zero value otherwise.
func (s *SignaturesProtectedBranch) GetURL() string {
if s == nil || s.URL == nil {
return ""
}
return *s.URL
}
// GetPayload returns the Payload field if it's non-nil, zero value otherwise. // GetPayload returns the Payload field if it's non-nil, zero value otherwise.
func (s *SignatureVerification) GetPayload() string { func (s *SignatureVerification) GetPayload() string {
if s == nil || s.Payload == nil { if s == nil || s.Payload == nil {

View File

@ -54,6 +54,9 @@ const (
// https://developer.github.com/changes/2016-04-06-deployment-and-deployment-status-enhancements/ // https://developer.github.com/changes/2016-04-06-deployment-and-deployment-status-enhancements/
mediaTypeDeploymentStatusPreview = "application/vnd.github.ant-man-preview+json" mediaTypeDeploymentStatusPreview = "application/vnd.github.ant-man-preview+json"
// https://developer.github.com/changes/2018-10-16-deployments-environments-states-and-auto-inactive-updates/
mediaTypeExpandDeploymentStatusPreview = "application/vnd.github.flash-preview+json"
// https://developer.github.com/changes/2016-02-19-source-import-preview-api/ // https://developer.github.com/changes/2016-02-19-source-import-preview-api/
mediaTypeImportPreview = "application/vnd.github.barred-rock-preview" mediaTypeImportPreview = "application/vnd.github.barred-rock-preview"
@ -122,6 +125,9 @@ const (
// https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/ // https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/
mediaTypePreReceiveHooksPreview = "application/vnd.github.eye-scream-preview" mediaTypePreReceiveHooksPreview = "application/vnd.github.eye-scream-preview"
// https://developer.github.com/changes/2018-02-22-protected-branches-required-signatures/
mediaTypeSignaturePreview = "application/vnd.github.zzzax-preview+json"
) )
// A Client manages communication with the GitHub API. // A Client manages communication with the GitHub API.

View File

@ -107,7 +107,7 @@ type PullRequestBranch struct {
// PullRequestsService.List method. // PullRequestsService.List method.
type PullRequestListOptions struct { type PullRequestListOptions struct {
// State filters pull requests based on their state. Possible values are: // State filters pull requests based on their state. Possible values are:
// open, closed. Default is "open". // open, closed, all. Default is "open".
State string `url:"state,omitempty"` State string `url:"state,omitempty"`
// Head filters pull requests by head user and branch name in the format of: // Head filters pull requests by head user and branch name in the format of:

View File

@ -698,6 +698,13 @@ type DismissalRestrictionsRequest struct {
Teams *[]string `json:"teams,omitempty"` Teams *[]string `json:"teams,omitempty"`
} }
// SignaturesProtectedBranch represents the protection status of an individual branch.
type SignaturesProtectedBranch struct {
URL *string `json:"url,omitempty"`
// Commits pushed to matching branches must have verified signatures.
Enabled *bool `json:"enabled,omitempty"`
}
// ListBranches lists branches for the specified repository. // ListBranches lists branches for the specified repository.
// //
// GitHub API docs: https://developer.github.com/v3/repos/#list-branches // GitHub API docs: https://developer.github.com/v3/repos/#list-branches
@ -850,6 +857,67 @@ func (s *RepositoriesService) RemoveBranchProtection(ctx context.Context, owner,
return s.client.Do(ctx, req, nil) return s.client.Do(ctx, req, nil)
} }
// GetSignaturesProtectedBranch gets required signatures of protected branch.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-required-signatures-of-protected-branch
func (s *RepositoriesService) GetSignaturesProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch)
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", mediaTypeSignaturePreview)
p := new(SignaturesProtectedBranch)
resp, err := s.client.Do(ctx, req, p)
if err != nil {
return nil, resp, err
}
return p, resp, nil
}
// RequireSignaturesOnProtectedBranch makes signed commits required on a protected branch.
// It requires admin access and branch protection to be enabled.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#add-required-signatures-of-protected-branch
func (s *RepositoriesService) RequireSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch)
req, err := s.client.NewRequest("POST", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeSignaturePreview)
r := new(SignaturesProtectedBranch)
resp, err := s.client.Do(ctx, req, r)
if err != nil {
return nil, resp, err
}
return r, resp, err
}
// OptionalSignaturesOnProtectedBranch removes required signed commits on a given branch.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-required-signatures-of-protected-branch
func (s *RepositoriesService) OptionalSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeSignaturePreview)
return s.client.Do(ctx, req, nil)
}
// UpdateRequiredStatusChecks updates the required status checks for a given protected branch. // 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 // GitHub API docs: https://developer.github.com/v3/repos/branches/#update-required-status-checks-of-protected-branch

View File

@ -48,16 +48,17 @@ func (c CommitStats) String() string {
// CommitFile represents a file modified in a commit. // CommitFile represents a file modified in a commit.
type CommitFile struct { type CommitFile struct {
SHA *string `json:"sha,omitempty"` SHA *string `json:"sha,omitempty"`
Filename *string `json:"filename,omitempty"` Filename *string `json:"filename,omitempty"`
Additions *int `json:"additions,omitempty"` Additions *int `json:"additions,omitempty"`
Deletions *int `json:"deletions,omitempty"` Deletions *int `json:"deletions,omitempty"`
Changes *int `json:"changes,omitempty"` Changes *int `json:"changes,omitempty"`
Status *string `json:"status,omitempty"` Status *string `json:"status,omitempty"`
Patch *string `json:"patch,omitempty"` Patch *string `json:"patch,omitempty"`
BlobURL *string `json:"blob_url,omitempty"` BlobURL *string `json:"blob_url,omitempty"`
RawURL *string `json:"raw_url,omitempty"` RawURL *string `json:"raw_url,omitempty"`
ContentsURL *string `json:"contents_url,omitempty"` ContentsURL *string `json:"contents_url,omitempty"`
PreviousFilename *string `json:"previous_filename,omitempty"`
} }
func (c CommitFile) String() string { func (c CommitFile) String() string {

View File

@ -9,6 +9,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings"
) )
// Deployment represents a deployment in a repo // Deployment represents a deployment in a repo
@ -116,7 +117,8 @@ 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.
req.Header.Set("Accept", mediaTypeDeploymentStatusPreview) acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeExpandDeploymentStatusPreview}
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)
@ -149,6 +151,7 @@ type DeploymentStatusRequest struct {
State *string `json:"state,omitempty"` State *string `json:"state,omitempty"`
LogURL *string `json:"log_url,omitempty"` LogURL *string `json:"log_url,omitempty"`
Description *string `json:"description,omitempty"` Description *string `json:"description,omitempty"`
Environment *string `json:"environment,omitempty"`
EnvironmentURL *string `json:"environment_url,omitempty"` EnvironmentURL *string `json:"environment_url,omitempty"`
AutoInactive *bool `json:"auto_inactive,omitempty"` AutoInactive *bool `json:"auto_inactive,omitempty"`
} }
@ -189,7 +192,8 @@ 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.
req.Header.Set("Accept", mediaTypeDeploymentStatusPreview) acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeExpandDeploymentStatusPreview}
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)
@ -212,7 +216,8 @@ 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.
req.Header.Set("Accept", mediaTypeDeploymentStatusPreview) acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeExpandDeploymentStatusPreview}
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

@ -65,6 +65,8 @@ Add your issue here on GitHub. Feel free to get in touch if you have any questio
(There are no corresponding tags in the project. I only keep such a history in this README.) (There are no corresponding tags in the project. I only keep such a history in this README.)
- v0.19 (2018-10-28)
- Added `QueueUpdate()` and `QueueEvent()` to `Application` to help with modifications to primitives from goroutines.
- v0.18 (2018-10-18) - v0.18 (2018-10-18)
- `InputField` elements can now be navigated freely. - `InputField` elements can now be navigated freely.
- v0.17 (2018-06-20) - v0.17 (2018-06-20)

View File

@ -1,25 +1,34 @@
package tview package tview
import ( import (
"fmt"
"os"
"sync" "sync"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
) )
// The size of the event/update/redraw channels.
const queueSize = 100
// Application represents the top node of an application. // Application represents the top node of an application.
// //
// It is not strictly required to use this class as none of the other classes // It is not strictly required to use this class as none of the other classes
// depend on it. However, it provides useful tools to set up an application and // depend on it. However, it provides useful tools to set up an application and
// plays nicely with all widgets. // plays nicely with all widgets.
//
// The following command displays a primitive p on the screen until Ctrl-C is
// pressed:
//
// if err := tview.NewApplication().SetRoot(p, true).Run(); err != nil {
// panic(err)
// }
type Application struct { type Application struct {
sync.RWMutex sync.RWMutex
// The application's screen. // The application's screen.
screen tcell.Screen screen tcell.Screen
// Indicates whether the application's screen is currently active. // Indicates whether the application's screen is currently active. This is
// false during suspended mode.
running bool running bool
// The primitive which currently has the keyboard focus. // The primitive which currently has the keyboard focus.
@ -44,13 +53,23 @@ type Application struct {
// was drawn. // was drawn.
afterDraw func(screen tcell.Screen) afterDraw func(screen tcell.Screen)
// Halts the event loop during suspended mode. // Used to send screen events from separate goroutine to main event loop
suspendMutex sync.Mutex events chan tcell.Event
// Functions queued from goroutines, used to serialize updates to primitives.
updates chan func()
// A channel which signals the end of the suspended mode.
suspendToken chan struct{}
} }
// NewApplication creates and returns a new application. // NewApplication creates and returns a new application.
func NewApplication() *Application { func NewApplication() *Application {
return &Application{} return &Application{
events: make(chan tcell.Event, queueSize),
updates: make(chan func(), queueSize),
suspendToken: make(chan struct{}, 1),
}
} }
// SetInputCapture sets a function which captures all key events before they are // SetInputCapture sets a function which captures all key events before they are
@ -134,65 +153,105 @@ func (a *Application) Run() error {
// Draw the screen for the first time. // Draw the screen for the first time.
a.Unlock() a.Unlock()
a.Draw() a.draw()
// Separate loop to wait for screen events.
var wg sync.WaitGroup
wg.Add(1)
a.suspendToken <- struct{}{} // We need this to get started.
go func() {
defer wg.Done()
for range a.suspendToken {
for {
a.RLock()
screen := a.screen
a.RUnlock()
if screen == nil {
// We have no screen. We might need to stop.
break
}
// Wait for next event and queue it.
event := screen.PollEvent()
if event != nil {
// Regular event. Queue.
a.QueueEvent(event)
continue
}
// A screen was finalized (event is nil).
a.RLock()
running := a.running
a.RUnlock()
if running {
// The application was stopped. End the event loop.
a.QueueEvent(nil)
return
}
// We're in suspended mode (running is false). Pause and wait for new
// token.
break
}
}
}()
// Start event loop. // Start event loop.
EventLoop:
for { for {
// Do not poll events during suspend mode select {
a.suspendMutex.Lock() case event := <-a.events:
a.RLock() if event == nil {
screen := a.screen break EventLoop
a.RUnlock() }
if screen == nil {
a.suspendMutex.Unlock()
break
}
// Wait for next event. switch event := event.(type) {
event := a.screen.PollEvent() case *tcell.EventKey:
a.suspendMutex.Unlock() a.RLock()
if event == nil { p := a.focus
// The screen was finalized. Exit the loop. inputCapture := a.inputCapture
break a.RUnlock()
}
switch event := event.(type) { // Intercept keys.
case *tcell.EventKey: if inputCapture != nil {
a.RLock() event = inputCapture(event)
p := a.focus if event == nil {
a.RUnlock() continue // Don't forward event.
}
// Intercept keys.
if a.inputCapture != nil {
event = a.inputCapture(event)
if event == nil {
break // Don't forward event.
} }
}
// Ctrl-C closes the application. // Ctrl-C closes the application.
if event.Key() == tcell.KeyCtrlC { if event.Key() == tcell.KeyCtrlC {
a.Stop() a.Stop()
}
// Pass other key events to the currently focused primitive.
if p != nil {
if handler := p.InputHandler(); handler != nil {
handler(event, func(p Primitive) {
a.SetFocus(p)
})
a.Draw()
} }
// Pass other key events to the currently focused primitive.
if p != nil {
if handler := p.InputHandler(); handler != nil {
handler(event, func(p Primitive) {
a.SetFocus(p)
})
a.draw()
}
}
case *tcell.EventResize:
a.RLock()
screen := a.screen
a.RUnlock()
screen.Clear()
a.draw()
} }
case *tcell.EventResize:
a.RLock() // If we have updates, now is the time to execute them.
screen := a.screen case updater := <-a.updates:
a.RUnlock() updater()
screen.Clear()
a.Draw()
} }
} }
a.running = false
close(a.suspendToken)
wg.Wait()
return nil return nil
} }
@ -200,12 +259,13 @@ func (a *Application) Run() error {
func (a *Application) Stop() { func (a *Application) Stop() {
a.Lock() a.Lock()
defer a.Unlock() defer a.Unlock()
if a.screen == nil { screen := a.screen
if screen == nil {
return return
} }
a.screen.Fini()
a.screen = nil a.screen = nil
a.running = false screen.Fini()
// a.running is still true, the main loop will clean up.
} }
// Suspend temporarily suspends the application by exiting terminal UI mode and // Suspend temporarily suspends the application by exiting terminal UI mode and
@ -216,32 +276,26 @@ func (a *Application) Stop() {
// was called. If false is returned, the application was already suspended, // was called. If false is returned, the application was already suspended,
// terminal UI mode was not exited, and "f" was not called. // terminal UI mode was not exited, and "f" was not called.
func (a *Application) Suspend(f func()) bool { func (a *Application) Suspend(f func()) bool {
a.RLock() a.Lock()
if a.screen == nil { screen := a.screen
if screen == nil {
// Screen has not yet been initialized. // Screen has not yet been initialized.
a.RUnlock() a.Unlock()
return false return false
} }
// Enter suspended mode. // Enter suspended mode. Make a new screen here already so our event loop can
a.suspendMutex.Lock() // continue.
defer a.suspendMutex.Unlock() a.screen = nil
a.RUnlock() a.running = false
a.Stop() screen.Fini()
a.Unlock()
// Deal with panics during suspended mode. Exit the program.
defer func() {
if p := recover(); p != nil {
fmt.Println(p)
os.Exit(1)
}
}()
// Wait for "f" to return. // Wait for "f" to return.
f() f()
// Make a new screen and redraw. // Initialize our new screen and draw the contents.
a.Lock() a.Lock()
var err error var err error
a.screen, err = tcell.NewScreen() a.screen, err = tcell.NewScreen()
@ -255,15 +309,26 @@ func (a *Application) Suspend(f func()) bool {
} }
a.running = true a.running = true
a.Unlock() a.Unlock()
a.Draw() a.draw()
a.suspendToken <- struct{}{}
// One key event will get lost, see https://github.com/gdamore/tcell/issues/194
// Continue application loop. // Continue application loop.
return true return true
} }
// Draw refreshes the screen. It calls the Draw() function of the application's // Draw refreshes the screen (during the next update cycle). It calls the Draw()
// root primitive and then syncs the screen buffer. // function of the application's root primitive and then syncs the screen
// buffer.
func (a *Application) Draw() *Application { func (a *Application) Draw() *Application {
a.QueueUpdate(func() {
a.draw()
})
return a
}
// draw actually does what Draw() promises to do.
func (a *Application) draw() *Application {
a.Lock() a.Lock()
defer a.Unlock() defer a.Unlock()
@ -404,3 +469,35 @@ func (a *Application) GetFocus() Primitive {
defer a.RUnlock() defer a.RUnlock()
return a.focus return a.focus
} }
// QueueUpdate is used to synchronize access to primitives from non-main
// goroutines. The provided function will be executed as part of the event loop
// and thus will not cause race conditions with other such update functions or
// the Draw() function.
//
// Note that Draw() is not implicitly called after the execution of f as that
// may not be desirable. You can call Draw() from f if the screen should be
// refreshed after each update. Alternatively, use QueueUpdateDraw() to follow
// up with an immediate refresh of the screen.
func (a *Application) QueueUpdate(f func()) *Application {
a.updates <- f
return a
}
// QueueUpdateDraw works like QueueUpdate() except it refreshes the screen
// immediately after executing f.
func (a *Application) QueueUpdateDraw(f func()) *Application {
a.QueueUpdate(func() {
f()
a.draw()
})
return a
}
// QueueEvent sends an event to the Application event loop.
//
// It is not recommended for event to be nil.
func (a *Application) QueueEvent(event tcell.Event) *Application {
a.events <- event
return a
}

21
vendor/github.com/rivo/tview/doc.go generated vendored
View File

@ -137,6 +137,27 @@ Unicode Support
This package supports unicode characters including wide characters. This package supports unicode characters including wide characters.
Concurrency
Many functions in this package are not thread-safe. For many applications, this
may not be an issue: If your code makes changes in response to key events, it
will execute in the main goroutine and thus will not cause any race conditions.
If you access your primitives from other goroutines, however, you will need to
synchronize execution. The easiest way to do this is to call
Application.QueueUpdate() or Application.QueueUpdateDraw() (see the function
documentation for details):
go func() {
app.QueueUpdateDraw(func() {
table.SetCellSimple(0, 0, "Foo bar")
})
}()
One exception to this is the io.Writer interface implemented by TextView. You
can safely write to a TextView from any goroutine. See the TextView
documentation for details.
Type Hierarchy Type Hierarchy
All widgets listed above contain the Box type. All of Box's functions are All widgets listed above contain the Box type. All of Box's functions are

View File

@ -102,6 +102,7 @@ func NewInputField() *InputField {
// SetText sets the current text of the input field. // SetText sets the current text of the input field.
func (i *InputField) SetText(text string) *InputField { func (i *InputField) SetText(text string) *InputField {
i.text = text i.text = text
i.cursorPos = len(text)
if i.changed != nil { if i.changed != nil {
i.changed(text) i.changed(text)
} }
@ -359,21 +360,22 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
i.cursorPos = len(i.text) - len(regexp.MustCompile(`^\s*\S+\s*`).ReplaceAllString(i.text[i.cursorPos:], "")) i.cursorPos = len(i.text) - len(regexp.MustCompile(`^\s*\S+\s*`).ReplaceAllString(i.text[i.cursorPos:], ""))
} }
// Add character function. Returns whether or not the rune character is
// accepted.
add := func(r rune) bool {
newText := i.text[:i.cursorPos] + string(r) + i.text[i.cursorPos:]
if i.accept != nil {
return i.accept(newText, r)
}
i.text = newText
i.cursorPos += len(string(r))
return true
}
// Process key event. // Process key event.
switch key := event.Key(); key { switch key := event.Key(); key {
case tcell.KeyRune: // Regular character. case tcell.KeyRune: // Regular character.
modifiers := event.Modifiers() if event.Modifiers()&tcell.ModAlt > 0 {
if modifiers == tcell.ModNone {
ch := string(event.Rune())
newText := i.text[:i.cursorPos] + ch + i.text[i.cursorPos:]
if i.accept != nil {
if !i.accept(newText, event.Rune()) {
break
}
}
i.text = newText
i.cursorPos += len(ch)
} else if modifiers&tcell.ModAlt > 0 {
// We accept some Alt- key combinations. // We accept some Alt- key combinations.
switch event.Rune() { switch event.Rune() {
case 'a': // Home. case 'a': // Home.
@ -385,6 +387,11 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
case 'f': // Move word right. case 'f': // Move word right.
moveWordRight() moveWordRight()
} }
} else {
// Other keys are simply accepted as regular characters.
if !add(event.Rune()) {
break
}
} }
case tcell.KeyCtrlU: // Delete all. case tcell.KeyCtrlU: // Delete all.
i.text = "" i.text = ""

View File

@ -389,7 +389,7 @@ func (t *Table) SetDoneFunc(handler func(key tcell.Key)) *Table {
} }
// SetCell sets the content of a cell the specified position. It is ok to // SetCell sets the content of a cell the specified position. It is ok to
// directly instantiate a TableCell object. If the cell has contain, at least // directly instantiate a TableCell object. If the cell has content, at least
// the Text and Color fields should be set. // the Text and Color fields should be set.
// //
// Note that setting cells in previously unknown rows and columns will // Note that setting cells in previously unknown rows and columns will
@ -422,7 +422,7 @@ func (t *Table) SetCellSimple(row, column int, text string) *Table {
} }
// GetCell returns the contents of the cell at the specified position. A valid // GetCell returns the contents of the cell at the specified position. A valid
// TableCell object is always returns but it will be uninitialized if the cell // TableCell object is always returned but it will be uninitialized if the cell
// was not previously set. // was not previously set.
func (t *Table) GetCell(row, column int) *TableCell { func (t *Table) GetCell(row, column int) *TableCell {
if row >= len(t.cells) || column >= len(t.cells[row]) { if row >= len(t.cells) || column >= len(t.cells[row]) {
@ -431,6 +431,31 @@ func (t *Table) GetCell(row, column int) *TableCell {
return t.cells[row][column] return t.cells[row][column]
} }
// RemoveRow removes the row at the given position from the table. If there is
// no such row, this has no effect.
func (t *Table) RemoveRow(row int) *Table {
if row < 0 || row >= len(t.cells) {
return t
}
t.cells = append(t.cells[:row], t.cells[row+1:]...)
return t
}
// RemoveColumn removes the column at the given position from the table. If
// there is no such column, this has no effect.
func (t *Table) RemoveColumn(column int) *Table {
for row := range t.cells {
if column < 0 || column >= len(t.cells[row]) {
continue
}
t.cells[row] = append(t.cells[row][:column], t.cells[row][column+1:]...)
}
return t
}
// GetRowCount returns the number of rows in the table. // GetRowCount returns the number of rows in the table.
func (t *Table) GetRowCount() int { func (t *Table) GetRowCount() int {
return len(t.cells) return len(t.cells)

View File

@ -31,7 +31,7 @@ type textViewIndex struct {
// TextView is a box which displays text. It implements the io.Writer interface // TextView is a box which displays text. It implements the io.Writer interface
// so you can stream text to it. This does not trigger a redraw automatically // so you can stream text to it. This does not trigger a redraw automatically
// but if a handler is installed via SetChangedFunc(), you can cause it to be // but if a handler is installed via SetChangedFunc(), you can cause it to be
// redrawn. // redrawn. (See SetChangedFunc() for more details.)
// //
// Navigation // Navigation
// //
@ -260,8 +260,20 @@ func (t *TextView) SetRegions(regions bool) *TextView {
} }
// SetChangedFunc sets a handler function which is called when the text of the // SetChangedFunc sets a handler function which is called when the text of the
// text view has changed. This is typically used to cause the application to // text view has changed. This is useful when text is written to this io.Writer
// redraw the screen. // in a separate goroutine. This does not automatically cause the screen to be
// refreshed so you may want to use the "changed" handler to redraw the screen.
//
// Note that to avoid race conditions or deadlocks, there are a few rules you
// should follow:
//
// - You can call Application.Draw() from this handler.
// - You can call TextView.HasFocus() from this handler.
// - During the execution of this handler, access to any other variables from
// this primitive or any other primitive should be queued using
// Application.QueueUpdate().
//
// See package description for details on dealing with concurrency.
func (t *TextView) SetChangedFunc(handler func()) *TextView { func (t *TextView) SetChangedFunc(handler func()) *TextView {
t.changed = handler t.changed = handler
return t return t
@ -441,13 +453,33 @@ func (t *TextView) GetRegionText(regionID string) string {
return escapePattern.ReplaceAllString(buffer.String(), `[$1$2]`) return escapePattern.ReplaceAllString(buffer.String(), `[$1$2]`)
} }
// Focus is called when this primitive receives focus.
func (t *TextView) Focus(delegate func(p Primitive)) {
// Implemented here with locking because this is used by layout primitives.
t.Lock()
defer t.Unlock()
t.hasFocus = true
}
// HasFocus returns whether or not this primitive has focus.
func (t *TextView) HasFocus() bool {
// Implemented here with locking because this may be used in the "changed"
// callback.
t.Lock()
defer t.Unlock()
return t.hasFocus
}
// Write lets us implement the io.Writer interface. Tab characters will be // Write lets us implement the io.Writer interface. Tab characters will be
// replaced with TabSize space characters. A "\n" or "\r\n" will be interpreted // replaced with TabSize space characters. A "\n" or "\r\n" will be interpreted
// as a new line. // as a new line.
func (t *TextView) Write(p []byte) (n int, err error) { func (t *TextView) Write(p []byte) (n int, err error) {
// Notify at the end. // Notify at the end.
if t.changed != nil { t.Lock()
defer t.changed() changed := t.changed
t.Unlock()
if changed != nil {
defer changed() // Deadlocks may occur if we lock here.
} }
t.Lock() t.Lock()
@ -840,18 +872,21 @@ func (t *TextView) Draw(screen tcell.Screen) {
// Print the line. // Print the line.
var colorPos, regionPos, escapePos, tagOffset, skipped int var colorPos, regionPos, escapePos, tagOffset, skipped int
iterateString(strippedText, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool { iterateString(strippedText, func(main rune, comb []rune, textPos, textWidth, screenPos, screenWidth int) bool {
// Get the color. // Process tags.
if colorPos < len(colorTags) && textPos+tagOffset >= colorTagIndices[colorPos][0] && textPos+tagOffset < colorTagIndices[colorPos][1] { for {
foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colorTags[colorPos]) if colorPos < len(colorTags) && textPos+tagOffset >= colorTagIndices[colorPos][0] && textPos+tagOffset < colorTagIndices[colorPos][1] {
tagOffset += colorTagIndices[colorPos][1] - colorTagIndices[colorPos][0] // Get the color.
colorPos++ foregroundColor, backgroundColor, attributes = styleFromTag(foregroundColor, backgroundColor, attributes, colorTags[colorPos])
} tagOffset += colorTagIndices[colorPos][1] - colorTagIndices[colorPos][0]
colorPos++
// Get the region. } else if regionPos < len(regionIndices) && textPos+tagOffset >= regionIndices[regionPos][0] && textPos+tagOffset < regionIndices[regionPos][1] {
if regionPos < len(regionIndices) && textPos+tagOffset >= regionIndices[regionPos][0] && textPos+tagOffset < regionIndices[regionPos][1] { // Get the region.
regionID = regions[regionPos][1] regionID = regions[regionPos][1]
tagOffset += regionIndices[regionPos][1] - regionIndices[regionPos][0] tagOffset += regionIndices[regionPos][1] - regionIndices[regionPos][0]
regionPos++ regionPos++
} else {
break
}
} }
// Skip the second-to-last character of an escape tag. // Skip the second-to-last character of an escape tag.
@ -894,7 +929,7 @@ func (t *TextView) Draw(screen tcell.Screen) {
} }
// Stop at the right border. // Stop at the right border.
if posX+screenWidth >= width { if posX+screenWidth > width {
return true return true
} }

View File

@ -569,7 +569,7 @@ func (t *TreeView) Draw(screen tcell.Screen) {
// Draw the tree. // Draw the tree.
posY := y posY := y
lineStyle := tcell.StyleDefault.Foreground(t.graphicsColor) lineStyle := tcell.StyleDefault.Background(t.backgroundColor).Foreground(t.graphicsColor)
for index, node := range t.nodes { for index, node := range t.nodes {
// Skip invisible parts. // Skip invisible parts.
if posY >= y+height+1 { if posY >= y+height+1 {

View File

@ -46,7 +46,7 @@ to add new and/or missing endpoints. Currently the following services are suppor
- [x] Jobs - [x] Jobs
- [x] Keys - [x] Keys
- [x] Labels - [x] Labels
- [ ] License - [x] License
- [x] Merge Requests - [x] Merge Requests
- [x] Merge Request Approvals - [x] Merge Request Approvals
- [x] Project Milestones - [x] Project Milestones

View File

@ -303,6 +303,7 @@ type Client struct {
Keys *KeysService Keys *KeysService
Boards *IssueBoardsService Boards *IssueBoardsService
Labels *LabelsService Labels *LabelsService
License *LicenseService
LicenseTemplates *LicenseTemplatesService LicenseTemplates *LicenseTemplatesService
MergeRequests *MergeRequestsService MergeRequests *MergeRequestsService
MergeRequestApprovals *MergeRequestApprovalsService MergeRequestApprovals *MergeRequestApprovalsService
@ -442,6 +443,7 @@ func newClient(httpClient *http.Client) *Client {
c.Keys = &KeysService{client: c} c.Keys = &KeysService{client: c}
c.Boards = &IssueBoardsService{client: c} c.Boards = &IssueBoardsService{client: c}
c.Labels = &LabelsService{client: c} c.Labels = &LabelsService{client: c}
c.License = &LicenseService{client: c}
c.LicenseTemplates = &LicenseTemplatesService{client: c} c.LicenseTemplates = &LicenseTemplatesService{client: c}
c.MergeRequests = &MergeRequestsService{client: c, timeStats: timeStats} c.MergeRequests = &MergeRequestsService{client: c, timeStats: timeStats}
c.MergeRequestApprovals = &MergeRequestApprovalsService{client: c} c.MergeRequestApprovals = &MergeRequestApprovalsService{client: c}

7
vendor/github.com/xanzy/go-gitlab/go.mod generated vendored Normal file
View File

@ -0,0 +1,7 @@
module github.com/xanzy/go-gitlab
require (
github.com/google/go-querystring v1.0.0
golang.org/x/net v0.0.0-20181108082009-03003ca0c849 // indirect
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288
)

6
vendor/github.com/xanzy/go-gitlab/go.sum generated vendored Normal file
View File

@ -0,0 +1,6 @@
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=
golang.org/x/net v0.0.0-20181108082009-03003ca0c849 h1:FSqE2GGG7wzsYUsWiQ8MZrvEd1EOyU3NCF0AW3Wtltg=
golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288 h1:JIqe8uIcRBHXDQVvZtHwp80ai3Lw3IJAeJEs55Dc1W0=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=

View File

@ -42,30 +42,30 @@ type Issue struct {
ProjectID int `json:"project_id"` ProjectID int `json:"project_id"`
Milestone *Milestone `json:"milestone"` Milestone *Milestone `json:"milestone"`
Author struct { Author struct {
ID int `json:"id"` ID int `json:"id"`
Username string `json:"username"` State string `json:"state"`
Email string `json:"email"` WebURL string `json:"web_url"`
Name string `json:"name"` Name string `json:"name"`
State string `json:"state"` AvatarURL string `json:"avatar_url"`
CreatedAt *time.Time `json:"created_at"` Username string `json:"username"`
} `json:"author"` } `json:"author"`
Description string `json:"description"` Description string `json:"description"`
State string `json:"state"` State string `json:"state"`
Assignees []struct { Assignees []struct {
ID int `json:"id"` ID int `json:"id"`
Username string `json:"username"` State string `json:"state"`
Email string `json:"email"` WebURL string `json:"web_url"`
Name string `json:"name"` Name string `json:"name"`
State string `json:"state"` AvatarURL string `json:"avatar_url"`
CreatedAt *time.Time `json:"created_at"` Username string `json:"username"`
} `json:"assignees"` } `json:"assignees"`
Assignee struct { Assignee struct {
ID int `json:"id"` ID int `json:"id"`
Name string `json:"name"`
Username string `json:"username"`
State string `json:"state"` State string `json:"state"`
AvatarURL string `json:"avatar_url"`
WebURL string `json:"web_url"` WebURL string `json:"web_url"`
Name string `json:"name"`
AvatarURL string `json:"avatar_url"`
Username string `json:"username"`
} `json:"assignee"` } `json:"assignee"`
Upvotes int `json:"upvotes"` Upvotes int `json:"upvotes"`
Downvotes int `json:"downvotes"` Downvotes int `json:"downvotes"`

94
vendor/github.com/xanzy/go-gitlab/license.go generated vendored Normal file
View File

@ -0,0 +1,94 @@
//
// Copyright 2018, Patrick Webster
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package gitlab
// LicenseService handles communication with the license
// related methods of the GitLab API.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html
type LicenseService struct {
client *Client
}
// License represents a GitLab license.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html
type License struct {
StartsAt *ISOTime `json:"starts_at"`
ExpiresAt *ISOTime `json:"expires_at"`
Licensee struct {
Name string `json:"Name"`
Company string `json:"Company"`
Email string `json:"Email"`
} `json:"licensee"`
UserLimit int `json:"user_limit"`
ActiveUsers int `json:"active_users"`
AddOns struct {
GitLabFileLocks int `json:"GitLabFileLocks"`
} `json:"add_ons"`
}
func (l License) String() string {
return Stringify(l)
}
// GetLicense retrieves information about the current license.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html#retrieve-information-about-the-current-license
func (s *LicenseService) GetLicense() (*License, *Response, error) {
req, err := s.client.NewRequest("GET", "license", nil, nil)
if err != nil {
return nil, nil, err
}
l := new(License)
resp, err := s.client.Do(req, l)
if err != nil {
return nil, resp, err
}
return l, resp, err
}
// AddLicenseOptions represents the available AddLicense() options.
//
// https://docs.gitlab.com/ee/api/license.html#add-a-new-license
type AddLicenseOptions struct {
License *string `url:"license" json:"license"`
}
// AddLicense adds a new license.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/license.html#add-a-new-license
func (s *LicenseService) AddLicense(opt *AddLicenseOptions, options ...OptionFunc) (*License, *Response, error) {
req, err := s.client.NewRequest("POST", "license", opt, options)
if err != nil {
return nil, nil, err
}
l := new(License)
resp, err := s.client.Do(req, l)
if err != nil {
return nil, resp, err
}
return l, resp, err
}

View File

@ -77,7 +77,7 @@ func (m MergeRequestApprovals) String() string {
// GitLab API docs: // GitLab API docs:
// https://docs.gitlab.com/ee/api/merge_request_approvals.html#approve-merge-request // https://docs.gitlab.com/ee/api/merge_request_approvals.html#approve-merge-request
type ApproveMergeRequestOptions struct { type ApproveMergeRequestOptions struct {
Sha *string `url:"sha,omitempty" json:"sha,omitempty"` SHA *string `url:"sha,omitempty" json:"sha,omitempty"`
} }
// ApproveMergeRequest approves a merge request on GitLab. If a non-empty sha // ApproveMergeRequest approves a merge request on GitLab. If a non-empty sha
@ -92,7 +92,7 @@ func (s *MergeRequestApprovalsService) ApproveMergeRequest(pid interface{}, mr i
} }
u := fmt.Sprintf("projects/%s/merge_requests/%d/approve", url.QueryEscape(project), mr) u := fmt.Sprintf("projects/%s/merge_requests/%d/approve", url.QueryEscape(project), mr)
req, err := s.client.NewRequest("GET", u, opt, options) req, err := s.client.NewRequest("POST", u, opt, options)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -117,7 +117,7 @@ func (s *MergeRequestApprovalsService) UnapproveMergeRequest(pid interface{}, mr
} }
u := fmt.Sprintf("projects/%s/merge_requests/%d/unapprove", url.QueryEscape(project), mr) u := fmt.Sprintf("projects/%s/merge_requests/%d/unapprove", url.QueryEscape(project), mr)
req, err := s.client.NewRequest("GET", u, nil, options) req, err := s.client.NewRequest("POST", u, nil, options)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1026,3 +1026,149 @@ func (s *ProjectsService) ListProjectForks(pid interface{}, opt *ListProjectsOpt
return forks, resp, err return forks, resp, err
} }
// ProjectPushRules represents a project push rule.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/projects.html#push-rules
type ProjectPushRules struct {
ID int `json:"id"`
ProjectID int `json:"project_id"`
CommitMessageRegex string `json:"commit_message_regex"`
BranchNameRegex string `json:"branch_name_regex"`
DenyDeleteTag bool `json:"deny_delete_tag"`
CreatedAt *time.Time `json:"created_at"`
MemberCheck bool `json:"member_check"`
PreventSecrets bool `json:"prevent_secrets"`
AuthorEmailRegex string `json:"author_email_regex"`
FileNameRegex string `json:"file_name_regex"`
MaxFileSize int `json:"max_file_size"`
}
// GetProjectPushRules gets the push rules of a project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/projects.html#get-project-push-rules
func (s *ProjectsService) GetProjectPushRules(pid interface{}, options ...OptionFunc) (*ProjectPushRules, *Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("projects/%s/push_rule", url.QueryEscape(project))
req, err := s.client.NewRequest("GET", u, nil, options)
if err != nil {
return nil, nil, err
}
ppr := new(ProjectPushRules)
resp, err := s.client.Do(req, ppr)
if err != nil {
return nil, resp, err
}
return ppr, resp, err
}
// AddProjectPushRuleOptions represents the available AddProjectPushRule()
// options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/projects.html#add-project-push-rule
type AddProjectPushRuleOptions struct {
DenyDeleteTag *bool `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"`
MemberCheck *bool `url:"member_check,omitempty" json:"member_check,omitempty"`
PreventSecrets *bool `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"`
CommitMessageRegex *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"`
BranchNameRegex *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"`
AuthorEmailRegex *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"`
FileNameRegex *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"`
MaxFileSize *int `url:"max_file_size,omitempty" json:"max_file_size,omitempty"`
}
// AddProjectPushRule adds a push rule to a specified project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/projects.html#add-project-push-rule
func (s *ProjectsService) AddProjectPushRule(pid interface{}, opt *AddProjectPushRuleOptions, options ...OptionFunc) (*ProjectPushRules, *Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("projects/%s/push_rule", url.QueryEscape(project))
req, err := s.client.NewRequest("POST", u, opt, options)
if err != nil {
return nil, nil, err
}
ppr := new(ProjectPushRules)
resp, err := s.client.Do(req, ppr)
if err != nil {
return nil, resp, err
}
return ppr, resp, err
}
// EditProjectPushRuleOptions represents the available EditProjectPushRule()
// options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/projects.html#edit-project-push-rule
type EditProjectPushRuleOptions struct {
AuthorEmailRegex *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"`
BranchNameRegex *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"`
CommitMessageRegex *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"`
FileNameRegex *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"`
DenyDeleteTag *bool `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"`
MemberCheck *bool `url:"member_check,omitempty" json:"member_check,omitempty"`
PreventSecrets *bool `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"`
MaxFileSize *int `url:"max_file_size,omitempty" json:"max_file_size,omitempty"`
}
// EditProjectPushRule edits a push rule for a specified project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/projects.html#edit-project-push-rule
func (s *ProjectsService) EditProjectPushRule(pid interface{}, opt *EditProjectPushRuleOptions, options ...OptionFunc) (*ProjectPushRules, *Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("projects/%s/push_rule", url.QueryEscape(project))
req, err := s.client.NewRequest("PUT", u, opt, options)
if err != nil {
return nil, nil, err
}
ppr := new(ProjectPushRules)
resp, err := s.client.Do(req, ppr)
if err != nil {
return nil, resp, err
}
return ppr, resp, err
}
// DeleteProjectPushRule removes a push rule from a project. This is an
// idempotent method and can be called multiple times. Either the push rule is
// available or not.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/projects.html#delete-project-push-rule
func (s *ProjectsService) DeleteProjectPushRule(pid interface{}, options ...OptionFunc) (*Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, err
}
u := fmt.Sprintf("projects/%s/push_rule", url.QueryEscape(project))
req, err := s.client.NewRequest("DELETE", u, nil, options)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

View File

@ -230,8 +230,7 @@ func (c Contributor) String() string {
return Stringify(c) return Stringify(c)
} }
// ListContributorsOptions represents the available ListContributorsOptions() // ListContributorsOptions represents the available ListContributors() options.
// options.
// //
// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors // GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors
type ListContributorsOptions ListOptions type ListContributorsOptions ListOptions
@ -259,3 +258,37 @@ func (s *RepositoriesService) Contributors(pid interface{}, opt *ListContributor
return c, resp, err return c, resp, err
} }
// MergeBaseOptions represents the available MergeBase() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/repositories.html#merge-base
type MergeBaseOptions struct {
Ref []string `url:"refs[],omitempty" json:"refs,omitempty"`
}
// MergeBase gets the common ancestor for 2 refs (commit SHAs, branch
// names or tags).
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/repositories.html#merge-base
func (s *RepositoriesService) MergeBase(pid interface{}, opt *MergeBaseOptions, options ...OptionFunc) (*Commit, *Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("projects/%s/repository/merge_base", url.QueryEscape(project))
req, err := s.client.NewRequest("GET", u, opt, options)
if err != nil {
return nil, nil, err
}
c := new(Commit)
resp, err := s.client.Do(req, c)
if err != nil {
return nil, resp, err
}
return c, resp, err
}

View File

@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"net/url" "net/url"
"strconv"
) )
// RepositoryFilesService handles communication with the repository files // RepositoryFilesService handles communication with the repository files
@ -66,7 +67,11 @@ func (s *RepositoryFilesService) GetFile(pid interface{}, fileName string, opt *
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.PathEscape(fileName)) u := fmt.Sprintf(
"projects/%s/repository/files/%s",
url.QueryEscape(project),
url.PathEscape(fileName),
)
req, err := s.client.NewRequest("GET", u, opt, options) req, err := s.client.NewRequest("GET", u, opt, options)
if err != nil { if err != nil {
@ -82,6 +87,59 @@ func (s *RepositoryFilesService) GetFile(pid interface{}, fileName string, opt *
return f, resp, err return f, resp, err
} }
// GetFileMetaDataOptions represents the available GetFileMetaData() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository
type GetFileMetaDataOptions struct {
Ref *string `url:"ref,omitempty" json:"ref,omitempty"`
}
// GetFileMetaData allows you to receive meta information about a file in
// repository like name, size.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository
func (s *RepositoryFilesService) GetFileMetaData(pid interface{}, fileName string, opt *GetFileMetaDataOptions, options ...OptionFunc) (*File, *Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf(
"projects/%s/repository/files/%s",
url.QueryEscape(project),
url.PathEscape(fileName),
)
req, err := s.client.NewRequest("HEAD", u, opt, options)
if err != nil {
return nil, nil, err
}
resp, err := s.client.Do(req, nil)
if err != nil {
return nil, resp, err
}
f := &File{
BlobID: resp.Header.Get("X-Gitlab-Blob-Id"),
CommitID: resp.Header.Get("X-Gitlab-Last-Commit-Id"),
Encoding: resp.Header.Get("X-Gitlab-Encoding"),
FileName: resp.Header.Get("X-Gitlab-File-Name"),
FilePath: resp.Header.Get("X-Gitlab-File-Path"),
Ref: resp.Header.Get("X-Gitlab-Ref"),
}
if sizeString := resp.Header.Get("X-Gitlab-Size"); sizeString != "" {
f.Size, err = strconv.Atoi(sizeString)
if err != nil {
return nil, resp, err
}
}
return f, resp, err
}
// GetRawFileOptions represents the available GetRawFile() options. // GetRawFileOptions represents the available GetRawFile() options.
// //
// GitLab API docs: // GitLab API docs:
@ -99,7 +157,11 @@ func (s *RepositoryFilesService) GetRawFile(pid interface{}, fileName string, op
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
u := fmt.Sprintf("projects/%s/repository/files/%s/raw", url.QueryEscape(project), url.PathEscape(fileName)) u := fmt.Sprintf(
"projects/%s/repository/files/%s/raw",
url.QueryEscape(project),
url.PathEscape(fileName),
)
req, err := s.client.NewRequest("GET", u, opt, options) req, err := s.client.NewRequest("GET", u, opt, options)
if err != nil { if err != nil {
@ -149,7 +211,11 @@ func (s *RepositoryFilesService) CreateFile(pid interface{}, fileName string, op
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.PathEscape(fileName)) u := fmt.Sprintf(
"projects/%s/repository/files/%s",
url.QueryEscape(project),
url.PathEscape(fileName),
)
req, err := s.client.NewRequest("POST", u, opt, options) req, err := s.client.NewRequest("POST", u, opt, options)
if err != nil { if err != nil {
@ -188,7 +254,11 @@ func (s *RepositoryFilesService) UpdateFile(pid interface{}, fileName string, op
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.PathEscape(fileName)) u := fmt.Sprintf(
"projects/%s/repository/files/%s",
url.QueryEscape(project),
url.PathEscape(fileName),
)
req, err := s.client.NewRequest("PUT", u, opt, options) req, err := s.client.NewRequest("PUT", u, opt, options)
if err != nil { if err != nil {
@ -224,7 +294,11 @@ func (s *RepositoryFilesService) DeleteFile(pid interface{}, fileName string, op
if err != nil { if err != nil {
return nil, err return nil, err
} }
u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.PathEscape(fileName)) u := fmt.Sprintf(
"projects/%s/repository/files/%s",
url.QueryEscape(project),
url.PathEscape(fileName),
)
req, err := s.client.NewRequest("DELETE", u, opt, options) req, err := s.client.NewRequest("DELETE", u, opt, options)
if err != nil { if err != nil {

View File

@ -769,3 +769,81 @@ func (s *UsersService) GetUserActivities(opt *GetUserActivitiesOptions, options
return t, resp, err return t, resp, err
} }
// UserStatus represents the current status of a user
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/users.html#user-status
type UserStatus struct {
Emoji string `json:"emoji"`
Message string `json:"message"`
MessageHTML string `json:"message_html"`
}
// CurrentUserStatus retrieves the user status
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/users.html#user-status
func (s *UsersService) CurrentUserStatus(options ...OptionFunc) (*UserStatus, *Response, error) {
req, err := s.client.NewRequest("GET", "user/status", nil, options)
if err != nil {
return nil, nil, err
}
status := new(UserStatus)
resp, err := s.client.Do(req, status)
if err != nil {
return nil, resp, err
}
return status, resp, err
}
// GetUserStatus retrieves a user's status
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/users.html#get-the-status-of-a-user
func (s *UsersService) GetUserStatus(user int, options ...OptionFunc) (*UserStatus, *Response, error) {
u := fmt.Sprintf("users/%d/status", user)
req, err := s.client.NewRequest("GET", u, nil, options)
if err != nil {
return nil, nil, err
}
status := new(UserStatus)
resp, err := s.client.Do(req, status)
if err != nil {
return nil, resp, err
}
return status, resp, err
}
// UserStatusOptions represents the options required to set the status
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/users.html#set-user-status
type UserStatusOptions struct {
Emoji *string `url:"emoji,omitempty" json:"emoji,omitempty"`
Message *string `url:"message,omitempty" json:"message,omitempty"`
}
// SetUserStatus sets the user's status
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/users.html#set-user-status
func (s *UsersService) SetUserStatus(opt *UserStatusOptions, options ...OptionFunc) (*UserStatus, *Response, error) {
req, err := s.client.NewRequest("PUT", "user/status", opt, options)
if err != nil {
return nil, nil, err
}
status := new(UserStatus)
resp, err := s.client.Do(req, status)
if err != nil {
return nil, resp, err
}
return status, resp, err
}

View File

@ -1,10 +1,9 @@
language: go language: go
go: go:
- "1.7"
- "1.8"
- "1.9" - "1.9"
- "1.10.x" - "1.10.x"
- "1.11.x"
- "tip" - "tip"
env: env:

View File

@ -5779,6 +5779,37 @@ func (o *Options) SetThresholds(v ThresholdCount) {
o.Thresholds = &v o.Thresholds = &v
} }
// GetThresholdWindows returns the ThresholdWindows field if non-nil, zero value otherwise.
func (o *Options) GetThresholdWindows() ThresholdWindows {
if o == nil || o.ThresholdWindows == nil {
return ThresholdWindows{}
}
return *o.ThresholdWindows
}
// GetThresholdWindowsOk returns a tuple with the ThresholdWindows field if it's non-nil, zero value otherwise
// and a boolean to check if the value has been set.
func (o *Options) GetThresholdWindowsOk() (ThresholdWindows, bool) {
if o == nil || o.ThresholdWindows == nil {
return ThresholdWindows{}, false
}
return *o.ThresholdWindows, true
}
// HasThresholdWindows returns a boolean if a field has been set.
func (o *Options) HasThresholdWindows() bool {
if o != nil && o.ThresholdWindows != nil {
return true
}
return false
}
// SetThresholdWindows allocates a new o.ThresholdWindows and returns the pointer to it.
func (o *Options) SetThresholdWindows(v ThresholdWindows) {
o.ThresholdWindows = &v
}
// GetTimeoutH returns the TimeoutH field if non-nil, zero value otherwise. // GetTimeoutH returns the TimeoutH field if non-nil, zero value otherwise.
func (o *Options) GetTimeoutH() int { func (o *Options) GetTimeoutH() int {
if o == nil || o.TimeoutH == nil { if o == nil || o.TimeoutH == nil {
@ -6338,18 +6369,18 @@ func (r *Rule) SetTimeframe(v string) {
} }
// GetHeight returns the Height field if non-nil, zero value otherwise. // GetHeight returns the Height field if non-nil, zero value otherwise.
func (s *Screenboard) GetHeight() string { func (s *Screenboard) GetHeight() int {
if s == nil || s.Height == nil { if s == nil || s.Height == nil {
return "" return 0
} }
return *s.Height return *s.Height
} }
// GetHeightOk returns a tuple with the Height field if it's non-nil, zero value otherwise // GetHeightOk returns a tuple with the Height field if it's non-nil, zero value otherwise
// and a boolean to check if the value has been set. // and a boolean to check if the value has been set.
func (s *Screenboard) GetHeightOk() (string, bool) { func (s *Screenboard) GetHeightOk() (int, bool) {
if s == nil || s.Height == nil { if s == nil || s.Height == nil {
return "", false return 0, false
} }
return *s.Height, true return *s.Height, true
} }
@ -6364,7 +6395,7 @@ func (s *Screenboard) HasHeight() bool {
} }
// SetHeight allocates a new s.Height and returns the pointer to it. // SetHeight allocates a new s.Height and returns the pointer to it.
func (s *Screenboard) SetHeight(v string) { func (s *Screenboard) SetHeight(v int) {
s.Height = &v s.Height = &v
} }
@ -6493,18 +6524,18 @@ func (s *Screenboard) SetTitle(v string) {
} }
// GetWidth returns the Width field if non-nil, zero value otherwise. // GetWidth returns the Width field if non-nil, zero value otherwise.
func (s *Screenboard) GetWidth() string { func (s *Screenboard) GetWidth() int {
if s == nil || s.Width == nil { if s == nil || s.Width == nil {
return "" return 0
} }
return *s.Width return *s.Width
} }
// GetWidthOk returns a tuple with the Width field if it's non-nil, zero value otherwise // GetWidthOk returns a tuple with the Width field if it's non-nil, zero value otherwise
// and a boolean to check if the value has been set. // and a boolean to check if the value has been set.
func (s *Screenboard) GetWidthOk() (string, bool) { func (s *Screenboard) GetWidthOk() (int, bool) {
if s == nil || s.Width == nil { if s == nil || s.Width == nil {
return "", false return 0, false
} }
return *s.Width, true return *s.Width, true
} }
@ -6519,7 +6550,7 @@ func (s *Screenboard) HasWidth() bool {
} }
// SetWidth allocates a new s.Width and returns the pointer to it. // SetWidth allocates a new s.Width and returns the pointer to it.
func (s *Screenboard) SetWidth(v string) { func (s *Screenboard) SetWidth(v int) {
s.Width = &v s.Width = &v
} }
@ -7546,6 +7577,68 @@ func (t *ThresholdCount) SetWarningRecovery(v json.Number) {
t.WarningRecovery = &v t.WarningRecovery = &v
} }
// GetRecoveryWindow returns the RecoveryWindow field if non-nil, zero value otherwise.
func (t *ThresholdWindows) GetRecoveryWindow() string {
if t == nil || t.RecoveryWindow == nil {
return ""
}
return *t.RecoveryWindow
}
// GetRecoveryWindowOk returns a tuple with the RecoveryWindow field if it's non-nil, zero value otherwise
// and a boolean to check if the value has been set.
func (t *ThresholdWindows) GetRecoveryWindowOk() (string, bool) {
if t == nil || t.RecoveryWindow == nil {
return "", false
}
return *t.RecoveryWindow, true
}
// HasRecoveryWindow returns a boolean if a field has been set.
func (t *ThresholdWindows) HasRecoveryWindow() bool {
if t != nil && t.RecoveryWindow != nil {
return true
}
return false
}
// SetRecoveryWindow allocates a new t.RecoveryWindow and returns the pointer to it.
func (t *ThresholdWindows) SetRecoveryWindow(v string) {
t.RecoveryWindow = &v
}
// GetTriggerWindow returns the TriggerWindow field if non-nil, zero value otherwise.
func (t *ThresholdWindows) GetTriggerWindow() string {
if t == nil || t.TriggerWindow == nil {
return ""
}
return *t.TriggerWindow
}
// GetTriggerWindowOk returns a tuple with the TriggerWindow field if it's non-nil, zero value otherwise
// and a boolean to check if the value has been set.
func (t *ThresholdWindows) GetTriggerWindowOk() (string, bool) {
if t == nil || t.TriggerWindow == nil {
return "", false
}
return *t.TriggerWindow, true
}
// HasTriggerWindow returns a boolean if a field has been set.
func (t *ThresholdWindows) HasTriggerWindow() bool {
if t != nil && t.TriggerWindow != nil {
return true
}
return false
}
// SetTriggerWindow allocates a new t.TriggerWindow and returns the pointer to it.
func (t *ThresholdWindows) SetTriggerWindow(v string) {
t.TriggerWindow = &v
}
// GetAutoscale returns the Autoscale field if non-nil, zero value otherwise. // GetAutoscale returns the Autoscale field if non-nil, zero value otherwise.
func (t *TileDef) GetAutoscale() bool { func (t *TileDef) GetAutoscale() bool {
if t == nil || t.Autoscale == nil { if t == nil || t.Autoscale == nil {

View File

@ -25,6 +25,11 @@ type ThresholdCount struct {
WarningRecovery *json.Number `json:"warning_recovery,omitempty"` WarningRecovery *json.Number `json:"warning_recovery,omitempty"`
} }
type ThresholdWindows struct {
RecoveryWindow *string `json:"recovery_window,omitempty"`
TriggerWindow *string `json:"trigger_window,omitempty"`
}
type NoDataTimeframe int type NoDataTimeframe int
func (tf *NoDataTimeframe) UnmarshalJSON(data []byte) error { func (tf *NoDataTimeframe) UnmarshalJSON(data []byte) error {
@ -42,19 +47,20 @@ func (tf *NoDataTimeframe) UnmarshalJSON(data []byte) error {
} }
type Options struct { type Options struct {
NoDataTimeframe NoDataTimeframe `json:"no_data_timeframe,omitempty"` NoDataTimeframe NoDataTimeframe `json:"no_data_timeframe,omitempty"`
NotifyAudit *bool `json:"notify_audit,omitempty"` NotifyAudit *bool `json:"notify_audit,omitempty"`
NotifyNoData *bool `json:"notify_no_data,omitempty"` NotifyNoData *bool `json:"notify_no_data,omitempty"`
RenotifyInterval *int `json:"renotify_interval,omitempty"` RenotifyInterval *int `json:"renotify_interval,omitempty"`
NewHostDelay *int `json:"new_host_delay,omitempty"` NewHostDelay *int `json:"new_host_delay,omitempty"`
EvaluationDelay *int `json:"evaluation_delay,omitempty"` EvaluationDelay *int `json:"evaluation_delay,omitempty"`
Silenced map[string]int `json:"silenced,omitempty"` Silenced map[string]int `json:"silenced,omitempty"`
TimeoutH *int `json:"timeout_h,omitempty"` TimeoutH *int `json:"timeout_h,omitempty"`
EscalationMessage *string `json:"escalation_message,omitempty"` EscalationMessage *string `json:"escalation_message,omitempty"`
Thresholds *ThresholdCount `json:"thresholds,omitempty"` Thresholds *ThresholdCount `json:"thresholds,omitempty"`
IncludeTags *bool `json:"include_tags,omitempty"` ThresholdWindows *ThresholdWindows `json:"threshold_windows,omitempty"`
RequireFullWindow *bool `json:"require_full_window,omitempty"` IncludeTags *bool `json:"include_tags,omitempty"`
Locked *bool `json:"locked,omitempty"` RequireFullWindow *bool `json:"require_full_window,omitempty"`
Locked *bool `json:"locked,omitempty"`
} }
type TriggeringValue struct { type TriggeringValue struct {

View File

@ -90,8 +90,8 @@ type Widget struct {
TitleSize *int `json:"title_size,omitempty"` TitleSize *int `json:"title_size,omitempty"`
Height *int `json:"height,omitempty"` Height *int `json:"height,omitempty"`
Width *int `json:"width,omitempty"` Width *int `json:"width,omitempty"`
X *int `json:"y,omitempty"` X *int `json:"x,omitempty"`
Y *int `json:"x,omitempty"` Y *int `json:"y,omitempty"`
// For Timeseries, TopList, EventTimeline, EvenStream, AlertGraph, CheckStatus, ServiceSummary, LogStream widgets // For Timeseries, TopList, EventTimeline, EvenStream, AlertGraph, CheckStatus, ServiceSummary, LogStream widgets
Time *Time `json:"time,omitempty"` Time *Time `json:"time,omitempty"`

View File

@ -17,8 +17,8 @@ import (
type Screenboard struct { type Screenboard struct {
Id *int `json:"id,omitempty"` Id *int `json:"id,omitempty"`
Title *string `json:"board_title,omitempty"` Title *string `json:"board_title,omitempty"`
Height *string `json:"height,omitempty"` Height *int `json:"height,omitempty"`
Width *string `json:"width,omitempty"` Width *int `json:"width,omitempty"`
Shared *bool `json:"shared,omitempty"` Shared *bool `json:"shared,omitempty"`
TemplateVariables []TemplateVariable `json:"template_variables,omitempty"` TemplateVariables []TemplateVariable `json:"template_variables,omitempty"`
Widgets []Widget `json:"widgets"` Widgets []Widget `json:"widgets"`

13
vendor/golang.org/x/oauth2/README.md generated vendored
View File

@ -24,7 +24,9 @@ See godoc for further documentation and examples.
In change 96e89be (March 2015), we removed the `oauth2.Context2` type in favor In change 96e89be (March 2015), we removed the `oauth2.Context2` type in favor
of the [`context.Context`](https://golang.org/x/net/context#Context) type from of the [`context.Context`](https://golang.org/x/net/context#Context) type from
the `golang.org/x/net/context` package the `golang.org/x/net/context` package. Later replaced by the standard `context` package
of the [`context.Context`](https://golang.org/pkg/context#Context) type.
This means it's no longer possible to use the "Classic App Engine" This means it's no longer possible to use the "Classic App Engine"
`appengine.Context` type with the `oauth2` package. (You're using `appengine.Context` type with the `oauth2` package. (You're using
@ -44,7 +46,7 @@ with the `oauth2` package.
```go ```go
import ( import (
"golang.org/x/net/context" "context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/google" "golang.org/x/oauth2/google"
newappengine "google.golang.org/appengine" newappengine "google.golang.org/appengine"
@ -68,6 +70,13 @@ func handler(w http.ResponseWriter, r *http.Request) {
} }
``` ```
## Policy for new packages
We no longer accept new provider-specific packages in this repo. For
defining provider endpoints and provider-specific OAuth2 behavior, we
encourage you to create packages elsewhere. We'll keep the existing
packages for compatibility.
## Report Issues / Send Patches ## Report Issues / Send Patches
This repository uses Gerrit for code changes. To learn how to submit changes to This repository uses Gerrit for code changes. To learn how to submit changes to

View File

@ -5,85 +5,34 @@
package google package google
import ( import (
"sort" "context"
"strings"
"sync"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
// appengineFlex is set at init time by appengineflex_hook.go. If true, we are on App Engine Flex. // Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible.
var appengineFlex bool
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error) var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
// Set at init time by appengine_hook.go. If nil, we're not on App Engine. // Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible.
var appengineAppIDFunc func(c context.Context) string var appengineAppIDFunc func(c context.Context) string
// AppEngineTokenSource returns a token source that fetches tokens // AppEngineTokenSource returns a token source that fetches tokens from either
// issued to the current App Engine application's service account. // the current application's service account or from the metadata server,
// If you are implementing a 3-legged OAuth 2.0 flow on App Engine // depending on the App Engine environment. See below for environment-specific
// that involves user accounts, see oauth2.Config instead. // details. If you are implementing a 3-legged OAuth 2.0 flow on App Engine that
// involves user accounts, see oauth2.Config instead.
// //
// The provided context must have come from appengine.NewContext. // First generation App Engine runtimes (<= Go 1.9):
// AppEngineTokenSource returns a token source that fetches tokens issued to the
// current App Engine application's service account. The provided context must have
// come from appengine.NewContext.
//
// Second generation App Engine runtimes (>= Go 1.11) and App Engine flexible:
// AppEngineTokenSource is DEPRECATED on second generation runtimes and on the
// flexible environment. It delegates to ComputeTokenSource, and the provided
// context and scopes are not used. Please use DefaultTokenSource (or ComputeTokenSource,
// which DefaultTokenSource will use in this case) instead.
func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource { func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
if appengineTokenFunc == nil { return appEngineTokenSource(ctx, scope...)
panic("google: AppEngineTokenSource can only be used on App Engine.")
}
scopes := append([]string{}, scope...)
sort.Strings(scopes)
return &appEngineTokenSource{
ctx: ctx,
scopes: scopes,
key: strings.Join(scopes, " "),
}
}
// aeTokens helps the fetched tokens to be reused until their expiration.
var (
aeTokensMu sync.Mutex
aeTokens = make(map[string]*tokenLock) // key is space-separated scopes
)
type tokenLock struct {
mu sync.Mutex // guards t; held while fetching or updating t
t *oauth2.Token
}
type appEngineTokenSource struct {
ctx context.Context
scopes []string
key string // to aeTokens map; space-separated scopes
}
func (ts *appEngineTokenSource) Token() (*oauth2.Token, error) {
if appengineTokenFunc == nil {
panic("google: AppEngineTokenSource can only be used on App Engine.")
}
aeTokensMu.Lock()
tok, ok := aeTokens[ts.key]
if !ok {
tok = &tokenLock{}
aeTokens[ts.key] = tok
}
aeTokensMu.Unlock()
tok.mu.Lock()
defer tok.mu.Unlock()
if tok.t.Valid() {
return tok.t, nil
}
access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...)
if err != nil {
return nil, err
}
tok.t = &oauth2.Token{
AccessToken: access,
Expiry: exp,
}
return tok.t, nil
} }

77
vendor/golang.org/x/oauth2/google/appengine_gen1.go generated vendored Normal file
View File

@ -0,0 +1,77 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build appengine
// This file applies to App Engine first generation runtimes (<= Go 1.9).
package google
import (
"context"
"sort"
"strings"
"sync"
"golang.org/x/oauth2"
"google.golang.org/appengine"
)
func init() {
appengineTokenFunc = appengine.AccessToken
appengineAppIDFunc = appengine.AppID
}
// See comment on AppEngineTokenSource in appengine.go.
func appEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
scopes := append([]string{}, scope...)
sort.Strings(scopes)
return &gaeTokenSource{
ctx: ctx,
scopes: scopes,
key: strings.Join(scopes, " "),
}
}
// aeTokens helps the fetched tokens to be reused until their expiration.
var (
aeTokensMu sync.Mutex
aeTokens = make(map[string]*tokenLock) // key is space-separated scopes
)
type tokenLock struct {
mu sync.Mutex // guards t; held while fetching or updating t
t *oauth2.Token
}
type gaeTokenSource struct {
ctx context.Context
scopes []string
key string // to aeTokens map; space-separated scopes
}
func (ts *gaeTokenSource) Token() (*oauth2.Token, error) {
aeTokensMu.Lock()
tok, ok := aeTokens[ts.key]
if !ok {
tok = &tokenLock{}
aeTokens[ts.key] = tok
}
aeTokensMu.Unlock()
tok.mu.Lock()
defer tok.mu.Unlock()
if tok.t.Valid() {
return tok.t, nil
}
access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...)
if err != nil {
return nil, err
}
tok.t = &oauth2.Token{
AccessToken: access,
Expiry: exp,
}
return tok.t, nil
}

View File

@ -0,0 +1,27 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !appengine
// This file applies to App Engine second generation runtimes (>= Go 1.11) and App Engine flexible.
package google
import (
"context"
"log"
"sync"
"golang.org/x/oauth2"
)
var logOnce sync.Once // only spam about deprecation once
// See comment on AppEngineTokenSource in appengine.go.
func appEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
logOnce.Do(func() {
log.Print("google: AppEngineTokenSource is deprecated on App Engine standard second generation runtimes (>= Go 1.11) and App Engine flexible. Please use DefaultTokenSource or ComputeTokenSource.")
})
return ComputeTokenSource("")
}

View File

@ -1,14 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build appengine appenginevm
package google
import "google.golang.org/appengine"
func init() {
appengineTokenFunc = appengine.AccessToken
appengineAppIDFunc = appengine.AppID
}

View File

@ -1,11 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build appenginevm
package google
func init() {
appengineFlex = true // Flex doesn't support appengine.AccessToken; depend on metadata server.
}

View File

@ -5,6 +5,7 @@
package google package google
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
@ -14,10 +15,28 @@ import (
"runtime" "runtime"
"cloud.google.com/go/compute/metadata" "cloud.google.com/go/compute/metadata"
"golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
// Credentials holds Google credentials, including "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
type Credentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
// JSON contains the raw bytes from a JSON credentials file.
// This field may be nil if authentication is provided by the
// environment and not with a credentials file, e.g. when code is
// running on Google Cloud Platform.
JSON []byte
}
// DefaultCredentials is the old name of Credentials.
//
// Deprecated: use Credentials instead.
type DefaultCredentials = Credentials
// DefaultClient returns an HTTP Client that uses the // DefaultClient returns an HTTP Client that uses the
// DefaultTokenSource to obtain authentication credentials. // DefaultTokenSource to obtain authentication credentials.
func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) { func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
@ -39,8 +58,23 @@ func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSourc
return creds.TokenSource, nil return creds.TokenSource, nil
} }
// Common implementation for FindDefaultCredentials. // FindDefaultCredentials searches for "Application Default Credentials".
func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCredentials, error) { //
// It looks for credentials in the following places,
// preferring the first location found:
//
// 1. A JSON file whose path is specified by the
// GOOGLE_APPLICATION_CREDENTIALS environment variable.
// 2. A JSON file in a location known to the gcloud command-line tool.
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
// 3. On Google App Engine standard first generation runtimes (<= Go 1.9) it uses
// the appengine.AccessToken function.
// 4. On Google Compute Engine, Google App Engine standard second generation runtimes
// (>= Go 1.11), and Google App Engine flexible environment, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.)
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) {
// First, try the environment variable. // First, try the environment variable.
const envVar = "GOOGLE_APPLICATION_CREDENTIALS" const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
if filename := os.Getenv(envVar); filename != "" { if filename := os.Getenv(envVar); filename != "" {
@ -59,15 +93,18 @@ func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCrede
return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err) return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err)
} }
// Third, if we're on Google App Engine use those credentials. // Third, if we're on a Google App Engine standard first generation runtime (<= Go 1.9)
if appengineTokenFunc != nil && !appengineFlex { // use those credentials. App Engine standard second generation runtimes (>= Go 1.11)
// and App Engine flexible use ComputeTokenSource and the metadata server.
if appengineTokenFunc != nil {
return &DefaultCredentials{ return &DefaultCredentials{
ProjectID: appengineAppIDFunc(ctx), ProjectID: appengineAppIDFunc(ctx),
TokenSource: AppEngineTokenSource(ctx, scopes...), TokenSource: AppEngineTokenSource(ctx, scopes...),
}, nil }, nil
} }
// Fourth, if we're on Google Compute Engine use the metadata server. // Fourth, if we're on Google Compute Engine, an App Engine standard second generation runtime,
// or App Engine flexible, use the metadata server.
if metadata.OnGCE() { if metadata.OnGCE() {
id, _ := metadata.ProjectID() id, _ := metadata.ProjectID()
return &DefaultCredentials{ return &DefaultCredentials{
@ -81,8 +118,11 @@ func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCrede
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url) return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url)
} }
// Common implementation for CredentialsFromJSON. // CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
func credentialsFromJSON(ctx context.Context, jsonData []byte, scopes []string) (*DefaultCredentials, error) { // represent either a Google Developers Console client_credentials.json file (as in
// ConfigFromJSON) or a Google Developers service account key file (as in
// JWTConfigFromJSON).
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
var f credentialsFile var f credentialsFile
if err := json.Unmarshal(jsonData, &f); err != nil { if err := json.Unmarshal(jsonData, &f); err != nil {
return nil, err return nil, err

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build go1.9
// Package google provides support for making OAuth2 authorized and authenticated // Package google provides support for making OAuth2 authorized and authenticated
// HTTP requests to Google APIs. It supports the Web server flow, client-side // HTTP requests to Google APIs. It supports the Web server flow, client-side
// credentials, service accounts, Google Compute Engine service accounts, and Google // credentials, service accounts, Google Compute Engine service accounts, and Google

View File

@ -1,43 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.9
// Package google provides support for making OAuth2 authorized and authenticated
// HTTP requests to Google APIs. It supports the Web server flow, client-side
// credentials, service accounts, Google Compute Engine service accounts, and Google
// App Engine service accounts.
//
// A brief overview of the package follows. For more information, please read
// https://developers.google.com/accounts/docs/OAuth2
// and
// https://developers.google.com/accounts/docs/application-default-credentials.
//
// OAuth2 Configs
//
// Two functions in this package return golang.org/x/oauth2.Config values from Google credential
// data. Google supports two JSON formats for OAuth2 credentials: one is handled by ConfigFromJSON,
// the other by JWTConfigFromJSON. The returned Config can be used to obtain a TokenSource or
// create an http.Client.
//
//
// Credentials
//
// The DefaultCredentials type represents Google Application Default Credentials, as
// well as other forms of credential.
//
// Use FindDefaultCredentials to obtain Application Default Credentials.
// FindDefaultCredentials looks in some well-known places for a credentials file, and
// will call AppEngineTokenSource or ComputeTokenSource as needed.
//
// DefaultClient and DefaultTokenSource are convenience methods. They first call FindDefaultCredentials,
// then use the credentials to construct an http.Client or an oauth2.TokenSource.
//
// Use CredentialsFromJSON to obtain credentials from either of the two JSON
// formats described in OAuth2 Configs, above. (The DefaultCredentials returned may
// not be "Application Default Credentials".) The TokenSource in the returned value
// is the same as the one obtained from the oauth2.Config returned from
// ConfigFromJSON or JWTConfigFromJSON, but the DefaultCredentials may contain
// additional information that is useful is some circumstances.
package google // import "golang.org/x/oauth2/google"

View File

@ -1,57 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.9
package google
import (
"golang.org/x/net/context"
"golang.org/x/oauth2"
)
// Credentials holds Google credentials, including "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
type Credentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
// JSON contains the raw bytes from a JSON credentials file.
// This field may be nil if authentication is provided by the
// environment and not with a credentials file, e.g. when code is
// running on Google Cloud Platform.
JSON []byte
}
// DefaultCredentials is the old name of Credentials.
//
// Deprecated: use Credentials instead.
type DefaultCredentials = Credentials
// FindDefaultCredentials searches for "Application Default Credentials".
//
// It looks for credentials in the following places,
// preferring the first location found:
//
// 1. A JSON file whose path is specified by the
// GOOGLE_APPLICATION_CREDENTIALS environment variable.
// 2. A JSON file in a location known to the gcloud command-line tool.
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
// 3. On Google App Engine it uses the appengine.AccessToken function.
// 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.)
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) {
return findDefaultCredentials(ctx, scopes)
}
// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
// represent either a Google Developers Console client_credentials.json file (as in
// ConfigFromJSON) or a Google Developers service account key file (as in
// JWTConfigFromJSON).
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
return credentialsFromJSON(ctx, jsonData, scopes)
}

View File

@ -5,6 +5,7 @@
package google package google
import ( import (
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -12,7 +13,6 @@ import (
"time" "time"
"cloud.google.com/go/compute/metadata" "cloud.google.com/go/compute/metadata"
"golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/jwt" "golang.org/x/oauth2/jwt"
) )

View File

@ -1,54 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.9
package google
import (
"golang.org/x/net/context"
"golang.org/x/oauth2"
)
// DefaultCredentials holds Google credentials, including "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
type DefaultCredentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
// JSON contains the raw bytes from a JSON credentials file.
// This field may be nil if authentication is provided by the
// environment and not with a credentials file, e.g. when code is
// running on Google Cloud Platform.
JSON []byte
}
// FindDefaultCredentials searches for "Application Default Credentials".
//
// It looks for credentials in the following places,
// preferring the first location found:
//
// 1. A JSON file whose path is specified by the
// GOOGLE_APPLICATION_CREDENTIALS environment variable.
// 2. A JSON file in a location known to the gcloud command-line tool.
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
// 3. On Google App Engine it uses the appengine.AccessToken function.
// 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.)
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*DefaultCredentials, error) {
return findDefaultCredentials(ctx, scopes)
}
// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
// represent either a Google Developers Console client_credentials.json file (as in
// ConfigFromJSON) or a Google Developers service account key file (as in
// JWTConfigFromJSON).
//
// Note: despite the name, the returned credentials may not be Application Default Credentials.
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*DefaultCredentials, error) {
return credentialsFromJSON(ctx, jsonData, scopes)
}

View File

@ -6,6 +6,7 @@ package google
import ( import (
"bufio" "bufio"
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -18,7 +19,6 @@ import (
"strings" "strings"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )

View File

@ -26,7 +26,7 @@ func ParseKey(key []byte) (*rsa.PrivateKey, error) {
if err != nil { if err != nil {
parsedKey, err = x509.ParsePKCS1PrivateKey(key) parsedKey, err = x509.ParsePKCS1PrivateKey(key)
if err != nil { if err != nil {
return nil, fmt.Errorf("private key should be a PEM or plain PKSC1 or PKCS8; parse error: %v", err) return nil, fmt.Errorf("private key should be a PEM or plain PKCS1 or PKCS8; parse error: %v", err)
} }
} }
parsed, ok := parsedKey.(*rsa.PrivateKey) parsed, ok := parsedKey.(*rsa.PrivateKey)

View File

@ -5,6 +5,7 @@
package internal package internal
import ( import (
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -17,7 +18,6 @@ import (
"strings" "strings"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp" "golang.org/x/net/context/ctxhttp"
) )

View File

@ -5,9 +5,8 @@
package internal package internal
import ( import (
"context"
"net/http" "net/http"
"golang.org/x/net/context"
) )
// HTTPClient is the context key to use with golang.org/x/net/context's // HTTPClient is the context key to use with golang.org/x/net/context's

View File

@ -9,6 +9,7 @@
package jwt package jwt
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@ -18,7 +19,6 @@ import (
"strings" "strings"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/internal" "golang.org/x/oauth2/internal"
"golang.org/x/oauth2/jws" "golang.org/x/oauth2/jws"

View File

@ -10,13 +10,13 @@ package oauth2 // import "golang.org/x/oauth2"
import ( import (
"bytes" "bytes"
"context"
"errors" "errors"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
"sync" "sync"
"golang.org/x/net/context"
"golang.org/x/oauth2/internal" "golang.org/x/oauth2/internal"
) )
@ -164,8 +164,7 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
// and when other authorization grant types are not available." // and when other authorization grant types are not available."
// See https://tools.ietf.org/html/rfc6749#section-4.3 for more info. // See https://tools.ietf.org/html/rfc6749#section-4.3 for more info.
// //
// The HTTP client to use is derived from the context. // The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
// If nil, http.DefaultClient is used.
func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) { func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) {
v := url.Values{ v := url.Values{
"grant_type": {"password"}, "grant_type": {"password"},
@ -183,8 +182,7 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor
// It is used after a resource provider redirects the user back // It is used after a resource provider redirects the user back
// to the Redirect URI (the URL obtained from AuthCodeURL). // to the Redirect URI (the URL obtained from AuthCodeURL).
// //
// The HTTP client to use is derived from the context. // The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
// If a client is not provided via the context, http.DefaultClient is used.
// //
// The code will be in the *http.Request.FormValue("code"). Before // The code will be in the *http.Request.FormValue("code"). Before
// calling Exchange, be sure to validate FormValue("state"). // calling Exchange, be sure to validate FormValue("state").

View File

@ -5,6 +5,7 @@
package oauth2 package oauth2
import ( import (
"context"
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
@ -12,7 +13,6 @@ import (
"strings" "strings"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/oauth2/internal" "golang.org/x/oauth2/internal"
) )

View File

@ -3,7 +3,7 @@
"oauth2": { "oauth2": {
"scopes": { "scopes": {
"https://www.googleapis.com/auth/calendar": { "https://www.googleapis.com/auth/calendar": {
"description": "Manage your calendars" "description": "See, edit, share, and permanently delete all the calendars you can access using Google Calendar"
}, },
"https://www.googleapis.com/auth/calendar.events": { "https://www.googleapis.com/auth/calendar.events": {
"description": "View and edit events on all your calendars" "description": "View and edit events on all your calendars"
@ -26,7 +26,7 @@
"description": "Manipulates events and other calendar data.", "description": "Manipulates events and other calendar data.",
"discoveryVersion": "v1", "discoveryVersion": "v1",
"documentationLink": "https://developers.google.com/google-apps/calendar/firstapp", "documentationLink": "https://developers.google.com/google-apps/calendar/firstapp",
"etag": "\"J3WqvAcMk4eQjJXvfSI4Yr8VouA/HcEmuhTEJ15i1AnuK6mgjI8kmMs\"", "etag": "\"J3WqvAcMk4eQjJXvfSI4Yr8VouA/7shFmGJYOQm8lYcU7swGRcnQGuU\"",
"icons": { "icons": {
"x16": "http://www.google.com/images/icons/product/calendar-16.png", "x16": "http://www.google.com/images/icons/product/calendar-16.png",
"x32": "http://www.google.com/images/icons/product/calendar-32.png" "x32": "http://www.google.com/images/icons/product/calendar-32.png"
@ -1724,7 +1724,7 @@
} }
} }
}, },
"revision": "20181002", "revision": "20181023",
"rootUrl": "https://www.googleapis.com/", "rootUrl": "https://www.googleapis.com/",
"schemas": { "schemas": {
"Acl": { "Acl": {

View File

@ -11,18 +11,18 @@ package calendar // import "google.golang.org/api/calendar/v3"
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
context "golang.org/x/net/context"
ctxhttp "golang.org/x/net/context/ctxhttp"
gensupport "google.golang.org/api/gensupport"
googleapi "google.golang.org/api/googleapi"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
gensupport "google.golang.org/api/gensupport"
googleapi "google.golang.org/api/googleapi"
) )
// Always reference these packages, just in case the auto-generated code // Always reference these packages, just in case the auto-generated code
@ -38,7 +38,6 @@ var _ = googleapi.Version
var _ = errors.New var _ = errors.New
var _ = strings.Replace var _ = strings.Replace
var _ = context.Canceled var _ = context.Canceled
var _ = ctxhttp.Do
const apiId = "calendar:v3" const apiId = "calendar:v3"
const apiName = "calendar" const apiName = "calendar"
@ -47,7 +46,8 @@ const basePath = "https://www.googleapis.com/calendar/v3/"
// OAuth2 scopes used by this API. // OAuth2 scopes used by this API.
const ( const (
// Manage your calendars // See, edit, share, and permanently delete all the calendars you can
// access using Google Calendar
CalendarScope = "https://www.googleapis.com/auth/calendar" CalendarScope = "https://www.googleapis.com/auth/calendar"
// View and edit events on all your calendars // View and edit events on all your calendars

View File

@ -5,14 +5,13 @@
package gensupport package gensupport
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"sync" "sync"
"time" "time"
"golang.org/x/net/context"
) )
const ( const (

View File

@ -15,12 +15,11 @@
package gensupport package gensupport
import ( import (
"context"
"io" "io"
"net" "net"
"net/http" "net/http"
"time" "time"
"golang.org/x/net/context"
) )
// Retry invokes the given function, retrying it multiple times if the connection failed or // Retry invokes the given function, retrying it multiple times if the connection failed or

View File

@ -5,12 +5,10 @@
package gensupport package gensupport
import ( import (
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"net/http" "net/http"
"golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp"
) )
// Hook is the type of a function that is called once before each HTTP request // Hook is the type of a function that is called once before each HTTP request
@ -32,7 +30,8 @@ func RegisterHook(h Hook) {
// SendRequest sends a single HTTP request using the given client. // SendRequest sends a single HTTP request using the given client.
// If ctx is non-nil, it calls all hooks, then sends the request with // If ctx is non-nil, it calls all hooks, then sends the request with
// ctxhttp.Do, then calls any functions returned by the hooks in reverse order. // req.WithContext, then calls any functions returned by the hooks in
// reverse order.
func SendRequest(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { func SendRequest(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
// Disallow Accept-Encoding because it interferes with the automatic gzip handling // Disallow Accept-Encoding because it interferes with the automatic gzip handling
// done by the default http.Transport. See https://github.com/google/google-api-go-client/issues/219. // done by the default http.Transport. See https://github.com/google/google-api-go-client/issues/219.
@ -50,7 +49,7 @@ func SendRequest(ctx context.Context, client *http.Client, req *http.Request) (*
} }
// Send request. // Send request.
resp, err := ctxhttp.Do(ctx, client, req) resp, err := send(ctx, client, req)
// Call returned funcs in reverse order. // Call returned funcs in reverse order.
for i := len(post) - 1; i >= 0; i-- { for i := len(post) - 1; i >= 0; i-- {
@ -61,6 +60,23 @@ func SendRequest(ctx context.Context, client *http.Client, req *http.Request) (*
return resp, err return resp, err
} }
func send(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
if client == nil {
client = http.DefaultClient
}
resp, err := client.Do(req.WithContext(ctx))
// If we got an error, and the context has been canceled,
// the context's error is probably more useful.
if err != nil {
select {
case <-ctx.Done():
err = ctx.Err()
default:
}
}
return resp, err
}
// DecodeResponse decodes the body of res into target. If there is no body, // DecodeResponse decodes the body of res into target. If there is no body,
// target is unchanged. // target is unchanged.
func DecodeResponse(target interface{}, res *http.Response) error { func DecodeResponse(target interface{}, res *http.Response) error {

View File

@ -11,18 +11,18 @@ package sheets // import "google.golang.org/api/sheets/v4"
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
context "golang.org/x/net/context"
ctxhttp "golang.org/x/net/context/ctxhttp"
gensupport "google.golang.org/api/gensupport"
googleapi "google.golang.org/api/googleapi"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
gensupport "google.golang.org/api/gensupport"
googleapi "google.golang.org/api/googleapi"
) )
// Always reference these packages, just in case the auto-generated code // Always reference these packages, just in case the auto-generated code
@ -38,7 +38,6 @@ var _ = googleapi.Version
var _ = errors.New var _ = errors.New
var _ = strings.Replace var _ = strings.Replace
var _ = context.Canceled var _ = context.Canceled
var _ = ctxhttp.Do
const apiId = "sheets:v4" const apiId = "sheets:v4"
const apiName = "sheets" const apiName = "sheets"

View File

@ -1,24 +1,20 @@
language: go language: go
go:
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
go_import_path: google.golang.org/appengine go_import_path: google.golang.org/appengine
install: install:
- go get -u -v $(go list -f '{{join .Imports "\n"}}{{"\n"}}{{join .TestImports "\n"}}' ./... | sort | uniq | grep -v appengine) - ./travis_install.sh
- mkdir /tmp/sdk
- curl -o /tmp/sdk.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.40.zip"
- unzip -q /tmp/sdk.zip -d /tmp/sdk
- export PATH="$PATH:/tmp/sdk/go_appengine"
- export APPENGINE_DEV_APPSERVER=/tmp/sdk/go_appengine/dev_appserver.py
script: script:
- goapp version - ./travis_test.sh
- go version
- go test -v google.golang.org/appengine/... matrix:
- go test -v -race google.golang.org/appengine/... include:
- goapp test -v google.golang.org/appengine/... - go: 1.8.x
env: GOAPP=true
- go: 1.9.x
env: GOAPP=true
- go: 1.10.x
env: GOAPP=false
- go: 1.11.x
env: GO111MODULE=on

View File

@ -60,6 +60,24 @@ func IsDevAppServer() bool {
return internal.IsDevAppServer() return internal.IsDevAppServer()
} }
// IsStandard reports whether the App Engine app is running in the standard
// environment. This includes both the first generation runtimes (<= Go 1.9)
// and the second generation runtimes (>= Go 1.11).
func IsStandard() bool {
return internal.IsStandard()
}
// IsFlex reports whether the App Engine app is running in the flexible environment.
func IsFlex() bool {
return internal.IsFlex()
}
// IsAppEngine reports whether the App Engine app is running on App Engine, in either
// the standard or flexible environment.
func IsAppEngine() bool {
return internal.IsAppEngine()
}
// NewContext returns a context for an in-flight HTTP request. // NewContext returns a context for an in-flight HTTP request.
// This function is cheap. // This function is cheap.
func NewContext(req *http.Request) context.Context { func NewContext(req *http.Request) context.Context {

View File

@ -1,3 +1,6 @@
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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225 h1:kNX+jCowfMYzvlSvJu5pQWEmyWFrBXJ3PBy10xKMXK8=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !appengine // +build !appengine
// +build go1.7
package internal package internal
@ -130,7 +129,13 @@ func handleHTTP(w http.ResponseWriter, r *http.Request) {
flushes++ flushes++
} }
c.pendingLogs.Unlock() c.pendingLogs.Unlock()
go c.flushLog(false) flushed := make(chan struct{})
go func() {
defer close(flushed)
// Force a log flush, because with very short requests we
// may not ever flush logs.
c.flushLog(true)
}()
w.Header().Set(logFlushHeader, strconv.Itoa(flushes)) w.Header().Set(logFlushHeader, strconv.Itoa(flushes))
// Avoid nil Write call if c.Write is never called. // Avoid nil Write call if c.Write is never called.
@ -140,6 +145,9 @@ func handleHTTP(w http.ResponseWriter, r *http.Request) {
if c.outBody != nil { if c.outBody != nil {
w.Write(c.outBody) w.Write(c.outBody)
} }
// Wait for the last flush to complete before returning,
// otherwise the security ticket will not be valid.
<-flushed
} }
func executeRequestSafely(c *context, r *http.Request) { func executeRequestSafely(c *context, r *http.Request) {

View File

@ -1,682 +0,0 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build !appengine
// +build !go1.7
package internal
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
"os"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/golang/protobuf/proto"
netcontext "golang.org/x/net/context"
basepb "google.golang.org/appengine/internal/base"
logpb "google.golang.org/appengine/internal/log"
remotepb "google.golang.org/appengine/internal/remote_api"
)
const (
apiPath = "/rpc_http"
defaultTicketSuffix = "/default.20150612t184001.0"
)
var (
// Incoming headers.
ticketHeader = http.CanonicalHeaderKey("X-AppEngine-API-Ticket")
dapperHeader = http.CanonicalHeaderKey("X-Google-DapperTraceInfo")
traceHeader = http.CanonicalHeaderKey("X-Cloud-Trace-Context")
curNamespaceHeader = http.CanonicalHeaderKey("X-AppEngine-Current-Namespace")
userIPHeader = http.CanonicalHeaderKey("X-AppEngine-User-IP")
remoteAddrHeader = http.CanonicalHeaderKey("X-AppEngine-Remote-Addr")
// Outgoing headers.
apiEndpointHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Endpoint")
apiEndpointHeaderValue = []string{"app-engine-apis"}
apiMethodHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Method")
apiMethodHeaderValue = []string{"/VMRemoteAPI.CallRemoteAPI"}
apiDeadlineHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Deadline")
apiContentType = http.CanonicalHeaderKey("Content-Type")
apiContentTypeValue = []string{"application/octet-stream"}
logFlushHeader = http.CanonicalHeaderKey("X-AppEngine-Log-Flush-Count")
apiHTTPClient = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: limitDial,
},
}
defaultTicketOnce sync.Once
defaultTicket string
)
func apiURL() *url.URL {
host, port := "appengine.googleapis.internal", "10001"
if h := os.Getenv("API_HOST"); h != "" {
host = h
}
if p := os.Getenv("API_PORT"); p != "" {
port = p
}
return &url.URL{
Scheme: "http",
Host: host + ":" + port,
Path: apiPath,
}
}
func handleHTTP(w http.ResponseWriter, r *http.Request) {
c := &context{
req: r,
outHeader: w.Header(),
apiURL: apiURL(),
}
stopFlushing := make(chan int)
ctxs.Lock()
ctxs.m[r] = c
ctxs.Unlock()
defer func() {
ctxs.Lock()
delete(ctxs.m, r)
ctxs.Unlock()
}()
// Patch up RemoteAddr so it looks reasonable.
if addr := r.Header.Get(userIPHeader); addr != "" {
r.RemoteAddr = addr
} else if addr = r.Header.Get(remoteAddrHeader); addr != "" {
r.RemoteAddr = addr
} else {
// Should not normally reach here, but pick a sensible default anyway.
r.RemoteAddr = "127.0.0.1"
}
// The address in the headers will most likely be of these forms:
// 123.123.123.123
// 2001:db8::1
// net/http.Request.RemoteAddr is specified to be in "IP:port" form.
if _, _, err := net.SplitHostPort(r.RemoteAddr); err != nil {
// Assume the remote address is only a host; add a default port.
r.RemoteAddr = net.JoinHostPort(r.RemoteAddr, "80")
}
// Start goroutine responsible for flushing app logs.
// This is done after adding c to ctx.m (and stopped before removing it)
// because flushing logs requires making an API call.
go c.logFlusher(stopFlushing)
executeRequestSafely(c, r)
c.outHeader = nil // make sure header changes aren't respected any more
stopFlushing <- 1 // any logging beyond this point will be dropped
// Flush any pending logs asynchronously.
c.pendingLogs.Lock()
flushes := c.pendingLogs.flushes
if len(c.pendingLogs.lines) > 0 {
flushes++
}
c.pendingLogs.Unlock()
go c.flushLog(false)
w.Header().Set(logFlushHeader, strconv.Itoa(flushes))
// Avoid nil Write call if c.Write is never called.
if c.outCode != 0 {
w.WriteHeader(c.outCode)
}
if c.outBody != nil {
w.Write(c.outBody)
}
}
func executeRequestSafely(c *context, r *http.Request) {
defer func() {
if x := recover(); x != nil {
logf(c, 4, "%s", renderPanic(x)) // 4 == critical
c.outCode = 500
}
}()
http.DefaultServeMux.ServeHTTP(c, r)
}
func renderPanic(x interface{}) string {
buf := make([]byte, 16<<10) // 16 KB should be plenty
buf = buf[:runtime.Stack(buf, false)]
// Remove the first few stack frames:
// this func
// the recover closure in the caller
// That will root the stack trace at the site of the panic.
const (
skipStart = "internal.renderPanic"
skipFrames = 2
)
start := bytes.Index(buf, []byte(skipStart))
p := start
for i := 0; i < skipFrames*2 && p+1 < len(buf); i++ {
p = bytes.IndexByte(buf[p+1:], '\n') + p + 1
if p < 0 {
break
}
}
if p >= 0 {
// buf[start:p+1] is the block to remove.
// Copy buf[p+1:] over buf[start:] and shrink buf.
copy(buf[start:], buf[p+1:])
buf = buf[:len(buf)-(p+1-start)]
}
// Add panic heading.
head := fmt.Sprintf("panic: %v\n\n", x)
if len(head) > len(buf) {
// Extremely unlikely to happen.
return head
}
copy(buf[len(head):], buf)
copy(buf, head)
return string(buf)
}
var ctxs = struct {
sync.Mutex
m map[*http.Request]*context
bg *context // background context, lazily initialized
// dec is used by tests to decorate the netcontext.Context returned
// for a given request. This allows tests to add overrides (such as
// WithAppIDOverride) to the context. The map is nil outside tests.
dec map[*http.Request]func(netcontext.Context) netcontext.Context
}{
m: make(map[*http.Request]*context),
}
// context represents the context of an in-flight HTTP request.
// It implements the appengine.Context and http.ResponseWriter interfaces.
type context struct {
req *http.Request
outCode int
outHeader http.Header
outBody []byte
pendingLogs struct {
sync.Mutex
lines []*logpb.UserAppLogLine
flushes int
}
apiURL *url.URL
}
var contextKey = "holds a *context"
// fromContext returns the App Engine context or nil if ctx is not
// derived from an App Engine context.
func fromContext(ctx netcontext.Context) *context {
c, _ := ctx.Value(&contextKey).(*context)
return c
}
func withContext(parent netcontext.Context, c *context) netcontext.Context {
ctx := netcontext.WithValue(parent, &contextKey, c)
if ns := c.req.Header.Get(curNamespaceHeader); ns != "" {
ctx = withNamespace(ctx, ns)
}
return ctx
}
func toContext(c *context) netcontext.Context {
return withContext(netcontext.Background(), c)
}
func IncomingHeaders(ctx netcontext.Context) http.Header {
if c := fromContext(ctx); c != nil {
return c.req.Header
}
return nil
}
func ReqContext(req *http.Request) netcontext.Context {
return WithContext(netcontext.Background(), req)
}
func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context {
ctxs.Lock()
c := ctxs.m[req]
d := ctxs.dec[req]
ctxs.Unlock()
if d != nil {
parent = d(parent)
}
if c == nil {
// Someone passed in an http.Request that is not in-flight.
// We panic here rather than panicking at a later point
// so that stack traces will be more sensible.
log.Panic("appengine: NewContext passed an unknown http.Request")
}
return withContext(parent, c)
}
// DefaultTicket returns a ticket used for background context or dev_appserver.
func DefaultTicket() string {
defaultTicketOnce.Do(func() {
if IsDevAppServer() {
defaultTicket = "testapp" + defaultTicketSuffix
return
}
appID := partitionlessAppID()
escAppID := strings.Replace(strings.Replace(appID, ":", "_", -1), ".", "_", -1)
majVersion := VersionID(nil)
if i := strings.Index(majVersion, "."); i > 0 {
majVersion = majVersion[:i]
}
defaultTicket = fmt.Sprintf("%s/%s.%s.%s", escAppID, ModuleName(nil), majVersion, InstanceID())
})
return defaultTicket
}
func BackgroundContext() netcontext.Context {
ctxs.Lock()
defer ctxs.Unlock()
if ctxs.bg != nil {
return toContext(ctxs.bg)
}
// Compute background security ticket.
ticket := DefaultTicket()
ctxs.bg = &context{
req: &http.Request{
Header: http.Header{
ticketHeader: []string{ticket},
},
},
apiURL: apiURL(),
}
// TODO(dsymonds): Wire up the shutdown handler to do a final flush.
go ctxs.bg.logFlusher(make(chan int))
return toContext(ctxs.bg)
}
// RegisterTestRequest registers the HTTP request req for testing, such that
// any API calls are sent to the provided URL. It returns a closure to delete
// the registration.
// It should only be used by aetest package.
func RegisterTestRequest(req *http.Request, apiURL *url.URL, decorate func(netcontext.Context) netcontext.Context) (*http.Request, func()) {
c := &context{
req: req,
apiURL: apiURL,
}
ctxs.Lock()
defer ctxs.Unlock()
if _, ok := ctxs.m[req]; ok {
log.Panic("req already associated with context")
}
if _, ok := ctxs.dec[req]; ok {
log.Panic("req already associated with context")
}
if ctxs.dec == nil {
ctxs.dec = make(map[*http.Request]func(netcontext.Context) netcontext.Context)
}
ctxs.m[req] = c
ctxs.dec[req] = decorate
return req, func() {
ctxs.Lock()
delete(ctxs.m, req)
delete(ctxs.dec, req)
ctxs.Unlock()
}
}
var errTimeout = &CallError{
Detail: "Deadline exceeded",
Code: int32(remotepb.RpcError_CANCELLED),
Timeout: true,
}
func (c *context) Header() http.Header { return c.outHeader }
// Copied from $GOROOT/src/pkg/net/http/transfer.go. Some response status
// codes do not permit a response body (nor response entity headers such as
// Content-Length, Content-Type, etc).
func bodyAllowedForStatus(status int) bool {
switch {
case status >= 100 && status <= 199:
return false
case status == 204:
return false
case status == 304:
return false
}
return true
}
func (c *context) Write(b []byte) (int, error) {
if c.outCode == 0 {
c.WriteHeader(http.StatusOK)
}
if len(b) > 0 && !bodyAllowedForStatus(c.outCode) {
return 0, http.ErrBodyNotAllowed
}
c.outBody = append(c.outBody, b...)
return len(b), nil
}
func (c *context) WriteHeader(code int) {
if c.outCode != 0 {
logf(c, 3, "WriteHeader called multiple times on request.") // error level
return
}
c.outCode = code
}
func (c *context) post(body []byte, timeout time.Duration) (b []byte, err error) {
hreq := &http.Request{
Method: "POST",
URL: c.apiURL,
Header: http.Header{
apiEndpointHeader: apiEndpointHeaderValue,
apiMethodHeader: apiMethodHeaderValue,
apiContentType: apiContentTypeValue,
apiDeadlineHeader: []string{strconv.FormatFloat(timeout.Seconds(), 'f', -1, 64)},
},
Body: ioutil.NopCloser(bytes.NewReader(body)),
ContentLength: int64(len(body)),
Host: c.apiURL.Host,
}
if info := c.req.Header.Get(dapperHeader); info != "" {
hreq.Header.Set(dapperHeader, info)
}
if info := c.req.Header.Get(traceHeader); info != "" {
hreq.Header.Set(traceHeader, info)
}
tr := apiHTTPClient.Transport.(*http.Transport)
var timedOut int32 // atomic; set to 1 if timed out
t := time.AfterFunc(timeout, func() {
atomic.StoreInt32(&timedOut, 1)
tr.CancelRequest(hreq)
})
defer t.Stop()
defer func() {
// Check if timeout was exceeded.
if atomic.LoadInt32(&timedOut) != 0 {
err = errTimeout
}
}()
hresp, err := apiHTTPClient.Do(hreq)
if err != nil {
return nil, &CallError{
Detail: fmt.Sprintf("service bridge HTTP failed: %v", err),
Code: int32(remotepb.RpcError_UNKNOWN),
}
}
defer hresp.Body.Close()
hrespBody, err := ioutil.ReadAll(hresp.Body)
if hresp.StatusCode != 200 {
return nil, &CallError{
Detail: fmt.Sprintf("service bridge returned HTTP %d (%q)", hresp.StatusCode, hrespBody),
Code: int32(remotepb.RpcError_UNKNOWN),
}
}
if err != nil {
return nil, &CallError{
Detail: fmt.Sprintf("service bridge response bad: %v", err),
Code: int32(remotepb.RpcError_UNKNOWN),
}
}
return hrespBody, nil
}
func Call(ctx netcontext.Context, service, method string, in, out proto.Message) error {
if ns := NamespaceFromContext(ctx); ns != "" {
if fn, ok := NamespaceMods[service]; ok {
fn(in, ns)
}
}
if f, ctx, ok := callOverrideFromContext(ctx); ok {
return f(ctx, service, method, in, out)
}
// Handle already-done contexts quickly.
select {
case <-ctx.Done():
return ctx.Err()
default:
}
c := fromContext(ctx)
if c == nil {
// Give a good error message rather than a panic lower down.
return errNotAppEngineContext
}
// Apply transaction modifications if we're in a transaction.
if t := transactionFromContext(ctx); t != nil {
if t.finished {
return errors.New("transaction context has expired")
}
applyTransaction(in, &t.transaction)
}
// Default RPC timeout is 60s.
timeout := 60 * time.Second
if deadline, ok := ctx.Deadline(); ok {
timeout = deadline.Sub(time.Now())
}
data, err := proto.Marshal(in)
if err != nil {
return err
}
ticket := c.req.Header.Get(ticketHeader)
// Use a test ticket under test environment.
if ticket == "" {
if appid := ctx.Value(&appIDOverrideKey); appid != nil {
ticket = appid.(string) + defaultTicketSuffix
}
}
// Fall back to use background ticket when the request ticket is not available in Flex or dev_appserver.
if ticket == "" {
ticket = DefaultTicket()
}
req := &remotepb.Request{
ServiceName: &service,
Method: &method,
Request: data,
RequestId: &ticket,
}
hreqBody, err := proto.Marshal(req)
if err != nil {
return err
}
hrespBody, err := c.post(hreqBody, timeout)
if err != nil {
return err
}
res := &remotepb.Response{}
if err := proto.Unmarshal(hrespBody, res); err != nil {
return err
}
if res.RpcError != nil {
ce := &CallError{
Detail: res.RpcError.GetDetail(),
Code: *res.RpcError.Code,
}
switch remotepb.RpcError_ErrorCode(ce.Code) {
case remotepb.RpcError_CANCELLED, remotepb.RpcError_DEADLINE_EXCEEDED:
ce.Timeout = true
}
return ce
}
if res.ApplicationError != nil {
return &APIError{
Service: *req.ServiceName,
Detail: res.ApplicationError.GetDetail(),
Code: *res.ApplicationError.Code,
}
}
if res.Exception != nil || res.JavaException != nil {
// This shouldn't happen, but let's be defensive.
return &CallError{
Detail: "service bridge returned exception",
Code: int32(remotepb.RpcError_UNKNOWN),
}
}
return proto.Unmarshal(res.Response, out)
}
func (c *context) Request() *http.Request {
return c.req
}
func (c *context) addLogLine(ll *logpb.UserAppLogLine) {
// Truncate long log lines.
// TODO(dsymonds): Check if this is still necessary.
const lim = 8 << 10
if len(*ll.Message) > lim {
suffix := fmt.Sprintf("...(length %d)", len(*ll.Message))
ll.Message = proto.String((*ll.Message)[:lim-len(suffix)] + suffix)
}
c.pendingLogs.Lock()
c.pendingLogs.lines = append(c.pendingLogs.lines, ll)
c.pendingLogs.Unlock()
}
var logLevelName = map[int64]string{
0: "DEBUG",
1: "INFO",
2: "WARNING",
3: "ERROR",
4: "CRITICAL",
}
func logf(c *context, level int64, format string, args ...interface{}) {
if c == nil {
panic("not an App Engine context")
}
s := fmt.Sprintf(format, args...)
s = strings.TrimRight(s, "\n") // Remove any trailing newline characters.
c.addLogLine(&logpb.UserAppLogLine{
TimestampUsec: proto.Int64(time.Now().UnixNano() / 1e3),
Level: &level,
Message: &s,
})
log.Print(logLevelName[level] + ": " + s)
}
// flushLog attempts to flush any pending logs to the appserver.
// It should not be called concurrently.
func (c *context) flushLog(force bool) (flushed bool) {
c.pendingLogs.Lock()
// Grab up to 30 MB. We can get away with up to 32 MB, but let's be cautious.
n, rem := 0, 30<<20
for ; n < len(c.pendingLogs.lines); n++ {
ll := c.pendingLogs.lines[n]
// Each log line will require about 3 bytes of overhead.
nb := proto.Size(ll) + 3
if nb > rem {
break
}
rem -= nb
}
lines := c.pendingLogs.lines[:n]
c.pendingLogs.lines = c.pendingLogs.lines[n:]
c.pendingLogs.Unlock()
if len(lines) == 0 && !force {
// Nothing to flush.
return false
}
rescueLogs := false
defer func() {
if rescueLogs {
c.pendingLogs.Lock()
c.pendingLogs.lines = append(lines, c.pendingLogs.lines...)
c.pendingLogs.Unlock()
}
}()
buf, err := proto.Marshal(&logpb.UserAppLogGroup{
LogLine: lines,
})
if err != nil {
log.Printf("internal.flushLog: marshaling UserAppLogGroup: %v", err)
rescueLogs = true
return false
}
req := &logpb.FlushRequest{
Logs: buf,
}
res := &basepb.VoidProto{}
c.pendingLogs.Lock()
c.pendingLogs.flushes++
c.pendingLogs.Unlock()
if err := Call(toContext(c), "logservice", "Flush", req, res); err != nil {
log.Printf("internal.flushLog: Flush RPC: %v", err)
rescueLogs = true
return false
}
return true
}
const (
// Log flushing parameters.
flushInterval = 1 * time.Second
forceFlushInterval = 60 * time.Second
)
func (c *context) logFlusher(stop <-chan int) {
lastFlush := time.Now()
tick := time.NewTicker(flushInterval)
for {
select {
case <-stop:
// Request finished.
tick.Stop()
return
case <-tick.C:
force := time.Now().Sub(lastFlush) > forceFlushInterval
if c.flushLog(force) {
lastFlush = time.Now()
}
}
}
}
func ContextForTesting(req *http.Request) netcontext.Context {
return toContext(&context{req: req})
}

View File

@ -4,11 +4,46 @@
package internal package internal
import netcontext "golang.org/x/net/context" import (
"os"
// These functions are implementations of the wrapper functions netcontext "golang.org/x/net/context"
// in ../appengine/identity.go. See that file for commentary. )
var (
// This is set to true in identity_classic.go, which is behind the appengine build tag.
// The appengine build tag is set for the first generation runtimes (<= Go 1.9) but not
// the second generation runtimes (>= Go 1.11), so this indicates whether we're on a
// first-gen runtime. See IsStandard below for the second-gen check.
appengineStandard bool
// This is set to true in identity_flex.go, which is behind the appenginevm build tag.
appengineFlex bool
)
// AppID is the implementation of the wrapper function of the same name in
// ../identity.go. See that file for commentary.
func AppID(c netcontext.Context) string { func AppID(c netcontext.Context) string {
return appID(FullyQualifiedAppID(c)) return appID(FullyQualifiedAppID(c))
} }
// IsStandard is the implementation of the wrapper function of the same name in
// ../appengine.go. See that file for commentary.
func IsStandard() bool {
// appengineStandard will be true for first-gen runtimes (<= Go 1.9) but not
// second-gen (>= Go 1.11). Second-gen runtimes set $GAE_ENV so we use that
// to check if we're on a second-gen runtime.
return appengineStandard || os.Getenv("GAE_ENV") == "standard"
}
// IsFlex is the implementation of the wrapper function of the same name in
// ../appengine.go. See that file for commentary.
func IsFlex() bool {
return appengineFlex
}
// IsAppEngine is the implementation of the wrapper function of the same name in
// ../appengine.go. See that file for commentary.
func IsAppEngine() bool {
return IsStandard() || IsFlex()
}

View File

@ -12,6 +12,10 @@ import (
netcontext "golang.org/x/net/context" netcontext "golang.org/x/net/context"
) )
func init() {
appengineStandard = true
}
func DefaultVersionHostname(ctx netcontext.Context) string { func DefaultVersionHostname(ctx netcontext.Context) string {
c := fromContext(ctx) c := fromContext(ctx)
if c == nil { if c == nil {

View File

@ -0,0 +1,11 @@
// Copyright 2018 Google LLC. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build appenginevm
package internal
func init() {
appengineFlex = true
}

18
vendor/google.golang.org/appengine/travis_install.sh generated vendored Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
set -e
if [[ $GO111MODULE == "on" ]]; then
go get .
else
go get -u -v $(go list -f '{{join .Imports "\n"}}{{"\n"}}{{join .TestImports "\n"}}' ./... | sort | uniq | grep -v appengine)
fi
if [[ $GOAPP == "true" ]]; then
mkdir /tmp/sdk
curl -o /tmp/sdk.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.68.zip"
unzip -q /tmp/sdk.zip -d /tmp/sdk
# NOTE: Set the following env vars in the test script:
# export PATH="$PATH:/tmp/sdk/go_appengine"
# export APPENGINE_DEV_APPSERVER=/tmp/sdk/go_appengine/dev_appserver.py
fi

12
vendor/google.golang.org/appengine/travis_test.sh generated vendored Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
set -e
go version
go test -v google.golang.org/appengine/...
go test -v -race google.golang.org/appengine/...
if [[ $GOAPP == "true" ]]; then
export PATH="$PATH:/tmp/sdk/go_appengine"
export APPENGINE_DEV_APPSERVER=/tmp/sdk/go_appengine/dev_appserver.py
goapp version
goapp test -v google.golang.org/appengine/...
fi