Bump docker/cli
Bump docker/docker Fix last changes on context stores made on docker/cli (the main store interface has been split to multiple smaller interfaces). Signed-off-by: Silvin Lubecki <silvin.lubecki@docker.com>
This commit is contained in:
Родитель
f2fbcae871
Коммит
b4a8a4a6f9
|
@ -29,7 +29,7 @@
|
||||||
version = "v0.4.12"
|
version = "v0.4.12"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:a8e16b4caf3575365c9aa3380d9418f31dd0b810596faebfe3a15c37fabeee4a"
|
digest = "1:3b7289c340e1043e1b826ba201d4d9ed1eb3ec32a5e8600208ec030afa74f458"
|
||||||
name = "github.com/Microsoft/hcsshim"
|
name = "github.com/Microsoft/hcsshim"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
|
@ -47,6 +47,7 @@
|
||||||
"internal/schema2",
|
"internal/schema2",
|
||||||
"internal/timeout",
|
"internal/timeout",
|
||||||
"internal/wclayer",
|
"internal/wclayer",
|
||||||
|
"osversion",
|
||||||
]
|
]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "f92b8fb9c92e17da496af5a69e3ee13fbe9916e1"
|
revision = "f92b8fb9c92e17da496af5a69e3ee13fbe9916e1"
|
||||||
|
@ -209,7 +210,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "19.03"
|
branch = "19.03"
|
||||||
digest = "1:45401220d930972198a7880d87df89485e53ac44b2a5826d9c2fe57344f650a6"
|
digest = "1:2f437f78f32178b2951314dd82649fda98e8f114e4d2c42588dd40fc2184a434"
|
||||||
name = "github.com/docker/cli"
|
name = "github.com/docker/cli"
|
||||||
packages = [
|
packages = [
|
||||||
"cli",
|
"cli",
|
||||||
|
@ -264,7 +265,7 @@
|
||||||
"types",
|
"types",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "2432af701a7973ea582196b4b9488831156f3458"
|
revision = "8aebc318062963ba861b65cc2a43425dfdd80fe7"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -323,7 +324,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:37c8169fc0ff166b4ca825154d709545282fffee5572a6a63e1fdfa709c3f0fe"
|
digest = "1:83ede099909456cf1f5d6de21e5108b1ea593d5d33859799bfa7d8e575281a3c"
|
||||||
name = "github.com/docker/docker"
|
name = "github.com/docker/docker"
|
||||||
packages = [
|
packages = [
|
||||||
"api",
|
"api",
|
||||||
|
@ -365,7 +366,7 @@
|
||||||
"registry/resumable",
|
"registry/resumable",
|
||||||
]
|
]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "df3b6383d1ee2f067afce98cefd7c300ddcb02d6"
|
revision = "8a208a10de6a13ba2d9f65b9955d3594d9b14615"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:8866486038791fe65ea1abf660041423954b1f3fb99ea6a0ad8424422e943458"
|
digest = "1:8866486038791fe65ea1abf660041423954b1f3fb99ea6a0ad8424422e943458"
|
||||||
|
@ -435,14 +436,6 @@
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "18e7e58ea1a5ec016625a636d0d52500eea123bc"
|
revision = "18e7e58ea1a5ec016625a636d0d52500eea123bc"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:1ccd7321e62f680a988bba496f0f5a9c80410b8104d55b0f6b8ecf84ad328476"
|
|
||||||
name = "github.com/flynn-archive/go-shlex"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "NUT"
|
|
||||||
revision = "3f9db97f856818214da2e1057f8ad84803971cff"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:c6f5a29fce208cb102ad1e356d3a3a361be54604549063943613058a377dd0d0"
|
digest = "1:c6f5a29fce208cb102ad1e356d3a3a361be54604549063943613058a377dd0d0"
|
||||||
name = "github.com/gogo/googleapis"
|
name = "github.com/gogo/googleapis"
|
||||||
|
@ -500,6 +493,14 @@
|
||||||
revision = "f140a6486e521aad38f5917de355cbf147cc0496"
|
revision = "f140a6486e521aad38f5917de355cbf147cc0496"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:c54b2df9eb45e238bca9d7f0e1a4acc90a2e6284e8d31c0df3ec72886ec53406"
|
||||||
|
name = "github.com/google/shlex"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "c34317bd91bf98fab745d77b03933cf8769299fe"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:06a7dadb7b760767341ffb6c8d377238d68a1226f2b21b5d497d2e3f6ecf6b4e"
|
digest = "1:06a7dadb7b760767341ffb6c8d377238d68a1226f2b21b5d497d2e3f6ecf6b4e"
|
||||||
name = "github.com/googleapis/gnostic"
|
name = "github.com/googleapis/gnostic"
|
||||||
|
|
|
@ -296,7 +296,7 @@ func requiredBindMount(targetContextName string, targetOrchestrator string, s st
|
||||||
// in case of docker desktop, we want to rewrite the context in cases where it targets the local swarm or Kubernetes
|
// in case of docker desktop, we want to rewrite the context in cases where it targets the local swarm or Kubernetes
|
||||||
s = &dockerDesktopAwareStore{Store: s}
|
s = &dockerDesktopAwareStore{Store: s}
|
||||||
|
|
||||||
ctxMeta, err := s.GetContextMetadata(targetContextName)
|
ctxMeta, err := s.GetMetadata(targetContextName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bindMount{}, err
|
return bindMount{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,7 @@ func (r *dockerDesktopKubernetesEndpointRewriter) rewrite(ep *kubernetes.Endpoin
|
||||||
ep.Host = fmt.Sprintf("https://%s:6443", ip)
|
ep.Host = fmt.Sprintf("https://%s:6443", ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint:interfacer
|
||||||
func makeLinuxkitIPProvider(contextName string, s store.Store) dockerDesktopLinuxKitIPProvider {
|
func makeLinuxkitIPProvider(contextName string, s store.Store) dockerDesktopLinuxKitIPProvider {
|
||||||
return func() (string, error) {
|
return func() (string, error) {
|
||||||
clientCfg, err := kubernetes.ConfigFromContext(contextName, s)
|
clientCfg, err := kubernetes.ConfigFromContext(contextName, s)
|
||||||
|
@ -104,7 +105,7 @@ func makeLinuxkitIPProvider(contextName string, s store.Store) dockerDesktopLinu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func rewriteContextIfDockerDesktop(meta *store.ContextMetadata, s store.Store) {
|
func rewriteContextIfDockerDesktop(meta *store.Metadata, s store.Store) {
|
||||||
// errors are treated as "don't rewrite"
|
// errors are treated as "don't rewrite"
|
||||||
rewriter := dockerDesktopDockerEndpointRewriter{
|
rewriter := dockerDesktopDockerEndpointRewriter{
|
||||||
defaultHostProvider: defaultDockerDesktopHostProvider,
|
defaultHostProvider: defaultDockerDesktopHostProvider,
|
||||||
|
@ -131,8 +132,8 @@ type dockerDesktopAwareStore struct {
|
||||||
store.Store
|
store.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s dockerDesktopAwareStore) ListContexts() ([]store.ContextMetadata, error) {
|
func (s dockerDesktopAwareStore) List() ([]store.Metadata, error) {
|
||||||
contexts, err := s.Store.ListContexts()
|
contexts, err := s.Store.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -143,10 +144,10 @@ func (s dockerDesktopAwareStore) ListContexts() ([]store.ContextMetadata, error)
|
||||||
return contexts, nil
|
return contexts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s dockerDesktopAwareStore) GetContextMetadata(name string) (store.ContextMetadata, error) {
|
func (s dockerDesktopAwareStore) GetMetadata(name string) (store.Metadata, error) {
|
||||||
context, err := s.Store.GetContextMetadata(name)
|
context, err := s.Store.GetMetadata(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return store.ContextMetadata{}, err
|
return store.Metadata{}, err
|
||||||
}
|
}
|
||||||
rewriteContextIfDockerDesktop(&context, s.Store)
|
rewriteContextIfDockerDesktop(&context, s.Store)
|
||||||
return context, nil
|
return context, nil
|
||||||
|
|
51
vendor/github.com/Microsoft/hcsshim/osversion/osversion.go
сгенерированный
поставляемый
Normal file
51
vendor/github.com/Microsoft/hcsshim/osversion/osversion.go
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package osversion
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OSVersion is a wrapper for Windows version information
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
|
||||||
|
type OSVersion struct {
|
||||||
|
Version uint32
|
||||||
|
MajorVersion uint8
|
||||||
|
MinorVersion uint8
|
||||||
|
Build uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx
|
||||||
|
type osVersionInfoEx struct {
|
||||||
|
OSVersionInfoSize uint32
|
||||||
|
MajorVersion uint32
|
||||||
|
MinorVersion uint32
|
||||||
|
BuildNumber uint32
|
||||||
|
PlatformID uint32
|
||||||
|
CSDVersion [128]uint16
|
||||||
|
ServicePackMajor uint16
|
||||||
|
ServicePackMinor uint16
|
||||||
|
SuiteMask uint16
|
||||||
|
ProductType byte
|
||||||
|
Reserve byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the operating system version on Windows.
|
||||||
|
// The calling application must be manifested to get the correct version information.
|
||||||
|
func Get() OSVersion {
|
||||||
|
var err error
|
||||||
|
osv := OSVersion{}
|
||||||
|
osv.Version, err = windows.GetVersion()
|
||||||
|
if err != nil {
|
||||||
|
// GetVersion never fails.
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
osv.MajorVersion = uint8(osv.Version & 0xFF)
|
||||||
|
osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF)
|
||||||
|
osv.Build = uint16(osv.Version >> 16)
|
||||||
|
return osv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (osv OSVersion) ToString() string {
|
||||||
|
return fmt.Sprintf("%d.%d.%d", osv.MajorVersion, osv.MinorVersion, osv.Build)
|
||||||
|
}
|
10
vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go
сгенерированный
поставляемый
Normal file
10
vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package osversion
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// RS2 was a client-only release in case you're asking why it's not in the list.
|
||||||
|
RS1 = 14393
|
||||||
|
RS3 = 16299
|
||||||
|
RS4 = 17134
|
||||||
|
RS5 = 17763
|
||||||
|
)
|
|
@ -58,6 +58,7 @@ Anton Polonskiy <anton.polonskiy@gmail.com>
|
||||||
Antonio Murdaca <antonio.murdaca@gmail.com>
|
Antonio Murdaca <antonio.murdaca@gmail.com>
|
||||||
Antonis Kalipetis <akalipetis@gmail.com>
|
Antonis Kalipetis <akalipetis@gmail.com>
|
||||||
Anusha Ragunathan <anusha.ragunathan@docker.com>
|
Anusha Ragunathan <anusha.ragunathan@docker.com>
|
||||||
|
Ao Li <la9249@163.com>
|
||||||
Arash Deshmeh <adeshmeh@ca.ibm.com>
|
Arash Deshmeh <adeshmeh@ca.ibm.com>
|
||||||
Arnaud Porterie <arnaud.porterie@docker.com>
|
Arnaud Porterie <arnaud.porterie@docker.com>
|
||||||
Ashwini Oruganti <ashwini.oruganti@gmail.com>
|
Ashwini Oruganti <ashwini.oruganti@gmail.com>
|
||||||
|
@ -158,6 +159,7 @@ David Cramer <davcrame@cisco.com>
|
||||||
David Dooling <dooling@gmail.com>
|
David Dooling <dooling@gmail.com>
|
||||||
David Gageot <david@gageot.net>
|
David Gageot <david@gageot.net>
|
||||||
David Lechner <david@lechnology.com>
|
David Lechner <david@lechnology.com>
|
||||||
|
David Scott <dave@recoil.org>
|
||||||
David Sheets <dsheets@docker.com>
|
David Sheets <dsheets@docker.com>
|
||||||
David Williamson <david.williamson@docker.com>
|
David Williamson <david.williamson@docker.com>
|
||||||
David Xia <dxia@spotify.com>
|
David Xia <dxia@spotify.com>
|
||||||
|
@ -300,6 +302,7 @@ Jim Galasyn <jim.galasyn@docker.com>
|
||||||
Jimmy Leger <jimmy.leger@gmail.com>
|
Jimmy Leger <jimmy.leger@gmail.com>
|
||||||
Jimmy Song <rootsongjc@gmail.com>
|
Jimmy Song <rootsongjc@gmail.com>
|
||||||
jimmyxian <jimmyxian2004@yahoo.com.cn>
|
jimmyxian <jimmyxian2004@yahoo.com.cn>
|
||||||
|
Jintao Zhang <zhangjintao9020@gmail.com>
|
||||||
Joao Fernandes <joao.fernandes@docker.com>
|
Joao Fernandes <joao.fernandes@docker.com>
|
||||||
Joe Doliner <jdoliner@pachyderm.io>
|
Joe Doliner <jdoliner@pachyderm.io>
|
||||||
Joe Gordon <joe.gordon0@gmail.com>
|
Joe Gordon <joe.gordon0@gmail.com>
|
||||||
|
@ -471,9 +474,11 @@ Mrunal Patel <mrunalp@gmail.com>
|
||||||
muicoder <muicoder@gmail.com>
|
muicoder <muicoder@gmail.com>
|
||||||
Muthukumar R <muthur@gmail.com>
|
Muthukumar R <muthur@gmail.com>
|
||||||
Máximo Cuadros <mcuadros@gmail.com>
|
Máximo Cuadros <mcuadros@gmail.com>
|
||||||
|
Mårten Cassel <marten.cassel@gmail.com>
|
||||||
Nace Oroz <orkica@gmail.com>
|
Nace Oroz <orkica@gmail.com>
|
||||||
Nahum Shalman <nshalman@omniti.com>
|
Nahum Shalman <nshalman@omniti.com>
|
||||||
Nalin Dahyabhai <nalin@redhat.com>
|
Nalin Dahyabhai <nalin@redhat.com>
|
||||||
|
Nao YONASHIRO <owan.orisano@gmail.com>
|
||||||
Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
|
Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
|
||||||
Natalie Parker <nparker@omnifone.com>
|
Natalie Parker <nparker@omnifone.com>
|
||||||
Nate Brennand <nate.brennand@clever.com>
|
Nate Brennand <nate.brennand@clever.com>
|
||||||
|
@ -595,7 +600,7 @@ Spencer Brown <spencer@spencerbrown.org>
|
||||||
squeegels <1674195+squeegels@users.noreply.github.com>
|
squeegels <1674195+squeegels@users.noreply.github.com>
|
||||||
Srini Brahmaroutu <srbrahma@us.ibm.com>
|
Srini Brahmaroutu <srbrahma@us.ibm.com>
|
||||||
Stefan S. <tronicum@user.github.com>
|
Stefan S. <tronicum@user.github.com>
|
||||||
Stefan Scherer <scherer_stefan@icloud.com>
|
Stefan Scherer <stefan.scherer@docker.com>
|
||||||
Stefan Weil <sw@weilnetz.de>
|
Stefan Weil <sw@weilnetz.de>
|
||||||
Stephane Jeandeaux <stephane.jeandeaux@gmail.com>
|
Stephane Jeandeaux <stephane.jeandeaux@gmail.com>
|
||||||
Stephen Day <stevvooe@gmail.com>
|
Stephen Day <stevvooe@gmail.com>
|
||||||
|
@ -605,7 +610,9 @@ Steve Richards <steve.richards@docker.com>
|
||||||
Steven Burgess <steven.a.burgess@hotmail.com>
|
Steven Burgess <steven.a.burgess@hotmail.com>
|
||||||
Subhajit Ghosh <isubuz.g@gmail.com>
|
Subhajit Ghosh <isubuz.g@gmail.com>
|
||||||
Sun Jianbo <wonderflow.sun@gmail.com>
|
Sun Jianbo <wonderflow.sun@gmail.com>
|
||||||
|
Sune Keller <absukl@almbrand.dk>
|
||||||
Sungwon Han <sungwon.han@navercorp.com>
|
Sungwon Han <sungwon.han@navercorp.com>
|
||||||
|
Sunny Gogoi <indiasuny000@gmail.com>
|
||||||
Sven Dowideit <SvenDowideit@home.org.au>
|
Sven Dowideit <SvenDowideit@home.org.au>
|
||||||
Sylvain Baubeau <sbaubeau@redhat.com>
|
Sylvain Baubeau <sbaubeau@redhat.com>
|
||||||
Sébastien HOUZÉ <cto@verylastroom.com>
|
Sébastien HOUZÉ <cto@verylastroom.com>
|
||||||
|
|
|
@ -164,6 +164,7 @@ func PluginRunCommand(dockerCli command.Cli, name string, rootcmd *cobra.Command
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if plugin.Err != nil {
|
if plugin.Err != nil {
|
||||||
|
// TODO: why are we not returning plugin.Err?
|
||||||
return nil, errPluginNotFound(name)
|
return nil, errPluginNotFound(name)
|
||||||
}
|
}
|
||||||
cmd := exec.Command(plugin.Path, args...)
|
cmd := exec.Command(plugin.Path, args...)
|
||||||
|
|
|
@ -114,11 +114,14 @@ func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta
|
||||||
fullname := manager.NamePrefix + name
|
fullname := manager.NamePrefix + name
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: fmt.Sprintf("docker [OPTIONS] %s [ARG...]", name),
|
Use: fmt.Sprintf("docker [OPTIONS] %s [ARG...]", name),
|
||||||
Short: fullname + " is a Docker CLI plugin",
|
Short: fullname + " is a Docker CLI plugin",
|
||||||
SilenceUsage: true,
|
SilenceUsage: true,
|
||||||
SilenceErrors: true,
|
SilenceErrors: true,
|
||||||
PersistentPreRunE: PersistentPreRunE,
|
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
// We can't use this as the hook directly since it is initialised later (in runPlugin)
|
||||||
|
return PersistentPreRunE(cmd, args)
|
||||||
|
},
|
||||||
TraverseChildren: true,
|
TraverseChildren: true,
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,8 +290,8 @@ func newAPIClientFromEndpoint(ep docker.Endpoint, configFile *configfile.ConfigF
|
||||||
return client.NewClientWithOpts(clientOpts...)
|
return client.NewClientWithOpts(clientOpts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveDockerEndpoint(s store.Store, contextName string) (docker.Endpoint, error) {
|
func resolveDockerEndpoint(s store.Reader, contextName string) (docker.Endpoint, error) {
|
||||||
ctxMeta, err := s.GetContextMetadata(contextName)
|
ctxMeta, err := s.GetMetadata(contextName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return docker.Endpoint{}, err
|
return docker.Endpoint{}, err
|
||||||
}
|
}
|
||||||
|
@ -399,7 +399,7 @@ func (cli *DockerCli) CurrentContext() string {
|
||||||
// StackOrchestrator resolves which stack orchestrator is in use
|
// StackOrchestrator resolves which stack orchestrator is in use
|
||||||
func (cli *DockerCli) StackOrchestrator(flagValue string) (Orchestrator, error) {
|
func (cli *DockerCli) StackOrchestrator(flagValue string) (Orchestrator, error) {
|
||||||
currentContext := cli.CurrentContext()
|
currentContext := cli.CurrentContext()
|
||||||
ctxRaw, err := cli.ContextStore().GetContextMetadata(currentContext)
|
ctxRaw, err := cli.ContextStore().GetMetadata(currentContext)
|
||||||
if store.IsErrContextDoesNotExist(err) {
|
if store.IsErrContextDoesNotExist(err) {
|
||||||
// case where the currentContext has been removed (CLI behavior is to fallback to using DOCKER_HOST based resolution)
|
// case where the currentContext has been removed (CLI behavior is to fallback to using DOCKER_HOST based resolution)
|
||||||
return GetStackOrchestrator(flagValue, "", cli.ConfigFile().StackOrchestrator, cli.Err())
|
return GetStackOrchestrator(flagValue, "", cli.ConfigFile().StackOrchestrator, cli.Err())
|
||||||
|
@ -500,7 +500,7 @@ func UserAgent() string {
|
||||||
// - if DOCKER_CONTEXT is set, use this value
|
// - if DOCKER_CONTEXT is set, use this value
|
||||||
// - if Config file has a globally set "CurrentContext", use this value
|
// - if Config file has a globally set "CurrentContext", use this value
|
||||||
// - fallbacks to default HOST, uses TLS config from flags/env vars
|
// - fallbacks to default HOST, uses TLS config from flags/env vars
|
||||||
func resolveContextName(opts *cliflags.CommonOptions, config *configfile.ConfigFile, contextstore store.Store) (string, error) {
|
func resolveContextName(opts *cliflags.CommonOptions, config *configfile.ConfigFile, contextstore store.Reader) (string, error) {
|
||||||
if opts.Context != "" && len(opts.Hosts) > 0 {
|
if opts.Context != "" && len(opts.Hosts) > 0 {
|
||||||
return "", errors.New("Conflicting options: either specify --host or --context, not both")
|
return "", errors.New("Conflicting options: either specify --host or --context, not both")
|
||||||
}
|
}
|
||||||
|
@ -517,7 +517,7 @@ func resolveContextName(opts *cliflags.CommonOptions, config *configfile.ConfigF
|
||||||
return ctxName, nil
|
return ctxName, nil
|
||||||
}
|
}
|
||||||
if config != nil && config.CurrentContext != "" {
|
if config != nil && config.CurrentContext != "" {
|
||||||
_, err := contextstore.GetContextMetadata(config.CurrentContext)
|
_, err := contextstore.GetMetadata(config.CurrentContext)
|
||||||
if store.IsErrContextDoesNotExist(err) {
|
if store.IsErrContextDoesNotExist(err) {
|
||||||
return "", errors.Errorf("Current context %q is not found on the file system, please check your config file at %s", config.CurrentContext, config.Filename)
|
return "", errors.Errorf("Current context %q is not found on the file system, please check your config file at %s", config.CurrentContext, config.Filename)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ type DockerContext struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDockerContext extracts metadata from stored context metadata
|
// GetDockerContext extracts metadata from stored context metadata
|
||||||
func GetDockerContext(storeMetadata store.ContextMetadata) (DockerContext, error) {
|
func GetDockerContext(storeMetadata store.Metadata) (DockerContext, error) {
|
||||||
if storeMetadata.Metadata == nil {
|
if storeMetadata.Metadata == nil {
|
||||||
// can happen if we save endpoints before assigning a context metadata
|
// can happen if we save endpoints before assigning a context metadata
|
||||||
// it is totally valid, and we should return a default initialized value
|
// it is totally valid, and we should return a default initialized value
|
||||||
|
|
|
@ -22,7 +22,7 @@ const (
|
||||||
|
|
||||||
// DefaultContext contains the default context data for all enpoints
|
// DefaultContext contains the default context data for all enpoints
|
||||||
type DefaultContext struct {
|
type DefaultContext struct {
|
||||||
Meta store.ContextMetadata
|
Meta store.Metadata
|
||||||
TLS store.ContextTLSData
|
TLS store.ContextTLSData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ type ContextStoreWithDefault struct {
|
||||||
Resolver DefaultContextResolver
|
Resolver DefaultContextResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveDefaultContext creates a ContextMetadata for the current CLI invocation parameters
|
// resolveDefaultContext creates a Metadata for the current CLI invocation parameters
|
||||||
func resolveDefaultContext(opts *cliflags.CommonOptions, config *configfile.ConfigFile, stderr io.Writer) (*DefaultContext, error) {
|
func resolveDefaultContext(opts *cliflags.CommonOptions, config *configfile.ConfigFile, stderr io.Writer) (*DefaultContext, error) {
|
||||||
stackOrchestrator, err := GetStackOrchestrator("", "", config.StackOrchestrator, stderr)
|
stackOrchestrator, err := GetStackOrchestrator("", "", config.StackOrchestrator, stderr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -44,7 +44,7 @@ func resolveDefaultContext(opts *cliflags.CommonOptions, config *configfile.Conf
|
||||||
contextTLSData := store.ContextTLSData{
|
contextTLSData := store.ContextTLSData{
|
||||||
Endpoints: make(map[string]store.EndpointTLSData),
|
Endpoints: make(map[string]store.EndpointTLSData),
|
||||||
}
|
}
|
||||||
contextMetadata := store.ContextMetadata{
|
contextMetadata := store.Metadata{
|
||||||
Endpoints: make(map[string]interface{}),
|
Endpoints: make(map[string]interface{}),
|
||||||
Metadata: DockerContext{
|
Metadata: DockerContext{
|
||||||
Description: "",
|
Description: "",
|
||||||
|
@ -81,9 +81,9 @@ func resolveDefaultContext(opts *cliflags.CommonOptions, config *configfile.Conf
|
||||||
return &DefaultContext{Meta: contextMetadata, TLS: contextTLSData}, nil
|
return &DefaultContext{Meta: contextMetadata, TLS: contextTLSData}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListContexts implements store.Store's ListContexts
|
// List implements store.Store's List
|
||||||
func (s *ContextStoreWithDefault) ListContexts() ([]store.ContextMetadata, error) {
|
func (s *ContextStoreWithDefault) List() ([]store.Metadata, error) {
|
||||||
contextList, err := s.Store.ListContexts()
|
contextList, err := s.Store.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -94,52 +94,52 @@ func (s *ContextStoreWithDefault) ListContexts() ([]store.ContextMetadata, error
|
||||||
return append(contextList, defaultContext.Meta), nil
|
return append(contextList, defaultContext.Meta), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateOrUpdateContext is not allowed for the default context and fails
|
// CreateOrUpdate is not allowed for the default context and fails
|
||||||
func (s *ContextStoreWithDefault) CreateOrUpdateContext(meta store.ContextMetadata) error {
|
func (s *ContextStoreWithDefault) CreateOrUpdate(meta store.Metadata) error {
|
||||||
if meta.Name == DefaultContextName {
|
if meta.Name == DefaultContextName {
|
||||||
return errors.New("default context cannot be created nor updated")
|
return errors.New("default context cannot be created nor updated")
|
||||||
}
|
}
|
||||||
return s.Store.CreateOrUpdateContext(meta)
|
return s.Store.CreateOrUpdate(meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveContext is not allowed for the default context and fails
|
// Remove is not allowed for the default context and fails
|
||||||
func (s *ContextStoreWithDefault) RemoveContext(name string) error {
|
func (s *ContextStoreWithDefault) Remove(name string) error {
|
||||||
if name == DefaultContextName {
|
if name == DefaultContextName {
|
||||||
return errors.New("default context cannot be removed")
|
return errors.New("default context cannot be removed")
|
||||||
}
|
}
|
||||||
return s.Store.RemoveContext(name)
|
return s.Store.Remove(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContextMetadata implements store.Store's GetContextMetadata
|
// GetMetadata implements store.Store's GetMetadata
|
||||||
func (s *ContextStoreWithDefault) GetContextMetadata(name string) (store.ContextMetadata, error) {
|
func (s *ContextStoreWithDefault) GetMetadata(name string) (store.Metadata, error) {
|
||||||
if name == DefaultContextName {
|
if name == DefaultContextName {
|
||||||
defaultContext, err := s.Resolver()
|
defaultContext, err := s.Resolver()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return store.ContextMetadata{}, err
|
return store.Metadata{}, err
|
||||||
}
|
}
|
||||||
return defaultContext.Meta, nil
|
return defaultContext.Meta, nil
|
||||||
}
|
}
|
||||||
return s.Store.GetContextMetadata(name)
|
return s.Store.GetMetadata(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetContextTLSMaterial is not implemented for default context and fails
|
// ResetTLSMaterial is not implemented for default context and fails
|
||||||
func (s *ContextStoreWithDefault) ResetContextTLSMaterial(name string, data *store.ContextTLSData) error {
|
func (s *ContextStoreWithDefault) ResetTLSMaterial(name string, data *store.ContextTLSData) error {
|
||||||
if name == DefaultContextName {
|
if name == DefaultContextName {
|
||||||
return errors.New("The default context store does not support ResetContextTLSMaterial")
|
return errors.New("The default context store does not support ResetTLSMaterial")
|
||||||
}
|
}
|
||||||
return s.Store.ResetContextTLSMaterial(name, data)
|
return s.Store.ResetTLSMaterial(name, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetContextEndpointTLSMaterial is not implemented for default context and fails
|
// ResetEndpointTLSMaterial is not implemented for default context and fails
|
||||||
func (s *ContextStoreWithDefault) ResetContextEndpointTLSMaterial(contextName string, endpointName string, data *store.EndpointTLSData) error {
|
func (s *ContextStoreWithDefault) ResetEndpointTLSMaterial(contextName string, endpointName string, data *store.EndpointTLSData) error {
|
||||||
if contextName == DefaultContextName {
|
if contextName == DefaultContextName {
|
||||||
return errors.New("The default context store does not support ResetContextEndpointTLSMaterial")
|
return errors.New("The default context store does not support ResetEndpointTLSMaterial")
|
||||||
}
|
}
|
||||||
return s.Store.ResetContextEndpointTLSMaterial(contextName, endpointName, data)
|
return s.Store.ResetEndpointTLSMaterial(contextName, endpointName, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListContextTLSFiles implements store.Store's ListContextTLSFiles
|
// ListTLSFiles implements store.Store's ListTLSFiles
|
||||||
func (s *ContextStoreWithDefault) ListContextTLSFiles(name string) (map[string]store.EndpointFiles, error) {
|
func (s *ContextStoreWithDefault) ListTLSFiles(name string) (map[string]store.EndpointFiles, error) {
|
||||||
if name == DefaultContextName {
|
if name == DefaultContextName {
|
||||||
defaultContext, err := s.Resolver()
|
defaultContext, err := s.Resolver()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -155,11 +155,11 @@ func (s *ContextStoreWithDefault) ListContextTLSFiles(name string) (map[string]s
|
||||||
}
|
}
|
||||||
return tlsfiles, nil
|
return tlsfiles, nil
|
||||||
}
|
}
|
||||||
return s.Store.ListContextTLSFiles(name)
|
return s.Store.ListTLSFiles(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContextTLSData implements store.Store's GetContextTLSData
|
// GetTLSData implements store.Store's GetTLSData
|
||||||
func (s *ContextStoreWithDefault) GetContextTLSData(contextName, endpointName, fileName string) ([]byte, error) {
|
func (s *ContextStoreWithDefault) GetTLSData(contextName, endpointName, fileName string) ([]byte, error) {
|
||||||
if contextName == DefaultContextName {
|
if contextName == DefaultContextName {
|
||||||
defaultContext, err := s.Resolver()
|
defaultContext, err := s.Resolver()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -171,7 +171,7 @@ func (s *ContextStoreWithDefault) GetContextTLSData(contextName, endpointName, f
|
||||||
return defaultContext.TLS.Endpoints[endpointName].Files[fileName], nil
|
return defaultContext.TLS.Endpoints[endpointName].Files[fileName], nil
|
||||||
|
|
||||||
}
|
}
|
||||||
return s.Store.GetContextTLSData(contextName, endpointName, fileName)
|
return s.Store.GetTLSData(contextName, endpointName, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
type noDefaultTLSDataError struct {
|
type noDefaultTLSDataError struct {
|
||||||
|
@ -189,10 +189,10 @@ func (e *noDefaultTLSDataError) NotFound() {}
|
||||||
// IsTLSDataDoesNotExist satisfies github.com/docker/cli/cli/context/store.tlsDataDoesNotExist
|
// IsTLSDataDoesNotExist satisfies github.com/docker/cli/cli/context/store.tlsDataDoesNotExist
|
||||||
func (e *noDefaultTLSDataError) IsTLSDataDoesNotExist() {}
|
func (e *noDefaultTLSDataError) IsTLSDataDoesNotExist() {}
|
||||||
|
|
||||||
// GetContextStorageInfo implements store.Store's GetContextStorageInfo
|
// GetStorageInfo implements store.Store's GetStorageInfo
|
||||||
func (s *ContextStoreWithDefault) GetContextStorageInfo(contextName string) store.ContextStorageInfo {
|
func (s *ContextStoreWithDefault) GetStorageInfo(contextName string) store.StorageInfo {
|
||||||
if contextName == DefaultContextName {
|
if contextName == DefaultContextName {
|
||||||
return store.ContextStorageInfo{MetadataPath: "<IN MEMORY>", TLSPath: "<IN MEMORY>"}
|
return store.StorageInfo{MetadataPath: "<IN MEMORY>", TLSPath: "<IN MEMORY>"}
|
||||||
}
|
}
|
||||||
return s.Store.GetContextStorageInfo(contextName)
|
return s.Store.GetStorageInfo(contextName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@ import (
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/docker/swarmkit/api"
|
"github.com/docker/swarmkit/api"
|
||||||
"github.com/docker/swarmkit/api/defaults"
|
"github.com/docker/swarmkit/api/defaults"
|
||||||
shlex "github.com/flynn-archive/go-shlex"
|
|
||||||
gogotypes "github.com/gogo/protobuf/types"
|
gogotypes "github.com/gogo/protobuf/types"
|
||||||
|
"github.com/google/shlex"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
|
@ -161,3 +161,34 @@ func ValidateOutputPathFileMode(fileMode os.FileMode) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stringSliceIndex(s, subs []string) int {
|
||||||
|
j := 0
|
||||||
|
if len(subs) > 0 {
|
||||||
|
for i, x := range s {
|
||||||
|
if j < len(subs) && subs[j] == x {
|
||||||
|
j++
|
||||||
|
} else {
|
||||||
|
j = 0
|
||||||
|
}
|
||||||
|
if len(subs) == j {
|
||||||
|
return i + 1 - j
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSliceReplaceAt replaces the sub-slice old, with the sub-slice new, in the string
|
||||||
|
// slice s, returning a new slice and a boolean indicating if the replacement happened.
|
||||||
|
// requireIdx is the index at which old needs to be found at (or -1 to disregard that).
|
||||||
|
func StringSliceReplaceAt(s, old, new []string, requireIndex int) ([]string, bool) {
|
||||||
|
idx := stringSliceIndex(s, old)
|
||||||
|
if (requireIndex != -1 && requireIndex != idx) || idx == -1 {
|
||||||
|
return s, false
|
||||||
|
}
|
||||||
|
out := append([]string{}, s[:idx]...)
|
||||||
|
out = append(out, new...)
|
||||||
|
out = append(out, s[idx+len(old):]...)
|
||||||
|
return out, true
|
||||||
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ type ConfigFile struct {
|
||||||
CurrentContext string `json:"currentContext,omitempty"`
|
CurrentContext string `json:"currentContext,omitempty"`
|
||||||
CLIPluginsExtraDirs []string `json:"cliPluginsExtraDirs,omitempty"`
|
CLIPluginsExtraDirs []string `json:"cliPluginsExtraDirs,omitempty"`
|
||||||
Plugins map[string]map[string]string `json:"plugins,omitempty"`
|
Plugins map[string]map[string]string `json:"plugins,omitempty"`
|
||||||
|
Aliases map[string]string `json:"aliases,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProxyConfig contains proxy configuration settings
|
// ProxyConfig contains proxy configuration settings
|
||||||
|
@ -72,6 +73,7 @@ func New(fn string) *ConfigFile {
|
||||||
HTTPHeaders: make(map[string]string),
|
HTTPHeaders: make(map[string]string),
|
||||||
Filename: fn,
|
Filename: fn,
|
||||||
Plugins: make(map[string]map[string]string),
|
Plugins: make(map[string]map[string]string),
|
||||||
|
Aliases: make(map[string]string),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
vendor/github.com/docker/cli/cli/connhelper/commandconn/commandconn.go
сгенерированный
поставляемый
2
vendor/github.com/docker/cli/cli/connhelper/commandconn/commandconn.go
сгенерированный
поставляемый
|
@ -41,7 +41,9 @@ func New(ctx context.Context, cmd string, args ...string) (net.Conn, error) {
|
||||||
// we assume that args never contains sensitive information
|
// we assume that args never contains sensitive information
|
||||||
logrus.Debugf("commandconn: starting %s with %v", cmd, args)
|
logrus.Debugf("commandconn: starting %s with %v", cmd, args)
|
||||||
c.cmd.Env = os.Environ()
|
c.cmd.Env = os.Environ()
|
||||||
|
c.cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
setPdeathsig(c.cmd)
|
setPdeathsig(c.cmd)
|
||||||
|
createSession(c.cmd)
|
||||||
c.stdin, err = c.cmd.StdinPipe()
|
c.stdin, err = c.cmd.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -6,7 +6,5 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func setPdeathsig(cmd *exec.Cmd) {
|
func setPdeathsig(cmd *exec.Cmd) {
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
cmd.SysProcAttr.Pdeathsig = syscall.SIGKILL
|
||||||
Pdeathsig: syscall.SIGKILL,
|
|
||||||
}
|
|
||||||
}
|
}
|
13
vendor/github.com/docker/cli/cli/connhelper/commandconn/session_unix.go
сгенерированный
поставляемый
Normal file
13
vendor/github.com/docker/cli/cli/connhelper/commandconn/session_unix.go
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package commandconn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createSession(cmd *exec.Cmd) {
|
||||||
|
// for supporting ssh connection helper with ProxyCommand
|
||||||
|
// https://github.com/docker/cli/issues/1707
|
||||||
|
cmd.SysProcAttr.Setsid = true
|
||||||
|
}
|
8
vendor/github.com/docker/cli/cli/connhelper/commandconn/session_windows.go
сгенерированный
поставляемый
Normal file
8
vendor/github.com/docker/cli/cli/connhelper/commandconn/session_windows.go
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package commandconn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createSession(cmd *exec.Cmd) {
|
||||||
|
}
|
|
@ -31,7 +31,7 @@ type Endpoint struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithTLSData loads TLS materials for the endpoint
|
// WithTLSData loads TLS materials for the endpoint
|
||||||
func WithTLSData(s store.Store, contextName string, m EndpointMeta) (Endpoint, error) {
|
func WithTLSData(s store.Reader, contextName string, m EndpointMeta) (Endpoint, error) {
|
||||||
tlsData, err := context.LoadTLSData(s, contextName, DockerEndpoint)
|
tlsData, err := context.LoadTLSData(s, contextName, DockerEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Endpoint{}, err
|
return Endpoint{}, err
|
||||||
|
@ -91,8 +91,8 @@ func (c *Endpoint) tlsConfig() (*tls.Config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientOpts returns a slice of Client options to configure an API client with this endpoint
|
// ClientOpts returns a slice of Client options to configure an API client with this endpoint
|
||||||
func (c *Endpoint) ClientOpts() ([]func(*client.Client) error, error) {
|
func (c *Endpoint) ClientOpts() ([]client.Opt, error) {
|
||||||
var result []func(*client.Client) error
|
var result []client.Opt
|
||||||
if c.Host != "" {
|
if c.Host != "" {
|
||||||
helper, err := connhelper.GetConnectionHelper(c.Host)
|
helper, err := connhelper.GetConnectionHelper(c.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -153,7 +153,7 @@ func withHTTPClient(tlsConfig *tls.Config) func(*client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointFromContext parses a context docker endpoint metadata into a typed EndpointMeta structure
|
// EndpointFromContext parses a context docker endpoint metadata into a typed EndpointMeta structure
|
||||||
func EndpointFromContext(metadata store.ContextMetadata) (EndpointMeta, error) {
|
func EndpointFromContext(metadata store.Metadata) (EndpointMeta, error) {
|
||||||
ep, ok := metadata.Endpoints[DockerEndpoint]
|
ep, ok := metadata.Endpoints[DockerEndpoint]
|
||||||
if !ok {
|
if !ok {
|
||||||
return EndpointMeta{}, errors.New("cannot find docker endpoint in context")
|
return EndpointMeta{}, errors.New("cannot find docker endpoint in context")
|
||||||
|
|
|
@ -25,7 +25,7 @@ type Endpoint struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithTLSData loads TLS materials for the endpoint
|
// WithTLSData loads TLS materials for the endpoint
|
||||||
func (c *EndpointMeta) WithTLSData(s store.Store, contextName string) (Endpoint, error) {
|
func (c *EndpointMeta) WithTLSData(s store.Reader, contextName string) (Endpoint, error) {
|
||||||
tlsData, err := context.LoadTLSData(s, contextName, KubernetesEndpoint)
|
tlsData, err := context.LoadTLSData(s, contextName, KubernetesEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Endpoint{}, err
|
return Endpoint{}, err
|
||||||
|
@ -62,7 +62,7 @@ func (c *Endpoint) KubernetesConfig() clientcmd.ClientConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointFromContext extracts kubernetes endpoint info from current context
|
// EndpointFromContext extracts kubernetes endpoint info from current context
|
||||||
func EndpointFromContext(metadata store.ContextMetadata) *EndpointMeta {
|
func EndpointFromContext(metadata store.Metadata) *EndpointMeta {
|
||||||
ep, ok := metadata.Endpoints[KubernetesEndpoint]
|
ep, ok := metadata.Endpoints[KubernetesEndpoint]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
|
@ -77,8 +77,8 @@ func EndpointFromContext(metadata store.ContextMetadata) *EndpointMeta {
|
||||||
// ConfigFromContext resolves a kubernetes client config for the specified context.
|
// ConfigFromContext resolves a kubernetes client config for the specified context.
|
||||||
// If kubeconfigOverride is specified, use this config file instead of the context defaults.ConfigFromContext
|
// If kubeconfigOverride is specified, use this config file instead of the context defaults.ConfigFromContext
|
||||||
// if command.ContextDockerHost is specified as the context name, fallsback to the default user's kubeconfig file
|
// if command.ContextDockerHost is specified as the context name, fallsback to the default user's kubeconfig file
|
||||||
func ConfigFromContext(name string, s store.Store) (clientcmd.ClientConfig, error) {
|
func ConfigFromContext(name string, s store.Reader) (clientcmd.ClientConfig, error) {
|
||||||
ctxMeta, err := s.GetContextMetadata(name)
|
ctxMeta, err := s.GetMetadata(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (s *metadataStore) contextDir(id contextdir) string {
|
||||||
return filepath.Join(s.root, string(id))
|
return filepath.Join(s.root, string(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *metadataStore) createOrUpdate(meta ContextMetadata) error {
|
func (s *metadataStore) createOrUpdate(meta Metadata) error {
|
||||||
contextDir := s.contextDir(contextdirOf(meta.Name))
|
contextDir := s.contextDir(contextdirOf(meta.Name))
|
||||||
if err := os.MkdirAll(contextDir, 0755); err != nil {
|
if err := os.MkdirAll(contextDir, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -56,26 +56,26 @@ func parseTypedOrMap(payload []byte, getter TypeGetter) (interface{}, error) {
|
||||||
return reflect.ValueOf(typed).Elem().Interface(), nil
|
return reflect.ValueOf(typed).Elem().Interface(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *metadataStore) get(id contextdir) (ContextMetadata, error) {
|
func (s *metadataStore) get(id contextdir) (Metadata, error) {
|
||||||
contextDir := s.contextDir(id)
|
contextDir := s.contextDir(id)
|
||||||
bytes, err := ioutil.ReadFile(filepath.Join(contextDir, metaFile))
|
bytes, err := ioutil.ReadFile(filepath.Join(contextDir, metaFile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ContextMetadata{}, convertContextDoesNotExist(err)
|
return Metadata{}, convertContextDoesNotExist(err)
|
||||||
}
|
}
|
||||||
var untyped untypedContextMetadata
|
var untyped untypedContextMetadata
|
||||||
r := ContextMetadata{
|
r := Metadata{
|
||||||
Endpoints: make(map[string]interface{}),
|
Endpoints: make(map[string]interface{}),
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(bytes, &untyped); err != nil {
|
if err := json.Unmarshal(bytes, &untyped); err != nil {
|
||||||
return ContextMetadata{}, err
|
return Metadata{}, err
|
||||||
}
|
}
|
||||||
r.Name = untyped.Name
|
r.Name = untyped.Name
|
||||||
if r.Metadata, err = parseTypedOrMap(untyped.Metadata, s.config.contextType); err != nil {
|
if r.Metadata, err = parseTypedOrMap(untyped.Metadata, s.config.contextType); err != nil {
|
||||||
return ContextMetadata{}, err
|
return Metadata{}, err
|
||||||
}
|
}
|
||||||
for k, v := range untyped.Endpoints {
|
for k, v := range untyped.Endpoints {
|
||||||
if r.Endpoints[k], err = parseTypedOrMap(v, s.config.endpointTypes[k]); err != nil {
|
if r.Endpoints[k], err = parseTypedOrMap(v, s.config.endpointTypes[k]); err != nil {
|
||||||
return ContextMetadata{}, err
|
return Metadata{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r, err
|
return r, err
|
||||||
|
@ -86,7 +86,7 @@ func (s *metadataStore) remove(id contextdir) error {
|
||||||
return os.RemoveAll(contextDir)
|
return os.RemoveAll(contextDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *metadataStore) list() ([]ContextMetadata, error) {
|
func (s *metadataStore) list() ([]Metadata, error) {
|
||||||
ctxDirs, err := listRecursivelyMetadataDirs(s.root)
|
ctxDirs, err := listRecursivelyMetadataDirs(s.root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
@ -94,7 +94,7 @@ func (s *metadataStore) list() ([]ContextMetadata, error) {
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var res []ContextMetadata
|
var res []Metadata
|
||||||
for _, dir := range ctxDirs {
|
for _, dir := range ctxDirs {
|
||||||
c, err := s.get(contextdir(dir))
|
c, err := s.get(contextdir(dir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -18,26 +18,58 @@ import (
|
||||||
|
|
||||||
// Store provides a context store for easily remembering endpoints configuration
|
// Store provides a context store for easily remembering endpoints configuration
|
||||||
type Store interface {
|
type Store interface {
|
||||||
ListContexts() ([]ContextMetadata, error)
|
Reader
|
||||||
CreateOrUpdateContext(meta ContextMetadata) error
|
Lister
|
||||||
RemoveContext(name string) error
|
Writer
|
||||||
GetContextMetadata(name string) (ContextMetadata, error)
|
StorageInfoProvider
|
||||||
ResetContextTLSMaterial(name string, data *ContextTLSData) error
|
|
||||||
ResetContextEndpointTLSMaterial(contextName string, endpointName string, data *EndpointTLSData) error
|
|
||||||
ListContextTLSFiles(name string) (map[string]EndpointFiles, error)
|
|
||||||
GetContextTLSData(contextName, endpointName, fileName string) ([]byte, error)
|
|
||||||
GetContextStorageInfo(contextName string) ContextStorageInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContextMetadata contains metadata about a context and its endpoints
|
// Reader provides read-only (without list) access to context data
|
||||||
type ContextMetadata struct {
|
type Reader interface {
|
||||||
|
GetMetadata(name string) (Metadata, error)
|
||||||
|
ListTLSFiles(name string) (map[string]EndpointFiles, error)
|
||||||
|
GetTLSData(contextName, endpointName, fileName string) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lister provides listing of contexts
|
||||||
|
type Lister interface {
|
||||||
|
List() ([]Metadata, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReaderLister combines Reader and Lister interfaces
|
||||||
|
type ReaderLister interface {
|
||||||
|
Reader
|
||||||
|
Lister
|
||||||
|
}
|
||||||
|
|
||||||
|
// StorageInfoProvider provides more information about storage details of contexts
|
||||||
|
type StorageInfoProvider interface {
|
||||||
|
GetStorageInfo(contextName string) StorageInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writer provides write access to context data
|
||||||
|
type Writer interface {
|
||||||
|
CreateOrUpdate(meta Metadata) error
|
||||||
|
Remove(name string) error
|
||||||
|
ResetTLSMaterial(name string, data *ContextTLSData) error
|
||||||
|
ResetEndpointTLSMaterial(contextName string, endpointName string, data *EndpointTLSData) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReaderWriter combines Reader and Writer interfaces
|
||||||
|
type ReaderWriter interface {
|
||||||
|
Reader
|
||||||
|
Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadata contains metadata about a context and its endpoints
|
||||||
|
type Metadata struct {
|
||||||
Name string `json:",omitempty"`
|
Name string `json:",omitempty"`
|
||||||
Metadata interface{} `json:",omitempty"`
|
Metadata interface{} `json:",omitempty"`
|
||||||
Endpoints map[string]interface{} `json:",omitempty"`
|
Endpoints map[string]interface{} `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContextStorageInfo contains data about where a given context is stored
|
// StorageInfo contains data about where a given context is stored
|
||||||
type ContextStorageInfo struct {
|
type StorageInfo struct {
|
||||||
MetadataPath string
|
MetadataPath string
|
||||||
TLSPath string
|
TLSPath string
|
||||||
}
|
}
|
||||||
|
@ -74,15 +106,15 @@ type store struct {
|
||||||
tls *tlsStore
|
tls *tlsStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) ListContexts() ([]ContextMetadata, error) {
|
func (s *store) List() ([]Metadata, error) {
|
||||||
return s.meta.list()
|
return s.meta.list()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) CreateOrUpdateContext(meta ContextMetadata) error {
|
func (s *store) CreateOrUpdate(meta Metadata) error {
|
||||||
return s.meta.createOrUpdate(meta)
|
return s.meta.createOrUpdate(meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) RemoveContext(name string) error {
|
func (s *store) Remove(name string) error {
|
||||||
id := contextdirOf(name)
|
id := contextdirOf(name)
|
||||||
if err := s.meta.remove(id); err != nil {
|
if err := s.meta.remove(id); err != nil {
|
||||||
return patchErrContextName(err, name)
|
return patchErrContextName(err, name)
|
||||||
|
@ -90,13 +122,13 @@ func (s *store) RemoveContext(name string) error {
|
||||||
return patchErrContextName(s.tls.removeAllContextData(id), name)
|
return patchErrContextName(s.tls.removeAllContextData(id), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) GetContextMetadata(name string) (ContextMetadata, error) {
|
func (s *store) GetMetadata(name string) (Metadata, error) {
|
||||||
res, err := s.meta.get(contextdirOf(name))
|
res, err := s.meta.get(contextdirOf(name))
|
||||||
patchErrContextName(err, name)
|
patchErrContextName(err, name)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) ResetContextTLSMaterial(name string, data *ContextTLSData) error {
|
func (s *store) ResetTLSMaterial(name string, data *ContextTLSData) error {
|
||||||
id := contextdirOf(name)
|
id := contextdirOf(name)
|
||||||
if err := s.tls.removeAllContextData(id); err != nil {
|
if err := s.tls.removeAllContextData(id); err != nil {
|
||||||
return patchErrContextName(err, name)
|
return patchErrContextName(err, name)
|
||||||
|
@ -114,7 +146,7 @@ func (s *store) ResetContextTLSMaterial(name string, data *ContextTLSData) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) ResetContextEndpointTLSMaterial(contextName string, endpointName string, data *EndpointTLSData) error {
|
func (s *store) ResetEndpointTLSMaterial(contextName string, endpointName string, data *EndpointTLSData) error {
|
||||||
id := contextdirOf(contextName)
|
id := contextdirOf(contextName)
|
||||||
if err := s.tls.removeAllEndpointData(id, endpointName); err != nil {
|
if err := s.tls.removeAllEndpointData(id, endpointName); err != nil {
|
||||||
return patchErrContextName(err, contextName)
|
return patchErrContextName(err, contextName)
|
||||||
|
@ -130,19 +162,19 @@ func (s *store) ResetContextEndpointTLSMaterial(contextName string, endpointName
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) ListContextTLSFiles(name string) (map[string]EndpointFiles, error) {
|
func (s *store) ListTLSFiles(name string) (map[string]EndpointFiles, error) {
|
||||||
res, err := s.tls.listContextData(contextdirOf(name))
|
res, err := s.tls.listContextData(contextdirOf(name))
|
||||||
return res, patchErrContextName(err, name)
|
return res, patchErrContextName(err, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) GetContextTLSData(contextName, endpointName, fileName string) ([]byte, error) {
|
func (s *store) GetTLSData(contextName, endpointName, fileName string) ([]byte, error) {
|
||||||
res, err := s.tls.getData(contextdirOf(contextName), endpointName, fileName)
|
res, err := s.tls.getData(contextdirOf(contextName), endpointName, fileName)
|
||||||
return res, patchErrContextName(err, contextName)
|
return res, patchErrContextName(err, contextName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) GetContextStorageInfo(contextName string) ContextStorageInfo {
|
func (s *store) GetStorageInfo(contextName string) StorageInfo {
|
||||||
dir := contextdirOf(contextName)
|
dir := contextdirOf(contextName)
|
||||||
return ContextStorageInfo{
|
return StorageInfo{
|
||||||
MetadataPath: s.meta.contextDir(dir),
|
MetadataPath: s.meta.contextDir(dir),
|
||||||
TLSPath: s.tls.contextDir(dir),
|
TLSPath: s.tls.contextDir(dir),
|
||||||
}
|
}
|
||||||
|
@ -151,13 +183,13 @@ func (s *store) GetContextStorageInfo(contextName string) ContextStorageInfo {
|
||||||
// Export exports an existing namespace into an opaque data stream
|
// Export exports an existing namespace into an opaque data stream
|
||||||
// This stream is actually a tarball containing context metadata and TLS materials, but it does
|
// This stream is actually a tarball containing context metadata and TLS materials, but it does
|
||||||
// not map 1:1 the layout of the context store (don't try to restore it manually without calling store.Import)
|
// not map 1:1 the layout of the context store (don't try to restore it manually without calling store.Import)
|
||||||
func Export(name string, s Store) io.ReadCloser {
|
func Export(name string, s Reader) io.ReadCloser {
|
||||||
reader, writer := io.Pipe()
|
reader, writer := io.Pipe()
|
||||||
go func() {
|
go func() {
|
||||||
tw := tar.NewWriter(writer)
|
tw := tar.NewWriter(writer)
|
||||||
defer tw.Close()
|
defer tw.Close()
|
||||||
defer writer.Close()
|
defer writer.Close()
|
||||||
meta, err := s.GetContextMetadata(name)
|
meta, err := s.GetMetadata(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writer.CloseWithError(err)
|
writer.CloseWithError(err)
|
||||||
return
|
return
|
||||||
|
@ -179,7 +211,7 @@ func Export(name string, s Store) io.ReadCloser {
|
||||||
writer.CloseWithError(err)
|
writer.CloseWithError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tlsFiles, err := s.ListContextTLSFiles(name)
|
tlsFiles, err := s.ListTLSFiles(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writer.CloseWithError(err)
|
writer.CloseWithError(err)
|
||||||
return
|
return
|
||||||
|
@ -204,7 +236,7 @@ func Export(name string, s Store) io.ReadCloser {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, fileName := range endpointFiles {
|
for _, fileName := range endpointFiles {
|
||||||
data, err := s.GetContextTLSData(name, endpointName, fileName)
|
data, err := s.GetTLSData(name, endpointName, fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writer.CloseWithError(err)
|
writer.CloseWithError(err)
|
||||||
return
|
return
|
||||||
|
@ -228,7 +260,7 @@ func Export(name string, s Store) io.ReadCloser {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import imports an exported context into a store
|
// Import imports an exported context into a store
|
||||||
func Import(name string, s Store, reader io.Reader) error {
|
func Import(name string, s Writer, reader io.Reader) error {
|
||||||
tr := tar.NewReader(reader)
|
tr := tar.NewReader(reader)
|
||||||
tlsData := ContextTLSData{
|
tlsData := ContextTLSData{
|
||||||
Endpoints: map[string]EndpointTLSData{},
|
Endpoints: map[string]EndpointTLSData{},
|
||||||
|
@ -250,12 +282,12 @@ func Import(name string, s Store, reader io.Reader) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var meta ContextMetadata
|
var meta Metadata
|
||||||
if err := json.Unmarshal(data, &meta); err != nil {
|
if err := json.Unmarshal(data, &meta); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
meta.Name = name
|
meta.Name = name
|
||||||
if err := s.CreateOrUpdateContext(meta); err != nil {
|
if err := s.CreateOrUpdate(meta); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if strings.HasPrefix(hdr.Name, "tls/") {
|
} else if strings.HasPrefix(hdr.Name, "tls/") {
|
||||||
|
@ -278,7 +310,7 @@ func Import(name string, s Store, reader io.Reader) error {
|
||||||
tlsData.Endpoints[endpointName].Files[fileName] = data
|
tlsData.Endpoints[endpointName].Files[fileName] = data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s.ResetContextTLSMaterial(name, &tlsData)
|
return s.ResetTLSMaterial(name, &tlsData)
|
||||||
}
|
}
|
||||||
|
|
||||||
type setContextName interface {
|
type setContextName interface {
|
||||||
|
|
|
@ -42,15 +42,15 @@ func (data *TLSData) ToStoreTLSData() *store.EndpointTLSData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadTLSData loads TLS data from the store
|
// LoadTLSData loads TLS data from the store
|
||||||
func LoadTLSData(s store.Store, contextName, endpointName string) (*TLSData, error) {
|
func LoadTLSData(s store.Reader, contextName, endpointName string) (*TLSData, error) {
|
||||||
tlsFiles, err := s.ListContextTLSFiles(contextName)
|
tlsFiles, err := s.ListTLSFiles(contextName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to retrieve context tls files for context %q", contextName)
|
return nil, errors.Wrapf(err, "failed to retrieve context tls files for context %q", contextName)
|
||||||
}
|
}
|
||||||
if epTLSFiles, ok := tlsFiles[endpointName]; ok {
|
if epTLSFiles, ok := tlsFiles[endpointName]; ok {
|
||||||
var tlsData TLSData
|
var tlsData TLSData
|
||||||
for _, f := range epTLSFiles {
|
for _, f := range epTLSFiles {
|
||||||
data, err := s.GetContextTLSData(contextName, endpointName, f)
|
data, err := s.GetTLSData(contextName, endpointName, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to retrieve context tls data for file %q of context %q", f, contextName)
|
return nil, errors.Wrapf(err, "failed to retrieve context tls data for file %q of context %q", f, contextName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
Aanand Prasad <aanand.prasad@gmail.com>
|
Aanand Prasad <aanand.prasad@gmail.com>
|
||||||
Aaron Davidson <aaron@databricks.com>
|
Aaron Davidson <aaron@databricks.com>
|
||||||
Aaron Feng <aaron.feng@gmail.com>
|
Aaron Feng <aaron.feng@gmail.com>
|
||||||
|
Aaron Hnatiw <aaron@griddio.com>
|
||||||
Aaron Huslage <huslage@gmail.com>
|
Aaron Huslage <huslage@gmail.com>
|
||||||
Aaron L. Xu <liker.xu@foxmail.com>
|
Aaron L. Xu <liker.xu@foxmail.com>
|
||||||
Aaron Lehmann <aaron.lehmann@docker.com>
|
Aaron Lehmann <aaron.lehmann@docker.com>
|
||||||
|
@ -44,7 +45,7 @@ Ajey Charantimath <ajey.charantimath@gmail.com>
|
||||||
ajneu <ajneu@users.noreply.github.com>
|
ajneu <ajneu@users.noreply.github.com>
|
||||||
Akash Gupta <akagup@microsoft.com>
|
Akash Gupta <akagup@microsoft.com>
|
||||||
Akihiro Matsushima <amatsusbit@gmail.com>
|
Akihiro Matsushima <amatsusbit@gmail.com>
|
||||||
Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
|
Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
|
||||||
Akim Demaille <akim.demaille@docker.com>
|
Akim Demaille <akim.demaille@docker.com>
|
||||||
Akira Koyasu <mail@akirakoyasu.net>
|
Akira Koyasu <mail@akirakoyasu.net>
|
||||||
Akshay Karle <akshay.a.karle@gmail.com>
|
Akshay Karle <akshay.a.karle@gmail.com>
|
||||||
|
@ -81,6 +82,7 @@ Alexandre Garnier <zigarn@gmail.com>
|
||||||
Alexandre González <agonzalezro@gmail.com>
|
Alexandre González <agonzalezro@gmail.com>
|
||||||
Alexandre Jomin <alexandrejomin@gmail.com>
|
Alexandre Jomin <alexandrejomin@gmail.com>
|
||||||
Alexandru Sfirlogea <alexandru.sfirlogea@gmail.com>
|
Alexandru Sfirlogea <alexandru.sfirlogea@gmail.com>
|
||||||
|
Alexei Margasov <alexei38@yandex.ru>
|
||||||
Alexey Guskov <lexag@mail.ru>
|
Alexey Guskov <lexag@mail.ru>
|
||||||
Alexey Kotlyarov <alexey@infoxchange.net.au>
|
Alexey Kotlyarov <alexey@infoxchange.net.au>
|
||||||
Alexey Shamrin <shamrin@gmail.com>
|
Alexey Shamrin <shamrin@gmail.com>
|
||||||
|
@ -153,6 +155,7 @@ Andy Wilson <wilson.andrew.j+github@gmail.com>
|
||||||
Anes Hasicic <anes.hasicic@gmail.com>
|
Anes Hasicic <anes.hasicic@gmail.com>
|
||||||
Anil Belur <askb23@gmail.com>
|
Anil Belur <askb23@gmail.com>
|
||||||
Anil Madhavapeddy <anil@recoil.org>
|
Anil Madhavapeddy <anil@recoil.org>
|
||||||
|
Ankit Jain <ajatkj@yahoo.co.in>
|
||||||
Ankush Agarwal <ankushagarwal11@gmail.com>
|
Ankush Agarwal <ankushagarwal11@gmail.com>
|
||||||
Anonmily <michelle@michelleliu.io>
|
Anonmily <michelle@michelleliu.io>
|
||||||
Anran Qiao <anran.qiao@daocloud.io>
|
Anran Qiao <anran.qiao@daocloud.io>
|
||||||
|
@ -184,6 +187,7 @@ Asad Saeeduddin <masaeedu@gmail.com>
|
||||||
Asbjørn Enge <asbjorn@hanafjedle.net>
|
Asbjørn Enge <asbjorn@hanafjedle.net>
|
||||||
averagehuman <averagehuman@users.noreply.github.com>
|
averagehuman <averagehuman@users.noreply.github.com>
|
||||||
Avi Das <andas222@gmail.com>
|
Avi Das <andas222@gmail.com>
|
||||||
|
Avi Kivity <avi@scylladb.com>
|
||||||
Avi Miller <avi.miller@oracle.com>
|
Avi Miller <avi.miller@oracle.com>
|
||||||
Avi Vaid <avaid1996@gmail.com>
|
Avi Vaid <avaid1996@gmail.com>
|
||||||
ayoshitake <airandfingers@gmail.com>
|
ayoshitake <airandfingers@gmail.com>
|
||||||
|
@ -507,6 +511,7 @@ Dmitri Shuralyov <shurcooL@gmail.com>
|
||||||
Dmitry Demeshchuk <demeshchuk@gmail.com>
|
Dmitry Demeshchuk <demeshchuk@gmail.com>
|
||||||
Dmitry Gusev <dmitry.gusev@gmail.com>
|
Dmitry Gusev <dmitry.gusev@gmail.com>
|
||||||
Dmitry Kononenko <d@dm42.ru>
|
Dmitry Kononenko <d@dm42.ru>
|
||||||
|
Dmitry Sharshakov <d3dx12.xx@gmail.com>
|
||||||
Dmitry Shyshkin <dmitry@shyshkin.org.ua>
|
Dmitry Shyshkin <dmitry@shyshkin.org.ua>
|
||||||
Dmitry Smirnov <onlyjob@member.fsf.org>
|
Dmitry Smirnov <onlyjob@member.fsf.org>
|
||||||
Dmitry V. Krivenok <krivenok.dmitry@gmail.com>
|
Dmitry V. Krivenok <krivenok.dmitry@gmail.com>
|
||||||
|
@ -656,6 +661,7 @@ Frederik Loeffert <frederik@zitrusmedia.de>
|
||||||
Frederik Nordahl Jul Sabroe <frederikns@gmail.com>
|
Frederik Nordahl Jul Sabroe <frederikns@gmail.com>
|
||||||
Freek Kalter <freek@kalteronline.org>
|
Freek Kalter <freek@kalteronline.org>
|
||||||
Frieder Bluemle <frieder.bluemle@gmail.com>
|
Frieder Bluemle <frieder.bluemle@gmail.com>
|
||||||
|
Fu JinLin <withlin@yeah.net>
|
||||||
Félix Baylac-Jacqué <baylac.felix@gmail.com>
|
Félix Baylac-Jacqué <baylac.felix@gmail.com>
|
||||||
Félix Cantournet <felix.cantournet@cloudwatt.com>
|
Félix Cantournet <felix.cantournet@cloudwatt.com>
|
||||||
Gabe Rosenhouse <gabe@missionst.com>
|
Gabe Rosenhouse <gabe@missionst.com>
|
||||||
|
@ -688,6 +694,7 @@ Ghislain Bourgeois <ghislain.bourgeois@gmail.com>
|
||||||
Giampaolo Mancini <giampaolo@trampolineup.com>
|
Giampaolo Mancini <giampaolo@trampolineup.com>
|
||||||
Gianluca Borello <g.borello@gmail.com>
|
Gianluca Borello <g.borello@gmail.com>
|
||||||
Gildas Cuisinier <gildas.cuisinier@gcuisinier.net>
|
Gildas Cuisinier <gildas.cuisinier@gcuisinier.net>
|
||||||
|
Giovan Isa Musthofa <giovanism@outlook.co.id>
|
||||||
gissehel <public-devgit-dantus@gissehel.org>
|
gissehel <public-devgit-dantus@gissehel.org>
|
||||||
Giuseppe Mazzotta <gdm85@users.noreply.github.com>
|
Giuseppe Mazzotta <gdm85@users.noreply.github.com>
|
||||||
Gleb Fotengauer-Malinovskiy <glebfm@altlinux.org>
|
Gleb Fotengauer-Malinovskiy <glebfm@altlinux.org>
|
||||||
|
@ -898,6 +905,7 @@ Jimmy Cuadra <jimmy@jimmycuadra.com>
|
||||||
Jimmy Puckett <jimmy.puckett@spinen.com>
|
Jimmy Puckett <jimmy.puckett@spinen.com>
|
||||||
Jimmy Song <rootsongjc@gmail.com>
|
Jimmy Song <rootsongjc@gmail.com>
|
||||||
Jinsoo Park <cellpjs@gmail.com>
|
Jinsoo Park <cellpjs@gmail.com>
|
||||||
|
Jintao Zhang <zhangjintao9020@gmail.com>
|
||||||
Jiri Appl <jiria@microsoft.com>
|
Jiri Appl <jiria@microsoft.com>
|
||||||
Jiri Popelka <jpopelka@redhat.com>
|
Jiri Popelka <jpopelka@redhat.com>
|
||||||
Jiuyue Ma <majiuyue@huawei.com>
|
Jiuyue Ma <majiuyue@huawei.com>
|
||||||
|
@ -1079,6 +1087,7 @@ Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp>
|
||||||
Kunal Tyagi <tyagi.kunal@live.com>
|
Kunal Tyagi <tyagi.kunal@live.com>
|
||||||
Kyle Conroy <kyle.j.conroy@gmail.com>
|
Kyle Conroy <kyle.j.conroy@gmail.com>
|
||||||
Kyle Linden <linden.kyle@gmail.com>
|
Kyle Linden <linden.kyle@gmail.com>
|
||||||
|
Kyle Wuolle <kyle.wuolle@gmail.com>
|
||||||
kyu <leehk1227@gmail.com>
|
kyu <leehk1227@gmail.com>
|
||||||
Lachlan Coote <lcoote@vmware.com>
|
Lachlan Coote <lcoote@vmware.com>
|
||||||
Lai Jiangshan <jiangshanlai@gmail.com>
|
Lai Jiangshan <jiangshanlai@gmail.com>
|
||||||
|
@ -1146,6 +1155,7 @@ Luca-Bogdan Grigorescu <Luca-Bogdan Grigorescu>
|
||||||
Lucas Chan <lucas-github@lucaschan.com>
|
Lucas Chan <lucas-github@lucaschan.com>
|
||||||
Lucas Chi <lucas@teacherspayteachers.com>
|
Lucas Chi <lucas@teacherspayteachers.com>
|
||||||
Lucas Molas <lmolas@fundacionsadosky.org.ar>
|
Lucas Molas <lmolas@fundacionsadosky.org.ar>
|
||||||
|
Lucas Silvestre <lukas.silvestre@gmail.com>
|
||||||
Luciano Mores <leslau@gmail.com>
|
Luciano Mores <leslau@gmail.com>
|
||||||
Luis Martínez de Bartolomé Izquierdo <lmartinez@biicode.com>
|
Luis Martínez de Bartolomé Izquierdo <lmartinez@biicode.com>
|
||||||
Luiz Svoboda <luizek@gmail.com>
|
Luiz Svoboda <luizek@gmail.com>
|
||||||
|
@ -1255,6 +1265,7 @@ Maxim Kulkin <mkulkin@mirantis.com>
|
||||||
Maxim Treskin <zerthurd@gmail.com>
|
Maxim Treskin <zerthurd@gmail.com>
|
||||||
Maxime Petazzoni <max@signalfuse.com>
|
Maxime Petazzoni <max@signalfuse.com>
|
||||||
Maximiliano Maccanti <maccanti@amazon.com>
|
Maximiliano Maccanti <maccanti@amazon.com>
|
||||||
|
Maxwell <csuhp007@gmail.com>
|
||||||
Meaglith Ma <genedna@gmail.com>
|
Meaglith Ma <genedna@gmail.com>
|
||||||
meejah <meejah@meejah.ca>
|
meejah <meejah@meejah.ca>
|
||||||
Megan Kostick <mkostick@us.ibm.com>
|
Megan Kostick <mkostick@us.ibm.com>
|
||||||
|
@ -1519,6 +1530,7 @@ Quentin Brossard <qbrossard@gmail.com>
|
||||||
Quentin Perez <qperez@ocs.online.net>
|
Quentin Perez <qperez@ocs.online.net>
|
||||||
Quentin Tayssier <qtayssier@gmail.com>
|
Quentin Tayssier <qtayssier@gmail.com>
|
||||||
r0n22 <cameron.regan@gmail.com>
|
r0n22 <cameron.regan@gmail.com>
|
||||||
|
Radostin Stoyanov <rstoyanov1@gmail.com>
|
||||||
Rafal Jeczalik <rjeczalik@gmail.com>
|
Rafal Jeczalik <rjeczalik@gmail.com>
|
||||||
Rafe Colton <rafael.colton@gmail.com>
|
Rafe Colton <rafael.colton@gmail.com>
|
||||||
Raghavendra K T <raghavendra.kt@linux.vnet.ibm.com>
|
Raghavendra K T <raghavendra.kt@linux.vnet.ibm.com>
|
||||||
|
@ -1743,7 +1755,7 @@ Stefan Berger <stefanb@linux.vnet.ibm.com>
|
||||||
Stefan J. Wernli <swernli@microsoft.com>
|
Stefan J. Wernli <swernli@microsoft.com>
|
||||||
Stefan Praszalowicz <stefan@greplin.com>
|
Stefan Praszalowicz <stefan@greplin.com>
|
||||||
Stefan S. <tronicum@user.github.com>
|
Stefan S. <tronicum@user.github.com>
|
||||||
Stefan Scherer <scherer_stefan@icloud.com>
|
Stefan Scherer <stefan.scherer@docker.com>
|
||||||
Stefan Staudenmeyer <doerte@instana.com>
|
Stefan Staudenmeyer <doerte@instana.com>
|
||||||
Stefan Weil <sw@weilnetz.de>
|
Stefan Weil <sw@weilnetz.de>
|
||||||
Stephan Spindler <shutefan@gmail.com>
|
Stephan Spindler <shutefan@gmail.com>
|
||||||
|
@ -1976,6 +1988,7 @@ xamyzhao <x.amy.zhao@gmail.com>
|
||||||
Xian Chaobo <xianchaobo@huawei.com>
|
Xian Chaobo <xianchaobo@huawei.com>
|
||||||
Xianglin Gao <xlgao@zju.edu.cn>
|
Xianglin Gao <xlgao@zju.edu.cn>
|
||||||
Xianlu Bird <xianlubird@gmail.com>
|
Xianlu Bird <xianlubird@gmail.com>
|
||||||
|
Xiao YongBiao <xyb4638@gmail.com>
|
||||||
XiaoBing Jiang <s7v7nislands@gmail.com>
|
XiaoBing Jiang <s7v7nislands@gmail.com>
|
||||||
Xiaodong Zhang <a4012017@sina.com>
|
Xiaodong Zhang <a4012017@sina.com>
|
||||||
Xiaoxi He <xxhe@alauda.io>
|
Xiaoxi He <xxhe@alauda.io>
|
||||||
|
|
|
@ -3,7 +3,7 @@ package api // import "github.com/docker/docker/api"
|
||||||
// Common constants for daemon and client.
|
// Common constants for daemon and client.
|
||||||
const (
|
const (
|
||||||
// DefaultVersion of Current REST API
|
// DefaultVersion of Current REST API
|
||||||
DefaultVersion = "1.40"
|
DefaultVersion = "1.41"
|
||||||
|
|
||||||
// NoBaseImageSpecifier is the symbol used by the FROM
|
// NoBaseImageSpecifier is the symbol used by the FROM
|
||||||
// command to specify that no base image is to be used.
|
// command to specify that no base image is to be used.
|
||||||
|
|
2
vendor/github.com/docker/docker/api/types/container/container_changes.go
сгенерированный
поставляемый
2
vendor/github.com/docker/docker/api/types/container/container_changes.go
сгенерированный
поставляемый
|
@ -1,4 +1,4 @@
|
||||||
package container
|
package container // import "github.com/docker/docker/api/types/container"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// DO NOT EDIT THIS FILE
|
// DO NOT EDIT THIS FILE
|
||||||
|
|
2
vendor/github.com/docker/docker/api/types/container/container_create.go
сгенерированный
поставляемый
2
vendor/github.com/docker/docker/api/types/container/container_create.go
сгенерированный
поставляемый
|
@ -1,4 +1,4 @@
|
||||||
package container
|
package container // import "github.com/docker/docker/api/types/container"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// DO NOT EDIT THIS FILE
|
// DO NOT EDIT THIS FILE
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package container
|
package container // import "github.com/docker/docker/api/types/container"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// DO NOT EDIT THIS FILE
|
// DO NOT EDIT THIS FILE
|
||||||
|
|
2
vendor/github.com/docker/docker/api/types/container/container_update.go
сгенерированный
поставляемый
2
vendor/github.com/docker/docker/api/types/container/container_update.go
сгенерированный
поставляемый
|
@ -1,4 +1,4 @@
|
||||||
package container
|
package container // import "github.com/docker/docker/api/types/container"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// DO NOT EDIT THIS FILE
|
// DO NOT EDIT THIS FILE
|
||||||
|
|
2
vendor/github.com/docker/docker/api/types/container/container_wait.go
сгенерированный
поставляемый
2
vendor/github.com/docker/docker/api/types/container/container_wait.go
сгенерированный
поставляемый
|
@ -1,4 +1,4 @@
|
||||||
package container
|
package container // import "github.com/docker/docker/api/types/container"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// DO NOT EDIT THIS FILE
|
// DO NOT EDIT THIS FILE
|
||||||
|
|
|
@ -10,6 +10,29 @@ import (
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CgroupnsMode represents the cgroup namespace mode of the container
|
||||||
|
type CgroupnsMode string
|
||||||
|
|
||||||
|
// IsPrivate indicates whether the container uses its own private cgroup namespace
|
||||||
|
func (c CgroupnsMode) IsPrivate() bool {
|
||||||
|
return c == "private"
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsHost indicates whether the container shares the host's cgroup namespace
|
||||||
|
func (c CgroupnsMode) IsHost() bool {
|
||||||
|
return c == "host"
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty indicates whether the container cgroup namespace mode is unset
|
||||||
|
func (c CgroupnsMode) IsEmpty() bool {
|
||||||
|
return c == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid indicates whether the cgroup namespace mode is valid
|
||||||
|
func (c CgroupnsMode) Valid() bool {
|
||||||
|
return c.IsEmpty() || c.IsPrivate() || c.IsHost()
|
||||||
|
}
|
||||||
|
|
||||||
// Isolation represents the isolation technology of a container. The supported
|
// Isolation represents the isolation technology of a container. The supported
|
||||||
// values are platform specific
|
// values are platform specific
|
||||||
type Isolation string
|
type Isolation string
|
||||||
|
@ -338,7 +361,6 @@ type Resources struct {
|
||||||
Devices []DeviceMapping // List of devices to map inside the container
|
Devices []DeviceMapping // List of devices to map inside the container
|
||||||
DeviceCgroupRules []string // List of rule to be added to the device cgroup
|
DeviceCgroupRules []string // List of rule to be added to the device cgroup
|
||||||
DeviceRequests []DeviceRequest // List of device requests for device drivers
|
DeviceRequests []DeviceRequest // List of device requests for device drivers
|
||||||
DiskQuota int64 // Disk limit (in bytes)
|
|
||||||
KernelMemory int64 // Kernel memory limit (in bytes)
|
KernelMemory int64 // Kernel memory limit (in bytes)
|
||||||
KernelMemoryTCP int64 // Hard limit for kernel TCP buffer memory (in bytes)
|
KernelMemoryTCP int64 // Hard limit for kernel TCP buffer memory (in bytes)
|
||||||
MemoryReservation int64 // Memory soft limit (in bytes)
|
MemoryReservation int64 // Memory soft limit (in bytes)
|
||||||
|
@ -382,9 +404,10 @@ type HostConfig struct {
|
||||||
CapAdd strslice.StrSlice // List of kernel capabilities to add to the container
|
CapAdd strslice.StrSlice // List of kernel capabilities to add to the container
|
||||||
CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container
|
CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container
|
||||||
Capabilities []string `json:"Capabilities"` // List of kernel capabilities to be available for container (this overrides the default set)
|
Capabilities []string `json:"Capabilities"` // List of kernel capabilities to be available for container (this overrides the default set)
|
||||||
DNS []string `json:"Dns"` // List of DNS server to lookup
|
CgroupnsMode CgroupnsMode // Cgroup namespace mode to use for the container
|
||||||
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for
|
DNS []string `json:"Dns"` // List of DNS server to lookup
|
||||||
DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for
|
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for
|
||||||
|
DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for
|
||||||
ExtraHosts []string // List of extra hosts
|
ExtraHosts []string // List of extra hosts
|
||||||
GroupAdd []string // List of additional groups that the container process will run as
|
GroupAdd []string // List of additional groups that the container process will run as
|
||||||
IpcMode IpcMode // IPC namespace to use for the container
|
IpcMode IpcMode // IPC namespace to use for the container
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package image
|
package image // import "github.com/docker/docker/api/types/image"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// DO NOT EDIT THIS FILE
|
// DO NOT EDIT THIS FILE
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package volume
|
package volume // import "github.com/docker/docker/api/types/volume"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// DO NOT EDIT THIS FILE
|
// DO NOT EDIT THIS FILE
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package volume
|
package volume // import "github.com/docker/docker/api/types/volume"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// DO NOT EDIT THIS FILE
|
// DO NOT EDIT THIS FILE
|
||||||
|
|
|
@ -81,6 +81,15 @@ type Client struct {
|
||||||
customHTTPHeaders map[string]string
|
customHTTPHeaders map[string]string
|
||||||
// manualOverride is set to true when the version was set by users.
|
// manualOverride is set to true when the version was set by users.
|
||||||
manualOverride bool
|
manualOverride bool
|
||||||
|
|
||||||
|
// negotiateVersion indicates if the client should automatically negotiate
|
||||||
|
// the API version to use when making requests. API version negotiation is
|
||||||
|
// performed on the first request, after which negotiated is set to "true"
|
||||||
|
// so that subsequent requests do not re-negotiate.
|
||||||
|
negotiateVersion bool
|
||||||
|
|
||||||
|
// negotiated indicates that API version negotiation took place
|
||||||
|
negotiated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckRedirect specifies the policy for dealing with redirect responses:
|
// CheckRedirect specifies the policy for dealing with redirect responses:
|
||||||
|
@ -107,7 +116,7 @@ func CheckRedirect(req *http.Request, via []*http.Request) error {
|
||||||
// It won't send any version information if the version number is empty. It is
|
// It won't send any version information if the version number is empty. It is
|
||||||
// highly recommended that you set a version or your client may break if the
|
// highly recommended that you set a version or your client may break if the
|
||||||
// server is upgraded.
|
// server is upgraded.
|
||||||
func NewClientWithOpts(ops ...func(*Client) error) (*Client, error) {
|
func NewClientWithOpts(ops ...Opt) (*Client, error) {
|
||||||
client, err := defaultHTTPClient(DefaultDockerHost)
|
client, err := defaultHTTPClient(DefaultDockerHost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -169,8 +178,11 @@ func (cli *Client) Close() error {
|
||||||
|
|
||||||
// getAPIPath returns the versioned request path to call the api.
|
// getAPIPath returns the versioned request path to call the api.
|
||||||
// It appends the query parameters to the path if they are not empty.
|
// It appends the query parameters to the path if they are not empty.
|
||||||
func (cli *Client) getAPIPath(p string, query url.Values) string {
|
func (cli *Client) getAPIPath(ctx context.Context, p string, query url.Values) string {
|
||||||
var apiPath string
|
var apiPath string
|
||||||
|
if cli.negotiateVersion && !cli.negotiated {
|
||||||
|
cli.NegotiateAPIVersion(ctx)
|
||||||
|
}
|
||||||
if cli.version != "" {
|
if cli.version != "" {
|
||||||
v := strings.TrimPrefix(cli.version, "v")
|
v := strings.TrimPrefix(cli.version, "v")
|
||||||
apiPath = path.Join(cli.basePath, "/v"+v, p)
|
apiPath = path.Join(cli.basePath, "/v"+v, p)
|
||||||
|
@ -186,19 +198,31 @@ func (cli *Client) ClientVersion() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NegotiateAPIVersion queries the API and updates the version to match the
|
// NegotiateAPIVersion queries the API and updates the version to match the
|
||||||
// API version. Any errors are silently ignored.
|
// API version. Any errors are silently ignored. If a manual override is in place,
|
||||||
|
// either through the `DOCKER_API_VERSION` environment variable, or if the client
|
||||||
|
// was initialized with a fixed version (`opts.WithVersion(xx)`), no negotiation
|
||||||
|
// will be performed.
|
||||||
func (cli *Client) NegotiateAPIVersion(ctx context.Context) {
|
func (cli *Client) NegotiateAPIVersion(ctx context.Context) {
|
||||||
ping, _ := cli.Ping(ctx)
|
if !cli.manualOverride {
|
||||||
cli.NegotiateAPIVersionPing(ping)
|
ping, _ := cli.Ping(ctx)
|
||||||
|
cli.negotiateAPIVersionPing(ping)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NegotiateAPIVersionPing updates the client version to match the Ping.APIVersion
|
// NegotiateAPIVersionPing updates the client version to match the Ping.APIVersion
|
||||||
// if the ping version is less than the default version.
|
// if the ping version is less than the default version. If a manual override is
|
||||||
|
// in place, either through the `DOCKER_API_VERSION` environment variable, or if
|
||||||
|
// the client was initialized with a fixed version (`opts.WithVersion(xx)`), no
|
||||||
|
// negotiation is performed.
|
||||||
func (cli *Client) NegotiateAPIVersionPing(p types.Ping) {
|
func (cli *Client) NegotiateAPIVersionPing(p types.Ping) {
|
||||||
if cli.manualOverride {
|
if !cli.manualOverride {
|
||||||
return
|
cli.negotiateAPIVersionPing(p)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// negotiateAPIVersionPing queries the API and updates the version to match the
|
||||||
|
// API version. Any errors are silently ignored.
|
||||||
|
func (cli *Client) negotiateAPIVersionPing(p types.Ping) {
|
||||||
// try the latest version before versioning headers existed
|
// try the latest version before versioning headers existed
|
||||||
if p.APIVersion == "" {
|
if p.APIVersion == "" {
|
||||||
p.APIVersion = "1.24"
|
p.APIVersion = "1.24"
|
||||||
|
@ -213,6 +237,12 @@ func (cli *Client) NegotiateAPIVersionPing(p types.Ping) {
|
||||||
if versions.LessThan(p.APIVersion, cli.version) {
|
if versions.LessThan(p.APIVersion, cli.version) {
|
||||||
cli.version = p.APIVersion
|
cli.version = p.APIVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store the results, so that automatic API version negotiation (if enabled)
|
||||||
|
// won't be performed on the next request.
|
||||||
|
if cli.negotiateVersion {
|
||||||
|
cli.negotiated = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DaemonHost returns the host address used by the client
|
// DaemonHost returns the host address used by the client
|
||||||
|
|
|
@ -23,7 +23,7 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
|
||||||
return types.HijackedResponse{}, err
|
return types.HijackedResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
apiPath := cli.getAPIPath(path, query)
|
apiPath := cli.getAPIPath(ctx, path, query)
|
||||||
req, err := http.NewRequest("POST", apiPath, bodyEncoded)
|
req, err := http.NewRequest("POST", apiPath, bodyEncoded)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.HijackedResponse{}, err
|
return types.HijackedResponse{}, err
|
||||||
|
|
|
@ -6,12 +6,16 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/go-connections/sockets"
|
"github.com/docker/go-connections/sockets"
|
||||||
"github.com/docker/go-connections/tlsconfig"
|
"github.com/docker/go-connections/tlsconfig"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Opt is a configuration option to initialize a client
|
||||||
|
type Opt func(*Client) error
|
||||||
|
|
||||||
// FromEnv configures the client with values from environment variables.
|
// FromEnv configures the client with values from environment variables.
|
||||||
//
|
//
|
||||||
// Supported environment variables:
|
// Supported environment variables:
|
||||||
|
@ -55,13 +59,13 @@ func FromEnv(c *Client) error {
|
||||||
// WithDialer applies the dialer.DialContext to the client transport. This can be
|
// WithDialer applies the dialer.DialContext to the client transport. This can be
|
||||||
// used to set the Timeout and KeepAlive settings of the client.
|
// used to set the Timeout and KeepAlive settings of the client.
|
||||||
// Deprecated: use WithDialContext
|
// Deprecated: use WithDialContext
|
||||||
func WithDialer(dialer *net.Dialer) func(*Client) error {
|
func WithDialer(dialer *net.Dialer) Opt {
|
||||||
return WithDialContext(dialer.DialContext)
|
return WithDialContext(dialer.DialContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDialContext applies the dialer to the client transport. This can be
|
// WithDialContext applies the dialer to the client transport. This can be
|
||||||
// used to set the Timeout and KeepAlive settings of the client.
|
// used to set the Timeout and KeepAlive settings of the client.
|
||||||
func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) func(*Client) error {
|
func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) Opt {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if transport, ok := c.client.Transport.(*http.Transport); ok {
|
if transport, ok := c.client.Transport.(*http.Transport); ok {
|
||||||
transport.DialContext = dialContext
|
transport.DialContext = dialContext
|
||||||
|
@ -72,7 +76,7 @@ func WithDialContext(dialContext func(ctx context.Context, network, addr string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithHost overrides the client host with the specified one.
|
// WithHost overrides the client host with the specified one.
|
||||||
func WithHost(host string) func(*Client) error {
|
func WithHost(host string) Opt {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
hostURL, err := ParseHostURL(host)
|
hostURL, err := ParseHostURL(host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -90,7 +94,7 @@ func WithHost(host string) func(*Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithHTTPClient overrides the client http client with the specified one
|
// WithHTTPClient overrides the client http client with the specified one
|
||||||
func WithHTTPClient(client *http.Client) func(*Client) error {
|
func WithHTTPClient(client *http.Client) Opt {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
if client != nil {
|
if client != nil {
|
||||||
c.client = client
|
c.client = client
|
||||||
|
@ -99,8 +103,16 @@ func WithHTTPClient(client *http.Client) func(*Client) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithTimeout configures the time limit for requests made by the HTTP client
|
||||||
|
func WithTimeout(timeout time.Duration) Opt {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.client.Timeout = timeout
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithHTTPHeaders overrides the client default http headers
|
// WithHTTPHeaders overrides the client default http headers
|
||||||
func WithHTTPHeaders(headers map[string]string) func(*Client) error {
|
func WithHTTPHeaders(headers map[string]string) Opt {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.customHTTPHeaders = headers
|
c.customHTTPHeaders = headers
|
||||||
return nil
|
return nil
|
||||||
|
@ -108,7 +120,7 @@ func WithHTTPHeaders(headers map[string]string) func(*Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithScheme overrides the client scheme with the specified one
|
// WithScheme overrides the client scheme with the specified one
|
||||||
func WithScheme(scheme string) func(*Client) error {
|
func WithScheme(scheme string) Opt {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.scheme = scheme
|
c.scheme = scheme
|
||||||
return nil
|
return nil
|
||||||
|
@ -116,7 +128,7 @@ func WithScheme(scheme string) func(*Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithTLSClientConfig applies a tls config to the client transport.
|
// WithTLSClientConfig applies a tls config to the client transport.
|
||||||
func WithTLSClientConfig(cacertPath, certPath, keyPath string) func(*Client) error {
|
func WithTLSClientConfig(cacertPath, certPath, keyPath string) Opt {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
opts := tlsconfig.Options{
|
opts := tlsconfig.Options{
|
||||||
CAFile: cacertPath,
|
CAFile: cacertPath,
|
||||||
|
@ -136,11 +148,25 @@ func WithTLSClientConfig(cacertPath, certPath, keyPath string) func(*Client) err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithVersion overrides the client version with the specified one
|
// WithVersion overrides the client version with the specified one. If an empty
|
||||||
func WithVersion(version string) func(*Client) error {
|
// version is specified, the value will be ignored to allow version negotiation.
|
||||||
|
func WithVersion(version string) Opt {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.version = version
|
if version != "" {
|
||||||
c.manualOverride = true
|
c.version = version
|
||||||
|
c.manualOverride = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAPIVersionNegotiation enables automatic API version negotiation for the client.
|
||||||
|
// With this option enabled, the client automatically negotiates the API version
|
||||||
|
// to use when making requests. API version negotiation is performed on the first
|
||||||
|
// request; subsequent requests will not re-negotiate.
|
||||||
|
func WithAPIVersionNegotiation() Opt {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.negotiateVersion = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
|
||||||
// Server handled the request, so parse the response
|
// Server handled the request, so parse the response
|
||||||
return parsePingResponse(cli, serverResp)
|
return parsePingResponse(cli, serverResp)
|
||||||
}
|
}
|
||||||
|
} else if IsErrConnectionFailed(err) {
|
||||||
|
return ping, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err = cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil)
|
req, err = cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil)
|
||||||
|
|
|
@ -115,7 +115,7 @@ func (cli *Client) buildRequest(method, path string, body io.Reader, headers hea
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers headers) (serverResponse, error) {
|
func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers headers) (serverResponse, error) {
|
||||||
req, err := cli.buildRequest(method, cli.getAPIPath(path, query), body, headers)
|
req, err := cli.buildRequest(method, cli.getAPIPath(ctx, path, query), body, headers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return serverResponse{}, err
|
return serverResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,13 +102,13 @@ func Mounted(mountpoint string) (bool, error) {
|
||||||
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
|
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
|
||||||
// flags.go for supported option flags.
|
// flags.go for supported option flags.
|
||||||
func Mount(device, target, mType, options string) error {
|
func Mount(device, target, mType, options string) error {
|
||||||
flag, _ := parseOptions(options)
|
flag, data := parseOptions(options)
|
||||||
if flag&REMOUNT != REMOUNT {
|
if flag&REMOUNT != REMOUNT {
|
||||||
if mounted, err := Mounted(target); err != nil || mounted {
|
if mounted, err := Mounted(target); err != nil || mounted {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ForceMount(device, target, mType, options)
|
return mount(device, target, mType, uintptr(flag), data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForceMount will mount a filesystem according to the specified configuration,
|
// ForceMount will mount a filesystem according to the specified configuration,
|
||||||
|
|
|
@ -3,49 +3,49 @@ package mount // import "github.com/docker/docker/pkg/mount"
|
||||||
// MakeShared ensures a mounted filesystem has the SHARED mount option enabled.
|
// MakeShared ensures a mounted filesystem has the SHARED mount option enabled.
|
||||||
// See the supported options in flags.go for further reference.
|
// See the supported options in flags.go for further reference.
|
||||||
func MakeShared(mountPoint string) error {
|
func MakeShared(mountPoint string) error {
|
||||||
return ensureMountedAs(mountPoint, "shared")
|
return ensureMountedAs(mountPoint, SHARED)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled.
|
// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled.
|
||||||
// See the supported options in flags.go for further reference.
|
// See the supported options in flags.go for further reference.
|
||||||
func MakeRShared(mountPoint string) error {
|
func MakeRShared(mountPoint string) error {
|
||||||
return ensureMountedAs(mountPoint, "rshared")
|
return ensureMountedAs(mountPoint, RSHARED)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled.
|
// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled.
|
||||||
// See the supported options in flags.go for further reference.
|
// See the supported options in flags.go for further reference.
|
||||||
func MakePrivate(mountPoint string) error {
|
func MakePrivate(mountPoint string) error {
|
||||||
return ensureMountedAs(mountPoint, "private")
|
return ensureMountedAs(mountPoint, PRIVATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option
|
// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option
|
||||||
// enabled. See the supported options in flags.go for further reference.
|
// enabled. See the supported options in flags.go for further reference.
|
||||||
func MakeRPrivate(mountPoint string) error {
|
func MakeRPrivate(mountPoint string) error {
|
||||||
return ensureMountedAs(mountPoint, "rprivate")
|
return ensureMountedAs(mountPoint, RPRIVATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled.
|
// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled.
|
||||||
// See the supported options in flags.go for further reference.
|
// See the supported options in flags.go for further reference.
|
||||||
func MakeSlave(mountPoint string) error {
|
func MakeSlave(mountPoint string) error {
|
||||||
return ensureMountedAs(mountPoint, "slave")
|
return ensureMountedAs(mountPoint, SLAVE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled.
|
// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled.
|
||||||
// See the supported options in flags.go for further reference.
|
// See the supported options in flags.go for further reference.
|
||||||
func MakeRSlave(mountPoint string) error {
|
func MakeRSlave(mountPoint string) error {
|
||||||
return ensureMountedAs(mountPoint, "rslave")
|
return ensureMountedAs(mountPoint, RSLAVE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option
|
// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option
|
||||||
// enabled. See the supported options in flags.go for further reference.
|
// enabled. See the supported options in flags.go for further reference.
|
||||||
func MakeUnbindable(mountPoint string) error {
|
func MakeUnbindable(mountPoint string) error {
|
||||||
return ensureMountedAs(mountPoint, "unbindable")
|
return ensureMountedAs(mountPoint, UNBINDABLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount
|
// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount
|
||||||
// option enabled. See the supported options in flags.go for further reference.
|
// option enabled. See the supported options in flags.go for further reference.
|
||||||
func MakeRUnbindable(mountPoint string) error {
|
func MakeRUnbindable(mountPoint string) error {
|
||||||
return ensureMountedAs(mountPoint, "runbindable")
|
return ensureMountedAs(mountPoint, RUNBINDABLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeMount ensures that the file or directory given is a mount point,
|
// MakeMount ensures that the file or directory given is a mount point,
|
||||||
|
@ -59,13 +59,13 @@ func MakeMount(mnt string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return Mount(mnt, mnt, "none", "bind")
|
return mount(mnt, mnt, "none", uintptr(BIND), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureMountedAs(mountPoint, options string) error {
|
func ensureMountedAs(mnt string, flags int) error {
|
||||||
if err := MakeMount(mountPoint); err != nil {
|
if err := MakeMount(mnt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ForceMount("", mountPoint, "none", options)
|
return mount("", mnt, "none", uintptr(flags), "")
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package system // import "github.com/docker/docker/pkg/system"
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/osversion"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,10 +16,10 @@ var (
|
||||||
containerdRuntimeSupported = false
|
containerdRuntimeSupported = false
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitLCOW sets whether LCOW is supported or not
|
// InitLCOW sets whether LCOW is supported or not. Requires RS5+
|
||||||
func InitLCOW(experimental bool) {
|
func InitLCOW(experimental bool) {
|
||||||
v := GetOSVersion()
|
v := GetOSVersion()
|
||||||
if experimental && v.Build >= 16299 {
|
if experimental && v.Build >= osversion.RS5 {
|
||||||
lcowSupported = true
|
lcowSupported = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,457 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2012 Google Inc. All Rights Reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package shlex
|
|
||||||
|
|
||||||
/*
|
|
||||||
Package shlex implements a simple lexer which splits input in to tokens using
|
|
||||||
shell-style rules for quoting and commenting.
|
|
||||||
*/
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
A TokenType is a top-level token; a word, space, comment, unknown.
|
|
||||||
*/
|
|
||||||
type TokenType int
|
|
||||||
|
|
||||||
/*
|
|
||||||
A RuneTokenType is the type of a UTF-8 character; a character, quote, space, escape.
|
|
||||||
*/
|
|
||||||
type RuneTokenType int
|
|
||||||
|
|
||||||
type lexerState int
|
|
||||||
|
|
||||||
type Token struct {
|
|
||||||
tokenType TokenType
|
|
||||||
value string
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Two tokens are equal if both their types and values are equal. A nil token can
|
|
||||||
never equal another token.
|
|
||||||
*/
|
|
||||||
func (a *Token) Equal(b *Token) bool {
|
|
||||||
if a == nil || b == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if a.tokenType != b.tokenType {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return a.value == b.value
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
RUNE_CHAR string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._-,/@$*()+=><:;&^%~|!?[]{}"
|
|
||||||
RUNE_SPACE string = " \t\r\n"
|
|
||||||
RUNE_ESCAPING_QUOTE string = "\""
|
|
||||||
RUNE_NONESCAPING_QUOTE string = "'"
|
|
||||||
RUNE_ESCAPE = "\\"
|
|
||||||
RUNE_COMMENT = "#"
|
|
||||||
|
|
||||||
RUNETOKEN_UNKNOWN RuneTokenType = 0
|
|
||||||
RUNETOKEN_CHAR RuneTokenType = 1
|
|
||||||
RUNETOKEN_SPACE RuneTokenType = 2
|
|
||||||
RUNETOKEN_ESCAPING_QUOTE RuneTokenType = 3
|
|
||||||
RUNETOKEN_NONESCAPING_QUOTE RuneTokenType = 4
|
|
||||||
RUNETOKEN_ESCAPE RuneTokenType = 5
|
|
||||||
RUNETOKEN_COMMENT RuneTokenType = 6
|
|
||||||
RUNETOKEN_EOF RuneTokenType = 7
|
|
||||||
|
|
||||||
TOKEN_UNKNOWN TokenType = 0
|
|
||||||
TOKEN_WORD TokenType = 1
|
|
||||||
TOKEN_SPACE TokenType = 2
|
|
||||||
TOKEN_COMMENT TokenType = 3
|
|
||||||
|
|
||||||
STATE_START lexerState = 0
|
|
||||||
STATE_INWORD lexerState = 1
|
|
||||||
STATE_ESCAPING lexerState = 2
|
|
||||||
STATE_ESCAPING_QUOTED lexerState = 3
|
|
||||||
STATE_QUOTED_ESCAPING lexerState = 4
|
|
||||||
STATE_QUOTED lexerState = 5
|
|
||||||
STATE_COMMENT lexerState = 6
|
|
||||||
|
|
||||||
INITIAL_TOKEN_CAPACITY int = 100
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
A type for classifying characters. This allows for different sorts of
|
|
||||||
classifiers - those accepting extended non-ascii chars, or strict posix
|
|
||||||
compatibility, for example.
|
|
||||||
*/
|
|
||||||
type TokenClassifier struct {
|
|
||||||
typeMap map[int32]RuneTokenType
|
|
||||||
}
|
|
||||||
|
|
||||||
func addRuneClass(typeMap *map[int32]RuneTokenType, runes string, tokenType RuneTokenType) {
|
|
||||||
for _, rune := range runes {
|
|
||||||
(*typeMap)[int32(rune)] = tokenType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Create a new classifier for basic ASCII characters.
|
|
||||||
*/
|
|
||||||
func NewDefaultClassifier() *TokenClassifier {
|
|
||||||
typeMap := map[int32]RuneTokenType{}
|
|
||||||
addRuneClass(&typeMap, RUNE_CHAR, RUNETOKEN_CHAR)
|
|
||||||
addRuneClass(&typeMap, RUNE_SPACE, RUNETOKEN_SPACE)
|
|
||||||
addRuneClass(&typeMap, RUNE_ESCAPING_QUOTE, RUNETOKEN_ESCAPING_QUOTE)
|
|
||||||
addRuneClass(&typeMap, RUNE_NONESCAPING_QUOTE, RUNETOKEN_NONESCAPING_QUOTE)
|
|
||||||
addRuneClass(&typeMap, RUNE_ESCAPE, RUNETOKEN_ESCAPE)
|
|
||||||
addRuneClass(&typeMap, RUNE_COMMENT, RUNETOKEN_COMMENT)
|
|
||||||
return &TokenClassifier{
|
|
||||||
typeMap: typeMap}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (classifier *TokenClassifier) ClassifyRune(rune int32) RuneTokenType {
|
|
||||||
return classifier.typeMap[rune]
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
A type for turning an input stream in to a sequence of strings. Whitespace and
|
|
||||||
comments are skipped.
|
|
||||||
*/
|
|
||||||
type Lexer struct {
|
|
||||||
tokenizer *Tokenizer
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Create a new lexer.
|
|
||||||
*/
|
|
||||||
func NewLexer(r io.Reader) (*Lexer, error) {
|
|
||||||
|
|
||||||
tokenizer, err := NewTokenizer(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
lexer := &Lexer{tokenizer: tokenizer}
|
|
||||||
return lexer, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Return the next word, and an error value. If there are no more words, the error
|
|
||||||
will be io.EOF.
|
|
||||||
*/
|
|
||||||
func (l *Lexer) NextWord() (string, error) {
|
|
||||||
var token *Token
|
|
||||||
var err error
|
|
||||||
for {
|
|
||||||
token, err = l.tokenizer.NextToken()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
switch token.tokenType {
|
|
||||||
case TOKEN_WORD:
|
|
||||||
{
|
|
||||||
return token.value, nil
|
|
||||||
}
|
|
||||||
case TOKEN_COMMENT:
|
|
||||||
{
|
|
||||||
// skip comments
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
panic(fmt.Sprintf("Unknown token type: %v", token.tokenType))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
A type for turning an input stream in to a sequence of typed tokens.
|
|
||||||
*/
|
|
||||||
type Tokenizer struct {
|
|
||||||
input *bufio.Reader
|
|
||||||
classifier *TokenClassifier
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Create a new tokenizer.
|
|
||||||
*/
|
|
||||||
func NewTokenizer(r io.Reader) (*Tokenizer, error) {
|
|
||||||
input := bufio.NewReader(r)
|
|
||||||
classifier := NewDefaultClassifier()
|
|
||||||
tokenizer := &Tokenizer{
|
|
||||||
input: input,
|
|
||||||
classifier: classifier}
|
|
||||||
return tokenizer, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Scan the stream for the next token.
|
|
||||||
|
|
||||||
This uses an internal state machine. It will panic if it encounters a character
|
|
||||||
which it does not know how to handle.
|
|
||||||
*/
|
|
||||||
func (t *Tokenizer) scanStream() (*Token, error) {
|
|
||||||
state := STATE_START
|
|
||||||
var tokenType TokenType
|
|
||||||
value := make([]int32, 0, INITIAL_TOKEN_CAPACITY)
|
|
||||||
var (
|
|
||||||
nextRune int32
|
|
||||||
nextRuneType RuneTokenType
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
SCAN:
|
|
||||||
for {
|
|
||||||
nextRune, _, err = t.input.ReadRune()
|
|
||||||
nextRuneType = t.classifier.ClassifyRune(nextRune)
|
|
||||||
if err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
nextRuneType = RUNETOKEN_EOF
|
|
||||||
err = nil
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch state {
|
|
||||||
case STATE_START: // no runes read yet
|
|
||||||
{
|
|
||||||
switch nextRuneType {
|
|
||||||
case RUNETOKEN_EOF:
|
|
||||||
{
|
|
||||||
return nil, io.EOF
|
|
||||||
}
|
|
||||||
case RUNETOKEN_CHAR:
|
|
||||||
{
|
|
||||||
tokenType = TOKEN_WORD
|
|
||||||
value = append(value, nextRune)
|
|
||||||
state = STATE_INWORD
|
|
||||||
}
|
|
||||||
case RUNETOKEN_SPACE:
|
|
||||||
{
|
|
||||||
}
|
|
||||||
case RUNETOKEN_ESCAPING_QUOTE:
|
|
||||||
{
|
|
||||||
tokenType = TOKEN_WORD
|
|
||||||
state = STATE_QUOTED_ESCAPING
|
|
||||||
}
|
|
||||||
case RUNETOKEN_NONESCAPING_QUOTE:
|
|
||||||
{
|
|
||||||
tokenType = TOKEN_WORD
|
|
||||||
state = STATE_QUOTED
|
|
||||||
}
|
|
||||||
case RUNETOKEN_ESCAPE:
|
|
||||||
{
|
|
||||||
tokenType = TOKEN_WORD
|
|
||||||
state = STATE_ESCAPING
|
|
||||||
}
|
|
||||||
case RUNETOKEN_COMMENT:
|
|
||||||
{
|
|
||||||
tokenType = TOKEN_COMMENT
|
|
||||||
state = STATE_COMMENT
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
return nil, errors.New(fmt.Sprintf("Unknown rune: %v", nextRune))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case STATE_INWORD: // in a regular word
|
|
||||||
{
|
|
||||||
switch nextRuneType {
|
|
||||||
case RUNETOKEN_EOF:
|
|
||||||
{
|
|
||||||
break SCAN
|
|
||||||
}
|
|
||||||
case RUNETOKEN_CHAR, RUNETOKEN_COMMENT:
|
|
||||||
{
|
|
||||||
value = append(value, nextRune)
|
|
||||||
}
|
|
||||||
case RUNETOKEN_SPACE:
|
|
||||||
{
|
|
||||||
t.input.UnreadRune()
|
|
||||||
break SCAN
|
|
||||||
}
|
|
||||||
case RUNETOKEN_ESCAPING_QUOTE:
|
|
||||||
{
|
|
||||||
state = STATE_QUOTED_ESCAPING
|
|
||||||
}
|
|
||||||
case RUNETOKEN_NONESCAPING_QUOTE:
|
|
||||||
{
|
|
||||||
state = STATE_QUOTED
|
|
||||||
}
|
|
||||||
case RUNETOKEN_ESCAPE:
|
|
||||||
{
|
|
||||||
state = STATE_ESCAPING
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case STATE_ESCAPING: // the next rune after an escape character
|
|
||||||
{
|
|
||||||
switch nextRuneType {
|
|
||||||
case RUNETOKEN_EOF:
|
|
||||||
{
|
|
||||||
err = errors.New("EOF found after escape character")
|
|
||||||
break SCAN
|
|
||||||
}
|
|
||||||
case RUNETOKEN_CHAR, RUNETOKEN_SPACE, RUNETOKEN_ESCAPING_QUOTE, RUNETOKEN_NONESCAPING_QUOTE, RUNETOKEN_ESCAPE, RUNETOKEN_COMMENT:
|
|
||||||
{
|
|
||||||
state = STATE_INWORD
|
|
||||||
value = append(value, nextRune)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case STATE_ESCAPING_QUOTED: // the next rune after an escape character, in double quotes
|
|
||||||
{
|
|
||||||
switch nextRuneType {
|
|
||||||
case RUNETOKEN_EOF:
|
|
||||||
{
|
|
||||||
err = errors.New("EOF found after escape character")
|
|
||||||
break SCAN
|
|
||||||
}
|
|
||||||
case RUNETOKEN_CHAR, RUNETOKEN_SPACE, RUNETOKEN_ESCAPING_QUOTE, RUNETOKEN_NONESCAPING_QUOTE, RUNETOKEN_ESCAPE, RUNETOKEN_COMMENT:
|
|
||||||
{
|
|
||||||
state = STATE_QUOTED_ESCAPING
|
|
||||||
value = append(value, nextRune)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case STATE_QUOTED_ESCAPING: // in escaping double quotes
|
|
||||||
{
|
|
||||||
switch nextRuneType {
|
|
||||||
case RUNETOKEN_EOF:
|
|
||||||
{
|
|
||||||
err = errors.New("EOF found when expecting closing quote.")
|
|
||||||
break SCAN
|
|
||||||
}
|
|
||||||
case RUNETOKEN_CHAR, RUNETOKEN_UNKNOWN, RUNETOKEN_SPACE, RUNETOKEN_NONESCAPING_QUOTE, RUNETOKEN_COMMENT:
|
|
||||||
{
|
|
||||||
value = append(value, nextRune)
|
|
||||||
}
|
|
||||||
case RUNETOKEN_ESCAPING_QUOTE:
|
|
||||||
{
|
|
||||||
state = STATE_INWORD
|
|
||||||
}
|
|
||||||
case RUNETOKEN_ESCAPE:
|
|
||||||
{
|
|
||||||
state = STATE_ESCAPING_QUOTED
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case STATE_QUOTED: // in non-escaping single quotes
|
|
||||||
{
|
|
||||||
switch nextRuneType {
|
|
||||||
case RUNETOKEN_EOF:
|
|
||||||
{
|
|
||||||
err = errors.New("EOF found when expecting closing quote.")
|
|
||||||
break SCAN
|
|
||||||
}
|
|
||||||
case RUNETOKEN_CHAR, RUNETOKEN_UNKNOWN, RUNETOKEN_SPACE, RUNETOKEN_ESCAPING_QUOTE, RUNETOKEN_ESCAPE, RUNETOKEN_COMMENT:
|
|
||||||
{
|
|
||||||
value = append(value, nextRune)
|
|
||||||
}
|
|
||||||
case RUNETOKEN_NONESCAPING_QUOTE:
|
|
||||||
{
|
|
||||||
state = STATE_INWORD
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case STATE_COMMENT:
|
|
||||||
{
|
|
||||||
switch nextRuneType {
|
|
||||||
case RUNETOKEN_EOF:
|
|
||||||
{
|
|
||||||
break SCAN
|
|
||||||
}
|
|
||||||
case RUNETOKEN_CHAR, RUNETOKEN_UNKNOWN, RUNETOKEN_ESCAPING_QUOTE, RUNETOKEN_ESCAPE, RUNETOKEN_COMMENT, RUNETOKEN_NONESCAPING_QUOTE:
|
|
||||||
{
|
|
||||||
value = append(value, nextRune)
|
|
||||||
}
|
|
||||||
case RUNETOKEN_SPACE:
|
|
||||||
{
|
|
||||||
if nextRune == '\n' {
|
|
||||||
state = STATE_START
|
|
||||||
break SCAN
|
|
||||||
} else {
|
|
||||||
value = append(value, nextRune)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
return nil, errors.New(fmt.Sprintf("Uknown rune: %v", nextRune))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
panic(fmt.Sprintf("Unexpected state: %v", state))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
token := &Token{
|
|
||||||
tokenType: tokenType,
|
|
||||||
value: string(value)}
|
|
||||||
return token, err
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Return the next token in the stream, and an error value. If there are no more
|
|
||||||
tokens available, the error value will be io.EOF.
|
|
||||||
*/
|
|
||||||
func (t *Tokenizer) NextToken() (*Token, error) {
|
|
||||||
return t.scanStream()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Split a string in to a slice of strings, based upon shell-style rules for
|
|
||||||
quoting, escaping, and spaces.
|
|
||||||
*/
|
|
||||||
func Split(s string) ([]string, error) {
|
|
||||||
l, err := NewLexer(strings.NewReader(s))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
subStrings := []string{}
|
|
||||||
for {
|
|
||||||
word, err := l.NextWord()
|
|
||||||
if err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
return subStrings, nil
|
|
||||||
}
|
|
||||||
return subStrings, err
|
|
||||||
}
|
|
||||||
subStrings = append(subStrings, word)
|
|
||||||
}
|
|
||||||
return subStrings, nil
|
|
||||||
}
|
|
0
vendor/github.com/flynn-archive/go-shlex/COPYING → vendor/github.com/google/shlex/COPYING
сгенерированный
поставляемый
0
vendor/github.com/flynn-archive/go-shlex/COPYING → vendor/github.com/google/shlex/COPYING
сгенерированный
поставляемый
|
@ -0,0 +1,416 @@
|
||||||
|
/*
|
||||||
|
Copyright 2012 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package shlex implements a simple lexer which splits input in to tokens using
|
||||||
|
shell-style rules for quoting and commenting.
|
||||||
|
|
||||||
|
The basic use case uses the default ASCII lexer to split a string into sub-strings:
|
||||||
|
|
||||||
|
shlex.Split("one \"two three\" four") -> []string{"one", "two three", "four"}
|
||||||
|
|
||||||
|
To process a stream of strings:
|
||||||
|
|
||||||
|
l := NewLexer(os.Stdin)
|
||||||
|
for ; token, err := l.Next(); err != nil {
|
||||||
|
// process token
|
||||||
|
}
|
||||||
|
|
||||||
|
To access the raw token stream (which includes tokens for comments):
|
||||||
|
|
||||||
|
t := NewTokenizer(os.Stdin)
|
||||||
|
for ; token, err := t.Next(); err != nil {
|
||||||
|
// process token
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
package shlex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TokenType is a top-level token classification: A word, space, comment, unknown.
|
||||||
|
type TokenType int
|
||||||
|
|
||||||
|
// runeTokenClass is the type of a UTF-8 character classification: A quote, space, escape.
|
||||||
|
type runeTokenClass int
|
||||||
|
|
||||||
|
// the internal state used by the lexer state machine
|
||||||
|
type lexerState int
|
||||||
|
|
||||||
|
// Token is a (type, value) pair representing a lexographical token.
|
||||||
|
type Token struct {
|
||||||
|
tokenType TokenType
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal reports whether tokens a, and b, are equal.
|
||||||
|
// Two tokens are equal if both their types and values are equal. A nil token can
|
||||||
|
// never be equal to another token.
|
||||||
|
func (a *Token) Equal(b *Token) bool {
|
||||||
|
if a == nil || b == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if a.tokenType != b.tokenType {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return a.value == b.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Named classes of UTF-8 runes
|
||||||
|
const (
|
||||||
|
spaceRunes = " \t\r\n"
|
||||||
|
escapingQuoteRunes = `"`
|
||||||
|
nonEscapingQuoteRunes = "'"
|
||||||
|
escapeRunes = `\`
|
||||||
|
commentRunes = "#"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Classes of rune token
|
||||||
|
const (
|
||||||
|
unknownRuneClass runeTokenClass = iota
|
||||||
|
spaceRuneClass
|
||||||
|
escapingQuoteRuneClass
|
||||||
|
nonEscapingQuoteRuneClass
|
||||||
|
escapeRuneClass
|
||||||
|
commentRuneClass
|
||||||
|
eofRuneClass
|
||||||
|
)
|
||||||
|
|
||||||
|
// Classes of lexographic token
|
||||||
|
const (
|
||||||
|
UnknownToken TokenType = iota
|
||||||
|
WordToken
|
||||||
|
SpaceToken
|
||||||
|
CommentToken
|
||||||
|
)
|
||||||
|
|
||||||
|
// Lexer state machine states
|
||||||
|
const (
|
||||||
|
startState lexerState = iota // no runes have been seen
|
||||||
|
inWordState // processing regular runes in a word
|
||||||
|
escapingState // we have just consumed an escape rune; the next rune is literal
|
||||||
|
escapingQuotedState // we have just consumed an escape rune within a quoted string
|
||||||
|
quotingEscapingState // we are within a quoted string that supports escaping ("...")
|
||||||
|
quotingState // we are within a string that does not support escaping ('...')
|
||||||
|
commentState // we are within a comment (everything following an unquoted or unescaped #
|
||||||
|
)
|
||||||
|
|
||||||
|
// tokenClassifier is used for classifying rune characters.
|
||||||
|
type tokenClassifier map[rune]runeTokenClass
|
||||||
|
|
||||||
|
func (typeMap tokenClassifier) addRuneClass(runes string, tokenType runeTokenClass) {
|
||||||
|
for _, runeChar := range runes {
|
||||||
|
typeMap[runeChar] = tokenType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newDefaultClassifier creates a new classifier for ASCII characters.
|
||||||
|
func newDefaultClassifier() tokenClassifier {
|
||||||
|
t := tokenClassifier{}
|
||||||
|
t.addRuneClass(spaceRunes, spaceRuneClass)
|
||||||
|
t.addRuneClass(escapingQuoteRunes, escapingQuoteRuneClass)
|
||||||
|
t.addRuneClass(nonEscapingQuoteRunes, nonEscapingQuoteRuneClass)
|
||||||
|
t.addRuneClass(escapeRunes, escapeRuneClass)
|
||||||
|
t.addRuneClass(commentRunes, commentRuneClass)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClassifyRune classifiees a rune
|
||||||
|
func (t tokenClassifier) ClassifyRune(runeVal rune) runeTokenClass {
|
||||||
|
return t[runeVal]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lexer turns an input stream into a sequence of tokens. Whitespace and comments are skipped.
|
||||||
|
type Lexer Tokenizer
|
||||||
|
|
||||||
|
// NewLexer creates a new lexer from an input stream.
|
||||||
|
func NewLexer(r io.Reader) *Lexer {
|
||||||
|
|
||||||
|
return (*Lexer)(NewTokenizer(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the next word, or an error. If there are no more words,
|
||||||
|
// the error will be io.EOF.
|
||||||
|
func (l *Lexer) Next() (string, error) {
|
||||||
|
for {
|
||||||
|
token, err := (*Tokenizer)(l).Next()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
switch token.tokenType {
|
||||||
|
case WordToken:
|
||||||
|
return token.value, nil
|
||||||
|
case CommentToken:
|
||||||
|
// skip comments
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("Unknown token type: %v", token.tokenType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tokenizer turns an input stream into a sequence of typed tokens
|
||||||
|
type Tokenizer struct {
|
||||||
|
input bufio.Reader
|
||||||
|
classifier tokenClassifier
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTokenizer creates a new tokenizer from an input stream.
|
||||||
|
func NewTokenizer(r io.Reader) *Tokenizer {
|
||||||
|
input := bufio.NewReader(r)
|
||||||
|
classifier := newDefaultClassifier()
|
||||||
|
return &Tokenizer{
|
||||||
|
input: *input,
|
||||||
|
classifier: classifier}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanStream scans the stream for the next token using the internal state machine.
|
||||||
|
// It will panic if it encounters a rune which it does not know how to handle.
|
||||||
|
func (t *Tokenizer) scanStream() (*Token, error) {
|
||||||
|
state := startState
|
||||||
|
var tokenType TokenType
|
||||||
|
var value []rune
|
||||||
|
var nextRune rune
|
||||||
|
var nextRuneType runeTokenClass
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for {
|
||||||
|
nextRune, _, err = t.input.ReadRune()
|
||||||
|
nextRuneType = t.classifier.ClassifyRune(nextRune)
|
||||||
|
|
||||||
|
if err == io.EOF {
|
||||||
|
nextRuneType = eofRuneClass
|
||||||
|
err = nil
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch state {
|
||||||
|
case startState: // no runes read yet
|
||||||
|
{
|
||||||
|
switch nextRuneType {
|
||||||
|
case eofRuneClass:
|
||||||
|
{
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
case spaceRuneClass:
|
||||||
|
{
|
||||||
|
}
|
||||||
|
case escapingQuoteRuneClass:
|
||||||
|
{
|
||||||
|
tokenType = WordToken
|
||||||
|
state = quotingEscapingState
|
||||||
|
}
|
||||||
|
case nonEscapingQuoteRuneClass:
|
||||||
|
{
|
||||||
|
tokenType = WordToken
|
||||||
|
state = quotingState
|
||||||
|
}
|
||||||
|
case escapeRuneClass:
|
||||||
|
{
|
||||||
|
tokenType = WordToken
|
||||||
|
state = escapingState
|
||||||
|
}
|
||||||
|
case commentRuneClass:
|
||||||
|
{
|
||||||
|
tokenType = CommentToken
|
||||||
|
state = commentState
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
tokenType = WordToken
|
||||||
|
value = append(value, nextRune)
|
||||||
|
state = inWordState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case inWordState: // in a regular word
|
||||||
|
{
|
||||||
|
switch nextRuneType {
|
||||||
|
case eofRuneClass:
|
||||||
|
{
|
||||||
|
token := &Token{
|
||||||
|
tokenType: tokenType,
|
||||||
|
value: string(value)}
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
case spaceRuneClass:
|
||||||
|
{
|
||||||
|
token := &Token{
|
||||||
|
tokenType: tokenType,
|
||||||
|
value: string(value)}
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
case escapingQuoteRuneClass:
|
||||||
|
{
|
||||||
|
state = quotingEscapingState
|
||||||
|
}
|
||||||
|
case nonEscapingQuoteRuneClass:
|
||||||
|
{
|
||||||
|
state = quotingState
|
||||||
|
}
|
||||||
|
case escapeRuneClass:
|
||||||
|
{
|
||||||
|
state = escapingState
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
value = append(value, nextRune)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case escapingState: // the rune after an escape character
|
||||||
|
{
|
||||||
|
switch nextRuneType {
|
||||||
|
case eofRuneClass:
|
||||||
|
{
|
||||||
|
err = fmt.Errorf("EOF found after escape character")
|
||||||
|
token := &Token{
|
||||||
|
tokenType: tokenType,
|
||||||
|
value: string(value)}
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
state = inWordState
|
||||||
|
value = append(value, nextRune)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case escapingQuotedState: // the next rune after an escape character, in double quotes
|
||||||
|
{
|
||||||
|
switch nextRuneType {
|
||||||
|
case eofRuneClass:
|
||||||
|
{
|
||||||
|
err = fmt.Errorf("EOF found after escape character")
|
||||||
|
token := &Token{
|
||||||
|
tokenType: tokenType,
|
||||||
|
value: string(value)}
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
state = quotingEscapingState
|
||||||
|
value = append(value, nextRune)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case quotingEscapingState: // in escaping double quotes
|
||||||
|
{
|
||||||
|
switch nextRuneType {
|
||||||
|
case eofRuneClass:
|
||||||
|
{
|
||||||
|
err = fmt.Errorf("EOF found when expecting closing quote")
|
||||||
|
token := &Token{
|
||||||
|
tokenType: tokenType,
|
||||||
|
value: string(value)}
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
case escapingQuoteRuneClass:
|
||||||
|
{
|
||||||
|
state = inWordState
|
||||||
|
}
|
||||||
|
case escapeRuneClass:
|
||||||
|
{
|
||||||
|
state = escapingQuotedState
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
value = append(value, nextRune)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case quotingState: // in non-escaping single quotes
|
||||||
|
{
|
||||||
|
switch nextRuneType {
|
||||||
|
case eofRuneClass:
|
||||||
|
{
|
||||||
|
err = fmt.Errorf("EOF found when expecting closing quote")
|
||||||
|
token := &Token{
|
||||||
|
tokenType: tokenType,
|
||||||
|
value: string(value)}
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
case nonEscapingQuoteRuneClass:
|
||||||
|
{
|
||||||
|
state = inWordState
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
value = append(value, nextRune)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case commentState: // in a comment
|
||||||
|
{
|
||||||
|
switch nextRuneType {
|
||||||
|
case eofRuneClass:
|
||||||
|
{
|
||||||
|
token := &Token{
|
||||||
|
tokenType: tokenType,
|
||||||
|
value: string(value)}
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
case spaceRuneClass:
|
||||||
|
{
|
||||||
|
if nextRune == '\n' {
|
||||||
|
state = startState
|
||||||
|
token := &Token{
|
||||||
|
tokenType: tokenType,
|
||||||
|
value: string(value)}
|
||||||
|
return token, err
|
||||||
|
} else {
|
||||||
|
value = append(value, nextRune)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
value = append(value, nextRune)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return nil, fmt.Errorf("Unexpected state: %v", state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the next token in the stream.
|
||||||
|
func (t *Tokenizer) Next() (*Token, error) {
|
||||||
|
return t.scanStream()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split partitions a string into a slice of strings.
|
||||||
|
func Split(s string) ([]string, error) {
|
||||||
|
l := NewLexer(strings.NewReader(s))
|
||||||
|
subStrings := make([]string, 0)
|
||||||
|
for {
|
||||||
|
word, err := l.Next()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return subStrings, nil
|
||||||
|
}
|
||||||
|
return subStrings, err
|
||||||
|
}
|
||||||
|
subStrings = append(subStrings, word)
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче