grim/convey
Clone
Summary
Browse
Changes
Graph
Split the docs up to make them easier to maintain. Fixes #177
2018-02-18, Gary Kramlich
1a6ea3b6c7b9
Split the docs up to make them easier to maintain. Fixes #177
// Convey
// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Package command provides utilities for running external commands.
package
command
import
(
"bufio"
"os/exec"
"sync"
"time"
"bitbucket.org/rw_grim/convey/logging"
"github.com/aphistic/gomol"
)
var
(
lock
sync
.
Mutex
)
// Run runs the command specified in cmdTemplate which is rendered with the
// given params and logs stderr and stdout to a new log adapter.
func
Run
(
name
string
,
cmdv
[]
string
,
timeout
time
.
Duration
)
error
{
var
(
logger
=
logging
.
NewAdapter
(
name
)
outCollector
=
newLogCollector
(
logger
,
gomol
.
LevelInfo
)
errCollector
=
newLogCollector
(
logger
,
gomol
.
LevelError
)
)
return
run
(
name
,
cmdv
,
timeout
,
outCollector
,
errCollector
)
}
// RunOutput works just like Run but returns stdout and stderr instead of
// logging it.
func
RunOutput
(
name
string
,
cmdv
[]
string
,
timeout
time
.
Duration
)
(
string
,
string
,
error
)
{
var
(
wg
=
&
sync
.
WaitGroup
{}
outCollector
=
newStringCollector
(
wg
)
errCollector
=
newStringCollector
(
wg
)
)
wg
.
Add
(
2
)
err
:=
run
(
name
,
cmdv
,
timeout
,
outCollector
.
handler
,
errCollector
.
handler
)
wg
.
Wait
()
return
outCollector
.
output
,
errCollector
.
output
,
err
}
func
run
(
name
string
,
cmdv
[]
string
,
timeout
time
.
Duration
,
outHandler
,
errHandler
collector
)
error
{
logger
:=
logging
.
NewAdapter
(
name
)
logger
.
Debugf
(
"running command \"%v\""
,
cmdv
)
cmd
:=
exec
.
Command
(
cmdv
[
0
],
cmdv
[
1
:]
...
)
// setup the stdout wrapper
outReader
,
err
:=
cmd
.
StdoutPipe
()
if
err
!=
nil
{
return
err
}
// setup the stderr wrapper
errReader
,
err
:=
cmd
.
StderrPipe
()
if
err
!=
nil
{
return
err
}
// Pass output to the handlers
go
outHandler
(
bufio
.
NewScanner
(
outReader
))
go
errHandler
(
bufio
.
NewScanner
(
errReader
))
// now run the command
err
=
cmd
.
Start
()
if
err
!=
nil
{
return
err
}
var
timer
*
time
.
Timer
if
timeout
!=
0
{
timer
=
time
.
AfterFunc
(
timeout
,
func
()
{
// kill process, unblock the cmd.Wait() below
cmd
.
Process
.
Kill
()
// log that the process timed out
logger
.
Errorf
(
"command %v timed out after %v"
,
cmdv
,
timeout
)
})
}
err
=
cmd
.
Wait
()
// if cmd.Wait() returns before the timeout, we'll have a timer stop
if
timer
!=
nil
{
timer
.
Stop
()
}
return
err
}