1
0
Fork 0
mirror of https://github.com/drone/drone-cli.git synced 2024-05-12 18:46:02 +02:00

copy 0.6 cli to own repo

This commit is contained in:
Brad Rydzewski 2017-05-15 13:59:26 +02:00
parent 89df6891d1
commit 615bf50efb
602 changed files with 55751 additions and 29145 deletions

View File

@ -2,20 +2,23 @@
set -e
set -x
mkdir bin
mkdir dist
# compile drone for all architectures
GOOS=linux GOARCH=amd64 go build -o ./bin/linux_amd64/drone github.com/drone/drone-cli/drone
GOOS=darwin GOARCH=amd64 go build -o ./bin/darwin_amd64/drone github.com/drone/drone-cli/drone
GOOS=windows GOARCH=amd64 go build -o ./bin/windows_amd64/drone github.com/drone/drone-cli/drone
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o release/linux/amd64/drone github.com/drone/drone-cli/drone
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o release/linux/arm64/drone github.com/drone/drone-cli/drone
GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -o release/linux/arm/drone github.com/drone/drone-cli/drone
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o release/windows/amd64/drone github.com/drone/drone-cli/drone
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -o release/darwin/amd64/drone github.com/drone/drone-cli/drone
# tar binary files prior to upload
tar -cvzf dist/drone_linux_amd64.tar.gz --directory=bin/linux_amd64 drone
tar -cvzf dist/drone_darwin_amd64.tar.gz --directory=bin/darwin_amd64 drone
tar -cvzf dist/drone_windows_amd64.tar.gz --directory=bin/windows_amd64 drone
tar -cvzf release/linux/amd64/drone.tar.gz -C release/linux/amd64 drone
tar -cvzf release/linux/arm64/drone.tar.gz -C release/linux/arm64 drone
tar -cvzf release/linux/arm/drone.tar.gz -C release/linux/arm drone
tar -cvzf release/windows/amd64/drone.tar.gz -C release/windows/amd64 drone
tar -cvzf release/darwin/amd64/drone.tar.gz -C release/darwin/amd64 drone
# generate shas for tar files
sha256sum ./dist/drone_linux_amd64.tar.gz > ./dist/drone_linux_amd64.sha256
sha256sum ./dist/drone_darwin_amd64.tar.gz > ./dist/drone_darwin_amd64.sha256
sha256sum ./dist/drone_windows_amd64.tar.gz > ./dist/drone_windows_amd64.sha256
sha256sum release/linux/amd64/drone.tar.gz > release/linux/amd64/drone.sha256
sha256sum release/linux/arm64/drone.tar.gz > release/linux/arm64/drone.sha256
sha256sum release/linux/arm/drone.tar.gz > release/linux/arm/drone.sha256
sha256sum release/windows/amd64/drone.tar.gz > release/windows/amd64/drone.sha256
sha256sum release/darwin/amd64/drone.tar.gz > release/darwin/amd64/drone.sha256

View File

@ -8,14 +8,9 @@ pipeline:
commands:
- cd drone
- go test
dist:
build:
image: golang:1.6
commands: ./.drone.sh
commands: bash .drone.sh
when:
event: push
# publish:
# image: s3
# when:
# event: push
# branch: master

32
.gitignore vendored
View File

@ -1,32 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
# Binary file(s)
drone/drone
dist/
bin/
NOTES.md
drone/.drone.yml

View File

@ -1,43 +1 @@
# drone-cli
Drone command-line interface
### System Requirements
The Drone command-line utility requires **Docker 1.6** or higher. If you are using Windows or Mac you can install Docker using the [Docker Toolbox](https://www.docker.com/docker-toolbox).
### Installation
**Linux**
Download and install the x64 linux binary:
```
curl http://downloads.drone.io/drone-cli/drone_linux_amd64.tar.gz | tar zx
sudo install -t /usr/local/bin drone
```
**OSX**
Download and install using Homebrew:
```
brew tap drone/drone
brew install drone
```
Or manually download and install the binary:
```
curl http://downloads.drone.io/drone-cli/drone_darwin_amd64.tar.gz | tar zx
sudo cp drone /usr/local/bin
```
### Authentication
You must provide the command line utility with the Drone server URL and a valid API token. You can get your API token in the Drone profile page.
```
export DRONE_TOKEN=
export DRONE_SERVER=
```
Command line client for the Drone continuous integration server. Please see the official documentation at http://docs.drone.io/cli-installation/

View File

@ -1,59 +0,0 @@
package main
import (
"html/template"
"os"
"time"
"github.com/codegangsta/cli"
)
var agentCmd = cli.Command{
Name: "agents",
Usage: "manage agents",
Action: agentList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplAgentList,
},
},
}
func agentList(c *cli.Context) error {
client, err := newClient(c)
if err != nil {
return err
}
agents, err := client.AgentList()
if err != nil {
return err
}
tmpl, err := template.New("_").Funcs(funcMap).Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, agent := range agents {
tmpl.Execute(os.Stdout, agent)
}
return nil
}
// template for build list information
var tmplAgentList = "\x1b[33m{{ .Address }} \x1b[0m" + `
Platform: {{ .Platform }}
Capacity: {{ .Capacity }} concurrent build(s)
Pinged: {{ since .Updated }} ago
Uptime: {{ since .Created }}
`
var funcMap = template.FuncMap{
"since": func(t int64) string {
d := time.Now().Sub(time.Unix(t, 0))
return d.String()
},
}

View File

@ -1,341 +0,0 @@
package main
import (
"fmt"
"html/template"
"os"
"strconv"
"github.com/codegangsta/cli"
"github.com/drone/drone-go/drone"
)
var buildCmd = cli.Command{
Name: "build",
Usage: "manage builds",
Subcommands: []cli.Command{
// list command
cli.Command{
Name: "list",
Usage: "show build history",
Action: buildList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildList,
},
cli.StringFlag{
Name: "branch",
Usage: "branch filter",
},
cli.StringFlag{
Name: "event",
Usage: "event filter",
},
cli.StringFlag{
Name: "status",
Usage: "status filter",
},
cli.IntFlag{
Name: "limit",
Usage: "limit the list size",
Value: 25,
},
},
},
// last command
cli.Command{
Name: "last",
Usage: "show latest build details",
Action: buildLast,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildInfo,
},
cli.StringFlag{
Name: "branch",
Usage: "branch name",
Value: "master",
},
},
},
// info command
cli.Command{
Name: "info",
Usage: "show build details",
Action: buildInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildInfo,
},
},
},
// stop command
cli.Command{
Name: "stop",
Usage: "stop a build",
Action: buildStop,
},
// start command
cli.Command{
Name: "start",
Usage: "start a build",
Action: buildStart,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "fork",
Usage: "fork the build",
},
},
},
// queue command.
cli.Command{
Name: "queue",
Usage: "show build queue",
Action: buildQueue,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildQueue,
},
},
},
},
}
// command to display a list of recent builds.
func buildList(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
builds, err := client.BuildList(owner, name)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
branch := c.String("branch")
event := c.String("event")
status := c.String("status")
limit := c.Int("limit")
var count int
for _, build := range builds {
if count >= limit {
break
}
if branch != "" && build.Branch != branch {
continue
}
if event != "" && build.Event != event {
continue
}
if status != "" && build.Status != status {
continue
}
tmpl.Execute(os.Stdout, build)
count++
}
return nil
}
// command to display the last build
func buildLast(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
build, err := client.BuildLast(owner, name, c.String("branch"))
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, build)
}
// command to display build information.
func buildInfo(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
build, err := client.Build(owner, name, number)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, build)
}
// command to stop a running build.
func buildStop(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
job, _ := strconv.Atoi(c.Args().Get(2))
if job == 0 {
job = 1
}
client, err := newClient(c)
if err != nil {
return err
}
err = client.BuildStop(owner, name, number, job)
if err != nil {
return err
}
fmt.Printf("Stopping build %s/%s#%d.%d\n", owner, name, number, job)
return nil
}
// command to re-start an existing build.
func buildStart(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
var build *drone.Build
if c.Bool("fork") {
build, err = client.BuildStart(owner, name, number)
} else {
build, err = client.BuildFork(owner, name, number)
}
if err != nil {
return err
}
fmt.Printf("Starting build %s/%s#%d\n", owner, name, build.Number)
return nil
}
// command to display the build queue.
func buildQueue(c *cli.Context) error {
client, err := newClient(c)
if err != nil {
return err
}
builds, err := client.BuildQueue()
if err != nil {
return err
}
if len(builds) == 0 {
fmt.Println("there are no pending or running builds")
return nil
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, build := range builds {
tmpl.Execute(os.Stdout, build)
}
return nil
}
// build info template.
var tmplBuildInfo = `Number: {{ .Number }}
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Message: {{ .Message }}
Author: {{ .Author }}
`
// build queue template.
var tmplBuildQueue = "\x1b[33m{{ .FullName }} #{{ .Number }} \x1b[0m" + `
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Author: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}
Message: {{ .Message }}
`
// build list template.
var tmplBuildList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + `
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Author: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}
Message: {{ .Message }}
`

20
drone/build/build.go Normal file
View File

@ -0,0 +1,20 @@
package build
import "github.com/urfave/cli"
// Command exports the build command set.
var Command = cli.Command{
Name: "build",
Usage: "manage builds",
Subcommands: []cli.Command{
buildListCmd,
buildLastCmd,
buildLogsCmd,
buildInfoCmd,
buildStopCmd,
buildStartCmd,
buildApproveCmd,
buildDeclineCmd,
buildQueueCmd,
},
}

View File

@ -0,0 +1,40 @@
package build
import (
"fmt"
"strconv"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var buildApproveCmd = cli.Command{
Name: "approve",
Usage: "approve a build",
Action: buildApprove,
}
func buildApprove(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
_, err = client.BuildApprove(owner, name, number)
if err != nil {
return err
}
fmt.Printf("Approving build %s/%s#%d\n", owner, name, number)
return nil
}

View File

@ -0,0 +1,40 @@
package build
import (
"fmt"
"strconv"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var buildDeclineCmd = cli.Command{
Name: "decline",
Usage: "decline a build",
Action: buildDecline,
}
func buildDecline(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
_, err = client.BuildDecline(owner, name, number)
if err != nil {
return err
}
fmt.Printf("Declining build %s/%s#%d\n", owner, name, number)
return nil
}

74
drone/build/build_info.go Normal file
View File

@ -0,0 +1,74 @@
package build
import (
"os"
"strconv"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var buildInfoCmd = cli.Command{
Name: "info",
Usage: "show build details",
Action: buildInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildInfo,
},
},
}
func buildInfo(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
buildArg := c.Args().Get(1)
client, err := internal.NewClient(c)
if err != nil {
return err
}
var number int
if buildArg == "last" {
// Fetch the build number from the last build
build, err := client.BuildLast(owner, name, "")
if err != nil {
return err
}
number = build.Number
} else {
number, err = strconv.Atoi(buildArg)
if err != nil {
return err
}
}
build, err := client.Build(owner, name, number)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, build)
}
// template for build information
var tmplBuildInfo = `Number: {{ .Number }}
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Message: {{ .Message }}
Author: {{ .Author }}
`

51
drone/build/build_last.go Normal file
View File

@ -0,0 +1,51 @@
package build
import (
"os"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var buildLastCmd = cli.Command{
Name: "last",
Usage: "show latest build details",
Action: buildLast,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildInfo,
},
cli.StringFlag{
Name: "branch",
Usage: "branch name",
Value: "master",
},
},
}
func buildLast(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
build, err := client.BuildLast(owner, name, c.String("branch"))
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, build)
}

97
drone/build/build_list.go Normal file
View File

@ -0,0 +1,97 @@
package build
import (
"os"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var buildListCmd = cli.Command{
Name: "list",
Usage: "show build history",
Action: buildList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildList,
},
cli.StringFlag{
Name: "branch",
Usage: "branch filter",
},
cli.StringFlag{
Name: "event",
Usage: "event filter",
},
cli.StringFlag{
Name: "status",
Usage: "status filter",
},
cli.IntFlag{
Name: "limit",
Usage: "limit the list size",
Value: 25,
},
},
}
func buildList(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
builds, err := client.BuildList(owner, name)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
branch := c.String("branch")
event := c.String("event")
status := c.String("status")
limit := c.Int("limit")
var count int
for _, build := range builds {
if count >= limit {
break
}
if branch != "" && build.Branch != branch {
continue
}
if event != "" && build.Event != event {
continue
}
if status != "" && build.Status != status {
continue
}
tmpl.Execute(os.Stdout, build)
count++
}
return nil
}
// template for build list information
var tmplBuildList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + `
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Author: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}
Message: {{ .Message }}
`

17
drone/build/build_logs.go Normal file
View File

@ -0,0 +1,17 @@
package build
import (
"fmt"
"github.com/urfave/cli"
)
var buildLogsCmd = cli.Command{
Name: "logs",
Usage: "show build logs",
Action: buildLogs,
}
func buildLogs(c *cli.Context) error {
return fmt.Errorf("Command temporarily disabled. See https://github.com/drone/drone/issues/2005")
}

View File

@ -0,0 +1,62 @@
package build
import (
"fmt"
"os"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var buildQueueCmd = cli.Command{
Name: "queue",
Usage: "show build queue",
Action: buildQueue,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplBuildQueue,
},
},
}
func buildQueue(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
builds, err := client.BuildQueue()
if err != nil {
return err
}
if len(builds) == 0 {
fmt.Println("there are no pending or running builds")
return nil
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, build := range builds {
tmpl.Execute(os.Stdout, build)
}
return nil
}
// template for build list information
var tmplBuildQueue = "\x1b[33m{{ .FullName }} #{{ .Number }} \x1b[0m" + `
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Author: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}
Message: {{ .Message }}
`

View File

@ -0,0 +1,70 @@
package build
import (
"fmt"
"strconv"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var buildStartCmd = cli.Command{
Name: "start",
Usage: "start a build",
Action: buildStart,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "fork",
Usage: "fork the build",
},
cli.StringSliceFlag{
Name: "param, p",
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
},
},
}
func buildStart(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
buildArg := c.Args().Get(1)
var number int
if buildArg == "last" {
// Fetch the build number from the last build
build, err := client.BuildLast(owner, name, "")
if err != nil {
return err
}
number = build.Number
} else {
number, err = strconv.Atoi(buildArg)
if err != nil {
return err
}
}
params := internal.ParseKeyPair(c.StringSlice("param"))
var build *drone.Build
if c.Bool("fork") {
build, err = client.BuildFork(owner, name, number, params)
} else {
build, err = client.BuildStart(owner, name, number, params)
}
if err != nil {
return err
}
fmt.Printf("Starting build %s/%s#%d\n", owner, name, build.Number)
return nil
}

44
drone/build/build_stop.go Normal file
View File

@ -0,0 +1,44 @@
package build
import (
"fmt"
"strconv"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var buildStopCmd = cli.Command{
Name: "stop",
Usage: "stop a build",
Action: buildStop,
}
func buildStop(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
job, _ := strconv.Atoi(c.Args().Get(2))
if job == 0 {
job = 1
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
err = client.BuildStop(owner, name, number, job)
if err != nil {
return err
}
fmt.Printf("Stopping build %s/%s#%d.%d\n", owner, name, number, job)
return nil
}

View File

@ -1,75 +0,0 @@
package main
import (
"fmt"
"html/template"
"os"
"strconv"
"github.com/codegangsta/cli"
"github.com/drone/drone-go/drone"
)
var deployCmd = cli.Command{
Name: "deploy",
Usage: "deploy code",
Action: deploy,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplDeployInfo,
},
},
}
func deploy(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
build, err := client.Build(owner, name, number)
if err != nil {
return err
}
if build.Event == drone.EventPull {
return fmt.Errorf("Cannot deploy a pull request")
}
env := c.Args().Get(2)
if env == "" {
return fmt.Errorf("Please specify the target environment (ie production)")
}
deploy, err := client.Deploy(owner, name, number, env)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, deploy)
}
// template for deployment information
var tmplDeployInfo = `Number: {{ .Number }}
Status: {{ .Status }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Message: {{ .Message }}
Author: {{ .Author }}
Target: {{ .Deploy }}
`

124
drone/deploy/deploy.go Normal file
View File

@ -0,0 +1,124 @@
package deploy
import (
"fmt"
"html/template"
"os"
"strconv"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
// Command exports the deploy command.
var Command = cli.Command{
Name: "deploy",
Usage: "deploy code",
Action: deploy,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplDeployInfo,
},
cli.StringFlag{
Name: "branch",
Usage: "branch filter",
Value: "master",
},
cli.StringFlag{
Name: "event",
Usage: "event filter",
Value: drone.EventPush,
},
cli.StringFlag{
Name: "status",
Usage: "status filter",
Value: drone.StatusSuccess,
},
cli.StringSliceFlag{
Name: "param, p",
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
},
},
}
func deploy(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
branch := c.String("branch")
event := c.String("event")
status := c.String("status")
buildArg := c.Args().Get(1)
var number int
if buildArg == "last" {
// Fetch the build number from the last build
builds, berr := client.BuildList(owner, name)
if berr != nil {
return berr
}
for _, build := range builds {
if branch != "" && build.Branch != branch {
continue
}
if event != "" && build.Event != event {
continue
}
if status != "" && build.Status != status {
continue
}
if build.Number > number {
number = build.Number
}
}
if number == 0 {
return fmt.Errorf("Cannot deploy failure build")
}
} else {
number, err = strconv.Atoi(buildArg)
if err != nil {
return err
}
}
env := c.Args().Get(2)
if env == "" {
return fmt.Errorf("Please specify the target environment (ie production)")
}
params := internal.ParseKeyPair(c.StringSlice("param"))
deploy, err := client.Deploy(owner, name, number, env, params)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, deploy)
}
// template for deployment information
var tmplDeployInfo = `Number: {{ .Number }}
Status: {{ .Status }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Message: {{ .Message }}
Author: {{ .Author }}
Target: {{ .Deploy }}
`

View File

@ -1,423 +0,0 @@
package main
import (
"io/ioutil"
"log"
"os"
"os/signal"
"path/filepath"
"strings"
"time"
"github.com/drone/drone-exec/agent"
"github.com/drone/drone-exec/build/docker"
"github.com/drone/drone-go/drone"
"github.com/codegangsta/cli"
)
var execCmd = cli.Command{
Name: "exec",
Usage: "execute a local build",
Action: func(c *cli.Context) {
if err := exec(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.BoolTFlag{
Name: "local",
Usage: "build from local directory",
EnvVar: "DRONE_LOCAL",
},
cli.StringSliceFlag{
Name: "plugin",
Usage: "plugin steps to enable",
EnvVar: "DRONE_PLUGIN_ENABLE",
},
cli.StringSliceFlag{
Name: "secret",
Usage: "build secrets in KEY=VALUE format",
EnvVar: "DRONE_SECRET",
},
cli.StringSliceFlag{
Name: "matrix",
Usage: "build matrix in KEY=VALUE format",
EnvVar: "DRONE_MATRIX",
},
cli.DurationFlag{
Name: "timeout",
Usage: "build timeout",
Value: time.Hour,
EnvVar: "DRONE_TIMEOUT",
},
cli.DurationFlag{
Name: "timeout.inactivity",
Usage: "build timeout for inactivity",
Value: time.Minute * 15,
EnvVar: "DRONE_TIMEOUT_INACTIVITY",
},
cli.BoolFlag{
EnvVar: "DRONE_PLUGIN_PULL",
Name: "pull",
Usage: "always pull latest plugin images",
},
cli.StringFlag{
EnvVar: "DRONE_PLUGIN_NAMESPACE",
Name: "namespace",
Value: "plugins",
Usage: "default plugin image namespace",
},
cli.StringSliceFlag{
EnvVar: "DRONE_PLUGIN_PRIVILEGED",
Name: "privileged",
Usage: "plugins that require privileged mode",
Value: &cli.StringSlice{
"plugins/docker",
"plugins/docker:*",
"plguins/gcr",
"plguins/gcr:*",
"plugins/ecr",
"plugins/ecr:*",
},
},
// Docker daemon flags
cli.StringFlag{
EnvVar: "DOCKER_HOST",
Name: "docker-host",
Usage: "docker deamon address",
Value: "unix:///var/run/docker.sock",
},
cli.BoolFlag{
EnvVar: "DOCKER_TLS_VERIFY",
Name: "docker-tls-verify",
Usage: "docker daemon supports tlsverify",
},
cli.StringFlag{
EnvVar: "DOCKER_CERT_PATH",
Name: "docker-cert-path",
Usage: "docker certificate directory",
Value: "",
},
//
// Please note the below flags are mirrored in the plugin starter kit and
// should be kept synchronized.
// https://github.com/drone/drone-plugin-starter
//
cli.StringFlag{
Name: "repo.fullname",
Usage: "repository full name",
EnvVar: "DRONE_REPO",
},
cli.StringFlag{
Name: "repo.owner",
Usage: "repository owner",
EnvVar: "DRONE_REPO_OWNER",
},
cli.StringFlag{
Name: "repo.name",
Usage: "repository name",
EnvVar: "DRONE_REPO_NAME",
},
cli.StringFlag{
Name: "repo.type",
Value: "git",
Usage: "repository type",
EnvVar: "DRONE_REPO_SCM",
},
cli.StringFlag{
Name: "repo.link",
Usage: "repository link",
EnvVar: "DRONE_REPO_LINK",
},
cli.StringFlag{
Name: "repo.avatar",
Usage: "repository avatar",
EnvVar: "DRONE_REPO_AVATAR",
},
cli.StringFlag{
Name: "repo.branch",
Usage: "repository default branch",
EnvVar: "DRONE_REPO_BRANCH",
},
cli.BoolFlag{
Name: "repo.private",
Usage: "repository is private",
EnvVar: "DRONE_REPO_PRIVATE",
},
cli.BoolFlag{
Name: "repo.trusted",
Usage: "repository is trusted",
EnvVar: "DRONE_REPO_TRUSTED",
},
cli.StringFlag{
Name: "remote.url",
Usage: "git remote url",
EnvVar: "DRONE_REMOTE_URL",
},
cli.StringFlag{
Name: "commit.sha",
Usage: "git commit sha",
EnvVar: "DRONE_COMMIT_SHA",
},
cli.StringFlag{
Name: "commit.ref",
Value: "refs/heads/master",
Usage: "git commit ref",
EnvVar: "DRONE_COMMIT_REF",
},
cli.StringFlag{
Name: "commit.branch",
Value: "master",
Usage: "git commit branch",
EnvVar: "DRONE_COMMIT_BRANCH",
},
cli.StringFlag{
Name: "commit.message",
Usage: "git commit message",
EnvVar: "DRONE_COMMIT_MESSAGE",
},
cli.StringFlag{
Name: "commit.link",
Usage: "git commit link",
EnvVar: "DRONE_COMMIT_LINK",
},
cli.StringFlag{
Name: "commit.author.name",
Usage: "git author name",
EnvVar: "DRONE_COMMIT_AUTHOR",
},
cli.StringFlag{
Name: "commit.author.email",
Usage: "git author email",
EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL",
},
cli.StringFlag{
Name: "commit.author.avatar",
Usage: "git author avatar",
EnvVar: "DRONE_COMMIT_AUTHOR_AVATAR",
},
cli.StringFlag{
Name: "build.event",
Value: "push",
Usage: "build event",
EnvVar: "DRONE_BUILD_EVENT",
},
cli.IntFlag{
Name: "build.number",
Usage: "build number",
EnvVar: "DRONE_BUILD_NUMBER",
},
cli.IntFlag{
Name: "build.created",
Usage: "build created",
EnvVar: "DRONE_BUILD_CREATED",
},
cli.IntFlag{
Name: "build.started",
Usage: "build started",
EnvVar: "DRONE_BUILD_STARTED",
},
cli.IntFlag{
Name: "build.finished",
Usage: "build finished",
EnvVar: "DRONE_BUILD_FINISHED",
},
cli.StringFlag{
Name: "build.status",
Usage: "build status",
Value: "success",
EnvVar: "DRONE_BUILD_STATUS",
},
cli.StringFlag{
Name: "build.link",
Usage: "build link",
EnvVar: "DRONE_BUILD_LINK",
},
cli.StringFlag{
Name: "build.deploy",
Usage: "build deployment target",
EnvVar: "DRONE_DEPLOY_TO",
},
cli.BoolTFlag{
Name: "yaml.verified",
Usage: "build yaml is verified",
EnvVar: "DRONE_YAML_VERIFIED",
},
cli.BoolTFlag{
Name: "yaml.signed",
Usage: "build yaml is signed",
EnvVar: "DRONE_YAML_SIGNED",
},
cli.IntFlag{
Name: "prev.build.number",
Usage: "previous build number",
EnvVar: "DRONE_PREV_BUILD_NUMBER",
},
cli.StringFlag{
Name: "prev.build.status",
Usage: "previous build status",
EnvVar: "DRONE_PREV_BUILD_STATUS",
},
cli.StringFlag{
Name: "prev.commit.sha",
Usage: "previous build sha",
EnvVar: "DRONE_PREV_COMMIT_SHA",
},
cli.StringFlag{
Name: "netrc.username",
Usage: "previous build sha",
EnvVar: "DRONE_NETRC_USERNAME",
},
cli.StringFlag{
Name: "netrc.password",
Usage: "previous build sha",
EnvVar: "DRONE_NETRC_PASSWORD",
},
cli.StringFlag{
Name: "netrc.machine",
Usage: "previous build sha",
EnvVar: "DRONE_NETRC_MACHINE",
},
},
}
func exec(c *cli.Context) error {
sigterm := make(chan os.Signal, 1)
cancelc := make(chan bool, 1)
signal.Notify(sigterm, os.Interrupt)
go func() {
<-sigterm
cancelc <- true
}()
path := c.Args().First()
if path == "" {
path = ".drone.yml"
}
path, _ = filepath.Abs(path)
dir := filepath.Dir(path)
file, err := ioutil.ReadFile(path)
if err != nil {
return err
}
engine, err := docker.New(
c.String("docker-host"),
c.String("docker-cert-path"),
c.Bool("docker-tls-verify"),
)
if err != nil {
return err
}
agent := agent.Agent{
Update: agent.NoopUpdateFunc,
Logger: agent.TermLoggerFunc,
Engine: engine,
Timeout: c.Duration("timeout.inactivity"),
Platform: "linux/amd64",
Namespace: c.String("namespace"),
Disable: c.StringSlice("plugin"),
Escalate: c.StringSlice("privileged"),
Netrc: []string{},
Local: dir,
Pull: c.Bool("pull"),
}
payload := drone.Payload{
Yaml: string(file),
Repo: &drone.Repo{
FullName: c.String("repo.fullname"),
Owner: c.String("repo.owner"),
Name: c.String("repo.name"),
Kind: c.String("repo.type"),
Link: c.String("repo.link"),
Branch: c.String("repo.branch"),
Avatar: c.String("repo.avatar"),
Timeout: int64(c.Duration("timeout").Minutes()),
IsPrivate: c.Bool("repo.private"),
IsTrusted: c.Bool("repo.trusted"),
Clone: c.String("remote.url"),
},
System: &drone.System{
Link: c.GlobalString("server"),
},
Secrets: getSecrets(c),
Netrc: &drone.Netrc{
Login: c.String("netrc.username"),
Password: c.String("netrc.password"),
Machine: c.String("netrc.machine"),
},
Build: &drone.Build{
Commit: c.String("commit.sha"),
Branch: c.String("commit.branch"),
Ref: c.String("commit.ref"),
Link: c.String("commit.link"),
Message: c.String("commit.message"),
Author: c.String("commit.author.name"),
Email: c.String("commit.author.email"),
Avatar: c.String("commit.author.avatar"),
Number: c.Int("build.number"),
Event: c.String("build.event"),
Deploy: c.String("build.deploy"),
Verified: c.BoolT("yaml.verified"),
Signed: c.BoolT("yaml.signed"),
},
BuildLast: &drone.Build{
Number: c.Int("prev.build.number"),
Status: c.String("prev.build.status"),
Commit: c.String("prev.commit.sha"),
},
Job: &drone.Job{
Environment: getMatrix(c),
},
}
return agent.Run(&payload, cancelc)
}
// helper function to retrieve matrix variables.
func getMatrix(c *cli.Context) map[string]string {
envs := map[string]string{}
for _, s := range c.StringSlice("matrix") {
parts := strings.SplitN(s, "=", 2)
if len(parts) != 2 {
continue
}
k := parts[0]
v := parts[1]
envs[k] = v
}
return envs
}
// helper function to retrieve secret variables.
func getSecrets(c *cli.Context) []*drone.Secret {
var secrets []*drone.Secret
for _, s := range c.StringSlice("secret") {
parts := strings.SplitN(s, "=", 2)
if len(parts) != 2 {
continue
}
secret := &drone.Secret{
Name: parts[0],
Value: parts[1],
Events: []string{
drone.EventPull,
drone.EventPush,
drone.EventTag,
drone.EventDeploy,
},
Images: []string{"*"},
}
secrets = append(secrets, secret)
}
return secrets
}

456
drone/exec/exec.go Normal file
View File

@ -0,0 +1,456 @@
package exec
import (
"context"
"io"
"log"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/cncd/pipeline/pipeline"
"github.com/cncd/pipeline/pipeline/backend"
"github.com/cncd/pipeline/pipeline/backend/docker"
"github.com/cncd/pipeline/pipeline/frontend"
"github.com/cncd/pipeline/pipeline/frontend/yaml"
"github.com/cncd/pipeline/pipeline/frontend/yaml/compiler"
"github.com/cncd/pipeline/pipeline/frontend/yaml/linter"
"github.com/cncd/pipeline/pipeline/interrupt"
"github.com/cncd/pipeline/pipeline/multipart"
"github.com/drone/envsubst"
"github.com/urfave/cli"
)
// Command exports the exec command.
var Command = cli.Command{
Name: "exec",
Usage: "execute a local build",
Action: func(c *cli.Context) {
if err := exec(c); err != nil {
log.Fatalln(err)
}
},
Flags: []cli.Flag{
cli.BoolTFlag{
Name: "local",
Usage: "build from local directory",
EnvVar: "DRONE_LOCAL",
},
cli.DurationFlag{
Name: "timeout",
Usage: "build timeout",
Value: time.Hour,
EnvVar: "DRONE_TIMEOUT",
},
cli.StringSliceFlag{
Name: "volumes",
Usage: "build volumes",
EnvVar: "DRONE_VOLUMES",
},
cli.StringSliceFlag{
Name: "network",
Usage: "external networks",
EnvVar: "DRONE_NETWORKS",
},
cli.StringFlag{
Name: "prefix",
Value: "drone",
Usage: "prefix containers created by drone",
EnvVar: "DRONE_DOCKER_PREFIX",
Hidden: true,
},
cli.StringSliceFlag{
Name: "privileged",
Usage: "privileged plugins",
Value: &cli.StringSlice{
"plugins/docker",
"plugins/gcr",
"plugins/ecr",
},
},
//
// Please note the below flags are mirrored in the pipec and
// should be kept synchronized. Do not edit directly
// https://github.com/cncd/pipeline/pipec
//
//
// workspace default
//
cli.StringFlag{
Name: "workspace-base",
Value: "/pipeline",
EnvVar: "DRONE_WORKSPACE_BASE",
},
cli.StringFlag{
Name: "workspace-path",
Value: "src",
EnvVar: "DRONE_WORKSPACE_PATH",
},
//
// netrc parameters
//
cli.StringFlag{
Name: "netrc-username",
EnvVar: "DRONE_NETRC_USERNAME",
},
cli.StringFlag{
Name: "netrc-password",
EnvVar: "DRONE_NETRC_PASSWORD",
},
cli.StringFlag{
Name: "netrc-machine",
EnvVar: "DRONE_NETRC_MACHINE",
},
//
// metadata parameters
//
cli.StringFlag{
Name: "system-arch",
Value: "linux/amd64",
EnvVar: "DRONE_SYSTEM_ARCH",
},
cli.StringFlag{
Name: "system-name",
Value: "pipec",
EnvVar: "DRONE_SYSTEM_NAME",
},
cli.StringFlag{
Name: "system-link",
Value: "https://github.com/cncd/pipec",
EnvVar: "DRONE_SYSTEM_LINK",
},
cli.StringFlag{
Name: "repo-name",
EnvVar: "DRONE_REPO_NAME",
},
cli.StringFlag{
Name: "repo-link",
EnvVar: "DRONE_REPO_LINK",
},
cli.StringFlag{
Name: "repo-remote-url",
EnvVar: "DRONE_REPO_REMOTE",
},
cli.StringFlag{
Name: "repo-private",
EnvVar: "DRONE_REPO_PRIVATE",
},
cli.IntFlag{
Name: "build-number",
EnvVar: "DRONE_BUILD_NUMBER",
},
cli.IntFlag{
Name: "parent-build-number",
EnvVar: "DRONE_PARENT_BUILD_NUMBER",
},
cli.Int64Flag{
Name: "build-created",
EnvVar: "DRONE_BUILD_CREATED",
},
cli.Int64Flag{
Name: "build-started",
EnvVar: "DRONE_BUILD_STARTED",
},
cli.Int64Flag{
Name: "build-finished",
EnvVar: "DRONE_BUILD_FINISHED",
},
cli.StringFlag{
Name: "build-status",
EnvVar: "DRONE_BUILD_STATUS",
},
cli.StringFlag{
Name: "build-event",
EnvVar: "DRONE_BUILD_EVENT",
},
cli.StringFlag{
Name: "build-link",
EnvVar: "DRONE_BUILD_LINK",
},
cli.StringFlag{
Name: "build-target",
EnvVar: "DRONE_BUILD_TARGET",
},
cli.StringFlag{
Name: "commit-sha",
EnvVar: "DRONE_COMMIT_SHA",
},
cli.StringFlag{
Name: "commit-ref",
EnvVar: "DRONE_COMMIT_REF",
},
cli.StringFlag{
Name: "commit-refspec",
EnvVar: "DRONE_COMMIT_REFSPEC",
},
cli.StringFlag{
Name: "commit-branch",
EnvVar: "DRONE_COMMIT_BRANCH",
},
cli.StringFlag{
Name: "commit-message",
EnvVar: "DRONE_COMMIT_MESSAGE",
},
cli.StringFlag{
Name: "commit-author-name",
EnvVar: "DRONE_COMMIT_AUTHOR_NAME",
},
cli.StringFlag{
Name: "commit-author-avatar",
EnvVar: "DRONE_COMMIT_AUTHOR_AVATAR",
},
cli.StringFlag{
Name: "commit-author-email",
EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL",
},
cli.IntFlag{
Name: "prev-build-number",
EnvVar: "DRONE_PREV_BUILD_NUMBER",
},
cli.Int64Flag{
Name: "prev-build-created",
EnvVar: "DRONE_PREV_BUILD_CREATED",
},
cli.Int64Flag{
Name: "prev-build-started",
EnvVar: "DRONE_PREV_BUILD_STARTED",
},
cli.Int64Flag{
Name: "prev-build-finished",
EnvVar: "DRONE_PREV_BUILD_FINISHED",
},
cli.StringFlag{
Name: "prev-build-status",
EnvVar: "DRONE_PREV_BUILD_STATUS",
},
cli.StringFlag{
Name: "prev-build-event",
EnvVar: "DRONE_PREV_BUILD_EVENT",
},
cli.StringFlag{
Name: "prev-build-link",
EnvVar: "DRONE_PREV_BUILD_LINK",
},
cli.StringFlag{
Name: "prev-commit-sha",
EnvVar: "DRONE_PREV_COMMIT_SHA",
},
cli.StringFlag{
Name: "prev-commit-ref",
EnvVar: "DRONE_PREV_COMMIT_REF",
},
cli.StringFlag{
Name: "prev-commit-refspec",
EnvVar: "DRONE_PREV_COMMIT_REFSPEC",
},
cli.StringFlag{
Name: "prev-commit-branch",
EnvVar: "DRONE_PREV_COMMIT_BRANCH",
},
cli.StringFlag{
Name: "prev-commit-message",
EnvVar: "DRONE_PREV_COMMIT_MESSAGE",
},
cli.StringFlag{
Name: "prev-commit-author-name",
EnvVar: "DRONE_PREV_COMMIT_AUTHOR_NAME",
},
cli.StringFlag{
Name: "prev-commit-author-avatar",
EnvVar: "DRONE_PREV_COMMIT_AUTHOR_AVATAR",
},
cli.StringFlag{
Name: "prev-commit-author-email",
EnvVar: "DRONE_PREV_COMMIT_AUTHOR_EMAIL",
},
cli.IntFlag{
Name: "job-number",
EnvVar: "DRONE_JOB_NUMBER",
},
},
}
func exec(c *cli.Context) error {
file := c.Args().First()
if file == "" {
file = ".drone.yml"
}
metadata := metadataFromContext(c)
environ := metadata.Environ()
secrets := []compiler.Secret{}
for k, v := range metadata.EnvironDrone() {
environ[k] = v
}
for _, env := range os.Environ() {
k := strings.Split(env, "=")[0]
v := strings.Split(env, "=")[1]
environ[k] = v
secrets = append(secrets, compiler.Secret{
Name: k,
Value: v,
})
}
tmpl, err := envsubst.ParseFile(file)
if err != nil {
return err
}
confstr, err := tmpl.Execute(func(name string) string {
return environ[name]
})
if err != nil {
return err
}
conf, err := yaml.ParseString(confstr)
if err != nil {
return err
}
// configure volumes for local execution
volumes := c.StringSlice("volumes")
if c.Bool("local") {
var (
workspaceBase = conf.Workspace.Base
workspacePath = conf.Workspace.Path
)
if workspaceBase == "" {
workspaceBase = c.String("workspace-base")
}
if workspacePath == "" {
workspacePath = c.String("workspace-path")
}
dir, _ := filepath.Abs(filepath.Dir(file))
volumes = append(volumes, dir+":"+path.Join(workspaceBase, workspacePath))
}
// lint the yaml file
if lerr := linter.New(linter.WithTrusted(true)).Lint(conf); lerr != nil {
return lerr
}
// compiles the yaml file
compiled := compiler.New(
compiler.WithEscalated(
c.StringSlice("privileged")...,
),
compiler.WithVolumes(volumes...),
compiler.WithWorkspace(
c.String("workspace-base"),
c.String("workspace-path"),
),
compiler.WithNetworks(
c.StringSlice("network")...,
),
compiler.WithPrefix(
c.String("prefix"),
),
compiler.WithProxy(),
compiler.WithLocal(
c.Bool("local"),
),
compiler.WithNetrc(
c.String("netrc-username"),
c.String("netrc-password"),
c.String("netrc-machine"),
),
compiler.WithMetadata(metadata),
compiler.WithSecret(secrets...),
).Compile(conf)
engine, err := docker.NewEnv()
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
defer cancel()
ctx = interrupt.WithContext(ctx)
return pipeline.New(compiled,
pipeline.WithContext(ctx),
pipeline.WithLogger(defaultLogger),
pipeline.WithTracer(pipeline.DefaultTracer),
pipeline.WithLogger(defaultLogger),
pipeline.WithEngine(engine),
).Run()
}
// return the metadata from the cli context.
func metadataFromContext(c *cli.Context) frontend.Metadata {
return frontend.Metadata{
Repo: frontend.Repo{
Name: c.String("repo-name"),
Link: c.String("repo-link"),
Remote: c.String("repo-remote-url"),
Private: c.Bool("repo-private"),
},
Curr: frontend.Build{
Number: c.Int("build-number"),
Parent: c.Int("parent-build-number"),
Created: c.Int64("build-created"),
Started: c.Int64("build-started"),
Finished: c.Int64("build-finished"),
Status: c.String("build-status"),
Event: c.String("build-event"),
Link: c.String("build-link"),
Target: c.String("build-target"),
Commit: frontend.Commit{
Sha: c.String("commit-sha"),
Ref: c.String("commit-ref"),
Refspec: c.String("commit-refspec"),
Branch: c.String("commit-branch"),
Message: c.String("commit-message"),
Author: frontend.Author{
Name: c.String("commit-author-name"),
Email: c.String("commit-author-email"),
Avatar: c.String("commit-author-avatar"),
},
},
},
Prev: frontend.Build{
Number: c.Int("prev-build-number"),
Created: c.Int64("prev-build-created"),
Started: c.Int64("prev-build-started"),
Finished: c.Int64("prev-build-finished"),
Status: c.String("prev-build-status"),
Event: c.String("prev-build-event"),
Link: c.String("prev-build-link"),
Commit: frontend.Commit{
Sha: c.String("prev-commit-sha"),
Ref: c.String("prev-commit-ref"),
Refspec: c.String("prev-commit-refspec"),
Branch: c.String("prev-commit-branch"),
Message: c.String("prev-commit-message"),
Author: frontend.Author{
Name: c.String("prev-commit-author-name"),
Email: c.String("prev-commit-author-email"),
Avatar: c.String("prev-commit-author-avatar"),
},
},
},
Job: frontend.Job{
Number: c.Int("job-number"),
},
Sys: frontend.System{
Name: c.String("system-name"),
Link: c.String("system-link"),
Arch: c.String("system-arch"),
},
}
}
var defaultLogger = pipeline.LogFunc(func(proc *backend.Step, rc multipart.Reader) error {
part, err := rc.NextPart()
if err != nil {
return err
}
io.Copy(os.Stderr, part)
return nil
})

View File

@ -1,27 +1,31 @@
package main
package info
import (
"os"
"text/template"
"github.com/codegangsta/cli"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
)
var infoCmd = cli.Command{
// Command exports the info command.
var Command = cli.Command{
Name: "info",
Usage: "display session info",
Usage: "show information about the current user",
Action: info,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplUserInfo,
Name: "format",
Usage: "format output",
Value: tmplInfo,
Hidden: true,
},
},
}
func info(c *cli.Context) error {
client, err := newClient(c)
client, err := internal.NewClient(c)
if err != nil {
return err
}

97
drone/internal/util.go Normal file
View File

@ -0,0 +1,97 @@
package internal
import (
"crypto/tls"
"fmt"
"net/http"
"strings"
"github.com/jackspirou/syscerts"
"github.com/urfave/cli"
"golang.org/x/net/proxy"
"golang.org/x/oauth2"
"github.com/drone/drone-go/drone"
)
// NewClient returns a new client from the CLI context.
func NewClient(c *cli.Context) (drone.Client, error) {
var (
skip = c.GlobalBool("skip-verify")
socks = c.GlobalString("socks-proxy")
socksoff = c.GlobalBool("socks-proxy-off")
token = c.GlobalString("token")
server = c.GlobalString("server")
)
server = strings.TrimRight(server, "/")
// if no server url is provided we can default
// to the hosted Drone service.
if len(server) == 0 {
return nil, fmt.Errorf("Error: you must provide the Drone server address.")
}
if len(token) == 0 {
return nil, fmt.Errorf("Error: you must provide your Drone access token.")
}
// attempt to find system CA certs
certs := syscerts.SystemRootsPool()
tlsConfig := &tls.Config{
RootCAs: certs,
InsecureSkipVerify: skip,
}
config := new(oauth2.Config)
auther := config.Client(
oauth2.NoContext,
&oauth2.Token{
AccessToken: token,
},
)
trans, _ := auther.Transport.(*oauth2.Transport)
if len(socks) != 0 && !socksoff {
dialer, err := proxy.SOCKS5("tcp", socks, nil, proxy.Direct)
if err != nil {
return nil, err
}
trans.Base = &http.Transport{
TLSClientConfig: tlsConfig,
Proxy: http.ProxyFromEnvironment,
Dial: dialer.Dial,
}
} else {
trans.Base = &http.Transport{
TLSClientConfig: tlsConfig,
Proxy: http.ProxyFromEnvironment,
}
}
return drone.NewClient(server, auther), nil
}
// ParseRepo parses the repository owner and name from a string.
func ParseRepo(str string) (user, repo string, err error) {
var parts = strings.Split(str, "/")
if len(parts) != 2 {
err = fmt.Errorf("Error: Invalid or missing repository. eg octocat/hello-world.")
return
}
user = parts[0]
repo = parts[1]
return
}
// ParseKeyPair parses a key=value pair.
func ParseKeyPair(p []string) map[string]string {
params := map[string]string{}
for _, i := range p {
parts := strings.Split(i, "=")
if len(parts) != 2 {
continue
}
params[parts[0]] = parts[1]
}
return params
}

View File

@ -0,0 +1,17 @@
package internal
import "testing"
func TestParseKeyPair(t *testing.T) {
s := []string{"FOO=bar", "BAR=", "INVALID"}
p := ParseKeyPair(s)
if p["FOO"] != "bar" {
t.Errorf("Wanted %q, got %q.", "bar", p["FOO"])
}
if _, exists := p["BAR"]; !exists {
t.Error("Missing a key with no value. Keys with empty values are also valid.")
}
if _, exists := p["INVALID"]; exists {
t.Error("Keys without an equal sign suffix are invalid.")
}
}

View File

@ -1,18 +1,29 @@
package main
import (
"log"
"fmt"
"os"
"github.com/codegangsta/cli"
"github.com/drone/drone-cli/drone/build"
"github.com/drone/drone-cli/drone/deploy"
"github.com/drone/drone-cli/drone/exec"
"github.com/drone/drone-cli/drone/info"
"github.com/drone/drone-cli/drone/registry"
"github.com/drone/drone-cli/drone/repo"
"github.com/drone/drone-cli/drone/secret"
"github.com/drone/drone-cli/drone/user"
_ "github.com/joho/godotenv/autoload"
"github.com/urfave/cli"
)
func main() {
// drone version number
var version string
func main() {
app := cli.NewApp()
app.Name = "drone"
app.Version = "0.5"
app.Version = version
app.Usage = "command line utility"
app.Flags = []cli.Flag{
cli.StringFlag{
@ -25,20 +36,38 @@ func main() {
Usage: "server location",
EnvVar: "DRONE_SERVER",
},
cli.BoolFlag{
Name: "skip-verify",
Usage: "skip ssl verfification",
EnvVar: "DRONE_SKIP_VERIFY",
Hidden: true,
},
cli.StringFlag{
Name: "socks-proxy",
Usage: "socks proxy address",
EnvVar: "SOCKS_PROXY",
Hidden: true,
},
cli.BoolFlag{
Name: "socks-proxy-off",
Usage: "socks proxy ignored",
EnvVar: "SOCKS_PROXY_OFF",
Hidden: true,
},
}
app.Commands = []cli.Command{
agentCmd,
buildCmd,
deployCmd,
execCmd,
infoCmd,
secretCmd,
signCmd,
repoCmd,
userCmd,
build.Command,
deploy.Command,
exec.Command,
info.Command,
registry.Command,
secret.Command,
repo.Command,
user.Command,
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

View File

@ -0,0 +1,16 @@
package registry
import "github.com/urfave/cli"
// Command exports the registry command set.
var Command = cli.Command{
Name: "registry",
Usage: "manage registries",
Subcommands: []cli.Command{
registryCreateCmd,
registryDeleteCmd,
registryUpdateCmd,
registryInfoCmd,
registryListCmd,
},
}

View File

@ -0,0 +1,74 @@
package registry
import (
"io/ioutil"
"strings"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var registryCreateCmd = cli.Command{
Name: "add",
Usage: "adds a registry",
Action: registryCreate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "hostname",
Usage: "registry hostname",
Value: "docker.io",
},
cli.StringFlag{
Name: "username",
Usage: "registry username",
},
cli.StringFlag{
Name: "password",
Usage: "registry password",
},
},
}
func registryCreate(c *cli.Context) error {
var (
hostname = c.String("hostname")
username = c.String("username")
password = c.String("password")
reponame = c.String("repository")
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
registry := &drone.Registry{
Address: hostname,
Username: username,
Password: password,
}
if strings.HasPrefix(registry.Password, "@") {
path := strings.TrimPrefix(registry.Password, "@")
out, ferr := ioutil.ReadFile(path)
if ferr != nil {
return ferr
}
registry.Password = string(out)
}
_, err = client.RegistryCreate(owner, name, registry)
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,61 @@
package registry
import (
"html/template"
"os"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var registryInfoCmd = cli.Command{
Name: "info",
Usage: "display registry info",
Action: registryInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "hostname",
Usage: "registry hostname",
Value: "docker.io",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplRegistryList,
Hidden: true,
},
},
}
func registryInfo(c *cli.Context) error {
var (
hostname = c.String("hostname")
reponame = c.String("repository")
format = c.String("format") + "\n"
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
registry, err := client.Registry(owner, name, hostname)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(format)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, registry)
}

View File

@ -0,0 +1,64 @@
package registry
import (
"html/template"
"os"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
)
var registryListCmd = cli.Command{
Name: "ls",
Usage: "list regitries",
Action: registryList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplRegistryList,
Hidden: true,
},
},
}
func registryList(c *cli.Context) error {
var (
format = c.String("format") + "\n"
reponame = c.String("repository")
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
list, err := client.RegistryList(owner, name)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(format)
if err != nil {
return err
}
for _, registry := range list {
tmpl.Execute(os.Stdout, registry)
}
return nil
}
// template for build list information
var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
Username: {{ .Username }}
Email: {{ .Email }}
`

View File

@ -0,0 +1,43 @@
package registry
import (
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var registryDeleteCmd = cli.Command{
Name: "rm",
Usage: "remove a registry",
Action: registryDelete,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "hostname",
Usage: "registry hostname",
Value: "docker.io",
},
},
}
func registryDelete(c *cli.Context) error {
var (
hostname = c.String("hostname")
reponame = c.String("repository")
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
return client.RegistryDelete(owner, name, hostname)
}

View File

@ -0,0 +1,74 @@
package registry
import (
"io/ioutil"
"strings"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var registryUpdateCmd = cli.Command{
Name: "update",
Usage: "update a registry",
Action: registryUpdate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "hostname",
Usage: "registry hostname",
Value: "docker.io",
},
cli.StringFlag{
Name: "username",
Usage: "registry username",
},
cli.StringFlag{
Name: "password",
Usage: "registry password",
},
},
}
func registryUpdate(c *cli.Context) error {
var (
hostname = c.String("hostname")
username = c.String("username")
password = c.String("password")
reponame = c.String("repository")
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
registry := &drone.Registry{
Address: hostname,
Username: username,
Password: password,
}
if strings.HasPrefix(registry.Password, "@") {
path := strings.TrimPrefix(registry.Password, "@")
out, ferr := ioutil.ReadFile(path)
if ferr != nil {
return ferr
}
registry.Password = string(out)
}
_, err = client.RegistryUpdate(owner, name, registry)
if err != nil {
return err
}
return nil
}

View File

@ -1,165 +0,0 @@
package main
import (
"fmt"
"html/template"
"os"
"github.com/codegangsta/cli"
)
var repoCmd = cli.Command{
Name: "repo",
Usage: "manage repositories",
Subcommands: []cli.Command{
// list command
cli.Command{
Name: "ls",
Usage: "list all repos",
Action: repoList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplRepoList,
},
cli.StringFlag{
Name: "org",
Usage: "filter by organization",
},
},
},
// info command
cli.Command{
Name: "info",
Usage: "show repository details",
Action: repoInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplRepoInfo,
},
},
},
// add command
cli.Command{
Name: "add",
Usage: "add a repository",
Action: repoAdd,
},
// remove command
cli.Command{
Name: "rm",
Usage: "remove a repository",
Action: repoRemove,
},
},
}
// command to fetch and return repository information.
func repoInfo(c *cli.Context) error {
arg := c.Args().First()
owner, name, err := parseRepo(arg)
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
repo, err := client.Repo(owner, name)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, repo)
}
// command to add a repository.
func repoAdd(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
if _, err := client.RepoPost(owner, name); err != nil {
return err
}
fmt.Printf("Successfully activated repository %s/%s\n", owner, name)
return nil
}
// command to remove a repository from drone.
func repoRemove(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
if err := client.RepoDel(owner, name); err != nil {
return err
}
fmt.Printf("Successfully removed repository %s/%s\n", owner, name)
return nil
}
// command to list user repositories.
func repoList(c *cli.Context) error {
client, err := newClient(c)
if err != nil {
return err
}
repos, err := client.RepoList()
if err != nil || len(repos) == 0 {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
org := c.String("org")
for _, repo := range repos {
if org != "" && org != repo.Owner {
continue
}
tmpl.Execute(os.Stdout, repo)
}
return nil
}
// repository info template.
var tmplRepoInfo = `Owner: {{ .Owner }}
Repo: {{ .Name }}
Type: {{ .Kind }}
Private: {{ .IsPrivate }}
Remote: {{ .Clone }}
`
// repository list template.
var tmplRepoList = `{{ .FullName }}`

18
drone/repo/repo.go Normal file
View File

@ -0,0 +1,18 @@
package repo
import "github.com/urfave/cli"
// Command exports the repository command.
var Command = cli.Command{
Name: "repo",
Usage: "manage repositories",
Subcommands: []cli.Command{
repoListCmd,
repoInfoCmd,
repoAddCmd,
repoUpdateCmd,
repoRemoveCmd,
repoRepairCmd,
repoChownCmd,
},
}

33
drone/repo/repo_add.go Normal file
View File

@ -0,0 +1,33 @@
package repo
import (
"fmt"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var repoAddCmd = cli.Command{
Name: "add",
Usage: "add a repository",
Action: repoAdd,
}
func repoAdd(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
if _, err := client.RepoPost(owner, name); err != nil {
return err
}
fmt.Printf("Successfully activated repository %s/%s\n", owner, name)
return nil
}

33
drone/repo/repo_chown.go Normal file
View File

@ -0,0 +1,33 @@
package repo
import (
"fmt"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var repoChownCmd = cli.Command{
Name: "chown",
Usage: "assume ownership of a repository",
Action: repoChown,
}
func repoChown(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
if _, err := client.RepoChown(owner, name); err != nil {
return err
}
fmt.Printf("Successfully assumed ownership of repository %s/%s\n", owner, name)
return nil
}

57
drone/repo/repo_info.go Normal file
View File

@ -0,0 +1,57 @@
package repo
import (
"os"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var repoInfoCmd = cli.Command{
Name: "info",
Usage: "show repository details",
Action: repoInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplRepoInfo,
},
},
}
func repoInfo(c *cli.Context) error {
arg := c.Args().First()
owner, name, err := internal.ParseRepo(arg)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
repo, err := client.Repo(owner, name)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, repo)
}
// template for repo information
var tmplRepoInfo = `Owner: {{ .Owner }}
Repo: {{ .Name }}
Type: {{ .Kind }}
Config: {{ .Config }}
Private: {{ .IsPrivate }}
Trusted: {{ .IsTrusted }}
Gated: {{ .IsGated }}
Remote: {{ .Clone }}
`

55
drone/repo/repo_list.go Normal file
View File

@ -0,0 +1,55 @@
package repo
import (
"os"
"text/template"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var repoListCmd = cli.Command{
Name: "ls",
Usage: "list all repos",
Action: repoList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplRepoList,
},
cli.StringFlag{
Name: "org",
Usage: "filter by organization",
},
},
}
func repoList(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
repos, err := client.RepoList()
if err != nil || len(repos) == 0 {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
org := c.String("org")
for _, repo := range repos {
if org != "" && org != repo.Owner {
continue
}
tmpl.Execute(os.Stdout, repo)
}
return nil
}
// template for repository list items
var tmplRepoList = `{{ .FullName }}`

25
drone/repo/repo_repair.go Normal file
View File

@ -0,0 +1,25 @@
package repo
import (
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var repoRepairCmd = cli.Command{
Name: "repair",
Usage: "repair repository webhooks",
Action: repoRepair,
}
func repoRepair(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
return client.RepoRepair(owner, name)
}

34
drone/repo/repo_rm.go Normal file
View File

@ -0,0 +1,34 @@
package repo
import (
"fmt"
"github.com/drone/drone-cli/drone/internal"
"github.com/urfave/cli"
)
var repoRemoveCmd = cli.Command{
Name: "rm",
Usage: "remove a repository",
Action: repoRemove,
}
func repoRemove(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
if err := client.RepoDel(owner, name); err != nil {
return err
}
fmt.Printf("Successfully removed repository %s/%s\n", owner, name)
return nil
}

76
drone/repo/repo_update.go Normal file
View File

@ -0,0 +1,76 @@
package repo
import (
"fmt"
"time"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var repoUpdateCmd = cli.Command{
Name: "update",
Usage: "update a repository",
Action: repoUpdate,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "trusted",
Usage: "repository is trusted",
},
cli.BoolFlag{
Name: "gated",
Usage: "repository is gated",
},
cli.DurationFlag{
Name: "timeout",
Usage: "repository timeout",
},
cli.StringFlag{
Name: "config",
Usage: "repository configuration path (e.g. .drone.yml)",
},
},
}
func repoUpdate(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
var (
config = c.String("config")
timeout = c.Duration("timeout")
trusted = c.Bool("trusted")
gated = c.Bool("gated")
)
patch := new(drone.RepoPatch)
if c.IsSet("trusted") {
patch.IsTrusted = &trusted
}
if c.IsSet("gated") {
patch.IsGated = &gated
}
if c.IsSet("timeout") {
v := int64(timeout / time.Minute)
patch.Timeout = &v
}
if c.IsSet("config") {
patch.Config = &config
}
if _, err := client.RepoPatch(owner, name, patch); err != nil {
return err
}
fmt.Printf("Successfully updated repository %s/%s\n", owner, name)
return nil
}

View File

@ -1,109 +0,0 @@
package main
import (
"fmt"
"io/ioutil"
"strings"
"github.com/codegangsta/cli"
"github.com/drone/drone-go/drone"
)
var secretCmd = cli.Command{
Name: "secret",
Usage: "manage secrets",
Subcommands: []cli.Command{
cli.Command{
Name: "add",
Usage: "adds a secret",
ArgsUsage: "[repo] [key] [value]",
Action: secretAdd,
Flags: []cli.Flag{
cli.StringSliceFlag{
Name: "event",
Usage: "inject the secret for these event types",
Value: &cli.StringSlice{
drone.EventPush,
drone.EventTag,
drone.EventDeploy,
},
},
cli.StringSliceFlag{
Name: "image",
Usage: "inject the secret for these image types",
Value: &cli.StringSlice{},
},
cli.StringFlag{
Name: "input",
Usage: "input secret value from a file",
},
},
},
cli.Command{
Name: "rm",
Usage: "remove a secret",
Action: secretRemove,
},
},
}
// command to add a repository secret.
func secretAdd(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
tail := c.Args().Tail()
if len(tail) != 2 {
cli.ShowSubcommandHelp(c)
return nil
}
secret := &drone.Secret{
Name: tail[0],
Value: tail[1],
Images: c.StringSlice("image"),
Events: c.StringSlice("event"),
}
if len(secret.Images) == 0 {
return fmt.Errorf("Please specify the --image parameter")
}
// TODO(bradrydzewski) below we use an @ sybmol to denote that the secret
// value should be loaded from a file (inspired by curl). I'd prefer to use
// a --input flag to explicitly specify a filepath instead.
if strings.HasPrefix(secret.Value, "@") {
path := secret.Value[1:]
out, ferr := ioutil.ReadFile(path)
if ferr != nil {
return ferr
}
secret.Value = string(out)
}
client, err := newClient(c)
if err != nil {
return err
}
return client.SecretPost(owner, name, secret)
}
// command to remove a repository secret.
func secretRemove(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
secret := c.Args().Get(1)
client, err := newClient(c)
if err != nil {
return err
}
return client.SecretDel(owner, name, secret)
}

16
drone/secret/secret.go Normal file
View File

@ -0,0 +1,16 @@
package secret
import "github.com/urfave/cli"
// Command exports the secret command.
var Command = cli.Command{
Name: "secret",
Usage: "manage secrets",
Subcommands: []cli.Command{
secretCreateCmd,
secretDeleteCmd,
secretUpdateCmd,
secretInfoCmd,
secretListCmd,
},
}

View File

@ -0,0 +1,79 @@
package secret
import (
"io/ioutil"
"strings"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var secretCreateCmd = cli.Command{
Name: "add",
Usage: "adds a secret",
Action: secretCreate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "name",
Usage: "secret name",
},
cli.StringFlag{
Name: "value",
Usage: "secret value",
},
cli.StringSliceFlag{
Name: "event",
Usage: "secret limited to these events",
},
cli.StringSliceFlag{
Name: "image",
Usage: "secret limited to these images",
},
},
}
func secretCreate(c *cli.Context) error {
reponame := c.String("repository")
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
secret := &drone.Secret{
Name: c.String("name"),
Value: c.String("value"),
Images: c.StringSlice("image"),
Events: c.StringSlice("event"),
}
if len(secret.Events) == 0 {
secret.Events = defaultSecretEvents
}
if strings.HasPrefix(secret.Value, "@") {
path := strings.TrimPrefix(secret.Value, "@")
out, ferr := ioutil.ReadFile(path)
if ferr != nil {
return ferr
}
secret.Value = string(out)
}
_, err = client.SecretCreate(owner, name, secret)
return err
}
var defaultSecretEvents = []string{
drone.EventPush,
drone.EventTag,
drone.EventDeploy,
}

View File

@ -0,0 +1,60 @@
package secret
import (
"html/template"
"os"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
)
var secretInfoCmd = cli.Command{
Name: "info",
Usage: "display secret info",
Action: secretInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "name",
Usage: "secret name",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplSecretList,
Hidden: true,
},
},
}
func secretInfo(c *cli.Context) error {
var (
secretName = c.String("name")
repoName = c.String("repository")
format = c.String("format") + "\n"
)
if repoName == "" {
repoName = c.Args().First()
}
owner, name, err := internal.ParseRepo(repoName)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
secret, err := client.Secret(owner, name, secretName)
if err != nil {
return err
}
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, secret)
}

View File

@ -0,0 +1,75 @@
package secret
import (
"html/template"
"os"
"strings"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
)
var secretListCmd = cli.Command{
Name: "ls",
Usage: "list secrets",
Action: secretList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplSecretList,
Hidden: true,
},
},
}
func secretList(c *cli.Context) error {
var (
format = c.String("format") + "\n"
reponame = c.String("repository")
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
list, err := client.SecretList(owner, name)
if err != nil {
return err
}
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
if err != nil {
return err
}
for _, registry := range list {
tmpl.Execute(os.Stdout, registry)
}
return nil
}
// template for secret list items
var tmplSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + `
Events: {{ list .Events }}
{{- if .Images }}
Images: {{ list .Images }}
{{- else }}
Images: <any>
{{- end }}
`
var secretFuncMap = template.FuncMap{
"list": func(s []string) string {
return strings.Join(s, ", ")
},
}

42
drone/secret/secret_rm.go Normal file
View File

@ -0,0 +1,42 @@
package secret
import (
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
)
var secretDeleteCmd = cli.Command{
Name: "rm",
Usage: "remove a secret",
Action: secretDelete,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "name",
Usage: "secret name",
},
},
}
func secretDelete(c *cli.Context) error {
var (
secret = c.String("name")
reponame = c.String("repository")
)
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
return client.SecretDelete(owner, name, secret)
}

View File

@ -0,0 +1,70 @@
package secret
import (
"io/ioutil"
"strings"
"github.com/drone/drone-cli/drone/internal"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
)
var secretUpdateCmd = cli.Command{
Name: "update",
Usage: "update a secret",
Action: secretUpdate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "repository",
Usage: "repository name (e.g. octocat/hello-world)",
},
cli.StringFlag{
Name: "name",
Usage: "secret name",
},
cli.StringFlag{
Name: "value",
Usage: "secret value",
},
cli.StringSliceFlag{
Name: "event",
Usage: "secret limited to these events",
},
cli.StringSliceFlag{
Name: "image",
Usage: "secret limited to these images",
},
},
}
func secretUpdate(c *cli.Context) error {
reponame := c.String("repository")
if reponame == "" {
reponame = c.Args().First()
}
owner, name, err := internal.ParseRepo(reponame)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
secret := &drone.Secret{
Name: c.String("name"),
Value: c.String("value"),
Images: c.StringSlice("image"),
Events: c.StringSlice("events"),
}
if strings.HasPrefix(secret.Value, "@") {
path := strings.TrimPrefix(secret.Value, "@")
out, ferr := ioutil.ReadFile(path)
if ferr != nil {
return ferr
}
secret.Value = string(out)
}
_, err = client.SecretUpdate(owner, name, secret)
return err
}

View File

@ -1,50 +0,0 @@
package main
import (
"io/ioutil"
"github.com/codegangsta/cli"
)
var signCmd = cli.Command{
Name: "sign",
Usage: "sign the yaml file",
Action: sign,
Flags: []cli.Flag{
cli.StringFlag{
Name: "in",
Usage: "input file",
Value: ".drone.yml",
},
cli.StringFlag{
Name: "out",
Usage: "output file signature",
Value: ".drone.yml.sig",
},
},
}
func sign(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := parseRepo(repo)
if err != nil {
return err
}
in, err := readInput(c.String("in"))
if err != nil {
return err
}
client, err := newClient(c)
if err != nil {
return err
}
sig, err := client.Sign(owner, name, in)
if err != nil {
return err
}
return ioutil.WriteFile(c.String("out"), sig, 0664)
}

View File

@ -1,142 +0,0 @@
package main
import (
"fmt"
"html/template"
"os"
"github.com/codegangsta/cli"
"github.com/drone/drone-go/drone"
)
var userCmd = cli.Command{
Name: "user",
Usage: "manage users",
Subcommands: []cli.Command{
// list command
cli.Command{
Name: "ls",
Usage: "list all users",
Action: userList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplUserList,
},
},
},
// info command
cli.Command{
Name: "info",
Usage: "show user details",
Action: userInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplUserInfo,
},
},
},
// add command
cli.Command{
Name: "add",
Usage: "adds a user",
Action: userAdd,
},
// remove command
cli.Command{
Name: "rm",
Usage: "remove a user",
Action: userRemove,
},
},
}
// command to de-register a user from drone server.
func userRemove(c *cli.Context) error {
login := c.Args().First()
client, err := newClient(c)
if err != nil {
return err
}
if err := client.UserDel(login); err != nil {
return err
}
fmt.Printf("Successfully removed user %s\n", login)
return nil
}
// command to register a user with drone server.
func userAdd(c *cli.Context) error {
login := c.Args().First()
client, err := newClient(c)
if err != nil {
return err
}
user, err := client.UserPost(&drone.User{Login: login})
if err != nil {
return err
}
fmt.Printf("Successfully added user %s\n", user.Login)
return nil
}
// command to display information for a registered user.
func userInfo(c *cli.Context) error {
client, err := newClient(c)
if err != nil {
return err
}
login := c.Args().First()
if len(login) == 0 {
return fmt.Errorf("Missing or invalid user login")
}
user, err := client.User(login)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, user)
}
// command to list registered user.
func userList(c *cli.Context) error {
client, err := newClient(c)
if err != nil {
return err
}
users, err := client.UserList()
if err != nil || len(users) == 0 {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, user := range users {
tmpl.Execute(os.Stdout, user)
}
return nil
}
// template for user list.
var tmplUserList = `{{ .Login }}`
// template for user info
var tmplUserInfo = `User: {{ .Login }}
Email: {{ .Email }}`

15
drone/user/user.go Normal file
View File

@ -0,0 +1,15 @@
package user
import "github.com/urfave/cli"
// Command exports the user command set.
var Command = cli.Command{
Name: "user",
Usage: "manage users",
Subcommands: []cli.Command{
userListCmd,
userInfoCmd,
userAddCmd,
userRemoveCmd,
},
}

32
drone/user/user_add.go Normal file
View File

@ -0,0 +1,32 @@
package user
import (
"fmt"
"github.com/drone/drone-go/drone"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
)
var userAddCmd = cli.Command{
Name: "add",
Usage: "adds a user",
Action: userAdd,
}
func userAdd(c *cli.Context) error {
login := c.Args().First()
client, err := internal.NewClient(c)
if err != nil {
return err
}
user, err := client.UserPost(&drone.User{Login: login})
if err != nil {
return err
}
fmt.Printf("Successfully added user %s\n", user.Login)
return nil
}

51
drone/user/user_info.go Normal file
View File

@ -0,0 +1,51 @@
package user
import (
"fmt"
"os"
"text/template"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
)
var userInfoCmd = cli.Command{
Name: "info",
Usage: "show user details",
Action: userInfo,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplUserInfo,
},
},
}
func userInfo(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
login := c.Args().First()
if len(login) == 0 {
return fmt.Errorf("Missing or invalid user login")
}
user, err := client.User(login)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, user)
}
// template for user information
var tmplUserInfo = `User: {{ .Login }}
Email: {{ .Email }}`

47
drone/user/user_list.go Normal file
View File

@ -0,0 +1,47 @@
package user
import (
"os"
"text/template"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
)
var userListCmd = cli.Command{
Name: "ls",
Usage: "list all users",
Action: userList,
Flags: []cli.Flag{
cli.StringFlag{
Name: "format",
Usage: "format output",
Value: tmplUserList,
},
},
}
func userList(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
users, err := client.UserList()
if err != nil || len(users) == 0 {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, user := range users {
tmpl.Execute(os.Stdout, user)
}
return nil
}
// template for user list items
var tmplUserList = `{{ .Login }}`

30
drone/user/user_rm.go Normal file
View File

@ -0,0 +1,30 @@
package user
import (
"fmt"
"github.com/urfave/cli"
"github.com/drone/drone-cli/drone/internal"
)
var userRemoveCmd = cli.Command{
Name: "rm",
Usage: "remove a user",
Action: userRemove,
}
func userRemove(c *cli.Context) error {
login := c.Args().First()
client, err := internal.NewClient(c)
if err != nil {
return err
}
if err := client.UserDel(login); err != nil {
return err
}
fmt.Printf("Successfully removed user %s\n", login)
return nil
}

View File

@ -1,53 +0,0 @@
package main
import (
"crypto/tls"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/drone/drone-go/drone"
"github.com/codegangsta/cli"
"github.com/jackspirou/syscerts"
)
func newClient(c *cli.Context) (drone.Client, error) {
var token = c.GlobalString("token")
var server = c.GlobalString("server")
// if no server url is provided we can default
// to the hosted Drone service.
if len(server) == 0 {
return nil, fmt.Errorf("Error: you must provide the Drone server address.")
}
if len(token) == 0 {
return nil, fmt.Errorf("Error: you must provide your Drone access token.")
}
// attempt to find system CA certs
certs := syscerts.SystemRootsPool()
tlsConfig := &tls.Config{RootCAs: certs}
// create the drone client with TLS options
return drone.NewClientTokenTLS(server, token, tlsConfig), nil
}
func parseRepo(str string) (user, repo string, err error) {
var parts = strings.Split(str, "/")
if len(parts) != 2 {
err = fmt.Errorf("Error: Invalid or missing repository. eg octocat/hello-world.")
return
}
user = parts[0]
repo = parts[1]
return
}
func readInput(in string) ([]byte, error) {
if in == "-" {
return ioutil.ReadAll(os.Stdin)
}
return ioutil.ReadFile(in)
}

22
vendor/github.com/Microsoft/go-winio/LICENSE generated vendored Normal file
View File

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

268
vendor/github.com/Microsoft/go-winio/backup.go generated vendored Normal file
View File

@ -0,0 +1,268 @@
// +build windows
package winio
import (
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"runtime"
"syscall"
"unicode/utf16"
)
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
const (
BackupData = uint32(iota + 1)
BackupEaData
BackupSecurity
BackupAlternateData
BackupLink
BackupPropertyData
BackupObjectId
BackupReparseData
BackupSparseBlock
BackupTxfsData
)
const (
StreamSparseAttributes = uint32(8)
)
const (
WRITE_DAC = 0x40000
WRITE_OWNER = 0x80000
ACCESS_SYSTEM_SECURITY = 0x1000000
)
// BackupHeader represents a backup stream of a file.
type BackupHeader struct {
Id uint32 // The backup stream ID
Attributes uint32 // Stream attributes
Size int64 // The size of the stream in bytes
Name string // The name of the stream (for BackupAlternateData only).
Offset int64 // The offset of the stream in the file (for BackupSparseBlock only).
}
type win32StreamId struct {
StreamId uint32
Attributes uint32
Size uint64
NameSize uint32
}
// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series
// of BackupHeader values.
type BackupStreamReader struct {
r io.Reader
bytesLeft int64
}
// NewBackupStreamReader produces a BackupStreamReader from any io.Reader.
func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
return &BackupStreamReader{r, 0}
}
// Next returns the next backup stream and prepares for calls to Write(). It skips the remainder of the current stream if
// it was not completely read.
func (r *BackupStreamReader) Next() (*BackupHeader, error) {
if r.bytesLeft > 0 {
if _, err := io.Copy(ioutil.Discard, r); err != nil {
return nil, err
}
}
var wsi win32StreamId
if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
return nil, err
}
hdr := &BackupHeader{
Id: wsi.StreamId,
Attributes: wsi.Attributes,
Size: int64(wsi.Size),
}
if wsi.NameSize != 0 {
name := make([]uint16, int(wsi.NameSize/2))
if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
return nil, err
}
hdr.Name = syscall.UTF16ToString(name)
}
if wsi.StreamId == BackupSparseBlock {
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
return nil, err
}
hdr.Size -= 8
}
r.bytesLeft = hdr.Size
return hdr, nil
}
// Read reads from the current backup stream.
func (r *BackupStreamReader) Read(b []byte) (int, error) {
if r.bytesLeft == 0 {
return 0, io.EOF
}
if int64(len(b)) > r.bytesLeft {
b = b[:r.bytesLeft]
}
n, err := r.r.Read(b)
r.bytesLeft -= int64(n)
if err == io.EOF {
err = io.ErrUnexpectedEOF
} else if r.bytesLeft == 0 && err == nil {
err = io.EOF
}
return n, err
}
// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API.
type BackupStreamWriter struct {
w io.Writer
bytesLeft int64
}
// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer.
func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter {
return &BackupStreamWriter{w, 0}
}
// WriteHeader writes the next backup stream header and prepares for calls to Write().
func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
if w.bytesLeft != 0 {
return fmt.Errorf("missing %d bytes", w.bytesLeft)
}
name := utf16.Encode([]rune(hdr.Name))
wsi := win32StreamId{
StreamId: hdr.Id,
Attributes: hdr.Attributes,
Size: uint64(hdr.Size),
NameSize: uint32(len(name) * 2),
}
if hdr.Id == BackupSparseBlock {
// Include space for the int64 block offset
wsi.Size += 8
}
if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil {
return err
}
if len(name) != 0 {
if err := binary.Write(w.w, binary.LittleEndian, name); err != nil {
return err
}
}
if hdr.Id == BackupSparseBlock {
if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil {
return err
}
}
w.bytesLeft = hdr.Size
return nil
}
// Write writes to the current backup stream.
func (w *BackupStreamWriter) Write(b []byte) (int, error) {
if w.bytesLeft < int64(len(b)) {
return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft)
}
n, err := w.w.Write(b)
w.bytesLeft -= int64(n)
return n, err
}
// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API.
type BackupFileReader struct {
f *os.File
includeSecurity bool
ctx uintptr
}
// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true,
// Read will attempt to read the security descriptor of the file.
func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
r := &BackupFileReader{f, includeSecurity, 0}
runtime.SetFinalizer(r, func(r *BackupFileReader) { r.Close() })
return r
}
// Read reads a backup stream from the file by calling the Win32 API BackupRead().
func (r *BackupFileReader) Read(b []byte) (int, error) {
var bytesRead uint32
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
if err != nil {
return 0, &os.PathError{"BackupRead", r.f.Name(), err}
}
if bytesRead == 0 {
return 0, io.EOF
}
return int(bytesRead), nil
}
// Close frees Win32 resources associated with the BackupFileReader. It does not close
// the underlying file.
func (r *BackupFileReader) Close() error {
if r.ctx != 0 {
backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
r.ctx = 0
}
return nil
}
// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API.
type BackupFileWriter struct {
f *os.File
includeSecurity bool
ctx uintptr
}
// NewBackupFileWrtier returns a new BackupFileWriter from a file handle. If includeSecurity is true,
// Write() will attempt to restore the security descriptor from the stream.
func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
w := &BackupFileWriter{f, includeSecurity, 0}
runtime.SetFinalizer(w, func(w *BackupFileWriter) { w.Close() })
return w
}
// Write restores a portion of the file using the provided backup stream.
func (w *BackupFileWriter) Write(b []byte) (int, error) {
var bytesWritten uint32
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
if err != nil {
return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
}
if int(bytesWritten) != len(b) {
return int(bytesWritten), errors.New("not all bytes could be written")
}
return len(b), nil
}
// Close frees Win32 resources associated with the BackupFileWriter. It does not
// close the underlying file.
func (w *BackupFileWriter) Close() error {
if w.ctx != 0 {
backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
w.ctx = 0
}
return nil
}
// OpenForBackup opens a file or directory, potentially skipping access checks if the backup
// or restore privileges have been acquired.
//
// If the file opened was a directory, it cannot be used with Readdir().
func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
winPath, err := syscall.UTF16FromString(path)
if err != nil {
return nil, err
}
h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0)
if err != nil {
err = &os.PathError{Op: "open", Path: path, Err: err}
return nil, err
}
return os.NewFile(uintptr(h), path), nil
}

221
vendor/github.com/Microsoft/go-winio/file.go generated vendored Normal file
View File

@ -0,0 +1,221 @@
// +build windows
package winio
import (
"errors"
"io"
"runtime"
"sync"
"syscall"
"time"
)
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
//sys timeBeginPeriod(period uint32) (n int32) = winmm.timeBeginPeriod
const (
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
cFILE_SKIP_SET_EVENT_ON_HANDLE = 2
)
var (
ErrFileClosed = errors.New("file has already been closed")
ErrTimeout = &timeoutError{}
)
type timeoutError struct{}
func (e *timeoutError) Error() string { return "i/o timeout" }
func (e *timeoutError) Timeout() bool { return true }
func (e *timeoutError) Temporary() bool { return true }
var ioInitOnce sync.Once
var ioCompletionPort syscall.Handle
// ioResult contains the result of an asynchronous IO operation
type ioResult struct {
bytes uint32
err error
}
// ioOperation represents an outstanding asynchronous Win32 IO
type ioOperation struct {
o syscall.Overlapped
ch chan ioResult
}
func initIo() {
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
if err != nil {
panic(err)
}
ioCompletionPort = h
go ioCompletionProcessor(h)
}
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
// It takes ownership of this handle and will close it if it is garbage collected.
type win32File struct {
handle syscall.Handle
wg sync.WaitGroup
closing bool
readDeadline time.Time
writeDeadline time.Time
}
// makeWin32File makes a new win32File from an existing file handle
func makeWin32File(h syscall.Handle) (*win32File, error) {
f := &win32File{handle: h}
ioInitOnce.Do(initIo)
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
if err != nil {
return nil, err
}
err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
if err != nil {
return nil, err
}
runtime.SetFinalizer(f, (*win32File).closeHandle)
return f, nil
}
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
return makeWin32File(h)
}
// closeHandle closes the resources associated with a Win32 handle
func (f *win32File) closeHandle() {
if !f.closing {
// cancel all IO and wait for it to complete
f.closing = true
cancelIoEx(f.handle, nil)
f.wg.Wait()
// at this point, no new IO can start
syscall.Close(f.handle)
f.handle = 0
}
}
// Close closes a win32File.
func (f *win32File) Close() error {
f.closeHandle()
runtime.SetFinalizer(f, nil)
return nil
}
// prepareIo prepares for a new IO operation
func (f *win32File) prepareIo() (*ioOperation, error) {
f.wg.Add(1)
if f.closing {
return nil, ErrFileClosed
}
c := &ioOperation{}
c.ch = make(chan ioResult)
return c, nil
}
// ioCompletionProcessor processes completed async IOs forever
func ioCompletionProcessor(h syscall.Handle) {
// Set the timer resolution to 1. This fixes a performance regression in golang 1.6.
timeBeginPeriod(1)
for {
var bytes uint32
var key uintptr
var op *ioOperation
err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
if op == nil {
panic(err)
}
op.ch <- ioResult{bytes, err}
}
}
// asyncIo processes the return value from ReadFile or WriteFile, blocking until
// the operation has actually completed.
func (f *win32File) asyncIo(c *ioOperation, deadline time.Time, bytes uint32, err error) (int, error) {
if err != syscall.ERROR_IO_PENDING {
f.wg.Done()
return int(bytes), err
} else {
var r ioResult
wait := true
timedout := false
if f.closing {
cancelIoEx(f.handle, &c.o)
} else if !deadline.IsZero() {
now := time.Now()
if !deadline.After(now) {
timedout = true
} else {
timeout := time.After(deadline.Sub(now))
select {
case r = <-c.ch:
wait = false
case <-timeout:
timedout = true
}
}
}
if timedout {
cancelIoEx(f.handle, &c.o)
}
if wait {
r = <-c.ch
}
err = r.err
if err == syscall.ERROR_OPERATION_ABORTED {
if f.closing {
err = ErrFileClosed
} else if timedout {
err = ErrTimeout
}
}
f.wg.Done()
return int(r.bytes), err
}
}
// Read reads from a file handle.
func (f *win32File) Read(b []byte) (int, error) {
c, err := f.prepareIo()
if err != nil {
return 0, err
}
var bytes uint32
err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
n, err := f.asyncIo(c, f.readDeadline, bytes, err)
// Handle EOF conditions.
if err == nil && n == 0 && len(b) != 0 {
return 0, io.EOF
} else if err == syscall.ERROR_BROKEN_PIPE {
return 0, io.EOF
} else {
return n, err
}
}
// Write writes to a file handle.
func (f *win32File) Write(b []byte) (int, error) {
c, err := f.prepareIo()
if err != nil {
return 0, err
}
var bytes uint32
err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
return f.asyncIo(c, f.writeDeadline, bytes, err)
}
func (f *win32File) SetReadDeadline(t time.Time) error {
f.readDeadline = t
return nil
}
func (f *win32File) SetWriteDeadline(t time.Time) error {
f.writeDeadline = t
return nil
}

56
vendor/github.com/Microsoft/go-winio/fileinfo.go generated vendored Normal file
View File

@ -0,0 +1,56 @@
// +build windows
package winio
import (
"os"
"syscall"
"unsafe"
)
//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx
//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle
const (
fileBasicInfo = 0
fileIDInfo = 0x12
)
// FileBasicInfo contains file access time and file attributes information.
type FileBasicInfo struct {
CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
FileAttributes uintptr // includes padding
}
// GetFileBasicInfo retrieves times and attributes for a file.
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
bi := &FileBasicInfo{}
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
}
return bi, nil
}
// SetFileBasicInfo sets times and attributes for a file.
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
}
return nil
}
// FileIDInfo contains the volume serial number and file ID for a file. This pair should be
// unique on a system.
type FileIDInfo struct {
VolumeSerialNumber uint64
FileID [16]byte
}
// GetFileID retrieves the unique (volume, file ID) pair for a file.
func GetFileID(f *os.File) (*FileIDInfo, error) {
fileID := &FileIDInfo{}
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
}
return fileID, nil
}

400
vendor/github.com/Microsoft/go-winio/pipe.go generated vendored Normal file
View File

@ -0,0 +1,400 @@
// +build windows
package winio
import (
"errors"
"io"
"net"
"os"
"syscall"
"time"
"unsafe"
)
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
//sys createFile(name string, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
//sys waitNamedPipe(name string, timeout uint32) (err error) = WaitNamedPipeW
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
type securityAttributes struct {
Length uint32
SecurityDescriptor *byte
InheritHandle uint32
}
const (
cERROR_PIPE_BUSY = syscall.Errno(231)
cERROR_PIPE_CONNECTED = syscall.Errno(535)
cERROR_SEM_TIMEOUT = syscall.Errno(121)
cPIPE_ACCESS_DUPLEX = 0x3
cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000
cSECURITY_SQOS_PRESENT = 0x100000
cSECURITY_ANONYMOUS = 0
cPIPE_REJECT_REMOTE_CLIENTS = 0x8
cPIPE_UNLIMITED_INSTANCES = 255
cNMPWAIT_USE_DEFAULT_WAIT = 0
cNMPWAIT_NOWAIT = 1
cPIPE_TYPE_MESSAGE = 4
cPIPE_READMODE_MESSAGE = 2
)
var (
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
// This error should match net.errClosing since docker takes a dependency on its text.
ErrPipeListenerClosed = errors.New("use of closed network connection")
errPipeWriteClosed = errors.New("pipe has been closed for write")
)
type win32Pipe struct {
*win32File
path string
}
type win32MessageBytePipe struct {
win32Pipe
writeClosed bool
readEOF bool
}
type pipeAddress string
func (f *win32Pipe) LocalAddr() net.Addr {
return pipeAddress(f.path)
}
func (f *win32Pipe) RemoteAddr() net.Addr {
return pipeAddress(f.path)
}
func (f *win32Pipe) SetDeadline(t time.Time) error {
f.SetReadDeadline(t)
f.SetWriteDeadline(t)
return nil
}
// CloseWrite closes the write side of a message pipe in byte mode.
func (f *win32MessageBytePipe) CloseWrite() error {
if f.writeClosed {
return errPipeWriteClosed
}
_, err := f.win32File.Write(nil)
if err != nil {
return err
}
f.writeClosed = true
return nil
}
// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since
// they are used to implement CloseWrite().
func (f *win32MessageBytePipe) Write(b []byte) (int, error) {
if f.writeClosed {
return 0, errPipeWriteClosed
}
if len(b) == 0 {
return 0, nil
}
return f.win32File.Write(b)
}
// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message
// mode pipe will return io.EOF, as will all subsequent reads.
func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
if f.readEOF {
return 0, io.EOF
}
n, err := f.win32File.Read(b)
if err == io.EOF {
// If this was the result of a zero-byte read, then
// it is possible that the read was due to a zero-size
// message. Since we are simulating CloseWrite with a
// zero-byte message, ensure that all future Read() calls
// also return EOF.
f.readEOF = true
}
return n, err
}
func (s pipeAddress) Network() string {
return "pipe"
}
func (s pipeAddress) String() string {
return string(s)
}
// DialPipe connects to a named pipe by path, timing out if the connection
// takes longer than the specified duration. If timeout is nil, then the timeout
// is the default timeout established by the pipe server.
func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
var absTimeout time.Time
if timeout != nil {
absTimeout = time.Now().Add(*timeout)
}
var err error
var h syscall.Handle
for {
h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
if err != cERROR_PIPE_BUSY {
break
}
now := time.Now()
var ms uint32
if absTimeout.IsZero() {
ms = cNMPWAIT_USE_DEFAULT_WAIT
} else if now.After(absTimeout) {
ms = cNMPWAIT_NOWAIT
} else {
ms = uint32(absTimeout.Sub(now).Nanoseconds() / 1000 / 1000)
}
err = waitNamedPipe(path, ms)
if err != nil {
if err == cERROR_SEM_TIMEOUT {
return nil, ErrTimeout
}
break
}
}
if err != nil {
return nil, &os.PathError{Op: "open", Path: path, Err: err}
}
var flags uint32
err = getNamedPipeInfo(h, &flags, nil, nil, nil)
if err != nil {
return nil, err
}
var state uint32
err = getNamedPipeHandleState(h, &state, nil, nil, nil, nil, 0)
if err != nil {
return nil, err
}
if state&cPIPE_READMODE_MESSAGE != 0 {
return nil, &os.PathError{Op: "open", Path: path, Err: errors.New("message readmode pipes not supported")}
}
f, err := makeWin32File(h)
if err != nil {
syscall.Close(h)
return nil, err
}
// If the pipe is in message mode, return a message byte pipe, which
// supports CloseWrite().
if flags&cPIPE_TYPE_MESSAGE != 0 {
return &win32MessageBytePipe{
win32Pipe: win32Pipe{win32File: f, path: path},
}, nil
}
return &win32Pipe{win32File: f, path: path}, nil
}
type acceptResponse struct {
f *win32File
err error
}
type win32PipeListener struct {
firstHandle syscall.Handle
path string
securityDescriptor []byte
config PipeConfig
acceptCh chan (chan acceptResponse)
closeCh chan int
doneCh chan int
}
func makeServerPipeHandle(path string, securityDescriptor []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED
if first {
flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE
}
var mode uint32 = cPIPE_REJECT_REMOTE_CLIENTS
if c.MessageMode {
mode |= cPIPE_TYPE_MESSAGE
}
var sa securityAttributes
sa.Length = uint32(unsafe.Sizeof(sa))
if securityDescriptor != nil {
sa.SecurityDescriptor = &securityDescriptor[0]
}
h, err := createNamedPipe(path, flags, mode, cPIPE_UNLIMITED_INSTANCES, uint32(c.OutputBufferSize), uint32(c.InputBufferSize), 0, &sa)
if err != nil {
return 0, &os.PathError{Op: "open", Path: path, Err: err}
}
return h, nil
}
func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
h, err := makeServerPipeHandle(l.path, l.securityDescriptor, &l.config, false)
if err != nil {
return nil, err
}
f, err := makeWin32File(h)
if err != nil {
syscall.Close(h)
return nil, err
}
return f, nil
}
func (l *win32PipeListener) listenerRoutine() {
closed := false
for !closed {
select {
case <-l.closeCh:
closed = true
case responseCh := <-l.acceptCh:
p, err := l.makeServerPipe()
if err == nil {
// Wait for the client to connect.
ch := make(chan error)
go func() {
ch <- connectPipe(p)
}()
select {
case err = <-ch:
if err != nil {
p.Close()
p = nil
}
case <-l.closeCh:
// Abort the connect request by closing the handle.
p.Close()
p = nil
err = <-ch
if err == nil || err == ErrFileClosed {
err = ErrPipeListenerClosed
}
closed = true
}
}
responseCh <- acceptResponse{p, err}
}
}
syscall.Close(l.firstHandle)
l.firstHandle = 0
// Notify Close() and Accept() callers that the handle has been closed.
close(l.doneCh)
}
// PipeConfig contain configuration for the pipe listener.
type PipeConfig struct {
// SecurityDescriptor contains a Windows security descriptor in SDDL format.
SecurityDescriptor string
// MessageMode determines whether the pipe is in byte or message mode. In either
// case the pipe is read in byte mode by default. The only practical difference in
// this implementation is that CloseWrite() is only supported for message mode pipes;
// CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only
// transferred to the reader (and returned as io.EOF in this implementation)
// when the pipe is in message mode.
MessageMode bool
// InputBufferSize specifies the size the input buffer, in bytes.
InputBufferSize int32
// OutputBufferSize specifies the size the input buffer, in bytes.
OutputBufferSize int32
}
// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe.
// The pipe must not already exist.
func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
var (
sd []byte
err error
)
if c == nil {
c = &PipeConfig{}
}
if c.SecurityDescriptor != "" {
sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor)
if err != nil {
return nil, err
}
}
h, err := makeServerPipeHandle(path, sd, c, true)
if err != nil {
return nil, err
}
// Immediately open and then close a client handle so that the named pipe is
// created but not currently accepting connections.
h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
if err != nil {
syscall.Close(h)
return nil, err
}
syscall.Close(h2)
l := &win32PipeListener{
firstHandle: h,
path: path,
securityDescriptor: sd,
config: *c,
acceptCh: make(chan (chan acceptResponse)),
closeCh: make(chan int),
doneCh: make(chan int),
}
go l.listenerRoutine()
return l, nil
}
func connectPipe(p *win32File) error {
c, err := p.prepareIo()
if err != nil {
return err
}
err = connectNamedPipe(p.handle, &c.o)
_, err = p.asyncIo(c, time.Time{}, 0, err)
if err != nil && err != cERROR_PIPE_CONNECTED {
return err
}
return nil
}
func (l *win32PipeListener) Accept() (net.Conn, error) {
ch := make(chan acceptResponse)
select {
case l.acceptCh <- ch:
response := <-ch
err := response.err
if err != nil {
return nil, err
}
if l.config.MessageMode {
return &win32MessageBytePipe{
win32Pipe: win32Pipe{win32File: response.f, path: l.path},
}, nil
}
return &win32Pipe{win32File: response.f, path: l.path}, nil
case <-l.doneCh:
return nil, ErrPipeListenerClosed
}
}
func (l *win32PipeListener) Close() error {
select {
case l.closeCh <- 1:
<-l.doneCh
case <-l.doneCh:
}
return nil
}
func (l *win32PipeListener) Addr() net.Addr {
return pipeAddress(l.path)
}

202
vendor/github.com/Microsoft/go-winio/privilege.go generated vendored Normal file
View File

@ -0,0 +1,202 @@
// +build windows
package winio
import (
"bytes"
"encoding/binary"
"fmt"
"runtime"
"sync"
"syscall"
"unicode/utf16"
"golang.org/x/sys/windows"
)
//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
//sys revertToSelf() (err error) = advapi32.RevertToSelf
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
const (
SE_PRIVILEGE_ENABLED = 2
ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300
SeBackupPrivilege = "SeBackupPrivilege"
SeRestorePrivilege = "SeRestorePrivilege"
)
const (
securityAnonymous = iota
securityIdentification
securityImpersonation
securityDelegation
)
var (
privNames = make(map[string]uint64)
privNameMutex sync.Mutex
)
// PrivilegeError represents an error enabling privileges.
type PrivilegeError struct {
privileges []uint64
}
func (e *PrivilegeError) Error() string {
s := ""
if len(e.privileges) > 1 {
s = "Could not enable privileges "
} else {
s = "Could not enable privilege "
}
for i, p := range e.privileges {
if i != 0 {
s += ", "
}
s += `"`
s += getPrivilegeName(p)
s += `"`
}
return s
}
// RunWithPrivilege enables a single privilege for a function call.
func RunWithPrivilege(name string, fn func() error) error {
return RunWithPrivileges([]string{name}, fn)
}
// RunWithPrivileges enables privileges for a function call.
func RunWithPrivileges(names []string, fn func() error) error {
privileges, err := mapPrivileges(names)
if err != nil {
return err
}
runtime.LockOSThread()
defer runtime.UnlockOSThread()
token, err := newThreadToken()
if err != nil {
return err
}
defer releaseThreadToken(token)
err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED)
if err != nil {
return err
}
return fn()
}
func mapPrivileges(names []string) ([]uint64, error) {
var privileges []uint64
privNameMutex.Lock()
defer privNameMutex.Unlock()
for _, name := range names {
p, ok := privNames[name]
if !ok {
err := lookupPrivilegeValue("", name, &p)
if err != nil {
return nil, err
}
privNames[name] = p
}
privileges = append(privileges, p)
}
return privileges, nil
}
// EnableProcessPrivileges enables privileges globally for the process.
func EnableProcessPrivileges(names []string) error {
return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED)
}
// DisableProcessPrivileges disables privileges globally for the process.
func DisableProcessPrivileges(names []string) error {
return enableDisableProcessPrivilege(names, 0)
}
func enableDisableProcessPrivilege(names []string, action uint32) error {
privileges, err := mapPrivileges(names)
if err != nil {
return err
}
p, _ := windows.GetCurrentProcess()
var token windows.Token
err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
if err != nil {
return err
}
defer token.Close()
return adjustPrivileges(token, privileges, action)
}
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
var b bytes.Buffer
binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
for _, p := range privileges {
binary.Write(&b, binary.LittleEndian, p)
binary.Write(&b, binary.LittleEndian, action)
}
prevState := make([]byte, b.Len())
reqSize := uint32(0)
success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize)
if !success {
return err
}
if err == ERROR_NOT_ALL_ASSIGNED {
return &PrivilegeError{privileges}
}
return nil
}
func getPrivilegeName(luid uint64) string {
var nameBuffer [256]uint16
bufSize := uint32(len(nameBuffer))
err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize)
if err != nil {
return fmt.Sprintf("<unknown privilege %d>", luid)
}
var displayNameBuffer [256]uint16
displayBufSize := uint32(len(displayNameBuffer))
var langID uint32
err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID)
if err != nil {
return fmt.Sprintf("<unknown privilege %s>", string(utf16.Decode(nameBuffer[:bufSize])))
}
return string(utf16.Decode(displayNameBuffer[:displayBufSize]))
}
func newThreadToken() (windows.Token, error) {
err := impersonateSelf(securityImpersonation)
if err != nil {
return 0, err
}
var token windows.Token
err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token)
if err != nil {
rerr := revertToSelf()
if rerr != nil {
panic(rerr)
}
return 0, err
}
return token, nil
}
func releaseThreadToken(h windows.Token) {
err := revertToSelf()
if err != nil {
panic(err)
}
h.Close()
}

128
vendor/github.com/Microsoft/go-winio/reparse.go generated vendored Normal file
View File

@ -0,0 +1,128 @@
package winio
import (
"bytes"
"encoding/binary"
"fmt"
"strings"
"unicode/utf16"
"unsafe"
)
const (
reparseTagMountPoint = 0xA0000003
reparseTagSymlink = 0xA000000C
)
type reparseDataBuffer struct {
ReparseTag uint32
ReparseDataLength uint16
Reserved uint16
SubstituteNameOffset uint16
SubstituteNameLength uint16
PrintNameOffset uint16
PrintNameLength uint16
}
// ReparsePoint describes a Win32 symlink or mount point.
type ReparsePoint struct {
Target string
IsMountPoint bool
}
// UnsupportedReparsePointError is returned when trying to decode a non-symlink or
// mount point reparse point.
type UnsupportedReparsePointError struct {
Tag uint32
}
func (e *UnsupportedReparsePointError) Error() string {
return fmt.Sprintf("unsupported reparse point %x", e.Tag)
}
// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink
// or a mount point.
func DecodeReparsePoint(b []byte) (*ReparsePoint, error) {
tag := binary.LittleEndian.Uint32(b[0:4])
return DecodeReparsePointData(tag, b[8:])
}
func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) {
isMountPoint := false
switch tag {
case reparseTagMountPoint:
isMountPoint = true
case reparseTagSymlink:
default:
return nil, &UnsupportedReparsePointError{tag}
}
nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6])
if !isMountPoint {
nameOffset += 4
}
nameLength := binary.LittleEndian.Uint16(b[6:8])
name := make([]uint16, nameLength/2)
err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name)
if err != nil {
return nil, err
}
return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil
}
func isDriveLetter(c byte) bool {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}
// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or
// mount point.
func EncodeReparsePoint(rp *ReparsePoint) []byte {
// Generate an NT path and determine if this is a relative path.
var ntTarget string
relative := false
if strings.HasPrefix(rp.Target, `\\?\`) {
ntTarget = `\??\` + rp.Target[4:]
} else if strings.HasPrefix(rp.Target, `\\`) {
ntTarget = `\??\UNC\` + rp.Target[2:]
} else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' {
ntTarget = `\??\` + rp.Target
} else {
ntTarget = rp.Target
relative = true
}
// The paths must be NUL-terminated even though they are counted strings.
target16 := utf16.Encode([]rune(rp.Target + "\x00"))
ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00"))
size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8
size += len(ntTarget16)*2 + len(target16)*2
tag := uint32(reparseTagMountPoint)
if !rp.IsMountPoint {
tag = reparseTagSymlink
size += 4 // Add room for symlink flags
}
data := reparseDataBuffer{
ReparseTag: tag,
ReparseDataLength: uint16(size),
SubstituteNameOffset: 0,
SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2),
PrintNameOffset: uint16(len(ntTarget16) * 2),
PrintNameLength: uint16((len(target16) - 1) * 2),
}
var b bytes.Buffer
binary.Write(&b, binary.LittleEndian, &data)
if !rp.IsMountPoint {
flags := uint32(0)
if relative {
flags |= 1
}
binary.Write(&b, binary.LittleEndian, flags)
}
binary.Write(&b, binary.LittleEndian, ntTarget16)
binary.Write(&b, binary.LittleEndian, target16)
return b.Bytes()
}

98
vendor/github.com/Microsoft/go-winio/sd.go generated vendored Normal file
View File

@ -0,0 +1,98 @@
// +build windows
package winio
import (
"syscall"
"unsafe"
)
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
//sys localFree(mem uintptr) = LocalFree
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
const (
cERROR_NONE_MAPPED = syscall.Errno(1332)
)
type AccountLookupError struct {
Name string
Err error
}
func (e *AccountLookupError) Error() string {
if e.Name == "" {
return "lookup account: empty account name specified"
}
var s string
switch e.Err {
case cERROR_NONE_MAPPED:
s = "not found"
default:
s = e.Err.Error()
}
return "lookup account " + e.Name + ": " + s
}
type SddlConversionError struct {
Sddl string
Err error
}
func (e *SddlConversionError) Error() string {
return "convert " + e.Sddl + ": " + e.Err.Error()
}
// LookupSidByName looks up the SID of an account by name
func LookupSidByName(name string) (sid string, err error) {
if name == "" {
return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
}
var sidSize, sidNameUse, refDomainSize uint32
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
return "", &AccountLookupError{name, err}
}
sidBuffer := make([]byte, sidSize)
refDomainBuffer := make([]uint16, refDomainSize)
err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
if err != nil {
return "", &AccountLookupError{name, err}
}
var strBuffer *uint16
err = convertSidToStringSid(&sidBuffer[0], &strBuffer)
if err != nil {
return "", &AccountLookupError{name, err}
}
sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
localFree(uintptr(unsafe.Pointer(strBuffer)))
return sid, nil
}
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
var sdBuffer uintptr
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
if err != nil {
return nil, &SddlConversionError{sddl, err}
}
defer localFree(sdBuffer)
sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
return sd, nil
}
func SecurityDescriptorToSddl(sd []byte) (string, error) {
var sddl *uint16
// The returned string length seems to including an aribtrary number of terminating NULs.
// Don't use it.
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
if err != nil {
return "", err
}
defer localFree(uintptr(unsafe.Pointer(sddl)))
return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil
}

3
vendor/github.com/Microsoft/go-winio/syscall.go generated vendored Normal file
View File

@ -0,0 +1,3 @@
package winio
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go

View File

@ -0,0 +1,496 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
package winio
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modwinmm = windows.NewLazySystemDLL("winmm.dll")
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
proctimeBeginPeriod = modwinmm.NewProc("timeBeginPeriod")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procCreateFileW = modkernel32.NewProc("CreateFileW")
procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW")
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
procLocalFree = modkernel32.NewProc("LocalFree")
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
procBackupRead = modkernel32.NewProc("BackupRead")
procBackupWrite = modkernel32.NewProc("BackupWrite")
)
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
newport = syscall.Handle(r0)
if newport == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func timeBeginPeriod(period uint32) (n int32) {
r0, _, _ := syscall.Syscall(proctimeBeginPeriod.Addr(), 1, uintptr(period), 0, 0)
n = int32(r0)
return
}
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
}
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func createFile(name string, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _createFile(name *uint16, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func waitNamedPipe(name string, timeout uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _waitNamedPipe(_p0, timeout)
}
func _waitNamedPipe(name *uint16, timeout uint32) (err error) {
r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(accountName)
if err != nil {
return
}
return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse)
}
func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func convertSidToStringSid(sid *byte, str **uint16) (err error) {
r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(str)
if err != nil {
return
}
return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
}
func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func localFree(mem uintptr) {
syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
return
}
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
len = uint32(r0)
return
}
func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
var _p0 uint32
if releaseAll {
_p0 = 1
} else {
_p0 = 0
}
r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
success = r0 != 0
if true {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func impersonateSelf(level uint32) (err error) {
r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func revertToSelf() (err error) {
r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
var _p0 uint32
if openAsSelf {
_p0 = 1
} else {
_p0 = 0
}
r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getCurrentThread() (h syscall.Handle) {
r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
h = syscall.Handle(r0)
return
}
func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(systemName)
if err != nil {
return
}
var _p1 *uint16
_p1, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _lookupPrivilegeValue(_p0, _p1, luid)
}
func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(systemName)
if err != nil {
return
}
return _lookupPrivilegeName(_p0, luid, buffer, size)
}
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(systemName)
if err != nil {
return
}
return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId)
}
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
var _p0 *byte
if len(b) > 0 {
_p0 = &b[0]
}
var _p1 uint32
if abort {
_p1 = 1
} else {
_p1 = 0
}
var _p2 uint32
if processSecurity {
_p2 = 1
} else {
_p2 = 0
}
r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
var _p0 *byte
if len(b) > 0 {
_p0 = &b[0]
}
var _p1 uint32
if abort {
_p1 = 1
} else {
_p1 = 0
}
var _p2 uint32
if processSecurity {
_p2 = 1
} else {
_p2 = 0
}
r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}

View File

@ -1,66 +0,0 @@
# 0.10.0
* feature: Add a test hook (#180)
* feature: `ParseLevel` is now case-insensitive (#326)
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
* performance: avoid re-allocations on `WithFields` (#335)
# 0.9.0
* logrus/text_formatter: don't emit empty msg
* logrus/hooks/airbrake: move out of main repository
* logrus/hooks/sentry: move out of main repository
* logrus/hooks/papertrail: move out of main repository
* logrus/hooks/bugsnag: move out of main repository
* logrus/core: run tests with `-race`
* logrus/core: detect TTY based on `stderr`
* logrus/core: support `WithError` on logger
* logrus/core: Solaris support
# 0.8.7
* logrus/core: fix possible race (#216)
* logrus/doc: small typo fixes and doc improvements
# 0.8.6
* hooks/raven: allow passing an initialized client
# 0.8.5
* logrus/core: revert #208
# 0.8.4
* formatter/text: fix data race (#218)
# 0.8.3
* logrus/core: fix entry log level (#208)
* logrus/core: improve performance of text formatter by 40%
* logrus/core: expose `LevelHooks` type
* logrus/core: add support for DragonflyBSD and NetBSD
* formatter/text: print structs more verbosely
# 0.8.2
* logrus: fix more Fatal family functions
# 0.8.1
* logrus: fix not exiting on `Fatalf` and `Fatalln`
# 0.8.0
* logrus: defaults to stderr instead of stdout
* hooks/sentry: add special field for `*http.Request`
* formatter/text: ignore Windows for colors
# 0.7.3
* formatter/\*: allow configuration of timestamp layout
# 0.7.2
* formatter/text: Add configuration option for time format (#158)

View File

@ -1,388 +0,0 @@
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus)
Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
yet stable (pre 1.0). Logrus itself is completely stable and has been used in
many large deployments. The core API is unlikely to change much but please
version control your Logrus to make sure you aren't fetching latest `master` on
every build.**
Nicely color-coded in development (when a TTY is attached, otherwise just
plain text):
![Colored](http://i.imgur.com/PY7qMwd.png)
With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
or Splunk:
```json
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
{"level":"warning","msg":"The group's number increased tremendously!",
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
```
With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
attached, the output is compatible with the
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
```text
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
exit status 1
```
#### Example
The simplest way to use Logrus is simply the package-level exported logger:
```go
package main
import (
log "github.com/Sirupsen/logrus"
)
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
}).Info("A walrus appears")
}
```
Note that it's completely api-compatible with the stdlib logger, so you can
replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
and you'll now have the flexibility of Logrus. You can customize it all you
want:
```go
package main
import (
"os"
log "github.com/Sirupsen/logrus"
)
func init() {
// Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{})
// Output to stderr instead of stdout, could also be a file.
log.SetOutput(os.Stderr)
// Only log the warning severity or above.
log.SetLevel(log.WarnLevel)
}
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
log.WithFields(log.Fields{
"omg": true,
"number": 122,
}).Warn("The group's number increased tremendously!")
log.WithFields(log.Fields{
"omg": true,
"number": 100,
}).Fatal("The ice breaks!")
// A common pattern is to re-use fields between logging statements by re-using
// the logrus.Entry returned from WithFields()
contextLogger := log.WithFields(log.Fields{
"common": "this is a common field",
"other": "I also should be logged always",
})
contextLogger.Info("I'll be logged with common and other field")
contextLogger.Info("Me too")
}
```
For more advanced usage such as logging to multiple locations from the same
application, you can also create an instance of the `logrus` Logger:
```go
package main
import (
"github.com/Sirupsen/logrus"
)
// Create a new instance of the logger. You can have any number of instances.
var log = logrus.New()
func main() {
// The API for setting attributes is a little different than the package level
// exported logger. See Godoc.
log.Out = os.Stderr
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
}
```
#### Fields
Logrus encourages careful, structured logging though logging fields instead of
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
to send event %s to topic %s with key %d")`, you should log the much more
discoverable:
```go
log.WithFields(log.Fields{
"event": event,
"topic": topic,
"key": key,
}).Fatal("Failed to send event")
```
We've found this API forces you to think about logging in a way that produces
much more useful logging messages. We've been in countless situations where just
a single added field to a log statement that was already there would've saved us
hours. The `WithFields` call is optional.
In general, with Logrus using any of the `printf`-family functions should be
seen as a hint you should add a field, however, you can still use the
`printf`-family functions with Logrus.
#### Hooks
You can add hooks for logging levels. For example to send errors to an exception
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
multiple places simultaneously, e.g. syslog.
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
`init`:
```go
import (
log "github.com/Sirupsen/logrus"
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
"log/syslog"
)
func init() {
// Use the Airbrake hook to report errors that have Error severity or above to
// an exception tracker. You can create custom hooks, see the Hooks section.
log.AddHook(airbrake.NewHook(123, "xyz", "production"))
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
if err != nil {
log.Error("Unable to connect to local syslog daemon")
} else {
log.AddHook(hook)
}
}
```
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
| Hook | Description |
| ----- | ----------- |
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
#### Level logging
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
```go
log.Debug("Useful debugging information.")
log.Info("Something noteworthy happened!")
log.Warn("You should probably take a look at this.")
log.Error("Something failed but I'm not quitting.")
// Calls os.Exit(1) after logging
log.Fatal("Bye.")
// Calls panic() after logging
log.Panic("I'm bailing.")
```
You can set the logging level on a `Logger`, then it will only log entries with
that severity or anything above it:
```go
// Will log anything that is info or above (warn, error, fatal, panic). Default.
log.SetLevel(log.InfoLevel)
```
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
environment if your application has that.
#### Entries
Besides the fields added with `WithField` or `WithFields` some fields are
automatically added to all logging events:
1. `time`. The timestamp when the entry was created.
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
the `AddFields` call. E.g. `Failed to send event.`
3. `level`. The logging level. E.g. `info`.
#### Environments
Logrus has no notion of environment.
If you wish for hooks and formatters to only be used in specific environments,
you should handle that yourself. For example, if your application has a global
variable `Environment`, which is a string representation of the environment you
could do:
```go
import (
log "github.com/Sirupsen/logrus"
)
init() {
// do something here to set environment depending on an environment variable
// or command-line flag
if Environment == "production" {
log.SetFormatter(&log.JSONFormatter{})
} else {
// The TextFormatter is default, you don't actually have to do this.
log.SetFormatter(&log.TextFormatter{})
}
}
```
This configuration is how `logrus` was intended to be used, but JSON in
production is mostly only useful if you do log aggregation with tools like
Splunk or Logstash.
#### Formatters
The built-in logging formatters are:
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
without colors.
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
field to `true`. To force no colored output even if there is a TTY set the
`DisableColors` field to `true`
* `logrus.JSONFormatter`. Logs fields as JSON.
* `logrus/formatters/logstash.LogstashFormatter`. Logs fields as [Logstash](http://logstash.net) Events.
```go
logrus.SetFormatter(&logstash.LogstashFormatter{Type: "application_name"})
```
Third party logging formatters:
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
You can define your formatter by implementing the `Formatter` interface,
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
`Fields` type (`map[string]interface{}`) with all your fields as well as the
default ones (see Entries section above):
```go
type MyJSONFormatter struct {
}
log.SetFormatter(new(MyJSONFormatter))
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
// Note this doesn't include Time, Level and Message which are available on
// the Entry. Consult `godoc` on information about those fields or read the
// source of the official loggers.
serialized, err := json.Marshal(entry.Data)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
return append(serialized, '\n'), nil
}
```
#### Logger as an `io.Writer`
Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
```go
w := logger.Writer()
defer w.Close()
srv := http.Server{
// create a stdlib log.Logger that writes to
// logrus.Logger.
ErrorLog: log.New(w, "", 0),
}
```
Each line written to that writer will be printed the usual way, using formatters
and hooks. The level for those entries is `info`.
#### Rotation
Log rotation is not provided with Logrus. Log rotation should be done by an
external program (like `logrotate(8)`) that can compress and delete old log
entries. It should not be a feature of the application-level logger.
#### Tools
| Tool | Description |
| ---- | ----------- |
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
#### Testing
Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
```go
logger, hook := NewNullLogger()
logger.Error("Hello error")
assert.Equal(1, len(hook.Entries))
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
assert.Equal("Hello error", hook.LastEntry().Message)
hook.Reset()
assert.Nil(hook.LastEntry())
```

64
vendor/github.com/Sirupsen/logrus/alt_exit.go generated vendored Normal file
View File

@ -0,0 +1,64 @@
package logrus
// The following code was sourced and modified from the
// https://bitbucket.org/tebeka/atexit package governed by the following license:
//
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import (
"fmt"
"os"
)
var handlers = []func(){}
func runHandler(handler func()) {
defer func() {
if err := recover(); err != nil {
fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
}
}()
handler()
}
func runHandlers() {
for _, handler := range handlers {
runHandler(handler)
}
}
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
func Exit(code int) {
runHandlers()
os.Exit(code)
}
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
// all handlers. The handlers will also be invoked when any Fatal log entry is
// made.
//
// This method is useful when a caller wishes to use logrus to log a fatal
// message but also needs to gracefully shutdown. An example usecase could be
// closing database connections, or sending a alert that the application is
// closing.
func RegisterExitHandler(handler func()) {
handlers = append(handlers, handler)
}

View File

@ -3,11 +3,21 @@ package logrus
import (
"bytes"
"fmt"
"io"
"os"
"sync"
"time"
)
var bufferPool *sync.Pool
func init() {
bufferPool = &sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
}
// Defines the key when adding errors using WithError.
var ErrorKey = "error"
@ -29,6 +39,9 @@ type Entry struct {
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
Message string
// When formatter is called in entry.log(), an Buffer may be set to entry
Buffer *bytes.Buffer
}
func NewEntry(logger *Logger) *Entry {
@ -39,21 +52,15 @@ func NewEntry(logger *Logger) *Entry {
}
}
// Returns a reader for the entry, which is a proxy to the formatter.
func (entry *Entry) Reader() (*bytes.Buffer, error) {
serialized, err := entry.Logger.Formatter.Format(entry)
return bytes.NewBuffer(serialized), err
}
// Returns the string representation from the reader and ultimately the
// formatter.
func (entry *Entry) String() (string, error) {
reader, err := entry.Reader()
serialized, err := entry.Logger.Formatter.Format(entry)
if err != nil {
return "", err
}
return reader.String(), err
str := string(serialized)
return str, nil
}
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
@ -81,6 +88,7 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) log(level Level, msg string) {
var buffer *bytes.Buffer
entry.Time = time.Now()
entry.Level = level
entry.Message = msg
@ -90,20 +98,23 @@ func (entry Entry) log(level Level, msg string) {
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
entry.Logger.mu.Unlock()
}
reader, err := entry.Reader()
buffer = bufferPool.Get().(*bytes.Buffer)
buffer.Reset()
defer bufferPool.Put(buffer)
entry.Buffer = buffer
serialized, err := entry.Logger.Formatter.Format(&entry)
entry.Buffer = nil
if err != nil {
entry.Logger.mu.Lock()
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
entry.Logger.mu.Unlock()
}
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
_, err = io.Copy(entry.Logger.Out, reader)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
} else {
entry.Logger.mu.Lock()
_, err = entry.Logger.Out.Write(serialized)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
}
entry.Logger.mu.Unlock()
}
// To avoid Entry#log() returning a value that only would make sense for
@ -150,7 +161,7 @@ func (entry *Entry) Fatal(args ...interface{}) {
if entry.Logger.Level >= FatalLevel {
entry.log(FatalLevel, fmt.Sprint(args...))
}
os.Exit(1)
Exit(1)
}
func (entry *Entry) Panic(args ...interface{}) {
@ -198,7 +209,7 @@ func (entry *Entry) Fatalf(format string, args ...interface{}) {
if entry.Logger.Level >= FatalLevel {
entry.Fatal(fmt.Sprintf(format, args...))
}
os.Exit(1)
Exit(1)
}
func (entry *Entry) Panicf(format string, args ...interface{}) {
@ -245,7 +256,7 @@ func (entry *Entry) Fatalln(args ...interface{}) {
if entry.Logger.Level >= FatalLevel {
entry.Fatal(entry.sprintlnn(args...))
}
os.Exit(1)
Exit(1)
}
func (entry *Entry) Panicln(args ...interface{}) {

View File

@ -31,18 +31,15 @@ type Formatter interface {
// It's not exported because it's still using Data in an opinionated way. It's to
// avoid code duplication between the two default formatters.
func prefixFieldClashes(data Fields) {
_, ok := data["time"]
if ok {
data["fields.time"] = data["time"]
if t, ok := data["time"]; ok {
data["fields.time"] = t
}
_, ok = data["msg"]
if ok {
data["fields.msg"] = data["msg"]
if m, ok := data["msg"]; ok {
data["fields.msg"] = m
}
_, ok = data["level"]
if ok {
data["fields.level"] = data["level"]
if l, ok := data["level"]; ok {
data["fields.level"] = l
}
}

View File

@ -26,8 +26,31 @@ type Logger struct {
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
// logged. `logrus.Debug` is useful in
Level Level
// Used to sync writing to the log.
mu sync.Mutex
// Used to sync writing to the log. Locking is enabled by Default
mu MutexWrap
// Reusable empty entry
entryPool sync.Pool
}
type MutexWrap struct {
lock sync.Mutex
disabled bool
}
func (mw *MutexWrap) Lock() {
if !mw.disabled {
mw.lock.Lock()
}
}
func (mw *MutexWrap) Unlock() {
if !mw.disabled {
mw.lock.Unlock()
}
}
func (mw *MutexWrap) Disable() {
mw.disabled = true
}
// Creates a new logger. Configuration should be set by changing `Formatter`,
@ -51,162 +74,235 @@ func New() *Logger {
}
}
// Adds a field to the log entry, note that you it doesn't log until you call
func (logger *Logger) newEntry() *Entry {
entry, ok := logger.entryPool.Get().(*Entry)
if ok {
return entry
}
return NewEntry(logger)
}
func (logger *Logger) releaseEntry(entry *Entry) {
logger.entryPool.Put(entry)
}
// Adds a field to the log entry, note that it doesn't log until you call
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
// If you want multiple fields, use `WithFields`.
func (logger *Logger) WithField(key string, value interface{}) *Entry {
return NewEntry(logger).WithField(key, value)
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithField(key, value)
}
// Adds a struct of fields to the log entry. All it does is call `WithField` for
// each `Field`.
func (logger *Logger) WithFields(fields Fields) *Entry {
return NewEntry(logger).WithFields(fields)
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithFields(fields)
}
// Add an error as single field to the log entry. All it does is call
// `WithError` for the given `error`.
func (logger *Logger) WithError(err error) *Entry {
return NewEntry(logger).WithError(err)
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithError(err)
}
func (logger *Logger) Debugf(format string, args ...interface{}) {
if logger.Level >= DebugLevel {
NewEntry(logger).Debugf(format, args...)
entry := logger.newEntry()
entry.Debugf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Infof(format string, args ...interface{}) {
if logger.Level >= InfoLevel {
NewEntry(logger).Infof(format, args...)
entry := logger.newEntry()
entry.Infof(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Printf(format string, args ...interface{}) {
NewEntry(logger).Printf(format, args...)
entry := logger.newEntry()
entry.Printf(format, args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warnf(format string, args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnf(format, args...)
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warningf(format string, args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnf(format, args...)
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Errorf(format string, args ...interface{}) {
if logger.Level >= ErrorLevel {
NewEntry(logger).Errorf(format, args...)
entry := logger.newEntry()
entry.Errorf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatalf(format string, args ...interface{}) {
if logger.Level >= FatalLevel {
NewEntry(logger).Fatalf(format, args...)
entry := logger.newEntry()
entry.Fatalf(format, args...)
logger.releaseEntry(entry)
}
os.Exit(1)
Exit(1)
}
func (logger *Logger) Panicf(format string, args ...interface{}) {
if logger.Level >= PanicLevel {
NewEntry(logger).Panicf(format, args...)
entry := logger.newEntry()
entry.Panicf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Debug(args ...interface{}) {
if logger.Level >= DebugLevel {
NewEntry(logger).Debug(args...)
entry := logger.newEntry()
entry.Debug(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Info(args ...interface{}) {
if logger.Level >= InfoLevel {
NewEntry(logger).Info(args...)
entry := logger.newEntry()
entry.Info(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Print(args ...interface{}) {
NewEntry(logger).Info(args...)
entry := logger.newEntry()
entry.Info(args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warn(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warn(args...)
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warning(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warn(args...)
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Error(args ...interface{}) {
if logger.Level >= ErrorLevel {
NewEntry(logger).Error(args...)
entry := logger.newEntry()
entry.Error(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatal(args ...interface{}) {
if logger.Level >= FatalLevel {
NewEntry(logger).Fatal(args...)
entry := logger.newEntry()
entry.Fatal(args...)
logger.releaseEntry(entry)
}
os.Exit(1)
Exit(1)
}
func (logger *Logger) Panic(args ...interface{}) {
if logger.Level >= PanicLevel {
NewEntry(logger).Panic(args...)
entry := logger.newEntry()
entry.Panic(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Debugln(args ...interface{}) {
if logger.Level >= DebugLevel {
NewEntry(logger).Debugln(args...)
entry := logger.newEntry()
entry.Debugln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Infoln(args ...interface{}) {
if logger.Level >= InfoLevel {
NewEntry(logger).Infoln(args...)
entry := logger.newEntry()
entry.Infoln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Println(args ...interface{}) {
NewEntry(logger).Println(args...)
entry := logger.newEntry()
entry.Println(args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warnln(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnln(args...)
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warningln(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnln(args...)
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Errorln(args ...interface{}) {
if logger.Level >= ErrorLevel {
NewEntry(logger).Errorln(args...)
entry := logger.newEntry()
entry.Errorln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatalln(args ...interface{}) {
if logger.Level >= FatalLevel {
NewEntry(logger).Fatalln(args...)
entry := logger.newEntry()
entry.Fatalln(args...)
logger.releaseEntry(entry)
}
os.Exit(1)
Exit(1)
}
func (logger *Logger) Panicln(args ...interface{}) {
if logger.Level >= PanicLevel {
NewEntry(logger).Panicln(args...)
entry := logger.newEntry()
entry.Panicln(args...)
logger.releaseEntry(entry)
}
}
//When file is opened with appending mode, it's safe to
//write concurrently to a file (within 4k message on Linux).
//In these cases user can choose to disable the lock.
func (logger *Logger) SetNoLock() {
logger.mu.Disable()
}

View File

@ -0,0 +1,8 @@
// +build appengine
package logrus
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool {
return true
}

View File

@ -1,4 +1,5 @@
// +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package logrus

View File

@ -3,6 +3,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !appengine
package logrus
import "syscall"

View File

@ -4,6 +4,7 @@
// license that can be found in the LICENSE file.
// +build linux darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package logrus

View File

@ -1,4 +1,4 @@
// +build solaris
// +build solaris,!appengine
package logrus

View File

@ -3,7 +3,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// +build windows,!appengine
package logrus

View File

@ -57,6 +57,7 @@ type TextFormatter struct {
}
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var b *bytes.Buffer
var keys []string = make([]string, 0, len(entry.Data))
for k := range entry.Data {
keys = append(keys, k)
@ -65,8 +66,11 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
if !f.DisableSorting {
sort.Strings(keys)
}
b := &bytes.Buffer{}
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
prefixFieldClashes(entry.Data)
@ -118,7 +122,8 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
}
for _, k := range keys {
v := entry.Data[k]
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
f.appendValue(b, v)
}
}
@ -128,34 +133,36 @@ func needsQuoting(text string) bool {
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') ||
ch == '-' || ch == '.') {
return false
return true
}
}
return true
return false
}
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
b.WriteString(key)
b.WriteByte('=')
f.appendValue(b, value)
b.WriteByte(' ')
}
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
switch value := value.(type) {
case string:
if needsQuoting(value) {
if !needsQuoting(value) {
b.WriteString(value)
} else {
fmt.Fprintf(b, "%q", value)
}
case error:
errmsg := value.Error()
if needsQuoting(errmsg) {
if !needsQuoting(errmsg) {
b.WriteString(errmsg)
} else {
fmt.Fprintf(b, "%q", value)
fmt.Fprintf(b, "%q", errmsg)
}
default:
fmt.Fprint(b, value)
}
b.WriteByte(' ')
}

View File

@ -7,18 +7,40 @@ import (
)
func (logger *Logger) Writer() *io.PipeWriter {
return logger.WriterLevel(InfoLevel)
}
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
reader, writer := io.Pipe()
go logger.writerScanner(reader)
var printFunc func(args ...interface{})
switch level {
case DebugLevel:
printFunc = logger.Debug
case InfoLevel:
printFunc = logger.Info
case WarnLevel:
printFunc = logger.Warn
case ErrorLevel:
printFunc = logger.Error
case FatalLevel:
printFunc = logger.Fatal
case PanicLevel:
printFunc = logger.Panic
default:
printFunc = logger.Print
}
go logger.writerScanner(reader, printFunc)
runtime.SetFinalizer(writer, writerFinalizer)
return writer
}
func (logger *Logger) writerScanner(reader *io.PipeReader) {
func (logger *Logger) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
logger.Print(scanner.Text())
printFunc(scanner.Text())
}
if err := scanner.Err(); err != nil {
logger.Errorf("Error while reading from Writer: %s", err)

View File

@ -1,57 +0,0 @@
[![Build Status](https://travis-ci.org/cloudfoundry-incubator/candiedyaml.svg)](https://travis-ci.org/cloudfoundry-incubator/candiedyaml)
candiedyaml
===========
YAML for Go
A YAML 1.1 parser with support for YAML 1.2 features
Usage
-----
```go
package myApp
import (
"github.com/cloudfoundry-incubator/candiedyaml"
"fmt"
"os"
)
func main() {
file, err := os.Open("path/to/some/file.yml")
if err != nil {
println("File does not exist:", err.Error())
os.Exit(1)
}
defer file.Close()
document := new(interface{})
decoder := candiedyaml.NewDecoder(file)
err = decoder.Decode(document)
if err != nil {
println("Failed to decode document:", err.Error())
}
println("parsed yml into interface:", fmt.Sprintf("%#v", document))
fileToWrite, err := os.Create("path/to/some/new/file.yml")
if err != nil {
println("Failed to open file for writing:", err.Error())
os.Exit(1)
}
defer fileToWrite.Close()
encoder := candiedyaml.NewEncoder(fileToWrite)
err = encoder.Encode(document)
if err != nil {
println("Failed to encode document:", err.Error())
os.Exit(1)
}
return
}
```

View File

@ -1,834 +0,0 @@
/*
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 candiedyaml
import (
"io"
)
/*
* Create a new parser object.
*/
func yaml_parser_initialize(parser *yaml_parser_t) bool {
*parser = yaml_parser_t{
raw_buffer: make([]byte, 0, INPUT_RAW_BUFFER_SIZE),
buffer: make([]byte, 0, INPUT_BUFFER_SIZE),
}
return true
}
/*
* Destroy a parser object.
*/
func yaml_parser_delete(parser *yaml_parser_t) {
*parser = yaml_parser_t{}
}
/*
* String read handler.
*/
func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (int, error) {
if parser.input_pos == len(parser.input) {
return 0, io.EOF
}
n := copy(buffer, parser.input[parser.input_pos:])
parser.input_pos += n
return n, nil
}
/*
* File read handler.
*/
func yaml_file_read_handler(parser *yaml_parser_t, buffer []byte) (int, error) {
return parser.input_reader.Read(buffer)
}
/*
* Set a string input.
*/
func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
if parser.read_handler != nil {
panic("input already set")
}
parser.read_handler = yaml_string_read_handler
parser.input = input
parser.input_pos = 0
}
/*
* Set a reader input
*/
func yaml_parser_set_input_reader(parser *yaml_parser_t, reader io.Reader) {
if parser.read_handler != nil {
panic("input already set")
}
parser.read_handler = yaml_file_read_handler
parser.input_reader = reader
}
/*
* Set a generic input.
*/
func yaml_parser_set_input(parser *yaml_parser_t, handler yaml_read_handler_t) {
if parser.read_handler != nil {
panic("input already set")
}
parser.read_handler = handler
}
/*
* Set the source encoding.
*/
func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
if parser.encoding != yaml_ANY_ENCODING {
panic("encoding already set")
}
parser.encoding = encoding
}
/*
* Create a new emitter object.
*/
func yaml_emitter_initialize(emitter *yaml_emitter_t) {
*emitter = yaml_emitter_t{
buffer: make([]byte, OUTPUT_BUFFER_SIZE),
raw_buffer: make([]byte, 0, OUTPUT_RAW_BUFFER_SIZE),
states: make([]yaml_emitter_state_t, 0, INITIAL_STACK_SIZE),
events: make([]yaml_event_t, 0, INITIAL_QUEUE_SIZE),
}
}
func yaml_emitter_delete(emitter *yaml_emitter_t) {
*emitter = yaml_emitter_t{}
}
/*
* String write handler.
*/
func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
*emitter.output_buffer = append(*emitter.output_buffer, buffer...)
return nil
}
/*
* File write handler.
*/
func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
_, err := emitter.output_writer.Write(buffer)
return err
}
/*
* Set a string output.
*/
func yaml_emitter_set_output_string(emitter *yaml_emitter_t, buffer *[]byte) {
if emitter.write_handler != nil {
panic("output already set")
}
emitter.write_handler = yaml_string_write_handler
emitter.output_buffer = buffer
}
/*
* Set a file output.
*/
func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) {
if emitter.write_handler != nil {
panic("output already set")
}
emitter.write_handler = yaml_writer_write_handler
emitter.output_writer = w
}
/*
* Set a generic output handler.
*/
func yaml_emitter_set_output(emitter *yaml_emitter_t, handler yaml_write_handler_t) {
if emitter.write_handler != nil {
panic("output already set")
}
emitter.write_handler = handler
}
/*
* Set the output encoding.
*/
func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) {
if emitter.encoding != yaml_ANY_ENCODING {
panic("encoding already set")
}
emitter.encoding = encoding
}
/*
* Set the canonical output style.
*/
func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
emitter.canonical = canonical
}
/*
* Set the indentation increment.
*/
func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
if indent < 2 || indent > 9 {
indent = 2
}
emitter.best_indent = indent
}
/*
* Set the preferred line width.
*/
func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
if width < 0 {
width = -1
}
emitter.best_width = width
}
/*
* Set if unescaped non-ASCII characters are allowed.
*/
func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
emitter.unicode = unicode
}
/*
* Set the preferred line break character.
*/
func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
emitter.line_break = line_break
}
/*
* Destroy a token object.
*/
// yaml_DECLARE(void)
// yaml_token_delete(yaml_token_t *token)
// {
// assert(token); /* Non-NULL token object expected. */
//
// switch (token.type)
// {
// case yaml_TAG_DIRECTIVE_TOKEN:
// yaml_free(token.data.tag_directive.handle);
// yaml_free(token.data.tag_directive.prefix);
// break;
//
// case yaml_ALIAS_TOKEN:
// yaml_free(token.data.alias.value);
// break;
//
// case yaml_ANCHOR_TOKEN:
// yaml_free(token.data.anchor.value);
// break;
//
// case yaml_TAG_TOKEN:
// yaml_free(token.data.tag.handle);
// yaml_free(token.data.tag.suffix);
// break;
//
// case yaml_SCALAR_TOKEN:
// yaml_free(token.data.scalar.value);
// break;
//
// default:
// break;
// }
//
// memset(token, 0, sizeof(yaml_token_t));
// }
/*
* Check if a string is a valid UTF-8 sequence.
*
* Check 'reader.c' for more details on UTF-8 encoding.
*/
// static int
// yaml_check_utf8(yaml_char_t *start, size_t length)
// {
// yaml_char_t *end = start+length;
// yaml_char_t *pointer = start;
//
// while (pointer < end) {
// unsigned char octet;
// unsigned int width;
// unsigned int value;
// size_t k;
//
// octet = pointer[0];
// width = (octet & 0x80) == 0x00 ? 1 :
// (octet & 0xE0) == 0xC0 ? 2 :
// (octet & 0xF0) == 0xE0 ? 3 :
// (octet & 0xF8) == 0xF0 ? 4 : 0;
// value = (octet & 0x80) == 0x00 ? octet & 0x7F :
// (octet & 0xE0) == 0xC0 ? octet & 0x1F :
// (octet & 0xF0) == 0xE0 ? octet & 0x0F :
// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
// if (!width) return 0;
// if (pointer+width > end) return 0;
// for (k = 1; k < width; k ++) {
// octet = pointer[k];
// if ((octet & 0xC0) != 0x80) return 0;
// value = (value << 6) + (octet & 0x3F);
// }
// if (!((width == 1) ||
// (width == 2 && value >= 0x80) ||
// (width == 3 && value >= 0x800) ||
// (width == 4 && value >= 0x10000))) return 0;
//
// pointer += width;
// }
//
// return 1;
// }
/*
* Create STREAM-START.
*/
func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) {
*event = yaml_event_t{
event_type: yaml_STREAM_START_EVENT,
encoding: encoding,
}
}
/*
* Create STREAM-END.
*/
func yaml_stream_end_event_initialize(event *yaml_event_t) {
*event = yaml_event_t{
event_type: yaml_STREAM_END_EVENT,
}
}
/*
* Create DOCUMENT-START.
*/
func yaml_document_start_event_initialize(event *yaml_event_t,
version_directive *yaml_version_directive_t,
tag_directives []yaml_tag_directive_t,
implicit bool) {
*event = yaml_event_t{
event_type: yaml_DOCUMENT_START_EVENT,
version_directive: version_directive,
tag_directives: tag_directives,
implicit: implicit,
}
}
/*
* Create DOCUMENT-END.
*/
func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) {
*event = yaml_event_t{
event_type: yaml_DOCUMENT_END_EVENT,
implicit: implicit,
}
}
/*
* Create ALIAS.
*/
func yaml_alias_event_initialize(event *yaml_event_t, anchor []byte) {
*event = yaml_event_t{
event_type: yaml_ALIAS_EVENT,
anchor: anchor,
}
}
/*
* Create SCALAR.
*/
func yaml_scalar_event_initialize(event *yaml_event_t,
anchor []byte, tag []byte,
value []byte,
plain_implicit bool, quoted_implicit bool,
style yaml_scalar_style_t) {
*event = yaml_event_t{
event_type: yaml_SCALAR_EVENT,
anchor: anchor,
tag: tag,
value: value,
implicit: plain_implicit,
quoted_implicit: quoted_implicit,
style: yaml_style_t(style),
}
}
/*
* Create SEQUENCE-START.
*/
func yaml_sequence_start_event_initialize(event *yaml_event_t,
anchor []byte, tag []byte, implicit bool, style yaml_sequence_style_t) {
*event = yaml_event_t{
event_type: yaml_SEQUENCE_START_EVENT,
anchor: anchor,
tag: tag,
implicit: implicit,
style: yaml_style_t(style),
}
}
/*
* Create SEQUENCE-END.
*/
func yaml_sequence_end_event_initialize(event *yaml_event_t) {
*event = yaml_event_t{
event_type: yaml_SEQUENCE_END_EVENT,
}
}
/*
* Create MAPPING-START.
*/
func yaml_mapping_start_event_initialize(event *yaml_event_t,
anchor []byte, tag []byte, implicit bool, style yaml_mapping_style_t) {
*event = yaml_event_t{
event_type: yaml_MAPPING_START_EVENT,
anchor: anchor,
tag: tag,
implicit: implicit,
style: yaml_style_t(style),
}
}
/*
* Create MAPPING-END.
*/
func yaml_mapping_end_event_initialize(event *yaml_event_t) {
*event = yaml_event_t{
event_type: yaml_MAPPING_END_EVENT,
}
}
/*
* Destroy an event object.
*/
func yaml_event_delete(event *yaml_event_t) {
*event = yaml_event_t{}
}
// /*
// * Create a document object.
// */
//
// func yaml_document_initialize(document *yaml_document_t,
// version_directive *yaml_version_directive_t,
// tag_directives []yaml_tag_directive_t,
// start_implicit, end_implicit bool) bool {
//
//
// {
// struct {
// YAML_error_type_t error;
// } context;
// struct {
// yaml_node_t *start;
// yaml_node_t *end;
// yaml_node_t *top;
// } nodes = { NULL, NULL, NULL };
// yaml_version_directive_t *version_directive_copy = NULL;
// struct {
// yaml_tag_directive_t *start;
// yaml_tag_directive_t *end;
// yaml_tag_directive_t *top;
// } tag_directives_copy = { NULL, NULL, NULL };
// yaml_tag_directive_t value = { NULL, NULL };
// YAML_mark_t mark = { 0, 0, 0 };
//
// assert(document); /* Non-NULL document object is expected. */
// assert((tag_directives_start && tag_directives_end) ||
// (tag_directives_start == tag_directives_end));
// /* Valid tag directives are expected. */
//
// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error;
//
// if (version_directive) {
// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
// if (!version_directive_copy) goto error;
// version_directive_copy.major = version_directive.major;
// version_directive_copy.minor = version_directive.minor;
// }
//
// if (tag_directives_start != tag_directives_end) {
// yaml_tag_directive_t *tag_directive;
// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
// goto error;
// for (tag_directive = tag_directives_start;
// tag_directive != tag_directives_end; tag_directive ++) {
// assert(tag_directive.handle);
// assert(tag_directive.prefix);
// if (!yaml_check_utf8(tag_directive.handle,
// strlen((char *)tag_directive.handle)))
// goto error;
// if (!yaml_check_utf8(tag_directive.prefix,
// strlen((char *)tag_directive.prefix)))
// goto error;
// value.handle = yaml_strdup(tag_directive.handle);
// value.prefix = yaml_strdup(tag_directive.prefix);
// if (!value.handle || !value.prefix) goto error;
// if (!PUSH(&context, tag_directives_copy, value))
// goto error;
// value.handle = NULL;
// value.prefix = NULL;
// }
// }
//
// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
// tag_directives_copy.start, tag_directives_copy.top,
// start_implicit, end_implicit, mark, mark);
//
// return 1;
//
// error:
// STACK_DEL(&context, nodes);
// yaml_free(version_directive_copy);
// while (!STACK_EMPTY(&context, tag_directives_copy)) {
// yaml_tag_directive_t value = POP(&context, tag_directives_copy);
// yaml_free(value.handle);
// yaml_free(value.prefix);
// }
// STACK_DEL(&context, tag_directives_copy);
// yaml_free(value.handle);
// yaml_free(value.prefix);
//
// return 0;
// }
//
// /*
// * Destroy a document object.
// */
//
// yaml_DECLARE(void)
// yaml_document_delete(document *yaml_document_t)
// {
// struct {
// YAML_error_type_t error;
// } context;
// yaml_tag_directive_t *tag_directive;
//
// context.error = yaml_NO_ERROR; /* Eliminate a compliler warning. */
//
// assert(document); /* Non-NULL document object is expected. */
//
// while (!STACK_EMPTY(&context, document.nodes)) {
// yaml_node_t node = POP(&context, document.nodes);
// yaml_free(node.tag);
// switch (node.type) {
// case yaml_SCALAR_NODE:
// yaml_free(node.data.scalar.value);
// break;
// case yaml_SEQUENCE_NODE:
// STACK_DEL(&context, node.data.sequence.items);
// break;
// case yaml_MAPPING_NODE:
// STACK_DEL(&context, node.data.mapping.pairs);
// break;
// default:
// assert(0); /* Should not happen. */
// }
// }
// STACK_DEL(&context, document.nodes);
//
// yaml_free(document.version_directive);
// for (tag_directive = document.tag_directives.start;
// tag_directive != document.tag_directives.end;
// tag_directive++) {
// yaml_free(tag_directive.handle);
// yaml_free(tag_directive.prefix);
// }
// yaml_free(document.tag_directives.start);
//
// memset(document, 0, sizeof(yaml_document_t));
// }
//
// /**
// * Get a document node.
// */
//
// yaml_DECLARE(yaml_node_t *)
// yaml_document_get_node(document *yaml_document_t, int index)
// {
// assert(document); /* Non-NULL document object is expected. */
//
// if (index > 0 && document.nodes.start + index <= document.nodes.top) {
// return document.nodes.start + index - 1;
// }
// return NULL;
// }
//
// /**
// * Get the root object.
// */
//
// yaml_DECLARE(yaml_node_t *)
// yaml_document_get_root_node(document *yaml_document_t)
// {
// assert(document); /* Non-NULL document object is expected. */
//
// if (document.nodes.top != document.nodes.start) {
// return document.nodes.start;
// }
// return NULL;
// }
//
// /*
// * Add a scalar node to a document.
// */
//
// yaml_DECLARE(int)
// yaml_document_add_scalar(document *yaml_document_t,
// yaml_char_t *tag, yaml_char_t *value, int length,
// yaml_scalar_style_t style)
// {
// struct {
// YAML_error_type_t error;
// } context;
// YAML_mark_t mark = { 0, 0, 0 };
// yaml_char_t *tag_copy = NULL;
// yaml_char_t *value_copy = NULL;
// yaml_node_t node;
//
// assert(document); /* Non-NULL document object is expected. */
// assert(value); /* Non-NULL value is expected. */
//
// if (!tag) {
// tag = (yaml_char_t *)yaml_DEFAULT_SCALAR_TAG;
// }
//
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
// tag_copy = yaml_strdup(tag);
// if (!tag_copy) goto error;
//
// if (length < 0) {
// length = strlen((char *)value);
// }
//
// if (!yaml_check_utf8(value, length)) goto error;
// value_copy = yaml_malloc(length+1);
// if (!value_copy) goto error;
// memcpy(value_copy, value, length);
// value_copy[length] = '\0';
//
// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark);
// if (!PUSH(&context, document.nodes, node)) goto error;
//
// return document.nodes.top - document.nodes.start;
//
// error:
// yaml_free(tag_copy);
// yaml_free(value_copy);
//
// return 0;
// }
//
// /*
// * Add a sequence node to a document.
// */
//
// yaml_DECLARE(int)
// yaml_document_add_sequence(document *yaml_document_t,
// yaml_char_t *tag, yaml_sequence_style_t style)
// {
// struct {
// YAML_error_type_t error;
// } context;
// YAML_mark_t mark = { 0, 0, 0 };
// yaml_char_t *tag_copy = NULL;
// struct {
// yaml_node_item_t *start;
// yaml_node_item_t *end;
// yaml_node_item_t *top;
// } items = { NULL, NULL, NULL };
// yaml_node_t node;
//
// assert(document); /* Non-NULL document object is expected. */
//
// if (!tag) {
// tag = (yaml_char_t *)yaml_DEFAULT_SEQUENCE_TAG;
// }
//
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
// tag_copy = yaml_strdup(tag);
// if (!tag_copy) goto error;
//
// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error;
//
// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
// style, mark, mark);
// if (!PUSH(&context, document.nodes, node)) goto error;
//
// return document.nodes.top - document.nodes.start;
//
// error:
// STACK_DEL(&context, items);
// yaml_free(tag_copy);
//
// return 0;
// }
//
// /*
// * Add a mapping node to a document.
// */
//
// yaml_DECLARE(int)
// yaml_document_add_mapping(document *yaml_document_t,
// yaml_char_t *tag, yaml_mapping_style_t style)
// {
// struct {
// YAML_error_type_t error;
// } context;
// YAML_mark_t mark = { 0, 0, 0 };
// yaml_char_t *tag_copy = NULL;
// struct {
// yaml_node_pair_t *start;
// yaml_node_pair_t *end;
// yaml_node_pair_t *top;
// } pairs = { NULL, NULL, NULL };
// yaml_node_t node;
//
// assert(document); /* Non-NULL document object is expected. */
//
// if (!tag) {
// tag = (yaml_char_t *)yaml_DEFAULT_MAPPING_TAG;
// }
//
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
// tag_copy = yaml_strdup(tag);
// if (!tag_copy) goto error;
//
// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error;
//
// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
// style, mark, mark);
// if (!PUSH(&context, document.nodes, node)) goto error;
//
// return document.nodes.top - document.nodes.start;
//
// error:
// STACK_DEL(&context, pairs);
// yaml_free(tag_copy);
//
// return 0;
// }
//
// /*
// * Append an item to a sequence node.
// */
//
// yaml_DECLARE(int)
// yaml_document_append_sequence_item(document *yaml_document_t,
// int sequence, int item)
// {
// struct {
// YAML_error_type_t error;
// } context;
//
// assert(document); /* Non-NULL document is required. */
// assert(sequence > 0
// && document.nodes.start + sequence <= document.nodes.top);
// /* Valid sequence id is required. */
// assert(document.nodes.start[sequence-1].type == yaml_SEQUENCE_NODE);
// /* A sequence node is required. */
// assert(item > 0 && document.nodes.start + item <= document.nodes.top);
// /* Valid item id is required. */
//
// if (!PUSH(&context,
// document.nodes.start[sequence-1].data.sequence.items, item))
// return 0;
//
// return 1;
// }
//
// /*
// * Append a pair of a key and a value to a mapping node.
// */
//
// yaml_DECLARE(int)
// yaml_document_append_mapping_pair(document *yaml_document_t,
// int mapping, int key, int value)
// {
// struct {
// YAML_error_type_t error;
// } context;
//
// yaml_node_pair_t pair;
//
// assert(document); /* Non-NULL document is required. */
// assert(mapping > 0
// && document.nodes.start + mapping <= document.nodes.top);
// /* Valid mapping id is required. */
// assert(document.nodes.start[mapping-1].type == yaml_MAPPING_NODE);
// /* A mapping node is required. */
// assert(key > 0 && document.nodes.start + key <= document.nodes.top);
// /* Valid key id is required. */
// assert(value > 0 && document.nodes.start + value <= document.nodes.top);
// /* Valid value id is required. */
//
// pair.key = key;
// pair.value = value;
//
// if (!PUSH(&context,
// document.nodes.start[mapping-1].data.mapping.pairs, pair))
// return 0;
//
// return 1;
// }
//

View File

@ -1,622 +0,0 @@
/*
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 candiedyaml
import (
"bytes"
"errors"
"fmt"
"io"
"reflect"
"runtime"
"strconv"
"strings"
)
type Unmarshaler interface {
UnmarshalYAML(tag string, value interface{}) error
}
// A Number represents a JSON number literal.
type Number string
// String returns the literal text of the number.
func (n Number) String() string { return string(n) }
// Float64 returns the number as a float64.
func (n Number) Float64() (float64, error) {
return strconv.ParseFloat(string(n), 64)
}
// Int64 returns the number as an int64.
func (n Number) Int64() (int64, error) {
return strconv.ParseInt(string(n), 10, 64)
}
type Decoder struct {
parser yaml_parser_t
event yaml_event_t
replay_events []yaml_event_t
useNumber bool
anchors map[string][]yaml_event_t
tracking_anchors [][]yaml_event_t
}
type ParserError struct {
ErrorType YAML_error_type_t
Context string
ContextMark YAML_mark_t
Problem string
ProblemMark YAML_mark_t
}
func (e *ParserError) Error() string {
return fmt.Sprintf("yaml: [%s] %s at line %d, column %d", e.Context, e.Problem, e.ProblemMark.line+1, e.ProblemMark.column+1)
}
type UnexpectedEventError struct {
Value string
EventType yaml_event_type_t
At YAML_mark_t
}
func (e *UnexpectedEventError) Error() string {
return fmt.Sprintf("yaml: Unexpect event [%d]: '%s' at line %d, column %d", e.EventType, e.Value, e.At.line+1, e.At.column+1)
}
func recovery(err *error) {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
var tmpError error
switch r := r.(type) {
case error:
tmpError = r
case string:
tmpError = errors.New(r)
default:
tmpError = errors.New("Unknown panic: " + reflect.ValueOf(r).String())
}
*err = tmpError
}
}
func Unmarshal(data []byte, v interface{}) error {
d := NewDecoder(bytes.NewBuffer(data))
return d.Decode(v)
}
func NewDecoder(r io.Reader) *Decoder {
d := &Decoder{
anchors: make(map[string][]yaml_event_t),
tracking_anchors: make([][]yaml_event_t, 1),
}
yaml_parser_initialize(&d.parser)
yaml_parser_set_input_reader(&d.parser, r)
return d
}
func (d *Decoder) Decode(v interface{}) (err error) {
defer recovery(&err)
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
return fmt.Errorf("Expected a pointer or nil but was a %s at %s", rv.String(), d.event.start_mark)
}
if d.event.event_type == yaml_NO_EVENT {
d.nextEvent()
if d.event.event_type != yaml_STREAM_START_EVENT {
return errors.New("Invalid stream")
}
d.nextEvent()
}
d.document(rv)
return nil
}
func (d *Decoder) UseNumber() { d.useNumber = true }
func (d *Decoder) error(err error) {
panic(err)
}
func (d *Decoder) nextEvent() {
if d.event.event_type == yaml_STREAM_END_EVENT {
d.error(errors.New("The stream is closed"))
}
if d.replay_events != nil {
d.event = d.replay_events[0]
if len(d.replay_events) == 1 {
d.replay_events = nil
} else {
d.replay_events = d.replay_events[1:]
}
} else {
if !yaml_parser_parse(&d.parser, &d.event) {
yaml_event_delete(&d.event)
d.error(&ParserError{
ErrorType: d.parser.error,
Context: d.parser.context,
ContextMark: d.parser.context_mark,
Problem: d.parser.problem,
ProblemMark: d.parser.problem_mark,
})
}
}
last := len(d.tracking_anchors)
// skip aliases when tracking an anchor
if last > 0 && d.event.event_type != yaml_ALIAS_EVENT {
d.tracking_anchors[last-1] = append(d.tracking_anchors[last-1], d.event)
}
}
func (d *Decoder) document(rv reflect.Value) {
if d.event.event_type != yaml_DOCUMENT_START_EVENT {
d.error(fmt.Errorf("Expected document start at %s", d.event.start_mark))
}
d.nextEvent()
d.parse(rv)
if d.event.event_type != yaml_DOCUMENT_END_EVENT {
d.error(fmt.Errorf("Expected document end at %s", d.event.start_mark))
}
d.nextEvent()
}
func (d *Decoder) parse(rv reflect.Value) {
if !rv.IsValid() {
// skip ahead since we cannot store
d.valueInterface()
return
}
anchor := string(d.event.anchor)
switch d.event.event_type {
case yaml_SEQUENCE_START_EVENT:
d.begin_anchor(anchor)
d.sequence(rv)
d.end_anchor(anchor)
case yaml_MAPPING_START_EVENT:
d.begin_anchor(anchor)
d.mapping(rv)
d.end_anchor(anchor)
case yaml_SCALAR_EVENT:
d.begin_anchor(anchor)
d.scalar(rv)
d.end_anchor(anchor)
case yaml_ALIAS_EVENT:
d.alias(rv)
case yaml_DOCUMENT_END_EVENT:
default:
d.error(&UnexpectedEventError{
Value: string(d.event.value),
EventType: d.event.event_type,
At: d.event.start_mark,
})
}
}
func (d *Decoder) begin_anchor(anchor string) {
if anchor != "" {
events := []yaml_event_t{d.event}
d.tracking_anchors = append(d.tracking_anchors, events)
}
}
func (d *Decoder) end_anchor(anchor string) {
if anchor != "" {
events := d.tracking_anchors[len(d.tracking_anchors)-1]
d.tracking_anchors = d.tracking_anchors[0 : len(d.tracking_anchors)-1]
// remove the anchor, replaying events shouldn't have anchors
events[0].anchor = nil
// we went one too many, remove the extra event
events = events[:len(events)-1]
// if nested, append to all the other anchors
for i, e := range d.tracking_anchors {
d.tracking_anchors[i] = append(e, events...)
}
d.anchors[anchor] = events
}
}
func (d *Decoder) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, reflect.Value) {
// If v is a named type and is addressable,
// start with its address, so that if the type has pointer methods,
// we find them.
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
v = v.Addr()
}
for {
// Load value from interface, but only if the result will be
// usefully addressable.
if v.Kind() == reflect.Interface && !v.IsNil() {
e := v.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
v = e
continue
}
}
if v.Kind() != reflect.Ptr {
break
}
if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() {
break
}
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
if v.Type().NumMethod() > 0 {
if u, ok := v.Interface().(Unmarshaler); ok {
var temp interface{}
return u, reflect.ValueOf(&temp)
}
}
v = v.Elem()
}
return nil, v
}
func (d *Decoder) sequence(v reflect.Value) {
if d.event.event_type != yaml_SEQUENCE_START_EVENT {
d.error(fmt.Errorf("Expected sequence start at %s", d.event.start_mark))
}
u, pv := d.indirect(v, false)
if u != nil {
defer func() {
if err := u.UnmarshalYAML(yaml_SEQ_TAG, pv.Interface()); err != nil {
d.error(err)
}
}()
_, pv = d.indirect(pv, false)
}
v = pv
// Check type of target.
switch v.Kind() {
case reflect.Interface:
if v.NumMethod() == 0 {
// Decoding into nil interface? Switch to non-reflect code.
v.Set(reflect.ValueOf(d.sequenceInterface()))
return
}
// Otherwise it's invalid.
fallthrough
default:
d.error(fmt.Errorf("Expected an array, slice or interface{} but was a %s at %s", v, d.event.start_mark))
case reflect.Array:
case reflect.Slice:
break
}
d.nextEvent()
i := 0
done:
for {
switch d.event.event_type {
case yaml_SEQUENCE_END_EVENT, yaml_DOCUMENT_END_EVENT:
break done
}
// Get element of array, growing if necessary.
if v.Kind() == reflect.Slice {
// Grow slice if necessary
if i >= v.Cap() {
newcap := v.Cap() + v.Cap()/2
if newcap < 4 {
newcap = 4
}
newv := reflect.MakeSlice(v.Type(), v.Len(), newcap)
reflect.Copy(newv, v)
v.Set(newv)
}
if i >= v.Len() {
v.SetLen(i + 1)
}
}
if i < v.Len() {
// Decode into element.
d.parse(v.Index(i))
} else {
// Ran out of fixed array: skip.
d.parse(reflect.Value{})
}
i++
}
if i < v.Len() {
if v.Kind() == reflect.Array {
// Array. Zero the rest.
z := reflect.Zero(v.Type().Elem())
for ; i < v.Len(); i++ {
v.Index(i).Set(z)
}
} else {
v.SetLen(i)
}
}
if i == 0 && v.Kind() == reflect.Slice {
v.Set(reflect.MakeSlice(v.Type(), 0, 0))
}
if d.event.event_type != yaml_DOCUMENT_END_EVENT {
d.nextEvent()
}
}
func (d *Decoder) mapping(v reflect.Value) {
u, pv := d.indirect(v, false)
if u != nil {
defer func() {
if err := u.UnmarshalYAML(yaml_MAP_TAG, pv.Interface()); err != nil {
d.error(err)
}
}()
_, pv = d.indirect(pv, false)
}
v = pv
// Decoding into nil interface? Switch to non-reflect code.
if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
v.Set(reflect.ValueOf(d.mappingInterface()))
return
}
// Check type of target: struct or map[X]Y
switch v.Kind() {
case reflect.Struct:
d.mappingStruct(v)
return
case reflect.Map:
default:
d.error(fmt.Errorf("Expected a struct or map but was a %s at %s ", v, d.event.start_mark))
}
mapt := v.Type()
if v.IsNil() {
v.Set(reflect.MakeMap(mapt))
}
d.nextEvent()
keyt := mapt.Key()
mapElemt := mapt.Elem()
var mapElem reflect.Value
done:
for {
switch d.event.event_type {
case yaml_MAPPING_END_EVENT:
break done
case yaml_DOCUMENT_END_EVENT:
return
}
key := reflect.New(keyt)
d.parse(key.Elem())
if !mapElem.IsValid() {
mapElem = reflect.New(mapElemt).Elem()
} else {
mapElem.Set(reflect.Zero(mapElemt))
}
d.parse(mapElem)
v.SetMapIndex(key.Elem(), mapElem)
}
d.nextEvent()
}
func (d *Decoder) mappingStruct(v reflect.Value) {
structt := v.Type()
fields := cachedTypeFields(structt)
d.nextEvent()
done:
for {
switch d.event.event_type {
case yaml_MAPPING_END_EVENT:
break done
case yaml_DOCUMENT_END_EVENT:
return
}
key := ""
d.parse(reflect.ValueOf(&key))
// Figure out field corresponding to key.
var subv reflect.Value
var f *field
for i := range fields {
ff := &fields[i]
if ff.name == key {
f = ff
break
}
if f == nil && strings.EqualFold(ff.name, key) {
f = ff
}
}
if f != nil {
subv = v
for _, i := range f.index {
if subv.Kind() == reflect.Ptr {
if subv.IsNil() {
subv.Set(reflect.New(subv.Type().Elem()))
}
subv = subv.Elem()
}
subv = subv.Field(i)
}
}
d.parse(subv)
}
d.nextEvent()
}
func (d *Decoder) scalar(v reflect.Value) {
val := string(d.event.value)
wantptr := null_values[val]
u, pv := d.indirect(v, wantptr)
var tag string
if u != nil {
defer func() {
if err := u.UnmarshalYAML(tag, pv.Interface()); err != nil {
d.error(err)
}
}()
_, pv = d.indirect(pv, wantptr)
}
v = pv
var err error
tag, err = resolve(d.event, v, d.useNumber)
if err != nil {
d.error(err)
}
d.nextEvent()
}
func (d *Decoder) alias(rv reflect.Value) {
val, ok := d.anchors[string(d.event.anchor)]
if !ok {
d.error(fmt.Errorf("missing anchor: '%s' at %s", d.event.anchor, d.event.start_mark))
}
d.replay_events = val
d.nextEvent()
d.parse(rv)
}
func (d *Decoder) valueInterface() interface{} {
var v interface{}
anchor := string(d.event.anchor)
switch d.event.event_type {
case yaml_SEQUENCE_START_EVENT:
d.begin_anchor(anchor)
v = d.sequenceInterface()
case yaml_MAPPING_START_EVENT:
d.begin_anchor(anchor)
v = d.mappingInterface()
case yaml_SCALAR_EVENT:
d.begin_anchor(anchor)
v = d.scalarInterface()
case yaml_ALIAS_EVENT:
rv := reflect.ValueOf(&v)
d.alias(rv)
return v
case yaml_DOCUMENT_END_EVENT:
d.error(&UnexpectedEventError{
Value: string(d.event.value),
EventType: d.event.event_type,
At: d.event.start_mark,
})
}
d.end_anchor(anchor)
return v
}
func (d *Decoder) scalarInterface() interface{} {
_, v := resolveInterface(d.event, d.useNumber)
d.nextEvent()
return v
}
// sequenceInterface is like sequence but returns []interface{}.
func (d *Decoder) sequenceInterface() []interface{} {
var v = make([]interface{}, 0)
d.nextEvent()
done:
for {
switch d.event.event_type {
case yaml_SEQUENCE_END_EVENT, yaml_DOCUMENT_END_EVENT:
break done
}
v = append(v, d.valueInterface())
}
if d.event.event_type != yaml_DOCUMENT_END_EVENT {
d.nextEvent()
}
return v
}
// mappingInterface is like mapping but returns map[interface{}]interface{}.
func (d *Decoder) mappingInterface() map[interface{}]interface{} {
m := make(map[interface{}]interface{})
d.nextEvent()
done:
for {
switch d.event.event_type {
case yaml_MAPPING_END_EVENT, yaml_DOCUMENT_END_EVENT:
break done
}
key := d.valueInterface()
// Read value.
m[key] = d.valueInterface()
}
if d.event.event_type != yaml_DOCUMENT_END_EVENT {
d.nextEvent()
}
return m
}

View File

@ -1,2072 +0,0 @@
/*
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 candiedyaml
import (
"bytes"
)
var default_tag_directives = []yaml_tag_directive_t{
{[]byte("!"), []byte("!")},
{[]byte("!!"), []byte("tag:yaml.org,2002:")},
}
/*
* Flush the buffer if needed.
*/
func flush(emitter *yaml_emitter_t) bool {
if emitter.buffer_pos+5 >= len(emitter.buffer) {
return yaml_emitter_flush(emitter)
}
return true
}
/*
* Put a character to the output buffer.
*/
func put(emitter *yaml_emitter_t, value byte) bool {
if !flush(emitter) {
return false
}
emitter.buffer[emitter.buffer_pos] = value
emitter.buffer_pos++
emitter.column++
return true
}
/*
* Put a line break to the output buffer.
*/
func put_break(emitter *yaml_emitter_t) bool {
if !flush(emitter) {
return false
}
switch emitter.line_break {
case yaml_CR_BREAK:
emitter.buffer[emitter.buffer_pos] = '\r'
emitter.buffer_pos++
case yaml_LN_BREAK:
emitter.buffer[emitter.buffer_pos] = '\n'
emitter.buffer_pos++
case yaml_CRLN_BREAK:
emitter.buffer[emitter.buffer_pos] = '\r'
emitter.buffer[emitter.buffer_pos] = '\n'
emitter.buffer_pos += 2
default:
return false
}
emitter.column = 0
emitter.line++
return true
}
/*
* Copy a character from a string into buffer.
*/
func write(emitter *yaml_emitter_t, src []byte, src_pos *int) bool {
if !flush(emitter) {
return false
}
copy_bytes(emitter.buffer, &emitter.buffer_pos, src, src_pos)
emitter.column++
return true
}
/*
* Copy a line break character from a string into buffer.
*/
func write_break(emitter *yaml_emitter_t, src []byte, src_pos *int) bool {
if src[*src_pos] == '\n' {
if !put_break(emitter) {
return false
}
*src_pos++
} else {
if !write(emitter, src, src_pos) {
return false
}
emitter.column = 0
emitter.line++
}
return true
}
/*
* Set an emitter error and return 0.
*/
func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool {
emitter.error = yaml_EMITTER_ERROR
emitter.problem = problem
return false
}
/*
* Emit an event.
*/
func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool {
emitter.events = append(emitter.events, *event)
for !yaml_emitter_need_more_events(emitter) {
event := &emitter.events[emitter.events_head]
if !yaml_emitter_analyze_event(emitter, event) {
return false
}
if !yaml_emitter_state_machine(emitter, event) {
return false
}
yaml_event_delete(event)
emitter.events_head++
}
return true
}
/*
* Check if we need to accumulate more events before emitting.
*
* We accumulate extra
* - 1 event for DOCUMENT-START
* - 2 events for SEQUENCE-START
* - 3 events for MAPPING-START
*/
func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool {
if emitter.events_head == len(emitter.events) {
return true
}
accumulate := 0
switch emitter.events[emitter.events_head].event_type {
case yaml_DOCUMENT_START_EVENT:
accumulate = 1
case yaml_SEQUENCE_START_EVENT:
accumulate = 2
case yaml_MAPPING_START_EVENT:
accumulate = 3
default:
return false
}
if len(emitter.events)-emitter.events_head > accumulate {
return false
}
level := 0
for i := emitter.events_head; i < len(emitter.events); i++ {
switch emitter.events[i].event_type {
case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT:
level++
case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT:
level--
}
if level == 0 {
return false
}
}
return true
}
/*
* Append a directive to the directives stack.
*/
func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t,
value *yaml_tag_directive_t, allow_duplicates bool) bool {
for i := range emitter.tag_directives {
if bytes.Equal(value.handle, emitter.tag_directives[i].handle) {
if allow_duplicates {
return true
}
return yaml_emitter_set_emitter_error(emitter, "duplicat %TAG directive")
}
}
tag_copy := yaml_tag_directive_t{
handle: value.handle,
prefix: value.prefix,
}
emitter.tag_directives = append(emitter.tag_directives, tag_copy)
return true
}
/*
* Increase the indentation level.
*/
func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow bool, indentless bool) bool {
emitter.indents = append(emitter.indents, emitter.indent)
if emitter.indent < 0 {
if flow {
emitter.indent = emitter.best_indent
} else {
emitter.indent = 0
}
} else if !indentless {
emitter.indent += emitter.best_indent
}
return true
}
/*
* State dispatcher.
*/
func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool {
switch emitter.state {
case yaml_EMIT_STREAM_START_STATE:
return yaml_emitter_emit_stream_start(emitter, event)
case yaml_EMIT_FIRST_DOCUMENT_START_STATE:
return yaml_emitter_emit_document_start(emitter, event, true)
case yaml_EMIT_DOCUMENT_START_STATE:
return yaml_emitter_emit_document_start(emitter, event, false)
case yaml_EMIT_DOCUMENT_CONTENT_STATE:
return yaml_emitter_emit_document_content(emitter, event)
case yaml_EMIT_DOCUMENT_END_STATE:
return yaml_emitter_emit_document_end(emitter, event)
case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE:
return yaml_emitter_emit_flow_sequence_item(emitter, event, true)
case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE:
return yaml_emitter_emit_flow_sequence_item(emitter, event, false)
case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE:
return yaml_emitter_emit_flow_mapping_key(emitter, event, true)
case yaml_EMIT_FLOW_MAPPING_KEY_STATE:
return yaml_emitter_emit_flow_mapping_key(emitter, event, false)
case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE:
return yaml_emitter_emit_flow_mapping_value(emitter, event, true)
case yaml_EMIT_FLOW_MAPPING_VALUE_STATE:
return yaml_emitter_emit_flow_mapping_value(emitter, event, false)
case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE:
return yaml_emitter_emit_block_sequence_item(emitter, event, true)
case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE:
return yaml_emitter_emit_block_sequence_item(emitter, event, false)
case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE:
return yaml_emitter_emit_block_mapping_key(emitter, event, true)
case yaml_EMIT_BLOCK_MAPPING_KEY_STATE:
return yaml_emitter_emit_block_mapping_key(emitter, event, false)
case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE:
return yaml_emitter_emit_block_mapping_value(emitter, event, true)
case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE:
return yaml_emitter_emit_block_mapping_value(emitter, event, false)
case yaml_EMIT_END_STATE:
return yaml_emitter_set_emitter_error(emitter,
"expected nothing after STREAM-END")
}
panic("invalid state")
}
/*
* Expect STREAM-START.
*/
func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
if event.event_type != yaml_STREAM_START_EVENT {
return yaml_emitter_set_emitter_error(emitter,
"expected STREAM-START")
}
if emitter.encoding == yaml_ANY_ENCODING {
emitter.encoding = event.encoding
if emitter.encoding == yaml_ANY_ENCODING {
emitter.encoding = yaml_UTF8_ENCODING
}
}
if emitter.best_indent < 2 || emitter.best_indent > 9 {
emitter.best_indent = 2
}
if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 {
emitter.best_width = 80
}
if emitter.best_width < 0 {
emitter.best_width = 1<<31 - 1
}
if emitter.line_break == yaml_ANY_BREAK {
emitter.line_break = yaml_LN_BREAK
}
emitter.indent = -1
emitter.line = 0
emitter.column = 0
emitter.whitespace = true
emitter.indention = true
if emitter.encoding != yaml_UTF8_ENCODING {
if !yaml_emitter_write_bom(emitter) {
return false
}
}
emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE
return true
}
/*
* Expect DOCUMENT-START or STREAM-END.
*/
func yaml_emitter_emit_document_start(emitter *yaml_emitter_t,
event *yaml_event_t, first bool) bool {
if event.event_type == yaml_DOCUMENT_START_EVENT {
if event.version_directive != nil {
if !yaml_emitter_analyze_version_directive(emitter,
*event.version_directive) {
return false
}
}
for i := range event.tag_directives {
tag_directive := &event.tag_directives[i]
if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) {
return false
}
if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) {
return false
}
}
for i := range default_tag_directives {
if !yaml_emitter_append_tag_directive(emitter, &default_tag_directives[i], true) {
return false
}
}
implicit := event.implicit
if !first || emitter.canonical {
implicit = false
}
if (event.version_directive != nil || len(event.tag_directives) > 0) &&
emitter.open_ended {
if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
return false
}
if !yaml_emitter_write_indent(emitter) {
return false
}
}
if event.version_directive != nil {
implicit = false
if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) {
return false
}
if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) {
return false
}
if !yaml_emitter_write_indent(emitter) {
return false
}
}
if len(event.tag_directives) > 0 {
implicit = false
for i := range event.tag_directives {
tag_directive := &event.tag_directives[i]
if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) {
return false
}
if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) {
return false
}
if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) {
return false
}
if !yaml_emitter_write_indent(emitter) {
return false
}
}
}
if yaml_emitter_check_empty_document(emitter) {
implicit = false
}
if !implicit {
if !yaml_emitter_write_indent(emitter) {
return false
}
if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) {
return false
}
if emitter.canonical {
if !yaml_emitter_write_indent(emitter) {
return false
}
}
}
emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE
return true
} else if event.event_type == yaml_STREAM_END_EVENT {
if emitter.open_ended {
if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
return false
}
if !yaml_emitter_write_indent(emitter) {
return false
}
}
if !yaml_emitter_flush(emitter) {
return false
}
emitter.state = yaml_EMIT_END_STATE
return true
}
return yaml_emitter_set_emitter_error(emitter,
"expected DOCUMENT-START or STREAM-END")
}
/*
* Expect the root node.
*/
func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool {
emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE)
return yaml_emitter_emit_node(emitter, event, true, false, false, false)
}
/*
* Expect DOCUMENT-END.
*/
func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool {
if event.event_type != yaml_DOCUMENT_END_EVENT {
return yaml_emitter_set_emitter_error(emitter,
"expected DOCUMENT-END")
}
if !yaml_emitter_write_indent(emitter) {
return false
}
if !event.implicit {
if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
return false
}
if !yaml_emitter_write_indent(emitter) {
return false
}
}
if !yaml_emitter_flush(emitter) {
return false
}
emitter.state = yaml_EMIT_DOCUMENT_START_STATE
emitter.tag_directives = emitter.tag_directives[:0]
return true
}
/*
*
* Expect a flow item node.
*/
func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
if first {
if !yaml_emitter_write_indicator(emitter, []byte("["), true, true, false) {
return false
}
if !yaml_emitter_increase_indent(emitter, true, false) {
return false
}
emitter.flow_level++
}
if event.event_type == yaml_SEQUENCE_END_EVENT {
emitter.flow_level--
emitter.indent = emitter.indents[len(emitter.indents)-1]
emitter.indents = emitter.indents[:len(emitter.indents)-1]
if emitter.canonical && !first {
if !yaml_emitter_write_indicator(emitter, []byte(","), false, false, false) {
return false
}
if !yaml_emitter_write_indent(emitter) {
return false
}
}
if !yaml_emitter_write_indicator(emitter, []byte("]"), false, false, false) {
return false
}
emitter.state = emitter.states[len(emitter.states)-1]
emitter.states = emitter.states[:len(emitter.states)-1]
return true
}
if !first {
if !yaml_emitter_write_indicator(emitter, []byte(","), false, false, false) {
return false
}
}
if emitter.canonical || emitter.column > emitter.best_width {
if !yaml_emitter_write_indent(emitter) {
return false
}
}
emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE)
return yaml_emitter_emit_node(emitter, event, false, true, false, false)
}
/*
* Expect a flow key node.
*/
func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t,
event *yaml_event_t, first bool) bool {
if first {
if !yaml_emitter_write_indicator(emitter, []byte("{"), true, true, false) {
return false
}
if !yaml_emitter_increase_indent(emitter, true, false) {
return false
}
emitter.flow_level++
}
if event.event_type == yaml_MAPPING_END_EVENT {
emitter.flow_level--
emitter.indent = emitter.indents[len(emitter.indents)-1]
emitter.indents = emitter.indents[:len(emitter.indents)-1]
if emitter.canonical && !first {
if !yaml_emitter_write_indicator(emitter, []byte(","), false, false, false) {
return false
}
if !yaml_emitter_write_indent(emitter) {
return false
}
}
if !yaml_emitter_write_indicator(emitter, []byte("}"), false, false, false) {
return false
}
emitter.state = emitter.states[len(emitter.states)-1]
emitter.states = emitter.states[:len(emitter.states)-1]
return true
}
if !first {
if !yaml_emitter_write_indicator(emitter, []byte(","), false, false, false) {
return false
}
}
if emitter.canonical || emitter.column > emitter.best_width {
if !yaml_emitter_write_indent(emitter) {
return false
}
}
if !emitter.canonical && yaml_emitter_check_simple_key(emitter) {
emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)
return yaml_emitter_emit_node(emitter, event, false, false, true, true)
} else {
if !yaml_emitter_write_indicator(emitter, []byte("?"), true, false, false) {
return false
}
emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE)
return yaml_emitter_emit_node(emitter, event, false, false, true, false)
}
}
/*
* Expect a flow value node.
*/
func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t,
event *yaml_event_t, simple bool) bool {
if simple {
if !yaml_emitter_write_indicator(emitter, []byte(":"), false, false, false) {
return false
}
} else {
if emitter.canonical || emitter.column > emitter.best_width {
if !yaml_emitter_write_indent(emitter) {
return false
}
}
if !yaml_emitter_write_indicator(emitter, []byte(":"), true, false, false) {
return false
}
}
emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE)
return yaml_emitter_emit_node(emitter, event, false, false, true, false)
}
/*
* Expect a block item node.
*/
func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t,
event *yaml_event_t, first bool) bool {
if first {
if !yaml_emitter_increase_indent(emitter, false,
(emitter.mapping_context && !emitter.indention)) {
return false
}
}
if event.event_type == yaml_SEQUENCE_END_EVENT {
emitter.indent = emitter.indents[len(emitter.indents)-1]
emitter.indents = emitter.indents[:len(emitter.indents)-1]
emitter.state = emitter.states[len(emitter.states)-1]
emitter.states = emitter.states[:len(emitter.states)-1]
return true
}
if !yaml_emitter_write_indent(emitter) {
return false
}
if !yaml_emitter_write_indicator(emitter, []byte("-"), true, false, true) {
return false
}
emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE)
return yaml_emitter_emit_node(emitter, event, false, true, false, false)
}
/*
* Expect a block key node.
*/
func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t,
event *yaml_event_t, first bool) bool {
if first {
if !yaml_emitter_increase_indent(emitter, false, false) {
return false
}
}
if event.event_type == yaml_MAPPING_END_EVENT {
emitter.indent = emitter.indents[len(emitter.indents)-1]
emitter.indents = emitter.indents[:len(emitter.indents)-1]
emitter.state = emitter.states[len(emitter.states)-1]
emitter.states = emitter.states[:len(emitter.states)-1]
return true
}
if !yaml_emitter_write_indent(emitter) {
return false
}
if yaml_emitter_check_simple_key(emitter) {
emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)
return yaml_emitter_emit_node(emitter, event, false, false, true, true)
} else {
if !yaml_emitter_write_indicator(emitter, []byte("?"), true, false, true) {
return false
}
emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE)
return yaml_emitter_emit_node(emitter, event, false, false, true, false)
}
}
/*
* Expect a block value node.
*/
func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t,
event *yaml_event_t, simple bool) bool {
if simple {
if !yaml_emitter_write_indicator(emitter, []byte(":"), false, false, false) {
return false
}
} else {
if !yaml_emitter_write_indent(emitter) {
return false
}
if !yaml_emitter_write_indicator(emitter, []byte(":"), true, false, true) {
return false
}
}
emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE)
return yaml_emitter_emit_node(emitter, event, false, false, true, false)
}
/*
* Expect a node.
*/
func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
root bool, sequence bool, mapping bool, simple_key bool) bool {
emitter.root_context = root
emitter.sequence_context = sequence
emitter.mapping_context = mapping
emitter.simple_key_context = simple_key
switch event.event_type {
case yaml_ALIAS_EVENT:
return yaml_emitter_emit_alias(emitter, event)
case yaml_SCALAR_EVENT:
return yaml_emitter_emit_scalar(emitter, event)
case yaml_SEQUENCE_START_EVENT:
return yaml_emitter_emit_sequence_start(emitter, event)
case yaml_MAPPING_START_EVENT:
return yaml_emitter_emit_mapping_start(emitter, event)
default:
return yaml_emitter_set_emitter_error(emitter,
"expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS")
}
return false
}
/*
* Expect ALIAS.
*/
func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool {
if !yaml_emitter_process_anchor(emitter) {
return false
}
emitter.state = emitter.states[len(emitter.states)-1]
emitter.states = emitter.states[:len(emitter.states)-1]
return true
}
/*
* Expect SCALAR.
*/
func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool {
if !yaml_emitter_select_scalar_style(emitter, event) {
return false
}
if !yaml_emitter_process_anchor(emitter) {
return false
}
if !yaml_emitter_process_tag(emitter) {
return false
}
if !yaml_emitter_increase_indent(emitter, true, false) {
return false
}
if !yaml_emitter_process_scalar(emitter) {
return false
}
emitter.indent = emitter.indents[len(emitter.indents)-1]
emitter.indents = emitter.indents[:len(emitter.indents)-1]
emitter.state = emitter.states[len(emitter.states)-1]
emitter.states = emitter.states[:len(emitter.states)-1]
return true
}
/*
* Expect SEQUENCE-START.
*/
func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
if !yaml_emitter_process_anchor(emitter) {
return false
}
if !yaml_emitter_process_tag(emitter) {
return false
}
if emitter.flow_level > 0 || emitter.canonical ||
event.style == yaml_style_t(yaml_FLOW_SEQUENCE_STYLE) ||
yaml_emitter_check_empty_sequence(emitter) {
emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE
} else {
emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE
}
return true
}
/*
* Expect MAPPING-START.
*/
func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
if !yaml_emitter_process_anchor(emitter) {
return false
}
if !yaml_emitter_process_tag(emitter) {
return false
}
if emitter.flow_level > 0 || emitter.canonical ||
event.style == yaml_style_t(yaml_FLOW_MAPPING_STYLE) ||
yaml_emitter_check_empty_mapping(emitter) {
emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE
} else {
emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE
}
return true
}
/*
* Check if the document content is an empty scalar.
*/
func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool {
return false
}
/*
* Check if the next events represent an empty sequence.
*/
func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool {
if len(emitter.events)-emitter.events_head < 2 {
return false
}
return (emitter.events[emitter.events_head].event_type == yaml_SEQUENCE_START_EVENT &&
emitter.events[emitter.events_head+1].event_type == yaml_SEQUENCE_END_EVENT)
}
/*
* Check if the next events represent an empty mapping.
*/
func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool {
if len(emitter.events)-emitter.events_head < 2 {
return false
}
return (emitter.events[emitter.events_head].event_type == yaml_MAPPING_START_EVENT &&
emitter.events[emitter.events_head+1].event_type == yaml_MAPPING_END_EVENT)
}
/*
* Check if the next node can be expressed as a simple key.
*/
func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool {
length := 0
switch emitter.events[emitter.events_head].event_type {
case yaml_ALIAS_EVENT:
length += len(emitter.anchor_data.anchor)
case yaml_SCALAR_EVENT:
if emitter.scalar_data.multiline {
return false
}
length += len(emitter.anchor_data.anchor) +
len(emitter.tag_data.handle) +
len(emitter.tag_data.suffix) +
len(emitter.scalar_data.value)
case yaml_SEQUENCE_START_EVENT:
if !yaml_emitter_check_empty_sequence(emitter) {
return false
}
length += len(emitter.anchor_data.anchor) +
len(emitter.tag_data.handle) +
len(emitter.tag_data.suffix)
case yaml_MAPPING_START_EVENT:
if !yaml_emitter_check_empty_mapping(emitter) {
return false
}
length += len(emitter.anchor_data.anchor) +
len(emitter.tag_data.handle) +
len(emitter.tag_data.suffix)
default:
return false
}
if length > 128 {
return false
}
return true
}
/*
* Determine an acceptable scalar style.
*/
func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool {
no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0
if no_tag && !event.implicit && !event.quoted_implicit {
return yaml_emitter_set_emitter_error(emitter,
"neither tag nor implicit flags are specified")
}
style := yaml_scalar_style_t(event.style)
if style == yaml_ANY_SCALAR_STYLE {
style = yaml_PLAIN_SCALAR_STYLE
}
if emitter.canonical {
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
}
if emitter.simple_key_context && emitter.scalar_data.multiline {
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
}
if style == yaml_PLAIN_SCALAR_STYLE {
if (emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed) ||
(emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed) {
style = yaml_SINGLE_QUOTED_SCALAR_STYLE
}
if len(emitter.scalar_data.value) == 0 &&
(emitter.flow_level > 0 || emitter.simple_key_context) {
style = yaml_SINGLE_QUOTED_SCALAR_STYLE
}
if no_tag && !event.implicit {
style = yaml_SINGLE_QUOTED_SCALAR_STYLE
}
}
if style == yaml_SINGLE_QUOTED_SCALAR_STYLE {
if !emitter.scalar_data.single_quoted_allowed {
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
}
}
if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE {
if !emitter.scalar_data.block_allowed ||
emitter.flow_level > 0 || emitter.simple_key_context {
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
}
}
if no_tag && !event.quoted_implicit &&
style != yaml_PLAIN_SCALAR_STYLE {
emitter.tag_data.handle = []byte("!")
}
emitter.scalar_data.style = style
return true
}
/*
* Write an achor.
*/
func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool {
if emitter.anchor_data.anchor == nil {
return true
}
indicator := "*"
if !emitter.anchor_data.alias {
indicator = "&"
}
if !yaml_emitter_write_indicator(emitter, []byte(indicator), true, false, false) {
return false
}
return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor)
}
/*
* Write a tag.
*/
func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool {
if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 {
return true
}
if len(emitter.tag_data.handle) > 0 {
if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) {
return false
}
if len(emitter.tag_data.suffix) > 0 {
if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
return false
}
}
} else {
if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) {
return false
}
if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
return false
}
if !yaml_emitter_write_indicator(emitter, []byte(">"), false, false, false) {
return false
}
}
return true
}
/*
* Write a scalar.
*/
func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool {
switch emitter.scalar_data.style {
case yaml_PLAIN_SCALAR_STYLE:
return yaml_emitter_write_plain_scalar(emitter,
emitter.scalar_data.value,
!emitter.simple_key_context)
case yaml_SINGLE_QUOTED_SCALAR_STYLE:
return yaml_emitter_write_single_quoted_scalar(emitter,
emitter.scalar_data.value,
!emitter.simple_key_context)
case yaml_DOUBLE_QUOTED_SCALAR_STYLE:
return yaml_emitter_write_double_quoted_scalar(emitter,
emitter.scalar_data.value,
!emitter.simple_key_context)
case yaml_LITERAL_SCALAR_STYLE:
return yaml_emitter_write_literal_scalar(emitter,
emitter.scalar_data.value)
case yaml_FOLDED_SCALAR_STYLE:
return yaml_emitter_write_folded_scalar(emitter,
emitter.scalar_data.value)
default:
panic("unknown scalar")
}
return false
}
/*
* Check if a %YAML directive is valid.
*/
func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t,
version_directive yaml_version_directive_t) bool {
if version_directive.major != 1 || version_directive.minor != 1 {
return yaml_emitter_set_emitter_error(emitter,
"incompatible %YAML directive")
}
return true
}
/*
* Check if a %TAG directive is valid.
*/
func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t,
tag_directive *yaml_tag_directive_t) bool {
handle := tag_directive.handle
prefix := tag_directive.prefix
if len(handle) == 0 {
return yaml_emitter_set_emitter_error(emitter,
"tag handle must not be empty")
}
if handle[0] != '!' {
return yaml_emitter_set_emitter_error(emitter,
"tag handle must start with '!'")
}
if handle[len(handle)-1] != '!' {
return yaml_emitter_set_emitter_error(emitter,
"tag handle must end with '!'")
}
for i := 1; i < len(handle)-1; width(handle[i]) {
if !is_alpha(handle[i]) {
return yaml_emitter_set_emitter_error(emitter,
"tag handle must contain alphanumerical characters only")
}
}
if len(prefix) == 0 {
return yaml_emitter_set_emitter_error(emitter,
"tag prefix must not be empty")
}
return true
}
/*
* Check if an anchor is valid.
*/
func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t,
anchor []byte, alias bool) bool {
if len(anchor) == 0 {
errmsg := "alias value must not be empty"
if !alias {
errmsg = "anchor value must not be empty"
}
return yaml_emitter_set_emitter_error(emitter, errmsg)
}
for i := 0; i < len(anchor); i += width(anchor[i]) {
if !is_alpha(anchor[i]) {
errmsg := "alias value must contain alphanumerical characters only"
if !alias {
errmsg = "anchor value must contain alphanumerical characters only"
}
return yaml_emitter_set_emitter_error(emitter, errmsg)
}
}
emitter.anchor_data.anchor = anchor
emitter.anchor_data.alias = alias
return true
}
/*
* Check if a tag is valid.
*/
func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool {
if len(tag) == 0 {
return yaml_emitter_set_emitter_error(emitter,
"tag value must not be empty")
}
for i := range emitter.tag_directives {
tag_directive := &emitter.tag_directives[i]
if bytes.HasPrefix(tag, tag_directive.prefix) {
emitter.tag_data.handle = tag_directive.handle
emitter.tag_data.suffix = tag[len(tag_directive.prefix):]
return true
}
}
emitter.tag_data.suffix = tag
return true
}
/*
* Check if a scalar is valid.
*/
func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
block_indicators := false
flow_indicators := false
line_breaks := false
special_characters := false
leading_space := false
leading_break := false
trailing_space := false
trailing_break := false
break_space := false
space_break := false
preceeded_by_whitespace := false
followed_by_whitespace := false
previous_space := false
previous_break := false
emitter.scalar_data.value = value
if len(value) == 0 {
emitter.scalar_data.multiline = false
emitter.scalar_data.flow_plain_allowed = false
emitter.scalar_data.block_plain_allowed = true
emitter.scalar_data.single_quoted_allowed = true
emitter.scalar_data.block_allowed = false
return true
}
if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') ||
(value[0] == '.' && value[1] == '.' && value[2] == '.')) {
block_indicators = true
flow_indicators = true
}
preceeded_by_whitespace = true
for i, w := 0, 0; i < len(value); i += w {
w = width(value[i])
followed_by_whitespace = i+w >= len(value) || is_blankz_at(value, i+w)
if i == 0 {
switch value[i] {
case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`':
flow_indicators = true
block_indicators = true
case '?', ':':
flow_indicators = true
if followed_by_whitespace {
block_indicators = true
}
case '-':
if followed_by_whitespace {
flow_indicators = true
block_indicators = true
}
}
} else {
switch value[i] {
case ',', '?', '[', ']', '{', '}':
flow_indicators = true
case ':':
flow_indicators = true
if followed_by_whitespace {
block_indicators = true
}
case '#':
if preceeded_by_whitespace {
flow_indicators = true
block_indicators = true
}
}
}
if !is_printable_at(value, i) || (!is_ascii(value[i]) && !emitter.unicode) {
special_characters = true
}
if is_break_at(value, i) {
line_breaks = true
}
if is_space(value[i]) {
if i == 0 {
leading_space = true
}
if i+w == len(value) {
trailing_space = true
}
if previous_break {
break_space = true
}
previous_space = true
previous_break = false
} else if is_break_at(value, i) {
if i == 0 {
leading_break = true
}
if i+width(value[i]) == len(value) {
trailing_break = true
}
if previous_space {
space_break = true
}
previous_space = false
previous_break = true
} else {
previous_space = false
previous_break = false
}
preceeded_by_whitespace = is_blankz_at(value, i)
}
emitter.scalar_data.multiline = line_breaks
emitter.scalar_data.flow_plain_allowed = true
emitter.scalar_data.block_plain_allowed = true
emitter.scalar_data.single_quoted_allowed = true
emitter.scalar_data.block_allowed = true
if leading_space || leading_break || trailing_space || trailing_break {
emitter.scalar_data.flow_plain_allowed = false
emitter.scalar_data.block_plain_allowed = false
}
if trailing_space {
emitter.scalar_data.block_allowed = false
}
if break_space {
emitter.scalar_data.flow_plain_allowed = false
emitter.scalar_data.block_plain_allowed = false
emitter.scalar_data.single_quoted_allowed = false
}
if space_break || special_characters {
emitter.scalar_data.flow_plain_allowed = false
emitter.scalar_data.block_plain_allowed = false
emitter.scalar_data.single_quoted_allowed = false
emitter.scalar_data.block_allowed = false
}
if line_breaks {
emitter.scalar_data.flow_plain_allowed = false
emitter.scalar_data.block_plain_allowed = false
}
if flow_indicators {
emitter.scalar_data.flow_plain_allowed = false
}
if block_indicators {
emitter.scalar_data.block_plain_allowed = false
}
return true
}
/*
* Check if the event data is valid.
*/
func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
emitter.anchor_data.anchor = nil
emitter.tag_data.handle = nil
emitter.tag_data.suffix = nil
emitter.scalar_data.value = nil
switch event.event_type {
case yaml_ALIAS_EVENT:
if !yaml_emitter_analyze_anchor(emitter,
event.anchor, true) {
return false
}
case yaml_SCALAR_EVENT:
if len(event.anchor) > 0 {
if !yaml_emitter_analyze_anchor(emitter,
event.anchor, false) {
return false
}
}
if len(event.tag) > 0 && (emitter.canonical ||
(!event.implicit &&
!event.quoted_implicit)) {
if !yaml_emitter_analyze_tag(emitter, event.tag) {
return false
}
}
if !yaml_emitter_analyze_scalar(emitter, event.value) {
return false
}
case yaml_SEQUENCE_START_EVENT:
if len(event.anchor) > 0 {
if !yaml_emitter_analyze_anchor(emitter,
event.anchor, false) {
return false
}
}
if len(event.tag) > 0 && (emitter.canonical ||
!event.implicit) {
if !yaml_emitter_analyze_tag(emitter,
event.tag) {
return false
}
}
case yaml_MAPPING_START_EVENT:
if len(event.anchor) > 0 {
if !yaml_emitter_analyze_anchor(emitter,
event.anchor, false) {
return false
}
}
if len(event.tag) > 0 && (emitter.canonical ||
!event.implicit) {
if !yaml_emitter_analyze_tag(emitter,
event.tag) {
return false
}
}
}
return true
}
/*
* Write the BOM character.
*/
func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool {
if !flush(emitter) {
return false
}
pos := emitter.buffer_pos
emitter.buffer[pos] = '\xEF'
emitter.buffer[pos+1] = '\xBB'
emitter.buffer[pos+2] = '\xBF'
emitter.buffer_pos += 3
return true
}
func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool {
indent := emitter.indent
if indent < 0 {
indent = 0
}
if !emitter.indention || emitter.column > indent ||
(emitter.column == indent && !emitter.whitespace) {
if !put_break(emitter) {
return false
}
}
for emitter.column < indent {
if !put(emitter, ' ') {
return false
}
}
emitter.whitespace = true
emitter.indention = true
return true
}
func yaml_emitter_write_indicator(emitter *yaml_emitter_t,
indicator []byte, need_whitespace bool,
is_whitespace bool, is_indention bool) bool {
if need_whitespace && !emitter.whitespace {
if !put(emitter, ' ') {
return false
}
}
ind_pos := 0
for ind_pos < len(indicator) {
if !write(emitter, indicator, &ind_pos) {
return false
}
}
emitter.whitespace = is_whitespace
emitter.indention = (emitter.indention && is_indention)
emitter.open_ended = false
return true
}
func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool {
pos := 0
for pos < len(value) {
if !write(emitter, value, &pos) {
return false
}
}
emitter.whitespace = false
emitter.indention = false
return true
}
func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool {
if !emitter.whitespace {
if !put(emitter, ' ') {
return false
}
}
pos := 0
for pos < len(value) {
if !write(emitter, value, &pos) {
return false
}
}
emitter.whitespace = false
emitter.indention = false
return true
}
func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte,
need_whitespace bool) bool {
if need_whitespace && !emitter.whitespace {
if !put(emitter, ' ') {
return false
}
}
for i := 0; i < len(value); {
write_it := false
switch value[i] {
case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_',
'.', '!', '~', '*', '\'', '(', ')', '[', ']':
write_it = true
default:
write_it = is_alpha(value[i])
}
if write_it {
if !write(emitter, value, &i) {
return false
}
} else {
w := width(value[i])
for j := 0; j < w; j++ {
val := value[i]
i++
if !put(emitter, '%') {
return false
}
c := val >> 4
if c < 10 {
c += '0'
} else {
c += 'A' - 10
}
if !put(emitter, c) {
return false
}
c = val & 0x0f
if c < 10 {
c += '0'
} else {
c += 'A' - 10
}
if !put(emitter, c) {
return false
}
}
}
}
emitter.whitespace = false
emitter.indention = false
return true
}
func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte,
allow_breaks bool) bool {
spaces := false
breaks := false
if !emitter.whitespace {
if !put(emitter, ' ') {
return false
}
}
for i := 0; i < len(value); {
if is_space(value[i]) {
if allow_breaks && !spaces &&
emitter.column > emitter.best_width &&
!is_space(value[i+1]) {
if !yaml_emitter_write_indent(emitter) {
return false
}
i += width(value[i])
} else {
if !write(emitter, value, &i) {
return false
}
}
spaces = true
} else if is_break_at(value, i) {
if !breaks && value[i] == '\n' {
if !put_break(emitter) {
return false
}
}
if !write_break(emitter, value, &i) {
return false
}
emitter.indention = true
breaks = true
} else {
if breaks {
if !yaml_emitter_write_indent(emitter) {
return false
}
}
if !write(emitter, value, &i) {
return false
}
emitter.indention = false
spaces = false
breaks = false
}
}
emitter.whitespace = false
emitter.indention = false
if emitter.root_context {
emitter.open_ended = true
}
return true
}
func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte,
allow_breaks bool) bool {
spaces := false
breaks := false
if !yaml_emitter_write_indicator(emitter, []byte("'"), true, false, false) {
return false
}
for i := 0; i < len(value); {
if is_space(value[i]) {
if allow_breaks && !spaces &&
emitter.column > emitter.best_width &&
i > 0 && i < len(value)-1 &&
!is_space(value[i+1]) {
if !yaml_emitter_write_indent(emitter) {
return false
}
i += width(value[i])
} else {
if !write(emitter, value, &i) {
return false
}
}
spaces = true
} else if is_break_at(value, i) {
if !breaks && value[i] == '\n' {
if !put_break(emitter) {
return false
}
}
if !write_break(emitter, value, &i) {
return false
}
emitter.indention = true
breaks = true
} else {
if breaks {
if !yaml_emitter_write_indent(emitter) {
return false
}
}
if value[i] == '\'' {
if !put(emitter, '\'') {
return false
}
}
if !write(emitter, value, &i) {
return false
}
emitter.indention = false
spaces = false
breaks = false
}
}
if !yaml_emitter_write_indicator(emitter, []byte("'"), false, false, false) {
return false
}
emitter.whitespace = false
emitter.indention = false
return true
}
func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte,
allow_breaks bool) bool {
spaces := false
if !yaml_emitter_write_indicator(emitter, []byte("\""), true, false, false) {
return false
}
for i := 0; i < len(value); {
if !is_printable_at(value, i) || (!emitter.unicode && !is_ascii(value[i])) ||
is_bom_at(value, i) || is_break_at(value, i) ||
value[i] == '"' || value[i] == '\\' {
octet := value[i]
var w int
var v rune
switch {
case octet&0x80 == 0x00:
w, v = 1, rune(octet&0x7F)
case octet&0xE0 == 0xC0:
w, v = 2, rune(octet&0x1F)
case octet&0xF0 == 0xE0:
w, v = 3, rune(octet&0x0F)
case octet&0xF8 == 0xF0:
w, v = 4, rune(octet&0x07)
}
for k := 1; k < w; k++ {
octet = value[i+k]
v = (v << 6) + (rune(octet) & 0x3F)
}
i += w
if !put(emitter, '\\') {
return false
}
switch v {
case 0x00:
if !put(emitter, '0') {
return false
}
case 0x07:
if !put(emitter, 'a') {
return false
}
case 0x08:
if !put(emitter, 'b') {
return false
}
case 0x09:
if !put(emitter, 't') {
return false
}
case 0x0A:
if !put(emitter, 'n') {
return false
}
case 0x0B:
if !put(emitter, 'v') {
return false
}
case 0x0C:
if !put(emitter, 'f') {
return false
}
case 0x0D:
if !put(emitter, 'r') {
return false
}
case 0x1B:
if !put(emitter, 'e') {
return false
}
case 0x22:
if !put(emitter, '"') {
return false
}
case 0x5C:
if !put(emitter, '\\') {
return false
}
case 0x85:
if !put(emitter, 'N') {
return false
}
case 0xA0:
if !put(emitter, '_') {
return false
}
case 0x2028:
if !put(emitter, 'L') {
return false
}
case 0x2029:
if !put(emitter, 'P') {
return false
}
default:
if v <= 0xFF {
if !put(emitter, 'x') {
return false
}
w = 2
} else if v <= 0xFFFF {
if !put(emitter, 'u') {
return false
}
w = 4
} else {
if !put(emitter, 'U') {
return false
}
w = 8
}
for k := (w - 1) * 4; k >= 0; k -= 4 {
digit := byte((v >> uint(k)) & 0x0F)
c := digit + '0'
if c > 9 {
c = digit + 'A' - 10
}
if !put(emitter, c) {
return false
}
}
}
spaces = false
} else if is_space(value[i]) {
if allow_breaks && !spaces &&
emitter.column > emitter.best_width &&
i > 0 && i < len(value)-1 {
if !yaml_emitter_write_indent(emitter) {
return false
}
if is_space(value[i+1]) {
if !put(emitter, '\\') {
return false
}
}
i += width(value[i])
} else {
if !write(emitter, value, &i) {
return false
}
}
spaces = true
} else {
if !write(emitter, value, &i) {
return false
}
spaces = false
}
}
if !yaml_emitter_write_indicator(emitter, []byte("\""), false, false, false) {
return false
}
emitter.whitespace = false
emitter.indention = false
return true
}
func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool {
if is_space(value[0]) || is_break_at(value, 0) {
indent_hint := []byte{'0' + byte(emitter.best_indent)}
if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) {
return false
}
}
emitter.open_ended = false
var chomp_hint [1]byte
if len(value) == 0 {
chomp_hint[0] = '-'
} else {
i := len(value) - 1
for value[i]&0xC0 == 0x80 {
i--
}
if !is_break_at(value, i) {
chomp_hint[0] = '-'
} else if i == 0 {
chomp_hint[0] = '+'
emitter.open_ended = true
} else {
for value[i]&0xC0 == 0x80 {
i--
}
if is_break_at(value, i) {
chomp_hint[0] = '+'
emitter.open_ended = true
}
}
}
if chomp_hint[0] != 0 {
if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) {
return false
}
}
return true
}
func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool {
breaks := true
if !yaml_emitter_write_indicator(emitter, []byte("|"), true, false, false) {
return false
}
if !yaml_emitter_write_block_scalar_hints(emitter, value) {
return false
}
if !put_break(emitter) {
return false
}
emitter.indention = true
emitter.whitespace = true
for i := 0; i < len(value); {
if is_break_at(value, i) {
if !write_break(emitter, value, &i) {
return false
}
emitter.indention = true
breaks = true
} else {
if breaks {
if !yaml_emitter_write_indent(emitter) {
return false
}
}
if !write(emitter, value, &i) {
return false
}
emitter.indention = false
breaks = false
}
}
return true
}
func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool {
breaks := true
leading_spaces := true
if !yaml_emitter_write_indicator(emitter, []byte(">"), true, false, false) {
return false
}
if !yaml_emitter_write_block_scalar_hints(emitter, value) {
return false
}
if !put_break(emitter) {
return false
}
emitter.indention = true
emitter.whitespace = true
for i := 0; i < len(value); {
if is_break_at(value, i) {
if !breaks && !leading_spaces && value[i] == '\n' {
k := i
for is_break_at(value, k) {
k += width(value[k])
}
if !is_blankz_at(value, k) {
if !put_break(emitter) {
return false
}
}
}
if !write_break(emitter, value, &i) {
return false
}
emitter.indention = true
breaks = true
} else {
if breaks {
if !yaml_emitter_write_indent(emitter) {
return false
}
leading_spaces = is_blank(value[i])
}
if !breaks && is_space(value[i]) && !is_space(value[i+1]) &&
emitter.column > emitter.best_width {
if !yaml_emitter_write_indent(emitter) {
return false
}
i += width(value[i])
} else {
if !write(emitter, value, &i) {
return false
}
}
emitter.indention = false
breaks = false
}
}
return true
}

View File

@ -1,395 +0,0 @@
/*
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 candiedyaml
import (
"bytes"
"encoding/base64"
"io"
"math"
"reflect"
"regexp"
"sort"
"strconv"
"time"
)
var (
timeTimeType = reflect.TypeOf(time.Time{})
marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
numberType = reflect.TypeOf(Number(""))
nonPrintable = regexp.MustCompile("[^\t\n\r\u0020-\u007E\u0085\u00A0-\uD7FF\uE000-\uFFFD]")
multiline = regexp.MustCompile("\n|\u0085|\u2028|\u2029")
shortTags = map[string]string{
yaml_NULL_TAG: "!!null",
yaml_BOOL_TAG: "!!bool",
yaml_STR_TAG: "!!str",
yaml_INT_TAG: "!!int",
yaml_FLOAT_TAG: "!!float",
yaml_TIMESTAMP_TAG: "!!timestamp",
yaml_SEQ_TAG: "!!seq",
yaml_MAP_TAG: "!!map",
yaml_BINARY_TAG: "!!binary",
}
)
type Marshaler interface {
MarshalYAML() (tag string, value interface{}, err error)
}
// An Encoder writes JSON objects to an output stream.
type Encoder struct {
w io.Writer
emitter yaml_emitter_t
event yaml_event_t
flow bool
err error
}
func Marshal(v interface{}) ([]byte, error) {
b := bytes.Buffer{}
e := NewEncoder(&b)
err := e.Encode(v)
return b.Bytes(), err
}
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
e := &Encoder{w: w}
yaml_emitter_initialize(&e.emitter)
yaml_emitter_set_output_writer(&e.emitter, e.w)
yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
e.emit()
yaml_document_start_event_initialize(&e.event, nil, nil, true)
e.emit()
return e
}
func (e *Encoder) Encode(v interface{}) (err error) {
defer recovery(&err)
if e.err != nil {
return e.err
}
e.marshal("", reflect.ValueOf(v), true)
yaml_document_end_event_initialize(&e.event, true)
e.emit()
e.emitter.open_ended = false
yaml_stream_end_event_initialize(&e.event)
e.emit()
return nil
}
func (e *Encoder) emit() {
if !yaml_emitter_emit(&e.emitter, &e.event) {
panic("bad emit")
}
}
func (e *Encoder) marshal(tag string, v reflect.Value, allowAddr bool) {
vt := v.Type()
if vt.Implements(marshalerType) {
e.emitMarshaler(tag, v)
return
}
if vt.Kind() != reflect.Ptr && allowAddr {
if reflect.PtrTo(vt).Implements(marshalerType) {
e.emitAddrMarshaler(tag, v)
return
}
}
switch v.Kind() {
case reflect.Interface:
if v.IsNil() {
e.emitNil()
} else {
e.marshal(tag, v.Elem(), allowAddr)
}
case reflect.Map:
e.emitMap(tag, v)
case reflect.Ptr:
if v.IsNil() {
e.emitNil()
} else {
e.marshal(tag, v.Elem(), true)
}
case reflect.Struct:
e.emitStruct(tag, v)
case reflect.Slice:
e.emitSlice(tag, v)
case reflect.String:
e.emitString(tag, v)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
e.emitInt(tag, v)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
e.emitUint(tag, v)
case reflect.Float32, reflect.Float64:
e.emitFloat(tag, v)
case reflect.Bool:
e.emitBool(tag, v)
default:
panic("Can't marshal type yet: " + v.Type().String())
}
}
func (e *Encoder) emitMap(tag string, v reflect.Value) {
e.mapping(tag, func() {
var keys stringValues = v.MapKeys()
sort.Sort(keys)
for _, k := range keys {
e.marshal("", k, true)
e.marshal("", v.MapIndex(k), true)
}
})
}
func (e *Encoder) emitStruct(tag string, v reflect.Value) {
if v.Type() == timeTimeType {
e.emitTime(tag, v)
return
}
fields := cachedTypeFields(v.Type())
e.mapping(tag, func() {
for _, f := range fields {
fv := fieldByIndex(v, f.index)
if !fv.IsValid() || f.omitEmpty && isEmptyValue(fv) {
continue
}
e.marshal("", reflect.ValueOf(f.name), true)
e.flow = f.flow
e.marshal("", fv, true)
}
})
}
func (e *Encoder) emitTime(tag string, v reflect.Value) {
t := v.Interface().(time.Time)
bytes, _ := t.MarshalText()
e.emitScalar(string(bytes), "", tag, yaml_PLAIN_SCALAR_STYLE)
}
func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
}
return false
}
func (e *Encoder) mapping(tag string, f func()) {
implicit := tag == ""
style := yaml_BLOCK_MAPPING_STYLE
if e.flow {
e.flow = false
style = yaml_FLOW_MAPPING_STYLE
}
yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
e.emit()
f()
yaml_mapping_end_event_initialize(&e.event)
e.emit()
}
func (e *Encoder) emitSlice(tag string, v reflect.Value) {
if v.Type() == byteSliceType {
e.emitBase64(tag, v)
return
}
implicit := tag == ""
style := yaml_BLOCK_SEQUENCE_STYLE
if e.flow {
e.flow = false
style = yaml_FLOW_SEQUENCE_STYLE
}
yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
e.emit()
n := v.Len()
for i := 0; i < n; i++ {
e.marshal("", v.Index(i), true)
}
yaml_sequence_end_event_initialize(&e.event)
e.emit()
}
func (e *Encoder) emitBase64(tag string, v reflect.Value) {
if v.IsNil() {
e.emitNil()
return
}
s := v.Bytes()
dst := make([]byte, base64.StdEncoding.EncodedLen(len(s)))
base64.StdEncoding.Encode(dst, s)
e.emitScalar(string(dst), "", yaml_BINARY_TAG, yaml_DOUBLE_QUOTED_SCALAR_STYLE)
}
func (e *Encoder) emitString(tag string, v reflect.Value) {
var style yaml_scalar_style_t
s := v.String()
if nonPrintable.MatchString(s) {
e.emitBase64(tag, v)
return
}
if v.Type() == numberType {
style = yaml_PLAIN_SCALAR_STYLE
} else {
event := yaml_event_t{
implicit: true,
value: []byte(s),
}
rtag, _ := resolveInterface(event, false)
if tag == "" && rtag != yaml_STR_TAG {
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
} else if multiline.MatchString(s) {
style = yaml_LITERAL_SCALAR_STYLE
} else {
style = yaml_PLAIN_SCALAR_STYLE
}
}
e.emitScalar(s, "", tag, style)
}
func (e *Encoder) emitBool(tag string, v reflect.Value) {
s := strconv.FormatBool(v.Bool())
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
}
func (e *Encoder) emitInt(tag string, v reflect.Value) {
s := strconv.FormatInt(v.Int(), 10)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
}
func (e *Encoder) emitUint(tag string, v reflect.Value) {
s := strconv.FormatUint(v.Uint(), 10)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
}
func (e *Encoder) emitFloat(tag string, v reflect.Value) {
f := v.Float()
var s string
switch {
case math.IsNaN(f):
s = ".nan"
case math.IsInf(f, 1):
s = "+.inf"
case math.IsInf(f, -1):
s = "-.inf"
default:
s = strconv.FormatFloat(f, 'g', -1, v.Type().Bits())
}
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
}
func (e *Encoder) emitNil() {
e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE)
}
func (e *Encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) {
implicit := tag == ""
if !implicit {
style = yaml_PLAIN_SCALAR_STYLE
}
stag := shortTags[tag]
if stag == "" {
stag = tag
}
yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(stag), []byte(value), implicit, implicit, style)
e.emit()
}
func (e *Encoder) emitMarshaler(tag string, v reflect.Value) {
if v.Kind() == reflect.Ptr && v.IsNil() {
e.emitNil()
return
}
m := v.Interface().(Marshaler)
if m == nil {
e.emitNil()
return
}
t, val, err := m.MarshalYAML()
if err != nil {
panic(err)
}
if val == nil {
e.emitNil()
return
}
e.marshal(t, reflect.ValueOf(val), false)
}
func (e *Encoder) emitAddrMarshaler(tag string, v reflect.Value) {
if !v.CanAddr() {
e.marshal(tag, v, false)
return
}
va := v.Addr()
if va.IsNil() {
e.emitNil()
return
}
m := v.Interface().(Marshaler)
t, val, err := m.MarshalYAML()
if err != nil {
panic(err)
}
if val == nil {
e.emitNil()
return
}
e.marshal(t, reflect.ValueOf(val), false)
}

View File

@ -1,1230 +0,0 @@
/*
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 candiedyaml
import (
"bytes"
)
/*
* The parser implements the following grammar:
*
* stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
* implicit_document ::= block_node DOCUMENT-END*
* explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
* block_node_or_indentless_sequence ::=
* ALIAS
* | properties (block_content | indentless_block_sequence)?
* | block_content
* | indentless_block_sequence
* block_node ::= ALIAS
* | properties block_content?
* | block_content
* flow_node ::= ALIAS
* | properties flow_content?
* | flow_content
* properties ::= TAG ANCHOR? | ANCHOR TAG?
* block_content ::= block_collection | flow_collection | SCALAR
* flow_content ::= flow_collection | SCALAR
* block_collection ::= block_sequence | block_mapping
* flow_collection ::= flow_sequence | flow_mapping
* block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
* indentless_sequence ::= (BLOCK-ENTRY block_node?)+
* block_mapping ::= BLOCK-MAPPING_START
* ((KEY block_node_or_indentless_sequence?)?
* (VALUE block_node_or_indentless_sequence?)?)*
* BLOCK-END
* flow_sequence ::= FLOW-SEQUENCE-START
* (flow_sequence_entry FLOW-ENTRY)*
* flow_sequence_entry?
* FLOW-SEQUENCE-END
* flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* flow_mapping ::= FLOW-MAPPING-START
* (flow_mapping_entry FLOW-ENTRY)*
* flow_mapping_entry?
* FLOW-MAPPING-END
* flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
*/
/*
* Peek the next token in the token queue.
*/
func peek_token(parser *yaml_parser_t) *yaml_token_t {
if parser.token_available || yaml_parser_fetch_more_tokens(parser) {
return &parser.tokens[parser.tokens_head]
}
return nil
}
/*
* Remove the next token from the queue (must be called after peek_token).
*/
func skip_token(parser *yaml_parser_t) {
parser.token_available = false
parser.tokens_parsed++
parser.stream_end_produced = parser.tokens[parser.tokens_head].token_type == yaml_STREAM_END_TOKEN
parser.tokens_head++
}
/*
* Get the next event.
*/
func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool {
/* Erase the event object. */
*event = yaml_event_t{}
/* No events after the end of the stream or error. */
if parser.stream_end_produced || parser.error != yaml_NO_ERROR ||
parser.state == yaml_PARSE_END_STATE {
return true
}
/* Generate the next event. */
return yaml_parser_state_machine(parser, event)
}
/*
* Set parser error.
*/
func yaml_parser_set_parser_error(parser *yaml_parser_t,
problem string, problem_mark YAML_mark_t) bool {
parser.error = yaml_PARSER_ERROR
parser.problem = problem
parser.problem_mark = problem_mark
return false
}
func yaml_parser_set_parser_error_context(parser *yaml_parser_t,
context string, context_mark YAML_mark_t,
problem string, problem_mark YAML_mark_t) bool {
parser.error = yaml_PARSER_ERROR
parser.context = context
parser.context_mark = context_mark
parser.problem = problem
parser.problem_mark = problem_mark
return false
}
/*
* State dispatcher.
*/
func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool {
switch parser.state {
case yaml_PARSE_STREAM_START_STATE:
return yaml_parser_parse_stream_start(parser, event)
case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
return yaml_parser_parse_document_start(parser, event, true)
case yaml_PARSE_DOCUMENT_START_STATE:
return yaml_parser_parse_document_start(parser, event, false)
case yaml_PARSE_DOCUMENT_CONTENT_STATE:
return yaml_parser_parse_document_content(parser, event)
case yaml_PARSE_DOCUMENT_END_STATE:
return yaml_parser_parse_document_end(parser, event)
case yaml_PARSE_BLOCK_NODE_STATE:
return yaml_parser_parse_node(parser, event, true, false)
case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
return yaml_parser_parse_node(parser, event, true, true)
case yaml_PARSE_FLOW_NODE_STATE:
return yaml_parser_parse_node(parser, event, false, false)
case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
return yaml_parser_parse_block_sequence_entry(parser, event, true)
case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
return yaml_parser_parse_block_sequence_entry(parser, event, false)
case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
return yaml_parser_parse_indentless_sequence_entry(parser, event)
case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
return yaml_parser_parse_block_mapping_key(parser, event, true)
case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
return yaml_parser_parse_block_mapping_key(parser, event, false)
case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
return yaml_parser_parse_block_mapping_value(parser, event)
case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
return yaml_parser_parse_flow_sequence_entry(parser, event, true)
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
return yaml_parser_parse_flow_sequence_entry(parser, event, false)
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event)
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event)
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event)
case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
return yaml_parser_parse_flow_mapping_key(parser, event, true)
case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
return yaml_parser_parse_flow_mapping_key(parser, event, false)
case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
return yaml_parser_parse_flow_mapping_value(parser, event, false)
case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
return yaml_parser_parse_flow_mapping_value(parser, event, true)
}
panic("invalid parser state")
}
/*
* Parse the production:
* stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
* ************
*/
func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool {
token := peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_STREAM_START_TOKEN {
return yaml_parser_set_parser_error(parser,
"did not find expected <stream-start>", token.start_mark)
}
parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE
*event = yaml_event_t{
event_type: yaml_STREAM_START_EVENT,
start_mark: token.start_mark,
end_mark: token.end_mark,
encoding: token.encoding,
}
skip_token(parser)
return true
}
/*
* Parse the productions:
* implicit_document ::= block_node DOCUMENT-END*
* *
* explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
* *************************
*/
func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t,
implicit bool) bool {
token := peek_token(parser)
if token == nil {
return false
}
/* Parse extra document end indicators. */
if !implicit {
for token.token_type == yaml_DOCUMENT_END_TOKEN {
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
}
}
/* Parse an implicit document. */
if implicit && token.token_type != yaml_VERSION_DIRECTIVE_TOKEN &&
token.token_type != yaml_TAG_DIRECTIVE_TOKEN &&
token.token_type != yaml_DOCUMENT_START_TOKEN &&
token.token_type != yaml_STREAM_END_TOKEN {
if !yaml_parser_process_directives(parser, nil, nil) {
return false
}
parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
parser.state = yaml_PARSE_BLOCK_NODE_STATE
*event = yaml_event_t{
event_type: yaml_DOCUMENT_START_EVENT,
implicit: true,
start_mark: token.start_mark,
end_mark: token.end_mark,
}
} else if token.token_type != yaml_STREAM_END_TOKEN {
/* Parse an explicit document. */
var version_directive *yaml_version_directive_t
var tag_directives []yaml_tag_directive_t
start_mark := token.start_mark
if !yaml_parser_process_directives(parser, &version_directive,
&tag_directives) {
return false
}
token = peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_DOCUMENT_START_TOKEN {
yaml_parser_set_parser_error(parser,
"did not find expected <document start>", token.start_mark)
return false
}
parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE
end_mark := token.end_mark
*event = yaml_event_t{
event_type: yaml_DOCUMENT_START_EVENT,
start_mark: start_mark,
end_mark: end_mark,
version_directive: version_directive,
tag_directives: tag_directives,
implicit: false,
}
skip_token(parser)
} else {
/* Parse the stream end. */
parser.state = yaml_PARSE_END_STATE
*event = yaml_event_t{
event_type: yaml_STREAM_END_EVENT,
start_mark: token.start_mark,
end_mark: token.end_mark,
}
skip_token(parser)
}
return true
}
/*
* Parse the productions:
* explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
* ***********
*/
func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool {
token := peek_token(parser)
if token == nil {
return false
}
if token.token_type == yaml_VERSION_DIRECTIVE_TOKEN ||
token.token_type == yaml_TAG_DIRECTIVE_TOKEN ||
token.token_type == yaml_DOCUMENT_START_TOKEN ||
token.token_type == yaml_DOCUMENT_END_TOKEN ||
token.token_type == yaml_STREAM_END_TOKEN {
parser.state = parser.states[len(parser.states)-1]
parser.states = parser.states[:len(parser.states)-1]
return yaml_parser_process_empty_scalar(parser, event,
token.start_mark)
} else {
return yaml_parser_parse_node(parser, event, true, false)
}
}
/*
* Parse the productions:
* implicit_document ::= block_node DOCUMENT-END*
* *************
* explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
* *************
*/
func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool {
implicit := true
token := peek_token(parser)
if token == nil {
return false
}
start_mark, end_mark := token.start_mark, token.start_mark
if token.token_type == yaml_DOCUMENT_END_TOKEN {
end_mark = token.end_mark
skip_token(parser)
implicit = false
}
parser.tag_directives = parser.tag_directives[:0]
parser.state = yaml_PARSE_DOCUMENT_START_STATE
*event = yaml_event_t{
event_type: yaml_DOCUMENT_END_EVENT,
start_mark: start_mark,
end_mark: end_mark,
implicit: implicit,
}
return true
}
/*
* Parse the productions:
* block_node_or_indentless_sequence ::=
* ALIAS
* *****
* | properties (block_content | indentless_block_sequence)?
* ********** *
* | block_content | indentless_block_sequence
* *
* block_node ::= ALIAS
* *****
* | properties block_content?
* ********** *
* | block_content
* *
* flow_node ::= ALIAS
* *****
* | properties flow_content?
* ********** *
* | flow_content
* *
* properties ::= TAG ANCHOR? | ANCHOR TAG?
* *************************
* block_content ::= block_collection | flow_collection | SCALAR
* ******
* flow_content ::= flow_collection | SCALAR
* ******
*/
func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t,
block bool, indentless_sequence bool) bool {
token := peek_token(parser)
if token == nil {
return false
}
if token.token_type == yaml_ALIAS_TOKEN {
parser.state = parser.states[len(parser.states)-1]
parser.states = parser.states[:len(parser.states)-1]
*event = yaml_event_t{
event_type: yaml_ALIAS_EVENT,
start_mark: token.start_mark,
end_mark: token.end_mark,
anchor: token.value,
}
skip_token(parser)
return true
} else {
start_mark, end_mark := token.start_mark, token.start_mark
var tag_handle []byte
var tag_suffix, anchor []byte
var tag_mark YAML_mark_t
if token.token_type == yaml_ANCHOR_TOKEN {
anchor = token.value
start_mark = token.start_mark
end_mark = token.end_mark
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
if token.token_type == yaml_TAG_TOKEN {
tag_handle = token.value
tag_suffix = token.suffix
tag_mark = token.start_mark
end_mark = token.end_mark
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
}
} else if token.token_type == yaml_TAG_TOKEN {
tag_handle = token.value
tag_suffix = token.suffix
start_mark, tag_mark = token.start_mark, token.start_mark
end_mark = token.end_mark
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
if token.token_type == yaml_ANCHOR_TOKEN {
anchor = token.value
end_mark = token.end_mark
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
}
}
var tag []byte
if tag_handle != nil {
if len(tag_handle) == 0 {
tag = tag_suffix
tag_handle = nil
tag_suffix = nil
} else {
for i := range parser.tag_directives {
tag_directive := &parser.tag_directives[i]
if bytes.Equal(tag_directive.handle, tag_handle) {
tag = append([]byte(nil), tag_directive.prefix...)
tag = append(tag, tag_suffix...)
tag_handle = nil
tag_suffix = nil
break
}
}
if len(tag) == 0 {
yaml_parser_set_parser_error_context(parser,
"while parsing a node", start_mark,
"found undefined tag handle", tag_mark)
return false
}
}
}
implicit := len(tag) == 0
if indentless_sequence && token.token_type == yaml_BLOCK_ENTRY_TOKEN {
end_mark = token.end_mark
parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
*event = yaml_event_t{
event_type: yaml_SEQUENCE_START_EVENT,
start_mark: start_mark,
end_mark: end_mark,
anchor: anchor,
tag: tag,
implicit: implicit,
style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
}
return true
} else {
if token.token_type == yaml_SCALAR_TOKEN {
plain_implicit := false
quoted_implicit := false
end_mark = token.end_mark
if (token.style == yaml_PLAIN_SCALAR_STYLE && len(tag) == 0) ||
(len(tag) == 1 && tag[0] == '!') {
plain_implicit = true
} else if len(tag) == 0 {
quoted_implicit = true
}
parser.state = parser.states[len(parser.states)-1]
parser.states = parser.states[:len(parser.states)-1]
*event = yaml_event_t{
event_type: yaml_SCALAR_EVENT,
start_mark: start_mark,
end_mark: end_mark,
anchor: anchor,
tag: tag,
value: token.value,
implicit: plain_implicit,
quoted_implicit: quoted_implicit,
style: yaml_style_t(token.style),
}
skip_token(parser)
return true
} else if token.token_type == yaml_FLOW_SEQUENCE_START_TOKEN {
end_mark = token.end_mark
parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE
*event = yaml_event_t{
event_type: yaml_SEQUENCE_START_EVENT,
start_mark: start_mark,
end_mark: end_mark,
anchor: anchor,
tag: tag,
implicit: implicit,
style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE),
}
return true
} else if token.token_type == yaml_FLOW_MAPPING_START_TOKEN {
end_mark = token.end_mark
parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE
*event = yaml_event_t{
event_type: yaml_MAPPING_START_EVENT,
start_mark: start_mark,
end_mark: end_mark,
anchor: anchor,
tag: tag,
implicit: implicit,
style: yaml_style_t(yaml_FLOW_MAPPING_STYLE),
}
return true
} else if block && token.token_type == yaml_BLOCK_SEQUENCE_START_TOKEN {
end_mark = token.end_mark
parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE
*event = yaml_event_t{
event_type: yaml_SEQUENCE_START_EVENT,
start_mark: start_mark,
end_mark: end_mark,
anchor: anchor,
tag: tag,
implicit: implicit,
style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
}
return true
} else if block && token.token_type == yaml_BLOCK_MAPPING_START_TOKEN {
end_mark = token.end_mark
parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE
*event = yaml_event_t{
event_type: yaml_MAPPING_START_EVENT,
start_mark: start_mark,
end_mark: end_mark,
anchor: anchor,
tag: tag,
implicit: implicit,
style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE),
}
return true
} else if len(anchor) > 0 || len(tag) > 0 {
parser.state = parser.states[len(parser.states)-1]
parser.states = parser.states[:len(parser.states)-1]
*event = yaml_event_t{
event_type: yaml_SCALAR_EVENT,
start_mark: start_mark,
end_mark: end_mark,
anchor: anchor,
tag: tag,
implicit: implicit,
quoted_implicit: false,
style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
}
return true
} else {
msg := "while parsing a block node"
if !block {
msg = "while parsing a flow node"
}
yaml_parser_set_parser_error_context(parser, msg, start_mark,
"did not find expected node content", token.start_mark)
return false
}
}
}
return false
}
/*
* Parse the productions:
* block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
* ******************** *********** * *********
*/
func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t,
event *yaml_event_t, first bool) bool {
if first {
token := peek_token(parser)
parser.marks = append(parser.marks, token.start_mark)
skip_token(parser)
}
token := peek_token(parser)
if token == nil {
return false
}
if token.token_type == yaml_BLOCK_ENTRY_TOKEN {
mark := token.end_mark
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_BLOCK_ENTRY_TOKEN &&
token.token_type != yaml_BLOCK_END_TOKEN {
parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)
return yaml_parser_parse_node(parser, event, true, false)
} else {
parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE
return yaml_parser_process_empty_scalar(parser, event, mark)
}
} else if token.token_type == yaml_BLOCK_END_TOKEN {
parser.state = parser.states[len(parser.states)-1]
parser.states = parser.states[:len(parser.states)-1]
parser.marks = parser.marks[:len(parser.marks)-1]
*event = yaml_event_t{
event_type: yaml_SEQUENCE_END_EVENT,
start_mark: token.start_mark,
end_mark: token.end_mark,
}
skip_token(parser)
return true
} else {
mark := parser.marks[len(parser.marks)-1]
parser.marks = parser.marks[:len(parser.marks)-1]
return yaml_parser_set_parser_error_context(parser,
"while parsing a block collection", mark,
"did not find expected '-' indicator", token.start_mark)
}
}
/*
* Parse the productions:
* indentless_sequence ::= (BLOCK-ENTRY block_node?)+
* *********** *
*/
func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t,
event *yaml_event_t) bool {
token := peek_token(parser)
if token == nil {
return false
}
if token.token_type == yaml_BLOCK_ENTRY_TOKEN {
mark := token.end_mark
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_BLOCK_ENTRY_TOKEN &&
token.token_type != yaml_KEY_TOKEN &&
token.token_type != yaml_VALUE_TOKEN &&
token.token_type != yaml_BLOCK_END_TOKEN {
parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)
return yaml_parser_parse_node(parser, event, true, false)
} else {
parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
return yaml_parser_process_empty_scalar(parser, event, mark)
}
} else {
parser.state = parser.states[len(parser.states)-1]
parser.states = parser.states[:len(parser.states)-1]
*event = yaml_event_t{
event_type: yaml_SEQUENCE_END_EVENT,
start_mark: token.start_mark,
end_mark: token.start_mark,
}
return true
}
}
/*
* Parse the productions:
* block_mapping ::= BLOCK-MAPPING_START
* *******************
* ((KEY block_node_or_indentless_sequence?)?
* *** *
* (VALUE block_node_or_indentless_sequence?)?)*
*
* BLOCK-END
* *********
*/
func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t,
event *yaml_event_t, first bool) bool {
if first {
token := peek_token(parser)
parser.marks = append(parser.marks, token.start_mark)
skip_token(parser)
}
token := peek_token(parser)
if token == nil {
return false
}
if token.token_type == yaml_KEY_TOKEN {
mark := token.end_mark
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_KEY_TOKEN &&
token.token_type != yaml_VALUE_TOKEN &&
token.token_type != yaml_BLOCK_END_TOKEN {
parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE)
return yaml_parser_parse_node(parser, event, true, true)
} else {
parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE
return yaml_parser_process_empty_scalar(parser, event, mark)
}
} else if token.token_type == yaml_BLOCK_END_TOKEN {
parser.state = parser.states[len(parser.states)-1]
parser.states = parser.states[:len(parser.states)-1]
parser.marks = parser.marks[:len(parser.marks)-1]
*event = yaml_event_t{
event_type: yaml_MAPPING_END_EVENT,
start_mark: token.start_mark,
end_mark: token.end_mark,
}
skip_token(parser)
return true
} else {
mark := parser.marks[len(parser.marks)-1]
parser.marks = parser.marks[:len(parser.marks)-1]
return yaml_parser_set_parser_error_context(parser,
"while parsing a block mapping", mark,
"did not find expected key", token.start_mark)
}
}
/*
* Parse the productions:
* block_mapping ::= BLOCK-MAPPING_START
*
* ((KEY block_node_or_indentless_sequence?)?
*
* (VALUE block_node_or_indentless_sequence?)?)*
* ***** *
* BLOCK-END
*
*/
func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t,
event *yaml_event_t) bool {
token := peek_token(parser)
if token == nil {
return false
}
if token.token_type == yaml_VALUE_TOKEN {
mark := token.end_mark
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_KEY_TOKEN &&
token.token_type != yaml_VALUE_TOKEN &&
token.token_type != yaml_BLOCK_END_TOKEN {
parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE)
return yaml_parser_parse_node(parser, event, true, true)
} else {
parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
return yaml_parser_process_empty_scalar(parser, event, mark)
}
} else {
parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
}
}
/*
* Parse the productions:
* flow_sequence ::= FLOW-SEQUENCE-START
* *******************
* (flow_sequence_entry FLOW-ENTRY)*
* * **********
* flow_sequence_entry?
* *
* FLOW-SEQUENCE-END
* *****************
* flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* *
*/
func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t,
event *yaml_event_t, first bool) bool {
if first {
token := peek_token(parser)
parser.marks = append(parser.marks, token.start_mark)
skip_token(parser)
}
token := peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_FLOW_SEQUENCE_END_TOKEN {
if !first {
if token.token_type == yaml_FLOW_ENTRY_TOKEN {
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
} else {
mark := parser.marks[len(parser.marks)-1]
parser.marks = parser.marks[:len(parser.marks)-1]
return yaml_parser_set_parser_error_context(parser,
"while parsing a flow sequence", mark,
"did not find expected ',' or ']'", token.start_mark)
}
}
if token.token_type == yaml_KEY_TOKEN {
parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE
*event = yaml_event_t{
event_type: yaml_MAPPING_START_EVENT,
start_mark: token.start_mark,
end_mark: token.end_mark,
implicit: true,
style: yaml_style_t(yaml_FLOW_MAPPING_STYLE),
}
skip_token(parser)
return true
} else if token.token_type != yaml_FLOW_SEQUENCE_END_TOKEN {
parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE)
return yaml_parser_parse_node(parser, event, false, false)
}
}
parser.state = parser.states[len(parser.states)-1]
parser.states = parser.states[:len(parser.states)-1]
parser.marks = parser.marks[:len(parser.marks)-1]
*event = yaml_event_t{
event_type: yaml_SEQUENCE_END_EVENT,
start_mark: token.start_mark,
end_mark: token.end_mark,
}
skip_token(parser)
return true
}
/*
* Parse the productions:
* flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* *** *
*/
func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t,
event *yaml_event_t) bool {
token := peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_VALUE_TOKEN &&
token.token_type != yaml_FLOW_ENTRY_TOKEN &&
token.token_type != yaml_FLOW_SEQUENCE_END_TOKEN {
parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)
return yaml_parser_parse_node(parser, event, false, false)
} else {
mark := token.end_mark
skip_token(parser)
parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE
return yaml_parser_process_empty_scalar(parser, event, mark)
}
}
/*
* Parse the productions:
* flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* ***** *
*/
func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t,
event *yaml_event_t) bool {
token := peek_token(parser)
if token == nil {
return false
}
if token.token_type == yaml_VALUE_TOKEN {
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_FLOW_ENTRY_TOKEN &&
token.token_type != yaml_FLOW_SEQUENCE_END_TOKEN {
parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)
return yaml_parser_parse_node(parser, event, false, false)
}
}
parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE
return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
}
/*
* Parse the productions:
* flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* *
*/
func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t,
event *yaml_event_t) bool {
token := peek_token(parser)
if token == nil {
return false
}
parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE
*event = yaml_event_t{
event_type: yaml_MAPPING_END_EVENT,
start_mark: token.start_mark,
end_mark: token.start_mark,
}
return true
}
/*
* Parse the productions:
* flow_mapping ::= FLOW-MAPPING-START
* ******************
* (flow_mapping_entry FLOW-ENTRY)*
* * **********
* flow_mapping_entry?
* ******************
* FLOW-MAPPING-END
* ****************
* flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* * *** *
*/
func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t,
event *yaml_event_t, first bool) bool {
if first {
token := peek_token(parser)
parser.marks = append(parser.marks, token.start_mark)
skip_token(parser)
}
token := peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_FLOW_MAPPING_END_TOKEN {
if !first {
if token.token_type == yaml_FLOW_ENTRY_TOKEN {
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
} else {
mark := parser.marks[len(parser.marks)-1]
parser.marks = parser.marks[:len(parser.marks)-1]
return yaml_parser_set_parser_error_context(parser,
"while parsing a flow mapping", mark,
"did not find expected ',' or '}'", token.start_mark)
}
}
if token.token_type == yaml_KEY_TOKEN {
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_VALUE_TOKEN &&
token.token_type != yaml_FLOW_ENTRY_TOKEN &&
token.token_type != yaml_FLOW_MAPPING_END_TOKEN {
parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE)
return yaml_parser_parse_node(parser, event, false, false)
} else {
parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE
return yaml_parser_process_empty_scalar(parser, event,
token.start_mark)
}
} else if token.token_type != yaml_FLOW_MAPPING_END_TOKEN {
parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)
return yaml_parser_parse_node(parser, event, false, false)
}
}
parser.state = parser.states[len(parser.states)-1]
parser.states = parser.states[:len(parser.states)-1]
parser.marks = parser.marks[:len(parser.marks)-1]
*event = yaml_event_t{
event_type: yaml_MAPPING_END_EVENT,
start_mark: token.start_mark,
end_mark: token.end_mark,
}
skip_token(parser)
return true
}
/*
* Parse the productions:
* flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* * ***** *
*/
func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t,
event *yaml_event_t, empty bool) bool {
token := peek_token(parser)
if token == nil {
return false
}
if empty {
parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
return yaml_parser_process_empty_scalar(parser, event,
token.start_mark)
}
if token.token_type == yaml_VALUE_TOKEN {
skip_token(parser)
token = peek_token(parser)
if token == nil {
return false
}
if token.token_type != yaml_FLOW_ENTRY_TOKEN &&
token.token_type != yaml_FLOW_MAPPING_END_TOKEN {
parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE)
return yaml_parser_parse_node(parser, event, false, false)
}
}
parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
}
/*
* Generate an empty scalar event.
*/
func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t,
mark YAML_mark_t) bool {
*event = yaml_event_t{
event_type: yaml_SCALAR_EVENT,
start_mark: mark,
end_mark: mark,
value: nil,
implicit: true,
style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
}
return true
}
/*
* Parse directives.
*/
func yaml_parser_process_directives(parser *yaml_parser_t,
version_directive_ref **yaml_version_directive_t,
tag_directives_ref *[]yaml_tag_directive_t) bool {
token := peek_token(parser)
if token == nil {
return false
}
var version_directive *yaml_version_directive_t
var tag_directives []yaml_tag_directive_t
for token.token_type == yaml_VERSION_DIRECTIVE_TOKEN ||
token.token_type == yaml_TAG_DIRECTIVE_TOKEN {
if token.token_type == yaml_VERSION_DIRECTIVE_TOKEN {
if version_directive != nil {
yaml_parser_set_parser_error(parser,
"found duplicate %YAML directive", token.start_mark)
return false
}
if token.major != 1 ||
token.minor != 1 {
yaml_parser_set_parser_error(parser,
"found incompatible YAML document", token.start_mark)
return false
}
version_directive = &yaml_version_directive_t{
major: token.major,
minor: token.minor,
}
} else if token.token_type == yaml_TAG_DIRECTIVE_TOKEN {
value := yaml_tag_directive_t{
handle: token.value,
prefix: token.prefix,
}
if !yaml_parser_append_tag_directive(parser, value, false,
token.start_mark) {
return false
}
tag_directives = append(tag_directives, value)
}
skip_token(parser)
token := peek_token(parser)
if token == nil {
return false
}
}
for i := range default_tag_directives {
if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) {
return false
}
}
if version_directive_ref != nil {
*version_directive_ref = version_directive
}
if tag_directives_ref != nil {
*tag_directives_ref = tag_directives
}
return true
}
/*
* Append a tag directive to the directives stack.
*/
func yaml_parser_append_tag_directive(parser *yaml_parser_t,
value yaml_tag_directive_t, allow_duplicates bool, mark YAML_mark_t) bool {
for i := range parser.tag_directives {
tag := &parser.tag_directives[i]
if bytes.Equal(value.handle, tag.handle) {
if allow_duplicates {
return true
}
return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark)
}
}
parser.tag_directives = append(parser.tag_directives, value)
return true
}

View File

@ -1,465 +0,0 @@
/*
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 candiedyaml
import (
"io"
)
/*
* Set the reader error and return 0.
*/
func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string,
offset int, value int) bool {
parser.error = yaml_READER_ERROR
parser.problem = problem
parser.problem_offset = offset
parser.problem_value = value
return false
}
/*
* Byte order marks.
*/
const (
BOM_UTF8 = "\xef\xbb\xbf"
BOM_UTF16LE = "\xff\xfe"
BOM_UTF16BE = "\xfe\xff"
)
/*
* Determine the input stream encoding by checking the BOM symbol. If no BOM is
* found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
*/
func yaml_parser_determine_encoding(parser *yaml_parser_t) bool {
/* Ensure that we had enough bytes in the raw buffer. */
for !parser.eof &&
len(parser.raw_buffer)-parser.raw_buffer_pos < 3 {
if !yaml_parser_update_raw_buffer(parser) {
return false
}
}
/* Determine the encoding. */
raw := parser.raw_buffer
pos := parser.raw_buffer_pos
remaining := len(raw) - pos
if remaining >= 2 &&
raw[pos] == BOM_UTF16LE[0] && raw[pos+1] == BOM_UTF16LE[1] {
parser.encoding = yaml_UTF16LE_ENCODING
parser.raw_buffer_pos += 2
parser.offset += 2
} else if remaining >= 2 &&
raw[pos] == BOM_UTF16BE[0] && raw[pos+1] == BOM_UTF16BE[1] {
parser.encoding = yaml_UTF16BE_ENCODING
parser.raw_buffer_pos += 2
parser.offset += 2
} else if remaining >= 3 &&
raw[pos] == BOM_UTF8[0] && raw[pos+1] == BOM_UTF8[1] && raw[pos+2] == BOM_UTF8[2] {
parser.encoding = yaml_UTF8_ENCODING
parser.raw_buffer_pos += 3
parser.offset += 3
} else {
parser.encoding = yaml_UTF8_ENCODING
}
return true
}
/*
* Update the raw buffer.
*/
func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool {
size_read := 0
/* Return if the raw buffer is full. */
if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) {
return true
}
/* Return on EOF. */
if parser.eof {
return true
}
/* Move the remaining bytes in the raw buffer to the beginning. */
if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) {
copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:])
}
parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos]
parser.raw_buffer_pos = 0
/* Call the read handler to fill the buffer. */
size_read, err := parser.read_handler(parser,
parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)])
parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read]
if err == io.EOF {
parser.eof = true
} else if err != nil {
return yaml_parser_set_reader_error(parser, "input error: "+err.Error(),
parser.offset, -1)
}
return true
}
/*
* Ensure that the buffer contains at least `length` characters.
* Return 1 on success, 0 on failure.
*
* The length is supposed to be significantly less that the buffer size.
*/
func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
/* Read handler must be set. */
if parser.read_handler == nil {
panic("read handler must be set")
}
/* If the EOF flag is set and the raw buffer is empty, do nothing. */
if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
return true
}
/* Return if the buffer contains enough characters. */
if parser.unread >= length {
return true
}
/* Determine the input encoding if it is not known yet. */
if parser.encoding == yaml_ANY_ENCODING {
if !yaml_parser_determine_encoding(parser) {
return false
}
}
/* Move the unread characters to the beginning of the buffer. */
buffer_end := len(parser.buffer)
if 0 < parser.buffer_pos &&
parser.buffer_pos < buffer_end {
copy(parser.buffer, parser.buffer[parser.buffer_pos:])
buffer_end -= parser.buffer_pos
parser.buffer_pos = 0
} else if parser.buffer_pos == buffer_end {
buffer_end = 0
parser.buffer_pos = 0
}
parser.buffer = parser.buffer[:cap(parser.buffer)]
/* Fill the buffer until it has enough characters. */
first := true
for parser.unread < length {
/* Fill the raw buffer if necessary. */
if !first || parser.raw_buffer_pos == len(parser.raw_buffer) {
if !yaml_parser_update_raw_buffer(parser) {
parser.buffer = parser.buffer[:buffer_end]
return false
}
}
first = false
/* Decode the raw buffer. */
for parser.raw_buffer_pos != len(parser.raw_buffer) {
var value rune
var w int
raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos
incomplete := false
/* Decode the next character. */
switch parser.encoding {
case yaml_UTF8_ENCODING:
/*
* Decode a UTF-8 character. Check RFC 3629
* (http://www.ietf.org/rfc/rfc3629.txt) for more details.
*
* The following table (taken from the RFC) is used for
* decoding.
*
* Char. number range | UTF-8 octet sequence
* (hexadecimal) | (binary)
* --------------------+------------------------------------
* 0000 0000-0000 007F | 0xxxxxxx
* 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
* 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
* 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*
* Additionally, the characters in the range 0xD800-0xDFFF
* are prohibited as they are reserved for use with UTF-16
* surrogate pairs.
*/
/* Determine the length of the UTF-8 sequence. */
octet := parser.raw_buffer[parser.raw_buffer_pos]
w = width(octet)
/* Check if the leading octet is valid. */
if w == 0 {
return yaml_parser_set_reader_error(parser,
"invalid leading UTF-8 octet",
parser.offset, int(octet))
}
/* Check if the raw buffer contains an incomplete character. */
if w > raw_unread {
if parser.eof {
return yaml_parser_set_reader_error(parser,
"incomplete UTF-8 octet sequence",
parser.offset, -1)
}
incomplete = true
break
}
/* Decode the leading octet. */
switch {
case octet&0x80 == 0x00:
value = rune(octet & 0x7F)
case octet&0xE0 == 0xC0:
value = rune(octet & 0x1F)
case octet&0xF0 == 0xE0:
value = rune(octet & 0x0F)
case octet&0xF8 == 0xF0:
value = rune(octet & 0x07)
default:
value = 0
}
/* Check and decode the trailing octets. */
for k := 1; k < w; k++ {
octet = parser.raw_buffer[parser.raw_buffer_pos+k]
/* Check if the octet is valid. */
if (octet & 0xC0) != 0x80 {
return yaml_parser_set_reader_error(parser,
"invalid trailing UTF-8 octet",
parser.offset+k, int(octet))
}
/* Decode the octet. */
value = (value << 6) + rune(octet&0x3F)
}
/* Check the length of the sequence against the value. */
switch {
case w == 1:
case w == 2 && value >= 0x80:
case w == 3 && value >= 0x800:
case w == 4 && value >= 0x10000:
default:
return yaml_parser_set_reader_error(parser,
"invalid length of a UTF-8 sequence",
parser.offset, -1)
}
/* Check the range of the value. */
if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF {
return yaml_parser_set_reader_error(parser,
"invalid Unicode character",
parser.offset, int(value))
}
case yaml_UTF16LE_ENCODING,
yaml_UTF16BE_ENCODING:
var low, high int
if parser.encoding == yaml_UTF16LE_ENCODING {
low, high = 0, 1
} else {
high, low = 1, 0
}
/*
* The UTF-16 encoding is not as simple as one might
* naively think. Check RFC 2781
* (http://www.ietf.org/rfc/rfc2781.txt).
*
* Normally, two subsequent bytes describe a Unicode
* character. However a special technique (called a
* surrogate pair) is used for specifying character
* values larger than 0xFFFF.
*
* A surrogate pair consists of two pseudo-characters:
* high surrogate area (0xD800-0xDBFF)
* low surrogate area (0xDC00-0xDFFF)
*
* The following formulas are used for decoding
* and encoding characters using surrogate pairs:
*
* U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF)
* U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF)
* W1 = 110110yyyyyyyyyy
* W2 = 110111xxxxxxxxxx
*
* where U is the character value, W1 is the high surrogate
* area, W2 is the low surrogate area.
*/
/* Check for incomplete UTF-16 character. */
if raw_unread < 2 {
if parser.eof {
return yaml_parser_set_reader_error(parser,
"incomplete UTF-16 character",
parser.offset, -1)
}
incomplete = true
break
}
/* Get the character. */
value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) +
(rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8)
/* Check for unexpected low surrogate area. */
if (value & 0xFC00) == 0xDC00 {
return yaml_parser_set_reader_error(parser,
"unexpected low surrogate area",
parser.offset, int(value))
}
/* Check for a high surrogate area. */
if (value & 0xFC00) == 0xD800 {
w = 4
/* Check for incomplete surrogate pair. */
if raw_unread < 4 {
if parser.eof {
return yaml_parser_set_reader_error(parser,
"incomplete UTF-16 surrogate pair",
parser.offset, -1)
}
incomplete = true
break
}
/* Get the next character. */
value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) +
(rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8)
/* Check for a low surrogate area. */
if (value2 & 0xFC00) != 0xDC00 {
return yaml_parser_set_reader_error(parser,
"expected low surrogate area",
parser.offset+2, int(value2))
}
/* Generate the value of the surrogate pair. */
value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF)
} else {
w = 2
}
break
default:
panic("Impossible") /* Impossible. */
}
/* Check if the raw buffer contains enough bytes to form a character. */
if incomplete {
break
}
/*
* Check if the character is in the allowed range:
* #x9 | #xA | #xD | [#x20-#x7E] (8 bit)
* | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit)
* | [#x10000-#x10FFFF] (32 bit)
*/
if !(value == 0x09 || value == 0x0A || value == 0x0D ||
(value >= 0x20 && value <= 0x7E) ||
(value == 0x85) || (value >= 0xA0 && value <= 0xD7FF) ||
(value >= 0xE000 && value <= 0xFFFD) ||
(value >= 0x10000 && value <= 0x10FFFF)) {
return yaml_parser_set_reader_error(parser,
"control characters are not allowed",
parser.offset, int(value))
}
/* Move the raw pointers. */
parser.raw_buffer_pos += w
parser.offset += w
/* Finally put the character into the buffer. */
/* 0000 0000-0000 007F . 0xxxxxxx */
if value <= 0x7F {
parser.buffer[buffer_end] = byte(value)
} else if value <= 0x7FF {
/* 0000 0080-0000 07FF . 110xxxxx 10xxxxxx */
parser.buffer[buffer_end] = byte(0xC0 + (value >> 6))
parser.buffer[buffer_end+1] = byte(0x80 + (value & 0x3F))
} else if value <= 0xFFFF {
/* 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx */
parser.buffer[buffer_end] = byte(0xE0 + (value >> 12))
parser.buffer[buffer_end+1] = byte(0x80 + ((value >> 6) & 0x3F))
parser.buffer[buffer_end+2] = byte(0x80 + (value & 0x3F))
} else {
/* 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
parser.buffer[buffer_end] = byte(0xF0 + (value >> 18))
parser.buffer[buffer_end+1] = byte(0x80 + ((value >> 12) & 0x3F))
parser.buffer[buffer_end+2] = byte(0x80 + ((value >> 6) & 0x3F))
parser.buffer[buffer_end+3] = byte(0x80 + (value & 0x3F))
}
buffer_end += w
parser.unread++
}
/* On EOF, put NUL into the buffer and return. */
if parser.eof {
parser.buffer[buffer_end] = 0
buffer_end++
parser.buffer = parser.buffer[:buffer_end]
parser.unread++
return true
}
}
parser.buffer = parser.buffer[:buffer_end]
return true
}

View File

@ -1,449 +0,0 @@
/*
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 candiedyaml
import (
"bytes"
"encoding/base64"
"fmt"
"math"
"reflect"
"regexp"
"strconv"
"strings"
"time"
)
var byteSliceType = reflect.TypeOf([]byte(nil))
var binary_tags = [][]byte{[]byte("!binary"), []byte(yaml_BINARY_TAG)}
var bool_values map[string]bool
var null_values map[string]bool
var signs = []byte{'-', '+'}
var nulls = []byte{'~', 'n', 'N'}
var bools = []byte{'t', 'T', 'f', 'F', 'y', 'Y', 'n', 'N', 'o', 'O'}
var timestamp_regexp *regexp.Regexp
var ymd_regexp *regexp.Regexp
func init() {
bool_values = make(map[string]bool)
bool_values["y"] = true
bool_values["yes"] = true
bool_values["n"] = false
bool_values["no"] = false
bool_values["true"] = true
bool_values["false"] = false
bool_values["on"] = true
bool_values["off"] = false
null_values = make(map[string]bool)
null_values["~"] = true
null_values["null"] = true
null_values["Null"] = true
null_values["NULL"] = true
timestamp_regexp = regexp.MustCompile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:(?:[Tt]|[ \t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \t]*(?:Z|([-+][0-9][0-9]?)(?::([0-9][0-9])?)?))?)?$")
ymd_regexp = regexp.MustCompile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$")
}
func resolve(event yaml_event_t, v reflect.Value, useNumber bool) (string, error) {
val := string(event.value)
if null_values[val] {
v.Set(reflect.Zero(v.Type()))
return yaml_NULL_TAG, nil
}
switch v.Kind() {
case reflect.String:
if useNumber && v.Type() == numberType {
tag, i := resolveInterface(event, useNumber)
if n, ok := i.(Number); ok {
v.Set(reflect.ValueOf(n))
return tag, nil
}
return "", fmt.Errorf("Not a number: '%s' at %s", event.value, event.start_mark)
}
return resolve_string(val, v, event)
case reflect.Bool:
return resolve_bool(val, v, event)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return resolve_int(val, v, useNumber, event)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return resolve_uint(val, v, useNumber, event)
case reflect.Float32, reflect.Float64:
return resolve_float(val, v, useNumber, event)
case reflect.Interface:
_, i := resolveInterface(event, useNumber)
if i != nil {
v.Set(reflect.ValueOf(i))
} else {
v.Set(reflect.Zero(v.Type()))
}
case reflect.Struct:
return resolve_time(val, v, event)
case reflect.Slice:
if v.Type() != byteSliceType {
return "", fmt.Errorf("Cannot resolve %s into %s at %s", val, v.String(), event.start_mark)
}
b, err := decode_binary(event.value, event)
if err != nil {
return "", err
}
v.Set(reflect.ValueOf(b))
default:
return "", fmt.Errorf("Unknown resolution for '%s' using %s at %s", val, v.String(), event.start_mark)
}
return yaml_STR_TAG, nil
}
func hasBinaryTag(event yaml_event_t) bool {
for _, tag := range binary_tags {
if bytes.Equal(event.tag, tag) {
return true
}
}
return false
}
func decode_binary(value []byte, event yaml_event_t) ([]byte, error) {
b := make([]byte, base64.StdEncoding.DecodedLen(len(value)))
n, err := base64.StdEncoding.Decode(b, value)
if err != nil {
return nil, fmt.Errorf("Invalid base64 text: '%s' at %s", string(b), event.start_mark)
}
return b[:n], nil
}
func resolve_string(val string, v reflect.Value, event yaml_event_t) (string, error) {
if len(event.tag) > 0 {
if hasBinaryTag(event) {
b, err := decode_binary(event.value, event)
if err != nil {
return "", err
}
val = string(b)
}
}
v.SetString(val)
return yaml_STR_TAG, nil
}
func resolve_bool(val string, v reflect.Value, event yaml_event_t) (string, error) {
b, found := bool_values[strings.ToLower(val)]
if !found {
return "", fmt.Errorf("Invalid boolean: '%s' at %s", val, event.start_mark)
}
v.SetBool(b)
return yaml_BOOL_TAG, nil
}
func resolve_int(val string, v reflect.Value, useNumber bool, event yaml_event_t) (string, error) {
original := val
val = strings.Replace(val, "_", "", -1)
var value uint64
isNumberValue := v.Type() == numberType
sign := int64(1)
if val[0] == '-' {
sign = -1
val = val[1:]
} else if val[0] == '+' {
val = val[1:]
}
base := 0
if val == "0" {
if isNumberValue {
v.SetString("0")
} else {
v.Set(reflect.Zero(v.Type()))
}
return yaml_INT_TAG, nil
}
if strings.HasPrefix(val, "0o") {
base = 8
val = val[2:]
}
value, err := strconv.ParseUint(val, base, 64)
if err != nil {
return "", fmt.Errorf("Invalid integer: '%s' at %s", original, event.start_mark)
}
var val64 int64
if value <= math.MaxInt64 {
val64 = int64(value)
if sign == -1 {
val64 = -val64
}
} else if sign == -1 && value == uint64(math.MaxInt64)+1 {
val64 = math.MinInt64
} else {
return "", fmt.Errorf("Invalid integer: '%s' at %s", original, event.start_mark)
}
if isNumberValue {
v.SetString(strconv.FormatInt(val64, 10))
} else {
if v.OverflowInt(val64) {
return "", fmt.Errorf("Invalid integer: '%s' at %s", original, event.start_mark)
}
v.SetInt(val64)
}
return yaml_INT_TAG, nil
}
func resolve_uint(val string, v reflect.Value, useNumber bool, event yaml_event_t) (string, error) {
original := val
val = strings.Replace(val, "_", "", -1)
var value uint64
isNumberValue := v.Type() == numberType
if val[0] == '-' {
return "", fmt.Errorf("Unsigned int with negative value: '%s' at %s", original, event.start_mark)
}
if val[0] == '+' {
val = val[1:]
}
base := 0
if val == "0" {
if isNumberValue {
v.SetString("0")
} else {
v.Set(reflect.Zero(v.Type()))
}
return yaml_INT_TAG, nil
}
if strings.HasPrefix(val, "0o") {
base = 8
val = val[2:]
}
value, err := strconv.ParseUint(val, base, 64)
if err != nil {
return "", fmt.Errorf("Invalid unsigned integer: '%s' at %s", val, event.start_mark)
}
if isNumberValue {
v.SetString(strconv.FormatUint(value, 10))
} else {
if v.OverflowUint(value) {
return "", fmt.Errorf("Invalid unsigned integer: '%s' at %s", val, event.start_mark)
}
v.SetUint(value)
}
return yaml_INT_TAG, nil
}
func resolve_float(val string, v reflect.Value, useNumber bool, event yaml_event_t) (string, error) {
val = strings.Replace(val, "_", "", -1)
var value float64
isNumberValue := v.Type() == numberType
typeBits := 64
if !isNumberValue {
typeBits = v.Type().Bits()
}
sign := 1
if val[0] == '-' {
sign = -1
val = val[1:]
} else if val[0] == '+' {
val = val[1:]
}
valLower := strings.ToLower(val)
if valLower == ".inf" {
value = math.Inf(sign)
} else if valLower == ".nan" {
value = math.NaN()
} else {
var err error
value, err = strconv.ParseFloat(val, typeBits)
value *= float64(sign)
if err != nil {
return "", fmt.Errorf("Invalid float: '%s' at %s", val, event.start_mark)
}
}
if isNumberValue {
v.SetString(strconv.FormatFloat(value, 'g', -1, typeBits))
} else {
if v.OverflowFloat(value) {
return "", fmt.Errorf("Invalid float: '%s' at %s", val, event.start_mark)
}
v.SetFloat(value)
}
return yaml_FLOAT_TAG, nil
}
func resolve_time(val string, v reflect.Value, event yaml_event_t) (string, error) {
var parsedTime time.Time
matches := ymd_regexp.FindStringSubmatch(val)
if len(matches) > 0 {
year, _ := strconv.Atoi(matches[1])
month, _ := strconv.Atoi(matches[2])
day, _ := strconv.Atoi(matches[3])
parsedTime = time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
} else {
matches = timestamp_regexp.FindStringSubmatch(val)
if len(matches) == 0 {
return "", fmt.Errorf("Invalid timestamp: '%s' at %s", val, event.start_mark)
}
year, _ := strconv.Atoi(matches[1])
month, _ := strconv.Atoi(matches[2])
day, _ := strconv.Atoi(matches[3])
hour, _ := strconv.Atoi(matches[4])
min, _ := strconv.Atoi(matches[5])
sec, _ := strconv.Atoi(matches[6])
nsec := 0
if matches[7] != "" {
millis, _ := strconv.Atoi(matches[7])
nsec = int(time.Duration(millis) * time.Millisecond)
}
loc := time.UTC
if matches[8] != "" {
sign := matches[8][0]
hr, _ := strconv.Atoi(matches[8][1:])
min := 0
if matches[9] != "" {
min, _ = strconv.Atoi(matches[9])
}
zoneOffset := (hr*60 + min) * 60
if sign == '-' {
zoneOffset = -zoneOffset
}
loc = time.FixedZone("", zoneOffset)
}
parsedTime = time.Date(year, time.Month(month), day, hour, min, sec, nsec, loc)
}
v.Set(reflect.ValueOf(parsedTime))
return "", nil
}
func resolveInterface(event yaml_event_t, useNumber bool) (string, interface{}) {
val := string(event.value)
if len(event.tag) == 0 && !event.implicit {
return "", val
}
if len(val) == 0 {
return yaml_NULL_TAG, nil
}
var result interface{}
sign := false
c := val[0]
switch {
case bytes.IndexByte(signs, c) != -1:
sign = true
fallthrough
case c >= '0' && c <= '9':
i := int64(0)
result = &i
if useNumber {
var n Number
result = &n
}
v := reflect.ValueOf(result).Elem()
if _, err := resolve_int(val, v, useNumber, event); err == nil {
return yaml_INT_TAG, v.Interface()
}
f := float64(0)
result = &f
if useNumber {
var n Number
result = &n
}
v = reflect.ValueOf(result).Elem()
if _, err := resolve_float(val, v, useNumber, event); err == nil {
return yaml_FLOAT_TAG, v.Interface()
}
if !sign {
t := time.Time{}
if _, err := resolve_time(val, reflect.ValueOf(&t).Elem(), event); err == nil {
return "", t
}
}
case bytes.IndexByte(nulls, c) != -1:
if null_values[val] {
return yaml_NULL_TAG, nil
}
b := false
if _, err := resolve_bool(val, reflect.ValueOf(&b).Elem(), event); err == nil {
return yaml_BOOL_TAG, b
}
case c == '.':
f := float64(0)
result = &f
if useNumber {
var n Number
result = &n
}
v := reflect.ValueOf(result).Elem()
if _, err := resolve_float(val, v, useNumber, event); err == nil {
return yaml_FLOAT_TAG, v.Interface()
}
case bytes.IndexByte(bools, c) != -1:
b := false
if _, err := resolve_bool(val, reflect.ValueOf(&b).Elem(), event); err == nil {
return yaml_BOOL_TAG, b
}
}
if hasBinaryTag(event) {
bytes, err := decode_binary(event.value, event)
if err == nil {
return yaml_BINARY_TAG, bytes
}
}
return yaml_STR_TAG, val
}

View File

@ -1,62 +0,0 @@
/*
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 candiedyaml
import (
"fmt"
"os"
)
func Run_parser(cmd string, args []string) {
for i := 0; i < len(args); i++ {
fmt.Printf("[%d] Scanning '%s'", i, args[i])
file, err := os.Open(args[i])
if err != nil {
panic(fmt.Sprintf("Invalid file '%s': %s", args[i], err.Error()))
}
parser := yaml_parser_t{}
yaml_parser_initialize(&parser)
yaml_parser_set_input_reader(&parser, file)
failed := false
token := yaml_token_t{}
count := 0
for {
if !yaml_parser_scan(&parser, &token) {
failed = true
break
}
if token.token_type == yaml_STREAM_END_TOKEN {
break
}
count++
}
file.Close()
msg := "SUCCESS"
if failed {
msg = "FAILED"
if parser.error != yaml_NO_ERROR {
m := parser.problem_mark
fmt.Printf("ERROR: (%s) %s @ line: %d col: %d\n",
parser.context, parser.problem, m.line, m.column)
}
}
fmt.Printf("%s (%d tokens)\n", msg, count)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,360 +0,0 @@
/*
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 candiedyaml
import (
"reflect"
"sort"
"strings"
"sync"
"unicode"
)
// A field represents a single field found in a struct.
type field struct {
name string
tag bool
index []int
typ reflect.Type
omitEmpty bool
flow bool
}
// byName sorts field by name, breaking ties with depth,
// then breaking ties with "name came from json tag", then
// breaking ties with index sequence.
type byName []field
func (x byName) Len() int { return len(x) }
func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byName) Less(i, j int) bool {
if x[i].name != x[j].name {
return x[i].name < x[j].name
}
if len(x[i].index) != len(x[j].index) {
return len(x[i].index) < len(x[j].index)
}
if x[i].tag != x[j].tag {
return x[i].tag
}
return byIndex(x).Less(i, j)
}
// byIndex sorts field by index sequence.
type byIndex []field
func (x byIndex) Len() int { return len(x) }
func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byIndex) Less(i, j int) bool {
for k, xik := range x[i].index {
if k >= len(x[j].index) {
return false
}
if xik != x[j].index[k] {
return xik < x[j].index[k]
}
}
return len(x[i].index) < len(x[j].index)
}
// typeFields returns a list of fields that JSON should recognize for the given type.
// The algorithm is breadth-first search over the set of structs to include - the top struct
// and then any reachable anonymous structs.
func typeFields(t reflect.Type) []field {
// Anonymous fields to explore at the current level and the next.
current := []field{}
next := []field{{typ: t}}
// Count of queued names for current level and the next.
count := map[reflect.Type]int{}
nextCount := map[reflect.Type]int{}
// Types already visited at an earlier level.
visited := map[reflect.Type]bool{}
// Fields found.
var fields []field
for len(next) > 0 {
current, next = next, current[:0]
count, nextCount = nextCount, map[reflect.Type]int{}
for _, f := range current {
if visited[f.typ] {
continue
}
visited[f.typ] = true
// Scan f.typ for fields to include.
for i := 0; i < f.typ.NumField(); i++ {
sf := f.typ.Field(i)
if sf.PkgPath != "" { // unexported
continue
}
tag := sf.Tag.Get("yaml")
if tag == "-" {
continue
}
name, opts := parseTag(tag)
if !isValidTag(name) {
name = ""
}
index := make([]int, len(f.index)+1)
copy(index, f.index)
index[len(f.index)] = i
ft := sf.Type
if ft.Name() == "" && ft.Kind() == reflect.Ptr {
// Follow pointer.
ft = ft.Elem()
}
// Record found field and index sequence.
if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
tagged := name != ""
if name == "" {
name = sf.Name
}
fields = append(fields, field{name, tagged, index, ft,
opts.Contains("omitempty"), opts.Contains("flow")})
if count[f.typ] > 1 {
// If there were multiple instances, add a second,
// so that the annihilation code will see a duplicate.
// It only cares about the distinction between 1 or 2,
// so don't bother generating any more copies.
fields = append(fields, fields[len(fields)-1])
}
continue
}
// Record new anonymous struct to explore in next round.
nextCount[ft]++
if nextCount[ft] == 1 {
next = append(next, field{name: ft.Name(), index: index, typ: ft})
}
}
}
}
sort.Sort(byName(fields))
// Delete all fields that are hidden by the Go rules for embedded fields,
// except that fields with JSON tags are promoted.
// The fields are sorted in primary order of name, secondary order
// of field index length. Loop over names; for each name, delete
// hidden fields by choosing the one dominant field that survives.
out := fields[:0]
for advance, i := 0, 0; i < len(fields); i += advance {
// One iteration per name.
// Find the sequence of fields with the name of this first field.
fi := fields[i]
name := fi.name
for advance = 1; i+advance < len(fields); advance++ {
fj := fields[i+advance]
if fj.name != name {
break
}
}
if advance == 1 { // Only one field with this name
out = append(out, fi)
continue
}
dominant, ok := dominantField(fields[i : i+advance])
if ok {
out = append(out, dominant)
}
}
fields = out
sort.Sort(byIndex(fields))
return fields
}
// dominantField looks through the fields, all of which are known to
// have the same name, to find the single field that dominates the
// others using Go's embedding rules, modified by the presence of
// JSON tags. If there are multiple top-level fields, the boolean
// will be false: This condition is an error in Go and we skip all
// the fields.
func dominantField(fields []field) (field, bool) {
// The fields are sorted in increasing index-length order. The winner
// must therefore be one with the shortest index length. Drop all
// longer entries, which is easy: just truncate the slice.
length := len(fields[0].index)
tagged := -1 // Index of first tagged field.
for i, f := range fields {
if len(f.index) > length {
fields = fields[:i]
break
}
if f.tag {
if tagged >= 0 {
// Multiple tagged fields at the same level: conflict.
// Return no field.
return field{}, false
}
tagged = i
}
}
if tagged >= 0 {
return fields[tagged], true
}
// All remaining fields have the same length. If there's more than one,
// we have a conflict (two fields named "X" at the same level) and we
// return no field.
if len(fields) > 1 {
return field{}, false
}
return fields[0], true
}
var fieldCache struct {
sync.RWMutex
m map[reflect.Type][]field
}
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
func cachedTypeFields(t reflect.Type) []field {
fieldCache.RLock()
f := fieldCache.m[t]
fieldCache.RUnlock()
if f != nil {
return f
}
// Compute fields without lock.
// Might duplicate effort but won't hold other computations back.
f = typeFields(t)
if f == nil {
f = []field{}
}
fieldCache.Lock()
if fieldCache.m == nil {
fieldCache.m = map[reflect.Type][]field{}
}
fieldCache.m[t] = f
fieldCache.Unlock()
return f
}
// tagOptions is the string following a comma in a struct field's "json"
// tag, or the empty string. It does not include the leading comma.
type tagOptions string
func isValidTag(s string) bool {
if s == "" {
return false
}
for _, c := range s {
switch {
case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
// Backslash and quote chars are reserved, but
// otherwise any punctuation chars are allowed
// in a tag name.
default:
if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
return false
}
}
}
return true
}
func fieldByIndex(v reflect.Value, index []int) reflect.Value {
for _, i := range index {
if v.Kind() == reflect.Ptr {
if v.IsNil() {
return reflect.Value{}
}
v = v.Elem()
}
v = v.Field(i)
}
return v
}
func typeByIndex(t reflect.Type, index []int) reflect.Type {
for _, i := range index {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
t = t.Field(i).Type
}
return t
}
// stringValues is a slice of reflect.Value holding *reflect.StringValue.
// It implements the methods to sort by string.
type stringValues []reflect.Value
func (sv stringValues) Len() int { return len(sv) }
func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
func (sv stringValues) Less(i, j int) bool {
av, ak := getElem(sv[i])
bv, bk := getElem(sv[j])
if ak == reflect.String && bk == reflect.String {
return av.String() < bv.String()
}
return ak < bk
}
func getElem(v reflect.Value) (reflect.Value, reflect.Kind) {
k := v.Kind()
for k == reflect.Interface || k == reflect.Ptr && !v.IsNil() {
v = v.Elem()
k = v.Kind()
}
return v, k
}
// parseTag splits a struct field's json tag into its name and
// comma-separated options.
func parseTag(tag string) (string, tagOptions) {
if idx := strings.Index(tag, ","); idx != -1 {
return tag[:idx], tagOptions(tag[idx+1:])
}
return tag, tagOptions("")
}
// Contains reports whether a comma-separated list of options
// contains a particular substr flag. substr must be surrounded by a
// string boundary or commas.
func (o tagOptions) Contains(optionName string) bool {
if len(o) == 0 {
return false
}
s := string(o)
for s != "" {
var next string
i := strings.Index(s, ",")
if i >= 0 {
s, next = s[:i], s[i+1:]
}
if s == optionName {
return true
}
s = next
}
return false
}

View File

@ -1,128 +0,0 @@
/*
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 candiedyaml
/*
* Set the writer error and return 0.
*/
func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool {
emitter.error = yaml_WRITER_ERROR
emitter.problem = problem
return false
}
/*
* Flush the output buffer.
*/
func yaml_emitter_flush(emitter *yaml_emitter_t) bool {
if emitter.write_handler == nil {
panic("Write handler must be set") /* Write handler must be set. */
}
if emitter.encoding == yaml_ANY_ENCODING {
panic("Encoding must be set") /* Output encoding must be set. */
}
/* Check if the buffer is empty. */
if emitter.buffer_pos == 0 {
return true
}
/* If the output encoding is UTF-8, we don't need to recode the buffer. */
if emitter.encoding == yaml_UTF8_ENCODING {
if err := emitter.write_handler(emitter,
emitter.buffer[:emitter.buffer_pos]); err != nil {
return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
}
emitter.buffer_pos = 0
return true
}
/* Recode the buffer into the raw buffer. */
var low, high int
if emitter.encoding == yaml_UTF16LE_ENCODING {
low, high = 0, 1
} else {
high, low = 1, 0
}
pos := 0
for pos < emitter.buffer_pos {
/*
* See the "reader.c" code for more details on UTF-8 encoding. Note
* that we assume that the buffer contains a valid UTF-8 sequence.
*/
/* Read the next UTF-8 character. */
octet := emitter.buffer[pos]
var w int
var value rune
switch {
case octet&0x80 == 0x00:
w, value = 1, rune(octet&0x7F)
case octet&0xE0 == 0xC0:
w, value = 2, rune(octet&0x1F)
case octet&0xF0 == 0xE0:
w, value = 3, rune(octet&0x0F)
case octet&0xF8 == 0xF0:
w, value = 4, rune(octet&0x07)
}
for k := 1; k < w; k++ {
octet = emitter.buffer[pos+k]
value = (value << 6) + (rune(octet) & 0x3F)
}
pos += w
/* Write the character. */
if value < 0x10000 {
var b [2]byte
b[high] = byte(value >> 8)
b[low] = byte(value & 0xFF)
emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1])
} else {
/* Write the character using a surrogate pair (check "reader.c"). */
var b [4]byte
value -= 0x10000
b[high] = byte(0xD8 + (value >> 18))
b[low] = byte((value >> 10) & 0xFF)
b[high+2] = byte(0xDC + ((value >> 8) & 0xFF))
b[low+2] = byte(value & 0xFF)
emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1], b[2], b[3])
}
}
/* Write the raw buffer. */
// Write the raw buffer.
if err := emitter.write_handler(emitter, emitter.raw_buffer); err != nil {
return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
}
emitter.buffer_pos = 0
emitter.raw_buffer = emitter.raw_buffer[:0]
return true
}

View File

@ -1,22 +0,0 @@
/*
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 candiedyaml
const (
yaml_VERSION_MAJOR = 0
yaml_VERSION_MINOR = 1
yaml_VERSION_PATCH = 6
yaml_VERSION_STRING = "0.1.6"
)

View File

@ -1,891 +0,0 @@
/*
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 candiedyaml
const (
INPUT_RAW_BUFFER_SIZE = 1024
/*
* The size of the input buffer.
*
* It should be possible to decode the whole raw buffer.
*/
INPUT_BUFFER_SIZE = (INPUT_RAW_BUFFER_SIZE * 3)
/*
* The size of the output buffer.
*/
OUTPUT_BUFFER_SIZE = 512
/*
* The size of the output raw buffer.
*
* It should be possible to encode the whole output buffer.
*/
OUTPUT_RAW_BUFFER_SIZE = (OUTPUT_BUFFER_SIZE*2 + 2)
INITIAL_STACK_SIZE = 16
INITIAL_QUEUE_SIZE = 16
)
func width(b byte) int {
if b&0x80 == 0 {
return 1
}
if b&0xE0 == 0xC0 {
return 2
}
if b&0xF0 == 0xE0 {
return 3
}
if b&0xF8 == 0xF0 {
return 4
}
return 0
}
func copy_bytes(dest []byte, dest_pos *int, src []byte, src_pos *int) {
w := width(src[*src_pos])
switch w {
case 4:
dest[*dest_pos+3] = src[*src_pos+3]
fallthrough
case 3:
dest[*dest_pos+2] = src[*src_pos+2]
fallthrough
case 2:
dest[*dest_pos+1] = src[*src_pos+1]
fallthrough
case 1:
dest[*dest_pos] = src[*src_pos]
default:
panic("invalid width")
}
*dest_pos += w
*src_pos += w
}
// /*
// * Check if the character at the specified position is an alphabetical
// * character, a digit, '_', or '-'.
// */
func is_alpha(b byte) bool {
return (b >= '0' && b <= '9') ||
(b >= 'A' && b <= 'Z') ||
(b >= 'a' && b <= 'z') ||
b == '_' || b == '-'
}
// /*
// * Check if the character at the specified position is a digit.
// */
//
func is_digit(b byte) bool {
return b >= '0' && b <= '9'
}
// /*
// * Get the value of a digit.
// */
//
func as_digit(b byte) int {
return int(b) - '0'
}
// /*
// * Check if the character at the specified position is a hex-digit.
// */
//
func is_hex(b byte) bool {
return (b >= '0' && b <= '9') ||
(b >= 'A' && b <= 'F') ||
(b >= 'a' && b <= 'f')
}
//
// /*
// * Get the value of a hex-digit.
// */
//
func as_hex(b byte) int {
if b >= 'A' && b <= 'F' {
return int(b) - 'A' + 10
} else if b >= 'a' && b <= 'f' {
return int(b) - 'a' + 10
}
return int(b) - '0'
}
// #define AS_HEX_AT(string,offset) \
// (((string).pointer[offset] >= (yaml_char_t) 'A' && \
// (string).pointer[offset] <= (yaml_char_t) 'F') ? \
// ((string).pointer[offset] - (yaml_char_t) 'A' + 10) : \
// ((string).pointer[offset] >= (yaml_char_t) 'a' && \
// (string).pointer[offset] <= (yaml_char_t) 'f') ? \
// ((string).pointer[offset] - (yaml_char_t) 'a' + 10) : \
// ((string).pointer[offset] - (yaml_char_t) '0'))
// /*
// * Check if the character is a line break, space, tab, or NUL.
// */
func is_blankz_at(b []byte, i int) bool {
return is_blank(b[i]) || is_breakz_at(b, i)
}
// /*
// * Check if the character at the specified position is a line break.
// */
func is_break_at(b []byte, i int) bool {
return b[i] == '\r' || /* CR (#xD)*/
b[i] == '\n' || /* LF (#xA) */
(b[i] == 0xC2 && b[i+1] == 0x85) || /* NEL (#x85) */
(b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8) || /* LS (#x2028) */
(b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) /* PS (#x2029) */
}
func is_breakz_at(b []byte, i int) bool {
return is_break_at(b, i) || is_z(b[i])
}
func is_crlf_at(b []byte, i int) bool {
return b[i] == '\r' && b[i+1] == '\n'
}
// /*
// * Check if the character at the specified position is NUL.
// */
func is_z(b byte) bool {
return b == 0x0
}
// /*
// * Check if the character at the specified position is space.
// */
func is_space(b byte) bool {
return b == ' '
}
//
// /*
// * Check if the character at the specified position is tab.
// */
func is_tab(b byte) bool {
return b == '\t'
}
// /*
// * Check if the character at the specified position is blank (space or tab).
// */
func is_blank(b byte) bool {
return is_space(b) || is_tab(b)
}
// /*
// * Check if the character is ASCII.
// */
func is_ascii(b byte) bool {
return b <= '\x7f'
}
// /*
// * Check if the character can be printed unescaped.
// */
func is_printable_at(b []byte, i int) bool {
return ((b[i] == 0x0A) || /* . == #x0A */
(b[i] >= 0x20 && b[i] <= 0x7E) || /* #x20 <= . <= #x7E */
(b[i] == 0xC2 && b[i+1] >= 0xA0) || /* #0xA0 <= . <= #xD7FF */
(b[i] > 0xC2 && b[i] < 0xED) ||
(b[i] == 0xED && b[i+1] < 0xA0) ||
(b[i] == 0xEE) ||
(b[i] == 0xEF && /* && . != #xFEFF */
!(b[i+1] == 0xBB && b[i+2] == 0xBF) &&
!(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF))))
}
func insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
// collapse the slice
if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
if parser.tokens_head != len(parser.tokens) {
// move the tokens down
copy(parser.tokens, parser.tokens[parser.tokens_head:])
}
// readjust the length
parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
parser.tokens_head = 0
}
parser.tokens = append(parser.tokens, *token)
if pos < 0 {
return
}
copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
parser.tokens[parser.tokens_head+pos] = *token
}
// /*
// * Check if the character at the specified position is BOM.
// */
//
func is_bom_at(b []byte, i int) bool {
return b[i] == 0xEF && b[i+1] == 0xBB && b[i+2] == 0xBF
}
//
// #ifdef HAVE_CONFIG_H
// #include <config.h>
// #endif
//
// #include "./yaml.h"
//
// #include <assert.h>
// #include <limits.h>
//
// /*
// * Memory management.
// */
//
// yaml_DECLARE(void *)
// yaml_malloc(size_t size);
//
// yaml_DECLARE(void *)
// yaml_realloc(void *ptr, size_t size);
//
// yaml_DECLARE(void)
// yaml_free(void *ptr);
//
// yaml_DECLARE(yaml_char_t *)
// yaml_strdup(const yaml_char_t *);
//
// /*
// * Reader: Ensure that the buffer contains at least `length` characters.
// */
//
// yaml_DECLARE(int)
// yaml_parser_update_buffer(yaml_parser_t *parser, size_t length);
//
// /*
// * Scanner: Ensure that the token stack contains at least one token ready.
// */
//
// yaml_DECLARE(int)
// yaml_parser_fetch_more_tokens(yaml_parser_t *parser);
//
// /*
// * The size of the input raw buffer.
// */
//
// #define INPUT_RAW_BUFFER_SIZE 16384
//
// /*
// * The size of the input buffer.
// *
// * It should be possible to decode the whole raw buffer.
// */
//
// #define INPUT_BUFFER_SIZE (INPUT_RAW_BUFFER_SIZE*3)
//
// /*
// * The size of the output buffer.
// */
//
// #define OUTPUT_BUFFER_SIZE 16384
//
// /*
// * The size of the output raw buffer.
// *
// * It should be possible to encode the whole output buffer.
// */
//
// #define OUTPUT_RAW_BUFFER_SIZE (OUTPUT_BUFFER_SIZE*2+2)
//
// /*
// * The size of other stacks and queues.
// */
//
// #define INITIAL_STACK_SIZE 16
// #define INITIAL_QUEUE_SIZE 16
// #define INITIAL_STRING_SIZE 16
//
// /*
// * Buffer management.
// */
//
// #define BUFFER_INIT(context,buffer,size) \
// (((buffer).start = yaml_malloc(size)) ? \
// ((buffer).last = (buffer).pointer = (buffer).start, \
// (buffer).end = (buffer).start+(size), \
// 1) : \
// ((context)->error = yaml_MEMORY_ERROR, \
// 0))
//
// #define BUFFER_DEL(context,buffer) \
// (yaml_free((buffer).start), \
// (buffer).start = (buffer).pointer = (buffer).end = 0)
//
// /*
// * String management.
// */
//
// typedef struct {
// yaml_char_t *start;
// yaml_char_t *end;
// yaml_char_t *pointer;
// } yaml_string_t;
//
// yaml_DECLARE(int)
// yaml_string_extend(yaml_char_t **start,
// yaml_char_t **pointer, yaml_char_t **end);
//
// yaml_DECLARE(int)
// yaml_string_join(
// yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end,
// yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end);
//
// #define NULL_STRING { NULL, NULL, NULL }
//
// #define STRING(string,length) { (string), (string)+(length), (string) }
//
// #define STRING_ASSIGN(value,string,length) \
// ((value).start = (string), \
// (value).end = (string)+(length), \
// (value).pointer = (string))
//
// #define STRING_INIT(context,string,size) \
// (((string).start = yaml_malloc(size)) ? \
// ((string).pointer = (string).start, \
// (string).end = (string).start+(size), \
// memset((string).start, 0, (size)), \
// 1) : \
// ((context)->error = yaml_MEMORY_ERROR, \
// 0))
//
// #define STRING_DEL(context,string) \
// (yaml_free((string).start), \
// (string).start = (string).pointer = (string).end = 0)
//
// #define STRING_EXTEND(context,string) \
// (((string).pointer+5 < (string).end) \
// || yaml_string_extend(&(string).start, \
// &(string).pointer, &(string).end))
//
// #define CLEAR(context,string) \
// ((string).pointer = (string).start, \
// memset((string).start, 0, (string).end-(string).start))
//
// #define JOIN(context,string_a,string_b) \
// ((yaml_string_join(&(string_a).start, &(string_a).pointer, \
// &(string_a).end, &(string_b).start, \
// &(string_b).pointer, &(string_b).end)) ? \
// ((string_b).pointer = (string_b).start, \
// 1) : \
// ((context)->error = yaml_MEMORY_ERROR, \
// 0))
//
// /*
// * String check operations.
// */
//
// /*
// * Check the octet at the specified position.
// */
//
// #define CHECK_AT(string,octet,offset) \
// ((string).pointer[offset] == (yaml_char_t)(octet))
//
// /*
// * Check the current octet in the buffer.
// */
//
// #define CHECK(string,octet) CHECK_AT((string),(octet),0)
//
// /*
// * Check if the character at the specified position is an alphabetical
// * character, a digit, '_', or '-'.
// */
//
// #define IS_ALPHA_AT(string,offset) \
// (((string).pointer[offset] >= (yaml_char_t) '0' && \
// (string).pointer[offset] <= (yaml_char_t) '9') || \
// ((string).pointer[offset] >= (yaml_char_t) 'A' && \
// (string).pointer[offset] <= (yaml_char_t) 'Z') || \
// ((string).pointer[offset] >= (yaml_char_t) 'a' && \
// (string).pointer[offset] <= (yaml_char_t) 'z') || \
// (string).pointer[offset] == '_' || \
// (string).pointer[offset] == '-')
//
// #define IS_ALPHA(string) IS_ALPHA_AT((string),0)
//
// /*
// * Check if the character at the specified position is a digit.
// */
//
// #define IS_DIGIT_AT(string,offset) \
// (((string).pointer[offset] >= (yaml_char_t) '0' && \
// (string).pointer[offset] <= (yaml_char_t) '9'))
//
// #define IS_DIGIT(string) IS_DIGIT_AT((string),0)
//
// /*
// * Get the value of a digit.
// */
//
// #define AS_DIGIT_AT(string,offset) \
// ((string).pointer[offset] - (yaml_char_t) '0')
//
// #define AS_DIGIT(string) AS_DIGIT_AT((string),0)
//
// /*
// * Check if the character at the specified position is a hex-digit.
// */
//
// #define IS_HEX_AT(string,offset) \
// (((string).pointer[offset] >= (yaml_char_t) '0' && \
// (string).pointer[offset] <= (yaml_char_t) '9') || \
// ((string).pointer[offset] >= (yaml_char_t) 'A' && \
// (string).pointer[offset] <= (yaml_char_t) 'F') || \
// ((string).pointer[offset] >= (yaml_char_t) 'a' && \
// (string).pointer[offset] <= (yaml_char_t) 'f'))
//
// #define IS_HEX(string) IS_HEX_AT((string),0)
//
// /*
// * Get the value of a hex-digit.
// */
//
// #define AS_HEX_AT(string,offset) \
// (((string).pointer[offset] >= (yaml_char_t) 'A' && \
// (string).pointer[offset] <= (yaml_char_t) 'F') ? \
// ((string).pointer[offset] - (yaml_char_t) 'A' + 10) : \
// ((string).pointer[offset] >= (yaml_char_t) 'a' && \
// (string).pointer[offset] <= (yaml_char_t) 'f') ? \
// ((string).pointer[offset] - (yaml_char_t) 'a' + 10) : \
// ((string).pointer[offset] - (yaml_char_t) '0'))
//
// #define AS_HEX(string) AS_HEX_AT((string),0)
//
// /*
// * Check if the character is ASCII.
// */
//
// #define IS_ASCII_AT(string,offset) \
// ((string).pointer[offset] <= (yaml_char_t) '\x7F')
//
// #define IS_ASCII(string) IS_ASCII_AT((string),0)
//
// /*
// * Check if the character can be printed unescaped.
// */
//
// #define IS_PRINTABLE_AT(string,offset) \
// (((string).pointer[offset] == 0x0A) /* . == #x0A */ \
// || ((string).pointer[offset] >= 0x20 /* #x20 <= . <= #x7E */ \
// && (string).pointer[offset] <= 0x7E) \
// || ((string).pointer[offset] == 0xC2 /* #0xA0 <= . <= #xD7FF */ \
// && (string).pointer[offset+1] >= 0xA0) \
// || ((string).pointer[offset] > 0xC2 \
// && (string).pointer[offset] < 0xED) \
// || ((string).pointer[offset] == 0xED \
// && (string).pointer[offset+1] < 0xA0) \
// || ((string).pointer[offset] == 0xEE) \
// || ((string).pointer[offset] == 0xEF /* #xE000 <= . <= #xFFFD */ \
// && !((string).pointer[offset+1] == 0xBB /* && . != #xFEFF */ \
// && (string).pointer[offset+2] == 0xBF) \
// && !((string).pointer[offset+1] == 0xBF \
// && ((string).pointer[offset+2] == 0xBE \
// || (string).pointer[offset+2] == 0xBF))))
//
// #define IS_PRINTABLE(string) IS_PRINTABLE_AT((string),0)
//
// /*
// * Check if the character at the specified position is NUL.
// */
//
// #define IS_Z_AT(string,offset) CHECK_AT((string),'\0',(offset))
//
// #define IS_Z(string) IS_Z_AT((string),0)
//
// /*
// * Check if the character at the specified position is BOM.
// */
//
// #define IS_BOM_AT(string,offset) \
// (CHECK_AT((string),'\xEF',(offset)) \
// && CHECK_AT((string),'\xBB',(offset)+1) \
// && CHECK_AT((string),'\xBF',(offset)+2)) /* BOM (#xFEFF) */
//
// #define IS_BOM(string) IS_BOM_AT(string,0)
//
// /*
// * Check if the character at the specified position is space.
// */
//
// #define IS_SPACE_AT(string,offset) CHECK_AT((string),' ',(offset))
//
// #define IS_SPACE(string) IS_SPACE_AT((string),0)
//
// /*
// * Check if the character at the specified position is tab.
// */
//
// #define IS_TAB_AT(string,offset) CHECK_AT((string),'\t',(offset))
//
// #define IS_TAB(string) IS_TAB_AT((string),0)
//
// /*
// * Check if the character at the specified position is blank (space or tab).
// */
//
// #define IS_BLANK_AT(string,offset) \
// (IS_SPACE_AT((string),(offset)) || IS_TAB_AT((string),(offset)))
//
// #define IS_BLANK(string) IS_BLANK_AT((string),0)
//
// /*
// * Check if the character at the specified position is a line break.
// */
//
// #define IS_BREAK_AT(string,offset) \
// (CHECK_AT((string),'\r',(offset)) /* CR (#xD)*/ \
// || CHECK_AT((string),'\n',(offset)) /* LF (#xA) */ \
// || (CHECK_AT((string),'\xC2',(offset)) \
// && CHECK_AT((string),'\x85',(offset)+1)) /* NEL (#x85) */ \
// || (CHECK_AT((string),'\xE2',(offset)) \
// && CHECK_AT((string),'\x80',(offset)+1) \
// && CHECK_AT((string),'\xA8',(offset)+2)) /* LS (#x2028) */ \
// || (CHECK_AT((string),'\xE2',(offset)) \
// && CHECK_AT((string),'\x80',(offset)+1) \
// && CHECK_AT((string),'\xA9',(offset)+2))) /* PS (#x2029) */
//
// #define IS_BREAK(string) IS_BREAK_AT((string),0)
//
// #define IS_CRLF_AT(string,offset) \
// (CHECK_AT((string),'\r',(offset)) && CHECK_AT((string),'\n',(offset)+1))
//
// #define IS_CRLF(string) IS_CRLF_AT((string),0)
//
// /*
// * Check if the character is a line break or NUL.
// */
//
// #define IS_BREAKZ_AT(string,offset) \
// (IS_BREAK_AT((string),(offset)) || IS_Z_AT((string),(offset)))
//
// #define IS_BREAKZ(string) IS_BREAKZ_AT((string),0)
//
// /*
// * Check if the character is a line break, space, or NUL.
// */
//
// #define IS_SPACEZ_AT(string,offset) \
// (IS_SPACE_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset)))
//
// #define IS_SPACEZ(string) IS_SPACEZ_AT((string),0)
//
// /*
// * Check if the character is a line break, space, tab, or NUL.
// */
//
// #define IS_BLANKZ_AT(string,offset) \
// (IS_BLANK_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset)))
//
// #define IS_BLANKZ(string) IS_BLANKZ_AT((string),0)
//
// /*
// * Determine the width of the character.
// */
//
// #define WIDTH_AT(string,offset) \
// (((string).pointer[offset] & 0x80) == 0x00 ? 1 : \
// ((string).pointer[offset] & 0xE0) == 0xC0 ? 2 : \
// ((string).pointer[offset] & 0xF0) == 0xE0 ? 3 : \
// ((string).pointer[offset] & 0xF8) == 0xF0 ? 4 : 0)
//
// #define WIDTH(string) WIDTH_AT((string),0)
//
// /*
// * Move the string pointer to the next character.
// */
//
// #define MOVE(string) ((string).pointer += WIDTH((string)))
//
// /*
// * Copy a character and move the pointers of both strings.
// */
//
// #define COPY(string_a,string_b) \
// ((*(string_b).pointer & 0x80) == 0x00 ? \
// (*((string_a).pointer++) = *((string_b).pointer++)) : \
// (*(string_b).pointer & 0xE0) == 0xC0 ? \
// (*((string_a).pointer++) = *((string_b).pointer++), \
// *((string_a).pointer++) = *((string_b).pointer++)) : \
// (*(string_b).pointer & 0xF0) == 0xE0 ? \
// (*((string_a).pointer++) = *((string_b).pointer++), \
// *((string_a).pointer++) = *((string_b).pointer++), \
// *((string_a).pointer++) = *((string_b).pointer++)) : \
// (*(string_b).pointer & 0xF8) == 0xF0 ? \
// (*((string_a).pointer++) = *((string_b).pointer++), \
// *((string_a).pointer++) = *((string_b).pointer++), \
// *((string_a).pointer++) = *((string_b).pointer++), \
// *((string_a).pointer++) = *((string_b).pointer++)) : 0)
//
// /*
// * Stack and queue management.
// */
//
// yaml_DECLARE(int)
// yaml_stack_extend(void **start, void **top, void **end);
//
// yaml_DECLARE(int)
// yaml_queue_extend(void **start, void **head, void **tail, void **end);
//
// #define STACK_INIT(context,stack,size) \
// (((stack).start = yaml_malloc((size)*sizeof(*(stack).start))) ? \
// ((stack).top = (stack).start, \
// (stack).end = (stack).start+(size), \
// 1) : \
// ((context)->error = yaml_MEMORY_ERROR, \
// 0))
//
// #define STACK_DEL(context,stack) \
// (yaml_free((stack).start), \
// (stack).start = (stack).top = (stack).end = 0)
//
// #define STACK_EMPTY(context,stack) \
// ((stack).start == (stack).top)
//
// #define PUSH(context,stack,value) \
// (((stack).top != (stack).end \
// || yaml_stack_extend((void **)&(stack).start, \
// (void **)&(stack).top, (void **)&(stack).end)) ? \
// (*((stack).top++) = value, \
// 1) : \
// ((context)->error = yaml_MEMORY_ERROR, \
// 0))
//
// #define POP(context,stack) \
// (*(--(stack).top))
//
// #define QUEUE_INIT(context,queue,size) \
// (((queue).start = yaml_malloc((size)*sizeof(*(queue).start))) ? \
// ((queue).head = (queue).tail = (queue).start, \
// (queue).end = (queue).start+(size), \
// 1) : \
// ((context)->error = yaml_MEMORY_ERROR, \
// 0))
//
// #define QUEUE_DEL(context,queue) \
// (yaml_free((queue).start), \
// (queue).start = (queue).head = (queue).tail = (queue).end = 0)
//
// #define QUEUE_EMPTY(context,queue) \
// ((queue).head == (queue).tail)
//
// #define ENQUEUE(context,queue,value) \
// (((queue).tail != (queue).end \
// || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \
// (void **)&(queue).tail, (void **)&(queue).end)) ? \
// (*((queue).tail++) = value, \
// 1) : \
// ((context)->error = yaml_MEMORY_ERROR, \
// 0))
//
// #define DEQUEUE(context,queue) \
// (*((queue).head++))
//
// #define QUEUE_INSERT(context,queue,index,value) \
// (((queue).tail != (queue).end \
// || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \
// (void **)&(queue).tail, (void **)&(queue).end)) ? \
// (memmove((queue).head+(index)+1,(queue).head+(index), \
// ((queue).tail-(queue).head-(index))*sizeof(*(queue).start)), \
// *((queue).head+(index)) = value, \
// (queue).tail++, \
// 1) : \
// ((context)->error = yaml_MEMORY_ERROR, \
// 0))
//
// /*
// * Token initializers.
// */
//
// #define TOKEN_INIT(token,token_type,token_start_mark,token_end_mark) \
// (memset(&(token), 0, sizeof(yaml_token_t)), \
// (token).type = (token_type), \
// (token).start_mark = (token_start_mark), \
// (token).end_mark = (token_end_mark))
//
// #define STREAM_START_TOKEN_INIT(token,token_encoding,start_mark,end_mark) \
// (TOKEN_INIT((token),yaml_STREAM_START_TOKEN,(start_mark),(end_mark)), \
// (token).data.stream_start.encoding = (token_encoding))
//
// #define STREAM_END_TOKEN_INIT(token,start_mark,end_mark) \
// (TOKEN_INIT((token),yaml_STREAM_END_TOKEN,(start_mark),(end_mark)))
//
// #define ALIAS_TOKEN_INIT(token,token_value,start_mark,end_mark) \
// (TOKEN_INIT((token),yaml_ALIAS_TOKEN,(start_mark),(end_mark)), \
// (token).data.alias.value = (token_value))
//
// #define ANCHOR_TOKEN_INIT(token,token_value,start_mark,end_mark) \
// (TOKEN_INIT((token),yaml_ANCHOR_TOKEN,(start_mark),(end_mark)), \
// (token).data.anchor.value = (token_value))
//
// #define TAG_TOKEN_INIT(token,token_handle,token_suffix,start_mark,end_mark) \
// (TOKEN_INIT((token),yaml_TAG_TOKEN,(start_mark),(end_mark)), \
// (token).data.tag.handle = (token_handle), \
// (token).data.tag.suffix = (token_suffix))
//
// #define SCALAR_TOKEN_INIT(token,token_value,token_length,token_style,start_mark,end_mark) \
// (TOKEN_INIT((token),yaml_SCALAR_TOKEN,(start_mark),(end_mark)), \
// (token).data.scalar.value = (token_value), \
// (token).data.scalar.length = (token_length), \
// (token).data.scalar.style = (token_style))
//
// #define VERSION_DIRECTIVE_TOKEN_INIT(token,token_major,token_minor,start_mark,end_mark) \
// (TOKEN_INIT((token),yaml_VERSION_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \
// (token).data.version_directive.major = (token_major), \
// (token).data.version_directive.minor = (token_minor))
//
// #define TAG_DIRECTIVE_TOKEN_INIT(token,token_handle,token_prefix,start_mark,end_mark) \
// (TOKEN_INIT((token),yaml_TAG_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \
// (token).data.tag_directive.handle = (token_handle), \
// (token).data.tag_directive.prefix = (token_prefix))
//
// /*
// * Event initializers.
// */
//
// #define EVENT_INIT(event,event_type,event_start_mark,event_end_mark) \
// (memset(&(event), 0, sizeof(yaml_event_t)), \
// (event).type = (event_type), \
// (event).start_mark = (event_start_mark), \
// (event).end_mark = (event_end_mark))
//
// #define STREAM_START_EVENT_INIT(event,event_encoding,start_mark,end_mark) \
// (EVENT_INIT((event),yaml_STREAM_START_EVENT,(start_mark),(end_mark)), \
// (event).data.stream_start.encoding = (event_encoding))
//
// #define STREAM_END_EVENT_INIT(event,start_mark,end_mark) \
// (EVENT_INIT((event),yaml_STREAM_END_EVENT,(start_mark),(end_mark)))
//
// #define DOCUMENT_START_EVENT_INIT(event,event_version_directive, \
// event_tag_directives_start,event_tag_directives_end,event_implicit,start_mark,end_mark) \
// (EVENT_INIT((event),yaml_DOCUMENT_START_EVENT,(start_mark),(end_mark)), \
// (event).data.document_start.version_directive = (event_version_directive), \
// (event).data.document_start.tag_directives.start = (event_tag_directives_start), \
// (event).data.document_start.tag_directives.end = (event_tag_directives_end), \
// (event).data.document_start.implicit = (event_implicit))
//
// #define DOCUMENT_END_EVENT_INIT(event,event_implicit,start_mark,end_mark) \
// (EVENT_INIT((event),yaml_DOCUMENT_END_EVENT,(start_mark),(end_mark)), \
// (event).data.document_end.implicit = (event_implicit))
//
// #define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark) \
// (EVENT_INIT((event),yaml_ALIAS_EVENT,(start_mark),(end_mark)), \
// (event).data.alias.anchor = (event_anchor))
//
// #define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,event_length, \
// event_plain_implicit, event_quoted_implicit,event_style,start_mark,end_mark) \
// (EVENT_INIT((event),yaml_SCALAR_EVENT,(start_mark),(end_mark)), \
// (event).data.scalar.anchor = (event_anchor), \
// (event).data.scalar.tag = (event_tag), \
// (event).data.scalar.value = (event_value), \
// (event).data.scalar.length = (event_length), \
// (event).data.scalar.plain_implicit = (event_plain_implicit), \
// (event).data.scalar.quoted_implicit = (event_quoted_implicit), \
// (event).data.scalar.style = (event_style))
//
// #define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag, \
// event_implicit,event_style,start_mark,end_mark) \
// (EVENT_INIT((event),yaml_SEQUENCE_START_EVENT,(start_mark),(end_mark)), \
// (event).data.sequence_start.anchor = (event_anchor), \
// (event).data.sequence_start.tag = (event_tag), \
// (event).data.sequence_start.implicit = (event_implicit), \
// (event).data.sequence_start.style = (event_style))
//
// #define SEQUENCE_END_EVENT_INIT(event,start_mark,end_mark) \
// (EVENT_INIT((event),yaml_SEQUENCE_END_EVENT,(start_mark),(end_mark)))
//
// #define MAPPING_START_EVENT_INIT(event,event_anchor,event_tag, \
// event_implicit,event_style,start_mark,end_mark) \
// (EVENT_INIT((event),yaml_MAPPING_START_EVENT,(start_mark),(end_mark)), \
// (event).data.mapping_start.anchor = (event_anchor), \
// (event).data.mapping_start.tag = (event_tag), \
// (event).data.mapping_start.implicit = (event_implicit), \
// (event).data.mapping_start.style = (event_style))
//
// #define MAPPING_END_EVENT_INIT(event,start_mark,end_mark) \
// (EVENT_INIT((event),yaml_MAPPING_END_EVENT,(start_mark),(end_mark)))
//
// /*
// * Document initializer.
// */
//
// #define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end, \
// document_version_directive,document_tag_directives_start, \
// document_tag_directives_end,document_start_implicit, \
// document_end_implicit,document_start_mark,document_end_mark) \
// (memset(&(document), 0, sizeof(yaml_document_t)), \
// (document).nodes.start = (document_nodes_start), \
// (document).nodes.end = (document_nodes_end), \
// (document).nodes.top = (document_nodes_start), \
// (document).version_directive = (document_version_directive), \
// (document).tag_directives.start = (document_tag_directives_start), \
// (document).tag_directives.end = (document_tag_directives_end), \
// (document).start_implicit = (document_start_implicit), \
// (document).end_implicit = (document_end_implicit), \
// (document).start_mark = (document_start_mark), \
// (document).end_mark = (document_end_mark))
//
// /*
// * Node initializers.
// */
//
// #define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark) \
// (memset(&(node), 0, sizeof(yaml_node_t)), \
// (node).type = (node_type), \
// (node).tag = (node_tag), \
// (node).start_mark = (node_start_mark), \
// (node).end_mark = (node_end_mark))
//
// #define SCALAR_NODE_INIT(node,node_tag,node_value,node_length, \
// node_style,start_mark,end_mark) \
// (NODE_INIT((node),yaml_SCALAR_NODE,(node_tag),(start_mark),(end_mark)), \
// (node).data.scalar.value = (node_value), \
// (node).data.scalar.length = (node_length), \
// (node).data.scalar.style = (node_style))
//
// #define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end, \
// node_style,start_mark,end_mark) \
// (NODE_INIT((node),yaml_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)), \
// (node).data.sequence.items.start = (node_items_start), \
// (node).data.sequence.items.end = (node_items_end), \
// (node).data.sequence.items.top = (node_items_start), \
// (node).data.sequence.style = (node_style))
//
// #define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end, \
// node_style,start_mark,end_mark) \
// (NODE_INIT((node),yaml_MAPPING_NODE,(node_tag),(start_mark),(end_mark)), \
// (node).data.mapping.pairs.start = (node_pairs_start), \
// (node).data.mapping.pairs.end = (node_pairs_end), \
// (node).data.mapping.pairs.top = (node_pairs_start), \
// (node).data.mapping.style = (node_style))
//

View File

@ -1,953 +0,0 @@
/*
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 candiedyaml
import (
"fmt"
"io"
)
/** The version directive data. */
type yaml_version_directive_t struct {
major int // The major version number
minor int // The minor version number
}
/** The tag directive data. */
type yaml_tag_directive_t struct {
handle []byte // The tag handle
prefix []byte // The tag prefix
}
/** The stream encoding. */
type yaml_encoding_t int
const (
/** Let the parser choose the encoding. */
yaml_ANY_ENCODING yaml_encoding_t = iota
/** The defau lt UTF-8 encoding. */
yaml_UTF8_ENCODING
/** The UTF-16-LE encoding with BOM. */
yaml_UTF16LE_ENCODING
/** The UTF-16-BE encoding with BOM. */
yaml_UTF16BE_ENCODING
)
/** Line break types. */
type yaml_break_t int
const (
yaml_ANY_BREAK yaml_break_t = iota /** Let the parser choose the break type. */
yaml_CR_BREAK /** Use CR for line breaks (Mac style). */
yaml_LN_BREAK /** Use LN for line breaks (Unix style). */
yaml_CRLN_BREAK /** Use CR LN for line breaks (DOS style). */
)
/** Many bad things could happen with the parser and emitter. */
type YAML_error_type_t int
const (
/** No error is produced. */
yaml_NO_ERROR YAML_error_type_t = iota
/** Cannot allocate or reallocate a block of memory. */
yaml_MEMORY_ERROR
/** Cannot read or decode the input stream. */
yaml_READER_ERROR
/** Cannot scan the input stream. */
yaml_SCANNER_ERROR
/** Cannot parse the input stream. */
yaml_PARSER_ERROR
/** Cannot compose a YAML document. */
yaml_COMPOSER_ERROR
/** Cannot write to the output stream. */
yaml_WRITER_ERROR
/** Cannot emit a YAML stream. */
yaml_EMITTER_ERROR
)
/** The pointer position. */
type YAML_mark_t struct {
/** The position index. */
index int
/** The position line. */
line int
/** The position column. */
column int
}
func (m YAML_mark_t) String() string {
return fmt.Sprintf("line %d, column %d", m.line, m.column)
}
/** @} */
/**
* @defgroup styles Node Styles
* @{
*/
type yaml_style_t int
/** Scalar styles. */
type yaml_scalar_style_t yaml_style_t
const (
/** Let the emitter choose the style. */
yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota
/** The plain scalar style. */
yaml_PLAIN_SCALAR_STYLE
/** The single-quoted scalar style. */
yaml_SINGLE_QUOTED_SCALAR_STYLE
/** The double-quoted scalar style. */
yaml_DOUBLE_QUOTED_SCALAR_STYLE
/** The literal scalar style. */
yaml_LITERAL_SCALAR_STYLE
/** The folded scalar style. */
yaml_FOLDED_SCALAR_STYLE
)
/** Sequence styles. */
type yaml_sequence_style_t yaml_style_t
const (
/** Let the emitter choose the style. */
yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota
/** The block sequence style. */
yaml_BLOCK_SEQUENCE_STYLE
/** The flow sequence style. */
yaml_FLOW_SEQUENCE_STYLE
)
/** Mapping styles. */
type yaml_mapping_style_t yaml_style_t
const (
/** Let the emitter choose the style. */
yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota
/** The block mapping style. */
yaml_BLOCK_MAPPING_STYLE
/** The flow mapping style. */
yaml_FLOW_MAPPING_STYLE
/* yaml_FLOW_SET_MAPPING_STYLE */
)
/** @} */
/**
* @defgroup tokens Tokens
* @{
*/
/** Token types. */
type yaml_token_type_t int
const (
/** An empty token. */
yaml_NO_TOKEN yaml_token_type_t = iota
/** A STREAM-START token. */
yaml_STREAM_START_TOKEN
/** A STREAM-END token. */
yaml_STREAM_END_TOKEN
/** A VERSION-DIRECTIVE token. */
yaml_VERSION_DIRECTIVE_TOKEN
/** A TAG-DIRECTIVE token. */
yaml_TAG_DIRECTIVE_TOKEN
/** A DOCUMENT-START token. */
yaml_DOCUMENT_START_TOKEN
/** A DOCUMENT-END token. */
yaml_DOCUMENT_END_TOKEN
/** A BLOCK-SEQUENCE-START token. */
yaml_BLOCK_SEQUENCE_START_TOKEN
/** A BLOCK-SEQUENCE-END token. */
yaml_BLOCK_MAPPING_START_TOKEN
/** A BLOCK-END token. */
yaml_BLOCK_END_TOKEN
/** A FLOW-SEQUENCE-START token. */
yaml_FLOW_SEQUENCE_START_TOKEN
/** A FLOW-SEQUENCE-END token. */
yaml_FLOW_SEQUENCE_END_TOKEN
/** A FLOW-MAPPING-START token. */
yaml_FLOW_MAPPING_START_TOKEN
/** A FLOW-MAPPING-END token. */
yaml_FLOW_MAPPING_END_TOKEN
/** A BLOCK-ENTRY token. */
yaml_BLOCK_ENTRY_TOKEN
/** A FLOW-ENTRY token. */
yaml_FLOW_ENTRY_TOKEN
/** A KEY token. */
yaml_KEY_TOKEN
/** A VALUE token. */
yaml_VALUE_TOKEN
/** An ALIAS token. */
yaml_ALIAS_TOKEN
/** An ANCHOR token. */
yaml_ANCHOR_TOKEN
/** A TAG token. */
yaml_TAG_TOKEN
/** A SCALAR token. */
yaml_SCALAR_TOKEN
)
/** The token structure. */
type yaml_token_t struct {
/** The token type. */
token_type yaml_token_type_t
/** The token data. */
/** The stream start (for @c yaml_STREAM_START_TOKEN). */
encoding yaml_encoding_t
/** The alias (for @c yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN,yaml_TAG_TOKEN ). */
/** The anchor (for @c ). */
/** The scalar value (for @c ). */
value []byte
/** The tag suffix. */
suffix []byte
/** The scalar value (for @c yaml_SCALAR_TOKEN). */
/** The scalar style. */
style yaml_scalar_style_t
/** The version directive (for @c yaml_VERSION_DIRECTIVE_TOKEN). */
version_directive yaml_version_directive_t
/** The tag directive (for @c yaml_TAG_DIRECTIVE_TOKEN). */
prefix []byte
/** The beginning of the token. */
start_mark YAML_mark_t
/** The end of the token. */
end_mark YAML_mark_t
major, minor int
}
/**
* @defgroup events Events
* @{
*/
/** Event types. */
type yaml_event_type_t int
const (
/** An empty event. */
yaml_NO_EVENT yaml_event_type_t = iota
/** A STREAM-START event. */
yaml_STREAM_START_EVENT
/** A STREAM-END event. */
yaml_STREAM_END_EVENT
/** A DOCUMENT-START event. */
yaml_DOCUMENT_START_EVENT
/** A DOCUMENT-END event. */
yaml_DOCUMENT_END_EVENT
/** An ALIAS event. */
yaml_ALIAS_EVENT
/** A SCALAR event. */
yaml_SCALAR_EVENT
/** A SEQUENCE-START event. */
yaml_SEQUENCE_START_EVENT
/** A SEQUENCE-END event. */
yaml_SEQUENCE_END_EVENT
/** A MAPPING-START event. */
yaml_MAPPING_START_EVENT
/** A MAPPING-END event. */
yaml_MAPPING_END_EVENT
)
/** The event structure. */
type yaml_event_t struct {
/** The event type. */
event_type yaml_event_type_t
/** The stream parameters (for @c yaml_STREAM_START_EVENT). */
encoding yaml_encoding_t
/** The document parameters (for @c yaml_DOCUMENT_START_EVENT). */
version_directive *yaml_version_directive_t
/** The beginning and end of the tag directives list. */
tag_directives []yaml_tag_directive_t
/** The document parameters (for @c yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT,yaml_MAPPING_START_EVENT). */
/** Is the document indicator implicit? */
implicit bool
/** The alias parameters (for @c yaml_ALIAS_EVENT,yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). */
/** The anchor. */
anchor []byte
/** The scalar parameters (for @c yaml_SCALAR_EVENT,yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). */
/** The tag. */
tag []byte
/** The scalar value. */
value []byte
/** Is the tag optional for the plain style? */
plain_implicit bool
/** Is the tag optional for any non-plain style? */
quoted_implicit bool
/** The sequence parameters (for @c yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). */
/** The sequence style. */
/** The scalar style. */
style yaml_style_t
/** The beginning of the event. */
start_mark, end_mark YAML_mark_t
}
/**
* @defgroup nodes Nodes
* @{
*/
const (
/** The tag @c !!null with the only possible value: @c null. */
yaml_NULL_TAG = "tag:yaml.org,2002:null"
/** The tag @c !!bool with the values: @c true and @c falce. */
yaml_BOOL_TAG = "tag:yaml.org,2002:bool"
/** The tag @c !!str for string values. */
yaml_STR_TAG = "tag:yaml.org,2002:str"
/** The tag @c !!int for integer values. */
yaml_INT_TAG = "tag:yaml.org,2002:int"
/** The tag @c !!float for float values. */
yaml_FLOAT_TAG = "tag:yaml.org,2002:float"
/** The tag @c !!timestamp for date and time values. */
yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp"
/** The tag @c !!seq is used to denote sequences. */
yaml_SEQ_TAG = "tag:yaml.org,2002:seq"
/** The tag @c !!map is used to denote mapping. */
yaml_MAP_TAG = "tag:yaml.org,2002:map"
/** The default scalar tag is @c !!str. */
yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG
/** The default sequence tag is @c !!seq. */
yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG
/** The default mapping tag is @c !!map. */
yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG
yaml_BINARY_TAG = "tag:yaml.org,2002:binary"
)
/** Node types. */
type yaml_node_type_t int
const (
/** An empty node. */
yaml_NO_NODE yaml_node_type_t = iota
/** A scalar node. */
yaml_SCALAR_NODE
/** A sequence node. */
yaml_SEQUENCE_NODE
/** A mapping node. */
yaml_MAPPING_NODE
)
/** An element of a sequence node. */
type yaml_node_item_t int
/** An element of a mapping node. */
type yaml_node_pair_t struct {
/** The key of the element. */
key int
/** The value of the element. */
value int
}
/** The node structure. */
type yaml_node_t struct {
/** The node type. */
node_type yaml_node_type_t
/** The node tag. */
tag []byte
/** The scalar parameters (for @c yaml_SCALAR_NODE). */
scalar struct {
/** The scalar value. */
value []byte
/** The scalar style. */
style yaml_scalar_style_t
}
/** The sequence parameters (for @c yaml_SEQUENCE_NODE). */
sequence struct {
/** The stack of sequence items. */
items []yaml_node_item_t
/** The sequence style. */
style yaml_sequence_style_t
}
/** The mapping parameters (for @c yaml_MAPPING_NODE). */
mapping struct {
/** The stack of mapping pairs (key, value). */
pairs []yaml_node_pair_t
/** The mapping style. */
style yaml_mapping_style_t
}
/** The beginning of the node. */
start_mark YAML_mark_t
/** The end of the node. */
end_mark YAML_mark_t
}
/** The document structure. */
type yaml_document_t struct {
/** The document nodes. */
nodes []yaml_node_t
/** The version directive. */
version_directive *yaml_version_directive_t
/** The list of tag directives. */
tags []yaml_tag_directive_t
/** Is the document start indicator implicit? */
start_implicit bool
/** Is the document end indicator implicit? */
end_implicit bool
/** The beginning of the document. */
start_mark YAML_mark_t
/** The end of the document. */
end_mark YAML_mark_t
}
/**
* The prototype of a read handler.
*
* The read handler is called when the parser needs to read more bytes from the
* source. The handler should write not more than @a size bytes to the @a
* buffer. The number of written bytes should be set to the @a length variable.
*
* @param[in,out] data A pointer to an application data specified by
* yaml_parser_set_input().
* @param[out] buffer The buffer to write the data from the source.
* @param[in] size The size of the buffer.
* @param[out] size_read The actual number of bytes read from the source.
*
* @returns On success, the handler should return @c 1. If the handler failed,
* the returned value should be @c 0. On EOF, the handler should set the
* @a size_read to @c 0 and return @c 1.
*/
type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error)
/**
* This structure holds information about a potential simple key.
*/
type yaml_simple_key_t struct {
/** Is a simple key possible? */
possible bool
/** Is a simple key required? */
required bool
/** The number of the token. */
token_number int
/** The position mark. */
mark YAML_mark_t
}
/**
* The states of the parser.
*/
type yaml_parser_state_t int
const (
/** Expect STREAM-START. */
yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota
/** Expect the beginning of an implicit document. */
yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE
/** Expect DOCUMENT-START. */
yaml_PARSE_DOCUMENT_START_STATE
/** Expect the content of a document. */
yaml_PARSE_DOCUMENT_CONTENT_STATE
/** Expect DOCUMENT-END. */
yaml_PARSE_DOCUMENT_END_STATE
/** Expect a block node. */
yaml_PARSE_BLOCK_NODE_STATE
/** Expect a block node or indentless sequence. */
yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE
/** Expect a flow node. */
yaml_PARSE_FLOW_NODE_STATE
/** Expect the first entry of a block sequence. */
yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE
/** Expect an entry of a block sequence. */
yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE
/** Expect an entry of an indentless sequence. */
yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
/** Expect the first key of a block mapping. */
yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE
/** Expect a block mapping key. */
yaml_PARSE_BLOCK_MAPPING_KEY_STATE
/** Expect a block mapping value. */
yaml_PARSE_BLOCK_MAPPING_VALUE_STATE
/** Expect the first entry of a flow sequence. */
yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE
/** Expect an entry of a flow sequence. */
yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE
/** Expect a key of an ordered mapping. */
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE
/** Expect a value of an ordered mapping. */
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE
/** Expect the and of an ordered mapping entry. */
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE
/** Expect the first key of a flow mapping. */
yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE
/** Expect a key of a flow mapping. */
yaml_PARSE_FLOW_MAPPING_KEY_STATE
/** Expect a value of a flow mapping. */
yaml_PARSE_FLOW_MAPPING_VALUE_STATE
/** Expect an empty value of a flow mapping. */
yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE
/** Expect nothing. */
yaml_PARSE_END_STATE
)
/**
* This structure holds aliases data.
*/
type yaml_alias_data_t struct {
/** The anchor. */
anchor []byte
/** The node id. */
index int
/** The anchor mark. */
mark YAML_mark_t
}
/**
* The parser structure.
*
* All members are internal. Manage the structure using the @c yaml_parser_
* family of functions.
*/
type yaml_parser_t struct {
/**
* @name Error handling
* @{
*/
/** Error type. */
error YAML_error_type_t
/** Error description. */
problem string
/** The byte about which the problem occured. */
problem_offset int
/** The problematic value (@c -1 is none). */
problem_value int
/** The problem position. */
problem_mark YAML_mark_t
/** The error context. */
context string
/** The context position. */
context_mark YAML_mark_t
/**
* @}
*/
/**
* @name Reader stuff
* @{
*/
/** Read handler. */
read_handler yaml_read_handler_t
/** Reader input data. */
input_reader io.Reader
input []byte
input_pos int
/** EOF flag */
eof bool
/** The working buffer. */
buffer []byte
buffer_pos int
/* The number of unread characters in the buffer. */
unread int
/** The raw buffer. */
raw_buffer []byte
raw_buffer_pos int
/** The input encoding. */
encoding yaml_encoding_t
/** The offset of the current position (in bytes). */
offset int
/** The mark of the current position. */
mark YAML_mark_t
/**
* @}
*/
/**
* @name Scanner stuff
* @{
*/
/** Have we started to scan the input stream? */
stream_start_produced bool
/** Have we reached the end of the input stream? */
stream_end_produced bool
/** The number of unclosed '[' and '{' indicators. */
flow_level int
/** The tokens queue. */
tokens []yaml_token_t
tokens_head int
/** The number of tokens fetched from the queue. */
tokens_parsed int
/* Does the tokens queue contain a token ready for dequeueing. */
token_available bool
/** The indentation levels stack. */
indents []int
/** The current indentation level. */
indent int
/** May a simple key occur at the current position? */
simple_key_allowed bool
/** The stack of simple keys. */
simple_keys []yaml_simple_key_t
/**
* @}
*/
/**
* @name Parser stuff
* @{
*/
/** The parser states stack. */
states []yaml_parser_state_t
/** The current parser state. */
state yaml_parser_state_t
/** The stack of marks. */
marks []YAML_mark_t
/** The list of TAG directives. */
tag_directives []yaml_tag_directive_t
/**
* @}
*/
/**
* @name Dumper stuff
* @{
*/
/** The alias data. */
aliases []yaml_alias_data_t
/** The currently parsed document. */
document *yaml_document_t
/**
* @}
*/
}
/**
* The prototype of a write handler.
*
* The write handler is called when the emitter needs to flush the accumulated
* characters to the output. The handler should write @a size bytes of the
* @a buffer to the output.
*
* @param[in,out] data A pointer to an application data specified by
* yaml_emitter_set_output().
* @param[in] buffer The buffer with bytes to be written.
* @param[in] size The size of the buffer.
*
* @returns On success, the handler should return @c 1. If the handler failed,
* the returned value should be @c 0.
*/
type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
/** The emitter states. */
type yaml_emitter_state_t int
const (
/** Expect STREAM-START. */
yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota
/** Expect the first DOCUMENT-START or STREAM-END. */
yaml_EMIT_FIRST_DOCUMENT_START_STATE
/** Expect DOCUMENT-START or STREAM-END. */
yaml_EMIT_DOCUMENT_START_STATE
/** Expect the content of a document. */
yaml_EMIT_DOCUMENT_CONTENT_STATE
/** Expect DOCUMENT-END. */
yaml_EMIT_DOCUMENT_END_STATE
/** Expect the first item of a flow sequence. */
yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE
/** Expect an item of a flow sequence. */
yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE
/** Expect the first key of a flow mapping. */
yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE
/** Expect a key of a flow mapping. */
yaml_EMIT_FLOW_MAPPING_KEY_STATE
/** Expect a value for a simple key of a flow mapping. */
yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE
/** Expect a value of a flow mapping. */
yaml_EMIT_FLOW_MAPPING_VALUE_STATE
/** Expect the first item of a block sequence. */
yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE
/** Expect an item of a block sequence. */
yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE
/** Expect the first key of a block mapping. */
yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE
/** Expect the key of a block mapping. */
yaml_EMIT_BLOCK_MAPPING_KEY_STATE
/** Expect a value for a simple key of a block mapping. */
yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE
/** Expect a value of a block mapping. */
yaml_EMIT_BLOCK_MAPPING_VALUE_STATE
/** Expect nothing. */
yaml_EMIT_END_STATE
)
/**
* The emitter structure.
*
* All members are internal. Manage the structure using the @c yaml_emitter_
* family of functions.
*/
type yaml_emitter_t struct {
/**
* @name Error handling
* @{
*/
/** Error type. */
error YAML_error_type_t
/** Error description. */
problem string
/**
* @}
*/
/**
* @name Writer stuff
* @{
*/
/** Write handler. */
write_handler yaml_write_handler_t
/** Standard (string or file) output data. */
output_buffer *[]byte
output_writer io.Writer
/** The working buffer. */
buffer []byte
buffer_pos int
/** The raw buffer. */
raw_buffer []byte
raw_buffer_pos int
/** The stream encoding. */
encoding yaml_encoding_t
/**
* @}
*/
/**
* @name Emitter stuff
* @{
*/
/** If the output is in the canonical style? */
canonical bool
/** The number of indentation spaces. */
best_indent int
/** The preferred width of the output lines. */
best_width int
/** Allow unescaped non-ASCII characters? */
unicode bool
/** The preferred line break. */
line_break yaml_break_t
/** The stack of states. */
states []yaml_emitter_state_t
/** The current emitter state. */
state yaml_emitter_state_t
/** The event queue. */
events []yaml_event_t
events_head int
/** The stack of indentation levels. */
indents []int
/** The list of tag directives. */
tag_directives []yaml_tag_directive_t
/** The current indentation level. */
indent int
/** The current flow level. */
flow_level int
/** Is it the document root context? */
root_context bool
/** Is it a sequence context? */
sequence_context bool
/** Is it a mapping context? */
mapping_context bool
/** Is it a simple mapping key context? */
simple_key_context bool
/** The current line. */
line int
/** The current column. */
column int
/** If the last character was a whitespace? */
whitespace bool
/** If the last character was an indentation character (' ', '-', '?', ':')? */
indention bool
/** If an explicit document end is required? */
open_ended bool
/** Anchor analysis. */
anchor_data struct {
/** The anchor value. */
anchor []byte
/** Is it an alias? */
alias bool
}
/** Tag analysis. */
tag_data struct {
/** The tag handle. */
handle []byte
/** The tag suffix. */
suffix []byte
}
/** Scalar analysis. */
scalar_data struct {
/** The scalar value. */
value []byte
/** Does the scalar contain line breaks? */
multiline bool
/** Can the scalar be expessed in the flow plain style? */
flow_plain_allowed bool
/** Can the scalar be expressed in the block plain style? */
block_plain_allowed bool
/** Can the scalar be expressed in the single quoted style? */
single_quoted_allowed bool
/** Can the scalar be expressed in the literal or folded styles? */
block_allowed bool
/** The output style. */
style yaml_scalar_style_t
}
/**
* @}
*/
/**
* @name Dumper stuff
* @{
*/
/** If the stream was already opened? */
opened bool
/** If the stream was already closed? */
closed bool
/** The information associated with the document nodes. */
anchors *struct {
/** The number of references. */
references int
/** The anchor id. */
anchor int
/** If the node has been emitted? */
serialized bool
}
/** The last assigned anchor id. */
last_anchor_id int
/** The currently emitted document. */
document *yaml_document_t
/**
* @}
*/
}

View File

@ -0,0 +1,21 @@
package backend
import "io"
// Engine defines a container orchestration backend and is used
// to create and manage container resources.
type Engine interface {
// Setup the pipeline environment.
Setup(*Config) error
// Start the pipeline step.
Exec(*Step) error
// Kill the pipeline step.
Kill(*Step) error
// Wait for the pipeline step to complete and returns
// the completion results.
Wait(*Step) (*State, error)
// Tail the pipeline step logs.
Tail(*Step) (io.ReadCloser, error)
// Destroy the pipeline environment.
Destroy(*Config) error
}

View File

@ -0,0 +1,130 @@
package docker
import (
"encoding/base64"
"encoding/json"
"strings"
"github.com/cncd/pipeline/pipeline/backend"
"github.com/docker/docker/api/types/container"
)
// returns a container configuration.
func toConfig(proc *backend.Step) *container.Config {
config := &container.Config{
Image: proc.Image,
Labels: proc.Labels,
WorkingDir: proc.WorkingDir,
AttachStdout: true,
AttachStderr: true,
}
if len(proc.Environment) != 0 {
config.Env = toEnv(proc.Environment)
}
if len(proc.Command) != 0 {
config.Cmd = proc.Command
}
if len(proc.Entrypoint) != 0 {
config.Entrypoint = proc.Entrypoint
}
if len(proc.Volumes) != 0 {
config.Volumes = toVol(proc.Volumes)
}
return config
}
// returns a container host configuration.
func toHostConfig(proc *backend.Step) *container.HostConfig {
config := &container.HostConfig{
Resources: container.Resources{
CPUQuota: proc.CPUQuota,
CPUShares: proc.CPUShares,
CpusetCpus: proc.CPUSet,
Memory: proc.MemLimit,
MemorySwap: proc.MemSwapLimit,
},
Privileged: proc.Privileged,
ShmSize: proc.ShmSize,
}
// if len(proc.VolumesFrom) != 0 {
// config.VolumesFrom = proc.VolumesFrom
// }
// if len(proc.Network) != 0 {
// config.NetworkMode = container.NetworkMode(
// proc.Network,
// )
// }
if len(proc.DNS) != 0 {
config.DNS = proc.DNS
}
if len(proc.DNSSearch) != 0 {
config.DNSSearch = proc.DNSSearch
}
if len(proc.ExtraHosts) != 0 {
config.ExtraHosts = proc.ExtraHosts
}
if len(proc.Devices) != 0 {
config.Devices = toDev(proc.Devices)
}
if len(proc.Volumes) != 0 {
config.Binds = proc.Volumes
}
// if proc.OomKillDisable {
// config.OomKillDisable = &proc.OomKillDisable
// }
return config
}
// helper function that converts a slice of volume paths to a set of
// unique volume names.
func toVol(paths []string) map[string]struct{} {
set := map[string]struct{}{}
for _, path := range paths {
parts := strings.Split(path, ":")
if len(parts) < 2 {
continue
}
set[parts[1]] = struct{}{}
}
return set
}
// helper function that converts a key value map of environment variables to a
// string slice in key=value format.
func toEnv(env map[string]string) []string {
var envs []string
for k, v := range env {
envs = append(envs, k+"="+v)
}
return envs
}
// helper function that converts a slice of device paths to a slice of
// container.DeviceMapping.
func toDev(paths []string) []container.DeviceMapping {
var devices []container.DeviceMapping
for _, path := range paths {
parts := strings.Split(path, ":")
if len(parts) < 2 {
continue
}
devices = append(devices, container.DeviceMapping{
PathOnHost: parts[0],
PathInContainer: parts[1],
CgroupPermissions: "rwm",
})
}
return devices
}
// helper function that serializes the auth configuration as JSON
// base64 payload.
func encodeAuthToBase64(authConfig backend.Auth) (string, error) {
buf, err := json.Marshal(authConfig)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(buf), nil
}

View File

@ -0,0 +1,202 @@
package docker
import (
"context"
"io"
"io/ioutil"
"github.com/cncd/pipeline/pipeline/backend"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/stdcopy"
)
type engine struct {
client client.APIClient
}
// New returns a new Docker Engine using the given client.
func New(cli client.APIClient) backend.Engine {
return &engine{
client: cli,
}
}
// NewEnv returns a new Docker Engine using the client connection
// environment variables.
func NewEnv() (backend.Engine, error) {
cli, err := client.NewEnvClient()
if err != nil {
return nil, err
}
return New(cli), nil
}
func (e *engine) Setup(conf *backend.Config) error {
for _, vol := range conf.Volumes {
_, err := e.client.VolumeCreate(noContext, volume.VolumesCreateBody{
Name: vol.Name,
Driver: vol.Driver,
DriverOpts: vol.DriverOpts,
// Labels: defaultLabels,
})
if err != nil {
return err
}
}
for _, network := range conf.Networks {
_, err := e.client.NetworkCreate(noContext, network.Name, types.NetworkCreate{
Driver: network.Driver,
Options: network.DriverOpts,
// Labels: defaultLabels,
})
if err != nil {
return err
}
}
return nil
}
func (e *engine) Exec(proc *backend.Step) error {
ctx := context.Background()
config := toConfig(proc)
hostConfig := toHostConfig(proc)
// create pull options with encoded authorization credentials.
pullopts := types.ImagePullOptions{}
if proc.AuthConfig.Username != "" && proc.AuthConfig.Password != "" {
pullopts.RegistryAuth, _ = encodeAuthToBase64(proc.AuthConfig)
}
// automatically pull the latest version of the image if requested
// by the process configuration.
if proc.Pull {
rc, perr := e.client.ImagePull(ctx, config.Image, pullopts)
if perr == nil {
io.Copy(ioutil.Discard, rc)
rc.Close()
}
// fix for drone/drone#1917
if perr != nil && proc.AuthConfig.Password != "" {
return perr
}
}
_, err := e.client.ContainerCreate(ctx, config, hostConfig, nil, proc.Name)
if client.IsErrImageNotFound(err) {
// automatically pull and try to re-create the image if the
// failure is caused because the image does not exist.
rc, perr := e.client.ImagePull(ctx, config.Image, pullopts)
if perr != nil {
return perr
}
io.Copy(ioutil.Discard, rc)
rc.Close()
_, err = e.client.ContainerCreate(ctx, config, hostConfig, nil, proc.Name)
}
if err != nil {
return err
}
for _, net := range proc.Networks {
err = e.client.NetworkConnect(ctx, net.Name, proc.Name, &network.EndpointSettings{
Aliases: net.Aliases,
})
if err != nil {
return err
}
}
// if proc.Network != "host" { // or bridge, overlay, none, internal, container:<name> ....
// err = e.client.NetworkConnect(ctx, proc.Network, proc.Name, &network.EndpointSettings{
// Aliases: proc.NetworkAliases,
// })
// if err != nil {
// return err
// }
// }
return e.client.ContainerStart(ctx, proc.Name, startOpts)
}
func (e *engine) Kill(proc *backend.Step) error {
return e.client.ContainerKill(noContext, proc.Name, "9")
}
func (e *engine) Wait(proc *backend.Step) (*backend.State, error) {
_, err := e.client.ContainerWait(noContext, proc.Name)
if err != nil {
// todo
}
info, err := e.client.ContainerInspect(noContext, proc.Name)
if err != nil {
return nil, err
}
if info.State.Running {
// todo
}
return &backend.State{
Exited: true,
ExitCode: info.State.ExitCode,
OOMKilled: info.State.OOMKilled,
}, nil
}
func (e *engine) Tail(proc *backend.Step) (io.ReadCloser, error) {
logs, err := e.client.ContainerLogs(noContext, proc.Name, logsOpts)
if err != nil {
return nil, err
}
rc, wc := io.Pipe()
go func() {
stdcopy.StdCopy(wc, wc, logs)
logs.Close()
wc.Close()
rc.Close()
}()
return rc, nil
}
func (e *engine) Destroy(conf *backend.Config) error {
for _, stage := range conf.Stages {
for _, step := range stage.Steps {
e.client.ContainerKill(noContext, step.Name, "9")
e.client.ContainerRemove(noContext, step.Name, removeOpts)
}
}
for _, volume := range conf.Volumes {
e.client.VolumeRemove(noContext, volume.Name, true)
}
for _, network := range conf.Networks {
e.client.NetworkRemove(noContext, network.Name)
}
return nil
}
var (
noContext = context.Background()
startOpts = types.ContainerStartOptions{}
removeOpts = types.ContainerRemoveOptions{
RemoveVolumes: true,
RemoveLinks: false,
Force: false,
}
logsOpts = types.ContainerLogsOptions{
Follow: true,
ShowStdout: true,
ShowStderr: true,
Details: false,
Timestamps: false,
}
)

View File

@ -0,0 +1,44 @@
package docker
// import (
// "context"
//
// "github.com/cncd/pipeline/pipeline/backend"
// )
//
// // Pool manages a pool of Docker clients.
// type Pool struct {
// queue chan (backend.Engine)
// }
//
// // NewPool returns a Pool.
// func NewPool(engines ...backend.Engine) *Pool {
// return &Pool{
// queue: make(chan backend.Engine, len(engines)),
// }
// }
//
// // Reserve requests the next available Docker client in the pool.
// func (p *Pool) Reserve(c context.Context) backend.Engine {
// select {
// case <-c.Done():
// case engine := <-p.queue:
// return engine
// }
// return nil
// }
//
// // Release releases the Docker client back to the pool.
// func (p *Pool) Release(engine backend.Engine) {
// p.queue <- engine
// }
// pool := docker.Pool(
// docker.FromEnvironmentMust(),
// docker.FromEnvironmentMust(),
// docker.FromEnvironmentMust(),
// docker.FromEnvironmentMust(),
// )
//
// client := pool.Reserve()
// defer pool.Release(client)

View File

@ -0,0 +1,112 @@
package backend
type (
// Config defines the runtime configuration of a pipeline.
Config struct {
Stages []*Stage `json:"pipeline"` // pipeline stages
Networks []*Network `json:"networks"` // network definitions
Volumes []*Volume `json:"volumes"` // volume definitions
Secrets []*Secret `json:"secrets"` // secret definitions
}
// Stage denotes a collection of one or more steps.
Stage struct {
Name string `json:"name,omitempty"`
Alias string `json:"alias,omitempty"`
Steps []*Step `json:"steps,omitempty"`
}
// Step defines a container process.
Step struct {
Name string `json:"name"`
Alias string `json:"alias,omitempty"`
Image string `json:"image,omitempty"`
Pull bool `json:"pull,omitempty"`
Detached bool `json:"detach,omitempty"`
Privileged bool `json:"privileged,omitempty"`
WorkingDir string `json:"working_dir,omitempty"`
Environment map[string]string `json:"environment,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Entrypoint []string `json:"entrypoint,omitempty"`
Command []string `json:"command,omitempty"`
ExtraHosts []string `json:"extra_hosts,omitempty"`
Volumes []string `json:"volumes,omitempty"`
Devices []string `json:"devices,omitempty"`
Networks []Conn `json:"networks,omitempty"`
DNS []string `json:"dns,omitempty"`
DNSSearch []string `json:"dns_search,omitempty"`
MemSwapLimit int64 `json:"memswap_limit,omitempty"`
MemLimit int64 `json:"mem_limit,omitempty"`
ShmSize int64 `json:"shm_size,omitempty"`
CPUQuota int64 `json:"cpu_quota,omitempty"`
CPUShares int64 `json:"cpu_shares,omitempty"`
CPUSet string `json:"cpu_set,omitempty"`
OnFailure bool `json:"on_failure,omitempty"`
OnSuccess bool `json:"on_success,omitempty"`
AuthConfig Auth `json:"auth_config,omitempty"`
}
// Auth defines registry authentication credentials.
Auth struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Email string `json:"email,omitempty"`
}
// Conn defines a container network connection.
Conn struct {
Name string `json:"name"`
Aliases []string `json:"aliases"`
}
// Network defines a container network.
Network struct {
Name string `json:"name,omitempty"`
Driver string `json:"driver,omitempty"`
DriverOpts map[string]string `json:"driver_opts,omitempty"`
}
// Volume defines a container volume.
Volume struct {
Name string `json:"name,omitempty"`
Driver string `json:"driver,omitempty"`
DriverOpts map[string]string `json:"driver_opts,omitempty"`
}
// Secret defines a runtime secret
Secret struct {
Name string `json:"name,omitempty"`
Value string `json:"value,omitempty"`
Mount string `json:"mount,omitempty"`
Mask bool `json:"mask,omitempty"`
}
// State defines a container state.
State struct {
// Container exit code
ExitCode int `json:"exit_code"`
// Container exited, true or false
Exited bool `json:"exited"`
// Container is oom killed, true or false
OOMKilled bool `json:"oom_killed"`
}
// // State defines the pipeline and process state.
// State struct {
// Pipeline struct {
// // Current pipeline step
// Step *Step `json:"step"`
// // Current pipeline error state
// Error error `json:"error"`
// }
//
// Process struct {
// // Container exit code
// ExitCode int `json:"exit_code"`
// // Container exited, true or false
// Exited bool `json:"exited"`
// // Container is oom killed, true or false
// OOMKilled bool `json:"oom_killed"`
// }
// }
)

View File

@ -1,4 +1,4 @@
package build
package pipeline
import (
"errors"
@ -8,11 +8,11 @@ import (
var (
// ErrSkip is used as a return value when container execution should be
// skipped at runtime. It is not returned as an error by any function.
ErrSkip = errors.New("Skip")
ErrSkip = errors.New("Skipped")
// ErrTerm is used as a return value when the runner should terminate
// execution and exit. It is not returned as an error by any function.
ErrTerm = errors.New("Terminate")
// ErrCancel is used as a return value when the container execution receives
// a cancellation signal from the context.
ErrCancel = errors.New("Cancelled")
)
// An ExitError reports an unsuccessful exit.
@ -21,7 +21,7 @@ type ExitError struct {
Code int
}
// Error reteurns the error message in string format.
// Error returns the error message in string format.
func (e *ExitError) Error() string {
return fmt.Sprintf("%s : exit code %d", e.Name, e.Code)
}
@ -29,6 +29,7 @@ func (e *ExitError) Error() string {
// An OomError reports the process received an OOMKill from the kernel.
type OomError struct {
Name string
Code int
}
// Error reteurns the error message in string format.

View File

@ -0,0 +1,223 @@
package frontend
import (
"fmt"
"regexp"
"strconv"
"strings"
)
// Event types corresponding to scm hooks.
const (
EventPush = "push"
EventPull = "pull_request"
EventTag = "tag"
EventDeploy = "deployment"
)
type (
// Metadata defines runtime m.
Metadata struct {
ID string `json:"id,omitempty"`
Repo Repo `json:"repo,omitempty"`
Curr Build `json:"curr,omitempty"`
Prev Build `json:"prev,omitempty"`
Job Job `json:"job,omitempty"`
Sys System `json:"sys,omitempty"`
}
// Repo defines runtime metadata for a repository.
Repo struct {
Name string `json:"name,omitempty"`
Link string `json:"link,omitempty"`
Remote string `json:"remote,omitempty"`
Private bool `json:"private,omitempty"`
Secrets []Secret `json:"secrets,omitempty"`
}
// Build defines runtime metadata for a build.
Build struct {
Number int `json:"number,omitempty"`
Created int64 `json:"created,omitempty"`
Started int64 `json:"started,omitempty"`
Finished int64 `json:"finished,omitempty"`
Timeout int64 `json:"timeout,omitempty"`
Status string `json:"status,omitempty"`
Event string `json:"event,omitempty"`
Link string `json:"link,omitempty"`
Target string `json:"target,omitempty"`
Trusted bool `json:"trusted,omitempty"`
Commit Commit `json:"commit,omitempty"`
Parent int `json:"parent,omitempty"`
}
// Commit defines runtime metadata for a commit.
Commit struct {
Sha string `json:"sha,omitempty"`
Ref string `json:"ref,omitempty"`
Refspec string `json:"refspec,omitempty"`
Branch string `json:"branch,omitempty"`
Message string `json:"message,omitempty"`
Author Author `json:"author,omitempty"`
}
// Author defines runtime metadata for a commit author.
Author struct {
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Avatar string `json:"avatar,omitempty"`
}
// Job defines runtime metadata for a job.
Job struct {
Number int `json:"number,omitempty"`
Matrix map[string]string `json:"matrix,omitempty"`
}
// Secret defines a runtime secret
Secret struct {
Name string `json:"name,omitempty"`
Value string `json:"value,omitempty"`
Mount string `json:"mount,omitempty"`
Mask bool `json:"mask,omitempty"`
}
// System defines runtime metadata for a ci/cd system.
System struct {
Name string `json:"name,omitempty"`
Host string `json:"host,omitempty"`
Link string `json:"link,omitempty"`
Arch string `json:"arch,omitempty"`
Version string `json:"version,omitempty"`
}
)
// Environ returns the metadata as a map of environment variables.
func (m *Metadata) Environ() map[string]string {
params := map[string]string{
"CI_REPO": m.Repo.Name,
"CI_REPO_NAME": m.Repo.Name,
"CI_REPO_LINK": m.Repo.Link,
"CI_REPO_REMOTE": m.Repo.Remote,
"CI_REMOTE_URL": m.Repo.Remote,
"CI_REPO_PRIVATE": strconv.FormatBool(m.Repo.Private),
"CI_BUILD_NUMBER": strconv.Itoa(m.Curr.Number),
"CI_PARENT_BUILD_NUMBER": strconv.Itoa(m.Curr.Parent),
"CI_BUILD_CREATED": strconv.FormatInt(m.Curr.Created, 10),
"CI_BUILD_STARTED": strconv.FormatInt(m.Curr.Started, 10),
"CI_BUILD_FINISHED": strconv.FormatInt(m.Curr.Finished, 10),
"CI_BUILD_STATUS": m.Curr.Status,
"CI_BUILD_EVENT": m.Curr.Event,
"CI_BUILD_LINK": m.Curr.Link,
"CI_BUILD_TARGET": m.Curr.Target,
"CI_COMMIT_SHA": m.Curr.Commit.Sha,
"CI_COMMIT_REF": m.Curr.Commit.Ref,
"CI_COMMIT_REFSPEC": m.Curr.Commit.Refspec,
"CI_COMMIT_BRANCH": m.Curr.Commit.Branch,
"CI_COMMIT_MESSAGE": m.Curr.Commit.Message,
"CI_COMMIT_AUTHOR": m.Curr.Commit.Author.Name,
"CI_COMMIT_AUTHOR_NAME": m.Curr.Commit.Author.Name,
"CI_COMMIT_AUTHOR_EMAIL": m.Curr.Commit.Author.Email,
"CI_COMMIT_AUTHOR_AVATAR": m.Curr.Commit.Author.Avatar,
"CI_PREV_BUILD_NUMBER": strconv.Itoa(m.Prev.Number),
"CI_PREV_BUILD_CREATED": strconv.FormatInt(m.Prev.Created, 10),
"CI_PREV_BUILD_STARTED": strconv.FormatInt(m.Prev.Started, 10),
"CI_PREV_BUILD_FINISHED": strconv.FormatInt(m.Prev.Finished, 10),
"CI_PREV_BUILD_STATUS": m.Prev.Status,
"CI_PREV_BUILD_EVENT": m.Prev.Event,
"CI_PREV_BUILD_LINK": m.Prev.Link,
"CI_PREV_COMMIT_SHA": m.Prev.Commit.Sha,
"CI_PREV_COMMIT_REF": m.Prev.Commit.Ref,
"CI_PREV_COMMIT_REFSPEC": m.Prev.Commit.Refspec,
"CI_PREV_COMMIT_BRANCH": m.Prev.Commit.Branch,
"CI_PREV_COMMIT_MESSAGE": m.Prev.Commit.Message,
"CI_PREV_COMMIT_AUTHOR": m.Prev.Commit.Author.Name,
"CI_PREV_COMMIT_AUTHOR_NAME": m.Prev.Commit.Author.Name,
"CI_PREV_COMMIT_AUTHOR_EMAIL": m.Prev.Commit.Author.Email,
"CI_PREV_COMMIT_AUTHOR_AVATAR": m.Prev.Commit.Author.Avatar,
"CI_JOB_NUMBER": strconv.Itoa(m.Job.Number),
"CI_SYSTEM": m.Sys.Name,
"CI_SYSTEM_NAME": m.Sys.Name,
"CI_SYSTEM_LINK": m.Sys.Link,
"CI_SYSTEM_HOST": m.Sys.Host,
"CI_SYSTEM_ARCH": m.Sys.Arch,
"CI_SYSTEM_VERSION": m.Sys.Version,
"CI": m.Sys.Name,
}
if m.Curr.Event == EventTag {
params["CI_TAG"] = strings.TrimPrefix(m.Curr.Commit.Ref, "refs/tags/")
}
if m.Curr.Event == EventPull {
params["CI_PULL_REQUEST"] = pullRegexp.FindString(m.Curr.Commit.Ref)
}
return params
}
// EnvironDrone returns metadata as a map of DRONE_ environment variables.
// TODO: This is here for backward compatibility and will eventually be removed.
func (m *Metadata) EnvironDrone() map[string]string {
// MISSING PARAMETERS
// * DRONE_REPO_TRUSTED
// * DRONE_YAML_VERIFIED
// * DRONE_YAML_VERIFIED
var (
owner string
name string
parts = strings.Split(m.Repo.Name, "/")
)
if len(parts) == 2 {
owner = strings.Split(m.Repo.Name, "/")[0]
name = strings.Split(m.Repo.Name, "/")[1]
} else {
name = m.Repo.Name
}
params := map[string]string{
"CI": "drone",
"DRONE": "true",
"DRONE_ARCH": "linux/amd64",
"DRONE_REPO": m.Repo.Name,
"DRONE_REPO_SCM": "git",
"DRONE_REPO_OWNER": owner,
"DRONE_REPO_NAME": name,
"DRONE_REPO_LINK": m.Repo.Link,
"DRONE_REPO_BRANCH": m.Curr.Commit.Branch,
"DRONE_REPO_PRIVATE": fmt.Sprintf("%v", m.Repo.Private),
"DRONE_REPO_TRUSTED": "false", // TODO should this be added?
"DRONE_REMOTE_URL": m.Repo.Remote,
"DRONE_COMMIT_SHA": m.Curr.Commit.Sha,
"DRONE_COMMIT_REF": m.Curr.Commit.Ref,
"DRONE_COMMIT_REFSPEC": m.Curr.Commit.Refspec,
"DRONE_COMMIT_BRANCH": m.Curr.Commit.Branch,
"DRONE_COMMIT_LINK": m.Curr.Link,
"DRONE_COMMIT_MESSAGE": m.Curr.Commit.Message,
"DRONE_COMMIT_AUTHOR": m.Curr.Commit.Author.Name,
"DRONE_COMMIT_AUTHOR_EMAIL": m.Curr.Commit.Author.Email,
"DRONE_COMMIT_AUTHOR_AVATAR": m.Curr.Commit.Author.Avatar,
"DRONE_BUILD_NUMBER": fmt.Sprintf("%d", m.Curr.Number),
"DRONE_PARENT_BUILD_NUMBER": fmt.Sprintf("%d", m.Curr.Parent),
"DRONE_BUILD_EVENT": m.Curr.Event,
"DRONE_BUILD_LINK": fmt.Sprintf("%s/%s/%d", m.Sys.Link, m.Repo.Name, m.Curr.Number),
"DRONE_BUILD_CREATED": fmt.Sprintf("%d", m.Curr.Created),
"DRONE_BUILD_STARTED": fmt.Sprintf("%d", m.Curr.Started),
"DRONE_BUILD_FINISHED": fmt.Sprintf("%d", m.Curr.Finished),
"DRONE_JOB_NUMBER": fmt.Sprintf("%d", m.Job.Number),
"DRONE_JOB_STARTED": fmt.Sprintf("%d", m.Curr.Started), // ISSUE: no job started
"DRONE_BRANCH": m.Curr.Commit.Branch,
"DRONE_COMMIT": m.Curr.Commit.Sha,
"DRONE_VERSION": m.Sys.Version,
"DRONE_DEPLOY_TO": m.Curr.Target,
"DRONE_PREV_BUILD_STATUS": m.Prev.Status,
"DRONE_PREV_BUILD_NUMBER": fmt.Sprintf("%v", m.Prev.Number),
"DRONE_PREV_COMMIT_SHA": m.Prev.Commit.Sha,
}
if m.Curr.Event == EventTag {
params["DRONE_TAG"] = strings.TrimPrefix(m.Curr.Commit.Ref, "refs/tags/")
}
if m.Curr.Event == EventPull {
params["DRONE_PULL_REQUEST"] = pullRegexp.FindString(m.Curr.Commit.Ref)
}
return params
}
var pullRegexp = regexp.MustCompile("\\d+")

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