Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • ai3/tools/postfix-policyd-proxy
  • svp-bot/postfix-policyd-proxy
2 results
Show changes
Commits on Source (10)
Showing
with 289 additions and 113 deletions
include: "https://git.autistici.org/ai3/build-deb/raw/master/ci-buster-backports.yml" include: "https://git.autistici.org/pipelines/debian/raw/master/common.yml"
11
...@@ -2,12 +2,13 @@ Source: postfix-policyd-proxy ...@@ -2,12 +2,13 @@ Source: postfix-policyd-proxy
Section: unknown Section: unknown
Priority: optional Priority: optional
Maintainer: ale <ale@incal.net> Maintainer: ale <ale@incal.net>
Build-Depends: debhelper (>= 11), dh-golang, golang-any Build-Depends: debhelper-compat (= 12), dh-golang, golang-any
Standards-Version: 4.1.3 Standards-Version: 4.1.3
XS-Go-Import-Path: git.autistici.org/ai3/tools/postfix-policyd-proxy XS-Go-Import-Path: git.autistici.org/ai3/tools/postfix-policyd-proxy
Package: postfix-policyd-proxy Package: postfix-policyd-proxy
Architecture: any Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends} Depends: ${shlibs:Depends}, ${misc:Depends}
Built-Using: ${misc:Built-Using}
Description: Postfix policyd proxy Description: Postfix policyd proxy
Proxy for postfix policy services, directed by a LDAP backend. Proxy for postfix policy services, directed by a LDAP backend.
...@@ -9,4 +9,3 @@ export GO111MODULE := off ...@@ -9,4 +9,3 @@ export GO111MODULE := off
override_dh_auto_install: override_dh_auto_install:
dh_auto_install -- --no-source dh_auto_install -- --no-source
...@@ -4,7 +4,7 @@ go 1.14 ...@@ -4,7 +4,7 @@ go 1.14
require ( require (
git.autistici.org/ai3/go-common v0.0.0-20210118064555-73f00db54723 git.autistici.org/ai3/go-common v0.0.0-20210118064555-73f00db54723
github.com/coreos/go-systemd/v22 v22.2.0 github.com/coreos/go-systemd/v22 v22.5.0
github.com/go-ldap/ldap/v3 v3.2.4 github.com/go-ldap/ldap/v3 v3.2.4
gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86 gopkg.in/yaml.v3 v3.0.1
) )
...@@ -52,6 +52,8 @@ github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4 ...@@ -52,6 +52,8 @@ github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.2.0 h1:BBmbNtSc5PuUM3Byxs7yE5rLdxQO4/FMoEXY5Rle4GA= github.com/coreos/go-systemd/v22 v22.2.0 h1:BBmbNtSc5PuUM3Byxs7yE5rLdxQO4/FMoEXY5Rle4GA=
github.com/coreos/go-systemd/v22 v22.2.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.2.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
...@@ -90,6 +92,7 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG ...@@ -90,6 +92,7 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY= github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY=
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
...@@ -462,6 +465,8 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= ...@@ -462,6 +465,8 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86 h1:OfFoIUYv/me30yv7XlMy4F9RJw8DEm8WQ6QG1Ph4bH0= gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86 h1:OfFoIUYv/me30yv7XlMy4F9RJw8DEm8WQ6QG1Ph4bH0=
gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build !windows
// +build !windows // +build !windows
// Package activation implements primitives for systemd socket activation. // Package activation implements primitives for systemd socket activation.
......
...@@ -30,8 +30,8 @@ import ( ...@@ -30,8 +30,8 @@ import (
// It returns one of the following: // It returns one of the following:
// (0, nil) - watchdog isn't enabled or we aren't the watched PID. // (0, nil) - watchdog isn't enabled or we aren't the watched PID.
// (0, err) - an error happened (e.g. error converting time). // (0, err) - an error happened (e.g. error converting time).
// (time, nil) - watchdog is enabled and we can send ping. // (time, nil) - watchdog is enabled and we can send ping. time is delay
// time is delay before inactive service will be killed. // before inactive service will be killed.
func SdWatchdogEnabled(unsetEnvironment bool) (time.Duration, error) { func SdWatchdogEnabled(unsetEnvironment bool) (time.Duration, error) {
wusec := os.Getenv("WATCHDOG_USEC") wusec := os.Getenv("WATCHDOG_USEC")
wpid := os.Getenv("WATCHDOG_PID") wpid := os.Getenv("WATCHDOG_PID")
......
language: go
go:
- "1.4.x"
- "1.5.x"
- "1.6.x"
- "1.7.x"
- "1.8.x"
- "1.9.x"
- "1.10.x"
- "1.11.x"
- "1.12.x"
- "1.13.x"
- "tip"
go_import_path: gopkg.in/yaml.v3
...@@ -35,6 +35,7 @@ type parser struct { ...@@ -35,6 +35,7 @@ type parser struct {
doc *Node doc *Node
anchors map[string]*Node anchors map[string]*Node
doneInit bool doneInit bool
textless bool
} }
func newParser(b []byte) *parser { func newParser(b []byte) *parser {
...@@ -99,7 +100,10 @@ func (p *parser) peek() yaml_event_type_t { ...@@ -99,7 +100,10 @@ func (p *parser) peek() yaml_event_type_t {
if p.event.typ != yaml_NO_EVENT { if p.event.typ != yaml_NO_EVENT {
return p.event.typ return p.event.typ
} }
if !yaml_parser_parse(&p.parser, &p.event) { // It's curious choice from the underlying API to generally return a
// positive result on success, but on this case return true in an error
// scenario. This was the source of bugs in the past (issue #666).
if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR {
p.fail() p.fail()
} }
return p.event.typ return p.event.typ
...@@ -173,17 +177,20 @@ func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node { ...@@ -173,17 +177,20 @@ func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node {
} else if kind == ScalarNode { } else if kind == ScalarNode {
tag, _ = resolve("", value) tag, _ = resolve("", value)
} }
return &Node{ n := &Node{
Kind: kind, Kind: kind,
Tag: tag, Tag: tag,
Value: value, Value: value,
Style: style, Style: style,
Line: p.event.start_mark.line + 1, }
Column: p.event.start_mark.column + 1, if !p.textless {
HeadComment: string(p.event.head_comment), n.Line = p.event.start_mark.line + 1
LineComment: string(p.event.line_comment), n.Column = p.event.start_mark.column + 1
FootComment: string(p.event.foot_comment), n.HeadComment = string(p.event.head_comment)
n.LineComment = string(p.event.line_comment)
n.FootComment = string(p.event.foot_comment)
} }
return n
} }
func (p *parser) parseChild(parent *Node) *Node { func (p *parser) parseChild(parent *Node) *Node {
...@@ -316,6 +323,8 @@ type decoder struct { ...@@ -316,6 +323,8 @@ type decoder struct {
decodeCount int decodeCount int
aliasCount int aliasCount int
aliasDepth int aliasDepth int
mergedFields map[interface{}]bool
} }
var ( var (
...@@ -501,8 +510,13 @@ func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) { ...@@ -501,8 +510,13 @@ func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) {
good = d.mapping(n, out) good = d.mapping(n, out)
case SequenceNode: case SequenceNode:
good = d.sequence(n, out) good = d.sequence(n, out)
case 0:
if n.IsZero() {
return d.null(out)
}
fallthrough
default: default:
panic("internal error: unknown node kind: " + strconv.Itoa(int(n.Kind))) failf("cannot decode node with unknown kind %d", n.Kind)
} }
return good return good
} }
...@@ -537,6 +551,17 @@ func resetMap(out reflect.Value) { ...@@ -537,6 +551,17 @@ func resetMap(out reflect.Value) {
} }
} }
func (d *decoder) null(out reflect.Value) bool {
if out.CanAddr() {
switch out.Kind() {
case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
out.Set(reflect.Zero(out.Type()))
return true
}
}
return false
}
func (d *decoder) scalar(n *Node, out reflect.Value) bool { func (d *decoder) scalar(n *Node, out reflect.Value) bool {
var tag string var tag string
var resolved interface{} var resolved interface{}
...@@ -554,14 +579,7 @@ func (d *decoder) scalar(n *Node, out reflect.Value) bool { ...@@ -554,14 +579,7 @@ func (d *decoder) scalar(n *Node, out reflect.Value) bool {
} }
} }
if resolved == nil { if resolved == nil {
if out.CanAddr() { return d.null(out)
switch out.Kind() {
case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
out.Set(reflect.Zero(out.Type()))
return true
}
}
return false
} }
if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
// We've resolved to exactly the type we want, so use that. // We've resolved to exactly the type we want, so use that.
...@@ -795,16 +813,30 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { ...@@ -795,16 +813,30 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
} }
} }
mergedFields := d.mergedFields
d.mergedFields = nil
var mergeNode *Node
mapIsNew := false
if out.IsNil() { if out.IsNil() {
out.Set(reflect.MakeMap(outt)) out.Set(reflect.MakeMap(outt))
mapIsNew = true
} }
for i := 0; i < l; i += 2 { for i := 0; i < l; i += 2 {
if isMerge(n.Content[i]) { if isMerge(n.Content[i]) {
d.merge(n.Content[i+1], out) mergeNode = n.Content[i+1]
continue continue
} }
k := reflect.New(kt).Elem() k := reflect.New(kt).Elem()
if d.unmarshal(n.Content[i], k) { if d.unmarshal(n.Content[i], k) {
if mergedFields != nil {
ki := k.Interface()
if mergedFields[ki] {
continue
}
mergedFields[ki] = true
}
kkind := k.Kind() kkind := k.Kind()
if kkind == reflect.Interface { if kkind == reflect.Interface {
kkind = k.Elem().Kind() kkind = k.Elem().Kind()
...@@ -813,11 +845,17 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { ...@@ -813,11 +845,17 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
failf("invalid map key: %#v", k.Interface()) failf("invalid map key: %#v", k.Interface())
} }
e := reflect.New(et).Elem() e := reflect.New(et).Elem()
if d.unmarshal(n.Content[i+1], e) { if d.unmarshal(n.Content[i+1], e) || n.Content[i+1].ShortTag() == nullTag && (mapIsNew || !out.MapIndex(k).IsValid()) {
out.SetMapIndex(k, e) out.SetMapIndex(k, e)
} }
} }
} }
d.mergedFields = mergedFields
if mergeNode != nil {
d.merge(n, mergeNode, out)
}
d.stringMapType = stringMapType d.stringMapType = stringMapType
d.generalMapType = generalMapType d.generalMapType = generalMapType
return true return true
...@@ -829,7 +867,8 @@ func isStringMap(n *Node) bool { ...@@ -829,7 +867,8 @@ func isStringMap(n *Node) bool {
} }
l := len(n.Content) l := len(n.Content)
for i := 0; i < l; i += 2 { for i := 0; i < l; i += 2 {
if n.Content[i].ShortTag() != strTag { shortTag := n.Content[i].ShortTag()
if shortTag != strTag && shortTag != mergeTag {
return false return false
} }
} }
...@@ -846,7 +885,6 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { ...@@ -846,7 +885,6 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
var elemType reflect.Type var elemType reflect.Type
if sinfo.InlineMap != -1 { if sinfo.InlineMap != -1 {
inlineMap = out.Field(sinfo.InlineMap) inlineMap = out.Field(sinfo.InlineMap)
inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
elemType = inlineMap.Type().Elem() elemType = inlineMap.Type().Elem()
} }
...@@ -855,6 +893,9 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { ...@@ -855,6 +893,9 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
d.prepare(n, field) d.prepare(n, field)
} }
mergedFields := d.mergedFields
d.mergedFields = nil
var mergeNode *Node
var doneFields []bool var doneFields []bool
if d.uniqueKeys { if d.uniqueKeys {
doneFields = make([]bool, len(sinfo.FieldsList)) doneFields = make([]bool, len(sinfo.FieldsList))
...@@ -864,13 +905,20 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { ...@@ -864,13 +905,20 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
for i := 0; i < l; i += 2 { for i := 0; i < l; i += 2 {
ni := n.Content[i] ni := n.Content[i]
if isMerge(ni) { if isMerge(ni) {
d.merge(n.Content[i+1], out) mergeNode = n.Content[i+1]
continue continue
} }
if !d.unmarshal(ni, name) { if !d.unmarshal(ni, name) {
continue continue
} }
if info, ok := sinfo.FieldsMap[name.String()]; ok { sname := name.String()
if mergedFields != nil {
if mergedFields[sname] {
continue
}
mergedFields[sname] = true
}
if info, ok := sinfo.FieldsMap[sname]; ok {
if d.uniqueKeys { if d.uniqueKeys {
if doneFields[info.Id] { if doneFields[info.Id] {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type())) d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
...@@ -896,6 +944,11 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { ...@@ -896,6 +944,11 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type())) d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
} }
} }
d.mergedFields = mergedFields
if mergeNode != nil {
d.merge(n, mergeNode, out)
}
return true return true
} }
...@@ -903,19 +956,29 @@ func failWantMap() { ...@@ -903,19 +956,29 @@ func failWantMap() {
failf("map merge requires map or sequence of maps as the value") failf("map merge requires map or sequence of maps as the value")
} }
func (d *decoder) merge(n *Node, out reflect.Value) { func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) {
switch n.Kind { mergedFields := d.mergedFields
if mergedFields == nil {
d.mergedFields = make(map[interface{}]bool)
for i := 0; i < len(parent.Content); i += 2 {
k := reflect.New(ifaceType).Elem()
if d.unmarshal(parent.Content[i], k) {
d.mergedFields[k.Interface()] = true
}
}
}
switch merge.Kind {
case MappingNode: case MappingNode:
d.unmarshal(n, out) d.unmarshal(merge, out)
case AliasNode: case AliasNode:
if n.Alias != nil && n.Alias.Kind != MappingNode { if merge.Alias != nil && merge.Alias.Kind != MappingNode {
failWantMap() failWantMap()
} }
d.unmarshal(n, out) d.unmarshal(merge, out)
case SequenceNode: case SequenceNode:
// Step backwards as earlier nodes take precedence. for i := 0; i < len(merge.Content); i++ {
for i := len(n.Content) - 1; i >= 0; i-- { ni := merge.Content[i]
ni := n.Content[i]
if ni.Kind == AliasNode { if ni.Kind == AliasNode {
if ni.Alias != nil && ni.Alias.Kind != MappingNode { if ni.Alias != nil && ni.Alias.Kind != MappingNode {
failWantMap() failWantMap()
...@@ -928,6 +991,8 @@ func (d *decoder) merge(n *Node, out reflect.Value) { ...@@ -928,6 +991,8 @@ func (d *decoder) merge(n *Node, out reflect.Value) {
default: default:
failWantMap() failWantMap()
} }
d.mergedFields = mergedFields
} }
func isMerge(n *Node) bool { func isMerge(n *Node) bool {
......
...@@ -235,10 +235,13 @@ func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool ...@@ -235,10 +235,13 @@ func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool
emitter.indent = 0 emitter.indent = 0
} }
} else if !indentless { } else if !indentless {
emitter.indent += emitter.best_indent // [Go] This was changed so that indentations are more regular.
// [Go] If inside a block sequence item, discount the space taken by the indicator. if emitter.states[len(emitter.states)-1] == yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE {
if emitter.best_indent > 2 && emitter.states[len(emitter.states)-1] == yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE { // The first indent inside a sequence will just skip the "- " indicator.
emitter.indent -= 2 emitter.indent += 2
} else {
// Everything else aligns to the chosen indentation.
emitter.indent = emitter.best_indent*((emitter.indent+emitter.best_indent)/emitter.best_indent)
} }
} }
return true return true
...@@ -725,16 +728,9 @@ func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_e ...@@ -725,16 +728,9 @@ func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_e
// Expect a block item node. // Expect a block item node.
func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
if first { if first {
// [Go] The original logic here would not indent the sequence when if !yaml_emitter_increase_indent(emitter, false, false) {
// inside a mapping. In Go we always indent it.
indentless := false
original := emitter.indent
if !yaml_emitter_increase_indent(emitter, false, indentless) {
return false return false
} }
if emitter.indent > original+2 {
emitter.indent -= 2
}
} }
if event.typ == yaml_SEQUENCE_END_EVENT { if event.typ == yaml_SEQUENCE_END_EVENT {
emitter.indent = emitter.indents[len(emitter.indents)-1] emitter.indent = emitter.indents[len(emitter.indents)-1]
...@@ -785,6 +781,13 @@ func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_ev ...@@ -785,6 +781,13 @@ func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_ev
if !yaml_emitter_write_indent(emitter) { if !yaml_emitter_write_indent(emitter) {
return false return false
} }
if len(emitter.line_comment) > 0 {
// [Go] A line comment was provided for the key. That's unusual as the
// scanner associates line comments with the value. Either way,
// save the line comment and render it appropriately later.
emitter.key_line_comment = emitter.line_comment
emitter.line_comment = nil
}
if yaml_emitter_check_simple_key(emitter) { if yaml_emitter_check_simple_key(emitter) {
emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE) emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)
return yaml_emitter_emit_node(emitter, event, false, false, true, true) return yaml_emitter_emit_node(emitter, event, false, false, true, true)
...@@ -810,6 +813,27 @@ func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_ ...@@ -810,6 +813,27 @@ func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_
return false return false
} }
} }
if len(emitter.key_line_comment) > 0 {
// [Go] Line comments are generally associated with the value, but when there's
// no value on the same line as a mapping key they end up attached to the
// key itself.
if event.typ == yaml_SCALAR_EVENT {
if len(emitter.line_comment) == 0 {
// A scalar is coming and it has no line comments by itself yet,
// so just let it handle the line comment as usual. If it has a
// line comment, we can't have both so the one from the key is lost.
emitter.line_comment = emitter.key_line_comment
emitter.key_line_comment = nil
}
} else if event.sequence_style() != yaml_FLOW_SEQUENCE_STYLE && (event.typ == yaml_MAPPING_START_EVENT || event.typ == yaml_SEQUENCE_START_EVENT) {
// An indented block follows, so write the comment right now.
emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment
if !yaml_emitter_process_line_comment(emitter) {
return false
}
emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment
}
}
emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE) emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE)
if !yaml_emitter_emit_node(emitter, event, false, false, true, false) { if !yaml_emitter_emit_node(emitter, event, false, false, true, false) {
return false return false
...@@ -823,6 +847,10 @@ func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_ ...@@ -823,6 +847,10 @@ func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_
return true return true
} }
func yaml_emitter_silent_nil_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
return event.typ == yaml_SCALAR_EVENT && event.implicit && !emitter.canonical && len(emitter.scalar_data.value) == 0
}
// Expect a node. // Expect a node.
func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t, func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
root bool, sequence bool, mapping bool, simple_key bool) bool { root bool, sequence bool, mapping bool, simple_key bool) bool {
...@@ -1866,7 +1894,7 @@ func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bo ...@@ -1866,7 +1894,7 @@ func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bo
if !yaml_emitter_write_block_scalar_hints(emitter, value) { if !yaml_emitter_write_block_scalar_hints(emitter, value) {
return false return false
} }
if !put_break(emitter) { if !yaml_emitter_process_line_comment(emitter) {
return false return false
} }
//emitter.indention = true //emitter.indention = true
...@@ -1903,10 +1931,10 @@ func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) boo ...@@ -1903,10 +1931,10 @@ func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) boo
if !yaml_emitter_write_block_scalar_hints(emitter, value) { if !yaml_emitter_write_block_scalar_hints(emitter, value) {
return false return false
} }
if !yaml_emitter_process_line_comment(emitter) {
if !put_break(emitter) {
return false return false
} }
//emitter.indention = true //emitter.indention = true
emitter.whitespace = true emitter.whitespace = true
......
...@@ -120,6 +120,11 @@ func (e *encoder) marshal(tag string, in reflect.Value) { ...@@ -120,6 +120,11 @@ func (e *encoder) marshal(tag string, in reflect.Value) {
e.nodev(in) e.nodev(in)
return return
case Node: case Node:
if !in.CanAddr() {
var n = reflect.New(in.Type()).Elem()
n.Set(in)
in = n
}
e.nodev(in.Addr()) e.nodev(in.Addr())
return return
case time.Time: case time.Time:
...@@ -425,18 +430,23 @@ func (e *encoder) nodev(in reflect.Value) { ...@@ -425,18 +430,23 @@ func (e *encoder) nodev(in reflect.Value) {
} }
func (e *encoder) node(node *Node, tail string) { func (e *encoder) node(node *Node, tail string) {
// Zero nodes behave as nil.
if node.Kind == 0 && node.IsZero() {
e.nilv()
return
}
// If the tag was not explicitly requested, and dropping it won't change the // If the tag was not explicitly requested, and dropping it won't change the
// implicit tag of the value, don't include it in the presentation. // implicit tag of the value, don't include it in the presentation.
var tag = node.Tag var tag = node.Tag
var stag = shortTag(tag) var stag = shortTag(tag)
var rtag string
var forceQuoting bool var forceQuoting bool
if tag != "" && node.Style&TaggedStyle == 0 { if tag != "" && node.Style&TaggedStyle == 0 {
if node.Kind == ScalarNode { if node.Kind == ScalarNode {
if stag == strTag && node.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0 { if stag == strTag && node.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0 {
tag = "" tag = ""
} else { } else {
rtag, _ = resolve("", node.Value) rtag, _ := resolve("", node.Value)
if rtag == stag { if rtag == stag {
tag = "" tag = ""
} else if stag == strTag { } else if stag == strTag {
...@@ -445,6 +455,7 @@ func (e *encoder) node(node *Node, tail string) { ...@@ -445,6 +455,7 @@ func (e *encoder) node(node *Node, tail string) {
} }
} }
} else { } else {
var rtag string
switch node.Kind { switch node.Kind {
case MappingNode: case MappingNode:
rtag = mapTag rtag = mapTag
...@@ -474,7 +485,7 @@ func (e *encoder) node(node *Node, tail string) { ...@@ -474,7 +485,7 @@ func (e *encoder) node(node *Node, tail string) {
if node.Style&FlowStyle != 0 { if node.Style&FlowStyle != 0 {
style = yaml_FLOW_SEQUENCE_STYLE style = yaml_FLOW_SEQUENCE_STYLE
} }
e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(tag), tag == "", style)) e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style))
e.event.head_comment = []byte(node.HeadComment) e.event.head_comment = []byte(node.HeadComment)
e.emit() e.emit()
for _, node := range node.Content { for _, node := range node.Content {
...@@ -490,7 +501,7 @@ func (e *encoder) node(node *Node, tail string) { ...@@ -490,7 +501,7 @@ func (e *encoder) node(node *Node, tail string) {
if node.Style&FlowStyle != 0 { if node.Style&FlowStyle != 0 {
style = yaml_FLOW_MAPPING_STYLE style = yaml_FLOW_MAPPING_STYLE
} }
yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(tag), tag == "", style) yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style)
e.event.tail_comment = []byte(tail) e.event.tail_comment = []byte(tail)
e.event.head_comment = []byte(node.HeadComment) e.event.head_comment = []byte(node.HeadComment)
e.emit() e.emit()
...@@ -531,11 +542,11 @@ func (e *encoder) node(node *Node, tail string) { ...@@ -531,11 +542,11 @@ func (e *encoder) node(node *Node, tail string) {
case ScalarNode: case ScalarNode:
value := node.Value value := node.Value
if !utf8.ValidString(value) { if !utf8.ValidString(value) {
if tag == binaryTag { if stag == binaryTag {
failf("explicitly tagged !!binary data must be base64-encoded") failf("explicitly tagged !!binary data must be base64-encoded")
} }
if tag != "" { if stag != "" {
failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) failf("cannot marshal invalid UTF-8 data as %s", stag)
} }
// It can't be encoded directly as YAML so use a binary tag // It can't be encoded directly as YAML so use a binary tag
// and encode it as base64. // and encode it as base64.
...@@ -560,5 +571,7 @@ func (e *encoder) node(node *Node, tail string) { ...@@ -560,5 +571,7 @@ func (e *encoder) node(node *Node, tail string) {
} }
e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment), []byte(tail)) e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment), []byte(tail))
default:
failf("cannot encode node with unknown kind %d", node.Kind)
} }
} }
...@@ -648,6 +648,10 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i ...@@ -648,6 +648,10 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i
implicit: implicit, implicit: implicit,
style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE), style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE),
} }
if parser.stem_comment != nil {
event.head_comment = parser.stem_comment
parser.stem_comment = nil
}
return true return true
} }
if len(anchor) > 0 || len(tag) > 0 { if len(anchor) > 0 || len(tag) > 0 {
...@@ -683,6 +687,9 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i ...@@ -683,6 +687,9 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i
func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
if first { if first {
token := peek_token(parser) token := peek_token(parser)
if token == nil {
return false
}
parser.marks = append(parser.marks, token.start_mark) parser.marks = append(parser.marks, token.start_mark)
skip_token(parser) skip_token(parser)
} }
...@@ -694,25 +701,13 @@ func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_e ...@@ -694,25 +701,13 @@ func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_e
if token.typ == yaml_BLOCK_ENTRY_TOKEN { if token.typ == yaml_BLOCK_ENTRY_TOKEN {
mark := token.end_mark mark := token.end_mark
prior_head := len(parser.head_comment) prior_head_len := len(parser.head_comment)
skip_token(parser) skip_token(parser)
yaml_parser_split_stem_comment(parser, prior_head_len)
token = peek_token(parser) token = peek_token(parser)
if token == nil { if token == nil {
return false return false
} }
if prior_head > 0 && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN {
// [Go] It's a sequence under a sequence entry, so the former head comment
// is for the list itself, not the first list item under it.
parser.stem_comment = parser.head_comment[:prior_head]
if len(parser.head_comment) == prior_head {
parser.head_comment = nil
} else {
// Copy suffix to prevent very strange bugs if someone ever appends
// further bytes to the prefix in the stem_comment slice above.
parser.head_comment = append([]byte(nil), parser.head_comment[prior_head+1:]...)
}
}
if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN {
parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE) parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)
return yaml_parser_parse_node(parser, event, true, false) return yaml_parser_parse_node(parser, event, true, false)
...@@ -754,7 +749,9 @@ func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *y ...@@ -754,7 +749,9 @@ func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *y
if token.typ == yaml_BLOCK_ENTRY_TOKEN { if token.typ == yaml_BLOCK_ENTRY_TOKEN {
mark := token.end_mark mark := token.end_mark
prior_head_len := len(parser.head_comment)
skip_token(parser) skip_token(parser)
yaml_parser_split_stem_comment(parser, prior_head_len)
token = peek_token(parser) token = peek_token(parser)
if token == nil { if token == nil {
return false return false
...@@ -780,6 +777,32 @@ func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *y ...@@ -780,6 +777,32 @@ func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *y
return true return true
} }
// Split stem comment from head comment.
//
// When a sequence or map is found under a sequence entry, the former head comment
// is assigned to the underlying sequence or map as a whole, not the individual
// sequence or map entry as would be expected otherwise. To handle this case the
// previous head comment is moved aside as the stem comment.
func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) {
if stem_len == 0 {
return
}
token := peek_token(parser)
if token == nil || token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN {
return
}
parser.stem_comment = parser.head_comment[:stem_len]
if len(parser.head_comment) == stem_len {
parser.head_comment = nil
} else {
// Copy suffix to prevent very strange bugs if someone ever appends
// further bytes to the prefix in the stem_comment slice above.
parser.head_comment = append([]byte(nil), parser.head_comment[stem_len+1:]...)
}
}
// Parse the productions: // Parse the productions:
// block_mapping ::= BLOCK-MAPPING_START // block_mapping ::= BLOCK-MAPPING_START
// ******************* // *******************
...@@ -793,6 +816,9 @@ func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *y ...@@ -793,6 +816,9 @@ func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *y
func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
if first { if first {
token := peek_token(parser) token := peek_token(parser)
if token == nil {
return false
}
parser.marks = append(parser.marks, token.start_mark) parser.marks = append(parser.marks, token.start_mark)
skip_token(parser) skip_token(parser)
} }
...@@ -902,6 +928,9 @@ func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_ev ...@@ -902,6 +928,9 @@ func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_ev
func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
if first { if first {
token := peek_token(parser) token := peek_token(parser)
if token == nil {
return false
}
parser.marks = append(parser.marks, token.start_mark) parser.marks = append(parser.marks, token.start_mark)
skip_token(parser) skip_token(parser)
} }
......
...@@ -749,6 +749,11 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) (ok bool) { ...@@ -749,6 +749,11 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) (ok bool) {
if !ok { if !ok {
return return
} }
if len(parser.tokens) > 0 && parser.tokens[len(parser.tokens)-1].typ == yaml_BLOCK_ENTRY_TOKEN {
// Sequence indicators alone have no line comments. It becomes
// a head comment for whatever follows.
return
}
if !yaml_parser_scan_line_comment(parser, comment_mark) { if !yaml_parser_scan_line_comment(parser, comment_mark) {
ok = false ok = false
return return
...@@ -2255,10 +2260,9 @@ func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, l ...@@ -2255,10 +2260,9 @@ func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, l
} }
} }
if parser.buffer[parser.buffer_pos] == '#' { if parser.buffer[parser.buffer_pos] == '#' {
// TODO Test this and then re-enable it. if !yaml_parser_scan_line_comment(parser, start_mark) {
//if !yaml_parser_scan_line_comment(parser, start_mark) { return false
// return false }
//}
for !is_breakz(parser.buffer, parser.buffer_pos) { for !is_breakz(parser.buffer, parser.buffer_pos) {
skip(parser) skip(parser)
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
...@@ -2856,13 +2860,12 @@ func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t ...@@ -2856,13 +2860,12 @@ func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t
return false return false
} }
skip_line(parser) skip_line(parser)
} else { } else if parser.mark.index >= seen {
if parser.mark.index >= seen { if len(text) == 0 {
if len(text) == 0 { start_mark = parser.mark
start_mark = parser.mark
}
text = append(text, parser.buffer[parser.buffer_pos])
} }
text = read(parser, text)
} else {
skip(parser) skip(parser)
} }
} }
...@@ -2888,6 +2891,10 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo ...@@ -2888,6 +2891,10 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo
var token_mark = token.start_mark var token_mark = token.start_mark
var start_mark yaml_mark_t var start_mark yaml_mark_t
var next_indent = parser.indent
if next_indent < 0 {
next_indent = 0
}
var recent_empty = false var recent_empty = false
var first_empty = parser.newlines <= 1 var first_empty = parser.newlines <= 1
...@@ -2919,15 +2926,18 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo ...@@ -2919,15 +2926,18 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo
continue continue
} }
c := parser.buffer[parser.buffer_pos+peek] c := parser.buffer[parser.buffer_pos+peek]
if is_breakz(parser.buffer, parser.buffer_pos+peek) || parser.flow_level > 0 && (c == ']' || c == '}') { var close_flow = parser.flow_level > 0 && (c == ']' || c == '}')
if close_flow || is_breakz(parser.buffer, parser.buffer_pos+peek) {
// Got line break or terminator. // Got line break or terminator.
if !recent_empty { if close_flow || !recent_empty {
if first_empty && (start_mark.line == foot_line || start_mark.column-1 < parser.indent) { if close_flow || first_empty && (start_mark.line == foot_line && token.typ != yaml_VALUE_TOKEN || start_mark.column-1 < next_indent) {
// This is the first empty line and there were no empty lines before, // This is the first empty line and there were no empty lines before,
// so this initial part of the comment is a foot of the prior token // so this initial part of the comment is a foot of the prior token
// instead of being a head for the following one. Split it up. // instead of being a head for the following one. Split it up.
// Alternatively, this might also be the last comment inside a flow
// scope, so it must be a footer.
if len(text) > 0 { if len(text) > 0 {
if start_mark.column-1 < parser.indent { if start_mark.column-1 < next_indent {
// If dedented it's unrelated to the prior token. // If dedented it's unrelated to the prior token.
token_mark = start_mark token_mark = start_mark
} }
...@@ -2958,7 +2968,7 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo ...@@ -2958,7 +2968,7 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo
continue continue
} }
if len(text) > 0 && column < parser.indent+1 && column != start_mark.column { if len(text) > 0 && (close_flow || column-1 < next_indent && column != start_mark.column) {
// The comment at the different indentation is a foot of the // The comment at the different indentation is a foot of the
// preceding data rather than a head of the upcoming one. // preceding data rather than a head of the upcoming one.
parser.comments = append(parser.comments, yaml_comment_t{ parser.comments = append(parser.comments, yaml_comment_t{
...@@ -3009,6 +3019,10 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo ...@@ -3009,6 +3019,10 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo
peek = 0 peek = 0
column = 0 column = 0
line = parser.mark.line line = parser.mark.line
next_indent = parser.indent
if next_indent < 0 {
next_indent = 0
}
} }
if len(text) > 0 { if len(text) > 0 {
......
...@@ -89,7 +89,7 @@ func Unmarshal(in []byte, out interface{}) (err error) { ...@@ -89,7 +89,7 @@ func Unmarshal(in []byte, out interface{}) (err error) {
return unmarshal(in, out, false) return unmarshal(in, out, false)
} }
// A Decorder reads and decodes YAML values from an input stream. // A Decoder reads and decodes YAML values from an input stream.
type Decoder struct { type Decoder struct {
parser *parser parser *parser
knownFields bool knownFields bool
...@@ -194,7 +194,7 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) { ...@@ -194,7 +194,7 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) {
// Zero valued structs will be omitted if all their public // Zero valued structs will be omitted if all their public
// fields are zero, unless they implement an IsZero // fields are zero, unless they implement an IsZero
// method (see the IsZeroer interface type), in which // method (see the IsZeroer interface type), in which
// case the field will be included if that method returns true. // case the field will be excluded if IsZero returns true.
// //
// flow Marshal using a flow style (useful for structs, // flow Marshal using a flow style (useful for structs,
// sequences and maps). // sequences and maps).
...@@ -252,6 +252,24 @@ func (e *Encoder) Encode(v interface{}) (err error) { ...@@ -252,6 +252,24 @@ func (e *Encoder) Encode(v interface{}) (err error) {
return nil return nil
} }
// Encode encodes value v and stores its representation in n.
//
// See the documentation for Marshal for details about the
// conversion of Go values into YAML.
func (n *Node) Encode(v interface{}) (err error) {
defer handleErr(&err)
e := newEncoder()
defer e.destroy()
e.marshalDoc("", reflect.ValueOf(v))
e.finish()
p := newParser(e.out)
p.textless = true
defer p.destroy()
doc := p.parse()
*n = *doc.Content[0]
return nil
}
// SetIndent changes the used indentation used when encoding. // SetIndent changes the used indentation used when encoding.
func (e *Encoder) SetIndent(spaces int) { func (e *Encoder) SetIndent(spaces int) {
if spaces < 0 { if spaces < 0 {
...@@ -328,6 +346,12 @@ const ( ...@@ -328,6 +346,12 @@ const (
// and maps, Node is an intermediate representation that allows detailed // and maps, Node is an intermediate representation that allows detailed
// control over the content being decoded or encoded. // control over the content being decoded or encoded.
// //
// It's worth noting that although Node offers access into details such as
// line numbers, colums, and comments, the content when re-encoded will not
// have its original textual representation preserved. An effort is made to
// render the data plesantly, and to preserve comments near the data they
// describe, though.
//
// Values that make use of the Node type interact with the yaml package in the // Values that make use of the Node type interact with the yaml package in the
// same way any other type would do, by encoding and decoding yaml data // same way any other type would do, by encoding and decoding yaml data
// directly or indirectly into them. // directly or indirectly into them.
...@@ -391,6 +415,13 @@ type Node struct { ...@@ -391,6 +415,13 @@ type Node struct {
Column int Column int
} }
// IsZero returns whether the node has all of its fields unset.
func (n *Node) IsZero() bool {
return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil &&
n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0
}
// LongTag returns the long form of the tag that indicates the data type for // LongTag returns the long form of the tag that indicates the data type for
// the node. If the Tag field isn't explicitly defined, one will be computed // the node. If the Tag field isn't explicitly defined, one will be computed
// based on the node properties. // based on the node properties.
...@@ -418,6 +449,11 @@ func (n *Node) ShortTag() string { ...@@ -418,6 +449,11 @@ func (n *Node) ShortTag() string {
case ScalarNode: case ScalarNode:
tag, _ := resolve("", n.Value) tag, _ := resolve("", n.Value)
return tag return tag
case 0:
// Special case to make the zero value convenient.
if n.IsZero() {
return nullTag
}
} }
return "" return ""
} }
......
...@@ -787,6 +787,8 @@ type yaml_emitter_t struct { ...@@ -787,6 +787,8 @@ type yaml_emitter_t struct {
foot_comment []byte foot_comment []byte
tail_comment []byte tail_comment []byte
key_line_comment []byte
// Dumper stuff // Dumper stuff
opened bool // If the stream was already opened? opened bool // If the stream was already opened?
......
...@@ -10,7 +10,7 @@ github.com/beorn7/perks/quantile ...@@ -10,7 +10,7 @@ github.com/beorn7/perks/quantile
github.com/cenkalti/backoff/v4 github.com/cenkalti/backoff/v4
# github.com/cespare/xxhash/v2 v2.1.1 # github.com/cespare/xxhash/v2 v2.1.1
github.com/cespare/xxhash/v2 github.com/cespare/xxhash/v2
# github.com/coreos/go-systemd/v22 v22.2.0 # github.com/coreos/go-systemd/v22 v22.5.0
## explicit ## explicit
github.com/coreos/go-systemd/v22/activation github.com/coreos/go-systemd/v22/activation
github.com/coreos/go-systemd/v22/daemon github.com/coreos/go-systemd/v22/daemon
...@@ -86,6 +86,6 @@ google.golang.org/protobuf/runtime/protoimpl ...@@ -86,6 +86,6 @@ google.golang.org/protobuf/runtime/protoimpl
google.golang.org/protobuf/types/known/anypb google.golang.org/protobuf/types/known/anypb
google.golang.org/protobuf/types/known/durationpb google.golang.org/protobuf/types/known/durationpb
google.golang.org/protobuf/types/known/timestamppb google.golang.org/protobuf/types/known/timestamppb
# gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86 # gopkg.in/yaml.v3 v3.0.1
## explicit ## explicit
gopkg.in/yaml.v3 gopkg.in/yaml.v3