Format all code
This commit is contained in:
parent
92e5ab998e
commit
9ae78d506e
7 changed files with 106 additions and 79 deletions
2
rustfmt.toml
Normal file
2
rustfmt.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
max_width = 80
|
||||||
|
wrap_comments = true
|
|
@ -19,11 +19,12 @@ pub struct Config {
|
||||||
/// The root configuration directory for dip. This argument is required.
|
/// The root configuration directory for dip. This argument is required.
|
||||||
#[structopt(short = "d", long = "root", parse(from_os_str))]
|
#[structopt(short = "d", long = "root", parse(from_os_str))]
|
||||||
pub root: PathBuf,
|
pub root: PathBuf,
|
||||||
/// A string containing the address to bind to. This defaults to "0.0.0.0:5000".
|
/// A string containing the address to bind to. This defaults to
|
||||||
|
/// "0.0.0.0:5000".
|
||||||
#[structopt(short = "b", long = "bind", default_value = "0.0.0.0:5000")]
|
#[structopt(short = "b", long = "bind", default_value = "0.0.0.0:5000")]
|
||||||
pub bind: String,
|
pub bind: String,
|
||||||
/// If a hook is specified here, it will be triggered manually exactly once and then the
|
/// If a hook is specified here, it will be triggered manually exactly once
|
||||||
/// program will exit rather than running as a server.
|
/// and then the program will exit rather than running as a server.
|
||||||
#[structopt(short = "h", long = "hook")]
|
#[structopt(short = "h", long = "hook")]
|
||||||
pub hook: Option<String>,
|
pub hook: Option<String>,
|
||||||
}
|
}
|
||||||
|
@ -44,7 +45,8 @@ where
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
{
|
{
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(1))?;
|
let mut watcher: RecommendedWatcher =
|
||||||
|
Watcher::new(tx, Duration::from_secs(1))?;
|
||||||
println!("Watching {:?}", root.as_ref().to_path_buf());
|
println!("Watching {:?}", root.as_ref().to_path_buf());
|
||||||
watcher.watch(root.as_ref(), RecursiveMode::Recursive)?;
|
watcher.watch(root.as_ref(), RecursiveMode::Recursive)?;
|
||||||
loop {
|
loop {
|
||||||
|
@ -135,7 +137,10 @@ where
|
||||||
})(path)
|
})(path)
|
||||||
{
|
{
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => eprintln!("Failed to read config from {:?}: {}", path, err),
|
Err(err) => eprintln!(
|
||||||
|
"Failed to read config from {:?}: {}",
|
||||||
|
path, err
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,8 +97,8 @@ pub(crate) fn main(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload: GithubPayload =
|
let payload: GithubPayload = serde_json::from_str(&payload.body)
|
||||||
serde_json::from_str(&payload.body).expect("Could not parse Github input into json");
|
.expect("Could not parse Github input into json");
|
||||||
let mut target_path = env.workdir.clone();
|
let mut target_path = env.workdir.clone();
|
||||||
target_path.push(&config.path);
|
target_path.push(&config.path);
|
||||||
Command::new("git")
|
Command::new("git")
|
||||||
|
|
130
src/handler.rs
130
src/handler.rs
|
@ -26,10 +26,13 @@ pub struct Handler {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
/// A builtin function (for example, the Github handler).
|
/// A builtin function (for example, the Github handler).
|
||||||
Builtin(fn(&Environment, &TomlValue, &JsonValue) -> Result<JsonValue, Error>),
|
Builtin(
|
||||||
|
fn(&Environment, &TomlValue, &JsonValue) -> Result<JsonValue, Error>,
|
||||||
|
),
|
||||||
/// A command represents a string to be executed by `bash -c`.
|
/// A command represents a string to be executed by `bash -c`.
|
||||||
Command(String),
|
Command(String),
|
||||||
/// A program represents one of the handlers specified in the `handlers` directory.
|
/// A program represents one of the handlers specified in the `handlers`
|
||||||
|
/// directory.
|
||||||
Program(String),
|
Program(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,69 +102,72 @@ impl Handler {
|
||||||
.stderr(Stdio::piped());
|
.stderr(Stdio::piped());
|
||||||
};
|
};
|
||||||
|
|
||||||
let output: Box<dyn Future<Item = JsonValue, Error = Error> + Send> = match action {
|
let output: Box<dyn Future<Item = JsonValue, Error = Error> + Send> =
|
||||||
Action::Builtin(ref func) => {
|
match action {
|
||||||
let workdir = temp_path_cp.clone();
|
Action::Builtin(ref func) => {
|
||||||
let env = Environment { workdir };
|
let workdir = temp_path_cp.clone();
|
||||||
let result = func(&env, &config, &input);
|
let env = Environment { workdir };
|
||||||
Box::new(future::result(result))
|
let result = func(&env, &config, &input);
|
||||||
}
|
Box::new(future::result(result))
|
||||||
Action::Command(ref cmd) => {
|
}
|
||||||
// TODO: allow some kind of simple variable replacement
|
Action::Command(ref cmd) => {
|
||||||
let mut command = Command::new("/bin/bash");
|
// TODO: allow some kind of simple variable replacement
|
||||||
command_helper(&mut command);
|
let mut command = Command::new("/bin/bash");
|
||||||
let child = command.arg("-c").arg(cmd);
|
command_helper(&mut command);
|
||||||
let result = child
|
let child = command.arg("-c").arg(cmd);
|
||||||
.output_async()
|
let result = child
|
||||||
.map_err(|err| err_msg(format!("failed to spawn child: {}", err)))
|
.output_async()
|
||||||
.and_then(|output| {
|
.map_err(|err| {
|
||||||
let stdout =
|
err_msg(format!("failed to spawn child: {}", err))
|
||||||
String::from_utf8(output.stdout).unwrap_or_else(|_| String::new());
|
})
|
||||||
let stderr =
|
.and_then(|output| {
|
||||||
String::from_utf8(output.stderr).unwrap_or_else(|_| String::new());
|
let stdout = String::from_utf8(output.stdout)
|
||||||
future::ok(json!({
|
.unwrap_or_else(|_| String::new());
|
||||||
"stdout": stdout,
|
let stderr = String::from_utf8(output.stderr)
|
||||||
"stderr": stderr,
|
.unwrap_or_else(|_| String::new());
|
||||||
}))
|
future::ok(json!({
|
||||||
});
|
|
||||||
Box::new(result)
|
|
||||||
}
|
|
||||||
Action::Program(ref path) => {
|
|
||||||
let mut command = Command::new(&path);
|
|
||||||
command_helper(&mut command);
|
|
||||||
let mut child = command
|
|
||||||
.arg("--config")
|
|
||||||
.arg(config_str)
|
|
||||||
.spawn_async()
|
|
||||||
.expect("could not spawn child");
|
|
||||||
|
|
||||||
let stdin = child.stdin().take().unwrap();
|
|
||||||
|
|
||||||
let input = format!("{}", input);
|
|
||||||
let result = write_all(stdin, input)
|
|
||||||
.and_then(|_| child.wait_with_output())
|
|
||||||
.map_err(|err| err_msg(format!("error: {}", err)))
|
|
||||||
.and_then(|output| {
|
|
||||||
let stdout =
|
|
||||||
String::from_utf8(output.stdout).unwrap_or_else(|_| String::new());
|
|
||||||
let stderr =
|
|
||||||
String::from_utf8(output.stderr).unwrap_or_else(|_| String::new());
|
|
||||||
if output.status.success() {
|
|
||||||
Either::A(future::ok(json!({
|
|
||||||
"stdout": stdout,
|
"stdout": stdout,
|
||||||
"stderr": stderr,
|
"stderr": stderr,
|
||||||
})))
|
}))
|
||||||
} else {
|
});
|
||||||
Either::B(future::err(err_msg(format!(
|
Box::new(result)
|
||||||
"Failed, stdout: '{}', stderr: '{}'",
|
}
|
||||||
stdout, stderr
|
Action::Program(ref path) => {
|
||||||
))))
|
let mut command = Command::new(&path);
|
||||||
}
|
command_helper(&mut command);
|
||||||
});
|
let mut child = command
|
||||||
|
.arg("--config")
|
||||||
|
.arg(config_str)
|
||||||
|
.spawn_async()
|
||||||
|
.expect("could not spawn child");
|
||||||
|
|
||||||
Box::new(result)
|
let stdin = child.stdin().take().unwrap();
|
||||||
}
|
|
||||||
};
|
let input = format!("{}", input);
|
||||||
|
let result = write_all(stdin, input)
|
||||||
|
.and_then(|_| child.wait_with_output())
|
||||||
|
.map_err(|err| err_msg(format!("error: {}", err)))
|
||||||
|
.and_then(|output| {
|
||||||
|
let stdout = String::from_utf8(output.stdout)
|
||||||
|
.unwrap_or_else(|_| String::new());
|
||||||
|
let stderr = String::from_utf8(output.stderr)
|
||||||
|
.unwrap_or_else(|_| String::new());
|
||||||
|
if output.status.success() {
|
||||||
|
Either::A(future::ok(json!({
|
||||||
|
"stdout": stdout,
|
||||||
|
"stderr": stderr,
|
||||||
|
})))
|
||||||
|
} else {
|
||||||
|
Either::B(future::err(err_msg(format!(
|
||||||
|
"Failed, stdout: '{}', stderr: '{}'",
|
||||||
|
stdout, stderr
|
||||||
|
))))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Box::new(result)
|
||||||
|
}
|
||||||
|
};
|
||||||
output.map(|x| (temp_path_cp, x))
|
output.map(|x| (temp_path_cp, x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
src/hook.rs
14
src/hook.rs
|
@ -20,7 +20,10 @@ pub struct Hook {
|
||||||
|
|
||||||
impl Hook {
|
impl Hook {
|
||||||
/// Creates a hook from a (name, config) pair.
|
/// Creates a hook from a (name, config) pair.
|
||||||
pub fn from(name: impl Into<String>, config: &Value) -> Result<Self, Error> {
|
pub fn from(
|
||||||
|
name: impl Into<String>,
|
||||||
|
config: &Value,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
let handlers = config
|
let handlers = config
|
||||||
.get("handlers")
|
.get("handlers")
|
||||||
|
@ -59,7 +62,11 @@ impl Hook {
|
||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn handle(&self, req: JsonValue, temp_path: PathBuf) -> Result<String, String> {
|
pub(crate) fn handle(
|
||||||
|
&self,
|
||||||
|
req: JsonValue,
|
||||||
|
temp_path: PathBuf,
|
||||||
|
) -> Result<String, String> {
|
||||||
let handlers = self
|
let handlers = self
|
||||||
.handlers
|
.handlers
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -68,7 +75,8 @@ impl Hook {
|
||||||
let st = stream::iter_ok::<_, Error>(handlers.into_iter())
|
let st = stream::iter_ok::<_, Error>(handlers.into_iter())
|
||||||
.fold((temp_path, req), |(path, prev), (config, action)| {
|
.fold((temp_path, req), |(path, prev), (config, action)| {
|
||||||
Handler::run(config, action, path, prev)
|
Handler::run(config, action, path, prev)
|
||||||
}).map(|_| ())
|
})
|
||||||
|
.map(|_| ())
|
||||||
.map_err(|err: Error| {
|
.map_err(|err: Error| {
|
||||||
println!("Error from stream: {}", err);
|
println!("Error from stream: {}", err);
|
||||||
});
|
});
|
||||||
|
|
|
@ -58,11 +58,12 @@ use crate::service::*;
|
||||||
const URIPATTERN_STR: &str = r"/webhook/(?P<name>[A-Za-z._][A-Za-z0-9._]*)";
|
const URIPATTERN_STR: &str = r"/webhook/(?P<name>[A-Za-z._][A-Za-z0-9._]*)";
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref URIPATTERN: Regex =
|
static ref URIPATTERN: Regex = Regex::new(URIPATTERN_STR)
|
||||||
Regex::new(URIPATTERN_STR).expect("Could not compile regular expression.");
|
.expect("Could not compile regular expression.");
|
||||||
static ref PROGRAMS: Arc<Mutex<HashMap<String, PathBuf>>> =
|
static ref PROGRAMS: Arc<Mutex<HashMap<String, PathBuf>>> =
|
||||||
Arc::new(Mutex::new(HashMap::new()));
|
Arc::new(Mutex::new(HashMap::new()));
|
||||||
static ref HOOKS: Arc<Mutex<HashMap<String, Hook>>> = Arc::new(Mutex::new(HashMap::new()));
|
static ref HOOKS: Arc<Mutex<HashMap<String, Hook>>> =
|
||||||
|
Arc::new(Mutex::new(HashMap::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Main entry point of the entire application.
|
/// Main entry point of the entire application.
|
||||||
|
|
|
@ -42,7 +42,8 @@ pub(crate) fn dip_service(
|
||||||
.filter_map(|(k, v)| {
|
.filter_map(|(k, v)| {
|
||||||
let key = k.unwrap().as_str().to_owned();
|
let key = k.unwrap().as_str().to_owned();
|
||||||
v.to_str().map(|value| (key, value.to_owned())).ok()
|
v.to_str().map(|value| (key, value.to_owned())).ok()
|
||||||
}).collect::<HashMap<_, _>>();
|
})
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
let method = req.method().as_str().to_owned();
|
let method = req.method().as_str().to_owned();
|
||||||
|
|
||||||
// spawn job
|
// spawn job
|
||||||
|
@ -66,7 +67,9 @@ pub(crate) fn dip_service(
|
||||||
return Response::builder()
|
return Response::builder()
|
||||||
.status(StatusCode::NOT_FOUND)
|
.status(StatusCode::NOT_FOUND)
|
||||||
.body(Body::from("not found"))
|
.body(Body::from("not found"))
|
||||||
.unwrap_or_else(|_| Response::new(Body::from("not found")));
|
.unwrap_or_else(|_| {
|
||||||
|
Response::new(Body::from("not found"))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (code, msg) = match hook.handle(req_obj, temp_path) {
|
let (code, msg) = match hook.handle(req_obj, temp_path) {
|
||||||
|
@ -78,7 +81,9 @@ pub(crate) fn dip_service(
|
||||||
Response::builder()
|
Response::builder()
|
||||||
.status(code)
|
.status(code)
|
||||||
.body(Body::from(msg))
|
.body(Body::from(msg))
|
||||||
.unwrap_or_else(|err| Response::new(Body::from(format!("{}", err))))
|
.unwrap_or_else(|err| {
|
||||||
|
Response::new(Body::from(format!("{}", err)))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue