Wenk.
Language agnostic task wrapper and loyal servant. Runs arbitrary shell commands in an arbitrary working directory on an arbitrary server.
Gunter requires you to define a set of tasks, represented as JSON, which tell Gunter what commands to run, and where to run them.
Install gunter:
$ npm install gunter --save
Then require
gunter in your modules:
var gunter = require('gunter');
Tasks are represented as JSON objects. Here is a basic task:
{
"taskname" : {
"remote" : "localhost",
"cwd" : "/",
"commands" : [
"echo I'm a task!",
"echo I'm another task!",
"echo Hello, my name is Gunter!"
]
}
}
remote
tells Gunter where to execute (either localhost
, or some
arbitrary server)cwd
tells Gunter what directory to execute commands incommands
is an array of commands to execute. At run time, these will be
concatenated together with &&
s in the order in which you define them in
the arrayTake a look at this task definition:
{
"taskname" : {
"remote" : "localhost",
"cwd" : "/",
"commands" : [
"echo I'm a task!",
"echo I'm another task!",
"echo Hello, my name is {{name}}"
],
"defaults" : {
"name" : "Gunter"
}
}
}
There are a couple differences from the one in Defining Tasks.
Notice the mustache-style variable {{name}}
. This
is filled in at execution time by a vars
object passed to the exec
function.
You can also optionally include a defaults
object in your task definition if
you'd like to have defaults set for your variables, in case you don't pass anything
in to exec
. Otherwise, these variables will default to an empty string.
Gunter supports several authentication strategies (password, private key, and
agent auth). You can optionally add an auth
object to your task definitions
to specify a username
, password
, privateKey
, and port
. If you exclude
some or all of these parameters, Gunter will use agent authentication, on port
22, and set the username to the executing user's username.
Here's an example of a task definition that includes an auth
object:
{
"taskname" : {
"remote" : "example.com",
"cwd" : "/",
"commands" : [
"echo Holla!"
],
"auth" : {
"username" : "dudeson",
"port" : 22,
"password" : "suP3rSekr3tp@$sw0rd",
"privateKey" : "path/to/private/key"
}
}
}
Note that your real password probably shouldn't contain the word "password", no matter how creative you are with numbers and symbols.
If several forms of authentication are present, they will be tried in the following order until one is successful: Password -> Private Key -> Agent
Gunter is a simple penguin. Gunter only knows how to do a few things.
Load tasks for execution. Evaluates tasks for proper syntax, and will throw
an error if anything is ill-defined. You can call load
several times, and it
will append tasks to the list of previously defined tasks.
Note: Gunter makes use of a global variable to keep track of its defined
tasks, global.taskList
. If you overwrite this global, Gunter will become
confused and break.
Type: Object
or String
You can pass load
either an Object, or the path to a JSON file containing
tasks like the example in Defining Tasks. If passing load
a filepath, its best that you use an absolute path for simplicity, as relative
paths may not behave as you expect.
Clears all previously defined tasks from memory.
The meat and potatoes. Executes a task. exec
is asynchronous. It will emit
events against the event
tag whenever the shell surfaces some data, and you can
pass it a callback to handle task completion and error. You should make use of
the exported emitter
object to capture the output
events.
Type: String
The name of the task to execute, as defined in a previously loaded JSON object.
Type: String
Tells Gunter what event to emit on output
(stdout
and stderr
). If you
leave this value null
, it'll default to emitting on the 'output'
event. Make
sure you set up an event listener for the event passed here as described in
.emitter below before calling this function.
Important note: If you'll be running more than one task concurrently, you'll probably want to give each a unique event you can monitor.
Type: Object
or String
This parameter is for filling in variables defined in previously loaded
JSON tasks. Like load
, it accepts either an Object or the path to a JSON
file. Here you should pass in keys matching the variable names in your tasks,
and values containing what they should be replaced by. If you have no variables
to replace, just pass it an empty object {}
. Note that any variables you pass
in here that aren't actually defined in your task will just get eaten at runtime.
Example usage:
{
"name" : "Gunter",
"description" : "Wenk"
}
Type: Function
Here you can pass a callback function to execute when exec
completes. Gunter
will call this function in the idiomatic Node style: it will set the first param
to nil
and the second to the task object on success, and will set the first
param to an error message on error.
Your callback should look something like this:
function callback(err, task) {
if (err) {
return console.log(err);
}
// Do something with the task object
console.log('Task completed successfully!');
}
It's a good idea to always return
on err
. If you need to brush up on your
understanding of Node callbacks, take a look at
this great tutorial.
An EventEmitter
object used by exec
to asynchronously communicate its state.
Gunter captures and emits all output from running tasks as a buffer. This can be a little noisy, so its best to save this for some kind of verbose mode in your module, or write it to a log file.
How you should access these events depends on how you'll be calling exec
. If
you're going to pass exec
an event
, setup a listener for that event. If you're
not concerned about concurrency, aren't passing a value to event
, and want
everything to report on one event, setup a listener for the default event, 'output'
You can access it like this:
gunter.emitter.on('eventName', function(data) {
// Something's been spit out
console.log(data.toString('utf8');
});
To learn more about how events work, check out this tutorial.
The MIT License (MIT)
Copyright (c) 2015 500px
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.