Move to the mattermost/go-i18n fork (#10669)

This change is being made to address an issue where the go-i18n
translation library would result in partial-translations when a
given language dictionary was missing a given plural keyword. The
improvement made here leads the translation library to try an
'other' keyword lookup if the first plural keyword fails to have
a value.

This change was not accepted upstream due to concern regarding
changing the behavior, so we are using a fork at this time to
address the issue.
This commit is contained in:
Gabe Jackson
2019-04-23 09:33:42 -04:00
committed by GitHub
parent 0d1c69927f
commit be4b473aee
78 changed files with 888 additions and 409 deletions

View File

@@ -12,7 +12,7 @@ import (
"github.com/mattermost/mattermost-server/services/configservice"
"github.com/mattermost/mattermost-server/web"
_ "github.com/nicksnyder/go-i18n/i18n"
_ "github.com/mattermost/go-i18n/i18n"
)
type Routes struct {

View File

@@ -9,6 +9,7 @@ import (
"net/http"
"strconv"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/einterfaces"
"github.com/mattermost/mattermost-server/jobs"
"github.com/mattermost/mattermost-server/mlog"
@@ -17,7 +18,6 @@ import (
"github.com/mattermost/mattermost-server/services/imageproxy"
"github.com/mattermost/mattermost-server/services/timezones"
"github.com/mattermost/mattermost-server/utils"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type App struct {

View File

@@ -11,11 +11,11 @@ import (
"net/url"
"strings"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store"
"github.com/mattermost/mattermost-server/utils"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type CommandProvider interface {

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type AwayProvider struct {

View File

@@ -4,7 +4,7 @@
package app
import (
goi18n "github.com/nicksnyder/go-i18n/i18n"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
)

View File

@@ -4,7 +4,7 @@
package app
import (
goi18n "github.com/nicksnyder/go-i18n/i18n"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
)

View File

@@ -4,7 +4,7 @@
package app
import (
goi18n "github.com/nicksnyder/go-i18n/i18n"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
)

View File

@@ -6,8 +6,8 @@ package app
import (
"strings"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type CodeProvider struct {

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type DndProvider struct {

View File

@@ -9,9 +9,9 @@ import (
"strings"
"time"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
var echoSem chan bool

View File

@@ -6,8 +6,8 @@ package app
import (
"strconv"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type ExpandProvider struct {

View File

@@ -7,9 +7,9 @@ import (
"fmt"
"strings"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type groupmsgProvider struct {

View File

@@ -3,7 +3,7 @@ package app
import (
"testing"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/mattermost/go-i18n/i18n"
"github.com/stretchr/testify/assert"
"github.com/mattermost/mattermost-server/model"

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type HelpProvider struct {

View File

@@ -6,7 +6,7 @@ package app
import (
"strings"
goi18n "github.com/nicksnyder/go-i18n/i18n"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"

View File

@@ -6,9 +6,9 @@ package app
import (
"strings"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type InvitePeopleProvider struct {

View File

@@ -6,7 +6,7 @@ package app
import (
"strings"
goi18n "github.com/nicksnyder/go-i18n/i18n"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
)

View File

@@ -6,7 +6,7 @@ package app
import (
"testing"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/mattermost/go-i18n/i18n"
"github.com/stretchr/testify/assert"
"github.com/mattermost/mattermost-server/model"

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type LeaveProvider struct {

View File

@@ -10,10 +10,10 @@ import (
"strconv"
"strings"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
var usage = `Mattermost testing commands to help configure the system

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type LogoutProvider struct {

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type MeProvider struct {

View File

@@ -6,9 +6,9 @@ package app
import (
"strings"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type msgProvider struct {

View File

@@ -6,7 +6,7 @@ package app
import (
"testing"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/mattermost/go-i18n/i18n"
"github.com/stretchr/testify/assert"
"github.com/mattermost/mattermost-server/model"

View File

@@ -6,8 +6,8 @@ package app
import (
"strings"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type MuteProvider struct {

View File

@@ -7,8 +7,8 @@ import (
"testing"
"time"
"github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/stretchr/testify/assert"
)

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type OfflineProvider struct {

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type OnlineProvider struct {

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type OpenProvider struct {

View File

@@ -6,7 +6,7 @@ package app
import (
"strings"
goi18n "github.com/nicksnyder/go-i18n/i18n"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type SearchProvider struct {

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type SettingsProvider struct {

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type ShortcutsProvider struct {

View File

@@ -4,8 +4,8 @@
package app
import (
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
type ShrugProvider struct {

View File

@@ -9,7 +9,7 @@ import (
"net/http"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/mattermost/go-i18n/i18n"
"github.com/pkg/errors"
"github.com/throttled/throttled"
"github.com/throttled/throttled/store/memstore"

View File

@@ -16,7 +16,7 @@ import (
"net/http"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/mattermost/go-i18n/i18n"
)
const (

View File

@@ -13,7 +13,7 @@ var mainHelper *testlib.MainHelper
func TestMain(m *testing.M) {
var options = testlib.HelperOptions{
EnableStore: true,
EnableStore: true,
EnableResources: true,
}

View File

@@ -11,10 +11,10 @@ import (
"strings"
"time"
"github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
"github.com/nicksnyder/go-i18n/i18n"
)
func (a *App) sendNotificationEmail(notification *postNotification, user *model.User, team *model.Team) *model.AppError {

View File

@@ -9,10 +9,10 @@ import (
"net/http"
"strings"
"github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
"github.com/nicksnyder/go-i18n/i18n"
)
type NotificationType string

View File

@@ -230,7 +230,7 @@ func TestPanicLog(t *testing.T) {
ConsoleJson: true,
EnableFile: true,
FileLocation: tmpfile.Name(),
FileLevel: mlog.LevelInfo,
FileLevel: mlog.LevelInfo,
})
// Creating a server with logger

View File

@@ -10,9 +10,9 @@ import (
"time"
"github.com/gorilla/websocket"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
const (

View File

@@ -8,7 +8,7 @@ import (
"time"
"github.com/gorilla/websocket"
goi18n "github.com/nicksnyder/go-i18n/i18n"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/model"

3
go.mod
View File

@@ -41,6 +41,7 @@ require (
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/lib/pq v1.0.0
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe // indirect
github.com/mattermost/go-i18n v1.1.2
github.com/mattermost/gorp v2.0.1-0.20190301154413-3b31e9a39d05+incompatible
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0
github.com/mattermost/viper v1.0.4
@@ -50,12 +51,12 @@ require (
github.com/minio/minio-go v6.0.14+incompatible
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
github.com/nicksnyder/go-i18n v1.10.0
github.com/olekukonko/tablewriter v0.0.1 // indirect
github.com/onsi/ginkgo v1.8.0 // indirect
github.com/onsi/gomega v1.5.0 // indirect
github.com/pascaldekloe/goe v0.1.0 // indirect
github.com/pborman/uuid v1.2.0
github.com/pelletier/go-toml v1.3.0 // indirect
github.com/pkg/errors v0.8.1
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 // indirect

6
go.sum
View File

@@ -206,6 +206,8 @@ github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/mattermost/go-i18n v1.1.2 h1:iyIztdnCePILpzW1nsZSLQtqhtI6M5E3OS6IkFv/BMw=
github.com/mattermost/go-i18n v1.1.2/go.mod h1:RyS7FDNQlzF1PsjbJWHRI35exqaKGSO9qD4iv8QjE34=
github.com/mattermost/gorp v2.0.1-0.20190301154413-3b31e9a39d05+incompatible h1:FN4zK2wNig7MVVsOsGEZ+LeIq0gUcudn3LEGgbodMq8=
github.com/mattermost/gorp v2.0.1-0.20190301154413-3b31e9a39d05+incompatible/go.mod h1:0kX1qa3DOpaPJyOdMLeo7TcBN0QmUszj9a/VygOhDe0=
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0 h1:G9tL6JXRBMzjuD1kkBtcnd42kUiT6QDwxfFYu7adM6o=
@@ -240,8 +242,6 @@ github.com/muesli/smartcrop v0.2.1-0.20181030220600-548bbf0c0965/go.mod h1:i2fCI
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/nicksnyder/go-i18n v1.10.0 h1:5AzlPKvXBH4qBzmZ09Ua9Gipyruv6uApMcrNZdo96+Q=
github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
@@ -264,6 +264,8 @@ github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.3.0 h1:e5+lF2E4Y2WCIxBefVowBuB0iHrUH4HZ8q+6mGF7fJc=
github.com/pelletier/go-toml v1.3.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/peterbourgon/diskv v0.0.0-20171120014656-2973218375c3/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@@ -7,7 +7,7 @@ import (
"encoding/json"
"io"
goi18n "github.com/nicksnyder/go-i18n/i18n"
goi18n "github.com/mattermost/go-i18n/i18n"
)
type CommandArgs struct {

View File

@@ -21,7 +21,7 @@ import (
"time"
"unicode"
goi18n "github.com/nicksnyder/go-i18n/i18n"
goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/pborman/uuid"
)

View File

@@ -7,7 +7,7 @@ import (
"encoding/json"
"io"
goi18n "github.com/nicksnyder/go-i18n/i18n"
goi18n "github.com/mattermost/go-i18n/i18n"
)
type WebSocketRequest struct {

View File

@@ -15,9 +15,9 @@ import (
"sync/atomic"
"github.com/fsnotify/fsnotify"
"github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/utils/fileutils"
"github.com/nicksnyder/go-i18n/i18n"
)
type HTMLTemplateWatcher struct {

View File

@@ -12,10 +12,10 @@ import (
"testing"
"time"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/nicksnyder/go-i18n/i18n/bundle"
"github.com/nicksnyder/go-i18n/i18n/language"
"github.com/nicksnyder/go-i18n/i18n/translation"
"github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/go-i18n/i18n/bundle"
"github.com/mattermost/go-i18n/i18n/language"
"github.com/mattermost/go-i18n/i18n/translation"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

View File

@@ -10,10 +10,10 @@ import (
"path/filepath"
"strings"
"github.com/mattermost/go-i18n/i18n"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils/fileutils"
"github.com/nicksnyder/go-i18n/i18n"
)
var T i18n.TranslateFunc

View File

@@ -11,8 +11,8 @@ import (
"sync"
"unicode"
"github.com/nicksnyder/go-i18n/i18n/language"
"github.com/nicksnyder/go-i18n/i18n/translation"
"github.com/mattermost/go-i18n/i18n/language"
"github.com/mattermost/go-i18n/i18n/translation"
toml "github.com/pelletier/go-toml"
"gopkg.in/yaml.v2"
)
@@ -110,13 +110,12 @@ func parseTranslations(filename string, buf []byte) ([]translation.Translation,
return nil, fmt.Errorf("failed to unmarshal %v: %v", filename, err)
}
return parseStandardFormat(standardFormat)
} else {
var flatFormat map[string]map[string]interface{}
if err := unmarshal(ext, buf, &flatFormat); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", filename, err)
}
return parseFlatFormat(flatFormat)
}
var flatFormat map[string]map[string]interface{}
if err := unmarshal(ext, buf, &flatFormat); err != nil {
return nil, fmt.Errorf("failed to unmarshal %v: %v", filename, err)
}
return parseFlatFormat(flatFormat)
}
func isStandardFormat(ext string, buf []byte) bool {
@@ -381,7 +380,16 @@ func (b *Bundle) translate(lang *language.Language, translationID string, args .
p, _ := lang.Plural(count)
template := translation.Template(p)
if template == nil {
return translationID
if p == language.Other {
return translationID
}
countInt, ok := count.(int)
if ok && countInt > 1 {
template = translation.Template(language.Other)
if template == nil {
return translationID
}
}
}
s := template.Execute(data)

View File

@@ -56,9 +56,9 @@
package i18n
import (
"github.com/nicksnyder/go-i18n/i18n/bundle"
"github.com/nicksnyder/go-i18n/i18n/language"
"github.com/nicksnyder/go-i18n/i18n/translation"
"github.com/mattermost/go-i18n/i18n/bundle"
"github.com/mattermost/go-i18n/i18n/language"
"github.com/mattermost/go-i18n/i18n/translation"
)
// TranslateFunc returns the translation of the string identified by translationID.

View File

@@ -6,7 +6,7 @@ import (
"strings"
)
// http://unicode.org/reports/tr35/tr35-numbers.html#Operands
// Operands is a representation of http://unicode.org/reports/tr35/tr35-numbers.html#Operands
type Operands struct {
N float64 // absolute value of the source number (integer and decimals)
I int64 // integer digits of n
@@ -16,7 +16,7 @@ type Operands struct {
T int64 // visible fractional digits in n, without trailing zeros
}
// NmodEqualAny returns true if o represents an integer equal to any of the arguments.
// NequalsAny returns true if o represents an integer equal to any of the arguments.
func (o *Operands) NequalsAny(any ...int64) bool {
for _, i := range any {
if o.I == i && o.T == 0 {
@@ -26,7 +26,7 @@ func (o *Operands) NequalsAny(any ...int64) bool {
return false
}
// NmodEqualAny returns true if o represents an integer equal to any of the arguments modulo mod.
// NmodEqualsAny returns true if o represents an integer equal to any of the arguments modulo mod.
func (o *Operands) NmodEqualsAny(mod int64, any ...int64) bool {
modI := o.I % mod
for _, i := range any {
@@ -37,7 +37,7 @@ func (o *Operands) NmodEqualsAny(mod int64, any ...int64) bool {
return false
}
// NmodInRange returns true if o represents an integer in the closed interval [from, to].
// NinRange returns true if o represents an integer in the closed interval [from, to].
func (o *Operands) NinRange(from, to int64) bool {
return o.T == 0 && from <= o.I && o.I <= to
}

View File

@@ -1,7 +1,7 @@
package translation
import (
"github.com/nicksnyder/go-i18n/i18n/language"
"github.com/mattermost/go-i18n/i18n/language"
)
type pluralTranslation struct {

View File

@@ -1,7 +1,7 @@
package translation
import (
"github.com/nicksnyder/go-i18n/i18n/language"
"github.com/mattermost/go-i18n/i18n/language"
)
type singleTranslation struct {

View File

@@ -4,7 +4,7 @@ package translation
import (
"fmt"
"github.com/nicksnyder/go-i18n/i18n/language"
"github.com/mattermost/go-i18n/i18n/language"
)
// Translation is the interface that represents a translated string.
@@ -50,11 +50,11 @@ func NewTranslation(data map[string]interface{}) (Translation, error) {
// The YAML parser uses interface{} keys so we first convert them to string keys.
pluralObject = make(map[string]interface{})
for k, v := range translation {
kStr, ok := k.(string)
kstr, ok := k.(string)
if !ok {
return nil, fmt.Errorf(`invalid plural category type %T; expected string`, k)
}
pluralObject[kStr] = v
pluralObject[kstr] = v
}
case map[string]interface{}:
pluralObject = translation

View File

@@ -1,23 +1,22 @@
sudo: false
language: go
go:
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- 1.12.x
- tip
matrix:
allow_failures:
- go: tip
fast_finish: true
env:
- GO111MODULE=on
script:
- if [ -n "$(go fmt ./...)" ]; then exit 1; fi
- ./test.sh
- go test github.com/pelletier/go-toml -race -coverprofile=coverage.txt -covermode=atomic
- go test github.com/pelletier/go-toml/cmd/tomljson
- go test github.com/pelletier/go-toml/cmd/tomll
- go test github.com/pelletier/go-toml/query
- ./benchmark.sh $TRAVIS_BRANCH https://github.com/$TRAVIS_REPO_SLUG.git
before_install:
- go get github.com/axw/gocov/gocov
- go get github.com/mattn/goveralls
- if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
branches:
only: [master]
after_success:
- $HOME/gopath/bin/goveralls -service=travis-ci -coverprofile=coverage.out -repotoken $COVERALLS_TOKEN
- bash <(curl -s https://codecov.io/bash)

132
vendor/github.com/pelletier/go-toml/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,132 @@
## Contributing
Thank you for your interest in go-toml! We appreciate you considering
contributing to go-toml!
The main goal is the project is to provide an easy-to-use TOML
implementation for Go that gets the job done and gets out of your way
dealing with TOML is probably not the central piece of your project.
As the single maintainer of go-toml, time is scarce. All help, big or
small, is more than welcomed!
### Ask questions
Any question you may have, somebody else might have it too. Always feel
free to ask them on the [issues tracker][issues-tracker]. We will try to
answer them as clearly and quickly as possible, time permitting.
Asking questions also helps us identify areas where the documentation needs
improvement, or new features that weren't envisioned before. Sometimes, a
seemingly innocent question leads to the fix of a bug. Don't hesitate and
ask away!
### Improve the documentation
The best way to share your knowledge and experience with go-toml is to
improve the documentation. Fix a typo, clarify an interface, add an
example, anything goes!
The documentation is present in the [README][readme] and thorough the
source code. On release, it gets updated on [GoDoc][godoc]. To make a
change to the documentation, create a pull request with your proposed
changes. For simple changes like that, the easiest way to go is probably
the "Fork this project and edit the file" button on Github, displayed at
the top right of the file. Unless it's a trivial change (for example a
typo), provide a little bit of context in your pull request description or
commit message.
### Report a bug
Found a bug! Sorry to hear that :(. Help us and other track them down and
fix by reporting it. [File a new bug report][bug-report] on the [issues
tracker][issues-tracker]. The template should provide enough guidance on
what to include. When in doubt: add more details! By reducing ambiguity and
providing more information, it decreases back and forth and saves everyone
time.
### Code changes
Want to contribute a patch? Very happy to hear that!
First, some high-level rules:
* A short proposal with some POC code is better than a lengthy piece of
text with no code. Code speaks louder than words.
* No backward-incompatible patch will be accepted unless discussed.
Sometimes it's hard, and Go's lack of versioning by default does not
help, but we try not to break people's programs unless we absolutely have
to.
* If you are writing a new feature or extending an existing one, make sure
to write some documentation.
* Bug fixes need to be accompanied with regression tests.
* New code needs to be tested.
* Your commit messages need to explain why the change is needed, even if
already included in the PR description.
It does sound like a lot, but those best practices are here to save time
overall and continuously improve the quality of the project, which is
something everyone benefits from.
#### Get started
The fairly standard code contribution process looks like that:
1. [Fork the project][fork].
2. Make your changes, commit on any branch you like.
3. [Open up a pull request][pull-request]
4. Review, potential ask for changes.
5. Merge. You're in!
Feel free to ask for help! You can create draft pull requests to gather
some early feedback!
#### Run the tests
You can run tests for go-toml using Go's test tool: `go test ./...`.
When creating a pull requests, all tests will be ran on Linux on a few Go
versions (Travis CI), and on Windows using the latest Go version
(AppVeyor).
#### Style
Try to look around and follow the same format and structure as the rest of
the code. We enforce using `go fmt` on the whole code base.
---
### Maintainers-only
#### Merge pull request
Checklist:
* Passing CI.
* Does not introduce backward-incompatible changes (unless discussed).
* Has relevant doc changes.
* Has relevant unit tests.
1. Merge using "squash and merge".
2. Make sure to edit the commit message to keep all the useful information
nice and clean.
3. Make sure the commit title is clear and contains the PR number (#123).
#### New release
1. Go to [releases][releases]. Click on "X commits to master since this
release".
2. Make note of all the changes. Look for backward incompatible changes,
new features, and bug fixes.
3. Pick the new version using the above and semver.
4. Create a [new release][new-release].
5. Follow the same format as [1.1.0][release-110].
[issues-tracker]: https://github.com/pelletier/go-toml/issues
[bug-report]: https://github.com/pelletier/go-toml/issues/new?template=bug_report.md
[godoc]: https://godoc.org/github.com/pelletier/go-toml
[readme]: ./README.md
[fork]: https://help.github.com/articles/fork-a-repo
[pull-request]: https://help.github.com/en/articles/creating-a-pull-request
[releases]: https://github.com/pelletier/go-toml/releases
[new-release]: https://github.com/pelletier/go-toml/releases/new
[release-110]: https://github.com/pelletier/go-toml/releases/tag/v1.1.0

View File

@@ -0,0 +1,5 @@
**Issue:** add link to pelletier/go-toml issue here
Explanation of what this pull request does.
More detailed description of the decisions being made and the reasons why (if the patch is non-trivial).

View File

@@ -8,8 +8,10 @@ This library supports TOML version
[![GoDoc](https://godoc.org/github.com/pelletier/go-toml?status.svg)](http://godoc.org/github.com/pelletier/go-toml)
[![license](https://img.shields.io/github/license/pelletier/go-toml.svg)](https://github.com/pelletier/go-toml/blob/master/LICENSE)
[![Build Status](https://travis-ci.org/pelletier/go-toml.svg?branch=master)](https://travis-ci.org/pelletier/go-toml)
[![Coverage Status](https://coveralls.io/repos/github/pelletier/go-toml/badge.svg?branch=master)](https://coveralls.io/github/pelletier/go-toml?branch=master)
[![Windows Build status](https://ci.appveyor.com/api/projects/status/4aepwwjori266hkt/branch/master?svg=true)](https://ci.appveyor.com/project/pelletier/go-toml/branch/master)
[![codecov](https://codecov.io/gh/pelletier/go-toml/branch/master/graph/badge.svg)](https://codecov.io/gh/pelletier/go-toml)
[![Go Report Card](https://goreportcard.com/badge/github.com/pelletier/go-toml)](https://goreportcard.com/report/github.com/pelletier/go-toml)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fpelletier%2Fgo-toml.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fpelletier%2Fgo-toml?ref=badge_shield)
## Features
@@ -107,12 +109,7 @@ much appreciated!
### Run tests
You have to make sure two kind of tests run:
1. The Go unit tests
2. The TOML examples base
You can run both of them using `./test.sh`.
`go test ./...`
### Fuzzing

34
vendor/github.com/pelletier/go-toml/appveyor.yml generated vendored Normal file
View File

@@ -0,0 +1,34 @@
version: "{build}"
# Source Config
clone_folder: c:\gopath\src\github.com\pelletier\go-toml
# Build host
environment:
GOPATH: c:\gopath
DEPTESTBYPASS501: 1
GOVERSION: 1.12
GO111MODULE: on
init:
- git config --global core.autocrlf input
# Build
install:
# Install the specific Go version.
- rmdir c:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi
- msiexec /i go%GOVERSION%.windows-amd64.msi /q
- choco install bzr
- set Path=c:\go\bin;c:\gopath\bin;C:\Program Files (x86)\Bazaar\;C:\Program Files\Mercurial\%Path%
- go version
- go env
build: false
deploy: false
test_script:
- go test github.com/pelletier/go-toml
- go test github.com/pelletier/go-toml/cmd/tomljson
- go test github.com/pelletier/go-toml/cmd/tomll
- go test github.com/pelletier/go-toml/query

9
vendor/github.com/pelletier/go-toml/go.mod generated vendored Normal file
View File

@@ -0,0 +1,9 @@
module github.com/pelletier/go-toml
go 1.12
require (
github.com/BurntSushi/toml v0.3.1
github.com/davecgh/go-spew v1.1.1
gopkg.in/yaml.v2 v2.2.2
)

7
vendor/github.com/pelletier/go-toml/go.sum generated vendored Normal file
View File

@@ -0,0 +1,7 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -3,79 +3,107 @@
package toml
import (
"bytes"
"errors"
"fmt"
"unicode"
)
// Convert the bare key group string to an array.
// The input supports double quotation to allow "." inside the key name,
// The input supports double quotation and single quotation,
// but escape sequences are not supported. Lexers must unescape them beforehand.
func parseKey(key string) ([]string, error) {
groups := []string{}
var buffer bytes.Buffer
inQuotes := false
wasInQuotes := false
ignoreSpace := true
expectDot := false
runes := []rune(key)
var groups []string
for _, char := range key {
if ignoreSpace {
if char == ' ' {
continue
}
ignoreSpace = false
if len(key) == 0 {
return nil, errors.New("empty key")
}
idx := 0
for idx < len(runes) {
for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
// skip leading whitespace
}
switch char {
case '"':
if inQuotes {
groups = append(groups, buffer.String())
buffer.Reset()
wasInQuotes = true
}
inQuotes = !inQuotes
expectDot = false
case '.':
if inQuotes {
buffer.WriteRune(char)
} else {
if !wasInQuotes {
if buffer.Len() == 0 {
return nil, errors.New("empty table key")
if idx >= len(runes) {
break
}
r := runes[idx]
if isValidBareChar(r) {
// parse bare key
startIdx := idx
endIdx := -1
idx++
for idx < len(runes) {
r = runes[idx]
if isValidBareChar(r) {
idx++
} else if r == '.' {
endIdx = idx
break
} else if isSpace(r) {
endIdx = idx
for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
// skip trailing whitespace
}
groups = append(groups, buffer.String())
buffer.Reset()
if idx < len(runes) && runes[idx] != '.' {
return nil, fmt.Errorf("invalid key character after whitespace: %c", runes[idx])
}
break
} else {
return nil, fmt.Errorf("invalid bare key character: %c", r)
}
ignoreSpace = true
expectDot = false
wasInQuotes = false
}
case ' ':
if inQuotes {
buffer.WriteRune(char)
} else {
expectDot = true
if endIdx == -1 {
endIdx = idx
}
default:
if !inQuotes && !isValidBareChar(char) {
return nil, fmt.Errorf("invalid bare character: %c", char)
groups = append(groups, string(runes[startIdx:endIdx]))
} else if r == '\'' {
// parse single quoted key
idx++
startIdx := idx
for {
if idx >= len(runes) {
return nil, fmt.Errorf("unclosed single-quoted key")
}
r = runes[idx]
if r == '\'' {
groups = append(groups, string(runes[startIdx:idx]))
idx++
break
}
idx++
}
if !inQuotes && expectDot {
return nil, errors.New("what?")
} else if r == '"' {
// parse double quoted key
idx++
startIdx := idx
for {
if idx >= len(runes) {
return nil, fmt.Errorf("unclosed double-quoted key")
}
r = runes[idx]
if r == '"' {
groups = append(groups, string(runes[startIdx:idx]))
idx++
break
}
idx++
}
buffer.WriteRune(char)
expectDot = false
} else if r == '.' {
idx++
if idx >= len(runes) {
return nil, fmt.Errorf("unexpected end of key")
}
r = runes[idx]
if !isValidBareChar(r) && r != '\'' && r != '"' && r != ' ' {
return nil, fmt.Errorf("expecting key part after dot")
}
} else {
return nil, fmt.Errorf("invalid key character: %c", r)
}
}
if inQuotes {
return nil, errors.New("mismatched quotes")
}
if buffer.Len() > 0 {
groups = append(groups, buffer.String())
}
if len(groups) == 0 {
return nil, errors.New("empty key")
return nil, fmt.Errorf("empty key")
}
return groups, nil
}

View File

@@ -309,7 +309,7 @@ func (l *tomlLexer) lexKey() tomlLexStateFn {
if err != nil {
return l.errorf(err.Error())
}
growingString += str
growingString += "\"" + str + "\""
l.next()
continue
} else if r == '\'' {
@@ -318,13 +318,15 @@ func (l *tomlLexer) lexKey() tomlLexStateFn {
if err != nil {
return l.errorf(err.Error())
}
growingString += str
growingString += "'" + str + "'"
l.next()
continue
} else if r == '\n' {
return l.errorf("keys cannot contain new lines")
} else if isSpace(r) {
break
} else if r == '.' {
// skip
} else if !isValidBareChar(r) {
return l.errorf("keys cannot contain %c character", r)
}

View File

@@ -11,15 +11,22 @@ import (
"time"
)
const tagKeyMultiline = "multiline"
const (
tagFieldName = "toml"
tagFieldComment = "comment"
tagCommented = "commented"
tagMultiline = "multiline"
tagDefault = "default"
)
type tomlOpts struct {
name string
comment string
commented bool
multiline bool
include bool
omitempty bool
name string
comment string
commented bool
multiline bool
include bool
omitempty bool
defaultValue string
}
type encOpts struct {
@@ -31,10 +38,37 @@ var encOptsDefaults = encOpts{
quoteMapKeys: false,
}
type annotation struct {
tag string
comment string
commented string
multiline string
defaultValue string
}
var annotationDefault = annotation{
tag: tagFieldName,
comment: tagFieldComment,
commented: tagCommented,
multiline: tagMultiline,
defaultValue: tagDefault,
}
type marshalOrder int
// Orders the Encoder can write the fields to the output stream.
const (
// Sort fields alphabetically.
OrderAlphabetical marshalOrder = iota + 1
// Preserve the order the fields are encountered. For example, the order of fields in
// a struct.
OrderPreserve
)
var timeType = reflect.TypeOf(time.Time{})
var marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
// Check if the given marshall type maps to a Tree primitive
// Check if the given marshal type maps to a Tree primitive
func isPrimitive(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Ptr:
@@ -56,7 +90,7 @@ func isPrimitive(mtype reflect.Type) bool {
}
}
// Check if the given marshall type maps to a Tree slice
// Check if the given marshal type maps to a Tree slice
func isTreeSlice(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Slice:
@@ -66,7 +100,7 @@ func isTreeSlice(mtype reflect.Type) bool {
}
}
// Check if the given marshall type maps to a non-Tree slice
// Check if the given marshal type maps to a non-Tree slice
func isOtherSlice(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Ptr:
@@ -78,7 +112,7 @@ func isOtherSlice(mtype reflect.Type) bool {
}
}
// Check if the given marshall type maps to a Tree
// Check if the given marshal type maps to a Tree
func isTree(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Map:
@@ -136,6 +170,8 @@ Tree primitive types and corresponding marshal types:
string string, pointers to same
bool bool, pointers to same
time.Time time.Time{}, pointers to same
For additional flexibility, use the Encoder API.
*/
func Marshal(v interface{}) ([]byte, error) {
return NewEncoder(nil).marshal(v)
@@ -145,13 +181,21 @@ func Marshal(v interface{}) ([]byte, error) {
type Encoder struct {
w io.Writer
encOpts
annotation
line int
col int
order marshalOrder
}
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{
w: w,
encOpts: encOptsDefaults,
w: w,
encOpts: encOptsDefaults,
annotation: annotationDefault,
line: 0,
col: 1,
order: OrderAlphabetical,
}
}
@@ -197,11 +241,49 @@ func (e *Encoder) ArraysWithOneElementPerLine(v bool) *Encoder {
return e
}
// Order allows to change in which order fields will be written to the output stream.
func (e *Encoder) Order(ord marshalOrder) *Encoder {
e.order = ord
return e
}
// SetTagName allows changing default tag "toml"
func (e *Encoder) SetTagName(v string) *Encoder {
e.tag = v
return e
}
// SetTagComment allows changing default tag "comment"
func (e *Encoder) SetTagComment(v string) *Encoder {
e.comment = v
return e
}
// SetTagCommented allows changing default tag "commented"
func (e *Encoder) SetTagCommented(v string) *Encoder {
e.commented = v
return e
}
// SetTagMultiline allows changing default tag "multiline"
func (e *Encoder) SetTagMultiline(v string) *Encoder {
e.multiline = v
return e
}
func (e *Encoder) marshal(v interface{}) ([]byte, error) {
mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Struct {
return []byte{}, errors.New("Only a struct can be marshaled to TOML")
switch mtype.Kind() {
case reflect.Struct, reflect.Map:
case reflect.Ptr:
if mtype.Elem().Kind() != reflect.Struct {
return []byte{}, errors.New("Only pointer to struct can be marshaled to TOML")
}
default:
return []byte{}, errors.New("Only a struct or map can be marshaled to TOML")
}
sval := reflect.ValueOf(v)
if isCustomMarshaler(mtype) {
return callCustomMarshaler(sval)
@@ -212,22 +294,27 @@ func (e *Encoder) marshal(v interface{}) ([]byte, error) {
}
var buf bytes.Buffer
_, err = t.writeTo(&buf, "", "", 0, e.arraysOneElementPerLine)
_, err = t.writeToOrdered(&buf, "", "", 0, e.arraysOneElementPerLine, e.order)
return buf.Bytes(), err
}
// Create next tree with a position based on Encoder.line
func (e *Encoder) nextTree() *Tree {
return newTreeWithPosition(Position{Line: e.line, Col: 1})
}
// Convert given marshal struct or map value to toml tree
func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
if mtype.Kind() == reflect.Ptr {
return e.valueToTree(mtype.Elem(), mval.Elem())
}
tval := newTree()
tval := e.nextTree()
switch mtype.Kind() {
case reflect.Struct:
for i := 0; i < mtype.NumField(); i++ {
mtypef, mvalf := mtype.Field(i), mval.Field(i)
opts := tomlOptions(mtypef)
opts := tomlOptions(mtypef, e.annotation)
if opts.include && (!opts.omitempty || !isZero(mvalf)) {
val, err := e.valueToToml(mtypef.Type, mvalf)
if err != nil {
@@ -290,6 +377,7 @@ func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (int
// Convert given marshal value to toml value
func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
e.line++
if mtype.Kind() == reflect.Ptr {
return e.valueToToml(mtype.Elem(), mval.Elem())
}
@@ -307,6 +395,9 @@ func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface
case reflect.Bool:
return mval.Bool(), nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) {
return fmt.Sprint(mval), nil
}
return mval.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return mval.Uint(), nil
@@ -326,7 +417,7 @@ func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface
// Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for
// sub-structs, and only definite types can be unmarshaled.
func (t *Tree) Unmarshal(v interface{}) error {
d := Decoder{tval: t}
d := Decoder{tval: t, tagName: tagFieldName}
return d.unmarshal(v)
}
@@ -347,6 +438,14 @@ func (t *Tree) Marshal() ([]byte, error) {
// The following struct annotations are supported:
//
// toml:"Field" Overrides the field's name to map to.
// default:"foo" Provides a default value.
//
// For default values, only fields of the following types are supported:
// * string
// * bool
// * int
// * int64
// * float64
//
// See Marshal() documentation for types mapping table.
func Unmarshal(data []byte, v interface{}) error {
@@ -362,6 +461,7 @@ type Decoder struct {
r io.Reader
tval *Tree
encOpts
tagName string
}
// NewDecoder returns a new decoder that reads from r.
@@ -369,6 +469,7 @@ func NewDecoder(r io.Reader) *Decoder {
return &Decoder{
r: r,
encOpts: encOptsDefaults,
tagName: tagFieldName,
}
}
@@ -385,6 +486,12 @@ func (d *Decoder) Decode(v interface{}) error {
return d.unmarshal(v)
}
// SetTagName allows changing default tag "toml"
func (d *Decoder) SetTagName(v string) *Decoder {
d.tagName = v
return d
}
func (d *Decoder) unmarshal(v interface{}) error {
mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
@@ -410,10 +517,18 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value,
mval = reflect.New(mtype).Elem()
for i := 0; i < mtype.NumField(); i++ {
mtypef := mtype.Field(i)
opts := tomlOptions(mtypef)
an := annotation{tag: d.tagName}
opts := tomlOptions(mtypef, an)
if opts.include {
baseKey := opts.name
keysToTry := []string{baseKey, strings.ToLower(baseKey), strings.ToTitle(baseKey)}
keysToTry := []string{
baseKey,
strings.ToLower(baseKey),
strings.ToTitle(baseKey),
strings.ToLower(string(baseKey[0])) + baseKey[1:],
}
found := false
for _, key := range keysToTry {
exists := tval.Has(key)
if !exists {
@@ -425,8 +540,42 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value,
return mval, formatError(err, tval.GetPosition(key))
}
mval.Field(i).Set(mvalf)
found = true
break
}
if !found && opts.defaultValue != "" {
mvalf := mval.Field(i)
var val interface{} = nil
var err error = nil
switch mvalf.Kind() {
case reflect.Bool:
val, err = strconv.ParseBool(opts.defaultValue)
if err != nil {
return mval.Field(i), err
}
case reflect.Int:
val, err = strconv.Atoi(opts.defaultValue)
if err != nil {
return mval.Field(i), err
}
case reflect.String:
val = opts.defaultValue
case reflect.Int64:
val, err = strconv.ParseInt(opts.defaultValue, 10, 64)
if err != nil {
return mval.Field(i), err
}
case reflect.Float64:
val, err = strconv.ParseFloat(opts.defaultValue, 64)
if err != nil {
return mval.Field(i), err
}
default:
return mval.Field(i), fmt.Errorf("unsuported field type for default option")
}
mval.Field(i).Set(reflect.ValueOf(val))
}
}
}
case reflect.Map:
@@ -476,20 +625,20 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.V
return d.unwrapPointer(mtype, tval)
}
switch tval.(type) {
switch t := tval.(type) {
case *Tree:
if isTree(mtype) {
return d.valueFromTree(mtype, tval.(*Tree))
return d.valueFromTree(mtype, t)
}
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval)
case []*Tree:
if isTreeSlice(mtype) {
return d.valueFromTreeSlice(mtype, tval.([]*Tree))
return d.valueFromTreeSlice(mtype, t)
}
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval)
case []interface{}:
if isOtherSlice(mtype) {
return d.valueFromOtherSlice(mtype, tval.([]interface{}))
return d.valueFromOtherSlice(mtype, t)
}
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
default:
@@ -512,10 +661,17 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.V
return val.Convert(mtype), nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
val := reflect.ValueOf(tval)
if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) && val.Kind() == reflect.String {
d, err := time.ParseDuration(val.String())
if err != nil {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v. %s", tval, tval, mtype.String(), err)
}
return reflect.ValueOf(d), nil
}
if !val.Type().ConvertibleTo(mtype) {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
}
if reflect.Indirect(reflect.New(mtype)).OverflowInt(val.Int()) {
if reflect.Indirect(reflect.New(mtype)).OverflowInt(val.Convert(mtype).Int()) {
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
}
@@ -525,10 +681,11 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.V
if !val.Type().ConvertibleTo(mtype) {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
}
if val.Int() < 0 {
if val.Convert(reflect.TypeOf(int(1))).Int() < 0 {
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String())
}
if reflect.Indirect(reflect.New(mtype)).OverflowUint(uint64(val.Int())) {
if reflect.Indirect(reflect.New(mtype)).OverflowUint(uint64(val.Convert(mtype).Uint())) {
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
}
@@ -538,7 +695,7 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.V
if !val.Type().ConvertibleTo(mtype) {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
}
if reflect.Indirect(reflect.New(mtype)).OverflowFloat(val.Float()) {
if reflect.Indirect(reflect.New(mtype)).OverflowFloat(val.Convert(mtype).Float()) {
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
}
@@ -559,16 +716,25 @@ func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.V
return mval, nil
}
func tomlOptions(vf reflect.StructField) tomlOpts {
tag := vf.Tag.Get("toml")
func tomlOptions(vf reflect.StructField, an annotation) tomlOpts {
tag := vf.Tag.Get(an.tag)
parse := strings.Split(tag, ",")
var comment string
if c := vf.Tag.Get("comment"); c != "" {
if c := vf.Tag.Get(an.comment); c != "" {
comment = c
}
commented, _ := strconv.ParseBool(vf.Tag.Get("commented"))
multiline, _ := strconv.ParseBool(vf.Tag.Get(tagKeyMultiline))
result := tomlOpts{name: vf.Name, comment: comment, commented: commented, multiline: multiline, include: true, omitempty: false}
commented, _ := strconv.ParseBool(vf.Tag.Get(an.commented))
multiline, _ := strconv.ParseBool(vf.Tag.Get(an.multiline))
defaultValue := vf.Tag.Get(tagDefault)
result := tomlOpts{
name: vf.Name,
comment: comment,
commented: commented,
multiline: multiline,
include: true,
omitempty: false,
defaultValue: defaultValue,
}
if parse[0] != "" {
if parse[0] == "-" && len(parse) == 1 {
result.include = false

View File

@@ -0,0 +1,38 @@
title = "TOML Marshal Testing"
[basic_lists]
floats = [12.3,45.6,78.9]
bools = [true,false,true]
dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z]
ints = [8001,8001,8002]
uints = [5002,5003]
strings = ["One","Two","Three"]
[[subdocptrs]]
name = "Second"
[basic_map]
one = "one"
two = "two"
[subdoc]
[subdoc.second]
name = "Second"
[subdoc.first]
name = "First"
[basic]
uint = 5001
bool = true
float = 123.4
int = 5000
string = "Bite me"
date = 1979-05-27T07:32:00Z
[[subdoclist]]
name = "List.First"
[[subdoclist]]
name = "List.Second"

View File

@@ -77,8 +77,10 @@ func (p *tomlParser) parseStart() tomlParserStateFn {
return p.parseAssign
case tokenEOF:
return nil
case tokenError:
p.raiseError(tok, "parsing error: %s", tok.String())
default:
p.raiseError(tok, "unexpected token")
p.raiseError(tok, "unexpected token %s", tok.typ)
}
return nil
}
@@ -165,6 +167,11 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
key := p.getToken()
p.assume(tokenEqual)
parsedKey, err := parseKey(key.val)
if err != nil {
p.raiseError(key, "invalid key: %s", err.Error())
}
value := p.parseRvalue()
var tableKey []string
if len(p.currentTable) > 0 {
@@ -173,6 +180,9 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
tableKey = []string{}
}
prefixKey := parsedKey[0 : len(parsedKey)-1]
tableKey = append(tableKey, prefixKey...)
// find the table to assign, looking out for arrays of tables
var targetNode *Tree
switch node := p.tree.GetPath(tableKey).(type) {
@@ -180,17 +190,19 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
targetNode = node[len(node)-1]
case *Tree:
targetNode = node
case nil:
// create intermediate
if err := p.tree.createSubTree(tableKey, key.Position); err != nil {
p.raiseError(key, "could not create intermediate group: %s", err)
}
targetNode = p.tree.GetPath(tableKey).(*Tree)
default:
p.raiseError(key, "Unknown table type for path: %s",
strings.Join(tableKey, "."))
}
// assign value to the found table
keyVals := []string{key.val}
if len(keyVals) != 1 {
p.raiseError(key, "Invalid key")
}
keyVal := keyVals[0]
keyVal := parsedKey[len(parsedKey)-1]
localKey := []string{keyVal}
finalKey := append(tableKey, keyVal)
if targetNode.GetPath(localKey) != nil {
@@ -338,7 +350,7 @@ Loop:
case tokenRightCurlyBrace:
p.getToken()
break Loop
case tokenKey:
case tokenKey, tokenInteger, tokenString:
if !tokenIsComma(previous) && previous != nil {
p.raiseError(follow, "comma expected between fields in inline table")
}

View File

@@ -1,88 +0,0 @@
#!/bin/bash
# fail out of the script if anything here fails
set -e
set -o pipefail
# set the path to the present working directory
export GOPATH=`pwd`
function git_clone() {
path=$1
branch=$2
version=$3
if [ ! -d "src/$path" ]; then
mkdir -p src/$path
git clone https://$path.git src/$path
fi
pushd src/$path
git checkout "$branch"
git reset --hard "$version"
popd
}
# Remove potential previous runs
rm -rf src test_program_bin toml-test
go get github.com/pelletier/go-buffruneio
go get github.com/davecgh/go-spew/spew
go get gopkg.in/yaml.v2
go get github.com/BurntSushi/toml
# get code for BurntSushi TOML validation
# pinning all to 'HEAD' for version 0.3.x work (TODO: pin to commit hash when tests stabilize)
git_clone github.com/BurntSushi/toml master HEAD
git_clone github.com/BurntSushi/toml-test master HEAD #was: 0.2.0 HEAD
# build the BurntSushi test application
go build -o toml-test github.com/BurntSushi/toml-test
# vendorize the current lib for testing
# NOTE: this basically mocks an install without having to go back out to github for code
mkdir -p src/github.com/pelletier/go-toml/cmd
mkdir -p src/github.com/pelletier/go-toml/query
cp *.go *.toml src/github.com/pelletier/go-toml
cp -R cmd/* src/github.com/pelletier/go-toml/cmd
cp -R query/* src/github.com/pelletier/go-toml/query
go build -o test_program_bin src/github.com/pelletier/go-toml/cmd/test_program.go
# Run basic unit tests
go test github.com/pelletier/go-toml -covermode=count -coverprofile=coverage.out
go test github.com/pelletier/go-toml/cmd/tomljson
go test github.com/pelletier/go-toml/query
# run the entire BurntSushi test suite
if [[ $# -eq 0 ]] ; then
echo "Running all BurntSushi tests"
./toml-test ./test_program_bin | tee test_out
else
# run a specific test
test=$1
test_path='src/github.com/BurntSushi/toml-test/tests'
valid_test="$test_path/valid/$test"
invalid_test="$test_path/invalid/$test"
if [ -e "$valid_test.toml" ]; then
echo "Valid Test TOML for $test:"
echo "===="
cat "$valid_test.toml"
echo "Valid Test JSON for $test:"
echo "===="
cat "$valid_test.json"
echo "Go-TOML Output for $test:"
echo "===="
cat "$valid_test.toml" | ./test_program_bin
fi
if [ -e "$invalid_test.toml" ]; then
echo "Invalid Test TOML for $test:"
echo "===="
cat "$invalid_test.toml"
echo "Go-TOML Output for $test:"
echo "===="
echo "go-toml Output:"
cat "$invalid_test.toml" | ./test_program_bin
fi
fi

View File

@@ -27,9 +27,13 @@ type Tree struct {
}
func newTree() *Tree {
return newTreeWithPosition(Position{})
}
func newTreeWithPosition(pos Position) *Tree {
return &Tree{
values: make(map[string]interface{}),
position: Position{},
position: pos,
}
}
@@ -194,10 +198,10 @@ func (t *Tree) SetWithOptions(key string, opts SetOptions, value interface{}) {
// formatting instructions to the key, that will be reused by Marshal().
func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interface{}) {
subtree := t
for _, intermediateKey := range keys[:len(keys)-1] {
for i, intermediateKey := range keys[:len(keys)-1] {
nextTree, exists := subtree.values[intermediateKey]
if !exists {
nextTree = newTree()
nextTree = newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col})
subtree.values[intermediateKey] = nextTree // add new element here
}
switch node := nextTree.(type) {
@@ -207,7 +211,7 @@ func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interfac
// go to most recent element
if len(node) == 0 {
// create element if it does not exist
subtree.values[intermediateKey] = append(node, newTree())
subtree.values[intermediateKey] = append(node, newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col}))
}
subtree = node[len(node)-1]
}
@@ -215,19 +219,21 @@ func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interfac
var toInsert interface{}
switch value.(type) {
switch v := value.(type) {
case *Tree:
tt := value.(*Tree)
tt.comment = opts.Comment
v.comment = opts.Comment
toInsert = value
case []*Tree:
toInsert = value
case *tomlValue:
tt := value.(*tomlValue)
tt.comment = opts.Comment
toInsert = tt
v.comment = opts.Comment
toInsert = v
default:
toInsert = &tomlValue{value: value, comment: opts.Comment, commented: opts.Commented, multiline: opts.Multiline}
toInsert = &tomlValue{value: value,
comment: opts.Comment,
commented: opts.Commented,
multiline: opts.Multiline,
position: Position{Line: subtree.position.Line + len(subtree.values) + 1, Col: subtree.position.Col}}
}
subtree.values[keys[len(keys)-1]] = toInsert
@@ -256,44 +262,35 @@ func (t *Tree) SetPath(keys []string, value interface{}) {
// SetPathWithComment is the same as SetPath, but allows you to provide comment
// information to the key, that will be reused by Marshal().
func (t *Tree) SetPathWithComment(keys []string, comment string, commented bool, value interface{}) {
subtree := t
for _, intermediateKey := range keys[:len(keys)-1] {
nextTree, exists := subtree.values[intermediateKey]
if !exists {
nextTree = newTree()
subtree.values[intermediateKey] = nextTree // add new element here
}
switch node := nextTree.(type) {
case *Tree:
subtree = node
case []*Tree:
// go to most recent element
if len(node) == 0 {
// create element if it does not exist
subtree.values[intermediateKey] = append(node, newTree())
}
subtree = node[len(node)-1]
}
t.SetPathWithOptions(keys, SetOptions{Comment: comment, Commented: commented}, value)
}
// Delete removes a key from the tree.
// Key is a dot-separated path (e.g. a.b.c).
func (t *Tree) Delete(key string) error {
keys, err := parseKey(key)
if err != nil {
return err
}
return t.DeletePath(keys)
}
var toInsert interface{}
switch value.(type) {
// Delete removes a key from the tree.
// Keys is an array of path elements (e.g. {"a","b","c"}).
func (t *Tree) DeletePath(keys []string) error {
keyLen := len(keys)
if keyLen == 1 {
delete(t.values, keys[0])
return nil
}
tree := t.GetPath(keys[:keyLen-1])
item := keys[keyLen-1]
switch node := tree.(type) {
case *Tree:
tt := value.(*Tree)
tt.comment = comment
toInsert = value
case []*Tree:
toInsert = value
case *tomlValue:
tt := value.(*tomlValue)
tt.comment = comment
toInsert = tt
default:
toInsert = &tomlValue{value: value, comment: comment, commented: commented}
delete(node.values, item)
return nil
}
subtree.values[keys[len(keys)-1]] = toInsert
return errors.New("no such key to delete")
}
// createSubTree takes a tree and a key and create the necessary intermediate
@@ -305,10 +302,10 @@ func (t *Tree) SetPathWithComment(keys []string, comment string, commented bool,
// Returns nil on success, error object on failure
func (t *Tree) createSubTree(keys []string, pos Position) error {
subtree := t
for _, intermediateKey := range keys {
for i, intermediateKey := range keys {
nextTree, exists := subtree.values[intermediateKey]
if !exists {
tree := newTree()
tree := newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col})
tree.position = pos
subtree.values[intermediateKey] = tree
nextTree = tree
@@ -337,10 +334,39 @@ func LoadBytes(b []byte) (tree *Tree, err error) {
err = errors.New(r.(string))
}
}()
if len(b) >= 4 && (hasUTF32BigEndianBOM4(b) || hasUTF32LittleEndianBOM4(b)) {
b = b[4:]
} else if len(b) >= 3 && hasUTF8BOM3(b) {
b = b[3:]
} else if len(b) >= 2 && (hasUTF16BigEndianBOM2(b) || hasUTF16LittleEndianBOM2(b)) {
b = b[2:]
}
tree = parseToml(lexToml(b))
return
}
func hasUTF16BigEndianBOM2(b []byte) bool {
return b[0] == 0xFE && b[1] == 0xFF
}
func hasUTF16LittleEndianBOM2(b []byte) bool {
return b[0] == 0xFF && b[1] == 0xFE
}
func hasUTF8BOM3(b []byte) bool {
return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
}
func hasUTF32BigEndianBOM4(b []byte) bool {
return b[0] == 0x00 && b[1] == 0x00 && b[2] == 0xFE && b[3] == 0xFF
}
func hasUTF32LittleEndianBOM4(b []byte) bool {
return b[0] == 0xFF && b[1] == 0xFE && b[2] == 0x00 && b[3] == 0x00
}
// LoadReader creates a Tree from any io.Reader.
func LoadReader(reader io.Reader) (tree *Tree, err error) {
inputBytes, err := ioutil.ReadAll(reader)

View File

@@ -12,6 +12,18 @@ import (
"time"
)
type valueComplexity int
const (
valueSimple valueComplexity = iota + 1
valueComplex
)
type sortNode struct {
key string
complexity valueComplexity
}
// Encodes a string to a TOML-compliant multi-line string value
// This function is a clone of the existing encodeTomlString function, except that whitespace characters
// are preserved. Quotation marks and backslashes are also not escaped.
@@ -153,111 +165,200 @@ func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElemen
return "", fmt.Errorf("unsupported value type %T: %v", v, v)
}
func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool) (int64, error) {
simpleValuesKeys := make([]string, 0)
complexValuesKeys := make([]string, 0)
func getTreeArrayLine(trees []*Tree) (line int) {
// get lowest line number that is not 0
for _, tv := range trees {
if tv.position.Line < line || line == 0 {
line = tv.position.Line
}
}
return
}
func sortByLines(t *Tree) (vals []sortNode) {
var (
line int
lines []int
tv *Tree
tom *tomlValue
node sortNode
)
vals = make([]sortNode, 0)
m := make(map[int]sortNode)
for k := range t.values {
v := t.values[k]
switch v.(type) {
case *Tree:
tv = v.(*Tree)
line = tv.position.Line
node = sortNode{key: k, complexity: valueComplex}
case []*Tree:
line = getTreeArrayLine(v.([]*Tree))
node = sortNode{key: k, complexity: valueComplex}
default:
tom = v.(*tomlValue)
line = tom.position.Line
node = sortNode{key: k, complexity: valueSimple}
}
lines = append(lines, line)
vals = append(vals, node)
m[line] = node
}
sort.Ints(lines)
for i, line := range lines {
vals[i] = m[line]
}
return vals
}
func sortAlphabetical(t *Tree) (vals []sortNode) {
var (
node sortNode
simpVals []string
compVals []string
)
vals = make([]sortNode, 0)
m := make(map[string]sortNode)
for k := range t.values {
v := t.values[k]
switch v.(type) {
case *Tree, []*Tree:
complexValuesKeys = append(complexValuesKeys, k)
node = sortNode{key: k, complexity: valueComplex}
compVals = append(compVals, node.key)
default:
simpleValuesKeys = append(simpleValuesKeys, k)
node = sortNode{key: k, complexity: valueSimple}
simpVals = append(simpVals, node.key)
}
vals = append(vals, node)
m[node.key] = node
}
sort.Strings(simpleValuesKeys)
sort.Strings(complexValuesKeys)
for _, k := range simpleValuesKeys {
v, ok := t.values[k].(*tomlValue)
if !ok {
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
}
repr, err := tomlValueStringRepresentation(v, indent, arraysOneElementPerLine)
if err != nil {
return bytesCount, err
}
if v.comment != "" {
comment := strings.Replace(v.comment, "\n", "\n"+indent+"#", -1)
start := "# "
if strings.HasPrefix(comment, "#") {
start = ""
}
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment, "\n")
bytesCount += int64(writtenBytesCountComment)
if errc != nil {
return bytesCount, errc
}
}
var commented string
if v.commented {
commented = "# "
}
writtenBytesCount, err := writeStrings(w, indent, commented, k, " = ", repr, "\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
}
// Simples first to match previous implementation
sort.Strings(simpVals)
i := 0
for _, key := range simpVals {
vals[i] = m[key]
i++
}
for _, k := range complexValuesKeys {
v := t.values[k]
sort.Strings(compVals)
for _, key := range compVals {
vals[i] = m[key]
i++
}
combinedKey := k
if keyspace != "" {
combinedKey = keyspace + "." + combinedKey
}
var commented string
if t.commented {
commented = "# "
}
return vals
}
switch node := v.(type) {
// node has to be of those two types given how keys are sorted above
case *Tree:
tv, ok := t.values[k].(*Tree)
func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool) (int64, error) {
return t.writeToOrdered(w, indent, keyspace, bytesCount, arraysOneElementPerLine, OrderAlphabetical)
}
func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool, ord marshalOrder) (int64, error) {
orderedVals := make([]sortNode, 0)
switch ord {
case OrderPreserve:
orderedVals = sortByLines(t)
default:
orderedVals = sortAlphabetical(t)
}
for _, node := range orderedVals {
switch node.complexity {
case valueComplex:
k := node.key
v := t.values[k]
combinedKey := k
if keyspace != "" {
combinedKey = keyspace + "." + combinedKey
}
var commented string
if t.commented {
commented = "# "
}
switch node := v.(type) {
// node has to be of those two types given how keys are sorted above
case *Tree:
tv, ok := t.values[k].(*Tree)
if !ok {
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
}
if tv.comment != "" {
comment := strings.Replace(tv.comment, "\n", "\n"+indent+"#", -1)
start := "# "
if strings.HasPrefix(comment, "#") {
start = ""
}
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment)
bytesCount += int64(writtenBytesCountComment)
if errc != nil {
return bytesCount, errc
}
}
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
}
bytesCount, err = node.writeToOrdered(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine, ord)
if err != nil {
return bytesCount, err
}
case []*Tree:
for _, subTree := range node {
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
}
bytesCount, err = subTree.writeToOrdered(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine, ord)
if err != nil {
return bytesCount, err
}
}
}
default: // Simple
k := node.key
v, ok := t.values[k].(*tomlValue)
if !ok {
return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
}
if tv.comment != "" {
comment := strings.Replace(tv.comment, "\n", "\n"+indent+"#", -1)
repr, err := tomlValueStringRepresentation(v, indent, arraysOneElementPerLine)
if err != nil {
return bytesCount, err
}
if v.comment != "" {
comment := strings.Replace(v.comment, "\n", "\n"+indent+"#", -1)
start := "# "
if strings.HasPrefix(comment, "#") {
start = ""
}
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment)
writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment, "\n")
bytesCount += int64(writtenBytesCountComment)
if errc != nil {
return bytesCount, errc
}
}
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n")
var commented string
if v.commented {
commented = "# "
}
writtenBytesCount, err := writeStrings(w, indent, commented, k, " = ", repr, "\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
}
bytesCount, err = node.writeTo(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine)
if err != nil {
return bytesCount, err
}
case []*Tree:
for _, subTree := range node {
writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
}
bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine)
if err != nil {
return bytesCount, err
}
}
}
}

14
vendor/modules.txt vendored
View File

@@ -122,6 +122,11 @@ github.com/mailru/easyjson
github.com/mailru/easyjson/jlexer
github.com/mailru/easyjson/jwriter
github.com/mailru/easyjson/buffer
# github.com/mattermost/go-i18n v1.1.2
github.com/mattermost/go-i18n/i18n
github.com/mattermost/go-i18n/i18n/bundle
github.com/mattermost/go-i18n/i18n/language
github.com/mattermost/go-i18n/i18n/translation
# github.com/mattermost/gorp v2.0.1-0.20190301154413-3b31e9a39d05+incompatible
github.com/mattermost/gorp
# github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0
@@ -157,18 +162,13 @@ github.com/muesli/smartcrop/nfnt
github.com/muesli/smartcrop/options
# github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/nfnt/resize
# github.com/nicksnyder/go-i18n v1.10.0
github.com/nicksnyder/go-i18n/i18n
github.com/nicksnyder/go-i18n/i18n/bundle
github.com/nicksnyder/go-i18n/i18n/language
github.com/nicksnyder/go-i18n/i18n/translation
# github.com/oklog/run v1.0.0
github.com/oklog/run
# github.com/olekukonko/tablewriter v0.0.1
github.com/olekukonko/tablewriter
# github.com/pborman/uuid v1.2.0
github.com/pborman/uuid
# github.com/pelletier/go-toml v1.2.0
# github.com/pelletier/go-toml v1.3.0
github.com/pelletier/go-toml
# github.com/pkg/errors v0.8.1
github.com/pkg/errors
@@ -220,8 +220,8 @@ github.com/ssor/bom
github.com/stretchr/objx
# github.com/stretchr/testify v1.3.0
github.com/stretchr/testify/require
github.com/stretchr/testify/mock
github.com/stretchr/testify/assert
github.com/stretchr/testify/mock
github.com/stretchr/testify/suite
# github.com/throttled/throttled v2.2.4+incompatible
github.com/throttled/throttled