mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-25 08:31:03 +00:00
Merge remote-tracking branch 'origin/master' into multi-compose-projects
This commit is contained in:
commit
30f3619eb9
200 changed files with 15955 additions and 1667 deletions
4
.github/workflows/cd.yml
vendored
4
.github/workflows/cd.yml
vendored
|
|
@ -19,6 +19,10 @@ jobs:
|
|||
go-version: 1.18.x
|
||||
- name: Run goreleaser
|
||||
uses: goreleaser/goreleaser-action@v1
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: v1.17.2
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GORELEASER_TOKEN}}
|
||||
homebrew:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -24,6 +24,8 @@ gui:
|
|||
- bold
|
||||
inactiveBorderColor:
|
||||
- white
|
||||
selectedLineBgColor:
|
||||
- blue
|
||||
optionsTextColor:
|
||||
- blue
|
||||
returnImmediately: false
|
||||
|
|
@ -31,11 +33,17 @@ gui:
|
|||
# Side panel width as a ratio of the screen's width
|
||||
sidePanelWidth: 0.333
|
||||
# Determines whether we show the bottom line (the one containing keybinding
|
||||
# info and the status of the app).
|
||||
# info and the status of the app).
|
||||
showBottomLine: true
|
||||
# When true, increases vertical space used by focused side panel,
|
||||
# creating an accordion effect
|
||||
expandFocusedSidePanel: false
|
||||
# Determines which screen mode will be used on startup
|
||||
screenMode: "normal" # one of 'normal' | 'half' | 'fullscreen'
|
||||
# Determines the style of the container status and container health display in the
|
||||
# containers panel. "long": full words (default), "short": one or two characters,
|
||||
# "icon": unicode emoji.
|
||||
containerStatusHealthStyle: "long"
|
||||
logs:
|
||||
timestamps: false
|
||||
since: '60m' # set to '' to show all logs
|
||||
|
|
@ -104,6 +112,11 @@ customCommands:
|
|||
serviceNames: []
|
||||
```
|
||||
|
||||
You may use the following go templates (such as `{{ .Container.ID }}` above) in your commands:
|
||||
- `{{ .DockerCompose }}`: the docker compose command (default: `docker-compose`)
|
||||
- [`{{ .Container }}`](https://pkg.go.dev/github.com/jesseduffield/lazydocker@v0.20.0/pkg/commands#Container) and its fields. For example: `{{ .Container.Container.ImageID }}`
|
||||
- [`{{ .Service }}`](https://pkg.go.dev/github.com/jesseduffield/lazydocker@v0.20.0/pkg/commands#Service) and its fields. For example: `{{ .Service.Name }}`
|
||||
|
||||
## Replacements
|
||||
|
||||
You can add replacements like so:
|
||||
|
|
|
|||
107
docs/keybindings/Keybindings_pt.md
Normal file
107
docs/keybindings/Keybindings_pt.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
|
||||
|
||||
# Lazydocker menu
|
||||
|
||||
## Projeto
|
||||
|
||||
<pre>
|
||||
<kbd>e</kbd>: editar configuração do lazydocker
|
||||
<kbd>o</kbd>: abrir configuração do lazydocker
|
||||
<kbd>m</kbd>: ver logs
|
||||
<kbd>enter</kbd>: focar no painel principal
|
||||
<kbd>[</kbd>: aba anterior
|
||||
<kbd>]</kbd>: próxima aba
|
||||
</pre>
|
||||
|
||||
## Contêineres
|
||||
|
||||
<pre>
|
||||
<kbd>d</kbd>: remover
|
||||
<kbd>e</kbd>: ocultar/mostrar contêineres parados
|
||||
<kbd>p</kbd>: pausar
|
||||
<kbd>s</kbd>: parar
|
||||
<kbd>r</kbd>: reiniciar
|
||||
<kbd>a</kbd>: anexar
|
||||
<kbd>m</kbd>: ver logs
|
||||
<kbd>E</kbd>: executar shell
|
||||
<kbd>c</kbd>: executar comando personalizado predefinido
|
||||
<kbd>b</kbd>: ver comandos em massa
|
||||
<kbd>w</kbd>: abrir no navegador (primeira porta é http)
|
||||
<kbd>enter</kbd>: focar no painel principal
|
||||
<kbd>[</kbd>: aba anterior
|
||||
<kbd>]</kbd>: próxima aba
|
||||
<kbd>/</kbd>: filtrar lista
|
||||
</pre>
|
||||
|
||||
## Serviços
|
||||
|
||||
<pre>
|
||||
<kbd>u</kbd>: subir serviço
|
||||
<kbd>d</kbd>: remover contêineres
|
||||
<kbd>s</kbd>: parar
|
||||
<kbd>p</kbd>: pausar
|
||||
<kbd>r</kbd>: reiniciar
|
||||
<kbd>S</kbd>: iniciar
|
||||
<kbd>a</kbd>: anexar
|
||||
<kbd>m</kbd>: ver logs
|
||||
<kbd>U</kbd>: subir projeto
|
||||
<kbd>D</kbd>: derrubar projeto
|
||||
<kbd>R</kbd>: ver opções de reinício
|
||||
<kbd>c</kbd>: executar comando personalizado predefinido
|
||||
<kbd>b</kbd>: ver comandos em massa
|
||||
<kbd>E</kbd>: executar shell
|
||||
<kbd>w</kbd>: abrir no navegador (primeira porta é http)
|
||||
<kbd>enter</kbd>: focar no painel principal
|
||||
<kbd>[</kbd>: aba anterior
|
||||
<kbd>]</kbd>: próxima aba
|
||||
<kbd>/</kbd>: filtrar lista
|
||||
</pre>
|
||||
|
||||
## Imagens
|
||||
|
||||
<pre>
|
||||
<kbd>c</kbd>: executar comando personalizado predefinido
|
||||
<kbd>d</kbd>: remover imagem
|
||||
<kbd>b</kbd>: ver comandos em massa
|
||||
<kbd>enter</kbd>: focar no painel principal
|
||||
<kbd>[</kbd>: aba anterior
|
||||
<kbd>]</kbd>: próxima aba
|
||||
<kbd>/</kbd>: filtrar lista
|
||||
</pre>
|
||||
|
||||
## Volumes
|
||||
|
||||
<pre>
|
||||
<kbd>c</kbd>: executar comando personalizado predefinido
|
||||
<kbd>d</kbd>: remover volume
|
||||
<kbd>b</kbd>: ver comandos em massa
|
||||
<kbd>enter</kbd>: focar no painel principal
|
||||
<kbd>[</kbd>: aba anterior
|
||||
<kbd>]</kbd>: próxima aba
|
||||
<kbd>/</kbd>: filtrar lista
|
||||
</pre>
|
||||
|
||||
## Redes
|
||||
|
||||
<pre>
|
||||
<kbd>c</kbd>: executar comando personalizado predefinido
|
||||
<kbd>d</kbd>: remover rede
|
||||
<kbd>b</kbd>: ver comandos em massa
|
||||
<kbd>enter</kbd>: focar no painel principal
|
||||
<kbd>[</kbd>: aba anterior
|
||||
<kbd>]</kbd>: próxima aba
|
||||
<kbd>/</kbd>: filtrar lista
|
||||
</pre>
|
||||
|
||||
## Principal
|
||||
|
||||
<pre>
|
||||
<kbd>esc</kbd>: retornar
|
||||
</pre>
|
||||
|
||||
## Global
|
||||
|
||||
<pre>
|
||||
<kbd>+</kbd>: modo de tela seguinte (normal/meia/tela cheia)
|
||||
<kbd>_</kbd>: modo de tela anterior
|
||||
</pre>
|
||||
107
docs/keybindings/Keybindings_zh.md
Normal file
107
docs/keybindings/Keybindings_zh.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
|
||||
|
||||
# Lazydocker 菜单
|
||||
|
||||
## 项目
|
||||
|
||||
<pre>
|
||||
<kbd>e</kbd>: 编辑lazydocker配置
|
||||
<kbd>o</kbd>: 打开lazydocker配置
|
||||
<kbd>m</kbd>: 查看日志
|
||||
<kbd>enter</kbd>: 聚焦主面板
|
||||
<kbd>[</kbd>: 上一个选项卡
|
||||
<kbd>]</kbd>: 下一个选项卡
|
||||
</pre>
|
||||
|
||||
## 容器
|
||||
|
||||
<pre>
|
||||
<kbd>d</kbd>: 移除
|
||||
<kbd>e</kbd>: 隐藏/显示已停止的容器
|
||||
<kbd>p</kbd>: 暂停
|
||||
<kbd>s</kbd>: 停止
|
||||
<kbd>r</kbd>: 重新启动
|
||||
<kbd>a</kbd>: attach
|
||||
<kbd>m</kbd>: 查看日志
|
||||
<kbd>E</kbd>: 执行shell
|
||||
<kbd>c</kbd>: 运行预定义的自定义命令
|
||||
<kbd>b</kbd>: 查看批量命令
|
||||
<kbd>w</kbd>: 在浏览器中打开(第一个端口为http)
|
||||
<kbd>enter</kbd>: 聚焦主面板
|
||||
<kbd>[</kbd>: 上一个选项卡
|
||||
<kbd>]</kbd>: 下一个选项卡
|
||||
<kbd>/</kbd>: 过滤列表
|
||||
</pre>
|
||||
|
||||
## 服务
|
||||
|
||||
<pre>
|
||||
<kbd>u</kbd>: 启动服务
|
||||
<kbd>d</kbd>: 移除容器
|
||||
<kbd>s</kbd>: 停止
|
||||
<kbd>p</kbd>: 暂停
|
||||
<kbd>r</kbd>: 重新启动
|
||||
<kbd>S</kbd>: 启动项目
|
||||
<kbd>a</kbd>: attach
|
||||
<kbd>m</kbd>: 查看日志
|
||||
<kbd>U</kbd>: 创建并启动容器
|
||||
<kbd>D</kbd>: 停止并移除容器
|
||||
<kbd>R</kbd>: 查看重启选项
|
||||
<kbd>c</kbd>: 运行预定义的自定义命令
|
||||
<kbd>b</kbd>: 查看批量命令
|
||||
<kbd>E</kbd>: 执行shell
|
||||
<kbd>w</kbd>: 在浏览器中打开(第一个端口为http)
|
||||
<kbd>enter</kbd>: 聚焦主面板
|
||||
<kbd>[</kbd>: 上一个选项卡
|
||||
<kbd>]</kbd>: 下一个选项卡
|
||||
<kbd>/</kbd>: 过滤列表
|
||||
</pre>
|
||||
|
||||
## 镜像
|
||||
|
||||
<pre>
|
||||
<kbd>c</kbd>: 运行预定义的自定义命令
|
||||
<kbd>d</kbd>: 移除镜像
|
||||
<kbd>b</kbd>: 查看批量命令
|
||||
<kbd>enter</kbd>: 聚焦主面板
|
||||
<kbd>[</kbd>: 上一个选项卡
|
||||
<kbd>]</kbd>: 下一个选项卡
|
||||
<kbd>/</kbd>: 过滤列表
|
||||
</pre>
|
||||
|
||||
## 卷
|
||||
|
||||
<pre>
|
||||
<kbd>c</kbd>: 运行预定义的自定义命令
|
||||
<kbd>d</kbd>: 移除卷
|
||||
<kbd>b</kbd>: 查看批量命令
|
||||
<kbd>enter</kbd>: 聚焦主面板
|
||||
<kbd>[</kbd>: 上一个选项卡
|
||||
<kbd>]</kbd>: 下一个选项卡
|
||||
<kbd>/</kbd>: 过滤列表
|
||||
</pre>
|
||||
|
||||
## 网络
|
||||
|
||||
<pre>
|
||||
<kbd>c</kbd>: 运行预定义的自定义命令
|
||||
<kbd>d</kbd>: 移除网络
|
||||
<kbd>b</kbd>: 查看批量命令
|
||||
<kbd>enter</kbd>: 聚焦主面板
|
||||
<kbd>[</kbd>: 上一个选项卡
|
||||
<kbd>]</kbd>: 下一个选项卡
|
||||
<kbd>/</kbd>: 过滤列表
|
||||
</pre>
|
||||
|
||||
## 主要
|
||||
|
||||
<pre>
|
||||
<kbd>esc</kbd>: 返回
|
||||
</pre>
|
||||
|
||||
## 全局
|
||||
|
||||
<pre>
|
||||
<kbd>+</kbd>: 下一个屏幕模式(正常/半屏/全屏)
|
||||
<kbd>_</kbd>: 上一个屏幕模式
|
||||
</pre>
|
||||
11
go.mod
11
go.mod
|
|
@ -7,7 +7,7 @@ require (
|
|||
github.com/boz/go-throttle v0.0.0-20160922054636-fdc4eab740c1
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
|
||||
github.com/docker/docker v20.10.15+incompatible
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/fatih/color v1.10.0
|
||||
github.com/go-errors/errors v1.4.2
|
||||
github.com/gookit/color v1.5.0
|
||||
github.com/imdario/mergo v0.3.8
|
||||
|
|
@ -32,16 +32,17 @@ require (
|
|||
require (
|
||||
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/distribution v2.8.0+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/gdamore/encoding v1.0.0 // indirect
|
||||
github.com/gdamore/tcell/v2 v2.5.3 // indirect
|
||||
github.com/goccy/go-yaml v1.11.0
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.11 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
|
||||
github.com/onsi/ginkgo v1.8.0 // indirect
|
||||
|
|
@ -54,7 +55,7 @@ require (
|
|||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 // indirect
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/term v0.1.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
|
||||
|
|
|
|||
16
go.sum
16
go.sum
|
|
@ -12,8 +12,8 @@ github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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=
|
||||
github.com/docker/distribution v2.8.0+incompatible h1:l9EaZDICImO1ngI+uTifW+ZYvvz7fKISBAKpg+MbWbY=
|
||||
github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v20.10.15+incompatible h1:dk9FewY/9Xwm4ay/HViEEHSQuM/kL4F+JaG6GQdgmGo=
|
||||
github.com/docker/docker v20.10.15+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
|
|
@ -22,6 +22,8 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
|
|||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
|
|
@ -31,6 +33,8 @@ github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tv
|
|||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/goccy/go-yaml v1.11.0 h1:n7Z+zx8S9f9KgzG6KtQKf+kwqXZlLNR2F6018Dgau54=
|
||||
github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
|
@ -67,9 +71,13 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
|
|||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
|
|
@ -153,6 +161,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -161,6 +171,8 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ type UserConfig struct {
|
|||
type ThemeConfig struct {
|
||||
ActiveBorderColor []string `yaml:"activeBorderColor,omitempty"`
|
||||
InactiveBorderColor []string `yaml:"inactiveBorderColor,omitempty"`
|
||||
SelectedLineBgColor []string `yaml:"selectedLineBgColor,omitempty"`
|
||||
OptionsTextColor []string `yaml:"optionsTextColor,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -130,6 +131,14 @@ type GuiConfig struct {
|
|||
// When true, increases vertical space used by focused side panel,
|
||||
// creating an accordion effect
|
||||
ExpandFocusedSidePanel bool `yaml:"expandFocusedSidePanel"`
|
||||
|
||||
// ScreenMode allow user to specify which screen mode will be used on startup
|
||||
ScreenMode string `yaml:"screenMode,omitempty"`
|
||||
|
||||
// Determines the style of the container status and container health display in the
|
||||
// containers panel. "long": full words (default), "short": one or two characters,
|
||||
// "icon": unicode emoji.
|
||||
ContainerStatusHealthStyle string `yaml:"containerStatusHealthStyle"`
|
||||
}
|
||||
|
||||
// CommandTemplatesConfig determines what commands actually get called when we
|
||||
|
|
@ -353,15 +362,18 @@ func GetDefaultConfig() UserConfig {
|
|||
Theme: ThemeConfig{
|
||||
ActiveBorderColor: []string{"green", "bold"},
|
||||
InactiveBorderColor: []string{"default"},
|
||||
SelectedLineBgColor: []string{"blue"},
|
||||
OptionsTextColor: []string{"blue"},
|
||||
},
|
||||
ShowAllContainers: false,
|
||||
ReturnImmediately: false,
|
||||
WrapMainPanel: true,
|
||||
LegacySortContainers: false,
|
||||
SidePanelWidth: 0.3333,
|
||||
ShowBottomLine: true,
|
||||
ExpandFocusedSidePanel: false,
|
||||
ShowAllContainers: false,
|
||||
ReturnImmediately: false,
|
||||
WrapMainPanel: true,
|
||||
LegacySortContainers: false,
|
||||
SidePanelWidth: 0.3333,
|
||||
ShowBottomLine: true,
|
||||
ExpandFocusedSidePanel: false,
|
||||
ScreenMode: "normal",
|
||||
ContainerStatusHealthStyle: "long",
|
||||
},
|
||||
ConfirmOnQuit: false,
|
||||
Logs: LogsConfig{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package gui
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -100,7 +99,9 @@ func (gui *Gui) getContainersPanel() *panels.SideListPanel[*commands.Container]
|
|||
|
||||
return true
|
||||
},
|
||||
GetTableCells: presentation.GetContainerDisplayStrings,
|
||||
GetTableCells: func(container *commands.Container) []string {
|
||||
return presentation.GetContainerDisplayStrings(&gui.Config.UserConfig.Gui, container)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -203,12 +204,12 @@ func (gui *Gui) containerConfigStr(container *commands.Container) string {
|
|||
output += "none\n"
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(&container.Details, "", " ")
|
||||
data, err := utils.MarshalIntoYaml(&container.Details)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error marshalling container details: %v", err)
|
||||
}
|
||||
|
||||
output += fmt.Sprintf("\nFull details:\n\n%s", string(data))
|
||||
output += fmt.Sprintf("\nFull details:\n\n%s", utils.ColoredYamlString(string(data)))
|
||||
|
||||
return output
|
||||
}
|
||||
|
|
@ -418,7 +419,7 @@ func (gui *Gui) handleContainerAttach(g *gocui.Gui, v *gocui.View) error {
|
|||
return gui.createErrorPanel(err.Error())
|
||||
}
|
||||
|
||||
return gui.runSubprocess(c)
|
||||
return gui.runSubprocessWithMessage(c, gui.Tr.DetachFromContainerShortCut)
|
||||
}
|
||||
|
||||
func (gui *Gui) handlePruneContainers() error {
|
||||
|
|
|
|||
|
|
@ -18,9 +18,8 @@ func (gui *Gui) createCommandMenu(customCommands []config.CustomCommand, command
|
|||
return command.InternalFunction()
|
||||
}
|
||||
|
||||
resolvedCommand := command.Command
|
||||
if command.Shell {
|
||||
resolvedCommand = gui.OSCommand.NewCommandStringWithShell(command.Command)
|
||||
resolvedCommand = gui.OSCommand.NewCommandStringWithShell(resolvedCommand)
|
||||
}
|
||||
|
||||
// if we have a command for attaching, we attach and return the subprocess error
|
||||
|
|
|
|||
|
|
@ -114,6 +114,19 @@ const (
|
|||
SCREEN_FULL
|
||||
)
|
||||
|
||||
func getScreenMode(config *config.AppConfig) WindowMaximisation {
|
||||
switch config.UserConfig.Gui.ScreenMode {
|
||||
case "normal":
|
||||
return SCREEN_NORMAL
|
||||
case "half":
|
||||
return SCREEN_HALF
|
||||
case "fullscreen":
|
||||
return SCREEN_FULL
|
||||
default:
|
||||
return SCREEN_NORMAL
|
||||
}
|
||||
}
|
||||
|
||||
// NewGui builds a new gui handler
|
||||
func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand *commands.OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*Gui, error) {
|
||||
initialState := guiState{
|
||||
|
|
@ -126,6 +139,7 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
|
|||
ViewStack: []string{},
|
||||
|
||||
ShowExitedContainers: true,
|
||||
ScreenMode: getScreenMode(config),
|
||||
}
|
||||
|
||||
gui := &Gui{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package presentation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
|
|
@ -38,7 +37,7 @@ func RenderStats(userConfig *config.UserConfig, container *commands.Container, v
|
|||
dataReceived := fmt.Sprintf("Traffic received: %s", utils.FormatDecimalBytes(stats.ClientStats.Networks.Eth0.RxBytes))
|
||||
dataSent := fmt.Sprintf("Traffic sent: %s", utils.FormatDecimalBytes(stats.ClientStats.Networks.Eth0.TxBytes))
|
||||
|
||||
originalJSON, err := json.MarshalIndent(stats, "", " ")
|
||||
originalStats, err := utils.MarshalIntoYaml(stats)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -48,7 +47,7 @@ func RenderStats(userConfig *config.UserConfig, container *commands.Container, v
|
|||
pidsCount,
|
||||
dataReceived,
|
||||
dataSent,
|
||||
string(originalJSON),
|
||||
utils.ColoredYamlString(string(originalStats)),
|
||||
)
|
||||
|
||||
return contents, nil
|
||||
|
|
|
|||
|
|
@ -9,14 +9,15 @@ import (
|
|||
dockerTypes "github.com/docker/docker/api/types"
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/lazydocker/pkg/commands"
|
||||
"github.com/jesseduffield/lazydocker/pkg/config"
|
||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func GetContainerDisplayStrings(container *commands.Container) []string {
|
||||
func GetContainerDisplayStrings(guiConfig *config.GuiConfig, container *commands.Container) []string {
|
||||
return []string{
|
||||
getContainerDisplayStatus(container),
|
||||
getContainerDisplaySubstatus(container),
|
||||
getContainerDisplayStatus(guiConfig, container),
|
||||
getContainerDisplaySubstatus(guiConfig, container),
|
||||
container.Name,
|
||||
getDisplayCPUPerc(container),
|
||||
utils.ColoredString(displayPorts(container), color.FgYellow),
|
||||
|
|
@ -52,12 +53,44 @@ func displayPorts(c *commands.Container) string {
|
|||
}
|
||||
|
||||
// getContainerDisplayStatus returns the colored status of the container
|
||||
func getContainerDisplayStatus(c *commands.Container) string {
|
||||
return utils.ColoredString(c.Container.State, getContainerColor(c))
|
||||
func getContainerDisplayStatus(guiConfig *config.GuiConfig, c *commands.Container) string {
|
||||
shortStatusMap := map[string]string{
|
||||
"paused": "P",
|
||||
"exited": "X",
|
||||
"created": "C",
|
||||
"removing": "RM",
|
||||
"restarting": "RS",
|
||||
"running": "R",
|
||||
"dead": "D",
|
||||
}
|
||||
|
||||
iconStatusMap := map[string]rune{
|
||||
"paused": '◫',
|
||||
"exited": '⨯',
|
||||
"created": '+',
|
||||
"removing": '−',
|
||||
"restarting": '⟳',
|
||||
"running": '▶',
|
||||
"dead": '!',
|
||||
}
|
||||
|
||||
var containerState string
|
||||
switch guiConfig.ContainerStatusHealthStyle {
|
||||
case "short":
|
||||
containerState = shortStatusMap[c.Container.State]
|
||||
case "icon":
|
||||
containerState = string(iconStatusMap[c.Container.State])
|
||||
case "long":
|
||||
fallthrough
|
||||
default:
|
||||
containerState = c.Container.State
|
||||
}
|
||||
|
||||
return utils.ColoredString(containerState, getContainerColor(c))
|
||||
}
|
||||
|
||||
// GetDisplayStatus returns the exit code if the container has exited, and the health status if the container is running (and has a health check)
|
||||
func getContainerDisplaySubstatus(c *commands.Container) string {
|
||||
func getContainerDisplaySubstatus(guiConfig *config.GuiConfig, c *commands.Container) string {
|
||||
if !c.DetailsLoaded() {
|
||||
return ""
|
||||
}
|
||||
|
|
@ -68,13 +101,13 @@ func getContainerDisplaySubstatus(c *commands.Container) string {
|
|||
fmt.Sprintf("(%s)", strconv.Itoa(c.Details.State.ExitCode)), getContainerColor(c),
|
||||
)
|
||||
case "running":
|
||||
return getHealthStatus(c)
|
||||
return getHealthStatus(guiConfig, c)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func getHealthStatus(c *commands.Container) string {
|
||||
func getHealthStatus(guiConfig *config.GuiConfig, c *commands.Container) string {
|
||||
if !c.DetailsLoaded() {
|
||||
return ""
|
||||
}
|
||||
|
|
@ -88,8 +121,32 @@ func getHealthStatus(c *commands.Container) string {
|
|||
if c.Details.State.Health == nil {
|
||||
return ""
|
||||
}
|
||||
healthStatus := c.Details.State.Health.Status
|
||||
if healthStatusColor, ok := healthStatusColorMap[healthStatus]; ok {
|
||||
|
||||
shortHealthStatusMap := map[string]string{
|
||||
"healthy": "H",
|
||||
"unhealthy": "U",
|
||||
"starting": "S",
|
||||
}
|
||||
|
||||
iconHealthStatusMap := map[string]rune{
|
||||
"healthy": '✔',
|
||||
"unhealthy": '?',
|
||||
"starting": '…',
|
||||
}
|
||||
|
||||
var healthStatus string
|
||||
switch guiConfig.ContainerStatusHealthStyle {
|
||||
case "short":
|
||||
healthStatus = shortHealthStatusMap[c.Details.State.Health.Status]
|
||||
case "icon":
|
||||
healthStatus = string(iconHealthStatusMap[c.Details.State.Health.Status])
|
||||
case "long":
|
||||
fallthrough
|
||||
default:
|
||||
healthStatus = c.Details.State.Health.Status
|
||||
}
|
||||
|
||||
if healthStatusColor, ok := healthStatusColorMap[c.Details.State.Health.Status]; ok {
|
||||
return utils.ColoredString(fmt.Sprintf("(%s)", healthStatus), healthStatusColor)
|
||||
}
|
||||
return ""
|
||||
|
|
|
|||
|
|
@ -3,13 +3,26 @@ package presentation
|
|||
import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/jesseduffield/lazydocker/pkg/commands"
|
||||
"github.com/jesseduffield/lazydocker/pkg/config"
|
||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||
)
|
||||
|
||||
func GetServiceDisplayStrings(service *commands.Service) []string {
|
||||
func GetServiceDisplayStrings(guiConfig *config.GuiConfig, service *commands.Service) []string {
|
||||
if service.Container == nil {
|
||||
var containerState string
|
||||
switch guiConfig.ContainerStatusHealthStyle {
|
||||
case "short":
|
||||
containerState = "n"
|
||||
case "icon":
|
||||
containerState = "."
|
||||
case "long":
|
||||
fallthrough
|
||||
default:
|
||||
containerState = "none"
|
||||
}
|
||||
|
||||
return []string{
|
||||
utils.ColoredString("none", color.FgBlue),
|
||||
utils.ColoredString(containerState, color.FgBlue),
|
||||
"",
|
||||
service.Name,
|
||||
"",
|
||||
|
|
@ -20,8 +33,8 @@ func GetServiceDisplayStrings(service *commands.Service) []string {
|
|||
|
||||
container := service.Container
|
||||
return []string{
|
||||
getContainerDisplayStatus(container),
|
||||
getContainerDisplaySubstatus(container),
|
||||
getContainerDisplayStatus(guiConfig, container),
|
||||
getContainerDisplaySubstatus(guiConfig, container),
|
||||
service.Name,
|
||||
getDisplayCPUPerc(container),
|
||||
utils.ColoredString(displayPorts(container), color.FgYellow),
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ func (gui *Gui) creditsStr() string {
|
|||
"Raise an Issue: https://github.com/jesseduffield/lazydocker/issues",
|
||||
utils.ColoredString("Buy Jesse a coffee: https://github.com/sponsors/jesseduffield", color.FgMagenta), // caffeine ain't free
|
||||
"Here's your lazydocker config when merged in with the defaults (you can open your config by pressing 'o'):",
|
||||
configBuf.String(),
|
||||
utils.ColoredYamlString(configBuf.String()),
|
||||
}, "\n\n")
|
||||
}
|
||||
|
||||
|
|
@ -142,7 +142,9 @@ func (gui *Gui) renderAllLogs(_project *commands.Project) tasks.TaskFunc {
|
|||
}
|
||||
|
||||
func (gui *Gui) renderDockerComposeConfig(_project *commands.Project) tasks.TaskFunc {
|
||||
return gui.NewSimpleRenderStringTask(func() string { return gui.DockerCommand.DockerComposeConfig() })
|
||||
return gui.NewSimpleRenderStringTask(func() string {
|
||||
return utils.ColoredYamlString(gui.DockerCommand.DockerComposeConfig())
|
||||
})
|
||||
}
|
||||
|
||||
func (gui *Gui) handleOpenConfig(g *gocui.Gui, v *gocui.View) error {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,9 @@ func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] {
|
|||
|
||||
return a.Name < b.Name
|
||||
},
|
||||
GetTableCells: presentation.GetServiceDisplayStrings,
|
||||
GetTableCells: func(service *commands.Service) []string {
|
||||
return presentation.GetServiceDisplayStrings(&gui.Config.UserConfig.Gui, service)
|
||||
},
|
||||
//Hide: func() bool {
|
||||
// return gui.DockerCommand.SelectedComposeProject == nil
|
||||
//},
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ import (
|
|||
)
|
||||
|
||||
func (gui *Gui) runSubprocess(cmd *exec.Cmd) error {
|
||||
return gui.runSubprocessWithMessage(cmd, "")
|
||||
}
|
||||
|
||||
func (gui *Gui) runSubprocessWithMessage(cmd *exec.Cmd, msg string) error {
|
||||
gui.Mutexes.SubprocessMutex.Lock()
|
||||
defer gui.Mutexes.SubprocessMutex.Unlock()
|
||||
|
||||
|
|
@ -22,7 +26,7 @@ func (gui *Gui) runSubprocess(cmd *exec.Cmd) error {
|
|||
|
||||
gui.PauseBackgroundThreads = true
|
||||
|
||||
gui.runCommand(cmd)
|
||||
gui.runCommand(cmd, msg)
|
||||
|
||||
if err := gui.g.Resume(); err != nil {
|
||||
return gui.createErrorPanel(err.Error())
|
||||
|
|
@ -33,7 +37,7 @@ func (gui *Gui) runSubprocess(cmd *exec.Cmd) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) runCommand(cmd *exec.Cmd) {
|
||||
func (gui *Gui) runCommand(cmd *exec.Cmd, msg string) {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stdout
|
||||
cmd.Stdin = os.Stdin
|
||||
|
|
@ -51,7 +55,9 @@ func (gui *Gui) runCommand(cmd *exec.Cmd) {
|
|||
}()
|
||||
|
||||
fmt.Fprintf(os.Stdout, "\n%s\n\n", utils.ColoredString("+ "+strings.Join(cmd.Args, " "), color.FgBlue))
|
||||
|
||||
if msg != "" {
|
||||
fmt.Fprintf(os.Stdout, "\n%s\n\n", utils.ColoredString(msg, color.FgGreen))
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
// not handling the error explicitly because usually we're going to see it
|
||||
// in the output anyway
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ func (gui *Gui) createAllViews() error {
|
|||
(*mapping.viewPtr).FgColor = gocui.ColorDefault
|
||||
}
|
||||
|
||||
selectedLineBgColor := gocui.ColorBlue
|
||||
selectedLineBgColor := GetGocuiStyle(gui.Config.UserConfig.Gui.Theme.SelectedLineBgColor)
|
||||
|
||||
gui.Views.Main.Wrap = gui.Config.UserConfig.Gui.WrapMainPanel
|
||||
// when you run a docker container with the -it flags (interactive mode) it adds carriage returns for some reason. This is not docker's fault, it's an os-level default.
|
||||
|
|
|
|||
136
pkg/i18n/chinese.go
Normal file
136
pkg/i18n/chinese.go
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
package i18n
|
||||
|
||||
func chineseSet() TranslationSet {
|
||||
return TranslationSet{
|
||||
PruningStatus: "修剪中",
|
||||
RemovingStatus: "移除中",
|
||||
RestartingStatus: "重启中",
|
||||
StartingStatus: "启动中",
|
||||
StoppingStatus: "停止中",
|
||||
UppingServiceStatus: "升级服务中",
|
||||
UppingProjectStatus: "升级项目中",
|
||||
DowningStatus: "下架中",
|
||||
PausingStatus: "暂停中",
|
||||
RunningCustomCommandStatus: "正在运行自定义命令",
|
||||
RunningBulkCommandStatus: "正在运行批量命令",
|
||||
|
||||
NoViewMachingNewLineFocusedSwitchStatement: "没有匹配 newLineFocused switch 语句的视图",
|
||||
|
||||
ErrorOccurred: "发生错误!请在 https://github.com/jesseduffield/lazydocker/issues 上创建一个问题",
|
||||
ConnectionFailed: "无法连接到 Docker 客户端。您可能需要重新启动 Docker 客户端",
|
||||
UnattachableContainerError: "容器不支持 attaching。您必须使用“-it”标志运行服务,或者在docker-compose.yml文件中使用`stdin_open: true,tty: true`",
|
||||
WaitingForContainerInfo: "在 Docker 给我们更多关于容器的信息之前,无法继续。请几分钟后重试。",
|
||||
CannotAttachStoppedContainerError: "您不能 attach 到已停止的容器,您需要先启动它(您可以用 'r' 键来执行此操作)(是的,我懒得为您自动执行此操作)(很酷的是,我可以通过错误消息与您进行一对一的通讯)",
|
||||
CannotAccessDockerSocketError: "无法访问 Docker 套接字:unix:///var/run/docker.sock\n请以 root 用户身份运行 lazydocker 或阅读https://docs.docker.com/install/linux/linux-postinstall/",
|
||||
CannotKillChildError: "等待三秒钟以停止子进程。可能有一个孤儿进程在您的系统上继续运行。",
|
||||
|
||||
Donate: "捐赠",
|
||||
Confirm: "确认",
|
||||
|
||||
Return: "返回",
|
||||
FocusMain: "聚焦主面板",
|
||||
LcFilter: "过滤列表",
|
||||
Navigate: "导航",
|
||||
Execute: "执行",
|
||||
Close: "关闭",
|
||||
Quit: "退出",
|
||||
Menu: "菜单",
|
||||
MenuTitle: "菜单",
|
||||
Scroll: "滚动",
|
||||
OpenConfig: "打开lazydocker配置",
|
||||
EditConfig: "编辑lazydocker配置",
|
||||
Cancel: "取消",
|
||||
Remove: "移除",
|
||||
HideStopped: "隐藏/显示已停止的容器",
|
||||
ForceRemove: "强制移除",
|
||||
RemoveWithVolumes: "移除并删除卷",
|
||||
RemoveService: "移除容器",
|
||||
UpService: "启动服务",
|
||||
Stop: "停止",
|
||||
Pause: "暂停",
|
||||
Restart: "重新启动",
|
||||
Down: "关闭项目",
|
||||
DownWithVolumes: "关闭包括卷的项目",
|
||||
Start: "启动项目",
|
||||
Rebuild: "重建",
|
||||
Recreate: "重新创建",
|
||||
PreviousContext: "上一个选项卡",
|
||||
NextContext: "下一个选项卡",
|
||||
// Attach: "连接/附加",
|
||||
ViewLogs: "查看日志",
|
||||
UpProject: "创建并启动容器",
|
||||
DownProject: "停止并移除容器",
|
||||
RemoveImage: "移除镜像",
|
||||
RemoveVolume: "移除卷",
|
||||
RemoveNetwork: "移除网络",
|
||||
RemoveWithoutPrune: "移除但不删除未标记的父级",
|
||||
RemoveWithoutPruneWithForce: "移除(强制)但不删除未标记的父级",
|
||||
RemoveWithForce: "移除(强制)",
|
||||
PruneContainers: "删除退出的容器",
|
||||
PruneVolumes: "删除未使用的卷",
|
||||
PruneNetworks: "删除未使用的网络",
|
||||
PruneImages: "删除未使用的镜像",
|
||||
StopAllContainers: "停止所有容器",
|
||||
RemoveAllContainers: "删除所有容器(强制)",
|
||||
ViewRestartOptions: "查看重启选项",
|
||||
ExecShell: "执行shell",
|
||||
RunCustomCommand: "运行预定义的自定义命令",
|
||||
ViewBulkCommands: "查看批量命令",
|
||||
FilterList: "过滤列表",
|
||||
OpenInBrowser: "在浏览器中打开(第一个端口为http)",
|
||||
SortContainersByState: "按状态排序容器",
|
||||
|
||||
GlobalTitle: "全局",
|
||||
MainTitle: "主要",
|
||||
ProjectTitle: "项目",
|
||||
ServicesTitle: "服务",
|
||||
ContainersTitle: "容器",
|
||||
StandaloneContainersTitle: "独立容器",
|
||||
ImagesTitle: "镜像",
|
||||
VolumesTitle: "卷",
|
||||
NetworksTitle: "网络",
|
||||
CustomCommandTitle: "自定义命令:",
|
||||
BulkCommandTitle: "批量命令:",
|
||||
ErrorTitle: "错误",
|
||||
LogsTitle: "日志",
|
||||
ConfigTitle: "配置",
|
||||
EnvTitle: "环境变量",
|
||||
DockerComposeConfigTitle: "Docker-Compose配置",
|
||||
TopTitle: "系统资源管理",
|
||||
StatsTitle: "统计信息",
|
||||
CreditsTitle: "关于我们",
|
||||
ContainerConfigTitle: "容器配置",
|
||||
ContainerEnvTitle: "容器环境变量",
|
||||
NothingToDisplay: "无内容显示",
|
||||
NoContainerForService: "没有日志可以展示;该服务未关联任何容器",
|
||||
CannotDisplayEnvVariables: "展示环境变量时出现问题",
|
||||
|
||||
NoContainers: "没有容器",
|
||||
NoContainer: "没有容器",
|
||||
NoImages: "没有镜像",
|
||||
NoVolumes: "没有卷",
|
||||
NoNetworks: "没有网络",
|
||||
NoServices: "没有服务",
|
||||
|
||||
ConfirmQuit: "您确定要退出吗?",
|
||||
ConfirmUpProject: "您确定要“up”的docker compose项目吗?",
|
||||
MustForceToRemoveContainer: "您无法删除正在运行的容器,除非您强制执行。您想强制执行吗?",
|
||||
NotEnoughSpace: "空间不足,无法渲染面板",
|
||||
ConfirmPruneImages: "您确定要删除所有未使用的镜像吗?",
|
||||
ConfirmPruneContainers: "您确定要删除所有停止的容器吗?",
|
||||
ConfirmStopContainers: "您确定要停止所有容器吗?",
|
||||
ConfirmRemoveContainers: "您确定要删除所有容器吗?",
|
||||
ConfirmPruneVolumes: "您确定要删除所有未使用的卷吗?",
|
||||
ConfirmPruneNetworks: "您确定要删除所有未使用的网络吗?",
|
||||
StopService: "您确定要停止此服务的容器吗?",
|
||||
StopContainer: "您确定要停止此容器吗?",
|
||||
PressEnterToReturn: "按 enter 返回 lazydocker(您可以在配置文件中设置 `gui.returnImmediately: true` 来禁用此提示)",
|
||||
|
||||
No: "否",
|
||||
Yes: "是",
|
||||
|
||||
LcNextScreenMode: "下一个屏幕模式(正常/半屏/全屏)",
|
||||
LcPrevScreenMode: "上一个屏幕模式",
|
||||
FilterPrompt: "筛选",
|
||||
}
|
||||
}
|
||||
|
|
@ -83,15 +83,16 @@ func dutchSet() TranslationSet {
|
|||
NoVolumes: "Geen volumes",
|
||||
NoNetworks: "Geen networks",
|
||||
|
||||
ConfirmQuit: "Weet je zeker dat je weg wil gaan?",
|
||||
MustForceToRemoveContainer: "Je kan geen draaiende container verwijderen tenzij je het forceert, Wil je het forceren?",
|
||||
NotEnoughSpace: "Niet genoeg ruimte om de panelen te renderen",
|
||||
ConfirmPruneImages: "Weet je zeker dat je alle niet gebruikte images wil vernietigen?",
|
||||
ConfirmPruneContainers: "Weet je zeker dat je alle niet gestopte containers wil vernietigen?",
|
||||
ConfirmPruneVolumes: "Weet je zeker dat je alle niet gebruikte volumes wil vernietigen?",
|
||||
ConfirmPruneNetworks: "Weet je zeker dat je alle niet gebruikte networks wil vernietigen?",
|
||||
StopService: "Weet je zeker dat je deze service zijn containers wil stoppen?",
|
||||
StopContainer: "Weet je zeker dat je deze container wil stoppen?",
|
||||
PressEnterToReturn: "Druk op enter om terug te gaan naar lazydocker (Deze popup kan uit gezet worden door in de config dit neer te zetten `gui.returnImmediately: true`)",
|
||||
ConfirmQuit: "Weet je zeker dat je weg wil gaan?",
|
||||
MustForceToRemoveContainer: "Je kan geen draaiende container verwijderen tenzij je het forceert, Wil je het forceren?",
|
||||
NotEnoughSpace: "Niet genoeg ruimte om de panelen te renderen",
|
||||
ConfirmPruneImages: "Weet je zeker dat je alle niet gebruikte images wil vernietigen?",
|
||||
ConfirmPruneContainers: "Weet je zeker dat je alle niet gestopte containers wil vernietigen?",
|
||||
ConfirmPruneVolumes: "Weet je zeker dat je alle niet gebruikte volumes wil vernietigen?",
|
||||
ConfirmPruneNetworks: "Weet je zeker dat je alle niet gebruikte networks wil vernietigen?",
|
||||
StopService: "Weet je zeker dat je deze service zijn containers wil stoppen?",
|
||||
StopContainer: "Weet je zeker dat je deze container wil stoppen?",
|
||||
PressEnterToReturn: "Druk op enter om terug te gaan naar lazydocker (Deze popup kan uit gezet worden door in de config dit neer te zetten `gui.returnImmediately: true`)",
|
||||
DetachFromContainerShortCut: "Als u wilt loskoppelen van de container, drukt u standaard op ctrl-p en vervolgens op ctrl-q",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ type TranslationSet struct {
|
|||
PruningStatus string
|
||||
StopService string
|
||||
PressEnterToReturn string
|
||||
DetachFromContainerShortCut string
|
||||
StopAllContainers string
|
||||
RemoveAllContainers string
|
||||
ViewRestartOptions string
|
||||
|
|
@ -241,19 +242,20 @@ func englishSet() TranslationSet {
|
|||
NoNetworks: "No networks",
|
||||
NoServices: "No services",
|
||||
|
||||
ConfirmQuit: "Are you sure you want to quit?",
|
||||
ConfirmUpProject: "Are you sure you want to 'up' your docker compose project?",
|
||||
MustForceToRemoveContainer: "You cannot remove a running container unless you force it. Do you want to force it?",
|
||||
NotEnoughSpace: "Not enough space to render panels",
|
||||
ConfirmPruneImages: "Are you sure you want to prune all unused images?",
|
||||
ConfirmPruneContainers: "Are you sure you want to prune all stopped containers?",
|
||||
ConfirmStopContainers: "Are you sure you want to stop all containers?",
|
||||
ConfirmRemoveContainers: "Are you sure you want to remove all containers?",
|
||||
ConfirmPruneVolumes: "Are you sure you want to prune all unused volumes?",
|
||||
ConfirmPruneNetworks: "Are you sure you want to prune all unused networks?",
|
||||
StopService: "Are you sure you want to stop this service's containers?",
|
||||
StopContainer: "Are you sure you want to stop this container?",
|
||||
PressEnterToReturn: "Press enter to return to lazydocker (this prompt can be disabled in your config by setting `gui.returnImmediately: true`)",
|
||||
ConfirmQuit: "Are you sure you want to quit?",
|
||||
ConfirmUpProject: "Are you sure you want to 'up' your docker compose project?",
|
||||
MustForceToRemoveContainer: "You cannot remove a running container unless you force it. Do you want to force it?",
|
||||
NotEnoughSpace: "Not enough space to render panels",
|
||||
ConfirmPruneImages: "Are you sure you want to prune all unused images?",
|
||||
ConfirmPruneContainers: "Are you sure you want to prune all stopped containers?",
|
||||
ConfirmStopContainers: "Are you sure you want to stop all containers?",
|
||||
ConfirmRemoveContainers: "Are you sure you want to remove all containers?",
|
||||
ConfirmPruneVolumes: "Are you sure you want to prune all unused volumes?",
|
||||
ConfirmPruneNetworks: "Are you sure you want to prune all unused networks?",
|
||||
StopService: "Are you sure you want to stop this service's containers?",
|
||||
StopContainer: "Are you sure you want to stop this container?",
|
||||
PressEnterToReturn: "Press enter to return to lazydocker (this prompt can be disabled in your config by setting `gui.returnImmediately: true`)",
|
||||
DetachFromContainerShortCut: "By default, to detach from the container press ctrl-p then ctrl-q",
|
||||
|
||||
No: "no",
|
||||
Yes: "yes",
|
||||
|
|
|
|||
|
|
@ -100,18 +100,19 @@ func frenchSet() TranslationSet {
|
|||
NoVolumes: "Aucun volumes",
|
||||
NoNetworks: "Aucun réseaux",
|
||||
|
||||
ConfirmQuit: "Êtes vous certain de vouloir quitter?",
|
||||
MustForceToRemoveContainer: "Vous ne pouvez pas supprimer un conteneur qui tourne sans le forcer. Voulez-vous le forcer ?",
|
||||
NotEnoughSpace: "Manque d'espace pour afficher les differents panneaux",
|
||||
ConfirmPruneImages: "Êtes-vous certain de vouloir détruire toutes les images non utilisés ?",
|
||||
ConfirmPruneContainers: "Êtes-vous certain de vouloir détruire tous les conteneurs arrêtés ?",
|
||||
ConfirmStopContainers: "Êtes-vous certain de vouloir arrêter tous les conteneurs ?",
|
||||
ConfirmRemoveContainers: "Êtes-vous certain de vouloir supprimer tous les conteneurs ?",
|
||||
ConfirmPruneVolumes: "Êtes-vous certain de vouloir détruire tous les volumes non utilisés ?",
|
||||
ConfirmPruneNetworks: "Êtes-vous certain de vouloir détruire tous les réseaux non utilisés ?",
|
||||
StopService: "Êtes-vous certain de vouloir arrêter le conteneur de ce service ?",
|
||||
StopContainer: "Êtes-vous certain de vouloir arrêter ce conteneur ?",
|
||||
PressEnterToReturn: "Appuiez sur Enter pour revenir à lazydocker (ce message peut être désactivé dans vos configurations en appliquant `gui.returnImmediately: true`)",
|
||||
ConfirmQuit: "Êtes vous certain de vouloir quitter?",
|
||||
MustForceToRemoveContainer: "Vous ne pouvez pas supprimer un conteneur qui tourne sans le forcer. Voulez-vous le forcer ?",
|
||||
NotEnoughSpace: "Manque d'espace pour afficher les differents panneaux",
|
||||
ConfirmPruneImages: "Êtes-vous certain de vouloir détruire toutes les images non utilisés ?",
|
||||
ConfirmPruneContainers: "Êtes-vous certain de vouloir détruire tous les conteneurs arrêtés ?",
|
||||
ConfirmStopContainers: "Êtes-vous certain de vouloir arrêter tous les conteneurs ?",
|
||||
ConfirmRemoveContainers: "Êtes-vous certain de vouloir supprimer tous les conteneurs ?",
|
||||
ConfirmPruneVolumes: "Êtes-vous certain de vouloir détruire tous les volumes non utilisés ?",
|
||||
ConfirmPruneNetworks: "Êtes-vous certain de vouloir détruire tous les réseaux non utilisés ?",
|
||||
StopService: "Êtes-vous certain de vouloir arrêter le conteneur de ce service ?",
|
||||
StopContainer: "Êtes-vous certain de vouloir arrêter ce conteneur ?",
|
||||
PressEnterToReturn: "Appuiez sur Enter pour revenir à lazydocker (ce message peut être désactivé dans vos configurations en appliquant `gui.returnImmediately: true`)",
|
||||
DetachFromContainerShortCut: "Par défaut, pour se détacher du conteneur appuyez sur ctrl-p puis ctrl-q",
|
||||
|
||||
No: "non",
|
||||
Yes: "oui",
|
||||
|
|
|
|||
|
|
@ -82,15 +82,16 @@ func germanSet() TranslationSet {
|
|||
NoVolumes: "Keine Volumes",
|
||||
NoNetworks: "Keine Netzwerk",
|
||||
|
||||
ConfirmQuit: "Bist du dir sicher, dass du verlassen möchtest?",
|
||||
MustForceToRemoveContainer: "Du kannst keinen Container entfernen, der noch ausgeführt wird außer du erzwingst es. Möchtest du es erzwingen?",
|
||||
NotEnoughSpace: "Nicht genug Platz um die Panel darzustellen",
|
||||
ConfirmPruneImages: "Bist du dir sicher, dass du alle unbenutzten Images entfernen möchtest?",
|
||||
ConfirmPruneContainers: "Bist du dir sicher, dass du alle angehaltenen Container entfernen möchtes?",
|
||||
ConfirmPruneVolumes: "Bist du dir sicher, dass du alle unbenutzen Volumes entfernen möchtest?",
|
||||
ConfirmPruneNetworks: "Bist du dir sicher, dass du alle unbenutzen Netzwerk entfernen möchtest?",
|
||||
StopService: "Bist du dir sicher, dass du den Dienst dieses Containers anhalten möchtest?",
|
||||
StopContainer: "Bist du dir sicher, dass du den Container anhalten möchtest?",
|
||||
PressEnterToReturn: "Drücke Eingabe um zu lazydocker zurückzukehren. (Diese Nachfrage kann in Deiner Konfiguration deaktiviert werden, indem du folgenden Wert setzt: `gui.returnImmediately: true`)",
|
||||
ConfirmQuit: "Bist du dir sicher, dass du verlassen möchtest?",
|
||||
MustForceToRemoveContainer: "Du kannst keinen Container entfernen, der noch ausgeführt wird außer du erzwingst es. Möchtest du es erzwingen?",
|
||||
NotEnoughSpace: "Nicht genug Platz um die Panel darzustellen",
|
||||
ConfirmPruneImages: "Bist du dir sicher, dass du alle unbenutzten Images entfernen möchtest?",
|
||||
ConfirmPruneContainers: "Bist du dir sicher, dass du alle angehaltenen Container entfernen möchtes?",
|
||||
ConfirmPruneVolumes: "Bist du dir sicher, dass du alle unbenutzen Volumes entfernen möchtest?",
|
||||
ConfirmPruneNetworks: "Bist du dir sicher, dass du alle unbenutzen Netzwerk entfernen möchtest?",
|
||||
StopService: "Bist du dir sicher, dass du den Dienst dieses Containers anhalten möchtest?",
|
||||
StopContainer: "Bist du dir sicher, dass du den Container anhalten möchtest?",
|
||||
PressEnterToReturn: "Drücke Eingabe um zu lazydocker zurückzukehren. (Diese Nachfrage kann in Deiner Konfiguration deaktiviert werden, indem du folgenden Wert setzt: `gui.returnImmediately: true`)",
|
||||
DetachFromContainerShortCut: "Um sich vom Container zu trennen, drücken Sie standardmäßig ctrl-p und dann ctrl-q",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ func GetTranslationSets() map[string]TranslationSet {
|
|||
"tr": turkishSet(),
|
||||
"en": englishSet(),
|
||||
"fr": frenchSet(),
|
||||
"zh": chineseSet(),
|
||||
"pt": portugueseSet(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,15 +82,16 @@ func polishSet() TranslationSet {
|
|||
NoVolumes: "Brak wolumenów",
|
||||
NoNetworks: "Brak sieci",
|
||||
|
||||
ConfirmQuit: "Na pewno chcesz wyjść?",
|
||||
MustForceToRemoveContainer: "Nie możesz usunąć uruchomionego kontenera dopóki nie zrobisz tego siłą. Chcesz wykonać to z siłą?",
|
||||
NotEnoughSpace: "Niedostateczna ilość miejsca do wyświetlenia paneli",
|
||||
ConfirmPruneImages: "Na pewno wyczyścić wszystkie nieużywane obrazy?",
|
||||
ConfirmPruneContainers: "Na pewno wyczyścić wszystkie nieuruchomione kontenery?",
|
||||
ConfirmPruneVolumes: "Na pewno wyczyścić wszystkie nieużywane wolumeny?",
|
||||
ConfirmPruneNetworks: "Na pewno wyczyścić wszystkie nieużywane seici?",
|
||||
StopService: "Na pewno zatrzymać kontenery tego serwisu?",
|
||||
StopContainer: "Na pewno zatrzymać ten kontener?",
|
||||
PressEnterToReturn: "Wciśnij enter aby powrócić do lazydockera (ten komunikat może być wyłączony w konfiguracji poprzez ustawienie `gui.returnImmediately: true`)",
|
||||
ConfirmQuit: "Na pewno chcesz wyjść?",
|
||||
MustForceToRemoveContainer: "Nie możesz usunąć uruchomionego kontenera dopóki nie zrobisz tego siłą. Chcesz wykonać to z siłą?",
|
||||
NotEnoughSpace: "Niedostateczna ilość miejsca do wyświetlenia paneli",
|
||||
ConfirmPruneImages: "Na pewno wyczyścić wszystkie nieużywane obrazy?",
|
||||
ConfirmPruneContainers: "Na pewno wyczyścić wszystkie nieuruchomione kontenery?",
|
||||
ConfirmPruneVolumes: "Na pewno wyczyścić wszystkie nieużywane wolumeny?",
|
||||
ConfirmPruneNetworks: "Na pewno wyczyścić wszystkie nieużywane seici?",
|
||||
StopService: "Na pewno zatrzymać kontenery tego serwisu?",
|
||||
StopContainer: "Na pewno zatrzymać ten kontener?",
|
||||
PressEnterToReturn: "Wciśnij enter aby powrócić do lazydockera (ten komunikat może być wyłączony w konfiguracji poprzez ustawienie `gui.returnImmediately: true`)",
|
||||
DetachFromContainerShortCut: "Domyślnie, aby odłączyć się od kontenera, naciśnij ctrl-p, a następnie ctrl-q",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
137
pkg/i18n/portuguese.go
Normal file
137
pkg/i18n/portuguese.go
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
package i18n
|
||||
|
||||
func portugueseSet() TranslationSet {
|
||||
return TranslationSet{
|
||||
PruningStatus: "destruindo",
|
||||
RemovingStatus: "removendo",
|
||||
RestartingStatus: "reiniciando",
|
||||
StartingStatus: "iniciando",
|
||||
StoppingStatus: "parando",
|
||||
UppingServiceStatus: "subindo serviço",
|
||||
UppingProjectStatus: "subindo projeto",
|
||||
DowningStatus: "derrubando",
|
||||
PausingStatus: "pausando",
|
||||
RunningCustomCommandStatus: "executando comando personalizado",
|
||||
RunningBulkCommandStatus: "executando comando em massa",
|
||||
|
||||
NoViewMachingNewLineFocusedSwitchStatement: "No view matching newLineFocused switch statement",
|
||||
|
||||
ErrorOccurred: "Um erro ocorreu! Por favor, crie uma issue em https://github.com/jesseduffield/lazydocker/issues",
|
||||
ConnectionFailed: "Falha na conexão com o cliente Docker. Você pode precisar reiniciar o seu cliente Docker",
|
||||
UnattachableContainerError: "O contêiner não suporta anexação. Você deve executar o serviço com a flag '-it' ou usar `stdin_open: true, tty: true` no arquivo docker-compose.yml",
|
||||
WaitingForContainerInfo: "Não é possível prosseguir até que o Docker forneça mais informações sobre o contêiner. Por favor, tente novamente em alguns momentos.",
|
||||
CannotAttachStoppedContainerError: "Você não pode anexar a um contêiner parado, você precisa iniciá-lo primeiro (o que você pode fazer com a tecla 'r') (sim, sou preguiçoso demais para fazer isso automaticamente para você) (aliás, bem legal que eu posso me comunicar diretamente com você na forma de uma mensagem de erro)",
|
||||
CannotAccessDockerSocketError: "Não é possível acessar o sôquete docker em: unix:///var/run/docker.sock\nExecute o lazydocker como root ou leia https://docs.docker.com/install/linux/linux-postinstall/",
|
||||
CannotKillChildError: "Três segundos foram esperarados para que os processos filhos parassem. Pode haver um processo órfão que continua em execução em seu sistema.",
|
||||
|
||||
Donate: "Doar",
|
||||
Confirm: "Confirmar",
|
||||
|
||||
Return: "retornar",
|
||||
FocusMain: "focar no painel principal",
|
||||
LcFilter: "filtrar lista",
|
||||
Navigate: "navegar",
|
||||
Execute: "executar",
|
||||
Close: "fechar",
|
||||
Quit: "sair",
|
||||
Menu: "menu",
|
||||
MenuTitle: "Menu",
|
||||
Scroll: "rolar",
|
||||
OpenConfig: "abrir configuração do lazydocker",
|
||||
EditConfig: "editar configuração do lazydocker",
|
||||
Cancel: "cancelar",
|
||||
Remove: "remover",
|
||||
HideStopped: "ocultar/mostrar contêineres parados",
|
||||
ForceRemove: "forçar remoção",
|
||||
RemoveWithVolumes: "remover com volumes",
|
||||
RemoveService: "remover contêineres",
|
||||
UpService: "subir serviço",
|
||||
Stop: "parar",
|
||||
Pause: "pausar",
|
||||
Restart: "reiniciar",
|
||||
Down: "derrubar projeto",
|
||||
DownWithVolumes: "derrubar projetos com volumes",
|
||||
Start: "iniciar",
|
||||
Rebuild: "reconstuir",
|
||||
Recreate: "recriar",
|
||||
PreviousContext: "aba anterior",
|
||||
NextContext: "próxima aba",
|
||||
Attach: "anexar",
|
||||
ViewLogs: "ver logs",
|
||||
UpProject: "subir projeto",
|
||||
DownProject: "derrubar projeto",
|
||||
RemoveImage: "remover imagem",
|
||||
RemoveVolume: "remover volume",
|
||||
RemoveNetwork: "remover rede",
|
||||
RemoveWithoutPrune: "remover sem deletar pais não etiquetados",
|
||||
RemoveWithoutPruneWithForce: "remover (forçado) sem deletar pais não etiquetados",
|
||||
RemoveWithForce: "remover (forçado)",
|
||||
PruneContainers: "destruir contêineres encerrados",
|
||||
PruneVolumes: "destruir volumes não utilizados",
|
||||
PruneNetworks: "destruir redes não utilizadas",
|
||||
PruneImages: "destruir imagens não utilizadas",
|
||||
StopAllContainers: "parar todos os contêineres",
|
||||
RemoveAllContainers: "remover todos os contêineres (forçado)",
|
||||
ViewRestartOptions: "ver opções de reinício",
|
||||
ExecShell: "executar shell",
|
||||
RunCustomCommand: "executar comando personalizado predefinido",
|
||||
ViewBulkCommands: "ver comandos em massa",
|
||||
FilterList: "filtrar lista",
|
||||
OpenInBrowser: "abrir no navegador (primeira porta é http)",
|
||||
SortContainersByState: "ordenar contêineres por estado",
|
||||
|
||||
GlobalTitle: "Global",
|
||||
MainTitle: "Principal",
|
||||
ProjectTitle: "Projeto",
|
||||
ServicesTitle: "Serviços",
|
||||
ContainersTitle: "Contêineres",
|
||||
StandaloneContainersTitle: "Contêineres Avulsos",
|
||||
ImagesTitle: "Imagens",
|
||||
VolumesTitle: "Volumes",
|
||||
NetworksTitle: "Redes",
|
||||
CustomCommandTitle: "Comando Personalizado:",
|
||||
BulkCommandTitle: "Comando em Massa:",
|
||||
ErrorTitle: "Erro",
|
||||
LogsTitle: "Registros",
|
||||
ConfigTitle: "Config",
|
||||
EnvTitle: "Env",
|
||||
DockerComposeConfigTitle: "Docker-Compose Config",
|
||||
TopTitle: "Topo",
|
||||
StatsTitle: "Estatísticas",
|
||||
CreditsTitle: "Sobre",
|
||||
ContainerConfigTitle: "Configuração do Contêiner",
|
||||
ContainerEnvTitle: "Contêiner Env",
|
||||
NothingToDisplay: "Nada a exibir",
|
||||
NoContainerForService: "Nenhum log para exibir; o serviço não está associado a nenhum contêiner",
|
||||
CannotDisplayEnvVariables: "Algo deu errado ao exibir as variáveis de ambiente",
|
||||
|
||||
NoContainers: "Sem contêineres",
|
||||
NoContainer: "Sem contêiner",
|
||||
NoImages: "Sem imagens",
|
||||
NoVolumes: "Sem volumes",
|
||||
NoNetworks: "Sem redes",
|
||||
NoServices: "Sem serviços",
|
||||
|
||||
ConfirmQuit: "Tem certeza que deseja sair?",
|
||||
ConfirmUpProject: "Tem certeza que deseja 'iniciar' seu projeto docker compose?",
|
||||
MustForceToRemoveContainer: "Você não pode remover um contêiner em execução a menos que o force. Deseja forçar?",
|
||||
NotEnoughSpace: "Sem espaço suficiente para renderizar os painéis",
|
||||
ConfirmPruneImages: "Tem certeza que deseja eliminar todas as imagens não utilizadas?",
|
||||
ConfirmPruneContainers: "Tem certeza que deseja destruir todos os contêineres parados?",
|
||||
ConfirmStopContainers: "Tem certeza que deseja parar todos os contêineres?",
|
||||
ConfirmRemoveContainers: "Tem certeza que deseja remover todos os contêineres?",
|
||||
ConfirmPruneVolumes: "Tem certeza que deseja destruir todos os volumes não utilizados?",
|
||||
ConfirmPruneNetworks: "Tem certeza que deseja destruir todos as redes não utilizadas?",
|
||||
StopService: "Tem certeza que deseja parar os contêineres deste serviço?",
|
||||
StopContainer: "Tem certeza que deseja parar este contêiner?",
|
||||
PressEnterToReturn: "Pressione enter para retornar ao lazydocker (este prompt pode ser desativado em sua configuração definindo `gui.returnImmediately: true`)",
|
||||
DetachFromContainerShortCut: "Por padrão, para desanexar do contêiner, pressione ctrl-p e depois ctrl-q",
|
||||
|
||||
No: "não",
|
||||
Yes: "sim",
|
||||
|
||||
LcNextScreenMode: "modo de tela seguinte (normal/meia/tela cheia)",
|
||||
LcPrevScreenMode: "modo de tela anterior",
|
||||
FilterPrompt: "filtro",
|
||||
}
|
||||
}
|
||||
|
|
@ -82,15 +82,16 @@ func turkishSet() TranslationSet {
|
|||
NoVolumes: "Alanlar yok",
|
||||
NoNetworks: "Ağları yok",
|
||||
|
||||
ConfirmQuit: "Çıkmak istediğine emin misin?",
|
||||
MustForceToRemoveContainer: "Zorlamadan çalışan bir konteyneri kaldıramazsınız. Zorlamak ister misin?",
|
||||
NotEnoughSpace: "Panelleri oluşturmak için yeterli alan yok",
|
||||
ConfirmPruneImages: "Kullanılmayan tüm görüntüleri temizlemek istediğinize emin misiniz?",
|
||||
ConfirmPruneContainers: "Durdurulan tüm konteynerları temizlemek istediğinizden emin misiniz?",
|
||||
ConfirmPruneVolumes: "Kullanılmayan tüm alanları temizlemek istediğinizden emin misiniz?",
|
||||
ConfirmPruneNetworks: "Kullanılmayan tüm ağları temizlemek istediğinizden emin misiniz?",
|
||||
StopService: "Bu servisin konteynerlerini durdurmak istediğinize emin misiniz?",
|
||||
StopContainer: "Bu konteyneri durdurmak istediğinize emin misiniz?",
|
||||
PressEnterToReturn: "lazydocker' a geri dönmek için enter tuşuna basın ( Bu uyarı, `gui.return Immediately: true` ayarıyla devre dışı bırakılabilir)",
|
||||
ConfirmQuit: "Çıkmak istediğine emin misin?",
|
||||
MustForceToRemoveContainer: "Zorlamadan çalışan bir konteyneri kaldıramazsınız. Zorlamak ister misin?",
|
||||
NotEnoughSpace: "Panelleri oluşturmak için yeterli alan yok",
|
||||
ConfirmPruneImages: "Kullanılmayan tüm görüntüleri temizlemek istediğinize emin misiniz?",
|
||||
ConfirmPruneContainers: "Durdurulan tüm konteynerları temizlemek istediğinizden emin misiniz?",
|
||||
ConfirmPruneVolumes: "Kullanılmayan tüm alanları temizlemek istediğinizden emin misiniz?",
|
||||
ConfirmPruneNetworks: "Kullanılmayan tüm ağları temizlemek istediğinizden emin misiniz?",
|
||||
StopService: "Bu servisin konteynerlerini durdurmak istediğinize emin misiniz?",
|
||||
StopContainer: "Bu konteyneri durdurmak istediğinize emin misiniz?",
|
||||
PressEnterToReturn: "lazydocker' a geri dönmek için enter tuşuna basın ( Bu uyarı, `gui.return Immediately: true` ayarıyla devre dışı bırakılabilir)",
|
||||
DetachFromContainerShortCut: "Varsayılan olarak, kaptan ayırmak için ctrl-p ve ardından ctrl-q tuşlarına basın",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package utils
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
|
|
@ -13,8 +14,14 @@ import (
|
|||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/mattn/go-runewidth"
|
||||
|
||||
// "github.com/jesseduffield/yaml"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/goccy/go-yaml"
|
||||
"github.com/goccy/go-yaml/lexer"
|
||||
"github.com/goccy/go-yaml/printer"
|
||||
)
|
||||
|
||||
// SplitLines takes a multiline string and splits it on newlines
|
||||
|
|
@ -35,10 +42,10 @@ func SplitLines(multilineString string) []string {
|
|||
// WithPadding pads a string as much as you want
|
||||
func WithPadding(str string, padding int) string {
|
||||
uncoloredStr := Decolorise(str)
|
||||
if padding < len(uncoloredStr) {
|
||||
if padding < runewidth.StringWidth(uncoloredStr) {
|
||||
return str
|
||||
}
|
||||
return str + strings.Repeat(" ", padding-len(uncoloredStr))
|
||||
return str + strings.Repeat(" ", padding-runewidth.StringWidth(uncoloredStr))
|
||||
}
|
||||
|
||||
// ColoredString takes a string and a colour attribute and returns a colored
|
||||
|
|
@ -52,6 +59,45 @@ func ColoredString(str string, colorAttribute color.Attribute) string {
|
|||
return ColoredStringDirect(str, colour)
|
||||
}
|
||||
|
||||
// ColoredYamlString takes an YAML formatted string and returns a colored string
|
||||
// with colors hardcoded as:
|
||||
// keys: cyan
|
||||
// Booleans: magenta
|
||||
// Numbers: yellow
|
||||
// Strings: green
|
||||
func ColoredYamlString(str string) string {
|
||||
format := func(attr color.Attribute) string {
|
||||
return fmt.Sprintf("%s[%dm", "\x1b", attr)
|
||||
}
|
||||
tokens := lexer.Tokenize(str)
|
||||
var p printer.Printer
|
||||
p.Bool = func() *printer.Property {
|
||||
return &printer.Property{
|
||||
Prefix: format(color.FgMagenta),
|
||||
Suffix: format(color.Reset),
|
||||
}
|
||||
}
|
||||
p.Number = func() *printer.Property {
|
||||
return &printer.Property{
|
||||
Prefix: format(color.FgYellow),
|
||||
Suffix: format(color.Reset),
|
||||
}
|
||||
}
|
||||
p.MapKey = func() *printer.Property {
|
||||
return &printer.Property{
|
||||
Prefix: format(color.FgCyan),
|
||||
Suffix: format(color.Reset),
|
||||
}
|
||||
}
|
||||
p.String = func() *printer.Property {
|
||||
return &printer.Property{
|
||||
Prefix: format(color.FgGreen),
|
||||
Suffix: format(color.Reset),
|
||||
}
|
||||
}
|
||||
return p.PrintTokens(tokens)
|
||||
}
|
||||
|
||||
// MultiColoredString takes a string and an array of colour attributes and returns a colored
|
||||
// string with those attributes
|
||||
func MultiColoredString(str string, colorAttribute ...color.Attribute) string {
|
||||
|
|
@ -98,54 +144,52 @@ func Max(x, y int) int {
|
|||
}
|
||||
|
||||
// RenderTable takes an array of string arrays and returns a table containing the values
|
||||
func RenderTable(stringArrays [][]string) (string, error) {
|
||||
if len(stringArrays) == 0 {
|
||||
func RenderTable(rows [][]string) (string, error) {
|
||||
if len(rows) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
if !displayArraysAligned(stringArrays) {
|
||||
if !displayArraysAligned(rows) {
|
||||
return "", errors.New("Each item must return the same number of strings to display")
|
||||
}
|
||||
|
||||
padWidths := getPadWidths(stringArrays)
|
||||
paddedDisplayStrings := getPaddedDisplayStrings(stringArrays, padWidths)
|
||||
columnPadWidths := getPadWidths(rows)
|
||||
paddedDisplayRows := getPaddedDisplayStrings(rows, columnPadWidths)
|
||||
|
||||
return strings.Join(paddedDisplayStrings, "\n"), nil
|
||||
return strings.Join(paddedDisplayRows, "\n"), nil
|
||||
}
|
||||
|
||||
// Decolorise strips a string of color
|
||||
func Decolorise(str string) string {
|
||||
re := regexp.MustCompile(`\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]`)
|
||||
re := regexp.MustCompile(`\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mK]`)
|
||||
return re.ReplaceAllString(str, "")
|
||||
}
|
||||
|
||||
func getPadWidths(stringArrays [][]string) []int {
|
||||
if len(stringArrays[0]) <= 1 {
|
||||
func getPadWidths(rows [][]string) []int {
|
||||
if len(rows[0]) <= 1 {
|
||||
return []int{}
|
||||
}
|
||||
padWidths := make([]int, len(stringArrays[0])-1)
|
||||
for i := range padWidths {
|
||||
for _, strings := range stringArrays {
|
||||
uncoloredString := Decolorise(strings[i])
|
||||
if len(uncoloredString) > padWidths[i] {
|
||||
padWidths[i] = len(uncoloredString)
|
||||
columnPadWidths := make([]int, len(rows[0])-1)
|
||||
for i := range columnPadWidths {
|
||||
for _, cells := range rows {
|
||||
uncoloredCell := Decolorise(cells[i])
|
||||
|
||||
if runewidth.StringWidth(uncoloredCell) > columnPadWidths[i] {
|
||||
columnPadWidths[i] = runewidth.StringWidth(uncoloredCell)
|
||||
}
|
||||
}
|
||||
}
|
||||
return padWidths
|
||||
return columnPadWidths
|
||||
}
|
||||
|
||||
func getPaddedDisplayStrings(stringArrays [][]string, padWidths []int) []string {
|
||||
paddedDisplayStrings := make([]string, len(stringArrays))
|
||||
for i, stringArray := range stringArrays {
|
||||
if len(stringArray) == 0 {
|
||||
continue
|
||||
func getPaddedDisplayStrings(rows [][]string, columnPadWidths []int) []string {
|
||||
paddedDisplayRows := make([]string, len(rows))
|
||||
for i, cells := range rows {
|
||||
for j, columnPadWidth := range columnPadWidths {
|
||||
paddedDisplayRows[i] += WithPadding(cells[j], columnPadWidth) + " "
|
||||
}
|
||||
for j, padWidth := range padWidths {
|
||||
paddedDisplayStrings[i] += WithPadding(stringArray[j], padWidth) + " "
|
||||
}
|
||||
paddedDisplayStrings[i] += stringArray[len(padWidths)]
|
||||
paddedDisplayRows[i] += cells[len(columnPadWidths)]
|
||||
}
|
||||
return paddedDisplayStrings
|
||||
return paddedDisplayRows
|
||||
}
|
||||
|
||||
// displayArraysAligned returns true if every string array returned from our
|
||||
|
|
@ -339,3 +383,30 @@ func IsValidHexValue(v string) bool {
|
|||
func OpensMenuStyle(str string) string {
|
||||
return ColoredString(fmt.Sprintf("%s...", str), color.FgMagenta)
|
||||
}
|
||||
|
||||
// MarshalIntoYaml gets any json-tagged data and marshal it into yaml saving original json structure.
|
||||
// Useful for structs from 3rd-party libs without yaml tags.
|
||||
func MarshalIntoYaml(data interface{}) ([]byte, error) {
|
||||
return marshalIntoFormat(data, "yaml")
|
||||
}
|
||||
|
||||
func marshalIntoFormat(data interface{}, format string) ([]byte, error) {
|
||||
// First marshal struct->json to get the resulting structure declared by json tags
|
||||
dataJSON, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch format {
|
||||
case "json":
|
||||
return dataJSON, err
|
||||
case "yaml":
|
||||
// Use Unmarshal->Marshal hack to convert json into yaml with the original structure preserved
|
||||
var dataMirror yaml.MapSlice
|
||||
if err := yaml.Unmarshal(dataJSON, &dataMirror); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return yaml.Marshal(dataMirror)
|
||||
default:
|
||||
return nil, errors.New(fmt.Sprintf("Unsupported detailization format: %s", format))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,3 +257,65 @@ func TestRenderTable(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalIntoFormat(t *testing.T) {
|
||||
type innerData struct {
|
||||
Foo int `json:"foo"`
|
||||
Bar string `json:"bar"`
|
||||
Baz bool `json:"baz"`
|
||||
}
|
||||
type data struct {
|
||||
Qux int `json:"quz"`
|
||||
Quux innerData `json:"quux"`
|
||||
}
|
||||
|
||||
type scenario struct {
|
||||
input interface{}
|
||||
format string
|
||||
expected []byte
|
||||
expectedErr error
|
||||
}
|
||||
|
||||
scenarios := []scenario{
|
||||
{
|
||||
input: data{1, innerData{2, "foo", true}},
|
||||
format: "json",
|
||||
expected: []byte(`{
|
||||
"quz": 1,
|
||||
"quux": {
|
||||
"foo": 2,
|
||||
"bar": "foo",
|
||||
"baz": true
|
||||
}
|
||||
}`),
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
input: data{1, innerData{2, "foo", true}},
|
||||
format: "yaml",
|
||||
expected: []byte(`quz: 1
|
||||
quux:
|
||||
bar: foo
|
||||
baz: true
|
||||
foo: 2
|
||||
`),
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
input: data{1, innerData{2, "foo", true}},
|
||||
format: "xml",
|
||||
expected: nil,
|
||||
expectedErr: errors.New("Unsupported detailization format: xml"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range scenarios {
|
||||
output, err := marshalIntoFormat(s.input, s.format)
|
||||
assert.EqualValues(t, s.expected, output)
|
||||
if s.expectedErr != nil {
|
||||
assert.EqualError(t, err, s.expectedErr.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4
vendor/github.com/docker/distribution/reference/reference.go
generated
vendored
4
vendor/github.com/docker/distribution/reference/reference.go
generated
vendored
|
|
@ -3,13 +3,13 @@
|
|||
//
|
||||
// Grammar
|
||||
//
|
||||
// reference := name [ ":" tag ] [ "@" digest ]
|
||||
// reference := name [ ":" tag ] [ "@" digest ]
|
||||
// name := [domain '/'] path-component ['/' path-component]*
|
||||
// domain := domain-component ['.' domain-component]* [':' port-number]
|
||||
// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
|
||||
// port-number := /[0-9]+/
|
||||
// path-component := alpha-numeric [separator alpha-numeric]*
|
||||
// alpha-numeric := /[a-z0-9]+/
|
||||
// alpha-numeric := /[a-z0-9]+/
|
||||
// separator := /[_.]|__|[-]*/
|
||||
//
|
||||
// tag := /[\w][\w.-]{0,127}/
|
||||
|
|
|
|||
5
vendor/github.com/fatih/color/.travis.yml
generated
vendored
5
vendor/github.com/fatih/color/.travis.yml
generated
vendored
|
|
@ -1,5 +0,0 @@
|
|||
language: go
|
||||
go:
|
||||
- 1.8.x
|
||||
- tip
|
||||
|
||||
27
vendor/github.com/fatih/color/Gopkg.lock
generated
vendored
27
vendor/github.com/fatih/color/Gopkg.lock
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "e8a50671c3cb93ea935bf210b1cd20702876b9d9226129be581ef646d1565cdc"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
30
vendor/github.com/fatih/color/Gopkg.toml
generated
vendored
30
vendor/github.com/fatih/color/Gopkg.toml
generated
vendored
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mattn/go-colorable"
|
||||
version = "0.0.9"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
version = "0.0.3"
|
||||
10
vendor/github.com/fatih/color/README.md
generated
vendored
10
vendor/github.com/fatih/color/README.md
generated
vendored
|
|
@ -1,14 +1,11 @@
|
|||
# Color [](https://godoc.org/github.com/fatih/color) [](https://travis-ci.org/fatih/color)
|
||||
|
||||
|
||||
# color [](https://github.com/fatih/color/actions) [](https://pkg.go.dev/github.com/fatih/color)
|
||||
|
||||
Color lets you use colorized outputs in terms of [ANSI Escape
|
||||
Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It
|
||||
has support for Windows too! The API can be used in several ways, pick one that
|
||||
suits you.
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## Install
|
||||
|
|
@ -17,9 +14,6 @@ suits you.
|
|||
go get github.com/fatih/color
|
||||
```
|
||||
|
||||
Note that the `vendor` folder is here for stability. Remove the folder if you
|
||||
already have the dependencies in your GOPATH.
|
||||
|
||||
## Examples
|
||||
|
||||
### Standard colors
|
||||
|
|
|
|||
31
vendor/github.com/goccy/go-yaml/.codecov.yml
generated
vendored
Normal file
31
vendor/github.com/goccy/go-yaml/.codecov.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
codecov:
|
||||
require_ci_to_pass: yes
|
||||
|
||||
coverage:
|
||||
precision: 2
|
||||
round: down
|
||||
range: "70...100"
|
||||
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: 75%
|
||||
threshold: 2%
|
||||
patch: off
|
||||
changes: no
|
||||
|
||||
parsers:
|
||||
gcov:
|
||||
branch_detection:
|
||||
conditional: yes
|
||||
loop: yes
|
||||
method: no
|
||||
macro: no
|
||||
|
||||
comment:
|
||||
layout: "header,diff"
|
||||
behavior: default
|
||||
require_changes: no
|
||||
|
||||
ignore:
|
||||
- ast
|
||||
163
vendor/github.com/goccy/go-yaml/CHANGELOG.md
generated
vendored
Normal file
163
vendor/github.com/goccy/go-yaml/CHANGELOG.md
generated
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
# 1.10.1 - 2023-03-28
|
||||
|
||||
### Features
|
||||
|
||||
- Quote YAML 1.1 bools at encoding time for compatibility with other legacy parsers
|
||||
- Add support of 32-bit architecture
|
||||
|
||||
### Fix bugs
|
||||
|
||||
- Don't trim all space characters in block style sequence
|
||||
- Support strings starting with `@`
|
||||
|
||||
# 1.10.0 - 2023-03-01
|
||||
|
||||
### Fix bugs
|
||||
|
||||
Reversible conversion of comments was not working in various cases, which has been corrected.
|
||||
**Breaking Change** exists in the comment map interface. However, if you are dealing with CommentMap directly, there is no problem.
|
||||
|
||||
|
||||
# 1.9.8 - 2022-12-19
|
||||
|
||||
### Fix feature
|
||||
|
||||
- Append new line at the end of file ( #329 )
|
||||
|
||||
### Fix bugs
|
||||
|
||||
- Fix custom marshaler ( #333, #334 )
|
||||
- Fix behavior when struct fields conflicted( #335 )
|
||||
- Fix position calculation for literal, folded and raw folded strings ( #330 )
|
||||
|
||||
# 1.9.7 - 2022-12-03
|
||||
|
||||
### Fix bugs
|
||||
|
||||
- Fix handling of quoted map key ( #328 )
|
||||
- Fix resusing process of scanning context ( #322 )
|
||||
|
||||
## v1.9.6 - 2022-10-26
|
||||
|
||||
### New Features
|
||||
|
||||
- Introduce MapKeyNode interface to limit node types for map key ( #312 )
|
||||
|
||||
### Fix bugs
|
||||
|
||||
- Quote strings with special characters in flow mode ( #270 )
|
||||
- typeError implements PrettyPrinter interface ( #280 )
|
||||
- Fix incorrect const type ( #284 )
|
||||
- Fix large literals type inference on 32 bits ( #293 )
|
||||
- Fix UTF-8 characters ( #294 )
|
||||
- Fix decoding of unknown aliases ( #317 )
|
||||
- Fix stream encoder for insert a separator between each encoded document ( #318 )
|
||||
|
||||
### Update
|
||||
|
||||
- Update golang.org/x/sys ( #289 )
|
||||
- Update Go version in CI ( #295 )
|
||||
- Add test cases for missing keys to struct literals ( #300 )
|
||||
|
||||
## v1.9.5 - 2022-01-12
|
||||
|
||||
### New Features
|
||||
|
||||
* Add UseSingleQuote option ( #265 )
|
||||
|
||||
### Fix bugs
|
||||
|
||||
* Preserve defaults while decoding nested structs ( #260 )
|
||||
* Fix minor typo in decodeInit error ( #264 )
|
||||
* Handle empty sequence entries ( #275 )
|
||||
* Fix encoding of sequence with multiline string ( #276 )
|
||||
* Fix encoding of BytesMarshaler type ( #277 )
|
||||
* Fix indentState logic for multi-line value ( #278 )
|
||||
|
||||
## v1.9.4 - 2021-10-12
|
||||
|
||||
### Fix bugs
|
||||
|
||||
* Keep prev/next reference between tokens containing comments when filtering comment tokens ( #257 )
|
||||
* Supports escaping reserved keywords in PathBuilder ( #258 )
|
||||
|
||||
## v1.9.3 - 2021-09-07
|
||||
|
||||
### New Features
|
||||
|
||||
* Support encoding and decoding `time.Duration` fields ( #246 )
|
||||
* Allow reserved characters for key name in YAMLPath ( #251 )
|
||||
* Support getting YAMLPath from ast.Node ( #252 )
|
||||
* Support CommentToMap option ( #253 )
|
||||
|
||||
### Fix bugs
|
||||
|
||||
* Fix encoding nested sequences with `yaml.IndentSequence` ( #241 )
|
||||
* Fix error reporting on inline structs in strict mode ( #244, #245 )
|
||||
* Fix encoding of large floats ( #247 )
|
||||
|
||||
### Improve workflow
|
||||
|
||||
* Migrate CI from CircleCI to GitHub Action ( #249 )
|
||||
* Add workflow for ycat ( #250 )
|
||||
|
||||
## v1.9.2 - 2021-07-26
|
||||
|
||||
### Support WithComment option ( #238 )
|
||||
|
||||
`yaml.WithComment` is a option for encoding with comment.
|
||||
The position where you want to add a comment is represented by YAMLPath, and it is the key of `yaml.CommentMap`.
|
||||
Also, you can select `Head` comment or `Line` comment as the comment type.
|
||||
|
||||
## v1.9.1 - 2021-07-20
|
||||
|
||||
### Fix DecodeFromNode ( #237 )
|
||||
|
||||
- Fix YAML handling where anchor exists
|
||||
|
||||
## v1.9.0 - 2021-07-19
|
||||
|
||||
### New features
|
||||
|
||||
- Support encoding of comment node ( #233 )
|
||||
- Support `yaml.NodeToValue(ast.Node, interface{}, ...DecodeOption) error` ( #236 )
|
||||
- Can convert a AST node to a value directly
|
||||
|
||||
### Fix decoder for comment
|
||||
|
||||
- Fix parsing of literal with comment ( #234 )
|
||||
|
||||
### Rename API ( #235 )
|
||||
|
||||
- Rename `MarshalWithContext` to `MarshalContext`
|
||||
- Rename `UnmarshalWithContext` to `UnmarshalContext`
|
||||
|
||||
## v1.8.10 - 2021-07-02
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
- Fix searching anchor by alias name ( #212 )
|
||||
- Fixing Issue 186, scanner should account for newline characters when processing multi-line text. Without this source annotations line/column number (for this and all subsequent tokens) is inconsistent with plain text editors. e.g. https://github.com/goccy/go-yaml/issues/186. This addresses the issue specifically for single and double quote text only. ( #210 )
|
||||
- Add error for unterminated flow mapping node ( #213 )
|
||||
- Handle missing required field validation ( #221 )
|
||||
- Nicely format unexpected node type errors ( #229 )
|
||||
- Support to encode map which has defined type key ( #231 )
|
||||
|
||||
### New features
|
||||
|
||||
- Support sequence indentation by EncodeOption ( #232 )
|
||||
|
||||
## v1.8.9 - 2021-03-01
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
- Fix origin buffer for DocumentHeader and DocumentEnd and Directive
|
||||
- Fix origin buffer for anchor value
|
||||
- Fix syntax error about map value
|
||||
- Fix parsing MergeKey ('<<') characters
|
||||
- Fix encoding of float value
|
||||
- Fix incorrect column annotation when single or double quotes are used
|
||||
|
||||
### New features
|
||||
|
||||
- Support to encode/decode of ast.Node directly
|
||||
21
vendor/github.com/goccy/go-yaml/LICENSE
generated
vendored
Normal file
21
vendor/github.com/goccy/go-yaml/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Masaaki Goshima
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
19
vendor/github.com/goccy/go-yaml/Makefile
generated
vendored
Normal file
19
vendor/github.com/goccy/go-yaml/Makefile
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
.PHONY: test
|
||||
test:
|
||||
go test -v -race ./...
|
||||
|
||||
.PHONY: simple-test
|
||||
simple-test:
|
||||
go test -v ./...
|
||||
|
||||
.PHONY: cover
|
||||
cover:
|
||||
go test -coverprofile=cover.out ./...
|
||||
|
||||
.PHONY: cover-html
|
||||
cover-html: cover
|
||||
go tool cover -html=cover.out
|
||||
|
||||
.PHONY: ycat/build
|
||||
ycat/build:
|
||||
go build -o ycat ./cmd/ycat
|
||||
370
vendor/github.com/goccy/go-yaml/README.md
generated
vendored
Normal file
370
vendor/github.com/goccy/go-yaml/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
# YAML support for the Go language
|
||||
|
||||
[](https://pkg.go.dev/github.com/goccy/go-yaml)
|
||||

|
||||
[](https://codecov.io/gh/goccy/go-yaml)
|
||||
[](https://goreportcard.com/report/github.com/goccy/go-yaml)
|
||||
|
||||
<img width="300px" src="https://user-images.githubusercontent.com/209884/67159116-64d94b80-f37b-11e9-9b28-f8379636a43c.png"></img>
|
||||
|
||||
# Why a new library?
|
||||
|
||||
As of this writing, there already exists a de facto standard library for YAML processing for Go: [https://github.com/go-yaml/yaml](https://github.com/go-yaml/yaml). However we feel that some features are lacking, namely:
|
||||
|
||||
- Pretty format for error notifications
|
||||
- Direct manipulation of YAML abstract syntax tree
|
||||
- Support for `Anchor` and `Alias` when marshaling
|
||||
- Allow referencing elements declared in another file via anchors
|
||||
|
||||
# Features
|
||||
|
||||
- Pretty format for error notifications
|
||||
- Supports `Scanner` or `Lexer` or `Parser` as public API
|
||||
- Supports `Anchor` and `Alias` to Marshaler
|
||||
- Allow referencing elements declared in another file via anchors
|
||||
- Extract value or AST by YAMLPath ( YAMLPath is like a JSONPath )
|
||||
|
||||
# Installation
|
||||
|
||||
```sh
|
||||
go get -u github.com/goccy/go-yaml
|
||||
```
|
||||
|
||||
# Synopsis
|
||||
|
||||
## 1. Simple Encode/Decode
|
||||
|
||||
Has an interface like `go-yaml/yaml` using `reflect`
|
||||
|
||||
```go
|
||||
var v struct {
|
||||
A int
|
||||
B string
|
||||
}
|
||||
v.A = 1
|
||||
v.B = "hello"
|
||||
bytes, err := yaml.Marshal(v)
|
||||
if err != nil {
|
||||
//...
|
||||
}
|
||||
fmt.Println(string(bytes)) // "a: 1\nb: hello\n"
|
||||
```
|
||||
|
||||
```go
|
||||
yml := `
|
||||
%YAML 1.2
|
||||
---
|
||||
a: 1
|
||||
b: c
|
||||
`
|
||||
var v struct {
|
||||
A int
|
||||
B string
|
||||
}
|
||||
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
|
||||
//...
|
||||
}
|
||||
```
|
||||
|
||||
To control marshal/unmarshal behavior, you can use the `yaml` tag.
|
||||
|
||||
```go
|
||||
yml := `---
|
||||
foo: 1
|
||||
bar: c
|
||||
`
|
||||
var v struct {
|
||||
A int `yaml:"foo"`
|
||||
B string `yaml:"bar"`
|
||||
}
|
||||
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
|
||||
//...
|
||||
}
|
||||
```
|
||||
|
||||
For convenience, we also accept the `json` tag. Note that not all options from
|
||||
the `json` tag will have significance when parsing YAML documents. If both
|
||||
tags exist, `yaml` tag will take precedence.
|
||||
|
||||
```go
|
||||
yml := `---
|
||||
foo: 1
|
||||
bar: c
|
||||
`
|
||||
var v struct {
|
||||
A int `json:"foo"`
|
||||
B string `json:"bar"`
|
||||
}
|
||||
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
|
||||
//...
|
||||
}
|
||||
```
|
||||
|
||||
For custom marshal/unmarshaling, implement either `Bytes` or `Interface` variant of marshaler/unmarshaler. The difference is that while `BytesMarshaler`/`BytesUnmarshaler` behaves like [`encoding/json`](https://pkg.go.dev/encoding/json) and `InterfaceMarshaler`/`InterfaceUnmarshaler` behaves like [`gopkg.in/yaml.v2`](https://pkg.go.dev/gopkg.in/yaml.v2).
|
||||
|
||||
Semantically both are the same, but they differ in performance. Because indentation matters in YAML, you cannot simply accept a valid YAML fragment from a Marshaler, and expect it to work when it is attached to the parent container's serialized form. Therefore when we receive use the `BytesMarshaler`, which returns `[]byte`, we must decode it once to figure out how to make it work in the given context. If you use the `InterfaceMarshaler`, we can skip the decoding.
|
||||
|
||||
If you are repeatedly marshaling complex objects, the latter is always better
|
||||
performance wise. But if you are, for example, just providing a choice between
|
||||
a config file format that is read only once, the former is probably easier to
|
||||
code.
|
||||
|
||||
## 2. Reference elements declared in another file
|
||||
|
||||
`testdata` directory contains `anchor.yml` file:
|
||||
|
||||
```shell
|
||||
├── testdata
|
||||
└── anchor.yml
|
||||
```
|
||||
|
||||
And `anchor.yml` is defined as follows:
|
||||
|
||||
```yaml
|
||||
a: &a
|
||||
b: 1
|
||||
c: hello
|
||||
```
|
||||
|
||||
Then, if `yaml.ReferenceDirs("testdata")` option is passed to `yaml.Decoder`,
|
||||
`Decoder` tries to find the anchor definition from YAML files the under `testdata` directory.
|
||||
|
||||
```go
|
||||
buf := bytes.NewBufferString("a: *a\n")
|
||||
dec := yaml.NewDecoder(buf, yaml.ReferenceDirs("testdata"))
|
||||
var v struct {
|
||||
A struct {
|
||||
B int
|
||||
C string
|
||||
}
|
||||
}
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
//...
|
||||
}
|
||||
fmt.Printf("%+v\n", v) // {A:{B:1 C:hello}}
|
||||
```
|
||||
|
||||
## 3. Encode with `Anchor` and `Alias`
|
||||
|
||||
### 3.1. Explicitly declared `Anchor` name and `Alias` name
|
||||
|
||||
If you want to use `anchor` or `alias`, you can define it as a struct tag.
|
||||
|
||||
```go
|
||||
type T struct {
|
||||
A int
|
||||
B string
|
||||
}
|
||||
var v struct {
|
||||
C *T `yaml:"c,anchor=x"`
|
||||
D *T `yaml:"d,alias=x"`
|
||||
}
|
||||
v.C = &T{A: 1, B: "hello"}
|
||||
v.D = v.C
|
||||
bytes, err := yaml.Marshal(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(bytes))
|
||||
/*
|
||||
c: &x
|
||||
a: 1
|
||||
b: hello
|
||||
d: *x
|
||||
*/
|
||||
```
|
||||
|
||||
### 3.2. Implicitly declared `Anchor` and `Alias` names
|
||||
|
||||
If you do not explicitly declare the anchor name, the default behavior is to
|
||||
use the equivalent of `strings.ToLower($FieldName)` as the name of the anchor.
|
||||
|
||||
If you do not explicitly declare the alias name AND the value is a pointer
|
||||
to another element, we look up the anchor name by finding out which anchor
|
||||
field the value is assigned to by looking up its pointer address.
|
||||
|
||||
```go
|
||||
type T struct {
|
||||
I int
|
||||
S string
|
||||
}
|
||||
var v struct {
|
||||
A *T `yaml:"a,anchor"`
|
||||
B *T `yaml:"b,anchor"`
|
||||
C *T `yaml:"c,alias"`
|
||||
D *T `yaml:"d,alias"`
|
||||
}
|
||||
v.A = &T{I: 1, S: "hello"}
|
||||
v.B = &T{I: 2, S: "world"}
|
||||
v.C = v.A // C has same pointer address to A
|
||||
v.D = v.B // D has same pointer address to B
|
||||
bytes, err := yaml.Marshal(v)
|
||||
if err != nil {
|
||||
//...
|
||||
}
|
||||
fmt.Println(string(bytes))
|
||||
/*
|
||||
a: &a
|
||||
i: 1
|
||||
s: hello
|
||||
b: &b
|
||||
i: 2
|
||||
s: world
|
||||
c: *a
|
||||
d: *b
|
||||
*/
|
||||
```
|
||||
|
||||
### 3.3 MergeKey and Alias
|
||||
|
||||
Merge key and alias ( `<<: *alias` ) can be used by embedding a structure with the `inline,alias` tag.
|
||||
|
||||
```go
|
||||
type Person struct {
|
||||
*Person `yaml:",omitempty,inline,alias"` // embed Person type for default value
|
||||
Name string `yaml:",omitempty"`
|
||||
Age int `yaml:",omitempty"`
|
||||
}
|
||||
defaultPerson := &Person{
|
||||
Name: "John Smith",
|
||||
Age: 20,
|
||||
}
|
||||
people := []*Person{
|
||||
{
|
||||
Person: defaultPerson, // assign default value
|
||||
Name: "Ken", // override Name property
|
||||
Age: 10, // override Age property
|
||||
},
|
||||
{
|
||||
Person: defaultPerson, // assign default value only
|
||||
},
|
||||
}
|
||||
var doc struct {
|
||||
Default *Person `yaml:"default,anchor"`
|
||||
People []*Person `yaml:"people"`
|
||||
}
|
||||
doc.Default = defaultPerson
|
||||
doc.People = people
|
||||
bytes, err := yaml.Marshal(doc)
|
||||
if err != nil {
|
||||
//...
|
||||
}
|
||||
fmt.Println(string(bytes))
|
||||
/*
|
||||
default: &default
|
||||
name: John Smith
|
||||
age: 20
|
||||
people:
|
||||
- <<: *default
|
||||
name: Ken
|
||||
age: 10
|
||||
- <<: *default
|
||||
*/
|
||||
```
|
||||
|
||||
## 4. Pretty Formatted Errors
|
||||
|
||||
Error values produced during parsing have two extra features over regular
|
||||
error values.
|
||||
|
||||
First, by default, they contain extra information on the location of the error
|
||||
from the source YAML document, to make it easier to find the error location.
|
||||
|
||||
Second, the error messages can optionally be colorized.
|
||||
|
||||
If you would like to control exactly how the output looks like, consider
|
||||
using `yaml.FormatError`, which accepts two boolean values to
|
||||
control turning these features on or off.
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/209884/67358124-587f0980-f59a-11e9-96fc-7205aab77695.png"></img>
|
||||
|
||||
## 5. Use YAMLPath
|
||||
|
||||
```go
|
||||
yml := `
|
||||
store:
|
||||
book:
|
||||
- author: john
|
||||
price: 10
|
||||
- author: ken
|
||||
price: 12
|
||||
bicycle:
|
||||
color: red
|
||||
price: 19.95
|
||||
`
|
||||
path, err := yaml.PathString("$.store.book[*].author")
|
||||
if err != nil {
|
||||
//...
|
||||
}
|
||||
var authors []string
|
||||
if err := path.Read(strings.NewReader(yml), &authors); err != nil {
|
||||
//...
|
||||
}
|
||||
fmt.Println(authors)
|
||||
// [john ken]
|
||||
```
|
||||
|
||||
### 5.1 Print customized error with YAML source code
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/goccy/go-yaml"
|
||||
)
|
||||
|
||||
func main() {
|
||||
yml := `
|
||||
a: 1
|
||||
b: "hello"
|
||||
`
|
||||
var v struct {
|
||||
A int
|
||||
B string
|
||||
}
|
||||
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if v.A != 2 {
|
||||
// output error with YAML source
|
||||
path, err := yaml.PathString("$.a")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
source, err := path.AnnotateSource([]byte(yml), true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("a value expected 2 but actual %d:\n%s\n", v.A, string(source))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
output result is the following:
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/209884/84148813-7aca8680-aa9a-11ea-8fc9-37dece2ebdac.png"></img>
|
||||
|
||||
|
||||
# Tools
|
||||
|
||||
## ycat
|
||||
|
||||
print yaml file with color
|
||||
|
||||
<img width="713" alt="ycat" src="https://user-images.githubusercontent.com/209884/66986084-19b00600-f0f9-11e9-9f0e-1f91eb072fe0.png">
|
||||
|
||||
### Installation
|
||||
|
||||
```sh
|
||||
go install github.com/goccy/go-yaml/cmd/ycat@latest
|
||||
```
|
||||
|
||||
# Looking for Sponsors
|
||||
|
||||
I'm looking for sponsors this library. This library is being developed as a personal project in my spare time. If you want a quick response or problem resolution when using this library in your project, please register as a [sponsor](https://github.com/sponsors/goccy). I will cooperate as much as possible. Of course, this library is developed as an MIT license, so you can use it freely for free.
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
2117
vendor/github.com/goccy/go-yaml/ast/ast.go
generated
vendored
Normal file
2117
vendor/github.com/goccy/go-yaml/ast/ast.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1753
vendor/github.com/goccy/go-yaml/decode.go
generated
vendored
Normal file
1753
vendor/github.com/goccy/go-yaml/decode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
871
vendor/github.com/goccy/go-yaml/encode.go
generated
vendored
Normal file
871
vendor/github.com/goccy/go-yaml/encode.go
generated
vendored
Normal file
|
|
@ -0,0 +1,871 @@
|
|||
package yaml
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/goccy/go-yaml/ast"
|
||||
"github.com/goccy/go-yaml/internal/errors"
|
||||
"github.com/goccy/go-yaml/parser"
|
||||
"github.com/goccy/go-yaml/printer"
|
||||
"github.com/goccy/go-yaml/token"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultIndentSpaces default number of space for indent
|
||||
DefaultIndentSpaces = 2
|
||||
)
|
||||
|
||||
// Encoder writes YAML values to an output stream.
|
||||
type Encoder struct {
|
||||
writer io.Writer
|
||||
opts []EncodeOption
|
||||
indent int
|
||||
indentSequence bool
|
||||
singleQuote bool
|
||||
isFlowStyle bool
|
||||
isJSONStyle bool
|
||||
useJSONMarshaler bool
|
||||
anchorCallback func(*ast.AnchorNode, interface{}) error
|
||||
anchorPtrToNameMap map[uintptr]string
|
||||
customMarshalerMap map[reflect.Type]func(interface{}) ([]byte, error)
|
||||
useLiteralStyleIfMultiline bool
|
||||
commentMap map[*Path][]*Comment
|
||||
written bool
|
||||
|
||||
line int
|
||||
column int
|
||||
offset int
|
||||
indentNum int
|
||||
indentLevel int
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder that writes to w.
|
||||
// The Encoder should be closed after use to flush all data to w.
|
||||
func NewEncoder(w io.Writer, opts ...EncodeOption) *Encoder {
|
||||
return &Encoder{
|
||||
writer: w,
|
||||
opts: opts,
|
||||
indent: DefaultIndentSpaces,
|
||||
anchorPtrToNameMap: map[uintptr]string{},
|
||||
customMarshalerMap: map[reflect.Type]func(interface{}) ([]byte, error){},
|
||||
line: 1,
|
||||
column: 1,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Close closes the encoder by writing any remaining data.
|
||||
// It does not write a stream terminating string "...".
|
||||
func (e *Encoder) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encode writes the YAML encoding of v to the stream.
|
||||
// If multiple items are encoded to the stream,
|
||||
// the second and subsequent document will be preceded with a "---" document separator,
|
||||
// but the first will not.
|
||||
//
|
||||
// See the documentation for Marshal for details about the conversion of Go values to YAML.
|
||||
func (e *Encoder) Encode(v interface{}) error {
|
||||
return e.EncodeContext(context.Background(), v)
|
||||
}
|
||||
|
||||
// EncodeContext writes the YAML encoding of v to the stream with context.Context.
|
||||
func (e *Encoder) EncodeContext(ctx context.Context, v interface{}) error {
|
||||
node, err := e.EncodeToNodeContext(ctx, v)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to encode to node")
|
||||
}
|
||||
if err := e.setCommentByCommentMap(node); err != nil {
|
||||
return errors.Wrapf(err, "failed to set comment by comment map")
|
||||
}
|
||||
if !e.written {
|
||||
e.written = true
|
||||
} else {
|
||||
// write document separator
|
||||
e.writer.Write([]byte("---\n"))
|
||||
}
|
||||
var p printer.Printer
|
||||
e.writer.Write(p.PrintNode(node))
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeToNode convert v to ast.Node.
|
||||
func (e *Encoder) EncodeToNode(v interface{}) (ast.Node, error) {
|
||||
return e.EncodeToNodeContext(context.Background(), v)
|
||||
}
|
||||
|
||||
// EncodeToNodeContext convert v to ast.Node with context.Context.
|
||||
func (e *Encoder) EncodeToNodeContext(ctx context.Context, v interface{}) (ast.Node, error) {
|
||||
for _, opt := range e.opts {
|
||||
if err := opt(e); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to run option for encoder")
|
||||
}
|
||||
}
|
||||
node, err := e.encodeValue(ctx, reflect.ValueOf(v), 1)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode value")
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) setCommentByCommentMap(node ast.Node) error {
|
||||
if e.commentMap == nil {
|
||||
return nil
|
||||
}
|
||||
for path, comments := range e.commentMap {
|
||||
n, err := path.FilterNode(node)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to filter node")
|
||||
}
|
||||
if n == nil {
|
||||
continue
|
||||
}
|
||||
for _, comment := range comments {
|
||||
commentTokens := []*token.Token{}
|
||||
for _, text := range comment.Texts {
|
||||
commentTokens = append(commentTokens, token.New(text, text, nil))
|
||||
}
|
||||
commentGroup := ast.CommentGroup(commentTokens)
|
||||
switch comment.Position {
|
||||
case CommentHeadPosition:
|
||||
if err := e.setHeadComment(node, n, commentGroup); err != nil {
|
||||
return errors.Wrapf(err, "failed to set head comment")
|
||||
}
|
||||
case CommentLinePosition:
|
||||
if err := e.setLineComment(node, n, commentGroup); err != nil {
|
||||
return errors.Wrapf(err, "failed to set line comment")
|
||||
}
|
||||
case CommentFootPosition:
|
||||
if err := e.setFootComment(node, n, commentGroup); err != nil {
|
||||
return errors.Wrapf(err, "failed to set foot comment")
|
||||
}
|
||||
default:
|
||||
return ErrUnknownCommentPositionType
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) setHeadComment(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
|
||||
parent := ast.Parent(node, filtered)
|
||||
if parent == nil {
|
||||
return ErrUnsupportedHeadPositionType(node)
|
||||
}
|
||||
switch p := parent.(type) {
|
||||
case *ast.MappingValueNode:
|
||||
if err := p.SetComment(comment); err != nil {
|
||||
return errors.Wrapf(err, "failed to set comment")
|
||||
}
|
||||
case *ast.MappingNode:
|
||||
if err := p.SetComment(comment); err != nil {
|
||||
return errors.Wrapf(err, "failed to set comment")
|
||||
}
|
||||
case *ast.SequenceNode:
|
||||
if len(p.ValueHeadComments) == 0 {
|
||||
p.ValueHeadComments = make([]*ast.CommentGroupNode, len(p.Values))
|
||||
}
|
||||
var foundIdx int
|
||||
for idx, v := range p.Values {
|
||||
if v == filtered {
|
||||
foundIdx = idx
|
||||
break
|
||||
}
|
||||
}
|
||||
p.ValueHeadComments[foundIdx] = comment
|
||||
default:
|
||||
return ErrUnsupportedHeadPositionType(node)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) setLineComment(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
|
||||
switch filtered.(type) {
|
||||
case *ast.MappingValueNode, *ast.SequenceNode:
|
||||
// Line comment cannot be set for mapping value node.
|
||||
// It should probably be set for the parent map node
|
||||
if err := e.setLineCommentToParentMapNode(node, filtered, comment); err != nil {
|
||||
return errors.Wrapf(err, "failed to set line comment to parent node")
|
||||
}
|
||||
default:
|
||||
if err := filtered.SetComment(comment); err != nil {
|
||||
return errors.Wrapf(err, "failed to set comment")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) setLineCommentToParentMapNode(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
|
||||
parent := ast.Parent(node, filtered)
|
||||
if parent == nil {
|
||||
return ErrUnsupportedLinePositionType(node)
|
||||
}
|
||||
switch p := parent.(type) {
|
||||
case *ast.MappingValueNode:
|
||||
if err := p.Key.SetComment(comment); err != nil {
|
||||
return errors.Wrapf(err, "failed to set comment")
|
||||
}
|
||||
case *ast.MappingNode:
|
||||
if err := p.SetComment(comment); err != nil {
|
||||
return errors.Wrapf(err, "failed to set comment")
|
||||
}
|
||||
default:
|
||||
return ErrUnsupportedLinePositionType(parent)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) setFootComment(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
|
||||
parent := ast.Parent(node, filtered)
|
||||
if parent == nil {
|
||||
return ErrUnsupportedFootPositionType(node)
|
||||
}
|
||||
switch n := parent.(type) {
|
||||
case *ast.MappingValueNode:
|
||||
n.FootComment = comment
|
||||
case *ast.MappingNode:
|
||||
n.FootComment = comment
|
||||
case *ast.SequenceNode:
|
||||
n.FootComment = comment
|
||||
default:
|
||||
return ErrUnsupportedFootPositionType(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeDocument(doc []byte) (ast.Node, error) {
|
||||
f, err := parser.ParseBytes(doc, 0)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse yaml")
|
||||
}
|
||||
for _, docNode := range f.Docs {
|
||||
if docNode.Body != nil {
|
||||
return docNode.Body, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) isInvalidValue(v reflect.Value) bool {
|
||||
if !v.IsValid() {
|
||||
return true
|
||||
}
|
||||
kind := v.Type().Kind()
|
||||
if kind == reflect.Ptr && v.IsNil() {
|
||||
return true
|
||||
}
|
||||
if kind == reflect.Interface && v.IsNil() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type jsonMarshaler interface {
|
||||
MarshalJSON() ([]byte, error)
|
||||
}
|
||||
|
||||
func (e *Encoder) existsTypeInCustomMarshalerMap(t reflect.Type) bool {
|
||||
if _, exists := e.customMarshalerMap[t]; exists {
|
||||
return true
|
||||
}
|
||||
|
||||
globalCustomMarshalerMu.Lock()
|
||||
defer globalCustomMarshalerMu.Unlock()
|
||||
if _, exists := globalCustomMarshalerMap[t]; exists {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *Encoder) marshalerFromCustomMarshalerMap(t reflect.Type) (func(interface{}) ([]byte, error), bool) {
|
||||
if marshaler, exists := e.customMarshalerMap[t]; exists {
|
||||
return marshaler, exists
|
||||
}
|
||||
|
||||
globalCustomMarshalerMu.Lock()
|
||||
defer globalCustomMarshalerMu.Unlock()
|
||||
if marshaler, exists := globalCustomMarshalerMap[t]; exists {
|
||||
return marshaler, exists
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (e *Encoder) canEncodeByMarshaler(v reflect.Value) bool {
|
||||
if !v.CanInterface() {
|
||||
return false
|
||||
}
|
||||
if e.existsTypeInCustomMarshalerMap(v.Type()) {
|
||||
return true
|
||||
}
|
||||
iface := v.Interface()
|
||||
switch iface.(type) {
|
||||
case BytesMarshalerContext:
|
||||
return true
|
||||
case BytesMarshaler:
|
||||
return true
|
||||
case InterfaceMarshalerContext:
|
||||
return true
|
||||
case InterfaceMarshaler:
|
||||
return true
|
||||
case time.Time:
|
||||
return true
|
||||
case time.Duration:
|
||||
return true
|
||||
case encoding.TextMarshaler:
|
||||
return true
|
||||
case jsonMarshaler:
|
||||
return e.useJSONMarshaler
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeByMarshaler(ctx context.Context, v reflect.Value, column int) (ast.Node, error) {
|
||||
iface := v.Interface()
|
||||
|
||||
if marshaler, exists := e.marshalerFromCustomMarshalerMap(v.Type()); exists {
|
||||
doc, err := marshaler(iface)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to MarshalYAML")
|
||||
}
|
||||
node, err := e.encodeDocument(doc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode document")
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
if marshaler, ok := iface.(BytesMarshalerContext); ok {
|
||||
doc, err := marshaler.MarshalYAML(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to MarshalYAML")
|
||||
}
|
||||
node, err := e.encodeDocument(doc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode document")
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
if marshaler, ok := iface.(BytesMarshaler); ok {
|
||||
doc, err := marshaler.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to MarshalYAML")
|
||||
}
|
||||
node, err := e.encodeDocument(doc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode document")
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
if marshaler, ok := iface.(InterfaceMarshalerContext); ok {
|
||||
marshalV, err := marshaler.MarshalYAML(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to MarshalYAML")
|
||||
}
|
||||
return e.encodeValue(ctx, reflect.ValueOf(marshalV), column)
|
||||
}
|
||||
|
||||
if marshaler, ok := iface.(InterfaceMarshaler); ok {
|
||||
marshalV, err := marshaler.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to MarshalYAML")
|
||||
}
|
||||
return e.encodeValue(ctx, reflect.ValueOf(marshalV), column)
|
||||
}
|
||||
|
||||
if t, ok := iface.(time.Time); ok {
|
||||
return e.encodeTime(t, column), nil
|
||||
}
|
||||
|
||||
if t, ok := iface.(time.Duration); ok {
|
||||
return e.encodeDuration(t, column), nil
|
||||
}
|
||||
|
||||
if marshaler, ok := iface.(encoding.TextMarshaler); ok {
|
||||
doc, err := marshaler.MarshalText()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to MarshalText")
|
||||
}
|
||||
node, err := e.encodeDocument(doc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode document")
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
if e.useJSONMarshaler {
|
||||
if marshaler, ok := iface.(jsonMarshaler); ok {
|
||||
jsonBytes, err := marshaler.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to MarshalJSON")
|
||||
}
|
||||
doc, err := JSONToYAML(jsonBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to convert json to yaml")
|
||||
}
|
||||
node, err := e.encodeDocument(doc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode document")
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("does not implemented Marshaler")
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeValue(ctx context.Context, v reflect.Value, column int) (ast.Node, error) {
|
||||
if e.isInvalidValue(v) {
|
||||
return e.encodeNil(), nil
|
||||
}
|
||||
if e.canEncodeByMarshaler(v) {
|
||||
node, err := e.encodeByMarshaler(ctx, v, column)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode by marshaler")
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return e.encodeInt(v.Int()), nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return e.encodeUint(v.Uint()), nil
|
||||
case reflect.Float32:
|
||||
return e.encodeFloat(v.Float(), 32), nil
|
||||
case reflect.Float64:
|
||||
return e.encodeFloat(v.Float(), 64), nil
|
||||
case reflect.Ptr:
|
||||
anchorName := e.anchorPtrToNameMap[v.Pointer()]
|
||||
if anchorName != "" {
|
||||
aliasName := anchorName
|
||||
alias := ast.Alias(token.New("*", "*", e.pos(column)))
|
||||
alias.Value = ast.String(token.New(aliasName, aliasName, e.pos(column)))
|
||||
return alias, nil
|
||||
}
|
||||
return e.encodeValue(ctx, v.Elem(), column)
|
||||
case reflect.Interface:
|
||||
return e.encodeValue(ctx, v.Elem(), column)
|
||||
case reflect.String:
|
||||
return e.encodeString(v.String(), column), nil
|
||||
case reflect.Bool:
|
||||
return e.encodeBool(v.Bool()), nil
|
||||
case reflect.Slice:
|
||||
if mapSlice, ok := v.Interface().(MapSlice); ok {
|
||||
return e.encodeMapSlice(ctx, mapSlice, column)
|
||||
}
|
||||
return e.encodeSlice(ctx, v)
|
||||
case reflect.Array:
|
||||
return e.encodeArray(ctx, v)
|
||||
case reflect.Struct:
|
||||
if v.CanInterface() {
|
||||
if mapItem, ok := v.Interface().(MapItem); ok {
|
||||
return e.encodeMapItem(ctx, mapItem, column)
|
||||
}
|
||||
if t, ok := v.Interface().(time.Time); ok {
|
||||
return e.encodeTime(t, column), nil
|
||||
}
|
||||
}
|
||||
return e.encodeStruct(ctx, v, column)
|
||||
case reflect.Map:
|
||||
return e.encodeMap(ctx, v, column), nil
|
||||
default:
|
||||
return nil, xerrors.Errorf("unknown value type %s", v.Type().String())
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Encoder) pos(column int) *token.Position {
|
||||
return &token.Position{
|
||||
Line: e.line,
|
||||
Column: column,
|
||||
Offset: e.offset,
|
||||
IndentNum: e.indentNum,
|
||||
IndentLevel: e.indentLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeNil() *ast.NullNode {
|
||||
value := "null"
|
||||
return ast.Null(token.New(value, value, e.pos(e.column)))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeInt(v int64) *ast.IntegerNode {
|
||||
value := fmt.Sprint(v)
|
||||
return ast.Integer(token.New(value, value, e.pos(e.column)))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeUint(v uint64) *ast.IntegerNode {
|
||||
value := fmt.Sprint(v)
|
||||
return ast.Integer(token.New(value, value, e.pos(e.column)))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeFloat(v float64, bitSize int) ast.Node {
|
||||
if v == math.Inf(0) {
|
||||
value := ".inf"
|
||||
return ast.Infinity(token.New(value, value, e.pos(e.column)))
|
||||
} else if v == math.Inf(-1) {
|
||||
value := "-.inf"
|
||||
return ast.Infinity(token.New(value, value, e.pos(e.column)))
|
||||
} else if math.IsNaN(v) {
|
||||
value := ".nan"
|
||||
return ast.Nan(token.New(value, value, e.pos(e.column)))
|
||||
}
|
||||
value := strconv.FormatFloat(v, 'g', -1, bitSize)
|
||||
if !strings.Contains(value, ".") && !strings.Contains(value, "e") {
|
||||
// append x.0 suffix to keep float value context
|
||||
value = fmt.Sprintf("%s.0", value)
|
||||
}
|
||||
return ast.Float(token.New(value, value, e.pos(e.column)))
|
||||
}
|
||||
|
||||
func (e *Encoder) isNeedQuoted(v string) bool {
|
||||
if e.isJSONStyle {
|
||||
return true
|
||||
}
|
||||
if e.useLiteralStyleIfMultiline && strings.ContainsAny(v, "\n\r") {
|
||||
return false
|
||||
}
|
||||
if e.isFlowStyle && strings.ContainsAny(v, `]},'"`) {
|
||||
return true
|
||||
}
|
||||
if token.IsNeedQuoted(v) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeString(v string, column int) *ast.StringNode {
|
||||
if e.isNeedQuoted(v) {
|
||||
if e.singleQuote {
|
||||
v = quoteWith(v, '\'')
|
||||
} else {
|
||||
v = strconv.Quote(v)
|
||||
}
|
||||
}
|
||||
return ast.String(token.New(v, v, e.pos(column)))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeBool(v bool) *ast.BoolNode {
|
||||
value := fmt.Sprint(v)
|
||||
return ast.Bool(token.New(value, value, e.pos(e.column)))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeSlice(ctx context.Context, value reflect.Value) (*ast.SequenceNode, error) {
|
||||
if e.indentSequence {
|
||||
e.column += e.indent
|
||||
}
|
||||
column := e.column
|
||||
sequence := ast.Sequence(token.New("-", "-", e.pos(column)), e.isFlowStyle)
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
node, err := e.encodeValue(ctx, value.Index(i), column)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode value for slice")
|
||||
}
|
||||
sequence.Values = append(sequence.Values, node)
|
||||
}
|
||||
if e.indentSequence {
|
||||
e.column -= e.indent
|
||||
}
|
||||
return sequence, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeArray(ctx context.Context, value reflect.Value) (*ast.SequenceNode, error) {
|
||||
if e.indentSequence {
|
||||
e.column += e.indent
|
||||
}
|
||||
column := e.column
|
||||
sequence := ast.Sequence(token.New("-", "-", e.pos(column)), e.isFlowStyle)
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
node, err := e.encodeValue(ctx, value.Index(i), column)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode value for array")
|
||||
}
|
||||
sequence.Values = append(sequence.Values, node)
|
||||
}
|
||||
if e.indentSequence {
|
||||
e.column -= e.indent
|
||||
}
|
||||
return sequence, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeMapItem(ctx context.Context, item MapItem, column int) (*ast.MappingValueNode, error) {
|
||||
k := reflect.ValueOf(item.Key)
|
||||
v := reflect.ValueOf(item.Value)
|
||||
value, err := e.encodeValue(ctx, v, column)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode MapItem")
|
||||
}
|
||||
if e.isMapNode(value) {
|
||||
value.AddColumn(e.indent)
|
||||
}
|
||||
return ast.MappingValue(
|
||||
token.New("", "", e.pos(column)),
|
||||
e.encodeString(k.Interface().(string), column),
|
||||
value,
|
||||
), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeMapSlice(ctx context.Context, value MapSlice, column int) (*ast.MappingNode, error) {
|
||||
node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
|
||||
for _, item := range value {
|
||||
value, err := e.encodeMapItem(ctx, item, column)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode MapItem for MapSlice")
|
||||
}
|
||||
node.Values = append(node.Values, value)
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) isMapNode(node ast.Node) bool {
|
||||
_, ok := node.(ast.MapNode)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeMap(ctx context.Context, value reflect.Value, column int) ast.Node {
|
||||
node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
|
||||
keys := make([]interface{}, len(value.MapKeys()))
|
||||
for i, k := range value.MapKeys() {
|
||||
keys[i] = k.Interface()
|
||||
}
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return fmt.Sprint(keys[i]) < fmt.Sprint(keys[j])
|
||||
})
|
||||
for _, key := range keys {
|
||||
k := reflect.ValueOf(key)
|
||||
v := value.MapIndex(k)
|
||||
value, err := e.encodeValue(ctx, v, column)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if e.isMapNode(value) {
|
||||
value.AddColumn(e.indent)
|
||||
}
|
||||
node.Values = append(node.Values, ast.MappingValue(
|
||||
nil,
|
||||
e.encodeString(fmt.Sprint(key), column),
|
||||
value,
|
||||
))
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// IsZeroer is used to check whether an object is zero to determine
|
||||
// whether it should be omitted when marshaling with the omitempty flag.
|
||||
// One notable implementation is time.Time.
|
||||
type IsZeroer interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
func (e *Encoder) isZeroValue(v reflect.Value) bool {
|
||||
kind := v.Kind()
|
||||
if z, ok := v.Interface().(IsZeroer); ok {
|
||||
if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
|
||||
return true
|
||||
}
|
||||
return z.IsZero()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.String:
|
||||
return len(v.String()) == 0
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v.IsNil()
|
||||
case reflect.Slice:
|
||||
return v.Len() == 0
|
||||
case reflect.Map:
|
||||
return v.Len() == 0
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Struct:
|
||||
vt := v.Type()
|
||||
for i := v.NumField() - 1; i >= 0; i-- {
|
||||
if vt.Field(i).PkgPath != "" {
|
||||
continue // private field
|
||||
}
|
||||
if !e.isZeroValue(v.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeTime(v time.Time, column int) *ast.StringNode {
|
||||
value := v.Format(time.RFC3339Nano)
|
||||
if e.isJSONStyle {
|
||||
value = strconv.Quote(value)
|
||||
}
|
||||
return ast.String(token.New(value, value, e.pos(column)))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeDuration(v time.Duration, column int) *ast.StringNode {
|
||||
value := v.String()
|
||||
if e.isJSONStyle {
|
||||
value = strconv.Quote(value)
|
||||
}
|
||||
return ast.String(token.New(value, value, e.pos(column)))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeAnchor(anchorName string, value ast.Node, fieldValue reflect.Value, column int) (*ast.AnchorNode, error) {
|
||||
anchorNode := ast.Anchor(token.New("&", "&", e.pos(column)))
|
||||
anchorNode.Name = ast.String(token.New(anchorName, anchorName, e.pos(column)))
|
||||
anchorNode.Value = value
|
||||
if e.anchorCallback != nil {
|
||||
if err := e.anchorCallback(anchorNode, fieldValue.Interface()); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to marshal anchor")
|
||||
}
|
||||
if snode, ok := anchorNode.Name.(*ast.StringNode); ok {
|
||||
anchorName = snode.Value
|
||||
}
|
||||
}
|
||||
if fieldValue.Kind() == reflect.Ptr {
|
||||
e.anchorPtrToNameMap[fieldValue.Pointer()] = anchorName
|
||||
}
|
||||
return anchorNode, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeStruct(ctx context.Context, value reflect.Value, column int) (ast.Node, error) {
|
||||
node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
|
||||
structType := value.Type()
|
||||
structFieldMap, err := structFieldMap(structType)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get struct field map")
|
||||
}
|
||||
hasInlineAnchorField := false
|
||||
var inlineAnchorValue reflect.Value
|
||||
for i := 0; i < value.NumField(); i++ {
|
||||
field := structType.Field(i)
|
||||
if isIgnoredStructField(field) {
|
||||
continue
|
||||
}
|
||||
fieldValue := value.FieldByName(field.Name)
|
||||
structField := structFieldMap[field.Name]
|
||||
if structField.IsOmitEmpty && e.isZeroValue(fieldValue) {
|
||||
// omit encoding
|
||||
continue
|
||||
}
|
||||
ve := e
|
||||
if !e.isFlowStyle && structField.IsFlow {
|
||||
ve = &Encoder{}
|
||||
*ve = *e
|
||||
ve.isFlowStyle = true
|
||||
}
|
||||
value, err := ve.encodeValue(ctx, fieldValue, column)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode value")
|
||||
}
|
||||
if e.isMapNode(value) {
|
||||
value.AddColumn(e.indent)
|
||||
}
|
||||
var key ast.MapKeyNode = e.encodeString(structField.RenderName, column)
|
||||
switch {
|
||||
case structField.AnchorName != "":
|
||||
anchorNode, err := e.encodeAnchor(structField.AnchorName, value, fieldValue, column)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode anchor")
|
||||
}
|
||||
value = anchorNode
|
||||
case structField.IsAutoAlias:
|
||||
if fieldValue.Kind() != reflect.Ptr {
|
||||
return nil, xerrors.Errorf(
|
||||
"%s in struct is not pointer type. but required automatically alias detection",
|
||||
structField.FieldName,
|
||||
)
|
||||
}
|
||||
anchorName := e.anchorPtrToNameMap[fieldValue.Pointer()]
|
||||
if anchorName == "" {
|
||||
return nil, xerrors.Errorf(
|
||||
"cannot find anchor name from pointer address for automatically alias detection",
|
||||
)
|
||||
}
|
||||
aliasName := anchorName
|
||||
alias := ast.Alias(token.New("*", "*", e.pos(column)))
|
||||
alias.Value = ast.String(token.New(aliasName, aliasName, e.pos(column)))
|
||||
value = alias
|
||||
if structField.IsInline {
|
||||
// if both used alias and inline, output `<<: *alias`
|
||||
key = ast.MergeKey(token.New("<<", "<<", e.pos(column)))
|
||||
}
|
||||
case structField.AliasName != "":
|
||||
aliasName := structField.AliasName
|
||||
alias := ast.Alias(token.New("*", "*", e.pos(column)))
|
||||
alias.Value = ast.String(token.New(aliasName, aliasName, e.pos(column)))
|
||||
value = alias
|
||||
if structField.IsInline {
|
||||
// if both used alias and inline, output `<<: *alias`
|
||||
key = ast.MergeKey(token.New("<<", "<<", e.pos(column)))
|
||||
}
|
||||
case structField.IsInline:
|
||||
isAutoAnchor := structField.IsAutoAnchor
|
||||
if !hasInlineAnchorField {
|
||||
hasInlineAnchorField = isAutoAnchor
|
||||
}
|
||||
if isAutoAnchor {
|
||||
inlineAnchorValue = fieldValue
|
||||
}
|
||||
mapNode, ok := value.(ast.MapNode)
|
||||
if !ok {
|
||||
return nil, xerrors.Errorf("inline value is must be map or struct type")
|
||||
}
|
||||
mapIter := mapNode.MapRange()
|
||||
for mapIter.Next() {
|
||||
key := mapIter.Key()
|
||||
value := mapIter.Value()
|
||||
keyName := key.GetToken().Value
|
||||
if structFieldMap.isIncludedRenderName(keyName) {
|
||||
// if declared same key name, skip encoding this field
|
||||
continue
|
||||
}
|
||||
key.AddColumn(-e.indent)
|
||||
value.AddColumn(-e.indent)
|
||||
node.Values = append(node.Values, ast.MappingValue(nil, key, value))
|
||||
}
|
||||
continue
|
||||
case structField.IsAutoAnchor:
|
||||
anchorNode, err := e.encodeAnchor(structField.RenderName, value, fieldValue, column)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode anchor")
|
||||
}
|
||||
value = anchorNode
|
||||
}
|
||||
node.Values = append(node.Values, ast.MappingValue(nil, key, value))
|
||||
}
|
||||
if hasInlineAnchorField {
|
||||
node.AddColumn(e.indent)
|
||||
anchorName := "anchor"
|
||||
anchorNode := ast.Anchor(token.New("&", "&", e.pos(column)))
|
||||
anchorNode.Name = ast.String(token.New(anchorName, anchorName, e.pos(column)))
|
||||
anchorNode.Value = node
|
||||
if e.anchorCallback != nil {
|
||||
if err := e.anchorCallback(anchorNode, value.Addr().Interface()); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to marshal anchor")
|
||||
}
|
||||
if snode, ok := anchorNode.Name.(*ast.StringNode); ok {
|
||||
anchorName = snode.Value
|
||||
}
|
||||
}
|
||||
if inlineAnchorValue.Kind() == reflect.Ptr {
|
||||
e.anchorPtrToNameMap[inlineAnchorValue.Pointer()] = anchorName
|
||||
}
|
||||
return anchorNode, nil
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
62
vendor/github.com/goccy/go-yaml/error.go
generated
vendored
Normal file
62
vendor/github.com/goccy/go-yaml/error.go
generated
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package yaml
|
||||
|
||||
import (
|
||||
"github.com/goccy/go-yaml/ast"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidQuery = xerrors.New("invalid query")
|
||||
ErrInvalidPath = xerrors.New("invalid path instance")
|
||||
ErrInvalidPathString = xerrors.New("invalid path string")
|
||||
ErrNotFoundNode = xerrors.New("node not found")
|
||||
ErrUnknownCommentPositionType = xerrors.New("unknown comment position type")
|
||||
ErrInvalidCommentMapValue = xerrors.New("invalid comment map value. it must be not nil value")
|
||||
)
|
||||
|
||||
func ErrUnsupportedHeadPositionType(node ast.Node) error {
|
||||
return xerrors.Errorf("unsupported comment head position for %s", node.Type())
|
||||
}
|
||||
|
||||
func ErrUnsupportedLinePositionType(node ast.Node) error {
|
||||
return xerrors.Errorf("unsupported comment line position for %s", node.Type())
|
||||
}
|
||||
|
||||
func ErrUnsupportedFootPositionType(node ast.Node) error {
|
||||
return xerrors.Errorf("unsupported comment foot position for %s", node.Type())
|
||||
}
|
||||
|
||||
// IsInvalidQueryError whether err is ErrInvalidQuery or not.
|
||||
func IsInvalidQueryError(err error) bool {
|
||||
return xerrors.Is(err, ErrInvalidQuery)
|
||||
}
|
||||
|
||||
// IsInvalidPathError whether err is ErrInvalidPath or not.
|
||||
func IsInvalidPathError(err error) bool {
|
||||
return xerrors.Is(err, ErrInvalidPath)
|
||||
}
|
||||
|
||||
// IsInvalidPathStringError whether err is ErrInvalidPathString or not.
|
||||
func IsInvalidPathStringError(err error) bool {
|
||||
return xerrors.Is(err, ErrInvalidPathString)
|
||||
}
|
||||
|
||||
// IsNotFoundNodeError whether err is ErrNotFoundNode or not.
|
||||
func IsNotFoundNodeError(err error) bool {
|
||||
return xerrors.Is(err, ErrNotFoundNode)
|
||||
}
|
||||
|
||||
// IsInvalidTokenTypeError whether err is ast.ErrInvalidTokenType or not.
|
||||
func IsInvalidTokenTypeError(err error) bool {
|
||||
return xerrors.Is(err, ast.ErrInvalidTokenType)
|
||||
}
|
||||
|
||||
// IsInvalidAnchorNameError whether err is ast.ErrInvalidAnchorName or not.
|
||||
func IsInvalidAnchorNameError(err error) bool {
|
||||
return xerrors.Is(err, ast.ErrInvalidAnchorName)
|
||||
}
|
||||
|
||||
// IsInvalidAliasNameError whether err is ast.ErrInvalidAliasName or not.
|
||||
func IsInvalidAliasNameError(err error) bool {
|
||||
return xerrors.Is(err, ast.ErrInvalidAliasName)
|
||||
}
|
||||
260
vendor/github.com/goccy/go-yaml/internal/errors/error.go
generated
vendored
Normal file
260
vendor/github.com/goccy/go-yaml/internal/errors/error.go
generated
vendored
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
package errors
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/goccy/go-yaml/printer"
|
||||
"github.com/goccy/go-yaml/token"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultColorize = false
|
||||
defaultIncludeSource = true
|
||||
)
|
||||
|
||||
var (
|
||||
ErrDecodeRequiredPointerType = xerrors.New("required pointer type value")
|
||||
)
|
||||
|
||||
// Wrapf wrap error for stack trace
|
||||
func Wrapf(err error, msg string, args ...interface{}) error {
|
||||
return &wrapError{
|
||||
baseError: &baseError{},
|
||||
err: xerrors.Errorf(msg, args...),
|
||||
nextErr: err,
|
||||
frame: xerrors.Caller(1),
|
||||
}
|
||||
}
|
||||
|
||||
// ErrSyntax create syntax error instance with message and token
|
||||
func ErrSyntax(msg string, tk *token.Token) *syntaxError {
|
||||
return &syntaxError{
|
||||
baseError: &baseError{},
|
||||
msg: msg,
|
||||
token: tk,
|
||||
frame: xerrors.Caller(1),
|
||||
}
|
||||
}
|
||||
|
||||
type baseError struct {
|
||||
state fmt.State
|
||||
verb rune
|
||||
}
|
||||
|
||||
func (e *baseError) Error() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e *baseError) chainStateAndVerb(err error) {
|
||||
wrapErr, ok := err.(*wrapError)
|
||||
if ok {
|
||||
wrapErr.state = e.state
|
||||
wrapErr.verb = e.verb
|
||||
}
|
||||
syntaxErr, ok := err.(*syntaxError)
|
||||
if ok {
|
||||
syntaxErr.state = e.state
|
||||
syntaxErr.verb = e.verb
|
||||
}
|
||||
}
|
||||
|
||||
type wrapError struct {
|
||||
*baseError
|
||||
err error
|
||||
nextErr error
|
||||
frame xerrors.Frame
|
||||
}
|
||||
|
||||
type FormatErrorPrinter struct {
|
||||
xerrors.Printer
|
||||
Colored bool
|
||||
InclSource bool
|
||||
}
|
||||
|
||||
func (e *wrapError) As(target interface{}) bool {
|
||||
err := e.nextErr
|
||||
for {
|
||||
if wrapErr, ok := err.(*wrapError); ok {
|
||||
err = wrapErr.nextErr
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return xerrors.As(err, target)
|
||||
}
|
||||
|
||||
func (e *wrapError) Unwrap() error {
|
||||
return e.nextErr
|
||||
}
|
||||
|
||||
func (e *wrapError) PrettyPrint(p xerrors.Printer, colored, inclSource bool) error {
|
||||
return e.FormatError(&FormatErrorPrinter{Printer: p, Colored: colored, InclSource: inclSource})
|
||||
}
|
||||
|
||||
func (e *wrapError) FormatError(p xerrors.Printer) error {
|
||||
if _, ok := p.(*FormatErrorPrinter); !ok {
|
||||
p = &FormatErrorPrinter{
|
||||
Printer: p,
|
||||
Colored: defaultColorize,
|
||||
InclSource: defaultIncludeSource,
|
||||
}
|
||||
}
|
||||
if e.verb == 'v' && e.state.Flag('+') {
|
||||
// print stack trace for debugging
|
||||
p.Print(e.err, "\n")
|
||||
e.frame.Format(p)
|
||||
e.chainStateAndVerb(e.nextErr)
|
||||
return e.nextErr
|
||||
}
|
||||
err := e.nextErr
|
||||
for {
|
||||
if wrapErr, ok := err.(*wrapError); ok {
|
||||
err = wrapErr.nextErr
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
e.chainStateAndVerb(err)
|
||||
if fmtErr, ok := err.(xerrors.Formatter); ok {
|
||||
fmtErr.FormatError(p)
|
||||
} else {
|
||||
p.Print(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type wrapState struct {
|
||||
org fmt.State
|
||||
}
|
||||
|
||||
func (s *wrapState) Write(b []byte) (n int, err error) {
|
||||
return s.org.Write(b)
|
||||
}
|
||||
|
||||
func (s *wrapState) Width() (wid int, ok bool) {
|
||||
return s.org.Width()
|
||||
}
|
||||
|
||||
func (s *wrapState) Precision() (prec int, ok bool) {
|
||||
return s.org.Precision()
|
||||
}
|
||||
|
||||
func (s *wrapState) Flag(c int) bool {
|
||||
// set true to 'printDetail' forced because when p.Detail() is false, xerrors.Printer no output any text
|
||||
if c == '#' {
|
||||
// ignore '#' keyword because xerrors.FormatError doesn't set true to printDetail.
|
||||
// ( see https://github.com/golang/xerrors/blob/master/adaptor.go#L39-L43 )
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *wrapError) Format(state fmt.State, verb rune) {
|
||||
e.state = state
|
||||
e.verb = verb
|
||||
xerrors.FormatError(e, &wrapState{org: state}, verb)
|
||||
}
|
||||
|
||||
func (e *wrapError) Error() string {
|
||||
var buf bytes.Buffer
|
||||
e.PrettyPrint(&Sink{&buf}, defaultColorize, defaultIncludeSource)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
type syntaxError struct {
|
||||
*baseError
|
||||
msg string
|
||||
token *token.Token
|
||||
frame xerrors.Frame
|
||||
}
|
||||
|
||||
func (e *syntaxError) PrettyPrint(p xerrors.Printer, colored, inclSource bool) error {
|
||||
return e.FormatError(&FormatErrorPrinter{Printer: p, Colored: colored, InclSource: inclSource})
|
||||
}
|
||||
|
||||
func (e *syntaxError) FormatError(p xerrors.Printer) error {
|
||||
var pp printer.Printer
|
||||
|
||||
var colored, inclSource bool
|
||||
if fep, ok := p.(*FormatErrorPrinter); ok {
|
||||
colored = fep.Colored
|
||||
inclSource = fep.InclSource
|
||||
}
|
||||
|
||||
pos := fmt.Sprintf("[%d:%d] ", e.token.Position.Line, e.token.Position.Column)
|
||||
msg := pp.PrintErrorMessage(fmt.Sprintf("%s%s", pos, e.msg), colored)
|
||||
if inclSource {
|
||||
msg += "\n" + pp.PrintErrorToken(e.token, colored)
|
||||
}
|
||||
p.Print(msg)
|
||||
|
||||
if e.verb == 'v' && e.state.Flag('+') {
|
||||
// %+v
|
||||
// print stack trace for debugging
|
||||
e.frame.Format(p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PrettyPrinter interface {
|
||||
PrettyPrint(xerrors.Printer, bool, bool) error
|
||||
}
|
||||
type Sink struct{ *bytes.Buffer }
|
||||
|
||||
func (es *Sink) Print(args ...interface{}) {
|
||||
fmt.Fprint(es.Buffer, args...)
|
||||
}
|
||||
|
||||
func (es *Sink) Printf(f string, args ...interface{}) {
|
||||
fmt.Fprintf(es.Buffer, f, args...)
|
||||
}
|
||||
|
||||
func (es *Sink) Detail() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *syntaxError) Error() string {
|
||||
var buf bytes.Buffer
|
||||
e.PrettyPrint(&Sink{&buf}, defaultColorize, defaultIncludeSource)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
type TypeError struct {
|
||||
DstType reflect.Type
|
||||
SrcType reflect.Type
|
||||
StructFieldName *string
|
||||
Token *token.Token
|
||||
}
|
||||
|
||||
func (e *TypeError) Error() string {
|
||||
if e.StructFieldName != nil {
|
||||
return fmt.Sprintf("cannot unmarshal %s into Go struct field %s of type %s", e.SrcType, *e.StructFieldName, e.DstType)
|
||||
}
|
||||
return fmt.Sprintf("cannot unmarshal %s into Go value of type %s", e.SrcType, e.DstType)
|
||||
}
|
||||
|
||||
func (e *TypeError) PrettyPrint(p xerrors.Printer, colored, inclSource bool) error {
|
||||
return e.FormatError(&FormatErrorPrinter{Printer: p, Colored: colored, InclSource: inclSource})
|
||||
}
|
||||
|
||||
func (e *TypeError) FormatError(p xerrors.Printer) error {
|
||||
var pp printer.Printer
|
||||
|
||||
var colored, inclSource bool
|
||||
if fep, ok := p.(*FormatErrorPrinter); ok {
|
||||
colored = fep.Colored
|
||||
inclSource = fep.InclSource
|
||||
}
|
||||
|
||||
pos := fmt.Sprintf("[%d:%d] ", e.Token.Position.Line, e.Token.Position.Column)
|
||||
msg := pp.PrintErrorMessage(fmt.Sprintf("%s%s", pos, e.Error()), colored)
|
||||
if inclSource {
|
||||
msg += "\n" + pp.PrintErrorToken(e.Token, colored)
|
||||
}
|
||||
p.Print(msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
23
vendor/github.com/goccy/go-yaml/lexer/lexer.go
generated
vendored
Normal file
23
vendor/github.com/goccy/go-yaml/lexer/lexer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package lexer
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/goccy/go-yaml/scanner"
|
||||
"github.com/goccy/go-yaml/token"
|
||||
)
|
||||
|
||||
// Tokenize split to token instances from string
|
||||
func Tokenize(src string) token.Tokens {
|
||||
var s scanner.Scanner
|
||||
s.Init(src)
|
||||
var tokens token.Tokens
|
||||
for {
|
||||
subTokens, err := s.Scan()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
tokens.Add(subTokens...)
|
||||
}
|
||||
return tokens
|
||||
}
|
||||
278
vendor/github.com/goccy/go-yaml/option.go
generated
vendored
Normal file
278
vendor/github.com/goccy/go-yaml/option.go
generated
vendored
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
package yaml
|
||||
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/goccy/go-yaml/ast"
|
||||
)
|
||||
|
||||
// DecodeOption functional option type for Decoder
|
||||
type DecodeOption func(d *Decoder) error
|
||||
|
||||
// ReferenceReaders pass to Decoder that reference to anchor defined by passed readers
|
||||
func ReferenceReaders(readers ...io.Reader) DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
d.referenceReaders = append(d.referenceReaders, readers...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ReferenceFiles pass to Decoder that reference to anchor defined by passed files
|
||||
func ReferenceFiles(files ...string) DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
d.referenceFiles = files
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ReferenceDirs pass to Decoder that reference to anchor defined by files under the passed dirs
|
||||
func ReferenceDirs(dirs ...string) DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
d.referenceDirs = dirs
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// RecursiveDir search yaml file recursively from passed dirs by ReferenceDirs option
|
||||
func RecursiveDir(isRecursive bool) DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
d.isRecursiveDir = isRecursive
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Validator set StructValidator instance to Decoder
|
||||
func Validator(v StructValidator) DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
d.validator = v
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Strict enable DisallowUnknownField and DisallowDuplicateKey
|
||||
func Strict() DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
d.disallowUnknownField = true
|
||||
d.disallowDuplicateKey = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DisallowUnknownField causes the Decoder to return an error when the destination
|
||||
// is a struct and the input contains object keys which do not match any
|
||||
// non-ignored, exported fields in the destination.
|
||||
func DisallowUnknownField() DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
d.disallowUnknownField = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DisallowDuplicateKey causes an error when mapping keys that are duplicates
|
||||
func DisallowDuplicateKey() DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
d.disallowDuplicateKey = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// UseOrderedMap can be interpreted as a map,
|
||||
// and uses MapSlice ( ordered map ) aggressively if there is no type specification
|
||||
func UseOrderedMap() DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
d.useOrderedMap = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// UseJSONUnmarshaler if neither `BytesUnmarshaler` nor `InterfaceUnmarshaler` is implemented
|
||||
// and `UnmashalJSON([]byte)error` is implemented, convert the argument from `YAML` to `JSON` and then call it.
|
||||
func UseJSONUnmarshaler() DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
d.useJSONUnmarshaler = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// CustomUnmarshaler overrides any decoding process for the type specified in generics.
|
||||
//
|
||||
// NOTE: If RegisterCustomUnmarshaler and CustomUnmarshaler of DecodeOption are specified for the same type,
|
||||
// the CustomUnmarshaler specified in DecodeOption takes precedence.
|
||||
func CustomUnmarshaler[T any](unmarshaler func(*T, []byte) error) DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
var typ *T
|
||||
d.customUnmarshalerMap[reflect.TypeOf(typ)] = func(v interface{}, b []byte) error {
|
||||
return unmarshaler(v.(*T), b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeOption functional option type for Encoder
|
||||
type EncodeOption func(e *Encoder) error
|
||||
|
||||
// Indent change indent number
|
||||
func Indent(spaces int) EncodeOption {
|
||||
return func(e *Encoder) error {
|
||||
e.indent = spaces
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// IndentSequence causes sequence values to be indented the same value as Indent
|
||||
func IndentSequence(indent bool) EncodeOption {
|
||||
return func(e *Encoder) error {
|
||||
e.indentSequence = indent
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// UseSingleQuote determines if single or double quotes should be preferred for strings.
|
||||
func UseSingleQuote(sq bool) EncodeOption {
|
||||
return func(e *Encoder) error {
|
||||
e.singleQuote = sq
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Flow encoding by flow style
|
||||
func Flow(isFlowStyle bool) EncodeOption {
|
||||
return func(e *Encoder) error {
|
||||
e.isFlowStyle = isFlowStyle
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// UseLiteralStyleIfMultiline causes encoding multiline strings with a literal syntax,
|
||||
// no matter what characters they include
|
||||
func UseLiteralStyleIfMultiline(useLiteralStyleIfMultiline bool) EncodeOption {
|
||||
return func(e *Encoder) error {
|
||||
e.useLiteralStyleIfMultiline = useLiteralStyleIfMultiline
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// JSON encode in JSON format
|
||||
func JSON() EncodeOption {
|
||||
return func(e *Encoder) error {
|
||||
e.isJSONStyle = true
|
||||
e.isFlowStyle = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalAnchor call back if encoder find an anchor during encoding
|
||||
func MarshalAnchor(callback func(*ast.AnchorNode, interface{}) error) EncodeOption {
|
||||
return func(e *Encoder) error {
|
||||
e.anchorCallback = callback
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// UseJSONMarshaler if neither `BytesMarshaler` nor `InterfaceMarshaler`
|
||||
// nor `encoding.TextMarshaler` is implemented and `MarshalJSON()([]byte, error)` is implemented,
|
||||
// call `MarshalJSON` to convert the returned `JSON` to `YAML` for processing.
|
||||
func UseJSONMarshaler() EncodeOption {
|
||||
return func(e *Encoder) error {
|
||||
e.useJSONMarshaler = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// CustomMarshaler overrides any encoding process for the type specified in generics.
|
||||
//
|
||||
// NOTE: If type T implements MarshalYAML for pointer receiver, the type specified in CustomMarshaler must be *T.
|
||||
// If RegisterCustomMarshaler and CustomMarshaler of EncodeOption are specified for the same type,
|
||||
// the CustomMarshaler specified in EncodeOption takes precedence.
|
||||
func CustomMarshaler[T any](marshaler func(T) ([]byte, error)) EncodeOption {
|
||||
return func(e *Encoder) error {
|
||||
var typ T
|
||||
e.customMarshalerMap[reflect.TypeOf(typ)] = func(v interface{}) ([]byte, error) {
|
||||
return marshaler(v.(T))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// CommentPosition type of the position for comment.
|
||||
type CommentPosition int
|
||||
|
||||
const (
|
||||
CommentHeadPosition CommentPosition = CommentPosition(iota)
|
||||
CommentLinePosition
|
||||
CommentFootPosition
|
||||
)
|
||||
|
||||
func (p CommentPosition) String() string {
|
||||
switch p {
|
||||
case CommentHeadPosition:
|
||||
return "Head"
|
||||
case CommentLinePosition:
|
||||
return "Line"
|
||||
case CommentFootPosition:
|
||||
return "Foot"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// LineComment create a one-line comment for CommentMap.
|
||||
func LineComment(text string) *Comment {
|
||||
return &Comment{
|
||||
Texts: []string{text},
|
||||
Position: CommentLinePosition,
|
||||
}
|
||||
}
|
||||
|
||||
// HeadComment create a multiline comment for CommentMap.
|
||||
func HeadComment(texts ...string) *Comment {
|
||||
return &Comment{
|
||||
Texts: texts,
|
||||
Position: CommentHeadPosition,
|
||||
}
|
||||
}
|
||||
|
||||
// FootComment create a multiline comment for CommentMap.
|
||||
func FootComment(texts ...string) *Comment {
|
||||
return &Comment{
|
||||
Texts: texts,
|
||||
Position: CommentFootPosition,
|
||||
}
|
||||
}
|
||||
|
||||
// Comment raw data for comment.
|
||||
type Comment struct {
|
||||
Texts []string
|
||||
Position CommentPosition
|
||||
}
|
||||
|
||||
// CommentMap map of the position of the comment and the comment information.
|
||||
type CommentMap map[string][]*Comment
|
||||
|
||||
// WithComment add a comment using the location and text information given in the CommentMap.
|
||||
func WithComment(cm CommentMap) EncodeOption {
|
||||
return func(e *Encoder) error {
|
||||
commentMap := map[*Path][]*Comment{}
|
||||
for k, v := range cm {
|
||||
path, err := PathString(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commentMap[path] = v
|
||||
}
|
||||
e.commentMap = commentMap
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// CommentToMap apply the position and content of comments in a YAML document to a CommentMap.
|
||||
func CommentToMap(cm CommentMap) DecodeOption {
|
||||
return func(d *Decoder) error {
|
||||
if cm == nil {
|
||||
return ErrInvalidCommentMapValue
|
||||
}
|
||||
d.toCommentMap = cm
|
||||
return nil
|
||||
}
|
||||
}
|
||||
199
vendor/github.com/goccy/go-yaml/parser/context.go
generated
vendored
Normal file
199
vendor/github.com/goccy/go-yaml/parser/context.go
generated
vendored
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/goccy/go-yaml/token"
|
||||
)
|
||||
|
||||
// context context at parsing
|
||||
type context struct {
|
||||
parent *context
|
||||
idx int
|
||||
size int
|
||||
tokens token.Tokens
|
||||
mode Mode
|
||||
path string
|
||||
}
|
||||
|
||||
var pathSpecialChars = []string{
|
||||
"$", "*", ".", "[", "]",
|
||||
}
|
||||
|
||||
func containsPathSpecialChar(path string) bool {
|
||||
for _, char := range pathSpecialChars {
|
||||
if strings.Contains(path, char) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func normalizePath(path string) string {
|
||||
if containsPathSpecialChar(path) {
|
||||
return fmt.Sprintf("'%s'", path)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (c *context) withChild(path string) *context {
|
||||
ctx := c.copy()
|
||||
path = normalizePath(path)
|
||||
ctx.path += fmt.Sprintf(".%s", path)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (c *context) withIndex(idx uint) *context {
|
||||
ctx := c.copy()
|
||||
ctx.path += fmt.Sprintf("[%d]", idx)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (c *context) copy() *context {
|
||||
return &context{
|
||||
parent: c,
|
||||
idx: c.idx,
|
||||
size: c.size,
|
||||
tokens: append(token.Tokens{}, c.tokens...),
|
||||
mode: c.mode,
|
||||
path: c.path,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) next() bool {
|
||||
return c.idx < c.size
|
||||
}
|
||||
|
||||
func (c *context) previousToken() *token.Token {
|
||||
if c.idx > 0 {
|
||||
return c.tokens[c.idx-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) insertToken(idx int, tk *token.Token) {
|
||||
if c.parent != nil {
|
||||
c.parent.insertToken(idx, tk)
|
||||
}
|
||||
if c.size < idx {
|
||||
return
|
||||
}
|
||||
if c.size == idx {
|
||||
curToken := c.tokens[c.size-1]
|
||||
tk.Next = curToken
|
||||
curToken.Prev = tk
|
||||
|
||||
c.tokens = append(c.tokens, tk)
|
||||
c.size = len(c.tokens)
|
||||
return
|
||||
}
|
||||
|
||||
curToken := c.tokens[idx]
|
||||
tk.Next = curToken
|
||||
curToken.Prev = tk
|
||||
|
||||
c.tokens = append(c.tokens[:idx+1], c.tokens[idx:]...)
|
||||
c.tokens[idx] = tk
|
||||
c.size = len(c.tokens)
|
||||
}
|
||||
|
||||
func (c *context) currentToken() *token.Token {
|
||||
if c.idx >= c.size {
|
||||
return nil
|
||||
}
|
||||
return c.tokens[c.idx]
|
||||
}
|
||||
|
||||
func (c *context) nextToken() *token.Token {
|
||||
if c.idx+1 >= c.size {
|
||||
return nil
|
||||
}
|
||||
return c.tokens[c.idx+1]
|
||||
}
|
||||
|
||||
func (c *context) afterNextToken() *token.Token {
|
||||
if c.idx+2 >= c.size {
|
||||
return nil
|
||||
}
|
||||
return c.tokens[c.idx+2]
|
||||
}
|
||||
|
||||
func (c *context) nextNotCommentToken() *token.Token {
|
||||
for i := c.idx + 1; i < c.size; i++ {
|
||||
tk := c.tokens[i]
|
||||
if tk.Type == token.CommentType {
|
||||
continue
|
||||
}
|
||||
return tk
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) afterNextNotCommentToken() *token.Token {
|
||||
notCommentTokenCount := 0
|
||||
for i := c.idx + 1; i < c.size; i++ {
|
||||
tk := c.tokens[i]
|
||||
if tk.Type == token.CommentType {
|
||||
continue
|
||||
}
|
||||
notCommentTokenCount++
|
||||
if notCommentTokenCount == 2 {
|
||||
return tk
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) enabledComment() bool {
|
||||
return c.mode&ParseComments != 0
|
||||
}
|
||||
|
||||
func (c *context) isCurrentCommentToken() bool {
|
||||
tk := c.currentToken()
|
||||
if tk == nil {
|
||||
return false
|
||||
}
|
||||
return tk.Type == token.CommentType
|
||||
}
|
||||
|
||||
func (c *context) progressIgnoreComment(num int) {
|
||||
if c.parent != nil {
|
||||
c.parent.progressIgnoreComment(num)
|
||||
}
|
||||
if c.size <= c.idx+num {
|
||||
c.idx = c.size
|
||||
} else {
|
||||
c.idx += num
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) progress(num int) {
|
||||
if c.isCurrentCommentToken() {
|
||||
return
|
||||
}
|
||||
c.progressIgnoreComment(num)
|
||||
}
|
||||
|
||||
func newContext(tokens token.Tokens, mode Mode) *context {
|
||||
filteredTokens := []*token.Token{}
|
||||
if mode&ParseComments != 0 {
|
||||
filteredTokens = tokens
|
||||
} else {
|
||||
for _, tk := range tokens {
|
||||
if tk.Type == token.CommentType {
|
||||
continue
|
||||
}
|
||||
// keep prev/next reference between tokens containing comments
|
||||
// https://github.com/goccy/go-yaml/issues/254
|
||||
filteredTokens = append(filteredTokens, tk)
|
||||
}
|
||||
}
|
||||
return &context{
|
||||
idx: 0,
|
||||
size: len(filteredTokens),
|
||||
tokens: token.Tokens(filteredTokens),
|
||||
mode: mode,
|
||||
path: "$",
|
||||
}
|
||||
}
|
||||
714
vendor/github.com/goccy/go-yaml/parser/parser.go
generated
vendored
Normal file
714
vendor/github.com/goccy/go-yaml/parser/parser.go
generated
vendored
Normal file
|
|
@ -0,0 +1,714 @@
|
|||
package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/goccy/go-yaml/ast"
|
||||
"github.com/goccy/go-yaml/internal/errors"
|
||||
"github.com/goccy/go-yaml/lexer"
|
||||
"github.com/goccy/go-yaml/token"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type parser struct{}
|
||||
|
||||
func (p *parser) parseMapping(ctx *context) (*ast.MappingNode, error) {
|
||||
mapTk := ctx.currentToken()
|
||||
node := ast.Mapping(mapTk, true)
|
||||
node.SetPath(ctx.path)
|
||||
ctx.progress(1) // skip MappingStart token
|
||||
for ctx.next() {
|
||||
tk := ctx.currentToken()
|
||||
if tk.Type == token.MappingEndType {
|
||||
node.End = tk
|
||||
return node, nil
|
||||
} else if tk.Type == token.CollectEntryType {
|
||||
ctx.progress(1)
|
||||
continue
|
||||
}
|
||||
|
||||
value, err := p.parseMappingValue(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse mapping value in mapping node")
|
||||
}
|
||||
mvnode, ok := value.(*ast.MappingValueNode)
|
||||
if !ok {
|
||||
return nil, errors.ErrSyntax("failed to parse flow mapping node", value.GetToken())
|
||||
}
|
||||
node.Values = append(node.Values, mvnode)
|
||||
ctx.progress(1)
|
||||
}
|
||||
return nil, errors.ErrSyntax("unterminated flow mapping", node.GetToken())
|
||||
}
|
||||
|
||||
func (p *parser) parseSequence(ctx *context) (*ast.SequenceNode, error) {
|
||||
node := ast.Sequence(ctx.currentToken(), true)
|
||||
node.SetPath(ctx.path)
|
||||
ctx.progress(1) // skip SequenceStart token
|
||||
for ctx.next() {
|
||||
tk := ctx.currentToken()
|
||||
if tk.Type == token.SequenceEndType {
|
||||
node.End = tk
|
||||
break
|
||||
} else if tk.Type == token.CollectEntryType {
|
||||
ctx.progress(1)
|
||||
continue
|
||||
}
|
||||
|
||||
value, err := p.parseToken(ctx.withIndex(uint(len(node.Values))), tk)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse sequence value in flow sequence node")
|
||||
}
|
||||
node.Values = append(node.Values, value)
|
||||
ctx.progress(1)
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseTag(ctx *context) (*ast.TagNode, error) {
|
||||
tagToken := ctx.currentToken()
|
||||
node := ast.Tag(tagToken)
|
||||
node.SetPath(ctx.path)
|
||||
ctx.progress(1) // skip tag token
|
||||
var (
|
||||
value ast.Node
|
||||
err error
|
||||
)
|
||||
switch token.ReservedTagKeyword(tagToken.Value) {
|
||||
case token.MappingTag,
|
||||
token.OrderedMapTag:
|
||||
value, err = p.parseMapping(ctx)
|
||||
case token.IntegerTag,
|
||||
token.FloatTag,
|
||||
token.StringTag,
|
||||
token.BinaryTag,
|
||||
token.TimestampTag,
|
||||
token.NullTag:
|
||||
typ := ctx.currentToken().Type
|
||||
if typ == token.LiteralType || typ == token.FoldedType {
|
||||
value, err = p.parseLiteral(ctx)
|
||||
} else {
|
||||
value = p.parseScalarValue(ctx.currentToken())
|
||||
}
|
||||
case token.SequenceTag,
|
||||
token.SetTag:
|
||||
err = errors.ErrSyntax(fmt.Sprintf("sorry, currently not supported %s tag", tagToken.Value), tagToken)
|
||||
default:
|
||||
// custom tag
|
||||
value, err = p.parseToken(ctx, ctx.currentToken())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse tag value")
|
||||
}
|
||||
node.Value = value
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *parser) removeLeftSideNewLineCharacter(src string) string {
|
||||
// CR or LF or CRLF
|
||||
return strings.TrimLeft(strings.TrimLeft(strings.TrimLeft(src, "\r"), "\n"), "\r\n")
|
||||
}
|
||||
|
||||
func (p *parser) existsNewLineCharacter(src string) bool {
|
||||
if strings.Index(src, "\n") > 0 {
|
||||
return true
|
||||
}
|
||||
if strings.Index(src, "\r") > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *parser) validateMapKey(tk *token.Token) error {
|
||||
if tk.Type != token.StringType {
|
||||
return nil
|
||||
}
|
||||
origin := p.removeLeftSideNewLineCharacter(tk.Origin)
|
||||
if p.existsNewLineCharacter(origin) {
|
||||
return errors.ErrSyntax("unexpected key name", tk)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *parser) createNullToken(base *token.Token) *token.Token {
|
||||
pos := *(base.Position)
|
||||
pos.Column++
|
||||
return token.New("null", "null", &pos)
|
||||
}
|
||||
|
||||
func (p *parser) parseMapValue(ctx *context, key ast.MapKeyNode, colonToken *token.Token) (ast.Node, error) {
|
||||
node, err := p.createMapValueNode(ctx, key, colonToken)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create map value node")
|
||||
}
|
||||
if node != nil && node.GetPath() == "" {
|
||||
node.SetPath(ctx.path)
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *parser) createMapValueNode(ctx *context, key ast.MapKeyNode, colonToken *token.Token) (ast.Node, error) {
|
||||
tk := ctx.currentToken()
|
||||
if tk == nil {
|
||||
nullToken := p.createNullToken(colonToken)
|
||||
ctx.insertToken(ctx.idx, nullToken)
|
||||
return ast.Null(nullToken), nil
|
||||
}
|
||||
|
||||
if tk.Position.Column == key.GetToken().Position.Column && tk.Type == token.StringType {
|
||||
// in this case,
|
||||
// ----
|
||||
// key: <value does not defined>
|
||||
// next
|
||||
nullToken := p.createNullToken(colonToken)
|
||||
ctx.insertToken(ctx.idx, nullToken)
|
||||
return ast.Null(nullToken), nil
|
||||
}
|
||||
|
||||
if tk.Position.Column < key.GetToken().Position.Column {
|
||||
// in this case,
|
||||
// ----
|
||||
// key: <value does not defined>
|
||||
// next
|
||||
nullToken := p.createNullToken(colonToken)
|
||||
ctx.insertToken(ctx.idx, nullToken)
|
||||
return ast.Null(nullToken), nil
|
||||
}
|
||||
|
||||
value, err := p.parseToken(ctx, ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse mapping 'value' node")
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (p *parser) validateMapValue(ctx *context, key, value ast.Node) error {
|
||||
keyColumn := key.GetToken().Position.Column
|
||||
valueColumn := value.GetToken().Position.Column
|
||||
if keyColumn != valueColumn {
|
||||
return nil
|
||||
}
|
||||
if value.Type() != ast.StringType {
|
||||
return nil
|
||||
}
|
||||
ntk := ctx.nextToken()
|
||||
if ntk == nil || (ntk.Type != token.MappingValueType && ntk.Type != token.SequenceEntryType) {
|
||||
return errors.ErrSyntax("could not found expected ':' token", value.GetToken())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *parser) parseMappingValue(ctx *context) (ast.Node, error) {
|
||||
key, err := p.parseMapKey(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse map key")
|
||||
}
|
||||
keyText := key.GetToken().Value
|
||||
key.SetPath(ctx.withChild(keyText).path)
|
||||
if err := p.validateMapKey(key.GetToken()); err != nil {
|
||||
return nil, errors.Wrapf(err, "validate mapping key error")
|
||||
}
|
||||
ctx.progress(1) // progress to mapping value token
|
||||
tk := ctx.currentToken() // get mapping value token
|
||||
if tk == nil {
|
||||
return nil, errors.ErrSyntax("unexpected map", key.GetToken())
|
||||
}
|
||||
ctx.progress(1) // progress to value token
|
||||
if err := p.setSameLineCommentIfExists(ctx.withChild(keyText), key); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to set same line comment to node")
|
||||
}
|
||||
if key.GetComment() != nil {
|
||||
// if current token is comment, GetComment() is not nil.
|
||||
// then progress to value token
|
||||
ctx.progressIgnoreComment(1)
|
||||
}
|
||||
|
||||
value, err := p.parseMapValue(ctx.withChild(keyText), key, tk)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse map value")
|
||||
}
|
||||
if err := p.validateMapValue(ctx, key, value); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to validate map value")
|
||||
}
|
||||
|
||||
mvnode := ast.MappingValue(tk, key, value)
|
||||
mvnode.SetPath(ctx.withChild(keyText).path)
|
||||
node := ast.Mapping(tk, false, mvnode)
|
||||
node.SetPath(ctx.withChild(keyText).path)
|
||||
|
||||
ntk := ctx.nextNotCommentToken()
|
||||
antk := ctx.afterNextNotCommentToken()
|
||||
for antk != nil && antk.Type == token.MappingValueType &&
|
||||
ntk.Position.Column == key.GetToken().Position.Column {
|
||||
ctx.progressIgnoreComment(1)
|
||||
value, err := p.parseToken(ctx, ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse mapping node")
|
||||
}
|
||||
switch value.Type() {
|
||||
case ast.MappingType:
|
||||
c := value.(*ast.MappingNode)
|
||||
comment := c.GetComment()
|
||||
for idx, v := range c.Values {
|
||||
if idx == 0 && comment != nil {
|
||||
if err := v.SetComment(comment); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to set comment token to node")
|
||||
}
|
||||
}
|
||||
node.Values = append(node.Values, v)
|
||||
}
|
||||
case ast.MappingValueType:
|
||||
node.Values = append(node.Values, value.(*ast.MappingValueNode))
|
||||
default:
|
||||
return nil, xerrors.Errorf("failed to parse mapping value node node is %s", value.Type())
|
||||
}
|
||||
ntk = ctx.nextNotCommentToken()
|
||||
antk = ctx.afterNextNotCommentToken()
|
||||
}
|
||||
if len(node.Values) == 1 {
|
||||
mapKeyCol := mvnode.Key.GetToken().Position.Column
|
||||
commentTk := ctx.nextToken()
|
||||
if commentTk != nil && commentTk.Type == token.CommentType && mapKeyCol <= commentTk.Position.Column {
|
||||
// If the comment is in the same or deeper column as the last element column in map value,
|
||||
// treat it as a footer comment for the last element.
|
||||
comment := p.parseFootComment(ctx, mapKeyCol)
|
||||
mvnode.FootComment = comment
|
||||
}
|
||||
return mvnode, nil
|
||||
}
|
||||
mapCol := node.GetToken().Position.Column
|
||||
commentTk := ctx.nextToken()
|
||||
if commentTk != nil && commentTk.Type == token.CommentType && mapCol <= commentTk.Position.Column {
|
||||
// If the comment is in the same or deeper column as the last element column in map value,
|
||||
// treat it as a footer comment for the last element.
|
||||
comment := p.parseFootComment(ctx, mapCol)
|
||||
node.FootComment = comment
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseSequenceEntry(ctx *context) (*ast.SequenceNode, error) {
|
||||
tk := ctx.currentToken()
|
||||
sequenceNode := ast.Sequence(tk, false)
|
||||
sequenceNode.SetPath(ctx.path)
|
||||
curColumn := tk.Position.Column
|
||||
for tk.Type == token.SequenceEntryType {
|
||||
ctx.progress(1) // skip sequence token
|
||||
tk = ctx.currentToken()
|
||||
if tk == nil {
|
||||
return nil, errors.ErrSyntax("empty sequence entry", ctx.previousToken())
|
||||
}
|
||||
var comment *ast.CommentGroupNode
|
||||
if tk.Type == token.CommentType {
|
||||
comment = p.parseCommentOnly(ctx)
|
||||
tk = ctx.currentToken()
|
||||
if tk.Type != token.SequenceEntryType {
|
||||
break
|
||||
}
|
||||
ctx.progress(1) // skip sequence token
|
||||
}
|
||||
value, err := p.parseToken(ctx.withIndex(uint(len(sequenceNode.Values))), ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse sequence")
|
||||
}
|
||||
if comment != nil {
|
||||
comment.SetPath(ctx.withIndex(uint(len(sequenceNode.Values))).path)
|
||||
sequenceNode.ValueHeadComments = append(sequenceNode.ValueHeadComments, comment)
|
||||
} else {
|
||||
sequenceNode.ValueHeadComments = append(sequenceNode.ValueHeadComments, nil)
|
||||
}
|
||||
sequenceNode.Values = append(sequenceNode.Values, value)
|
||||
tk = ctx.nextNotCommentToken()
|
||||
if tk == nil {
|
||||
break
|
||||
}
|
||||
if tk.Type != token.SequenceEntryType {
|
||||
break
|
||||
}
|
||||
if tk.Position.Column != curColumn {
|
||||
break
|
||||
}
|
||||
ctx.progressIgnoreComment(1)
|
||||
}
|
||||
commentTk := ctx.nextToken()
|
||||
if commentTk != nil && commentTk.Type == token.CommentType && curColumn <= commentTk.Position.Column {
|
||||
// If the comment is in the same or deeper column as the last element column in sequence value,
|
||||
// treat it as a footer comment for the last element.
|
||||
comment := p.parseFootComment(ctx, curColumn)
|
||||
sequenceNode.FootComment = comment
|
||||
}
|
||||
return sequenceNode, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseAnchor(ctx *context) (*ast.AnchorNode, error) {
|
||||
tk := ctx.currentToken()
|
||||
anchor := ast.Anchor(tk)
|
||||
anchor.SetPath(ctx.path)
|
||||
ntk := ctx.nextToken()
|
||||
if ntk == nil {
|
||||
return nil, errors.ErrSyntax("unexpected anchor. anchor name is undefined", tk)
|
||||
}
|
||||
ctx.progress(1) // skip anchor token
|
||||
name, err := p.parseToken(ctx, ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parser anchor name node")
|
||||
}
|
||||
anchor.Name = name
|
||||
ntk = ctx.nextToken()
|
||||
if ntk == nil {
|
||||
return nil, errors.ErrSyntax("unexpected anchor. anchor value is undefined", ctx.currentToken())
|
||||
}
|
||||
ctx.progress(1)
|
||||
value, err := p.parseToken(ctx, ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parser anchor name node")
|
||||
}
|
||||
anchor.Value = value
|
||||
return anchor, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseAlias(ctx *context) (*ast.AliasNode, error) {
|
||||
tk := ctx.currentToken()
|
||||
alias := ast.Alias(tk)
|
||||
alias.SetPath(ctx.path)
|
||||
ntk := ctx.nextToken()
|
||||
if ntk == nil {
|
||||
return nil, errors.ErrSyntax("unexpected alias. alias name is undefined", tk)
|
||||
}
|
||||
ctx.progress(1) // skip alias token
|
||||
name, err := p.parseToken(ctx, ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parser alias name node")
|
||||
}
|
||||
alias.Value = name
|
||||
return alias, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseMapKey(ctx *context) (ast.MapKeyNode, error) {
|
||||
tk := ctx.currentToken()
|
||||
if value := p.parseScalarValue(tk); value != nil {
|
||||
return value, nil
|
||||
}
|
||||
switch tk.Type {
|
||||
case token.MergeKeyType:
|
||||
return ast.MergeKey(tk), nil
|
||||
case token.MappingKeyType:
|
||||
return p.parseMappingKey(ctx)
|
||||
}
|
||||
return nil, errors.ErrSyntax("unexpected mapping key", tk)
|
||||
}
|
||||
|
||||
func (p *parser) parseStringValue(tk *token.Token) *ast.StringNode {
|
||||
switch tk.Type {
|
||||
case token.StringType,
|
||||
token.SingleQuoteType,
|
||||
token.DoubleQuoteType:
|
||||
return ast.String(tk)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *parser) parseScalarValueWithComment(ctx *context, tk *token.Token) (ast.ScalarNode, error) {
|
||||
node := p.parseScalarValue(tk)
|
||||
if node == nil {
|
||||
return nil, nil
|
||||
}
|
||||
node.SetPath(ctx.path)
|
||||
if p.isSameLineComment(ctx.nextToken(), node) {
|
||||
ctx.progress(1)
|
||||
if err := p.setSameLineCommentIfExists(ctx, node); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to set same line comment to node")
|
||||
}
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseScalarValue(tk *token.Token) ast.ScalarNode {
|
||||
if node := p.parseStringValue(tk); node != nil {
|
||||
return node
|
||||
}
|
||||
switch tk.Type {
|
||||
case token.NullType:
|
||||
return ast.Null(tk)
|
||||
case token.BoolType:
|
||||
return ast.Bool(tk)
|
||||
case token.IntegerType,
|
||||
token.BinaryIntegerType,
|
||||
token.OctetIntegerType,
|
||||
token.HexIntegerType:
|
||||
return ast.Integer(tk)
|
||||
case token.FloatType:
|
||||
return ast.Float(tk)
|
||||
case token.InfinityType:
|
||||
return ast.Infinity(tk)
|
||||
case token.NanType:
|
||||
return ast.Nan(tk)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *parser) parseDirective(ctx *context) (*ast.DirectiveNode, error) {
|
||||
node := ast.Directive(ctx.currentToken())
|
||||
ctx.progress(1) // skip directive token
|
||||
value, err := p.parseToken(ctx, ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse directive value")
|
||||
}
|
||||
node.Value = value
|
||||
ctx.progress(1)
|
||||
tk := ctx.currentToken()
|
||||
if tk == nil {
|
||||
// Since current token is nil, use the previous token to specify
|
||||
// the syntax error location.
|
||||
return nil, errors.ErrSyntax("unexpected directive value. document not started", ctx.previousToken())
|
||||
}
|
||||
if tk.Type != token.DocumentHeaderType {
|
||||
return nil, errors.ErrSyntax("unexpected directive value. document not started", ctx.currentToken())
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseLiteral(ctx *context) (*ast.LiteralNode, error) {
|
||||
node := ast.Literal(ctx.currentToken())
|
||||
ctx.progress(1) // skip literal/folded token
|
||||
|
||||
tk := ctx.currentToken()
|
||||
var comment *ast.CommentGroupNode
|
||||
if tk.Type == token.CommentType {
|
||||
comment = p.parseCommentOnly(ctx)
|
||||
comment.SetPath(ctx.path)
|
||||
if err := node.SetComment(comment); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to set comment to literal")
|
||||
}
|
||||
tk = ctx.currentToken()
|
||||
}
|
||||
value, err := p.parseToken(ctx, tk)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse literal/folded value")
|
||||
}
|
||||
snode, ok := value.(*ast.StringNode)
|
||||
if !ok {
|
||||
return nil, errors.ErrSyntax("unexpected token. required string token", value.GetToken())
|
||||
}
|
||||
node.Value = snode
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *parser) isSameLineComment(tk *token.Token, node ast.Node) bool {
|
||||
if tk == nil {
|
||||
return false
|
||||
}
|
||||
if tk.Type != token.CommentType {
|
||||
return false
|
||||
}
|
||||
return tk.Position.Line == node.GetToken().Position.Line
|
||||
}
|
||||
|
||||
func (p *parser) setSameLineCommentIfExists(ctx *context, node ast.Node) error {
|
||||
tk := ctx.currentToken()
|
||||
if !p.isSameLineComment(tk, node) {
|
||||
return nil
|
||||
}
|
||||
comment := ast.CommentGroup([]*token.Token{tk})
|
||||
comment.SetPath(ctx.path)
|
||||
if err := node.SetComment(comment); err != nil {
|
||||
return errors.Wrapf(err, "failed to set comment token to ast.Node")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *parser) parseDocument(ctx *context) (*ast.DocumentNode, error) {
|
||||
startTk := ctx.currentToken()
|
||||
ctx.progress(1) // skip document header token
|
||||
body, err := p.parseToken(ctx, ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse document body")
|
||||
}
|
||||
node := ast.Document(startTk, body)
|
||||
if ntk := ctx.nextToken(); ntk != nil && ntk.Type == token.DocumentEndType {
|
||||
node.End = ntk
|
||||
ctx.progress(1)
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseCommentOnly(ctx *context) *ast.CommentGroupNode {
|
||||
commentTokens := []*token.Token{}
|
||||
for {
|
||||
tk := ctx.currentToken()
|
||||
if tk == nil {
|
||||
break
|
||||
}
|
||||
if tk.Type != token.CommentType {
|
||||
break
|
||||
}
|
||||
commentTokens = append(commentTokens, tk)
|
||||
ctx.progressIgnoreComment(1) // skip comment token
|
||||
}
|
||||
return ast.CommentGroup(commentTokens)
|
||||
}
|
||||
|
||||
func (p *parser) parseFootComment(ctx *context, col int) *ast.CommentGroupNode {
|
||||
commentTokens := []*token.Token{}
|
||||
for {
|
||||
ctx.progressIgnoreComment(1)
|
||||
commentTokens = append(commentTokens, ctx.currentToken())
|
||||
|
||||
nextTk := ctx.nextToken()
|
||||
if nextTk == nil {
|
||||
break
|
||||
}
|
||||
if nextTk.Type != token.CommentType {
|
||||
break
|
||||
}
|
||||
if col > nextTk.Position.Column {
|
||||
break
|
||||
}
|
||||
}
|
||||
return ast.CommentGroup(commentTokens)
|
||||
}
|
||||
|
||||
func (p *parser) parseComment(ctx *context) (ast.Node, error) {
|
||||
group := p.parseCommentOnly(ctx)
|
||||
node, err := p.parseToken(ctx, ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse node after comment")
|
||||
}
|
||||
if node == nil {
|
||||
return group, nil
|
||||
}
|
||||
group.SetPath(node.GetPath())
|
||||
if err := node.SetComment(group); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to set comment token to node")
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseMappingKey(ctx *context) (*ast.MappingKeyNode, error) {
|
||||
keyTk := ctx.currentToken()
|
||||
node := ast.MappingKey(keyTk)
|
||||
node.SetPath(ctx.path)
|
||||
ctx.progress(1) // skip mapping key token
|
||||
value, err := p.parseToken(ctx.withChild(keyTk.Value), ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse map key")
|
||||
}
|
||||
node.Value = value
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseToken(ctx *context, tk *token.Token) (ast.Node, error) {
|
||||
node, err := p.createNodeFromToken(ctx, tk)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create node from token")
|
||||
}
|
||||
if node != nil && node.GetPath() == "" {
|
||||
node.SetPath(ctx.path)
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (p *parser) createNodeFromToken(ctx *context, tk *token.Token) (ast.Node, error) {
|
||||
if tk == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if tk.NextType() == token.MappingValueType {
|
||||
node, err := p.parseMappingValue(ctx)
|
||||
return node, err
|
||||
}
|
||||
node, err := p.parseScalarValueWithComment(ctx, tk)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse scalar value")
|
||||
}
|
||||
if node != nil {
|
||||
return node, nil
|
||||
}
|
||||
switch tk.Type {
|
||||
case token.CommentType:
|
||||
return p.parseComment(ctx)
|
||||
case token.MappingKeyType:
|
||||
return p.parseMappingKey(ctx)
|
||||
case token.DocumentHeaderType:
|
||||
return p.parseDocument(ctx)
|
||||
case token.MappingStartType:
|
||||
return p.parseMapping(ctx)
|
||||
case token.SequenceStartType:
|
||||
return p.parseSequence(ctx)
|
||||
case token.SequenceEntryType:
|
||||
return p.parseSequenceEntry(ctx)
|
||||
case token.AnchorType:
|
||||
return p.parseAnchor(ctx)
|
||||
case token.AliasType:
|
||||
return p.parseAlias(ctx)
|
||||
case token.DirectiveType:
|
||||
return p.parseDirective(ctx)
|
||||
case token.TagType:
|
||||
return p.parseTag(ctx)
|
||||
case token.LiteralType, token.FoldedType:
|
||||
return p.parseLiteral(ctx)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (p *parser) parse(tokens token.Tokens, mode Mode) (*ast.File, error) {
|
||||
ctx := newContext(tokens, mode)
|
||||
file := &ast.File{Docs: []*ast.DocumentNode{}}
|
||||
for ctx.next() {
|
||||
node, err := p.parseToken(ctx, ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse")
|
||||
}
|
||||
ctx.progressIgnoreComment(1)
|
||||
if node == nil {
|
||||
continue
|
||||
}
|
||||
if doc, ok := node.(*ast.DocumentNode); ok {
|
||||
file.Docs = append(file.Docs, doc)
|
||||
} else {
|
||||
file.Docs = append(file.Docs, ast.Document(nil, node))
|
||||
}
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
type Mode uint
|
||||
|
||||
const (
|
||||
ParseComments Mode = 1 << iota // parse comments and add them to AST
|
||||
)
|
||||
|
||||
// ParseBytes parse from byte slice, and returns ast.File
|
||||
func ParseBytes(bytes []byte, mode Mode) (*ast.File, error) {
|
||||
tokens := lexer.Tokenize(string(bytes))
|
||||
f, err := Parse(tokens, mode)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse")
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Parse parse from token instances, and returns ast.File
|
||||
func Parse(tokens token.Tokens, mode Mode) (*ast.File, error) {
|
||||
var p parser
|
||||
f, err := p.parse(tokens, mode)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse")
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Parse parse from filename, and returns ast.File
|
||||
func ParseFile(filename string, mode Mode) (*ast.File, error) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to read file: %s", filename)
|
||||
}
|
||||
f, err := ParseBytes(file, mode)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse")
|
||||
}
|
||||
f.Name = filename
|
||||
return f, nil
|
||||
}
|
||||
794
vendor/github.com/goccy/go-yaml/path.go
generated
vendored
Normal file
794
vendor/github.com/goccy/go-yaml/path.go
generated
vendored
Normal file
|
|
@ -0,0 +1,794 @@
|
|||
package yaml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/goccy/go-yaml/ast"
|
||||
"github.com/goccy/go-yaml/internal/errors"
|
||||
"github.com/goccy/go-yaml/parser"
|
||||
"github.com/goccy/go-yaml/printer"
|
||||
)
|
||||
|
||||
// PathString create Path from string
|
||||
//
|
||||
// YAMLPath rule
|
||||
// $ : the root object/element
|
||||
// . : child operator
|
||||
// .. : recursive descent
|
||||
// [num] : object/element of array by number
|
||||
// [*] : all objects/elements for array.
|
||||
//
|
||||
// If you want to use reserved characters such as `.` and `*` as a key name,
|
||||
// enclose them in single quotation as follows ( $.foo.'bar.baz-*'.hoge ).
|
||||
// If you want to use a single quote with reserved characters, escape it with `\` ( $.foo.'bar.baz\'s value'.hoge ).
|
||||
func PathString(s string) (*Path, error) {
|
||||
buf := []rune(s)
|
||||
length := len(buf)
|
||||
cursor := 0
|
||||
builder := &PathBuilder{}
|
||||
for cursor < length {
|
||||
c := buf[cursor]
|
||||
switch c {
|
||||
case '$':
|
||||
builder = builder.Root()
|
||||
cursor++
|
||||
case '.':
|
||||
b, buf, c, err := parsePathDot(builder, buf, cursor)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse path of dot")
|
||||
}
|
||||
length = len(buf)
|
||||
builder = b
|
||||
cursor = c
|
||||
case '[':
|
||||
b, buf, c, err := parsePathIndex(builder, buf, cursor)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse path of index")
|
||||
}
|
||||
length = len(buf)
|
||||
builder = b
|
||||
cursor = c
|
||||
default:
|
||||
return nil, errors.Wrapf(ErrInvalidPathString, "invalid path at %d", cursor)
|
||||
}
|
||||
}
|
||||
return builder.Build(), nil
|
||||
}
|
||||
|
||||
func parsePathRecursive(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
|
||||
length := len(buf)
|
||||
cursor += 2 // skip .. characters
|
||||
start := cursor
|
||||
for ; cursor < length; cursor++ {
|
||||
c := buf[cursor]
|
||||
switch c {
|
||||
case '$':
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '$' after '..' character")
|
||||
case '*':
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '*' after '..' character")
|
||||
case '.', '[':
|
||||
goto end
|
||||
case ']':
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified ']' after '..' character")
|
||||
}
|
||||
}
|
||||
end:
|
||||
if start == cursor {
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "not found recursive selector")
|
||||
}
|
||||
return b.Recursive(string(buf[start:cursor])), buf, cursor, nil
|
||||
}
|
||||
|
||||
func parsePathDot(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
|
||||
length := len(buf)
|
||||
if cursor+1 < length && buf[cursor+1] == '.' {
|
||||
b, buf, c, err := parsePathRecursive(b, buf, cursor)
|
||||
if err != nil {
|
||||
return nil, nil, 0, errors.Wrapf(err, "failed to parse path of recursive")
|
||||
}
|
||||
return b, buf, c, nil
|
||||
}
|
||||
cursor++ // skip . character
|
||||
start := cursor
|
||||
|
||||
// if started single quote, looking for end single quote char
|
||||
if cursor < length && buf[cursor] == '\'' {
|
||||
return parseQuotedKey(b, buf, cursor)
|
||||
}
|
||||
for ; cursor < length; cursor++ {
|
||||
c := buf[cursor]
|
||||
switch c {
|
||||
case '$':
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '$' after '.' character")
|
||||
case '*':
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '*' after '.' character")
|
||||
case '.', '[':
|
||||
goto end
|
||||
case ']':
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified ']' after '.' character")
|
||||
}
|
||||
}
|
||||
end:
|
||||
if start == cursor {
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "cloud not find by empty key")
|
||||
}
|
||||
return b.child(string(buf[start:cursor])), buf, cursor, nil
|
||||
}
|
||||
|
||||
func parseQuotedKey(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
|
||||
cursor++ // skip single quote
|
||||
start := cursor
|
||||
length := len(buf)
|
||||
var foundEndDelim bool
|
||||
for ; cursor < length; cursor++ {
|
||||
switch buf[cursor] {
|
||||
case '\\':
|
||||
buf = append(append([]rune{}, buf[:cursor]...), buf[cursor+1:]...)
|
||||
length = len(buf)
|
||||
case '\'':
|
||||
foundEndDelim = true
|
||||
goto end
|
||||
}
|
||||
}
|
||||
end:
|
||||
if !foundEndDelim {
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "could not find end delimiter for key")
|
||||
}
|
||||
if start == cursor {
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "could not find by empty key")
|
||||
}
|
||||
selector := buf[start:cursor]
|
||||
cursor++
|
||||
if cursor < length {
|
||||
switch buf[cursor] {
|
||||
case '$':
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '$' after '.' character")
|
||||
case '*':
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '*' after '.' character")
|
||||
case ']':
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified ']' after '.' character")
|
||||
}
|
||||
}
|
||||
return b.child(string(selector)), buf, cursor, nil
|
||||
}
|
||||
|
||||
func parsePathIndex(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
|
||||
length := len(buf)
|
||||
cursor++ // skip '[' character
|
||||
if length <= cursor {
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "unexpected end of YAML Path")
|
||||
}
|
||||
c := buf[cursor]
|
||||
switch c {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*':
|
||||
start := cursor
|
||||
cursor++
|
||||
for ; cursor < length; cursor++ {
|
||||
c := buf[cursor]
|
||||
switch c {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
if buf[cursor] != ']' {
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "invalid character %s at %d", string(buf[cursor]), cursor)
|
||||
}
|
||||
numOrAll := string(buf[start:cursor])
|
||||
if numOrAll == "*" {
|
||||
return b.IndexAll(), buf, cursor + 1, nil
|
||||
}
|
||||
num, err := strconv.ParseInt(numOrAll, 10, 64)
|
||||
if err != nil {
|
||||
return nil, nil, 0, errors.Wrapf(err, "failed to parse number")
|
||||
}
|
||||
return b.Index(uint(num)), buf, cursor + 1, nil
|
||||
}
|
||||
return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "invalid character %s at %d", c, cursor)
|
||||
}
|
||||
|
||||
// Path represent YAMLPath ( like a JSONPath ).
|
||||
type Path struct {
|
||||
node pathNode
|
||||
}
|
||||
|
||||
// String path to text.
|
||||
func (p *Path) String() string {
|
||||
return p.node.String()
|
||||
}
|
||||
|
||||
// Read decode from r and set extracted value by YAMLPath to v.
|
||||
func (p *Path) Read(r io.Reader, v interface{}) error {
|
||||
node, err := p.ReadNode(r)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to read node")
|
||||
}
|
||||
if err := Unmarshal([]byte(node.String()), v); err != nil {
|
||||
return errors.Wrapf(err, "failed to unmarshal")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadNode create AST from r and extract node by YAMLPath.
|
||||
func (p *Path) ReadNode(r io.Reader) (ast.Node, error) {
|
||||
if p.node == nil {
|
||||
return nil, ErrInvalidPath
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if _, err := io.Copy(&buf, r); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to copy from reader")
|
||||
}
|
||||
f, err := parser.ParseBytes(buf.Bytes(), 0)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse yaml")
|
||||
}
|
||||
node, err := p.FilterFile(f)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter from ast.File")
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// Filter filter from target by YAMLPath and set it to v.
|
||||
func (p *Path) Filter(target, v interface{}) error {
|
||||
b, err := Marshal(target)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to marshal target value")
|
||||
}
|
||||
if err := p.Read(bytes.NewBuffer(b), v); err != nil {
|
||||
return errors.Wrapf(err, "failed to read")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FilterFile filter from ast.File by YAMLPath.
|
||||
func (p *Path) FilterFile(f *ast.File) (ast.Node, error) {
|
||||
for _, doc := range f.Docs {
|
||||
node, err := p.FilterNode(doc.Body)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter node by path ( %s )", p.node)
|
||||
}
|
||||
if node != nil {
|
||||
return node, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.Wrapf(ErrNotFoundNode, "failed to find path ( %s )", p.node)
|
||||
}
|
||||
|
||||
// FilterNode filter from node by YAMLPath.
|
||||
func (p *Path) FilterNode(node ast.Node) (ast.Node, error) {
|
||||
n, err := p.node.filter(node)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter node by path ( %s )", p.node)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// MergeFromReader merge YAML text into ast.File.
|
||||
func (p *Path) MergeFromReader(dst *ast.File, src io.Reader) error {
|
||||
var buf bytes.Buffer
|
||||
if _, err := io.Copy(&buf, src); err != nil {
|
||||
return errors.Wrapf(err, "failed to copy from reader")
|
||||
}
|
||||
file, err := parser.ParseBytes(buf.Bytes(), 0)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse")
|
||||
}
|
||||
if err := p.MergeFromFile(dst, file); err != nil {
|
||||
return errors.Wrapf(err, "failed to merge file")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MergeFromFile merge ast.File into ast.File.
|
||||
func (p *Path) MergeFromFile(dst *ast.File, src *ast.File) error {
|
||||
base, err := p.FilterFile(dst)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to filter file")
|
||||
}
|
||||
for _, doc := range src.Docs {
|
||||
if err := ast.Merge(base, doc); err != nil {
|
||||
return errors.Wrapf(err, "failed to merge")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MergeFromNode merge ast.Node into ast.File.
|
||||
func (p *Path) MergeFromNode(dst *ast.File, src ast.Node) error {
|
||||
base, err := p.FilterFile(dst)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to filter file")
|
||||
}
|
||||
if err := ast.Merge(base, src); err != nil {
|
||||
return errors.Wrapf(err, "failed to merge")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReplaceWithReader replace ast.File with io.Reader.
|
||||
func (p *Path) ReplaceWithReader(dst *ast.File, src io.Reader) error {
|
||||
var buf bytes.Buffer
|
||||
if _, err := io.Copy(&buf, src); err != nil {
|
||||
return errors.Wrapf(err, "failed to copy from reader")
|
||||
}
|
||||
file, err := parser.ParseBytes(buf.Bytes(), 0)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse")
|
||||
}
|
||||
if err := p.ReplaceWithFile(dst, file); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace file")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReplaceWithFile replace ast.File with ast.File.
|
||||
func (p *Path) ReplaceWithFile(dst *ast.File, src *ast.File) error {
|
||||
for _, doc := range src.Docs {
|
||||
if err := p.ReplaceWithNode(dst, doc); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace file by path ( %s )", p.node)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReplaceNode replace ast.File with ast.Node.
|
||||
func (p *Path) ReplaceWithNode(dst *ast.File, node ast.Node) error {
|
||||
for _, doc := range dst.Docs {
|
||||
if node.Type() == ast.DocumentType {
|
||||
node = node.(*ast.DocumentNode).Body
|
||||
}
|
||||
if err := p.node.replace(doc.Body, node); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace node by path ( %s )", p.node)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AnnotateSource add annotation to passed source ( see section 5.1 in README.md ).
|
||||
func (p *Path) AnnotateSource(source []byte, colored bool) ([]byte, error) {
|
||||
file, err := parser.ParseBytes([]byte(source), 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node, err := p.FilterFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pp printer.Printer
|
||||
return []byte(pp.PrintErrorToken(node.GetToken(), colored)), nil
|
||||
}
|
||||
|
||||
// PathBuilder represent builder for YAMLPath.
|
||||
type PathBuilder struct {
|
||||
root *rootNode
|
||||
node pathNode
|
||||
}
|
||||
|
||||
// Root add '$' to current path.
|
||||
func (b *PathBuilder) Root() *PathBuilder {
|
||||
root := newRootNode()
|
||||
return &PathBuilder{root: root, node: root}
|
||||
}
|
||||
|
||||
// IndexAll add '[*]' to current path.
|
||||
func (b *PathBuilder) IndexAll() *PathBuilder {
|
||||
b.node = b.node.chain(newIndexAllNode())
|
||||
return b
|
||||
}
|
||||
|
||||
// Recursive add '..selector' to current path.
|
||||
func (b *PathBuilder) Recursive(selector string) *PathBuilder {
|
||||
b.node = b.node.chain(newRecursiveNode(selector))
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *PathBuilder) containsReservedPathCharacters(path string) bool {
|
||||
if strings.Contains(path, ".") {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(path, "*") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *PathBuilder) enclosedSingleQuote(name string) bool {
|
||||
return strings.HasPrefix(name, "'") && strings.HasSuffix(name, "'")
|
||||
}
|
||||
|
||||
func (b *PathBuilder) normalizeSelectorName(name string) string {
|
||||
if b.enclosedSingleQuote(name) {
|
||||
// already escaped name
|
||||
return name
|
||||
}
|
||||
if b.containsReservedPathCharacters(name) {
|
||||
escapedName := strings.ReplaceAll(name, `'`, `\'`)
|
||||
return "'" + escapedName + "'"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func (b *PathBuilder) child(name string) *PathBuilder {
|
||||
b.node = b.node.chain(newSelectorNode(name))
|
||||
return b
|
||||
}
|
||||
|
||||
// Child add '.name' to current path.
|
||||
func (b *PathBuilder) Child(name string) *PathBuilder {
|
||||
return b.child(b.normalizeSelectorName(name))
|
||||
}
|
||||
|
||||
// Index add '[idx]' to current path.
|
||||
func (b *PathBuilder) Index(idx uint) *PathBuilder {
|
||||
b.node = b.node.chain(newIndexNode(idx))
|
||||
return b
|
||||
}
|
||||
|
||||
// Build build YAMLPath.
|
||||
func (b *PathBuilder) Build() *Path {
|
||||
return &Path{node: b.root}
|
||||
}
|
||||
|
||||
type pathNode interface {
|
||||
fmt.Stringer
|
||||
chain(pathNode) pathNode
|
||||
filter(ast.Node) (ast.Node, error)
|
||||
replace(ast.Node, ast.Node) error
|
||||
}
|
||||
|
||||
type basePathNode struct {
|
||||
child pathNode
|
||||
}
|
||||
|
||||
func (n *basePathNode) chain(node pathNode) pathNode {
|
||||
n.child = node
|
||||
return node
|
||||
}
|
||||
|
||||
type rootNode struct {
|
||||
*basePathNode
|
||||
}
|
||||
|
||||
func newRootNode() *rootNode {
|
||||
return &rootNode{basePathNode: &basePathNode{}}
|
||||
}
|
||||
|
||||
func (n *rootNode) String() string {
|
||||
s := "$"
|
||||
if n.child != nil {
|
||||
s += n.child.String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (n *rootNode) filter(node ast.Node) (ast.Node, error) {
|
||||
if n.child == nil {
|
||||
return nil, nil
|
||||
}
|
||||
filtered, err := n.child.filter(node)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter")
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
func (n *rootNode) replace(node ast.Node, target ast.Node) error {
|
||||
if n.child == nil {
|
||||
return nil
|
||||
}
|
||||
if err := n.child.replace(node, target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type selectorNode struct {
|
||||
*basePathNode
|
||||
selector string
|
||||
}
|
||||
|
||||
func newSelectorNode(selector string) *selectorNode {
|
||||
return &selectorNode{
|
||||
basePathNode: &basePathNode{},
|
||||
selector: selector,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *selectorNode) filter(node ast.Node) (ast.Node, error) {
|
||||
switch node.Type() {
|
||||
case ast.MappingType:
|
||||
for _, value := range node.(*ast.MappingNode).Values {
|
||||
key := value.Key.GetToken().Value
|
||||
if key == n.selector {
|
||||
if n.child == nil {
|
||||
return value.Value, nil
|
||||
}
|
||||
filtered, err := n.child.filter(value.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter")
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
}
|
||||
case ast.MappingValueType:
|
||||
value := node.(*ast.MappingValueNode)
|
||||
key := value.Key.GetToken().Value
|
||||
if key == n.selector {
|
||||
if n.child == nil {
|
||||
return value.Value, nil
|
||||
}
|
||||
filtered, err := n.child.filter(value.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter")
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
default:
|
||||
return nil, errors.Wrapf(ErrInvalidQuery, "expected node type is map or map value. but got %s", node.Type())
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (n *selectorNode) replaceMapValue(value *ast.MappingValueNode, target ast.Node) error {
|
||||
key := value.Key.GetToken().Value
|
||||
if key != n.selector {
|
||||
return nil
|
||||
}
|
||||
if n.child == nil {
|
||||
if err := value.Replace(target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
} else {
|
||||
if err := n.child.replace(value.Value, target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *selectorNode) replace(node ast.Node, target ast.Node) error {
|
||||
switch node.Type() {
|
||||
case ast.MappingType:
|
||||
for _, value := range node.(*ast.MappingNode).Values {
|
||||
if err := n.replaceMapValue(value, target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace map value")
|
||||
}
|
||||
}
|
||||
case ast.MappingValueType:
|
||||
value := node.(*ast.MappingValueNode)
|
||||
if err := n.replaceMapValue(value, target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace map value")
|
||||
}
|
||||
default:
|
||||
return errors.Wrapf(ErrInvalidQuery, "expected node type is map or map value. but got %s", node.Type())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *selectorNode) String() string {
|
||||
s := fmt.Sprintf(".%s", n.selector)
|
||||
if n.child != nil {
|
||||
s += n.child.String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type indexNode struct {
|
||||
*basePathNode
|
||||
selector uint
|
||||
}
|
||||
|
||||
func newIndexNode(selector uint) *indexNode {
|
||||
return &indexNode{
|
||||
basePathNode: &basePathNode{},
|
||||
selector: selector,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *indexNode) filter(node ast.Node) (ast.Node, error) {
|
||||
if node.Type() != ast.SequenceType {
|
||||
return nil, errors.Wrapf(ErrInvalidQuery, "expected sequence type node. but got %s", node.Type())
|
||||
}
|
||||
sequence := node.(*ast.SequenceNode)
|
||||
if n.selector >= uint(len(sequence.Values)) {
|
||||
return nil, errors.Wrapf(ErrInvalidQuery, "expected index is %d. but got sequences has %d items", n.selector, sequence.Values)
|
||||
}
|
||||
value := sequence.Values[n.selector]
|
||||
if n.child == nil {
|
||||
return value, nil
|
||||
}
|
||||
filtered, err := n.child.filter(value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter")
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
func (n *indexNode) replace(node ast.Node, target ast.Node) error {
|
||||
if node.Type() != ast.SequenceType {
|
||||
return errors.Wrapf(ErrInvalidQuery, "expected sequence type node. but got %s", node.Type())
|
||||
}
|
||||
sequence := node.(*ast.SequenceNode)
|
||||
if n.selector >= uint(len(sequence.Values)) {
|
||||
return errors.Wrapf(ErrInvalidQuery, "expected index is %d. but got sequences has %d items", n.selector, sequence.Values)
|
||||
}
|
||||
if n.child == nil {
|
||||
if err := sequence.Replace(int(n.selector), target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := n.child.replace(sequence.Values[n.selector], target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *indexNode) String() string {
|
||||
s := fmt.Sprintf("[%d]", n.selector)
|
||||
if n.child != nil {
|
||||
s += n.child.String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type indexAllNode struct {
|
||||
*basePathNode
|
||||
}
|
||||
|
||||
func newIndexAllNode() *indexAllNode {
|
||||
return &indexAllNode{
|
||||
basePathNode: &basePathNode{},
|
||||
}
|
||||
}
|
||||
|
||||
func (n *indexAllNode) String() string {
|
||||
s := "[*]"
|
||||
if n.child != nil {
|
||||
s += n.child.String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (n *indexAllNode) filter(node ast.Node) (ast.Node, error) {
|
||||
if node.Type() != ast.SequenceType {
|
||||
return nil, errors.Wrapf(ErrInvalidQuery, "expected sequence type node. but got %s", node.Type())
|
||||
}
|
||||
sequence := node.(*ast.SequenceNode)
|
||||
if n.child == nil {
|
||||
return sequence, nil
|
||||
}
|
||||
out := *sequence
|
||||
out.Values = []ast.Node{}
|
||||
for _, value := range sequence.Values {
|
||||
filtered, err := n.child.filter(value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter")
|
||||
}
|
||||
out.Values = append(out.Values, filtered)
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
func (n *indexAllNode) replace(node ast.Node, target ast.Node) error {
|
||||
if node.Type() != ast.SequenceType {
|
||||
return errors.Wrapf(ErrInvalidQuery, "expected sequence type node. but got %s", node.Type())
|
||||
}
|
||||
sequence := node.(*ast.SequenceNode)
|
||||
if n.child == nil {
|
||||
for idx := range sequence.Values {
|
||||
if err := sequence.Replace(idx, target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
for _, value := range sequence.Values {
|
||||
if err := n.child.replace(value, target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type recursiveNode struct {
|
||||
*basePathNode
|
||||
selector string
|
||||
}
|
||||
|
||||
func newRecursiveNode(selector string) *recursiveNode {
|
||||
return &recursiveNode{
|
||||
basePathNode: &basePathNode{},
|
||||
selector: selector,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *recursiveNode) String() string {
|
||||
s := fmt.Sprintf("..%s", n.selector)
|
||||
if n.child != nil {
|
||||
s += n.child.String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (n *recursiveNode) filterNode(node ast.Node) (*ast.SequenceNode, error) {
|
||||
sequence := &ast.SequenceNode{BaseNode: &ast.BaseNode{}}
|
||||
switch typedNode := node.(type) {
|
||||
case *ast.MappingNode:
|
||||
for _, value := range typedNode.Values {
|
||||
seq, err := n.filterNode(value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter")
|
||||
}
|
||||
sequence.Values = append(sequence.Values, seq.Values...)
|
||||
}
|
||||
case *ast.MappingValueNode:
|
||||
key := typedNode.Key.GetToken().Value
|
||||
if n.selector == key {
|
||||
sequence.Values = append(sequence.Values, typedNode.Value)
|
||||
}
|
||||
seq, err := n.filterNode(typedNode.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter")
|
||||
}
|
||||
sequence.Values = append(sequence.Values, seq.Values...)
|
||||
case *ast.SequenceNode:
|
||||
for _, value := range typedNode.Values {
|
||||
seq, err := n.filterNode(value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter")
|
||||
}
|
||||
sequence.Values = append(sequence.Values, seq.Values...)
|
||||
}
|
||||
}
|
||||
return sequence, nil
|
||||
}
|
||||
|
||||
func (n *recursiveNode) filter(node ast.Node) (ast.Node, error) {
|
||||
sequence, err := n.filterNode(node)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to filter")
|
||||
}
|
||||
sequence.Start = node.GetToken()
|
||||
return sequence, nil
|
||||
}
|
||||
|
||||
func (n *recursiveNode) replaceNode(node ast.Node, target ast.Node) error {
|
||||
switch typedNode := node.(type) {
|
||||
case *ast.MappingNode:
|
||||
for _, value := range typedNode.Values {
|
||||
if err := n.replaceNode(value, target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
}
|
||||
case *ast.MappingValueNode:
|
||||
key := typedNode.Key.GetToken().Value
|
||||
if n.selector == key {
|
||||
if err := typedNode.Replace(target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
}
|
||||
if err := n.replaceNode(typedNode.Value, target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
case *ast.SequenceNode:
|
||||
for _, value := range typedNode.Values {
|
||||
if err := n.replaceNode(value, target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *recursiveNode) replace(node ast.Node, target ast.Node) error {
|
||||
if err := n.replaceNode(node, target); err != nil {
|
||||
return errors.Wrapf(err, "failed to replace")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
352
vendor/github.com/goccy/go-yaml/printer/printer.go
generated
vendored
Normal file
352
vendor/github.com/goccy/go-yaml/printer/printer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
package printer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/goccy/go-yaml/ast"
|
||||
"github.com/goccy/go-yaml/token"
|
||||
)
|
||||
|
||||
// Property additional property set for each the token
|
||||
type Property struct {
|
||||
Prefix string
|
||||
Suffix string
|
||||
}
|
||||
|
||||
// PrintFunc returns property instance
|
||||
type PrintFunc func() *Property
|
||||
|
||||
// Printer create text from token collection or ast
|
||||
type Printer struct {
|
||||
LineNumber bool
|
||||
LineNumberFormat func(num int) string
|
||||
MapKey PrintFunc
|
||||
Anchor PrintFunc
|
||||
Alias PrintFunc
|
||||
Bool PrintFunc
|
||||
String PrintFunc
|
||||
Number PrintFunc
|
||||
}
|
||||
|
||||
func defaultLineNumberFormat(num int) string {
|
||||
return fmt.Sprintf("%2d | ", num)
|
||||
}
|
||||
|
||||
func (p *Printer) property(tk *token.Token) *Property {
|
||||
prop := &Property{}
|
||||
switch tk.PreviousType() {
|
||||
case token.AnchorType:
|
||||
if p.Anchor != nil {
|
||||
return p.Anchor()
|
||||
}
|
||||
return prop
|
||||
case token.AliasType:
|
||||
if p.Alias != nil {
|
||||
return p.Alias()
|
||||
}
|
||||
return prop
|
||||
}
|
||||
switch tk.NextType() {
|
||||
case token.MappingValueType:
|
||||
if p.MapKey != nil {
|
||||
return p.MapKey()
|
||||
}
|
||||
return prop
|
||||
}
|
||||
switch tk.Type {
|
||||
case token.BoolType:
|
||||
if p.Bool != nil {
|
||||
return p.Bool()
|
||||
}
|
||||
return prop
|
||||
case token.AnchorType:
|
||||
if p.Anchor != nil {
|
||||
return p.Anchor()
|
||||
}
|
||||
return prop
|
||||
case token.AliasType:
|
||||
if p.Anchor != nil {
|
||||
return p.Alias()
|
||||
}
|
||||
return prop
|
||||
case token.StringType, token.SingleQuoteType, token.DoubleQuoteType:
|
||||
if p.String != nil {
|
||||
return p.String()
|
||||
}
|
||||
return prop
|
||||
case token.IntegerType, token.FloatType:
|
||||
if p.Number != nil {
|
||||
return p.Number()
|
||||
}
|
||||
return prop
|
||||
default:
|
||||
}
|
||||
return prop
|
||||
}
|
||||
|
||||
// PrintTokens create text from token collection
|
||||
func (p *Printer) PrintTokens(tokens token.Tokens) string {
|
||||
if len(tokens) == 0 {
|
||||
return ""
|
||||
}
|
||||
if p.LineNumber {
|
||||
if p.LineNumberFormat == nil {
|
||||
p.LineNumberFormat = defaultLineNumberFormat
|
||||
}
|
||||
}
|
||||
texts := []string{}
|
||||
lineNumber := tokens[0].Position.Line
|
||||
for _, tk := range tokens {
|
||||
lines := strings.Split(tk.Origin, "\n")
|
||||
prop := p.property(tk)
|
||||
header := ""
|
||||
if p.LineNumber {
|
||||
header = p.LineNumberFormat(lineNumber)
|
||||
}
|
||||
if len(lines) == 1 {
|
||||
line := prop.Prefix + lines[0] + prop.Suffix
|
||||
if len(texts) == 0 {
|
||||
texts = append(texts, header+line)
|
||||
lineNumber++
|
||||
} else {
|
||||
text := texts[len(texts)-1]
|
||||
texts[len(texts)-1] = text + line
|
||||
}
|
||||
} else {
|
||||
for idx, src := range lines {
|
||||
if p.LineNumber {
|
||||
header = p.LineNumberFormat(lineNumber)
|
||||
}
|
||||
line := prop.Prefix + src + prop.Suffix
|
||||
if idx == 0 {
|
||||
if len(texts) == 0 {
|
||||
texts = append(texts, header+line)
|
||||
lineNumber++
|
||||
} else {
|
||||
text := texts[len(texts)-1]
|
||||
texts[len(texts)-1] = text + line
|
||||
}
|
||||
} else {
|
||||
texts = append(texts, fmt.Sprintf("%s%s", header, line))
|
||||
lineNumber++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(texts, "\n")
|
||||
}
|
||||
|
||||
// PrintNode create text from ast.Node
|
||||
func (p *Printer) PrintNode(node ast.Node) []byte {
|
||||
return []byte(fmt.Sprintf("%+v\n", node))
|
||||
}
|
||||
|
||||
const escape = "\x1b"
|
||||
|
||||
func format(attr color.Attribute) string {
|
||||
return fmt.Sprintf("%s[%dm", escape, attr)
|
||||
}
|
||||
|
||||
func (p *Printer) setDefaultColorSet() {
|
||||
p.Bool = func() *Property {
|
||||
return &Property{
|
||||
Prefix: format(color.FgHiMagenta),
|
||||
Suffix: format(color.Reset),
|
||||
}
|
||||
}
|
||||
p.Number = func() *Property {
|
||||
return &Property{
|
||||
Prefix: format(color.FgHiMagenta),
|
||||
Suffix: format(color.Reset),
|
||||
}
|
||||
}
|
||||
p.MapKey = func() *Property {
|
||||
return &Property{
|
||||
Prefix: format(color.FgHiCyan),
|
||||
Suffix: format(color.Reset),
|
||||
}
|
||||
}
|
||||
p.Anchor = func() *Property {
|
||||
return &Property{
|
||||
Prefix: format(color.FgHiYellow),
|
||||
Suffix: format(color.Reset),
|
||||
}
|
||||
}
|
||||
p.Alias = func() *Property {
|
||||
return &Property{
|
||||
Prefix: format(color.FgHiYellow),
|
||||
Suffix: format(color.Reset),
|
||||
}
|
||||
}
|
||||
p.String = func() *Property {
|
||||
return &Property{
|
||||
Prefix: format(color.FgHiGreen),
|
||||
Suffix: format(color.Reset),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Printer) PrintErrorMessage(msg string, isColored bool) string {
|
||||
if isColored {
|
||||
return fmt.Sprintf("%s%s%s",
|
||||
format(color.FgHiRed),
|
||||
msg,
|
||||
format(color.Reset),
|
||||
)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func (p *Printer) removeLeftSideNewLineChar(src string) string {
|
||||
return strings.TrimLeft(strings.TrimLeft(strings.TrimLeft(src, "\r"), "\n"), "\r\n")
|
||||
}
|
||||
|
||||
func (p *Printer) removeRightSideNewLineChar(src string) string {
|
||||
return strings.TrimRight(strings.TrimRight(strings.TrimRight(src, "\r"), "\n"), "\r\n")
|
||||
}
|
||||
|
||||
func (p *Printer) removeRightSideWhiteSpaceChar(src string) string {
|
||||
return p.removeRightSideNewLineChar(strings.TrimRight(src, " "))
|
||||
}
|
||||
|
||||
func (p *Printer) newLineCount(s string) int {
|
||||
src := []rune(s)
|
||||
size := len(src)
|
||||
cnt := 0
|
||||
for i := 0; i < size; i++ {
|
||||
c := src[i]
|
||||
switch c {
|
||||
case '\r':
|
||||
if i+1 < size && src[i+1] == '\n' {
|
||||
i++
|
||||
}
|
||||
cnt++
|
||||
case '\n':
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
return cnt
|
||||
}
|
||||
|
||||
func (p *Printer) isNewLineLastChar(s string) bool {
|
||||
for i := len(s) - 1; i > 0; i-- {
|
||||
c := s[i]
|
||||
switch c {
|
||||
case ' ':
|
||||
continue
|
||||
case '\n', '\r':
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Printer) printBeforeTokens(tk *token.Token, minLine, extLine int) token.Tokens {
|
||||
for {
|
||||
if tk.Prev == nil {
|
||||
break
|
||||
}
|
||||
if tk.Prev.Position.Line < minLine {
|
||||
break
|
||||
}
|
||||
tk = tk.Prev
|
||||
}
|
||||
minTk := tk.Clone()
|
||||
if minTk.Prev != nil {
|
||||
// add white spaces to minTk by prev token
|
||||
prev := minTk.Prev
|
||||
whiteSpaceLen := len(prev.Origin) - len(strings.TrimRight(prev.Origin, " "))
|
||||
minTk.Origin = strings.Repeat(" ", whiteSpaceLen) + minTk.Origin
|
||||
}
|
||||
minTk.Origin = p.removeLeftSideNewLineChar(minTk.Origin)
|
||||
tokens := token.Tokens{minTk}
|
||||
tk = minTk.Next
|
||||
for tk != nil && tk.Position.Line <= extLine {
|
||||
clonedTk := tk.Clone()
|
||||
tokens.Add(clonedTk)
|
||||
tk = clonedTk.Next
|
||||
}
|
||||
lastTk := tokens[len(tokens)-1]
|
||||
trimmedOrigin := p.removeRightSideWhiteSpaceChar(lastTk.Origin)
|
||||
suffix := lastTk.Origin[len(trimmedOrigin):]
|
||||
lastTk.Origin = trimmedOrigin
|
||||
|
||||
if lastTk.Next != nil && len(suffix) > 1 {
|
||||
next := lastTk.Next.Clone()
|
||||
// add suffix to header of next token
|
||||
if suffix[0] == '\n' || suffix[0] == '\r' {
|
||||
suffix = suffix[1:]
|
||||
}
|
||||
next.Origin = suffix + next.Origin
|
||||
lastTk.Next = next
|
||||
}
|
||||
return tokens
|
||||
}
|
||||
|
||||
func (p *Printer) printAfterTokens(tk *token.Token, maxLine int) token.Tokens {
|
||||
tokens := token.Tokens{}
|
||||
if tk == nil {
|
||||
return tokens
|
||||
}
|
||||
if tk.Position.Line > maxLine {
|
||||
return tokens
|
||||
}
|
||||
minTk := tk.Clone()
|
||||
minTk.Origin = p.removeLeftSideNewLineChar(minTk.Origin)
|
||||
tokens.Add(minTk)
|
||||
tk = minTk.Next
|
||||
for tk != nil && tk.Position.Line <= maxLine {
|
||||
clonedTk := tk.Clone()
|
||||
tokens.Add(clonedTk)
|
||||
tk = clonedTk.Next
|
||||
}
|
||||
return tokens
|
||||
}
|
||||
|
||||
func (p *Printer) setupErrorTokenFormat(annotateLine int, isColored bool) {
|
||||
prefix := func(annotateLine, num int) string {
|
||||
if annotateLine == num {
|
||||
return fmt.Sprintf("> %2d | ", num)
|
||||
}
|
||||
return fmt.Sprintf(" %2d | ", num)
|
||||
}
|
||||
p.LineNumber = true
|
||||
p.LineNumberFormat = func(num int) string {
|
||||
if isColored {
|
||||
fn := color.New(color.Bold, color.FgHiWhite).SprintFunc()
|
||||
return fn(prefix(annotateLine, num))
|
||||
}
|
||||
return prefix(annotateLine, num)
|
||||
}
|
||||
if isColored {
|
||||
p.setDefaultColorSet()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Printer) PrintErrorToken(tk *token.Token, isColored bool) string {
|
||||
errToken := tk
|
||||
curLine := tk.Position.Line
|
||||
curExtLine := curLine + p.newLineCount(p.removeLeftSideNewLineChar(tk.Origin))
|
||||
if p.isNewLineLastChar(tk.Origin) {
|
||||
// if last character ( exclude white space ) is new line character, ignore it.
|
||||
curExtLine--
|
||||
}
|
||||
|
||||
minLine := int(math.Max(float64(curLine-3), 1))
|
||||
maxLine := curExtLine + 3
|
||||
p.setupErrorTokenFormat(curLine, isColored)
|
||||
|
||||
beforeTokens := p.printBeforeTokens(tk, minLine, curExtLine)
|
||||
lastTk := beforeTokens[len(beforeTokens)-1]
|
||||
afterTokens := p.printAfterTokens(lastTk.Next, maxLine)
|
||||
|
||||
beforeSource := p.PrintTokens(beforeTokens)
|
||||
prefixSpaceNum := len(fmt.Sprintf(" %2d | ", curLine))
|
||||
annotateLine := strings.Repeat(" ", prefixSpaceNum+errToken.Position.Column-1) + "^"
|
||||
afterSource := p.PrintTokens(afterTokens)
|
||||
return fmt.Sprintf("%s\n%s\n%s", beforeSource, annotateLine, afterSource)
|
||||
}
|
||||
229
vendor/github.com/goccy/go-yaml/scanner/context.go
generated
vendored
Normal file
229
vendor/github.com/goccy/go-yaml/scanner/context.go
generated
vendored
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
package scanner
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/goccy/go-yaml/token"
|
||||
)
|
||||
|
||||
const whitespace = ' '
|
||||
|
||||
// Context context at scanning
|
||||
type Context struct {
|
||||
idx int
|
||||
size int
|
||||
notSpaceCharPos int
|
||||
notSpaceOrgCharPos int
|
||||
src []rune
|
||||
buf []rune
|
||||
obuf []rune
|
||||
tokens token.Tokens
|
||||
isRawFolded bool
|
||||
isLiteral bool
|
||||
isFolded bool
|
||||
isSingleLine bool
|
||||
literalOpt string
|
||||
}
|
||||
|
||||
var (
|
||||
ctxPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return createContext()
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func createContext() *Context {
|
||||
return &Context{
|
||||
idx: 0,
|
||||
tokens: token.Tokens{},
|
||||
isSingleLine: true,
|
||||
}
|
||||
}
|
||||
|
||||
func newContext(src []rune) *Context {
|
||||
ctx := ctxPool.Get().(*Context)
|
||||
ctx.reset(src)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (c *Context) release() {
|
||||
ctxPool.Put(c)
|
||||
}
|
||||
|
||||
func (c *Context) reset(src []rune) {
|
||||
c.idx = 0
|
||||
c.size = len(src)
|
||||
c.src = src
|
||||
c.tokens = c.tokens[:0]
|
||||
c.resetBuffer()
|
||||
c.isRawFolded = false
|
||||
c.isSingleLine = true
|
||||
c.isLiteral = false
|
||||
c.isFolded = false
|
||||
c.literalOpt = ""
|
||||
}
|
||||
|
||||
func (c *Context) resetBuffer() {
|
||||
c.buf = c.buf[:0]
|
||||
c.obuf = c.obuf[:0]
|
||||
c.notSpaceCharPos = 0
|
||||
c.notSpaceOrgCharPos = 0
|
||||
}
|
||||
|
||||
func (c *Context) isSaveIndentMode() bool {
|
||||
return c.isLiteral || c.isFolded || c.isRawFolded
|
||||
}
|
||||
|
||||
func (c *Context) breakLiteral() {
|
||||
c.isLiteral = false
|
||||
c.isRawFolded = false
|
||||
c.isFolded = false
|
||||
c.literalOpt = ""
|
||||
}
|
||||
|
||||
func (c *Context) addToken(tk *token.Token) {
|
||||
if tk == nil {
|
||||
return
|
||||
}
|
||||
c.tokens = append(c.tokens, tk)
|
||||
}
|
||||
|
||||
func (c *Context) addBuf(r rune) {
|
||||
if len(c.buf) == 0 && r == ' ' {
|
||||
return
|
||||
}
|
||||
c.buf = append(c.buf, r)
|
||||
if r != ' ' && r != '\t' {
|
||||
c.notSpaceCharPos = len(c.buf)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) addOriginBuf(r rune) {
|
||||
c.obuf = append(c.obuf, r)
|
||||
if r != ' ' && r != '\t' {
|
||||
c.notSpaceOrgCharPos = len(c.obuf)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) removeRightSpaceFromBuf() int {
|
||||
trimmedBuf := c.obuf[:c.notSpaceOrgCharPos]
|
||||
buflen := len(trimmedBuf)
|
||||
diff := len(c.obuf) - buflen
|
||||
if diff > 0 {
|
||||
c.obuf = c.obuf[:buflen]
|
||||
c.buf = c.bufferedSrc()
|
||||
}
|
||||
return diff
|
||||
}
|
||||
|
||||
func (c *Context) isDocument() bool {
|
||||
return c.isLiteral || c.isFolded || c.isRawFolded
|
||||
}
|
||||
|
||||
func (c *Context) isEOS() bool {
|
||||
return len(c.src)-1 <= c.idx
|
||||
}
|
||||
|
||||
func (c *Context) isNextEOS() bool {
|
||||
return len(c.src)-1 <= c.idx+1
|
||||
}
|
||||
|
||||
func (c *Context) next() bool {
|
||||
return c.idx < c.size
|
||||
}
|
||||
|
||||
func (c *Context) source(s, e int) string {
|
||||
return string(c.src[s:e])
|
||||
}
|
||||
|
||||
func (c *Context) previousChar() rune {
|
||||
if c.idx > 0 {
|
||||
return c.src[c.idx-1]
|
||||
}
|
||||
return rune(0)
|
||||
}
|
||||
|
||||
func (c *Context) currentChar() rune {
|
||||
if c.size > c.idx {
|
||||
return c.src[c.idx]
|
||||
}
|
||||
return rune(0)
|
||||
}
|
||||
|
||||
func (c *Context) currentCharWithSkipWhitespace() rune {
|
||||
idx := c.idx
|
||||
for c.size > idx {
|
||||
ch := c.src[idx]
|
||||
if ch != whitespace {
|
||||
return ch
|
||||
}
|
||||
idx++
|
||||
}
|
||||
return rune(0)
|
||||
}
|
||||
|
||||
func (c *Context) nextChar() rune {
|
||||
if c.size > c.idx+1 {
|
||||
return c.src[c.idx+1]
|
||||
}
|
||||
return rune(0)
|
||||
}
|
||||
|
||||
func (c *Context) repeatNum(r rune) int {
|
||||
cnt := 0
|
||||
for i := c.idx; i < c.size; i++ {
|
||||
if c.src[i] == r {
|
||||
cnt++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return cnt
|
||||
}
|
||||
|
||||
func (c *Context) progress(num int) {
|
||||
c.idx += num
|
||||
}
|
||||
|
||||
func (c *Context) nextPos() int {
|
||||
return c.idx + 1
|
||||
}
|
||||
|
||||
func (c *Context) existsBuffer() bool {
|
||||
return len(c.bufferedSrc()) != 0
|
||||
}
|
||||
|
||||
func (c *Context) bufferedSrc() []rune {
|
||||
src := c.buf[:c.notSpaceCharPos]
|
||||
if len(src) > 0 && src[len(src)-1] == '\n' && c.isDocument() && c.literalOpt == "-" {
|
||||
// remove end '\n' character
|
||||
src = src[:len(src)-1]
|
||||
}
|
||||
return src
|
||||
}
|
||||
|
||||
func (c *Context) bufferedToken(pos *token.Position) *token.Token {
|
||||
if c.idx == 0 {
|
||||
return nil
|
||||
}
|
||||
source := c.bufferedSrc()
|
||||
if len(source) == 0 {
|
||||
return nil
|
||||
}
|
||||
var tk *token.Token
|
||||
if c.isDocument() {
|
||||
tk = token.String(string(source), string(c.obuf), pos)
|
||||
} else {
|
||||
tk = token.New(string(source), string(c.obuf), pos)
|
||||
}
|
||||
c.resetBuffer()
|
||||
return tk
|
||||
}
|
||||
|
||||
func (c *Context) lastToken() *token.Token {
|
||||
if len(c.tokens) != 0 {
|
||||
return c.tokens[len(c.tokens)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
903
vendor/github.com/goccy/go-yaml/scanner/scanner.go
generated
vendored
Normal file
903
vendor/github.com/goccy/go-yaml/scanner/scanner.go
generated
vendored
Normal file
|
|
@ -0,0 +1,903 @@
|
|||
package scanner
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/goccy/go-yaml/token"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// IndentState state for indent
|
||||
type IndentState int
|
||||
|
||||
const (
|
||||
// IndentStateEqual equals previous indent
|
||||
IndentStateEqual IndentState = iota
|
||||
// IndentStateUp more indent than previous
|
||||
IndentStateUp
|
||||
// IndentStateDown less indent than previous
|
||||
IndentStateDown
|
||||
// IndentStateKeep uses not indent token
|
||||
IndentStateKeep
|
||||
)
|
||||
|
||||
// Scanner holds the scanner's internal state while processing a given text.
|
||||
// It can be allocated as part of another data structure but must be initialized via Init before use.
|
||||
type Scanner struct {
|
||||
source []rune
|
||||
sourcePos int
|
||||
sourceSize int
|
||||
line int
|
||||
column int
|
||||
offset int
|
||||
prevIndentLevel int
|
||||
prevIndentNum int
|
||||
prevIndentColumn int
|
||||
docStartColumn int
|
||||
indentLevel int
|
||||
indentNum int
|
||||
isFirstCharAtLine bool
|
||||
isAnchor bool
|
||||
startedFlowSequenceNum int
|
||||
startedFlowMapNum int
|
||||
indentState IndentState
|
||||
savedPos *token.Position
|
||||
}
|
||||
|
||||
func (s *Scanner) pos() *token.Position {
|
||||
return &token.Position{
|
||||
Line: s.line,
|
||||
Column: s.column,
|
||||
Offset: s.offset,
|
||||
IndentNum: s.indentNum,
|
||||
IndentLevel: s.indentLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scanner) bufferedToken(ctx *Context) *token.Token {
|
||||
if s.savedPos != nil {
|
||||
tk := ctx.bufferedToken(s.savedPos)
|
||||
s.savedPos = nil
|
||||
return tk
|
||||
}
|
||||
line := s.line
|
||||
column := s.column - len(ctx.buf)
|
||||
level := s.indentLevel
|
||||
if ctx.isSaveIndentMode() {
|
||||
line -= s.newLineCount(ctx.buf)
|
||||
column = strings.Index(string(ctx.obuf), string(ctx.buf)) + 1
|
||||
// Since we are in a literal, folded or raw folded
|
||||
// we can use the indent level from the last token.
|
||||
last := ctx.lastToken()
|
||||
if last != nil { // The last token should never be nil here.
|
||||
level = last.Position.IndentLevel + 1
|
||||
}
|
||||
}
|
||||
return ctx.bufferedToken(&token.Position{
|
||||
Line: line,
|
||||
Column: column,
|
||||
Offset: s.offset - len(ctx.buf),
|
||||
IndentNum: s.indentNum,
|
||||
IndentLevel: level,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Scanner) progressColumn(ctx *Context, num int) {
|
||||
s.column += num
|
||||
s.offset += num
|
||||
ctx.progress(num)
|
||||
}
|
||||
|
||||
func (s *Scanner) progressLine(ctx *Context) {
|
||||
s.column = 1
|
||||
s.line++
|
||||
s.offset++
|
||||
s.indentNum = 0
|
||||
s.isFirstCharAtLine = true
|
||||
s.isAnchor = false
|
||||
ctx.progress(1)
|
||||
}
|
||||
|
||||
func (s *Scanner) isNeededKeepPreviousIndentNum(ctx *Context, c rune) bool {
|
||||
if !s.isChangedToIndentStateUp() {
|
||||
return false
|
||||
}
|
||||
if ctx.isDocument() {
|
||||
return true
|
||||
}
|
||||
if c == '-' && ctx.existsBuffer() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Scanner) isNewLineChar(c rune) bool {
|
||||
if c == '\n' {
|
||||
return true
|
||||
}
|
||||
if c == '\r' {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Scanner) newLineCount(src []rune) int {
|
||||
size := len(src)
|
||||
cnt := 0
|
||||
for i := 0; i < size; i++ {
|
||||
c := src[i]
|
||||
switch c {
|
||||
case '\r':
|
||||
if i+1 < size && src[i+1] == '\n' {
|
||||
i++
|
||||
}
|
||||
cnt++
|
||||
case '\n':
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
return cnt
|
||||
}
|
||||
|
||||
func (s *Scanner) updateIndentState(ctx *Context) {
|
||||
indentNumBasedIndentState := s.indentState
|
||||
if s.prevIndentNum < s.indentNum {
|
||||
s.indentLevel = s.prevIndentLevel + 1
|
||||
indentNumBasedIndentState = IndentStateUp
|
||||
} else if s.prevIndentNum == s.indentNum {
|
||||
s.indentLevel = s.prevIndentLevel
|
||||
indentNumBasedIndentState = IndentStateEqual
|
||||
} else {
|
||||
indentNumBasedIndentState = IndentStateDown
|
||||
if s.prevIndentLevel > 0 {
|
||||
s.indentLevel = s.prevIndentLevel - 1
|
||||
}
|
||||
}
|
||||
|
||||
if s.prevIndentColumn > 0 {
|
||||
if s.prevIndentColumn < s.column {
|
||||
s.indentState = IndentStateUp
|
||||
} else if s.prevIndentColumn != s.column || indentNumBasedIndentState != IndentStateEqual {
|
||||
// The following case ( current position is 'd' ), some variables becomes like here
|
||||
// - prevIndentColumn: 1 of 'a'
|
||||
// - indentNumBasedIndentState: IndentStateDown because d's indentNum(1) is less than c's indentNum(3).
|
||||
// Therefore, s.prevIndentColumn(1) == s.column(1) is true, but we want to treat this as IndentStateDown.
|
||||
// So, we look also current indentState value by the above prevIndentNum based logic, and determins finally indentState.
|
||||
// ---
|
||||
// a:
|
||||
// b
|
||||
// c
|
||||
// d: e
|
||||
// ^
|
||||
s.indentState = IndentStateDown
|
||||
} else {
|
||||
s.indentState = IndentStateEqual
|
||||
}
|
||||
} else {
|
||||
s.indentState = indentNumBasedIndentState
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scanner) updateIndent(ctx *Context, c rune) {
|
||||
if s.isFirstCharAtLine && s.isNewLineChar(c) && ctx.isDocument() {
|
||||
return
|
||||
}
|
||||
if s.isFirstCharAtLine && c == ' ' {
|
||||
s.indentNum++
|
||||
return
|
||||
}
|
||||
if !s.isFirstCharAtLine {
|
||||
s.indentState = IndentStateKeep
|
||||
return
|
||||
}
|
||||
s.updateIndentState(ctx)
|
||||
s.isFirstCharAtLine = false
|
||||
if s.isNeededKeepPreviousIndentNum(ctx, c) {
|
||||
return
|
||||
}
|
||||
if s.indentState != IndentStateUp {
|
||||
s.prevIndentColumn = 0
|
||||
}
|
||||
s.prevIndentNum = s.indentNum
|
||||
s.prevIndentLevel = s.indentLevel
|
||||
}
|
||||
|
||||
func (s *Scanner) isChangedToIndentStateDown() bool {
|
||||
return s.indentState == IndentStateDown
|
||||
}
|
||||
|
||||
func (s *Scanner) isChangedToIndentStateUp() bool {
|
||||
return s.indentState == IndentStateUp
|
||||
}
|
||||
|
||||
func (s *Scanner) isChangedToIndentStateEqual() bool {
|
||||
return s.indentState == IndentStateEqual
|
||||
}
|
||||
|
||||
func (s *Scanner) addBufferedTokenIfExists(ctx *Context) {
|
||||
ctx.addToken(s.bufferedToken(ctx))
|
||||
}
|
||||
|
||||
func (s *Scanner) breakLiteral(ctx *Context) {
|
||||
s.docStartColumn = 0
|
||||
ctx.breakLiteral()
|
||||
}
|
||||
|
||||
func (s *Scanner) scanSingleQuote(ctx *Context) (tk *token.Token, pos int) {
|
||||
ctx.addOriginBuf('\'')
|
||||
srcpos := s.pos()
|
||||
startIndex := ctx.idx + 1
|
||||
src := ctx.src
|
||||
size := len(src)
|
||||
value := []rune{}
|
||||
isFirstLineChar := false
|
||||
isNewLine := false
|
||||
for idx := startIndex; idx < size; idx++ {
|
||||
if !isNewLine {
|
||||
s.progressColumn(ctx, 1)
|
||||
} else {
|
||||
isNewLine = false
|
||||
}
|
||||
c := src[idx]
|
||||
pos = idx + 1
|
||||
ctx.addOriginBuf(c)
|
||||
if s.isNewLineChar(c) {
|
||||
value = append(value, ' ')
|
||||
isFirstLineChar = true
|
||||
isNewLine = true
|
||||
s.progressLine(ctx)
|
||||
continue
|
||||
} else if c == ' ' && isFirstLineChar {
|
||||
continue
|
||||
} else if c != '\'' {
|
||||
value = append(value, c)
|
||||
isFirstLineChar = false
|
||||
continue
|
||||
}
|
||||
if idx+1 < len(ctx.src) && ctx.src[idx+1] == '\'' {
|
||||
// '' handle as ' character
|
||||
value = append(value, c)
|
||||
ctx.addOriginBuf(c)
|
||||
idx++
|
||||
continue
|
||||
}
|
||||
s.progressColumn(ctx, 1)
|
||||
tk = token.SingleQuote(string(value), string(ctx.obuf), srcpos)
|
||||
pos = idx - startIndex + 1
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hexToInt(b rune) int {
|
||||
if b >= 'A' && b <= 'F' {
|
||||
return int(b) - 'A' + 10
|
||||
}
|
||||
if b >= 'a' && b <= 'f' {
|
||||
return int(b) - 'a' + 10
|
||||
}
|
||||
return int(b) - '0'
|
||||
}
|
||||
|
||||
func hexRunesToInt(b []rune) int {
|
||||
sum := 0
|
||||
for i := 0; i < len(b); i++ {
|
||||
sum += hexToInt(b[i]) << (uint(len(b)-i-1) * 4)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func (s *Scanner) scanDoubleQuote(ctx *Context) (tk *token.Token, pos int) {
|
||||
ctx.addOriginBuf('"')
|
||||
srcpos := s.pos()
|
||||
startIndex := ctx.idx + 1
|
||||
src := ctx.src
|
||||
size := len(src)
|
||||
value := []rune{}
|
||||
isFirstLineChar := false
|
||||
isNewLine := false
|
||||
for idx := startIndex; idx < size; idx++ {
|
||||
if !isNewLine {
|
||||
s.progressColumn(ctx, 1)
|
||||
} else {
|
||||
isNewLine = false
|
||||
}
|
||||
c := src[idx]
|
||||
pos = idx + 1
|
||||
ctx.addOriginBuf(c)
|
||||
if s.isNewLineChar(c) {
|
||||
value = append(value, ' ')
|
||||
isFirstLineChar = true
|
||||
isNewLine = true
|
||||
s.progressLine(ctx)
|
||||
continue
|
||||
} else if c == ' ' && isFirstLineChar {
|
||||
continue
|
||||
} else if c == '\\' {
|
||||
isFirstLineChar = false
|
||||
if idx+1 < size {
|
||||
nextChar := src[idx+1]
|
||||
switch nextChar {
|
||||
case 'b':
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, '\b')
|
||||
idx++
|
||||
continue
|
||||
case 'e':
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, '\x1B')
|
||||
idx++
|
||||
continue
|
||||
case 'f':
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, '\f')
|
||||
idx++
|
||||
continue
|
||||
case 'n':
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, '\n')
|
||||
idx++
|
||||
continue
|
||||
case 'v':
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, '\v')
|
||||
idx++
|
||||
continue
|
||||
case 'L': // LS (#x2028)
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, []rune{'\xE2', '\x80', '\xA8'}...)
|
||||
idx++
|
||||
continue
|
||||
case 'N': // NEL (#x85)
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, []rune{'\xC2', '\x85'}...)
|
||||
idx++
|
||||
continue
|
||||
case 'P': // PS (#x2029)
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, []rune{'\xE2', '\x80', '\xA9'}...)
|
||||
idx++
|
||||
continue
|
||||
case '_': // #xA0
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, []rune{'\xC2', '\xA0'}...)
|
||||
idx++
|
||||
continue
|
||||
case '"':
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, nextChar)
|
||||
idx++
|
||||
continue
|
||||
case 'x':
|
||||
if idx+3 >= size {
|
||||
// TODO: need to return error
|
||||
//err = xerrors.New("invalid escape character \\x")
|
||||
return
|
||||
}
|
||||
codeNum := hexRunesToInt(src[idx+2 : idx+4])
|
||||
value = append(value, rune(codeNum))
|
||||
idx += 3
|
||||
continue
|
||||
case 'u':
|
||||
if idx+5 >= size {
|
||||
// TODO: need to return error
|
||||
//err = xerrors.New("invalid escape character \\u")
|
||||
return
|
||||
}
|
||||
codeNum := hexRunesToInt(src[idx+2 : idx+6])
|
||||
value = append(value, rune(codeNum))
|
||||
idx += 5
|
||||
continue
|
||||
case 'U':
|
||||
if idx+9 >= size {
|
||||
// TODO: need to return error
|
||||
//err = xerrors.New("invalid escape character \\U")
|
||||
return
|
||||
}
|
||||
codeNum := hexRunesToInt(src[idx+2 : idx+10])
|
||||
value = append(value, rune(codeNum))
|
||||
idx += 9
|
||||
continue
|
||||
case '\\':
|
||||
ctx.addOriginBuf(nextChar)
|
||||
idx++
|
||||
}
|
||||
}
|
||||
value = append(value, c)
|
||||
continue
|
||||
} else if c != '"' {
|
||||
value = append(value, c)
|
||||
isFirstLineChar = false
|
||||
continue
|
||||
}
|
||||
s.progressColumn(ctx, 1)
|
||||
tk = token.DoubleQuote(string(value), string(ctx.obuf), srcpos)
|
||||
pos = idx - startIndex + 1
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Scanner) scanQuote(ctx *Context, ch rune) (tk *token.Token, pos int) {
|
||||
if ch == '\'' {
|
||||
return s.scanSingleQuote(ctx)
|
||||
}
|
||||
return s.scanDoubleQuote(ctx)
|
||||
}
|
||||
|
||||
func (s *Scanner) isMergeKey(ctx *Context) bool {
|
||||
if ctx.repeatNum('<') != 2 {
|
||||
return false
|
||||
}
|
||||
src := ctx.src
|
||||
size := len(src)
|
||||
for idx := ctx.idx + 2; idx < size; idx++ {
|
||||
c := src[idx]
|
||||
if c == ' ' {
|
||||
continue
|
||||
}
|
||||
if c != ':' {
|
||||
return false
|
||||
}
|
||||
if idx+1 < size {
|
||||
nc := src[idx+1]
|
||||
if nc == ' ' || s.isNewLineChar(nc) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Scanner) scanTag(ctx *Context) (tk *token.Token, pos int) {
|
||||
ctx.addOriginBuf('!')
|
||||
ctx.progress(1) // skip '!' character
|
||||
for idx, c := range ctx.src[ctx.idx:] {
|
||||
pos = idx + 1
|
||||
ctx.addOriginBuf(c)
|
||||
switch c {
|
||||
case ' ', '\n', '\r':
|
||||
value := ctx.source(ctx.idx-1, ctx.idx+idx)
|
||||
tk = token.Tag(value, string(ctx.obuf), s.pos())
|
||||
pos = len([]rune(value))
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Scanner) scanComment(ctx *Context) (tk *token.Token, pos int) {
|
||||
ctx.addOriginBuf('#')
|
||||
ctx.progress(1) // skip '#' character
|
||||
for idx, c := range ctx.src[ctx.idx:] {
|
||||
pos = idx + 1
|
||||
ctx.addOriginBuf(c)
|
||||
switch c {
|
||||
case '\n', '\r':
|
||||
if ctx.previousChar() == '\\' {
|
||||
continue
|
||||
}
|
||||
value := ctx.source(ctx.idx, ctx.idx+idx)
|
||||
tk = token.Comment(value, string(ctx.obuf), s.pos())
|
||||
pos = len([]rune(value)) + 1
|
||||
return
|
||||
}
|
||||
}
|
||||
// document ends with comment.
|
||||
value := string(ctx.src[ctx.idx:])
|
||||
tk = token.Comment(value, string(ctx.obuf), s.pos())
|
||||
pos = len([]rune(value)) + 1
|
||||
return
|
||||
}
|
||||
|
||||
func trimCommentFromLiteralOpt(text string) (string, error) {
|
||||
idx := strings.Index(text, "#")
|
||||
if idx < 0 {
|
||||
return text, nil
|
||||
}
|
||||
if idx == 0 {
|
||||
return "", xerrors.New("invalid literal header")
|
||||
}
|
||||
return text[:idx-1], nil
|
||||
}
|
||||
|
||||
func (s *Scanner) scanLiteral(ctx *Context, c rune) {
|
||||
ctx.addOriginBuf(c)
|
||||
if ctx.isEOS() {
|
||||
if ctx.isLiteral {
|
||||
ctx.addBuf(c)
|
||||
}
|
||||
value := ctx.bufferedSrc()
|
||||
ctx.addToken(token.String(string(value), string(ctx.obuf), s.pos()))
|
||||
ctx.resetBuffer()
|
||||
s.progressColumn(ctx, 1)
|
||||
} else if s.isNewLineChar(c) {
|
||||
if ctx.isLiteral {
|
||||
ctx.addBuf(c)
|
||||
} else {
|
||||
ctx.addBuf(' ')
|
||||
}
|
||||
s.progressLine(ctx)
|
||||
} else if s.isFirstCharAtLine && c == ' ' {
|
||||
if 0 < s.docStartColumn && s.docStartColumn <= s.column {
|
||||
ctx.addBuf(c)
|
||||
}
|
||||
s.progressColumn(ctx, 1)
|
||||
} else {
|
||||
if s.docStartColumn == 0 {
|
||||
s.docStartColumn = s.column
|
||||
}
|
||||
ctx.addBuf(c)
|
||||
s.progressColumn(ctx, 1)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scanner) scanLiteralHeader(ctx *Context) (pos int, err error) {
|
||||
header := ctx.currentChar()
|
||||
ctx.addOriginBuf(header)
|
||||
ctx.progress(1) // skip '|' or '>' character
|
||||
for idx, c := range ctx.src[ctx.idx:] {
|
||||
pos = idx
|
||||
ctx.addOriginBuf(c)
|
||||
switch c {
|
||||
case '\n', '\r':
|
||||
value := ctx.source(ctx.idx, ctx.idx+idx)
|
||||
opt := strings.TrimRight(value, " ")
|
||||
orgOptLen := len(opt)
|
||||
opt, err = trimCommentFromLiteralOpt(opt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch opt {
|
||||
case "", "+", "-",
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9":
|
||||
hasComment := len(opt) < orgOptLen
|
||||
if header == '|' {
|
||||
if hasComment {
|
||||
commentLen := orgOptLen - len(opt)
|
||||
headerPos := strings.Index(string(ctx.obuf), "|")
|
||||
litBuf := ctx.obuf[:len(ctx.obuf)-commentLen-headerPos]
|
||||
commentBuf := ctx.obuf[len(litBuf):]
|
||||
ctx.addToken(token.Literal("|"+opt, string(litBuf), s.pos()))
|
||||
s.column += len(litBuf)
|
||||
s.offset += len(litBuf)
|
||||
commentHeader := strings.Index(value, "#")
|
||||
ctx.addToken(token.Comment(string(value[commentHeader+1:]), string(commentBuf), s.pos()))
|
||||
} else {
|
||||
ctx.addToken(token.Literal("|"+opt, string(ctx.obuf), s.pos()))
|
||||
}
|
||||
ctx.isLiteral = true
|
||||
} else if header == '>' {
|
||||
if hasComment {
|
||||
commentLen := orgOptLen - len(opt)
|
||||
headerPos := strings.Index(string(ctx.obuf), ">")
|
||||
foldedBuf := ctx.obuf[:len(ctx.obuf)-commentLen-headerPos]
|
||||
commentBuf := ctx.obuf[len(foldedBuf):]
|
||||
ctx.addToken(token.Folded(">"+opt, string(foldedBuf), s.pos()))
|
||||
s.column += len(foldedBuf)
|
||||
s.offset += len(foldedBuf)
|
||||
commentHeader := strings.Index(value, "#")
|
||||
ctx.addToken(token.Comment(string(value[commentHeader+1:]), string(commentBuf), s.pos()))
|
||||
} else {
|
||||
ctx.addToken(token.Folded(">"+opt, string(ctx.obuf), s.pos()))
|
||||
}
|
||||
ctx.isFolded = true
|
||||
}
|
||||
s.indentState = IndentStateKeep
|
||||
ctx.resetBuffer()
|
||||
ctx.literalOpt = opt
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
err = xerrors.New("invalid literal header")
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Scanner) scanNewLine(ctx *Context, c rune) {
|
||||
if len(ctx.buf) > 0 && s.savedPos == nil {
|
||||
s.savedPos = s.pos()
|
||||
s.savedPos.Column -= len(ctx.bufferedSrc())
|
||||
}
|
||||
|
||||
// if the following case, origin buffer has unnecessary two spaces.
|
||||
// So, `removeRightSpaceFromOriginBuf` remove them, also fix column number too.
|
||||
// ---
|
||||
// a:[space][space]
|
||||
// b: c
|
||||
removedNum := ctx.removeRightSpaceFromBuf()
|
||||
if removedNum > 0 {
|
||||
s.column -= removedNum
|
||||
s.offset -= removedNum
|
||||
if s.savedPos != nil {
|
||||
s.savedPos.Column -= removedNum
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.isEOS() {
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
} else if s.isAnchor {
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
}
|
||||
ctx.addBuf(' ')
|
||||
ctx.addOriginBuf(c)
|
||||
ctx.isSingleLine = false
|
||||
s.progressLine(ctx)
|
||||
}
|
||||
|
||||
func (s *Scanner) scan(ctx *Context) (pos int) {
|
||||
for ctx.next() {
|
||||
pos = ctx.nextPos()
|
||||
c := ctx.currentChar()
|
||||
s.updateIndent(ctx, c)
|
||||
if ctx.isDocument() {
|
||||
if s.isChangedToIndentStateEqual() ||
|
||||
s.isChangedToIndentStateDown() {
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
s.breakLiteral(ctx)
|
||||
} else {
|
||||
s.scanLiteral(ctx, c)
|
||||
continue
|
||||
}
|
||||
} else if s.isChangedToIndentStateDown() {
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
} else if s.isChangedToIndentStateEqual() {
|
||||
// if first character is new line character, buffer expect to raw folded literal
|
||||
if len(ctx.obuf) > 0 && s.newLineCount(ctx.obuf) <= 1 {
|
||||
// doesn't raw folded literal
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
}
|
||||
}
|
||||
switch c {
|
||||
case '{':
|
||||
if !ctx.existsBuffer() {
|
||||
ctx.addOriginBuf(c)
|
||||
ctx.addToken(token.MappingStart(string(ctx.obuf), s.pos()))
|
||||
s.startedFlowMapNum++
|
||||
s.progressColumn(ctx, 1)
|
||||
return
|
||||
}
|
||||
case '}':
|
||||
if !ctx.existsBuffer() || s.startedFlowMapNum > 0 {
|
||||
ctx.addToken(s.bufferedToken(ctx))
|
||||
ctx.addOriginBuf(c)
|
||||
ctx.addToken(token.MappingEnd(string(ctx.obuf), s.pos()))
|
||||
s.startedFlowMapNum--
|
||||
s.progressColumn(ctx, 1)
|
||||
return
|
||||
}
|
||||
case '.':
|
||||
if s.indentNum == 0 && s.column == 1 && ctx.repeatNum('.') == 3 {
|
||||
ctx.addToken(token.DocumentEnd(string(ctx.obuf)+"...", s.pos()))
|
||||
s.progressColumn(ctx, 3)
|
||||
pos += 2
|
||||
return
|
||||
}
|
||||
case '<':
|
||||
if s.isMergeKey(ctx) {
|
||||
s.prevIndentColumn = s.column
|
||||
ctx.addToken(token.MergeKey(string(ctx.obuf)+"<<", s.pos()))
|
||||
s.progressColumn(ctx, 1)
|
||||
pos++
|
||||
return
|
||||
}
|
||||
case '-':
|
||||
if s.indentNum == 0 && s.column == 1 && ctx.repeatNum('-') == 3 {
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
ctx.addToken(token.DocumentHeader(string(ctx.obuf)+"---", s.pos()))
|
||||
s.progressColumn(ctx, 3)
|
||||
pos += 2
|
||||
return
|
||||
}
|
||||
if ctx.existsBuffer() && s.isChangedToIndentStateUp() {
|
||||
// raw folded
|
||||
ctx.isRawFolded = true
|
||||
ctx.addBuf(c)
|
||||
ctx.addOriginBuf(c)
|
||||
s.progressColumn(ctx, 1)
|
||||
continue
|
||||
}
|
||||
if ctx.existsBuffer() {
|
||||
// '-' is literal
|
||||
ctx.addBuf(c)
|
||||
ctx.addOriginBuf(c)
|
||||
s.progressColumn(ctx, 1)
|
||||
continue
|
||||
}
|
||||
nc := ctx.nextChar()
|
||||
if nc == ' ' || s.isNewLineChar(nc) {
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
ctx.addOriginBuf(c)
|
||||
tk := token.SequenceEntry(string(ctx.obuf), s.pos())
|
||||
s.prevIndentColumn = tk.Position.Column
|
||||
ctx.addToken(tk)
|
||||
s.progressColumn(ctx, 1)
|
||||
return
|
||||
}
|
||||
case '[':
|
||||
if !ctx.existsBuffer() {
|
||||
ctx.addOriginBuf(c)
|
||||
ctx.addToken(token.SequenceStart(string(ctx.obuf), s.pos()))
|
||||
s.startedFlowSequenceNum++
|
||||
s.progressColumn(ctx, 1)
|
||||
return
|
||||
}
|
||||
case ']':
|
||||
if !ctx.existsBuffer() || s.startedFlowSequenceNum > 0 {
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
ctx.addOriginBuf(c)
|
||||
ctx.addToken(token.SequenceEnd(string(ctx.obuf), s.pos()))
|
||||
s.startedFlowSequenceNum--
|
||||
s.progressColumn(ctx, 1)
|
||||
return
|
||||
}
|
||||
case ',':
|
||||
if s.startedFlowSequenceNum > 0 || s.startedFlowMapNum > 0 {
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
ctx.addOriginBuf(c)
|
||||
ctx.addToken(token.CollectEntry(string(ctx.obuf), s.pos()))
|
||||
s.progressColumn(ctx, 1)
|
||||
return
|
||||
}
|
||||
case ':':
|
||||
nc := ctx.nextChar()
|
||||
if s.startedFlowMapNum > 0 || nc == ' ' || s.isNewLineChar(nc) || ctx.isNextEOS() {
|
||||
// mapping value
|
||||
tk := s.bufferedToken(ctx)
|
||||
if tk != nil {
|
||||
s.prevIndentColumn = tk.Position.Column
|
||||
ctx.addToken(tk)
|
||||
} else if tk := ctx.lastToken(); tk != nil {
|
||||
// If the map key is quote, the buffer does not exist because it has already been cut into tokens.
|
||||
// Therefore, we need to check the last token.
|
||||
if tk.Indicator == token.QuotedScalarIndicator {
|
||||
s.prevIndentColumn = tk.Position.Column
|
||||
}
|
||||
}
|
||||
ctx.addToken(token.MappingValue(s.pos()))
|
||||
s.progressColumn(ctx, 1)
|
||||
return
|
||||
}
|
||||
case '|', '>':
|
||||
if !ctx.existsBuffer() {
|
||||
progress, err := s.scanLiteralHeader(ctx)
|
||||
if err != nil {
|
||||
// TODO: returns syntax error object
|
||||
return
|
||||
}
|
||||
s.progressColumn(ctx, progress)
|
||||
s.progressLine(ctx)
|
||||
continue
|
||||
}
|
||||
case '!':
|
||||
if !ctx.existsBuffer() {
|
||||
token, progress := s.scanTag(ctx)
|
||||
ctx.addToken(token)
|
||||
s.progressColumn(ctx, progress)
|
||||
if c := ctx.previousChar(); s.isNewLineChar(c) {
|
||||
s.progressLine(ctx)
|
||||
}
|
||||
pos += progress
|
||||
return
|
||||
}
|
||||
case '%':
|
||||
if !ctx.existsBuffer() && s.indentNum == 0 {
|
||||
ctx.addToken(token.Directive(string(ctx.obuf)+"%", s.pos()))
|
||||
s.progressColumn(ctx, 1)
|
||||
return
|
||||
}
|
||||
case '?':
|
||||
nc := ctx.nextChar()
|
||||
if !ctx.existsBuffer() && nc == ' ' {
|
||||
ctx.addToken(token.MappingKey(s.pos()))
|
||||
s.progressColumn(ctx, 1)
|
||||
return
|
||||
}
|
||||
case '&':
|
||||
if !ctx.existsBuffer() {
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
ctx.addOriginBuf(c)
|
||||
ctx.addToken(token.Anchor(string(ctx.obuf), s.pos()))
|
||||
s.progressColumn(ctx, 1)
|
||||
s.isAnchor = true
|
||||
return
|
||||
}
|
||||
case '*':
|
||||
if !ctx.existsBuffer() {
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
ctx.addOriginBuf(c)
|
||||
ctx.addToken(token.Alias(string(ctx.obuf), s.pos()))
|
||||
s.progressColumn(ctx, 1)
|
||||
return
|
||||
}
|
||||
case '#':
|
||||
if !ctx.existsBuffer() || ctx.previousChar() == ' ' {
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
token, progress := s.scanComment(ctx)
|
||||
ctx.addToken(token)
|
||||
s.progressColumn(ctx, progress)
|
||||
s.progressLine(ctx)
|
||||
pos += progress
|
||||
return
|
||||
}
|
||||
case '\'', '"':
|
||||
if !ctx.existsBuffer() {
|
||||
token, progress := s.scanQuote(ctx, c)
|
||||
ctx.addToken(token)
|
||||
pos += progress
|
||||
// If the non-whitespace character immediately following the quote is ':', the quote should be treated as a map key.
|
||||
// Therefore, do not return and continue processing as a normal map key.
|
||||
if ctx.currentCharWithSkipWhitespace() == ':' {
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
case '\r', '\n':
|
||||
// There is no problem that we ignore CR which followed by LF and normalize it to LF, because of following YAML1.2 spec.
|
||||
// > Line breaks inside scalar content must be normalized by the YAML processor. Each such line break must be parsed into a single line feed character.
|
||||
// > Outside scalar content, YAML allows any line break to be used to terminate lines.
|
||||
// > -- https://yaml.org/spec/1.2/spec.html
|
||||
if c == '\r' && ctx.nextChar() == '\n' {
|
||||
ctx.addOriginBuf('\r')
|
||||
ctx.progress(1)
|
||||
c = '\n'
|
||||
}
|
||||
s.scanNewLine(ctx, c)
|
||||
continue
|
||||
case ' ':
|
||||
if ctx.isSaveIndentMode() || (!s.isAnchor && !s.isFirstCharAtLine) {
|
||||
ctx.addBuf(c)
|
||||
ctx.addOriginBuf(c)
|
||||
s.progressColumn(ctx, 1)
|
||||
continue
|
||||
}
|
||||
if s.isFirstCharAtLine {
|
||||
s.progressColumn(ctx, 1)
|
||||
ctx.addOriginBuf(c)
|
||||
continue
|
||||
}
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
pos-- // to rescan white space at next scanning for adding white space to next buffer.
|
||||
s.isAnchor = false
|
||||
return
|
||||
}
|
||||
ctx.addBuf(c)
|
||||
ctx.addOriginBuf(c)
|
||||
s.progressColumn(ctx, 1)
|
||||
}
|
||||
s.addBufferedTokenIfExists(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
// Init prepares the scanner s to tokenize the text src by setting the scanner at the beginning of src.
|
||||
func (s *Scanner) Init(text string) {
|
||||
src := []rune(text)
|
||||
s.source = src
|
||||
s.sourcePos = 0
|
||||
s.sourceSize = len(src)
|
||||
s.line = 1
|
||||
s.column = 1
|
||||
s.offset = 1
|
||||
s.prevIndentLevel = 0
|
||||
s.prevIndentNum = 0
|
||||
s.prevIndentColumn = 0
|
||||
s.indentLevel = 0
|
||||
s.indentNum = 0
|
||||
s.isFirstCharAtLine = true
|
||||
}
|
||||
|
||||
// Scan scans the next token and returns the token collection. The source end is indicated by io.EOF.
|
||||
func (s *Scanner) Scan() (token.Tokens, error) {
|
||||
if s.sourcePos >= s.sourceSize {
|
||||
return nil, io.EOF
|
||||
}
|
||||
ctx := newContext(s.source[s.sourcePos:])
|
||||
defer ctx.release()
|
||||
progress := s.scan(ctx)
|
||||
s.sourcePos += progress
|
||||
var tokens token.Tokens
|
||||
tokens = append(tokens, ctx.tokens...)
|
||||
return tokens, nil
|
||||
}
|
||||
103
vendor/github.com/goccy/go-yaml/stdlib_quote.go
generated
vendored
Normal file
103
vendor/github.com/goccy/go-yaml/stdlib_quote.go
generated
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copied and trimmed down from https://github.com/golang/go/blob/e3769299cd3484e018e0e2a6e1b95c2b18ce4f41/src/strconv/quote.go
|
||||
// We want to use the standard library's private "quoteWith" function rather than write our own so that we get robust unicode support.
|
||||
// Every private function called by quoteWith was copied.
|
||||
// There are 2 modifications to simplify the code:
|
||||
// 1. The unicode.IsPrint function was substituted for the custom implementation of IsPrint
|
||||
// 2. All code paths reachable only when ASCIIonly or grphicOnly are set to true were removed.
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
lowerhex = "0123456789abcdef"
|
||||
)
|
||||
|
||||
func quoteWith(s string, quote byte) string {
|
||||
return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote))
|
||||
}
|
||||
|
||||
func appendQuotedWith(buf []byte, s string, quote byte) []byte {
|
||||
// Often called with big strings, so preallocate. If there's quoting,
|
||||
// this is conservative but still helps a lot.
|
||||
if cap(buf)-len(buf) < len(s) {
|
||||
nBuf := make([]byte, len(buf), len(buf)+1+len(s)+1)
|
||||
copy(nBuf, buf)
|
||||
buf = nBuf
|
||||
}
|
||||
buf = append(buf, quote)
|
||||
for width := 0; len(s) > 0; s = s[width:] {
|
||||
r := rune(s[0])
|
||||
width = 1
|
||||
if r >= utf8.RuneSelf {
|
||||
r, width = utf8.DecodeRuneInString(s)
|
||||
}
|
||||
if width == 1 && r == utf8.RuneError {
|
||||
buf = append(buf, `\x`...)
|
||||
buf = append(buf, lowerhex[s[0]>>4])
|
||||
buf = append(buf, lowerhex[s[0]&0xF])
|
||||
continue
|
||||
}
|
||||
buf = appendEscapedRune(buf, r, quote)
|
||||
}
|
||||
buf = append(buf, quote)
|
||||
return buf
|
||||
}
|
||||
|
||||
func appendEscapedRune(buf []byte, r rune, quote byte) []byte {
|
||||
var runeTmp [utf8.UTFMax]byte
|
||||
if r == rune(quote) || r == '\\' { // always backslashed
|
||||
buf = append(buf, '\\')
|
||||
buf = append(buf, byte(r))
|
||||
return buf
|
||||
}
|
||||
if unicode.IsPrint(r) {
|
||||
n := utf8.EncodeRune(runeTmp[:], r)
|
||||
buf = append(buf, runeTmp[:n]...)
|
||||
return buf
|
||||
}
|
||||
switch r {
|
||||
case '\a':
|
||||
buf = append(buf, `\a`...)
|
||||
case '\b':
|
||||
buf = append(buf, `\b`...)
|
||||
case '\f':
|
||||
buf = append(buf, `\f`...)
|
||||
case '\n':
|
||||
buf = append(buf, `\n`...)
|
||||
case '\r':
|
||||
buf = append(buf, `\r`...)
|
||||
case '\t':
|
||||
buf = append(buf, `\t`...)
|
||||
case '\v':
|
||||
buf = append(buf, `\v`...)
|
||||
default:
|
||||
switch {
|
||||
case r < ' ':
|
||||
buf = append(buf, `\x`...)
|
||||
buf = append(buf, lowerhex[byte(r)>>4])
|
||||
buf = append(buf, lowerhex[byte(r)&0xF])
|
||||
case r > utf8.MaxRune:
|
||||
r = 0xFFFD
|
||||
fallthrough
|
||||
case r < 0x10000:
|
||||
buf = append(buf, `\u`...)
|
||||
for s := 12; s >= 0; s -= 4 {
|
||||
buf = append(buf, lowerhex[r>>uint(s)&0xF])
|
||||
}
|
||||
default:
|
||||
buf = append(buf, `\U`...)
|
||||
for s := 28; s >= 0; s -= 4 {
|
||||
buf = append(buf, lowerhex[r>>uint(s)&0xF])
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf
|
||||
}
|
||||
130
vendor/github.com/goccy/go-yaml/struct.go
generated
vendored
Normal file
130
vendor/github.com/goccy/go-yaml/struct.go
generated
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
package yaml
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
// StructTagName tag keyword for Marshal/Unmarshal
|
||||
StructTagName = "yaml"
|
||||
)
|
||||
|
||||
// StructField information for each the field in structure
|
||||
type StructField struct {
|
||||
FieldName string
|
||||
RenderName string
|
||||
AnchorName string
|
||||
AliasName string
|
||||
IsAutoAnchor bool
|
||||
IsAutoAlias bool
|
||||
IsOmitEmpty bool
|
||||
IsFlow bool
|
||||
IsInline bool
|
||||
}
|
||||
|
||||
func getTag(field reflect.StructField) string {
|
||||
// If struct tag `yaml` exist, use that. If no `yaml`
|
||||
// exists, but `json` does, use that and try the best to
|
||||
// adhere to its rules
|
||||
tag := field.Tag.Get(StructTagName)
|
||||
if tag == "" {
|
||||
tag = field.Tag.Get(`json`)
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
func structField(field reflect.StructField) *StructField {
|
||||
tag := getTag(field)
|
||||
fieldName := strings.ToLower(field.Name)
|
||||
options := strings.Split(tag, ",")
|
||||
if len(options) > 0 {
|
||||
if options[0] != "" {
|
||||
fieldName = options[0]
|
||||
}
|
||||
}
|
||||
structField := &StructField{
|
||||
FieldName: field.Name,
|
||||
RenderName: fieldName,
|
||||
}
|
||||
if len(options) > 1 {
|
||||
for _, opt := range options[1:] {
|
||||
switch {
|
||||
case opt == "omitempty":
|
||||
structField.IsOmitEmpty = true
|
||||
case opt == "flow":
|
||||
structField.IsFlow = true
|
||||
case opt == "inline":
|
||||
structField.IsInline = true
|
||||
case strings.HasPrefix(opt, "anchor"):
|
||||
anchor := strings.Split(opt, "=")
|
||||
if len(anchor) > 1 {
|
||||
structField.AnchorName = anchor[1]
|
||||
} else {
|
||||
structField.IsAutoAnchor = true
|
||||
}
|
||||
case strings.HasPrefix(opt, "alias"):
|
||||
alias := strings.Split(opt, "=")
|
||||
if len(alias) > 1 {
|
||||
structField.AliasName = alias[1]
|
||||
} else {
|
||||
structField.IsAutoAlias = true
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
return structField
|
||||
}
|
||||
|
||||
func isIgnoredStructField(field reflect.StructField) bool {
|
||||
if field.PkgPath != "" && !field.Anonymous {
|
||||
// private field
|
||||
return true
|
||||
}
|
||||
tag := getTag(field)
|
||||
if tag == "-" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type StructFieldMap map[string]*StructField
|
||||
|
||||
func (m StructFieldMap) isIncludedRenderName(name string) bool {
|
||||
for _, v := range m {
|
||||
if !v.IsInline && v.RenderName == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m StructFieldMap) hasMergeProperty() bool {
|
||||
for _, v := range m {
|
||||
if v.IsOmitEmpty && v.IsInline && v.IsAutoAlias {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func structFieldMap(structType reflect.Type) (StructFieldMap, error) {
|
||||
structFieldMap := StructFieldMap{}
|
||||
renderNameMap := map[string]struct{}{}
|
||||
for i := 0; i < structType.NumField(); i++ {
|
||||
field := structType.Field(i)
|
||||
if isIgnoredStructField(field) {
|
||||
continue
|
||||
}
|
||||
structField := structField(field)
|
||||
if _, exists := renderNameMap[structField.RenderName]; exists {
|
||||
return nil, xerrors.Errorf("duplicated struct field name %s", structField.RenderName)
|
||||
}
|
||||
structFieldMap[structField.FieldName] = structField
|
||||
renderNameMap[structField.RenderName] = struct{}{}
|
||||
}
|
||||
return structFieldMap, nil
|
||||
}
|
||||
1070
vendor/github.com/goccy/go-yaml/token/token.go
generated
vendored
Normal file
1070
vendor/github.com/goccy/go-yaml/token/token.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
13
vendor/github.com/goccy/go-yaml/validate.go
generated
vendored
Normal file
13
vendor/github.com/goccy/go-yaml/validate.go
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package yaml
|
||||
|
||||
// StructValidator need to implement Struct method only
|
||||
// ( see https://pkg.go.dev/github.com/go-playground/validator/v10#Validate.Struct )
|
||||
type StructValidator interface {
|
||||
Struct(interface{}) error
|
||||
}
|
||||
|
||||
// FieldError need to implement StructField method only
|
||||
// ( see https://pkg.go.dev/github.com/go-playground/validator/v10#FieldError )
|
||||
type FieldError interface {
|
||||
StructField() string
|
||||
}
|
||||
290
vendor/github.com/goccy/go-yaml/yaml.go
generated
vendored
Normal file
290
vendor/github.com/goccy/go-yaml/yaml.go
generated
vendored
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
package yaml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/goccy/go-yaml/ast"
|
||||
"github.com/goccy/go-yaml/internal/errors"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// BytesMarshaler interface may be implemented by types to customize their
|
||||
// behavior when being marshaled into a YAML document. The returned value
|
||||
// is marshaled in place of the original value implementing Marshaler.
|
||||
//
|
||||
// If an error is returned by MarshalYAML, the marshaling procedure stops
|
||||
// and returns with the provided error.
|
||||
type BytesMarshaler interface {
|
||||
MarshalYAML() ([]byte, error)
|
||||
}
|
||||
|
||||
// BytesMarshalerContext interface use BytesMarshaler with context.Context.
|
||||
type BytesMarshalerContext interface {
|
||||
MarshalYAML(context.Context) ([]byte, error)
|
||||
}
|
||||
|
||||
// InterfaceMarshaler interface has MarshalYAML compatible with github.com/go-yaml/yaml package.
|
||||
type InterfaceMarshaler interface {
|
||||
MarshalYAML() (interface{}, error)
|
||||
}
|
||||
|
||||
// InterfaceMarshalerContext interface use InterfaceMarshaler with context.Context.
|
||||
type InterfaceMarshalerContext interface {
|
||||
MarshalYAML(context.Context) (interface{}, error)
|
||||
}
|
||||
|
||||
// BytesUnmarshaler interface may be implemented by types to customize their
|
||||
// behavior when being unmarshaled from a YAML document.
|
||||
type BytesUnmarshaler interface {
|
||||
UnmarshalYAML([]byte) error
|
||||
}
|
||||
|
||||
// BytesUnmarshalerContext interface use BytesUnmarshaler with context.Context.
|
||||
type BytesUnmarshalerContext interface {
|
||||
UnmarshalYAML(context.Context, []byte) error
|
||||
}
|
||||
|
||||
// InterfaceUnmarshaler interface has UnmarshalYAML compatible with github.com/go-yaml/yaml package.
|
||||
type InterfaceUnmarshaler interface {
|
||||
UnmarshalYAML(func(interface{}) error) error
|
||||
}
|
||||
|
||||
// InterfaceUnmarshalerContext interface use InterfaceUnmarshaler with context.Context.
|
||||
type InterfaceUnmarshalerContext interface {
|
||||
UnmarshalYAML(context.Context, func(interface{}) error) error
|
||||
}
|
||||
|
||||
// MapItem is an item in a MapSlice.
|
||||
type MapItem struct {
|
||||
Key, Value interface{}
|
||||
}
|
||||
|
||||
// MapSlice encodes and decodes as a YAML map.
|
||||
// The order of keys is preserved when encoding and decoding.
|
||||
type MapSlice []MapItem
|
||||
|
||||
// ToMap convert to map[interface{}]interface{}.
|
||||
func (s MapSlice) ToMap() map[interface{}]interface{} {
|
||||
v := map[interface{}]interface{}{}
|
||||
for _, item := range s {
|
||||
v[item.Key] = item.Value
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Marshal serializes the value provided into a YAML document. The structure
|
||||
// of the generated document will reflect the structure of the value itself.
|
||||
// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
|
||||
//
|
||||
// Struct fields are only marshalled if they are exported (have an upper case
|
||||
// first letter), and are marshalled using the field name lowercased as the
|
||||
// default key. Custom keys may be defined via the "yaml" name in the field
|
||||
// tag: the content preceding the first comma is used as the key, and the
|
||||
// following comma-separated options are used to tweak the marshalling process.
|
||||
// Conflicting names result in a runtime error.
|
||||
//
|
||||
// The field tag format accepted is:
|
||||
//
|
||||
// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
|
||||
//
|
||||
// The following flags are currently supported:
|
||||
//
|
||||
// omitempty Only include the field if it's not set to the zero
|
||||
// value for the type or to empty slices or maps.
|
||||
// Zero valued structs will be omitted if all their public
|
||||
// fields are zero, unless they implement an IsZero
|
||||
// method (see the IsZeroer interface type), in which
|
||||
// case the field will be included if that method returns true.
|
||||
//
|
||||
// flow Marshal using a flow style (useful for structs,
|
||||
// sequences and maps).
|
||||
//
|
||||
// inline Inline the field, which must be a struct or a map,
|
||||
// causing all of its fields or keys to be processed as if
|
||||
// they were part of the outer struct. For maps, keys must
|
||||
// not conflict with the yaml keys of other struct fields.
|
||||
//
|
||||
// anchor Marshal with anchor. If want to define anchor name explicitly, use anchor=name style.
|
||||
// Otherwise, if used 'anchor' name only, used the field name lowercased as the anchor name
|
||||
//
|
||||
// alias Marshal with alias. If want to define alias name explicitly, use alias=name style.
|
||||
// Otherwise, If omitted alias name and the field type is pointer type,
|
||||
// assigned anchor name automatically from same pointer address.
|
||||
//
|
||||
// In addition, if the key is "-", the field is ignored.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// type T struct {
|
||||
// F int `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
|
||||
// yaml.Marshal(&T{F: 1}) // Returns "a: 1\nb: 0\n"
|
||||
//
|
||||
func Marshal(v interface{}) ([]byte, error) {
|
||||
return MarshalWithOptions(v)
|
||||
}
|
||||
|
||||
// MarshalWithOptions serializes the value provided into a YAML document with EncodeOptions.
|
||||
func MarshalWithOptions(v interface{}, opts ...EncodeOption) ([]byte, error) {
|
||||
return MarshalContext(context.Background(), v, opts...)
|
||||
}
|
||||
|
||||
// MarshalContext serializes the value provided into a YAML document with context.Context and EncodeOptions.
|
||||
func MarshalContext(ctx context.Context, v interface{}, opts ...EncodeOption) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := NewEncoder(&buf, opts...).EncodeContext(ctx, v); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to marshal")
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// ValueToNode convert from value to ast.Node.
|
||||
func ValueToNode(v interface{}, opts ...EncodeOption) (ast.Node, error) {
|
||||
var buf bytes.Buffer
|
||||
node, err := NewEncoder(&buf, opts...).EncodeToNode(v)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to convert value to node")
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// Unmarshal decodes the first document found within the in byte slice
|
||||
// and assigns decoded values into the out value.
|
||||
//
|
||||
// Struct fields are only unmarshalled if they are exported (have an
|
||||
// upper case first letter), and are unmarshalled using the field name
|
||||
// lowercased as the default key. Custom keys may be defined via the
|
||||
// "yaml" name in the field tag: the content preceding the first comma
|
||||
// is used as the key, and the following comma-separated options are
|
||||
// used to tweak the marshalling process (see Marshal).
|
||||
// Conflicting names result in a runtime error.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// type T struct {
|
||||
// F int `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// var t T
|
||||
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
|
||||
//
|
||||
// See the documentation of Marshal for the format of tags and a list of
|
||||
// supported tag options.
|
||||
//
|
||||
func Unmarshal(data []byte, v interface{}) error {
|
||||
return UnmarshalWithOptions(data, v)
|
||||
}
|
||||
|
||||
// UnmarshalWithOptions decodes with DecodeOptions the first document found within the in byte slice
|
||||
// and assigns decoded values into the out value.
|
||||
func UnmarshalWithOptions(data []byte, v interface{}, opts ...DecodeOption) error {
|
||||
return UnmarshalContext(context.Background(), data, v, opts...)
|
||||
}
|
||||
|
||||
// UnmarshalContext decodes with context.Context and DecodeOptions.
|
||||
func UnmarshalContext(ctx context.Context, data []byte, v interface{}, opts ...DecodeOption) error {
|
||||
dec := NewDecoder(bytes.NewBuffer(data), opts...)
|
||||
if err := dec.DecodeContext(ctx, v); err != nil {
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(err, "failed to unmarshal")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NodeToValue converts node to the value pointed to by v.
|
||||
func NodeToValue(node ast.Node, v interface{}, opts ...DecodeOption) error {
|
||||
var buf bytes.Buffer
|
||||
if err := NewDecoder(&buf, opts...).DecodeFromNode(node, v); err != nil {
|
||||
return errors.Wrapf(err, "failed to convert node to value")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FormatError is a utility function that takes advantage of the metadata
|
||||
// stored in the errors returned by this package's parser.
|
||||
//
|
||||
// If the second argument `colored` is true, the error message is colorized.
|
||||
// If the third argument `inclSource` is true, the error message will
|
||||
// contain snippets of the YAML source that was used.
|
||||
func FormatError(e error, colored, inclSource bool) string {
|
||||
var pp errors.PrettyPrinter
|
||||
if xerrors.As(e, &pp) {
|
||||
var buf bytes.Buffer
|
||||
pp.PrettyPrint(&errors.Sink{&buf}, colored, inclSource)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
// YAMLToJSON convert YAML bytes to JSON.
|
||||
func YAMLToJSON(bytes []byte) ([]byte, error) {
|
||||
var v interface{}
|
||||
if err := UnmarshalWithOptions(bytes, &v, UseOrderedMap()); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unmarshal")
|
||||
}
|
||||
out, err := MarshalWithOptions(v, JSON())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to marshal with json option")
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// JSONToYAML convert JSON bytes to YAML.
|
||||
func JSONToYAML(bytes []byte) ([]byte, error) {
|
||||
var v interface{}
|
||||
if err := UnmarshalWithOptions(bytes, &v, UseOrderedMap()); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unmarshal from json bytes")
|
||||
}
|
||||
out, err := Marshal(v)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to marshal")
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
var (
|
||||
globalCustomMarshalerMu sync.Mutex
|
||||
globalCustomUnmarshalerMu sync.Mutex
|
||||
globalCustomMarshalerMap = map[reflect.Type]func(interface{}) ([]byte, error){}
|
||||
globalCustomUnmarshalerMap = map[reflect.Type]func(interface{}, []byte) error{}
|
||||
)
|
||||
|
||||
// RegisterCustomMarshaler overrides any encoding process for the type specified in generics.
|
||||
// If you want to switch the behavior for each encoder, use `CustomMarshaler` defined as EncodeOption.
|
||||
//
|
||||
// NOTE: If type T implements MarshalYAML for pointer receiver, the type specified in RegisterCustomMarshaler must be *T.
|
||||
// If RegisterCustomMarshaler and CustomMarshaler of EncodeOption are specified for the same type,
|
||||
// the CustomMarshaler specified in EncodeOption takes precedence.
|
||||
func RegisterCustomMarshaler[T any](marshaler func(T) ([]byte, error)) {
|
||||
globalCustomMarshalerMu.Lock()
|
||||
defer globalCustomMarshalerMu.Unlock()
|
||||
|
||||
var typ T
|
||||
globalCustomMarshalerMap[reflect.TypeOf(typ)] = func(v interface{}) ([]byte, error) {
|
||||
return marshaler(v.(T))
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterCustomUnmarshaler overrides any decoding process for the type specified in generics.
|
||||
// If you want to switch the behavior for each decoder, use `CustomUnmarshaler` defined as DecodeOption.
|
||||
//
|
||||
// NOTE: If RegisterCustomUnmarshaler and CustomUnmarshaler of DecodeOption are specified for the same type,
|
||||
// the CustomUnmarshaler specified in DecodeOption takes precedence.
|
||||
func RegisterCustomUnmarshaler[T any](unmarshaler func(*T, []byte) error) {
|
||||
globalCustomUnmarshalerMu.Lock()
|
||||
defer globalCustomUnmarshalerMu.Unlock()
|
||||
|
||||
var typ *T
|
||||
globalCustomUnmarshalerMap[reflect.TypeOf(typ)] = func(v interface{}, b []byte) error {
|
||||
return unmarshaler(v.(*T), b)
|
||||
}
|
||||
}
|
||||
12
vendor/github.com/mattn/go-colorable/.travis.yml
generated
vendored
12
vendor/github.com/mattn/go-colorable/.travis.yml
generated
vendored
|
|
@ -1,9 +1,15 @@
|
|||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.13.x
|
||||
- tip
|
||||
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get -t -v ./...
|
||||
|
||||
script:
|
||||
- $HOME/gopath/bin/goveralls -repotoken xnXqRGwgW3SXIguzxf90ZSK1GPYZPaGrw
|
||||
- ./go.test.sh
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
|
|
|
|||
4
vendor/github.com/mattn/go-colorable/README.md
generated
vendored
4
vendor/github.com/mattn/go-colorable/README.md
generated
vendored
|
|
@ -1,8 +1,8 @@
|
|||
# go-colorable
|
||||
|
||||
[](http://godoc.org/github.com/mattn/go-colorable)
|
||||
[](https://travis-ci.org/mattn/go-colorable)
|
||||
[](https://coveralls.io/github/mattn/go-colorable?branch=master)
|
||||
[](https://codecov.io/gh/mattn/go-colorable)
|
||||
[](http://godoc.org/github.com/mattn/go-colorable)
|
||||
[](https://goreportcard.com/report/mattn/go-colorable)
|
||||
|
||||
Colorable writer for windows.
|
||||
|
|
|
|||
8
vendor/github.com/mattn/go-colorable/colorable_appengine.go
generated
vendored
8
vendor/github.com/mattn/go-colorable/colorable_appengine.go
generated
vendored
|
|
@ -27,3 +27,11 @@ func NewColorableStdout() io.Writer {
|
|||
func NewColorableStderr() io.Writer {
|
||||
return os.Stderr
|
||||
}
|
||||
|
||||
// EnableColorsStdout enable colors if possible.
|
||||
func EnableColorsStdout(enabled *bool) func() {
|
||||
if enabled != nil {
|
||||
*enabled = true
|
||||
}
|
||||
return func() {}
|
||||
}
|
||||
|
|
|
|||
8
vendor/github.com/mattn/go-colorable/colorable_others.go
generated
vendored
8
vendor/github.com/mattn/go-colorable/colorable_others.go
generated
vendored
|
|
@ -28,3 +28,11 @@ func NewColorableStdout() io.Writer {
|
|||
func NewColorableStderr() io.Writer {
|
||||
return os.Stderr
|
||||
}
|
||||
|
||||
// EnableColorsStdout enable colors if possible.
|
||||
func EnableColorsStdout(enabled *bool) func() {
|
||||
if enabled != nil {
|
||||
*enabled = true
|
||||
}
|
||||
return func() {}
|
||||
}
|
||||
|
|
|
|||
56
vendor/github.com/mattn/go-colorable/colorable_windows.go
generated
vendored
56
vendor/github.com/mattn/go-colorable/colorable_windows.go
generated
vendored
|
|
@ -10,6 +10,7 @@ import (
|
|||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
|
|
@ -27,6 +28,9 @@ const (
|
|||
backgroundRed = 0x40
|
||||
backgroundIntensity = 0x80
|
||||
backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
|
||||
commonLvbUnderscore = 0x8000
|
||||
|
||||
cENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -78,6 +82,8 @@ var (
|
|||
procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
|
||||
procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
|
||||
procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
|
||||
procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer")
|
||||
)
|
||||
|
||||
|
|
@ -89,6 +95,7 @@ type Writer struct {
|
|||
oldattr word
|
||||
oldpos coord
|
||||
rest bytes.Buffer
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// NewColorable returns new instance of Writer which handles escape sequence from File.
|
||||
|
|
@ -98,6 +105,10 @@ func NewColorable(file *os.File) io.Writer {
|
|||
}
|
||||
|
||||
if isatty.IsTerminal(file.Fd()) {
|
||||
var mode uint32
|
||||
if r, _, _ := procGetConsoleMode.Call(file.Fd(), uintptr(unsafe.Pointer(&mode))); r != 0 && mode&cENABLE_VIRTUAL_TERMINAL_PROCESSING != 0 {
|
||||
return file
|
||||
}
|
||||
var csbi consoleScreenBufferInfo
|
||||
handle := syscall.Handle(file.Fd())
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
|
|
@ -424,6 +435,8 @@ func atoiWithDefault(s string, def int) (int, error) {
|
|||
|
||||
// Write writes data on console
|
||||
func (w *Writer) Write(data []byte) (n int, err error) {
|
||||
w.mutex.Lock()
|
||||
defer w.mutex.Unlock()
|
||||
var csbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
|
||||
|
|
@ -675,14 +688,19 @@ loop:
|
|||
switch {
|
||||
case n == 0 || n == 100:
|
||||
attr = w.oldattr
|
||||
case 1 <= n && n <= 5:
|
||||
case n == 4:
|
||||
attr |= commonLvbUnderscore
|
||||
case (1 <= n && n <= 3) || n == 5:
|
||||
attr |= foregroundIntensity
|
||||
case n == 7:
|
||||
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
|
||||
case n == 22 || n == 25:
|
||||
attr |= foregroundIntensity
|
||||
case n == 27:
|
||||
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
|
||||
case n == 7 || n == 27:
|
||||
attr =
|
||||
(attr &^ (foregroundMask | backgroundMask)) |
|
||||
((attr & foregroundMask) << 4) |
|
||||
((attr & backgroundMask) >> 4)
|
||||
case n == 22:
|
||||
attr &^= foregroundIntensity
|
||||
case n == 24:
|
||||
attr &^= commonLvbUnderscore
|
||||
case 30 <= n && n <= 37:
|
||||
attr &= backgroundMask
|
||||
if (n-30)&1 != 0 {
|
||||
|
|
@ -701,7 +719,7 @@ loop:
|
|||
n256setup()
|
||||
}
|
||||
attr &= backgroundMask
|
||||
attr |= n256foreAttr[n256]
|
||||
attr |= n256foreAttr[n256%len(n256foreAttr)]
|
||||
i += 2
|
||||
}
|
||||
} else if len(token) == 5 && token[i+1] == "2" {
|
||||
|
|
@ -743,7 +761,7 @@ loop:
|
|||
n256setup()
|
||||
}
|
||||
attr &= foregroundMask
|
||||
attr |= n256backAttr[n256]
|
||||
attr |= n256backAttr[n256%len(n256backAttr)]
|
||||
i += 2
|
||||
}
|
||||
} else if len(token) == 5 && token[i+1] == "2" {
|
||||
|
|
@ -1003,3 +1021,23 @@ func n256setup() {
|
|||
n256backAttr[i] = c.backgroundAttr()
|
||||
}
|
||||
}
|
||||
|
||||
// EnableColorsStdout enable colors if possible.
|
||||
func EnableColorsStdout(enabled *bool) func() {
|
||||
var mode uint32
|
||||
h := os.Stdout.Fd()
|
||||
if r, _, _ := procGetConsoleMode.Call(h, uintptr(unsafe.Pointer(&mode))); r != 0 {
|
||||
if r, _, _ = procSetConsoleMode.Call(h, uintptr(mode|cENABLE_VIRTUAL_TERMINAL_PROCESSING)); r != 0 {
|
||||
if enabled != nil {
|
||||
*enabled = true
|
||||
}
|
||||
return func() {
|
||||
procSetConsoleMode.Call(h, uintptr(mode))
|
||||
}
|
||||
}
|
||||
}
|
||||
if enabled != nil {
|
||||
*enabled = true
|
||||
}
|
||||
return func() {}
|
||||
}
|
||||
|
|
|
|||
12
vendor/github.com/mattn/go-colorable/go.test.sh
generated
vendored
Normal file
12
vendor/github.com/mattn/go-colorable/go.test.sh
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
echo "" > coverage.txt
|
||||
|
||||
for d in $(go list ./... | grep -v vendor); do
|
||||
go test -race -coverprofile=profile.out -covermode=atomic "$d"
|
||||
if [ -f profile.out ]; then
|
||||
cat profile.out >> coverage.txt
|
||||
rm profile.out
|
||||
fi
|
||||
done
|
||||
15
vendor/github.com/mattn/go-isatty/.travis.yml
generated
vendored
15
vendor/github.com/mattn/go-isatty/.travis.yml
generated
vendored
|
|
@ -1,13 +1,14 @@
|
|||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.13.x
|
||||
- tip
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get -t -v ./...
|
||||
|
||||
script:
|
||||
- $HOME/gopath/bin/goveralls -repotoken 3gHdORO5k5ziZcWMBxnd9LrMZaJs8m9x5
|
||||
- ./go.test.sh
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
|
|
|||
2
vendor/github.com/mattn/go-isatty/README.md
generated
vendored
2
vendor/github.com/mattn/go-isatty/README.md
generated
vendored
|
|
@ -1,7 +1,7 @@
|
|||
# go-isatty
|
||||
|
||||
[](http://godoc.org/github.com/mattn/go-isatty)
|
||||
[](https://travis-ci.org/mattn/go-isatty)
|
||||
[](https://codecov.io/gh/mattn/go-isatty)
|
||||
[](https://coveralls.io/github/mattn/go-isatty?branch=master)
|
||||
[](https://goreportcard.com/report/mattn/go-isatty)
|
||||
|
||||
|
|
|
|||
12
vendor/github.com/mattn/go-isatty/go.test.sh
generated
vendored
Normal file
12
vendor/github.com/mattn/go-isatty/go.test.sh
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
echo "" > coverage.txt
|
||||
|
||||
for d in $(go list ./... | grep -v vendor); do
|
||||
go test -race -coverprofile=profile.out -covermode=atomic "$d"
|
||||
if [ -f profile.out ]; then
|
||||
cat profile.out >> coverage.txt
|
||||
rm profile.out
|
||||
fi
|
||||
done
|
||||
23
vendor/github.com/mattn/go-isatty/isatty_android.go
generated
vendored
23
vendor/github.com/mattn/go-isatty/isatty_android.go
generated
vendored
|
|
@ -1,23 +0,0 @@
|
|||
// +build android
|
||||
|
||||
package isatty
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const ioctlReadTermios = syscall.TCGETS
|
||||
|
||||
// IsTerminal return true if the file descriptor is terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
var termios syscall.Termios
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
}
|
||||
|
||||
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
|
||||
// terminal. This is also always false on this environment.
|
||||
func IsCygwinTerminal(fd uintptr) bool {
|
||||
return false
|
||||
}
|
||||
12
vendor/github.com/mattn/go-isatty/isatty_bsd.go
generated
vendored
12
vendor/github.com/mattn/go-isatty/isatty_bsd.go
generated
vendored
|
|
@ -3,18 +3,12 @@
|
|||
|
||||
package isatty
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
// IsTerminal return true if the file descriptor is terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
var termios syscall.Termios
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
_, err := unix.IoctlGetTermios(int(fd), unix.TIOCGETA)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
|
||||
|
|
|
|||
1
vendor/github.com/mattn/go-isatty/isatty_tcgets.go
generated
vendored
1
vendor/github.com/mattn/go-isatty/isatty_tcgets.go
generated
vendored
|
|
@ -1,6 +1,5 @@
|
|||
// +build linux aix
|
||||
// +build !appengine
|
||||
// +build !android
|
||||
|
||||
package isatty
|
||||
|
||||
|
|
|
|||
8
vendor/github.com/mattn/go-isatty/renovate.json
generated
vendored
Normal file
8
vendor/github.com/mattn/go-isatty/renovate.json
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
],
|
||||
"postUpdateOptions": [
|
||||
"gomodTidy"
|
||||
]
|
||||
}
|
||||
4
vendor/golang.org/x/sys/unix/gccgo.go
generated
vendored
4
vendor/golang.org/x/sys/unix/gccgo.go
generated
vendored
|
|
@ -2,8 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gccgo && !aix
|
||||
// +build gccgo,!aix
|
||||
//go:build gccgo && !aix && !hurd
|
||||
// +build gccgo,!aix,!hurd
|
||||
|
||||
package unix
|
||||
|
||||
|
|
|
|||
4
vendor/golang.org/x/sys/unix/gccgo_c.c
generated
vendored
4
vendor/golang.org/x/sys/unix/gccgo_c.c
generated
vendored
|
|
@ -2,8 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build gccgo
|
||||
// +build !aix
|
||||
//go:build gccgo && !aix && !hurd
|
||||
// +build gccgo,!aix,!hurd
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
|
|
|||
21
vendor/golang.org/x/sys/unix/ioctl.go
generated
vendored
21
vendor/golang.org/x/sys/unix/ioctl.go
generated
vendored
|
|
@ -2,13 +2,12 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
|
||||
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
|
@ -27,7 +26,7 @@ func IoctlSetInt(fd int, req uint, value int) error {
|
|||
// passing the integer value directly.
|
||||
func IoctlSetPointerInt(fd int, req uint, value int) error {
|
||||
v := int32(value)
|
||||
return ioctl(fd, req, uintptr(unsafe.Pointer(&v)))
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(&v))
|
||||
}
|
||||
|
||||
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
|
||||
|
|
@ -36,9 +35,7 @@ func IoctlSetPointerInt(fd int, req uint, value int) error {
|
|||
func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
|
||||
// TODO: if we get the chance, remove the req parameter and
|
||||
// hardcode TIOCSWINSZ.
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
|
||||
runtime.KeepAlive(value)
|
||||
return err
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(value))
|
||||
}
|
||||
|
||||
// IoctlSetTermios performs an ioctl on fd with a *Termios.
|
||||
|
|
@ -46,9 +43,7 @@ func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
|
|||
// The req value will usually be TCSETA or TIOCSETA.
|
||||
func IoctlSetTermios(fd int, req uint, value *Termios) error {
|
||||
// TODO: if we get the chance, remove the req parameter.
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
|
||||
runtime.KeepAlive(value)
|
||||
return err
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(value))
|
||||
}
|
||||
|
||||
// IoctlGetInt performs an ioctl operation which gets an integer value
|
||||
|
|
@ -58,18 +53,18 @@ func IoctlSetTermios(fd int, req uint, value *Termios) error {
|
|||
// for those, IoctlRetInt should be used instead of this function.
|
||||
func IoctlGetInt(fd int, req uint) (int, error) {
|
||||
var value int
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return value, err
|
||||
}
|
||||
|
||||
func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
|
||||
var value Winsize
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return &value, err
|
||||
}
|
||||
|
||||
func IoctlGetTermios(fd int, req uint) (*Termios, error) {
|
||||
var value Termios
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return &value, err
|
||||
}
|
||||
|
|
|
|||
8
vendor/golang.org/x/sys/unix/ioctl_zos.go
generated
vendored
8
vendor/golang.org/x/sys/unix/ioctl_zos.go
generated
vendored
|
|
@ -27,9 +27,7 @@ func IoctlSetInt(fd int, req uint, value int) error {
|
|||
func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
|
||||
// TODO: if we get the chance, remove the req parameter and
|
||||
// hardcode TIOCSWINSZ.
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
|
||||
runtime.KeepAlive(value)
|
||||
return err
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(value))
|
||||
}
|
||||
|
||||
// IoctlSetTermios performs an ioctl on fd with a *Termios.
|
||||
|
|
@ -51,13 +49,13 @@ func IoctlSetTermios(fd int, req uint, value *Termios) error {
|
|||
// for those, IoctlRetInt should be used instead of this function.
|
||||
func IoctlGetInt(fd int, req uint) (int, error) {
|
||||
var value int
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return value, err
|
||||
}
|
||||
|
||||
func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
|
||||
var value Winsize
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return &value, err
|
||||
}
|
||||
|
||||
|
|
|
|||
4
vendor/golang.org/x/sys/unix/mkall.sh
generated
vendored
4
vendor/golang.org/x/sys/unix/mkall.sh
generated
vendored
|
|
@ -174,10 +174,10 @@ openbsd_arm64)
|
|||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||
;;
|
||||
openbsd_mips64)
|
||||
mkasm="go run mkasm.go"
|
||||
mkerrors="$mkerrors -m64"
|
||||
mksyscall="go run mksyscall.go -openbsd"
|
||||
mksyscall="go run mksyscall.go -openbsd -libc"
|
||||
mksysctl="go run mksysctl_openbsd.go"
|
||||
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
|
||||
# Let the type of C char be signed for making the bare syscall
|
||||
# API consistent across platforms.
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
|
||||
|
|
|
|||
6
vendor/golang.org/x/sys/unix/ptrace_darwin.go
generated
vendored
6
vendor/golang.org/x/sys/unix/ptrace_darwin.go
generated
vendored
|
|
@ -7,6 +7,12 @@
|
|||
|
||||
package unix
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func ptrace(request int, pid int, addr uintptr, data uintptr) error {
|
||||
return ptrace1(request, pid, addr, data)
|
||||
}
|
||||
|
||||
func ptracePtr(request int, pid int, addr uintptr, data unsafe.Pointer) error {
|
||||
return ptrace1Ptr(request, pid, addr, data)
|
||||
}
|
||||
|
|
|
|||
6
vendor/golang.org/x/sys/unix/ptrace_ios.go
generated
vendored
6
vendor/golang.org/x/sys/unix/ptrace_ios.go
generated
vendored
|
|
@ -7,6 +7,12 @@
|
|||
|
||||
package unix
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
|
||||
return ENOTSUP
|
||||
}
|
||||
|
||||
func ptracePtr(request int, pid int, addr uintptr, data unsafe.Pointer) (err error) {
|
||||
return ENOTSUP
|
||||
}
|
||||
|
|
|
|||
14
vendor/golang.org/x/sys/unix/sockcmsg_unix.go
generated
vendored
14
vendor/golang.org/x/sys/unix/sockcmsg_unix.go
generated
vendored
|
|
@ -52,6 +52,20 @@ func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
|
|||
return msgs, nil
|
||||
}
|
||||
|
||||
// ParseOneSocketControlMessage parses a single socket control message from b, returning the message header,
|
||||
// message data (a slice of b), and the remainder of b after that single message.
|
||||
// When there are no remaining messages, len(remainder) == 0.
|
||||
func ParseOneSocketControlMessage(b []byte) (hdr Cmsghdr, data []byte, remainder []byte, err error) {
|
||||
h, dbuf, err := socketControlMessageHeaderAndData(b)
|
||||
if err != nil {
|
||||
return Cmsghdr{}, nil, nil, err
|
||||
}
|
||||
if i := cmsgAlignOf(int(h.Len)); i < len(b) {
|
||||
remainder = b[i:]
|
||||
}
|
||||
return *h, dbuf, remainder, nil
|
||||
}
|
||||
|
||||
func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
|
||||
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
|
||||
if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) {
|
||||
|
|
|
|||
5
vendor/golang.org/x/sys/unix/syscall_aix.go
generated
vendored
5
vendor/golang.org/x/sys/unix/syscall_aix.go
generated
vendored
|
|
@ -292,9 +292,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
|
||||
sa.Name = string(bytes)
|
||||
sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
|
||||
return sa, nil
|
||||
|
||||
case AF_INET:
|
||||
|
|
@ -411,6 +409,7 @@ func (w WaitStatus) CoreDump() bool { return w&0x80 == 0x80 }
|
|||
func (w WaitStatus) TrapCause() int { return -1 }
|
||||
|
||||
//sys ioctl(fd int, req uint, arg uintptr) (err error)
|
||||
//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = ioctl
|
||||
|
||||
// fcntl must never be called with cmd=F_DUP2FD because it doesn't work on AIX
|
||||
// There is no way to create a custom fcntl and to keep //sys fcntl easily,
|
||||
|
|
|
|||
3
vendor/golang.org/x/sys/unix/syscall_bsd.go
generated
vendored
3
vendor/golang.org/x/sys/unix/syscall_bsd.go
generated
vendored
|
|
@ -245,8 +245,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
|||
break
|
||||
}
|
||||
}
|
||||
bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
|
||||
sa.Name = string(bytes)
|
||||
sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
|
||||
return sa, nil
|
||||
|
||||
case AF_INET:
|
||||
|
|
|
|||
13
vendor/golang.org/x/sys/unix/syscall_darwin.go
generated
vendored
13
vendor/golang.org/x/sys/unix/syscall_darwin.go
generated
vendored
|
|
@ -14,7 +14,6 @@ package unix
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
|
@ -230,6 +229,7 @@ func direntNamlen(buf []byte) (uint64, bool) {
|
|||
|
||||
func PtraceAttach(pid int) (err error) { return ptrace(PT_ATTACH, pid, 0, 0) }
|
||||
func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) }
|
||||
func PtraceDenyAttach() (err error) { return ptrace(PT_DENY_ATTACH, 0, 0, 0) }
|
||||
|
||||
//sysnb pipe(p *[2]int32) (err error)
|
||||
|
||||
|
|
@ -375,11 +375,10 @@ func Flistxattr(fd int, dest []byte) (sz int, err error) {
|
|||
func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(signum), 1) }
|
||||
|
||||
//sys ioctl(fd int, req uint, arg uintptr) (err error)
|
||||
//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
|
||||
|
||||
func IoctlCtlInfo(fd int, ctlInfo *CtlInfo) error {
|
||||
err := ioctl(fd, CTLIOCGINFO, uintptr(unsafe.Pointer(ctlInfo)))
|
||||
runtime.KeepAlive(ctlInfo)
|
||||
return err
|
||||
return ioctlPtr(fd, CTLIOCGINFO, unsafe.Pointer(ctlInfo))
|
||||
}
|
||||
|
||||
// IfreqMTU is struct ifreq used to get or set a network device's MTU.
|
||||
|
|
@ -393,16 +392,14 @@ type IfreqMTU struct {
|
|||
func IoctlGetIfreqMTU(fd int, ifname string) (*IfreqMTU, error) {
|
||||
var ifreq IfreqMTU
|
||||
copy(ifreq.Name[:], ifname)
|
||||
err := ioctl(fd, SIOCGIFMTU, uintptr(unsafe.Pointer(&ifreq)))
|
||||
err := ioctlPtr(fd, SIOCGIFMTU, unsafe.Pointer(&ifreq))
|
||||
return &ifreq, err
|
||||
}
|
||||
|
||||
// IoctlSetIfreqMTU performs the SIOCSIFMTU ioctl operation on fd to set the MTU
|
||||
// of the network device specified by ifreq.Name.
|
||||
func IoctlSetIfreqMTU(fd int, ifreq *IfreqMTU) error {
|
||||
err := ioctl(fd, SIOCSIFMTU, uintptr(unsafe.Pointer(ifreq)))
|
||||
runtime.KeepAlive(ifreq)
|
||||
return err
|
||||
return ioctlPtr(fd, SIOCSIFMTU, unsafe.Pointer(ifreq))
|
||||
}
|
||||
|
||||
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS_SYSCTL
|
||||
|
|
|
|||
1
vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
generated
vendored
|
|
@ -47,5 +47,6 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
|
|||
//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64
|
||||
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
|
||||
//sys ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) = SYS_ptrace
|
||||
//sys ptrace1Ptr(request int, pid int, addr unsafe.Pointer, data uintptr) (err error) = SYS_ptrace
|
||||
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
|
||||
|
|
|
|||
1
vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
generated
vendored
|
|
@ -47,5 +47,6 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
|
|||
//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT
|
||||
//sys Lstat(path string, stat *Stat_t) (err error)
|
||||
//sys ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) = SYS_ptrace
|
||||
//sys ptrace1Ptr(request int, pid int, addr unsafe.Pointer, data uintptr) (err error) = SYS_ptrace
|
||||
//sys Stat(path string, stat *Stat_t) (err error)
|
||||
//sys Statfs(path string, stat *Statfs_t) (err error)
|
||||
|
|
|
|||
2
vendor/golang.org/x/sys/unix/syscall_dragonfly.go
generated
vendored
2
vendor/golang.org/x/sys/unix/syscall_dragonfly.go
generated
vendored
|
|
@ -172,6 +172,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
|||
}
|
||||
|
||||
//sys ioctl(fd int, req uint, arg uintptr) (err error)
|
||||
//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
|
||||
|
||||
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
|
||||
|
||||
|
|
@ -255,6 +256,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||
//sys Chmod(path string, mode uint32) (err error)
|
||||
//sys Chown(path string, uid int, gid int) (err error)
|
||||
//sys Chroot(path string) (err error)
|
||||
//sys ClockGettime(clockid int32, time *Timespec) (err error)
|
||||
//sys Close(fd int) (err error)
|
||||
//sys Dup(fd int) (nfd int, err error)
|
||||
//sys Dup2(from int, to int) (err error)
|
||||
|
|
|
|||
44
vendor/golang.org/x/sys/unix/syscall_freebsd.go
generated
vendored
44
vendor/golang.org/x/sys/unix/syscall_freebsd.go
generated
vendored
|
|
@ -161,7 +161,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
//sys ioctl(fd int, req uint, arg uintptr) (err error)
|
||||
//sys ioctl(fd int, req uint, arg uintptr) (err error) = SYS_IOCTL
|
||||
//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
|
||||
|
||||
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
|
||||
|
||||
|
|
@ -253,6 +254,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||
}
|
||||
|
||||
//sys ptrace(request int, pid int, addr uintptr, data int) (err error)
|
||||
//sys ptracePtr(request int, pid int, addr unsafe.Pointer, data int) (err error) = SYS_PTRACE
|
||||
|
||||
func PtraceAttach(pid int) (err error) {
|
||||
return ptrace(PT_ATTACH, pid, 0, 0)
|
||||
|
|
@ -267,19 +269,36 @@ func PtraceDetach(pid int) (err error) {
|
|||
}
|
||||
|
||||
func PtraceGetFpRegs(pid int, fpregsout *FpReg) (err error) {
|
||||
return ptrace(PT_GETFPREGS, pid, uintptr(unsafe.Pointer(fpregsout)), 0)
|
||||
return ptracePtr(PT_GETFPREGS, pid, unsafe.Pointer(fpregsout), 0)
|
||||
}
|
||||
|
||||
func PtraceGetRegs(pid int, regsout *Reg) (err error) {
|
||||
return ptrace(PT_GETREGS, pid, uintptr(unsafe.Pointer(regsout)), 0)
|
||||
return ptracePtr(PT_GETREGS, pid, unsafe.Pointer(regsout), 0)
|
||||
}
|
||||
|
||||
func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
|
||||
ioDesc := PtraceIoDesc{
|
||||
Op: int32(req),
|
||||
Offs: offs,
|
||||
}
|
||||
if countin > 0 {
|
||||
_ = out[:countin] // check bounds
|
||||
ioDesc.Addr = &out[0]
|
||||
} else if out != nil {
|
||||
ioDesc.Addr = (*byte)(unsafe.Pointer(&_zero))
|
||||
}
|
||||
ioDesc.SetLen(countin)
|
||||
|
||||
err = ptracePtr(PT_IO, pid, unsafe.Pointer(&ioDesc), 0)
|
||||
return int(ioDesc.Len), err
|
||||
}
|
||||
|
||||
func PtraceLwpEvents(pid int, enable int) (err error) {
|
||||
return ptrace(PT_LWP_EVENTS, pid, 0, enable)
|
||||
}
|
||||
|
||||
func PtraceLwpInfo(pid int, info uintptr) (err error) {
|
||||
return ptrace(PT_LWPINFO, pid, info, int(unsafe.Sizeof(PtraceLwpInfoStruct{})))
|
||||
func PtraceLwpInfo(pid int, info *PtraceLwpInfoStruct) (err error) {
|
||||
return ptracePtr(PT_LWPINFO, pid, unsafe.Pointer(info), int(unsafe.Sizeof(*info)))
|
||||
}
|
||||
|
||||
func PtracePeekData(pid int, addr uintptr, out []byte) (count int, err error) {
|
||||
|
|
@ -299,13 +318,25 @@ func PtracePokeText(pid int, addr uintptr, data []byte) (count int, err error) {
|
|||
}
|
||||
|
||||
func PtraceSetRegs(pid int, regs *Reg) (err error) {
|
||||
return ptrace(PT_SETREGS, pid, uintptr(unsafe.Pointer(regs)), 0)
|
||||
return ptracePtr(PT_SETREGS, pid, unsafe.Pointer(regs), 0)
|
||||
}
|
||||
|
||||
func PtraceSingleStep(pid int) (err error) {
|
||||
return ptrace(PT_STEP, pid, 1, 0)
|
||||
}
|
||||
|
||||
func Dup3(oldfd, newfd, flags int) error {
|
||||
if oldfd == newfd || flags&^O_CLOEXEC != 0 {
|
||||
return EINVAL
|
||||
}
|
||||
how := F_DUP2FD
|
||||
if flags&O_CLOEXEC != 0 {
|
||||
how = F_DUP2FD_CLOEXEC
|
||||
}
|
||||
_, err := fcntl(oldfd, how, newfd)
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
* Exposed directly
|
||||
*/
|
||||
|
|
@ -319,6 +350,7 @@ func PtraceSingleStep(pid int) (err error) {
|
|||
//sys Chmod(path string, mode uint32) (err error)
|
||||
//sys Chown(path string, uid int, gid int) (err error)
|
||||
//sys Chroot(path string) (err error)
|
||||
//sys ClockGettime(clockid int32, time *Timespec) (err error)
|
||||
//sys Close(fd int) (err error)
|
||||
//sys Dup(fd int) (nfd int, err error)
|
||||
//sys Dup2(from int, to int) (err error)
|
||||
|
|
|
|||
12
vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
generated
vendored
12
vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
generated
vendored
|
|
@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
|
|||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func (d *PtraceIoDesc) SetLen(length int) {
|
||||
d.Len = uint32(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var writtenOut uint64 = 0
|
||||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
|
||||
|
|
@ -57,11 +61,5 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
|
||||
func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
|
||||
return ptrace(PT_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
|
||||
}
|
||||
|
||||
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
||||
ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint32(countin)}
|
||||
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
||||
return int(ioDesc.Len), err
|
||||
return ptracePtr(PT_GETFSBASE, pid, unsafe.Pointer(fsbase), 0)
|
||||
}
|
||||
|
|
|
|||
12
vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
generated
vendored
12
vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
generated
vendored
|
|
@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
|
|||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func (d *PtraceIoDesc) SetLen(length int) {
|
||||
d.Len = uint64(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var writtenOut uint64 = 0
|
||||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
|
||||
|
|
@ -57,11 +61,5 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
|
||||
func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
|
||||
return ptrace(PT_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
|
||||
}
|
||||
|
||||
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
||||
ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint64(countin)}
|
||||
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
||||
return int(ioDesc.Len), err
|
||||
return ptracePtr(PT_GETFSBASE, pid, unsafe.Pointer(fsbase), 0)
|
||||
}
|
||||
|
|
|
|||
10
vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
generated
vendored
10
vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
generated
vendored
|
|
@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
|
|||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func (d *PtraceIoDesc) SetLen(length int) {
|
||||
d.Len = uint32(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var writtenOut uint64 = 0
|
||||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
|
||||
|
|
@ -55,9 +59,3 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||
}
|
||||
|
||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
|
||||
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
||||
ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint32(countin)}
|
||||
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
||||
return int(ioDesc.Len), err
|
||||
}
|
||||
|
|
|
|||
10
vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go
generated
vendored
10
vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go
generated
vendored
|
|
@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
|
|||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func (d *PtraceIoDesc) SetLen(length int) {
|
||||
d.Len = uint64(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var writtenOut uint64 = 0
|
||||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
|
||||
|
|
@ -55,9 +59,3 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||
}
|
||||
|
||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
|
||||
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
||||
ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint64(countin)}
|
||||
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
||||
return int(ioDesc.Len), err
|
||||
}
|
||||
|
|
|
|||
10
vendor/golang.org/x/sys/unix/syscall_freebsd_riscv64.go
generated
vendored
10
vendor/golang.org/x/sys/unix/syscall_freebsd_riscv64.go
generated
vendored
|
|
@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
|
|||
cmsg.Len = uint32(length)
|
||||
}
|
||||
|
||||
func (d *PtraceIoDesc) SetLen(length int) {
|
||||
d.Len = uint64(length)
|
||||
}
|
||||
|
||||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
var writtenOut uint64 = 0
|
||||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
|
||||
|
|
@ -55,9 +59,3 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||
}
|
||||
|
||||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
|
||||
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
|
||||
ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint64(countin)}
|
||||
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
|
||||
return int(ioDesc.Len), err
|
||||
}
|
||||
|
|
|
|||
30
vendor/golang.org/x/sys/unix/syscall_hurd.go
generated
vendored
Normal file
30
vendor/golang.org/x/sys/unix/syscall_hurd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build hurd
|
||||
// +build hurd
|
||||
|
||||
package unix
|
||||
|
||||
/*
|
||||
#include <stdint.h>
|
||||
int ioctl(int, unsigned long int, uintptr_t);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func ioctl(fd int, req uint, arg uintptr) (err error) {
|
||||
r0, er := C.ioctl(C.int(fd), C.ulong(req), C.uintptr_t(arg))
|
||||
if r0 == -1 && er != nil {
|
||||
err = er
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
|
||||
r0, er := C.ioctl(C.int(fd), C.ulong(req), C.uintptr_t(uintptr(arg)))
|
||||
if r0 == -1 && er != nil {
|
||||
err = er
|
||||
}
|
||||
return
|
||||
}
|
||||
29
vendor/golang.org/x/sys/unix/syscall_hurd_386.go
generated
vendored
Normal file
29
vendor/golang.org/x/sys/unix/syscall_hurd_386.go
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build 386 && hurd
|
||||
// +build 386,hurd
|
||||
|
||||
package unix
|
||||
|
||||
const (
|
||||
TIOCGETA = 0x62251713
|
||||
)
|
||||
|
||||
type Winsize struct {
|
||||
Row uint16
|
||||
Col uint16
|
||||
Xpixel uint16
|
||||
Ypixel uint16
|
||||
}
|
||||
|
||||
type Termios struct {
|
||||
Iflag uint32
|
||||
Oflag uint32
|
||||
Cflag uint32
|
||||
Lflag uint32
|
||||
Cc [20]uint8
|
||||
Ispeed int32
|
||||
Ospeed int32
|
||||
}
|
||||
88
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
88
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
|
|
@ -1015,8 +1015,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
|||
for n < len(pp.Path) && pp.Path[n] != 0 {
|
||||
n++
|
||||
}
|
||||
bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
|
||||
sa.Name = string(bytes)
|
||||
sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
|
||||
return sa, nil
|
||||
|
||||
case AF_INET:
|
||||
|
|
@ -1365,6 +1364,10 @@ func SetsockoptTCPRepairOpt(fd, level, opt int, o []TCPRepairOpt) (err error) {
|
|||
return setsockopt(fd, level, opt, unsafe.Pointer(&o[0]), uintptr(SizeofTCPRepairOpt*len(o)))
|
||||
}
|
||||
|
||||
func SetsockoptTCPMD5Sig(fd, level, opt int, s *TCPMD5Sig) error {
|
||||
return setsockopt(fd, level, opt, unsafe.Pointer(s), unsafe.Sizeof(*s))
|
||||
}
|
||||
|
||||
// Keyctl Commands (http://man7.org/linux/man-pages/man2/keyctl.2.html)
|
||||
|
||||
// KeyctlInt calls keyctl commands in which each argument is an int.
|
||||
|
|
@ -1554,6 +1557,7 @@ func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Sockle
|
|||
var iova [1]Iovec
|
||||
iova[0].Base = &dummy
|
||||
iova[0].SetLen(1)
|
||||
iov = iova[:]
|
||||
}
|
||||
}
|
||||
msg.Control = &oob[0]
|
||||
|
|
@ -1578,6 +1582,7 @@ func BindToDevice(fd int, device string) (err error) {
|
|||
}
|
||||
|
||||
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
|
||||
//sys ptracePtr(request int, pid int, addr uintptr, data unsafe.Pointer) (err error) = SYS_PTRACE
|
||||
|
||||
func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err error) {
|
||||
// The peek requests are machine-size oriented, so we wrap it
|
||||
|
|
@ -1595,7 +1600,7 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err erro
|
|||
// boundary.
|
||||
n := 0
|
||||
if addr%SizeofPtr != 0 {
|
||||
err = ptrace(req, pid, addr-addr%SizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
|
||||
err = ptracePtr(req, pid, addr-addr%SizeofPtr, unsafe.Pointer(&buf[0]))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -1607,7 +1612,7 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err erro
|
|||
for len(out) > 0 {
|
||||
// We use an internal buffer to guarantee alignment.
|
||||
// It's not documented if this is necessary, but we're paranoid.
|
||||
err = ptrace(req, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
|
||||
err = ptracePtr(req, pid, addr+uintptr(n), unsafe.Pointer(&buf[0]))
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
|
@ -1639,7 +1644,7 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
|
|||
n := 0
|
||||
if addr%SizeofPtr != 0 {
|
||||
var buf [SizeofPtr]byte
|
||||
err = ptrace(peekReq, pid, addr-addr%SizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
|
||||
err = ptracePtr(peekReq, pid, addr-addr%SizeofPtr, unsafe.Pointer(&buf[0]))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -1666,7 +1671,7 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
|
|||
// Trailing edge.
|
||||
if len(data) > 0 {
|
||||
var buf [SizeofPtr]byte
|
||||
err = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
|
||||
err = ptracePtr(peekReq, pid, addr+uintptr(n), unsafe.Pointer(&buf[0]))
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
|
@ -1695,11 +1700,11 @@ func PtracePokeUser(pid int, addr uintptr, data []byte) (count int, err error) {
|
|||
}
|
||||
|
||||
func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
|
||||
return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
|
||||
return ptracePtr(PTRACE_GETREGS, pid, 0, unsafe.Pointer(regsout))
|
||||
}
|
||||
|
||||
func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
|
||||
return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
|
||||
return ptracePtr(PTRACE_SETREGS, pid, 0, unsafe.Pointer(regs))
|
||||
}
|
||||
|
||||
func PtraceSetOptions(pid int, options int) (err error) {
|
||||
|
|
@ -1708,7 +1713,7 @@ func PtraceSetOptions(pid int, options int) (err error) {
|
|||
|
||||
func PtraceGetEventMsg(pid int) (msg uint, err error) {
|
||||
var data _C_long
|
||||
err = ptrace(PTRACE_GETEVENTMSG, pid, 0, uintptr(unsafe.Pointer(&data)))
|
||||
err = ptracePtr(PTRACE_GETEVENTMSG, pid, 0, unsafe.Pointer(&data))
|
||||
msg = uint(data)
|
||||
return
|
||||
}
|
||||
|
|
@ -1799,6 +1804,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||
//sysnb Capset(hdr *CapUserHeader, data *CapUserData) (err error)
|
||||
//sys Chdir(path string) (err error)
|
||||
//sys Chroot(path string) (err error)
|
||||
//sys ClockAdjtime(clockid int32, buf *Timex) (state int, err error)
|
||||
//sys ClockGetres(clockid int32, res *Timespec) (err error)
|
||||
//sys ClockGettime(clockid int32, time *Timespec) (err error)
|
||||
//sys ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error)
|
||||
|
|
@ -1972,36 +1978,46 @@ func Signalfd(fd int, sigmask *Sigset_t, flags int) (newfd int, err error) {
|
|||
//sys preadv2(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr, flags int) (n int, err error) = SYS_PREADV2
|
||||
//sys pwritev2(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr, flags int) (n int, err error) = SYS_PWRITEV2
|
||||
|
||||
func bytes2iovec(bs [][]byte) []Iovec {
|
||||
iovecs := make([]Iovec, len(bs))
|
||||
for i, b := range bs {
|
||||
iovecs[i].SetLen(len(b))
|
||||
// minIovec is the size of the small initial allocation used by
|
||||
// Readv, Writev, etc.
|
||||
//
|
||||
// This small allocation gets stack allocated, which lets the
|
||||
// common use case of len(iovs) <= minIovs avoid more expensive
|
||||
// heap allocations.
|
||||
const minIovec = 8
|
||||
|
||||
// appendBytes converts bs to Iovecs and appends them to vecs.
|
||||
func appendBytes(vecs []Iovec, bs [][]byte) []Iovec {
|
||||
for _, b := range bs {
|
||||
var v Iovec
|
||||
v.SetLen(len(b))
|
||||
if len(b) > 0 {
|
||||
iovecs[i].Base = &b[0]
|
||||
v.Base = &b[0]
|
||||
} else {
|
||||
iovecs[i].Base = (*byte)(unsafe.Pointer(&_zero))
|
||||
v.Base = (*byte)(unsafe.Pointer(&_zero))
|
||||
}
|
||||
vecs = append(vecs, v)
|
||||
}
|
||||
return iovecs
|
||||
return vecs
|
||||
}
|
||||
|
||||
// offs2lohi splits offs into its lower and upper unsigned long. On 64-bit
|
||||
// systems, hi will always be 0. On 32-bit systems, offs will be split in half.
|
||||
// preadv/pwritev chose this calling convention so they don't need to add a
|
||||
// padding-register for alignment on ARM.
|
||||
// offs2lohi splits offs into its low and high order bits.
|
||||
func offs2lohi(offs int64) (lo, hi uintptr) {
|
||||
return uintptr(offs), uintptr(uint64(offs) >> SizeofLong)
|
||||
const longBits = SizeofLong * 8
|
||||
return uintptr(offs), uintptr(uint64(offs) >> (longBits - 1) >> 1) // two shifts to avoid false positive in vet
|
||||
}
|
||||
|
||||
func Readv(fd int, iovs [][]byte) (n int, err error) {
|
||||
iovecs := bytes2iovec(iovs)
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
n, err = readv(fd, iovecs)
|
||||
readvRacedetect(iovecs, n, err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
||||
iovecs := bytes2iovec(iovs)
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
lo, hi := offs2lohi(offset)
|
||||
n, err = preadv(fd, iovecs, lo, hi)
|
||||
readvRacedetect(iovecs, n, err)
|
||||
|
|
@ -2009,7 +2025,8 @@ func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
|||
}
|
||||
|
||||
func Preadv2(fd int, iovs [][]byte, offset int64, flags int) (n int, err error) {
|
||||
iovecs := bytes2iovec(iovs)
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
lo, hi := offs2lohi(offset)
|
||||
n, err = preadv2(fd, iovecs, lo, hi, flags)
|
||||
readvRacedetect(iovecs, n, err)
|
||||
|
|
@ -2036,7 +2053,8 @@ func readvRacedetect(iovecs []Iovec, n int, err error) {
|
|||
}
|
||||
|
||||
func Writev(fd int, iovs [][]byte) (n int, err error) {
|
||||
iovecs := bytes2iovec(iovs)
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
if raceenabled {
|
||||
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
|
|
@ -2046,7 +2064,8 @@ func Writev(fd int, iovs [][]byte) (n int, err error) {
|
|||
}
|
||||
|
||||
func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
||||
iovecs := bytes2iovec(iovs)
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
if raceenabled {
|
||||
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
|
|
@ -2057,7 +2076,8 @@ func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
|||
}
|
||||
|
||||
func Pwritev2(fd int, iovs [][]byte, offset int64, flags int) (n int, err error) {
|
||||
iovecs := bytes2iovec(iovs)
|
||||
iovecs := make([]Iovec, 0, minIovec)
|
||||
iovecs = appendBytes(iovecs, iovs)
|
||||
if raceenabled {
|
||||
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
||||
}
|
||||
|
|
@ -2138,6 +2158,14 @@ func isGroupMember(gid int) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func isCapDacOverrideSet() bool {
|
||||
hdr := CapUserHeader{Version: LINUX_CAPABILITY_VERSION_3}
|
||||
data := [2]CapUserData{}
|
||||
err := Capget(&hdr, &data[0])
|
||||
|
||||
return err == nil && data[0].Effective&(1<<CAP_DAC_OVERRIDE) != 0
|
||||
}
|
||||
|
||||
//sys faccessat(dirfd int, path string, mode uint32) (err error)
|
||||
//sys Faccessat2(dirfd int, path string, mode uint32, flags int) (err error)
|
||||
|
||||
|
|
@ -2173,6 +2201,12 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
|
|||
var uid int
|
||||
if flags&AT_EACCESS != 0 {
|
||||
uid = Geteuid()
|
||||
if uid != 0 && isCapDacOverrideSet() {
|
||||
// If CAP_DAC_OVERRIDE is set, file access check is
|
||||
// done by the kernel in the same way as for root
|
||||
// (see generic_permission() in the Linux sources).
|
||||
uid = 0
|
||||
}
|
||||
} else {
|
||||
uid = Getuid()
|
||||
}
|
||||
|
|
|
|||
20
vendor/golang.org/x/sys/unix/syscall_netbsd.go
generated
vendored
20
vendor/golang.org/x/sys/unix/syscall_netbsd.go
generated
vendored
|
|
@ -13,7 +13,6 @@
|
|||
package unix
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
|
@ -110,6 +109,20 @@ func direntNamlen(buf []byte) (uint64, bool) {
|
|||
return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
|
||||
}
|
||||
|
||||
func SysctlUvmexp(name string) (*Uvmexp, error) {
|
||||
mib, err := sysctlmib(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n := uintptr(SizeofUvmexp)
|
||||
var u Uvmexp
|
||||
if err := sysctl(mib, (*byte)(unsafe.Pointer(&u)), &n, nil, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &u, nil
|
||||
}
|
||||
|
||||
func Pipe(p []int) (err error) {
|
||||
return Pipe2(p, 0)
|
||||
}
|
||||
|
|
@ -164,13 +177,13 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||
}
|
||||
|
||||
//sys ioctl(fd int, req uint, arg uintptr) (err error)
|
||||
//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
|
||||
|
||||
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
|
||||
|
||||
func IoctlGetPtmget(fd int, req uint) (*Ptmget, error) {
|
||||
var value Ptmget
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
||||
runtime.KeepAlive(value)
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return &value, err
|
||||
}
|
||||
|
||||
|
|
@ -245,6 +258,7 @@ func Statvfs(path string, buf *Statvfs_t) (err error) {
|
|||
//sys Chmod(path string, mode uint32) (err error)
|
||||
//sys Chown(path string, uid int, gid int) (err error)
|
||||
//sys Chroot(path string) (err error)
|
||||
//sys ClockGettime(clockid int32, time *Timespec) (err error)
|
||||
//sys Close(fd int) (err error)
|
||||
//sys Dup(fd int) (nfd int, err error)
|
||||
//sys Dup2(from int, to int) (err error)
|
||||
|
|
|
|||
2
vendor/golang.org/x/sys/unix/syscall_openbsd.go
generated
vendored
2
vendor/golang.org/x/sys/unix/syscall_openbsd.go
generated
vendored
|
|
@ -152,6 +152,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
|||
}
|
||||
|
||||
//sys ioctl(fd int, req uint, arg uintptr) (err error)
|
||||
//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
|
||||
|
||||
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
|
||||
|
||||
|
|
@ -220,6 +221,7 @@ func Uname(uname *Utsname) error {
|
|||
//sys Chmod(path string, mode uint32) (err error)
|
||||
//sys Chown(path string, uid int, gid int) (err error)
|
||||
//sys Chroot(path string) (err error)
|
||||
//sys ClockGettime(clockid int32, time *Timespec) (err error)
|
||||
//sys Close(fd int) (err error)
|
||||
//sys Dup(fd int) (nfd int, err error)
|
||||
//sys Dup2(from int, to int) (err error)
|
||||
|
|
|
|||
4
vendor/golang.org/x/sys/unix/syscall_openbsd_libc.go
generated
vendored
4
vendor/golang.org/x/sys/unix/syscall_openbsd_libc.go
generated
vendored
|
|
@ -2,8 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build openbsd && !mips64
|
||||
// +build openbsd,!mips64
|
||||
//go:build openbsd
|
||||
// +build openbsd
|
||||
|
||||
package unix
|
||||
|
||||
|
|
|
|||
22
vendor/golang.org/x/sys/unix/syscall_solaris.go
generated
vendored
22
vendor/golang.org/x/sys/unix/syscall_solaris.go
generated
vendored
|
|
@ -408,8 +408,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
|||
for n < len(pp.Path) && pp.Path[n] != 0 {
|
||||
n++
|
||||
}
|
||||
bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
|
||||
sa.Name = string(bytes)
|
||||
sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
|
||||
return sa, nil
|
||||
|
||||
case AF_INET:
|
||||
|
|
@ -547,21 +546,25 @@ func Minor(dev uint64) uint32 {
|
|||
*/
|
||||
|
||||
//sys ioctlRet(fd int, req uint, arg uintptr) (ret int, err error) = libc.ioctl
|
||||
//sys ioctlPtrRet(fd int, req uint, arg unsafe.Pointer) (ret int, err error) = libc.ioctl
|
||||
|
||||
func ioctl(fd int, req uint, arg uintptr) (err error) {
|
||||
_, err = ioctlRet(fd, req, arg)
|
||||
return err
|
||||
}
|
||||
|
||||
func IoctlSetTermio(fd int, req uint, value *Termio) error {
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
|
||||
runtime.KeepAlive(value)
|
||||
func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
|
||||
_, err = ioctlPtrRet(fd, req, arg)
|
||||
return err
|
||||
}
|
||||
|
||||
func IoctlSetTermio(fd int, req uint, value *Termio) error {
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(value))
|
||||
}
|
||||
|
||||
func IoctlGetTermio(fd int, req uint) (*Termio, error) {
|
||||
var value Termio
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return &value, err
|
||||
}
|
||||
|
||||
|
|
@ -590,6 +593,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|||
//sys Chmod(path string, mode uint32) (err error)
|
||||
//sys Chown(path string, uid int, gid int) (err error)
|
||||
//sys Chroot(path string) (err error)
|
||||
//sys ClockGettime(clockid int32, time *Timespec) (err error)
|
||||
//sys Close(fd int) (err error)
|
||||
//sys Creat(path string, mode uint32) (fd int, err error)
|
||||
//sys Dup(fd int) (nfd int, err error)
|
||||
|
|
@ -1083,7 +1087,7 @@ func IoctlSetIntRetInt(fd int, req uint, arg int) (int, error) {
|
|||
func IoctlSetString(fd int, req uint, val string) error {
|
||||
bs := make([]byte, len(val)+1)
|
||||
copy(bs[:len(bs)-1], val)
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(&bs[0])))
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
|
||||
runtime.KeepAlive(&bs[0])
|
||||
return err
|
||||
}
|
||||
|
|
@ -1117,7 +1121,7 @@ func (l *Lifreq) GetLifruUint() uint {
|
|||
}
|
||||
|
||||
func IoctlLifreq(fd int, req uint, l *Lifreq) error {
|
||||
return ioctl(fd, req, uintptr(unsafe.Pointer(l)))
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(l))
|
||||
}
|
||||
|
||||
// Strioctl Helpers
|
||||
|
|
@ -1128,5 +1132,5 @@ func (s *Strioctl) SetInt(i int) {
|
|||
}
|
||||
|
||||
func IoctlSetStrioctlRetInt(fd int, req uint, s *Strioctl) (int, error) {
|
||||
return ioctlRet(fd, req, uintptr(unsafe.Pointer(s)))
|
||||
return ioctlPtrRet(fd, req, unsafe.Pointer(s))
|
||||
}
|
||||
|
|
|
|||
57
vendor/golang.org/x/sys/unix/syscall_unix.go
generated
vendored
57
vendor/golang.org/x/sys/unix/syscall_unix.go
generated
vendored
|
|
@ -331,6 +331,19 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// Recvmsg receives a message from a socket using the recvmsg system call. The
|
||||
// received non-control data will be written to p, and any "out of band"
|
||||
// control data will be written to oob. The flags are passed to recvmsg.
|
||||
//
|
||||
// The results are:
|
||||
// - n is the number of non-control data bytes read into p
|
||||
// - oobn is the number of control data bytes read into oob; this may be interpreted using [ParseSocketControlMessage]
|
||||
// - recvflags is flags returned by recvmsg
|
||||
// - from is the address of the sender
|
||||
//
|
||||
// If the underlying socket type is not SOCK_DGRAM, a received message
|
||||
// containing oob data and a single '\0' of non-control data is treated as if
|
||||
// the message contained only control data, i.e. n will be zero on return.
|
||||
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
|
||||
var iov [1]Iovec
|
||||
if len(p) > 0 {
|
||||
|
|
@ -346,13 +359,9 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
|
|||
return
|
||||
}
|
||||
|
||||
// RecvmsgBuffers receives a message from a socket using the recvmsg
|
||||
// system call. The flags are passed to recvmsg. Any non-control data
|
||||
// read is scattered into the buffers slices. The results are:
|
||||
// - n is the number of non-control data read into bufs
|
||||
// - oobn is the number of control data read into oob; this may be interpreted using [ParseSocketControlMessage]
|
||||
// - recvflags is flags returned by recvmsg
|
||||
// - from is the address of the sender
|
||||
// RecvmsgBuffers receives a message from a socket using the recvmsg system
|
||||
// call. This function is equivalent to Recvmsg, but non-control data read is
|
||||
// scattered into the buffers slices.
|
||||
func RecvmsgBuffers(fd int, buffers [][]byte, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
|
||||
iov := make([]Iovec, len(buffers))
|
||||
for i := range buffers {
|
||||
|
|
@ -371,11 +380,38 @@ func RecvmsgBuffers(fd int, buffers [][]byte, oob []byte, flags int) (n, oobn in
|
|||
return
|
||||
}
|
||||
|
||||
// Sendmsg sends a message on a socket to an address using the sendmsg system
|
||||
// call. This function is equivalent to SendmsgN, but does not return the
|
||||
// number of bytes actually sent.
|
||||
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
|
||||
_, err = SendmsgN(fd, p, oob, to, flags)
|
||||
return
|
||||
}
|
||||
|
||||
// SendmsgN sends a message on a socket to an address using the sendmsg system
|
||||
// call. p contains the non-control data to send, and oob contains the "out of
|
||||
// band" control data. The flags are passed to sendmsg. The number of
|
||||
// non-control bytes actually written to the socket is returned.
|
||||
//
|
||||
// Some socket types do not support sending control data without accompanying
|
||||
// non-control data. If p is empty, and oob contains control data, and the
|
||||
// underlying socket type is not SOCK_DGRAM, p will be treated as containing a
|
||||
// single '\0' and the return value will indicate zero bytes sent.
|
||||
//
|
||||
// The Go function Recvmsg, if called with an empty p and a non-empty oob,
|
||||
// will read and ignore this additional '\0'. If the message is received by
|
||||
// code that does not use Recvmsg, or that does not use Go at all, that code
|
||||
// will need to be written to expect and ignore the additional '\0'.
|
||||
//
|
||||
// If you need to send non-empty oob with p actually empty, and if the
|
||||
// underlying socket type supports it, you can do so via a raw system call as
|
||||
// follows:
|
||||
//
|
||||
// msg := &unix.Msghdr{
|
||||
// Control: &oob[0],
|
||||
// }
|
||||
// msg.SetControllen(len(oob))
|
||||
// n, _, errno := unix.Syscall(unix.SYS_SENDMSG, uintptr(fd), uintptr(unsafe.Pointer(msg)), flags)
|
||||
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
|
||||
var iov [1]Iovec
|
||||
if len(p) > 0 {
|
||||
|
|
@ -394,9 +430,8 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error)
|
|||
}
|
||||
|
||||
// SendmsgBuffers sends a message on a socket to an address using the sendmsg
|
||||
// system call. The flags are passed to sendmsg. Any non-control data written
|
||||
// is gathered from buffers. The function returns the number of bytes written
|
||||
// to the socket.
|
||||
// system call. This function is equivalent to SendmsgN, but the non-control
|
||||
// data is gathered from buffers.
|
||||
func SendmsgBuffers(fd int, buffers [][]byte, oob []byte, to Sockaddr, flags int) (n int, err error) {
|
||||
iov := make([]Iovec, len(buffers))
|
||||
for i := range buffers {
|
||||
|
|
@ -543,7 +578,7 @@ func Lutimes(path string, tv []Timeval) error {
|
|||
return UtimesNanoAt(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW)
|
||||
}
|
||||
|
||||
// emptyIovec reports whether there are no bytes in the slice of Iovec.
|
||||
// emptyIovecs reports whether there are no bytes in the slice of Iovec.
|
||||
func emptyIovecs(iov []Iovec) bool {
|
||||
for i := range iov {
|
||||
if iov[i].Len > 0 {
|
||||
|
|
|
|||
4
vendor/golang.org/x/sys/unix/syscall_zos_s390x.go
generated
vendored
4
vendor/golang.org/x/sys/unix/syscall_zos_s390x.go
generated
vendored
|
|
@ -139,8 +139,7 @@ func anyToSockaddr(_ int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
|||
for n < int(pp.Len) && pp.Path[n] != 0 {
|
||||
n++
|
||||
}
|
||||
bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
|
||||
sa.Name = string(bytes)
|
||||
sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
|
||||
return sa, nil
|
||||
|
||||
case AF_INET:
|
||||
|
|
@ -214,6 +213,7 @@ func (cmsg *Cmsghdr) SetLen(length int) {
|
|||
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) = SYS_MMAP
|
||||
//sys munmap(addr uintptr, length uintptr) (err error) = SYS_MUNMAP
|
||||
//sys ioctl(fd int, req uint, arg uintptr) (err error) = SYS_IOCTL
|
||||
//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
|
||||
|
||||
//sys Access(path string, mode uint32) (err error) = SYS___ACCESS_A
|
||||
//sys Chdir(path string) (err error) = SYS___CHDIR_A
|
||||
|
|
|
|||
2
vendor/golang.org/x/sys/unix/timestruct.go
generated
vendored
2
vendor/golang.org/x/sys/unix/timestruct.go
generated
vendored
|
|
@ -9,7 +9,7 @@ package unix
|
|||
|
||||
import "time"
|
||||
|
||||
// TimespecToNSec returns the time stored in ts as nanoseconds.
|
||||
// TimespecToNsec returns the time stored in ts as nanoseconds.
|
||||
func TimespecToNsec(ts Timespec) int64 { return ts.Nano() }
|
||||
|
||||
// NsecToTimespec converts a number of nanoseconds into a Timespec.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue