mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #1317 from calavera/login_signal
Exit from `docker login` on SIGTERM and SIGINT.
This commit is contained in:
commit
d13c2ed24e
2 changed files with 68 additions and 86 deletions
115
commands.go
115
commands.go
|
@ -2,6 +2,7 @@ package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
|
@ -25,7 +26,6 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -254,75 +254,20 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||||
|
|
||||||
// 'docker login': login / register a user to registry service.
|
// 'docker login': login / register a user to registry service.
|
||||||
func (cli *DockerCli) CmdLogin(args ...string) error {
|
func (cli *DockerCli) CmdLogin(args ...string) error {
|
||||||
var readStringOnRawTerminal = func(stdin io.Reader, stdout io.Writer, echo bool) string {
|
|
||||||
char := make([]byte, 1)
|
|
||||||
buffer := make([]byte, 64)
|
|
||||||
var i = 0
|
|
||||||
for i < len(buffer) {
|
|
||||||
n, err := stdin.Read(char)
|
|
||||||
if n > 0 {
|
|
||||||
if char[0] == '\r' || char[0] == '\n' {
|
|
||||||
stdout.Write([]byte{'\r', '\n'})
|
|
||||||
break
|
|
||||||
} else if char[0] == 127 || char[0] == '\b' {
|
|
||||||
if i > 0 {
|
|
||||||
if echo {
|
|
||||||
stdout.Write([]byte{'\b', ' ', '\b'})
|
|
||||||
}
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
} else if !unicode.IsSpace(rune(char[0])) &&
|
|
||||||
!unicode.IsControl(rune(char[0])) {
|
|
||||||
if echo {
|
|
||||||
stdout.Write(char)
|
|
||||||
}
|
|
||||||
buffer[i] = char[0]
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
if err != io.EOF {
|
|
||||||
fmt.Fprintf(stdout, "Read error: %v\r\n", err)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string(buffer[:i])
|
|
||||||
}
|
|
||||||
var readAndEchoString = func(stdin io.Reader, stdout io.Writer) string {
|
|
||||||
return readStringOnRawTerminal(stdin, stdout, true)
|
|
||||||
}
|
|
||||||
var readString = func(stdin io.Reader, stdout io.Writer) string {
|
|
||||||
return readStringOnRawTerminal(stdin, stdout, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := Subcmd("login", "[OPTIONS]", "Register or Login to the docker registry server")
|
cmd := Subcmd("login", "[OPTIONS]", "Register or Login to the docker registry server")
|
||||||
flUsername := cmd.String("u", "", "username")
|
|
||||||
flPassword := cmd.String("p", "", "password")
|
var username, password, email string
|
||||||
flEmail := cmd.String("e", "", "email")
|
|
||||||
|
cmd.StringVar(&username, "u", "", "username")
|
||||||
|
cmd.StringVar(&password, "p", "", "password")
|
||||||
|
cmd.StringVar(&email, "e", "", "email")
|
||||||
err := cmd.Parse(args)
|
err := cmd.Parse(args)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cli.LoadConfigFile()
|
promptDefault := func(prompt string, configDefault string) {
|
||||||
|
|
||||||
var oldState *term.State
|
|
||||||
if *flUsername == "" || *flPassword == "" || *flEmail == "" {
|
|
||||||
oldState, err = term.SetRawTerminal(cli.terminalFd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer term.RestoreTerminal(cli.terminalFd, oldState)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
username string
|
|
||||||
password string
|
|
||||||
email string
|
|
||||||
)
|
|
||||||
|
|
||||||
var promptDefault = func(prompt string, configDefault string) {
|
|
||||||
if configDefault == "" {
|
if configDefault == "" {
|
||||||
fmt.Fprintf(cli.out, "%s: ", prompt)
|
fmt.Fprintf(cli.out, "%s: ", prompt)
|
||||||
} else {
|
} else {
|
||||||
|
@ -330,47 +275,59 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readInput := func(in io.Reader, out io.Writer) string {
|
||||||
|
reader := bufio.NewReader(in)
|
||||||
|
line, _, err := reader.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(out, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return string(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
cli.LoadConfigFile()
|
||||||
authconfig, ok := cli.configFile.Configs[auth.IndexServerAddress()]
|
authconfig, ok := cli.configFile.Configs[auth.IndexServerAddress()]
|
||||||
if !ok {
|
if !ok {
|
||||||
authconfig = auth.AuthConfig{}
|
authconfig = auth.AuthConfig{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flUsername == "" {
|
if username == "" {
|
||||||
promptDefault("Username", authconfig.Username)
|
promptDefault("Username", authconfig.Username)
|
||||||
username = readAndEchoString(cli.in, cli.out)
|
username = readInput(cli.in, cli.out)
|
||||||
if username == "" {
|
if username == "" {
|
||||||
username = authconfig.Username
|
username = authconfig.Username
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
username = *flUsername
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if username != authconfig.Username {
|
if username != authconfig.Username {
|
||||||
if *flPassword == "" {
|
if password == "" {
|
||||||
|
oldState, _ := term.SaveState(cli.terminalFd)
|
||||||
fmt.Fprintf(cli.out, "Password: ")
|
fmt.Fprintf(cli.out, "Password: ")
|
||||||
password = readString(cli.in, cli.out)
|
|
||||||
|
term.DisableEcho(cli.terminalFd, oldState)
|
||||||
|
|
||||||
|
password = readInput(cli.in, cli.out)
|
||||||
|
fmt.Fprint(cli.out, "\n")
|
||||||
|
|
||||||
|
term.RestoreTerminal(cli.terminalFd, oldState)
|
||||||
|
|
||||||
if password == "" {
|
if password == "" {
|
||||||
return fmt.Errorf("Error : Password Required")
|
return fmt.Errorf("Error : Password Required")
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
password = *flPassword
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flEmail == "" {
|
if email == "" {
|
||||||
promptDefault("Email", authconfig.Email)
|
promptDefault("Email", authconfig.Email)
|
||||||
email = readAndEchoString(cli.in, cli.out)
|
email = readInput(cli.in, cli.out)
|
||||||
if email == "" {
|
if email == "" {
|
||||||
email = authconfig.Email
|
email = authconfig.Email
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
email = *flEmail
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
password = authconfig.Password
|
password = authconfig.Password
|
||||||
email = authconfig.Email
|
email = authconfig.Email
|
||||||
}
|
}
|
||||||
if oldState != nil {
|
|
||||||
term.RestoreTerminal(cli.terminalFd, oldState)
|
|
||||||
}
|
|
||||||
authconfig.Username = username
|
authconfig.Username = username
|
||||||
authconfig.Password = password
|
authconfig.Password = password
|
||||||
authconfig.Email = email
|
authconfig.Email = email
|
||||||
|
|
39
term/term.go
39
term/term.go
|
@ -43,17 +43,42 @@ func RestoreTerminal(fd uintptr, state *State) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SaveState(fd uintptr) (*State, error) {
|
||||||
|
var oldState State
|
||||||
|
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, getTermios, uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &oldState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DisableEcho(fd uintptr, state *State) error {
|
||||||
|
newState := state.termios
|
||||||
|
newState.Lflag &^= syscall.ECHO
|
||||||
|
|
||||||
|
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(&newState))); err != 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
handleInterrupt(fd, state)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func SetRawTerminal(fd uintptr) (*State, error) {
|
func SetRawTerminal(fd uintptr) (*State, error) {
|
||||||
oldState, err := MakeRaw(fd)
|
oldState, err := MakeRaw(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c := make(chan os.Signal, 1)
|
handleInterrupt(fd, oldState)
|
||||||
signal.Notify(c, os.Interrupt)
|
|
||||||
go func() {
|
|
||||||
_ = <-c
|
|
||||||
RestoreTerminal(fd, oldState)
|
|
||||||
os.Exit(0)
|
|
||||||
}()
|
|
||||||
return oldState, err
|
return oldState, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleInterrupt(fd uintptr, state *State) {
|
||||||
|
sigchan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigchan, os.Interrupt)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
_ = <-sigchan
|
||||||
|
RestoreTerminal(fd, state)
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue