mirror of
https://github.com/appleboy/drone-ssh.git
synced 2026-06-16 14:49:25 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 699d9148d8 | |||
| ceec42efdd | |||
| 88b5394dac | |||
| 1637772e0b | |||
| efdac217bd | |||
| f81056261d | |||
| 3fffe80a14 | |||
| 2d568d1fde | |||
| f26bd7f7f7 | |||
| 95427edbba | |||
| 7f168bd1cb | |||
| b6c973ef1e | |||
| 356b2ae6cc | |||
| b698d56d60 | |||
| 06f4f77ebc | |||
| b63f275e9e |
+20
-13
@@ -2,17 +2,20 @@ workspace:
|
|||||||
base: /srv/app
|
base: /srv/app
|
||||||
path: src/github.com/appleboy/drone-ssh
|
path: src/github.com/appleboy/drone-ssh
|
||||||
|
|
||||||
pipeline:
|
clone:
|
||||||
clone:
|
git:
|
||||||
image: plugins/git
|
image: plugins/git
|
||||||
|
depth: 50
|
||||||
tags: true
|
tags: true
|
||||||
|
|
||||||
|
pipeline:
|
||||||
test:
|
test:
|
||||||
image: appleboy/golang-testing
|
image: appleboy/golang-testing
|
||||||
pull: true
|
pull: true
|
||||||
environment:
|
environment:
|
||||||
TAGS: netgo
|
TAGS: netgo
|
||||||
GOPATH: /srv/app
|
GOPATH: /srv/app
|
||||||
|
secrets: [ codecov_token ]
|
||||||
commands:
|
commands:
|
||||||
- make ssh-server
|
- make ssh-server
|
||||||
- make vet
|
- make vet
|
||||||
@@ -26,6 +29,16 @@ pipeline:
|
|||||||
when:
|
when:
|
||||||
event: [ push, tag, pull_request ]
|
event: [ push, tag, pull_request ]
|
||||||
|
|
||||||
|
publish_latest:
|
||||||
|
image: plugins/docker
|
||||||
|
repo: ${DRONE_REPO}
|
||||||
|
tags: [ 'latest' ]
|
||||||
|
secrets: [ docker_username, docker_password ]
|
||||||
|
when:
|
||||||
|
event: [ push ]
|
||||||
|
branch: [ master ]
|
||||||
|
local: false
|
||||||
|
|
||||||
release:
|
release:
|
||||||
image: appleboy/golang-testing
|
image: appleboy/golang-testing
|
||||||
pull: true
|
pull: true
|
||||||
@@ -43,23 +56,17 @@ pipeline:
|
|||||||
image: plugins/docker
|
image: plugins/docker
|
||||||
repo: ${DRONE_REPO}
|
repo: ${DRONE_REPO}
|
||||||
tags: [ '${DRONE_TAG}' ]
|
tags: [ '${DRONE_TAG}' ]
|
||||||
|
secrets: [ docker_username, docker_password ]
|
||||||
|
group: release
|
||||||
when:
|
when:
|
||||||
event: [ tag ]
|
event: [ tag ]
|
||||||
branch: [ refs/tags/* ]
|
branch: [ refs/tags/* ]
|
||||||
local: false
|
local: false
|
||||||
|
|
||||||
publish_latest:
|
release_tag:
|
||||||
image: plugins/docker
|
|
||||||
repo: ${DRONE_REPO}
|
|
||||||
tags: [ 'latest' ]
|
|
||||||
when:
|
|
||||||
event: [ push ]
|
|
||||||
branch: [ master ]
|
|
||||||
local: false
|
|
||||||
|
|
||||||
release:
|
|
||||||
image: plugins/github-release
|
image: plugins/github-release
|
||||||
api_key: ${GITHUB_RELEASE_API_KEY}
|
secrets: [ github_release_api_key ]
|
||||||
|
group: release
|
||||||
files:
|
files:
|
||||||
- dist/release/*
|
- dist/release/*
|
||||||
when:
|
when:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ GOFMT ?= gofmt "-s"
|
|||||||
|
|
||||||
TARGETS ?= linux darwin windows
|
TARGETS ?= linux darwin windows
|
||||||
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
|
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
|
||||||
GOFILES := find . -name "*.go" -type f -not -path "./vendor/*"
|
GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*")
|
||||||
SOURCES ?= $(shell find . -name "*.go" -type f)
|
SOURCES ?= $(shell find . -name "*.go" -type f)
|
||||||
TAGS ?=
|
TAGS ?=
|
||||||
LDFLAGS ?= -X 'main.Version=$(VERSION)'
|
LDFLAGS ?= -X 'main.Version=$(VERSION)'
|
||||||
@@ -32,14 +32,15 @@ all: build
|
|||||||
.PHONY: fmt-check
|
.PHONY: fmt-check
|
||||||
fmt-check:
|
fmt-check:
|
||||||
# get all go files and run go fmt on them
|
# get all go files and run go fmt on them
|
||||||
@files=$$($(GOFILES) | xargs $(GOFMT) -l); if [ -n "$$files" ]; then \
|
@diff=$$($(GOFMT) -d $(GOFILES)); \
|
||||||
|
if [ -n "$$diff" ]; then \
|
||||||
echo "Please run 'make fmt' and commit the result:"; \
|
echo "Please run 'make fmt' and commit the result:"; \
|
||||||
echo "$${files}"; \
|
echo "$${diff}"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
$(GOFILES) | xargs $(GOFMT) -w
|
$(GOFMT) -w $(GOFILES)
|
||||||
|
|
||||||
vet:
|
vet:
|
||||||
go vet $(PACKAGES)
|
go vet $(PACKAGES)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ information and a listing of the available options please take a look at [the do
|
|||||||
|
|
||||||
**Note: Please update your image config path to `appleboy/drone-ssh` for drone. `plugins/ssh` is no longer maintained.**
|
**Note: Please update your image config path to `appleboy/drone-ssh` for drone. `plugins/ssh` is no longer maintained.**
|
||||||
|
|
||||||
|

|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
Build the binary with the following commands:
|
Build the binary with the following commands:
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -11,12 +10,11 @@ import (
|
|||||||
"github.com/appleboy/easyssh-proxy"
|
"github.com/appleboy/easyssh-proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
missingHostOrUser = "Error: missing server host or user"
|
missingHostOrUser = "Error: missing server host or user"
|
||||||
missingPasswordOrKey = "Error: can't connect without a private SSH key or password"
|
missingPasswordOrKey = "Error: can't connect without a private SSH key or password"
|
||||||
commandTimeOut = "Error: command timeout"
|
commandTimeOut = "Error: command timeout"
|
||||||
|
setPasswordandKey = "can't set password and key at the same time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -41,19 +39,28 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (p Plugin) log(host string, message ...interface{}) {
|
func (p Plugin) log(host string, message ...interface{}) {
|
||||||
log.Printf("%s: %s", host, fmt.Sprintln(message...))
|
if count := len(p.Config.Host); count == 1 {
|
||||||
|
fmt.Printf("%s", fmt.Sprintln(message...))
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s: %s", host, fmt.Sprintln(message...))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the plugin.
|
// Exec executes the plugin.
|
||||||
func (p Plugin) Exec() error {
|
func (p Plugin) Exec() error {
|
||||||
if len(p.Config.Host) == 0 && p.Config.UserName == "" {
|
if len(p.Config.Host) == 0 && len(p.Config.UserName) == 0 {
|
||||||
return fmt.Errorf(missingHostOrUser)
|
return fmt.Errorf(missingHostOrUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Config.Key == "" && p.Config.Password == "" && p.Config.KeyPath == "" {
|
if len(p.Config.Key) == 0 && len(p.Config.Password) == 0 && len(p.Config.KeyPath) == 0 {
|
||||||
return fmt.Errorf(missingPasswordOrKey)
|
return fmt.Errorf(missingPasswordOrKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(p.Config.Key) != 0 && len(p.Config.Password) != 0 {
|
||||||
|
return fmt.Errorf(setPasswordandKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(p.Config.Host))
|
wg.Add(len(p.Config.Host))
|
||||||
errChannel := make(chan error, 1)
|
errChannel := make(chan error, 1)
|
||||||
finished := make(chan bool, 1)
|
finished := make(chan bool, 1)
|
||||||
@@ -80,18 +87,34 @@ func (p Plugin) Exec() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.log(host, "commands: ", strings.Join(p.Config.Script, "\n"))
|
p.log(host, "commands: ", strings.Join(p.Config.Script, "\n"))
|
||||||
outStr, errStr, isTimeout, err := ssh.Run(strings.Join(p.Config.Script, "\n"), p.Config.CommandTimeout)
|
stdoutChan, stderrChan, doneChan, errChan, err := ssh.Stream(strings.Join(p.Config.Script, "\n"), p.Config.CommandTimeout)
|
||||||
p.log(host, "outputs:", outStr)
|
|
||||||
if len(errStr) != 0 {
|
|
||||||
p.log(host, "errors:", errStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChannel <- err
|
errChannel <- err
|
||||||
}
|
} else {
|
||||||
|
// read from the output channel until the done signal is passed
|
||||||
|
stillGoing := true
|
||||||
|
isTimeout := true
|
||||||
|
for stillGoing {
|
||||||
|
select {
|
||||||
|
case isTimeout = <-doneChan:
|
||||||
|
stillGoing = false
|
||||||
|
case outline := <-stdoutChan:
|
||||||
|
p.log(host, "out:", outline)
|
||||||
|
case errline := <-stderrChan:
|
||||||
|
p.log(host, "err:", errline)
|
||||||
|
case err = <-errChan:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !isTimeout {
|
// get exit code or command error.
|
||||||
errChannel <- fmt.Errorf(commandTimeOut)
|
if err != nil {
|
||||||
|
errChannel <- err
|
||||||
|
}
|
||||||
|
|
||||||
|
// command time out
|
||||||
|
if !isTimeout {
|
||||||
|
errChannel <- fmt.Errorf(commandTimeOut)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Done()
|
wg.Done()
|
||||||
@@ -107,12 +130,14 @@ func (p Plugin) Exec() error {
|
|||||||
case <-finished:
|
case <-finished:
|
||||||
case err := <-errChannel:
|
case err := <-errChannel:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("drone-ssh error: ", err)
|
fmt.Println("drone-ssh error: ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Successfully executed commands to all host.")
|
fmt.Println("==========================================")
|
||||||
|
fmt.Println("Successfully executed commands to all host.")
|
||||||
|
fmt.Println("==========================================")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,22 @@ func TestMissingKeyOrPassword(t *testing.T) {
|
|||||||
assert.Equal(t, missingPasswordOrKey, err.Error())
|
assert.Equal(t, missingPasswordOrKey, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetPasswordAndKey(t *testing.T) {
|
||||||
|
plugin := Plugin{
|
||||||
|
Config{
|
||||||
|
Host: []string{"localhost"},
|
||||||
|
UserName: "ubuntu",
|
||||||
|
Password: "1234",
|
||||||
|
Key: "1234",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := plugin.Exec()
|
||||||
|
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, setPasswordandKey, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
func TestIncorrectPassword(t *testing.T) {
|
func TestIncorrectPassword(t *testing.T) {
|
||||||
plugin := Plugin{
|
plugin := Plugin{
|
||||||
Config: Config{
|
Config: Config{
|
||||||
@@ -105,6 +121,39 @@ func TestSSHScriptFromKeyFile(t *testing.T) {
|
|||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStreamFromSSHCommand(t *testing.T) {
|
||||||
|
plugin := Plugin{
|
||||||
|
Config: Config{
|
||||||
|
Host: []string{"localhost", "127.0.0.1"},
|
||||||
|
UserName: "drone-scp",
|
||||||
|
Port: 22,
|
||||||
|
KeyPath: "./tests/.ssh/id_rsa",
|
||||||
|
Script: []string{"whoami", "for i in {1..5}; do echo ${i}; sleep 1; done", "echo 'done'"},
|
||||||
|
CommandTimeout: 60,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := plugin.Exec()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSSHScriptWithError(t *testing.T) {
|
||||||
|
plugin := Plugin{
|
||||||
|
Config: Config{
|
||||||
|
Host: []string{"localhost", "127.0.0.1"},
|
||||||
|
UserName: "drone-scp",
|
||||||
|
Port: 22,
|
||||||
|
KeyPath: "./tests/.ssh/id_rsa",
|
||||||
|
Script: []string{"exit 1"},
|
||||||
|
CommandTimeout: 60,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := plugin.Exec()
|
||||||
|
// Process exited with status 1
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSSHCommandTimeOut(t *testing.T) {
|
func TestSSHCommandTimeOut(t *testing.T) {
|
||||||
plugin := Plugin{
|
plugin := Plugin{
|
||||||
Config: Config{
|
Config: Config{
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.9 MiB |
+6
-6
@@ -1,8 +1,7 @@
|
|||||||
.PHONY: test drone-ssh fmt vet errcheck lint install update coverage embedmd
|
.PHONY: test drone-ssh fmt vet errcheck lint install update coverage embedmd
|
||||||
|
|
||||||
GOFMT ?= gofmt "-s"
|
GOFMT ?= gofmt "-s"
|
||||||
|
GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*")
|
||||||
GOFILES := find . -name "*.go" -type f -not -path "./vendor/*"
|
|
||||||
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
|
PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
|
||||||
|
|
||||||
all: install lint
|
all: install lint
|
||||||
@@ -14,16 +13,17 @@ install:
|
|||||||
govendor sync
|
govendor sync
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
$(GOFILES) | xargs $(GOFMT) -w
|
$(GOFMT) -w $(GOFILES)
|
||||||
|
|
||||||
.PHONY: fmt-check
|
.PHONY: fmt-check
|
||||||
fmt-check:
|
fmt-check:
|
||||||
# get all go files and run go fmt on them
|
# get all go files and run go fmt on them
|
||||||
@files=$$($(GOFILES) | xargs $(GOFMT) -l); if [ -n "$$files" ]; then \
|
@diff=$$($(GOFMT) -d $(GOFILES)); \
|
||||||
|
if [ -n "$$diff" ]; then \
|
||||||
echo "Please run 'make fmt' and commit the result:"; \
|
echo "Please run 'make fmt' and commit the result:"; \
|
||||||
echo "$${files}"; \
|
echo "$${diff}"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
vet:
|
vet:
|
||||||
go vet $(PACKAGES)
|
go vet $(PACKAGES)
|
||||||
|
|||||||
+26
-16
@@ -155,36 +155,44 @@ func (ssh_conf *MakeConfig) connect() (*ssh.Session, error) {
|
|||||||
// Stream returns one channel that combines the stdout and stderr of the command
|
// Stream returns one channel that combines the stdout and stderr of the command
|
||||||
// as it is run on the remote machine, and another that sends true when the
|
// as it is run on the remote machine, and another that sends true when the
|
||||||
// command is done. The sessions and channels will then be closed.
|
// command is done. The sessions and channels will then be closed.
|
||||||
func (ssh_conf *MakeConfig) Stream(command string, timeout int) (stdout chan string, stderr chan string, done chan bool, err error) {
|
func (ssh_conf *MakeConfig) Stream(command string, timeout int) (stdout chan string, stderr chan string, done chan bool, errChan chan error, err error) {
|
||||||
// connect to remote host
|
// connect to remote host
|
||||||
session, err := ssh_conf.connect()
|
session, err := ssh_conf.connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stdout, stderr, done, err
|
return stdout, stderr, done, errChan, err
|
||||||
}
|
}
|
||||||
|
// defer session.Close()
|
||||||
// connect to both outputs (they are of type io.Reader)
|
// connect to both outputs (they are of type io.Reader)
|
||||||
outReader, err := session.StdoutPipe()
|
outReader, err := session.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stdout, stderr, done, err
|
return stdout, stderr, done, errChan, err
|
||||||
}
|
}
|
||||||
errReader, err := session.StderrPipe()
|
errReader, err := session.StderrPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stdout, stderr, done, err
|
return stdout, stderr, done, errChan, err
|
||||||
}
|
}
|
||||||
|
err = session.Start(command)
|
||||||
|
if err != nil {
|
||||||
|
return stdout, stderr, done, errChan, err
|
||||||
|
}
|
||||||
|
|
||||||
// combine outputs, create a line-by-line scanner
|
// combine outputs, create a line-by-line scanner
|
||||||
stdoutReader := io.MultiReader(outReader)
|
stdoutReader := io.MultiReader(outReader)
|
||||||
stderrReader := io.MultiReader(errReader)
|
stderrReader := io.MultiReader(errReader)
|
||||||
err = session.Start(command)
|
|
||||||
stdoutScanner := bufio.NewScanner(stdoutReader)
|
stdoutScanner := bufio.NewScanner(stdoutReader)
|
||||||
stderrScanner := bufio.NewScanner(stderrReader)
|
stderrScanner := bufio.NewScanner(stderrReader)
|
||||||
// continuously send the command's output over the channel
|
// continuously send the command's output over the channel
|
||||||
stdoutChan := make(chan string)
|
stdoutChan := make(chan string)
|
||||||
stderrChan := make(chan string)
|
stderrChan := make(chan string)
|
||||||
done = make(chan bool)
|
done = make(chan bool)
|
||||||
|
errChan = make(chan error)
|
||||||
|
|
||||||
go func(stdoutScanner, stderrScanner *bufio.Scanner, stdoutChan, stderrChan chan string, done chan bool) {
|
go func(stdoutScanner, stderrScanner *bufio.Scanner, stdoutChan, stderrChan chan string, done chan bool, errChan chan error) {
|
||||||
defer close(stdoutChan)
|
defer close(stdoutChan)
|
||||||
defer close(stderrChan)
|
defer close(stderrChan)
|
||||||
defer close(done)
|
defer close(done)
|
||||||
|
defer close(errChan)
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
timeoutChan := time.After(time.Duration(timeout) * time.Second)
|
timeoutChan := time.After(time.Duration(timeout) * time.Second)
|
||||||
res := make(chan bool, 1)
|
res := make(chan bool, 1)
|
||||||
@@ -202,23 +210,21 @@ func (ssh_conf *MakeConfig) Stream(command string, timeout int) (stdout chan str
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case <-res:
|
case <-res:
|
||||||
stdoutChan <- ""
|
errChan <- session.Wait()
|
||||||
stderrChan <- ""
|
|
||||||
done <- true
|
done <- true
|
||||||
case <-timeoutChan:
|
case <-timeoutChan:
|
||||||
stdoutChan <- ""
|
|
||||||
stderrChan <- "Run Command Timeout!"
|
stderrChan <- "Run Command Timeout!"
|
||||||
|
errChan <- nil
|
||||||
done <- false
|
done <- false
|
||||||
}
|
}
|
||||||
|
}(stdoutScanner, stderrScanner, stdoutChan, stderrChan, done, errChan)
|
||||||
|
|
||||||
session.Close()
|
return stdoutChan, stderrChan, done, errChan, err
|
||||||
}(stdoutScanner, stderrScanner, stdoutChan, stderrChan, done)
|
|
||||||
return stdoutChan, stderrChan, done, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run command on remote machine and returns its stdout as a string
|
// Run command on remote machine and returns its stdout as a string
|
||||||
func (ssh_conf *MakeConfig) Run(command string, timeout int) (outStr string, errStr string, isTimeout bool, err error) {
|
func (ssh_conf *MakeConfig) Run(command string, timeout int) (outStr string, errStr string, isTimeout bool, err error) {
|
||||||
stdoutChan, stderrChan, doneChan, err := ssh_conf.Stream(command, timeout)
|
stdoutChan, stderrChan, doneChan, errChan, err := ssh_conf.Stream(command, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return outStr, errStr, isTimeout, err
|
return outStr, errStr, isTimeout, err
|
||||||
}
|
}
|
||||||
@@ -236,6 +242,7 @@ func (ssh_conf *MakeConfig) Run(command string, timeout int) (outStr string, err
|
|||||||
if errline != "" {
|
if errline != "" {
|
||||||
errStr += errline + "\n"
|
errStr += errline + "\n"
|
||||||
}
|
}
|
||||||
|
case err = <-errChan:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// return the concatenation of all signals from the output channel
|
// return the concatenation of all signals from the output channel
|
||||||
@@ -266,17 +273,20 @@ func (ssh_conf *MakeConfig) Scp(sourceFile string, etargetFile string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
w, _ := session.StdinPipe()
|
w, err := session.StdinPipe()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
fmt.Fprintln(w, "C0644", srcStat.Size(), targetFile)
|
fmt.Fprintln(w, "C0644", srcStat.Size(), targetFile)
|
||||||
|
|
||||||
if srcStat.Size() > 0 {
|
if srcStat.Size() > 0 {
|
||||||
io.Copy(w, src)
|
io.Copy(w, src)
|
||||||
fmt.Fprint(w, "\x00")
|
fmt.Fprint(w, "\x00")
|
||||||
w.Close()
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprint(w, "\x00")
|
fmt.Fprint(w, "\x00")
|
||||||
w.Close()
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
Vendored
+3
-5
@@ -3,12 +3,10 @@
|
|||||||
"ignore": "test",
|
"ignore": "test",
|
||||||
"package": [
|
"package": [
|
||||||
{
|
{
|
||||||
"checksumSHA1": "L3PugNJJOEpRmRbD+27LgTZC2E4=",
|
"checksumSHA1": "fmzCBkzzkd3KK/yfeMR8IYApkIE=",
|
||||||
"path": "github.com/appleboy/easyssh-proxy",
|
"path": "github.com/appleboy/easyssh-proxy",
|
||||||
"revision": "a13ed86767b8e8a24d8147a4909a702e7cf6b465",
|
"revision": "aa0e30613aeb5cca179bd3982da8d2e06a1bb2a4",
|
||||||
"revisionTime": "2017-04-14T13:46:38Z",
|
"revisionTime": "2017-05-10T13:33:00Z"
|
||||||
"version": "1.1.2",
|
|
||||||
"versionExact": "1.1.2"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "dvabztWVQX8f6oMLRyv4dLH+TGY=",
|
"checksumSHA1": "dvabztWVQX8f6oMLRyv4dLH+TGY=",
|
||||||
|
|||||||
Reference in New Issue
Block a user