github as builtin
This commit is contained in:
parent
134bfab8cd
commit
9b5c7a42b2
7 changed files with 101 additions and 55 deletions
11
.travis.yml
11
.travis.yml
|
@ -1,28 +1,27 @@
|
|||
language: rust
|
||||
sudo: false
|
||||
sudo: required
|
||||
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
os: linux
|
||||
matrix:
|
||||
fast_finish: true
|
||||
services:
|
||||
- docker
|
||||
|
||||
cache: cargo
|
||||
|
||||
script:
|
||||
- cargo test --all
|
||||
before_deploy:
|
||||
- cargo build --release --all
|
||||
- cargo build --release --examples
|
||||
- ./ci/build-release.sh dip ${TRAVIS_TAG}-${TRAVIS_OS_NAME}
|
||||
|
||||
deploy:
|
||||
- provider: releases
|
||||
api_key: $AUTH_TOKEN
|
||||
file:
|
||||
- target/release/dip
|
||||
- target/release/examples/github
|
||||
- dip-*
|
||||
on:
|
||||
condition: $TRAVIS_RUST_VERSION = stable
|
||||
tags: true
|
||||
|
|
12
Cargo.toml
12
Cargo.toml
|
@ -4,26 +4,22 @@ description = "Configurable webhook server."
|
|||
version = "0.1.0"
|
||||
authors = ["Michael Zhang <failed.down@gmail.com>"]
|
||||
|
||||
[[example]]
|
||||
name = "github"
|
||||
[dev_dependencies]
|
||||
generic-array = "0.9"
|
||||
hmac = "0.6"
|
||||
secstr = "0.3"
|
||||
sha-1 = "0.7"
|
||||
|
||||
[dependencies]
|
||||
failure = "0.1"
|
||||
futures = "0.1"
|
||||
generic-array = "0.9"
|
||||
hmac = "0.6"
|
||||
hyper = "0.12"
|
||||
mktemp = "0.3"
|
||||
lazy_static = "1.1"
|
||||
notify = "4.0"
|
||||
owning_ref = "0.3"
|
||||
regex = "1.0"
|
||||
secstr = "0.3"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
sha-1 = "0.7"
|
||||
structopt = "0.2"
|
||||
tokio = "0.1"
|
||||
tokio-process = "0.2"
|
||||
|
|
34
ci/build-release.sh
Normal file
34
ci/build-release.sh
Normal file
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Usage: ./build-release <PROJECT> ${TRAVIS_TAG}-${TRAVIS_OS_NAME}
|
||||
#
|
||||
# The latest version of this script is available at
|
||||
# https://github.com/emk/rust-musl-builder/blob/master/examples/build-release
|
||||
#
|
||||
# Called by `.travis.yml` to build release binaries. We use
|
||||
# ekidd/rust-musl-builder to make the Linux binaries so that we can run
|
||||
# them unchanged on any distro, including tiny distros like Alpine (which
|
||||
# is heavily used for Docker containers). Other platforms get regular
|
||||
# binaries, which will generally be dynamically linked against libc.
|
||||
#
|
||||
# If you have a platform which supports static linking of libc, and this
|
||||
# would be generally useful, please feel free to submit patches.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
case `uname -s` in
|
||||
Linux)
|
||||
echo "Building static binaries using ekidd/rust-musl-builder"
|
||||
docker build -t build-"$1"-image .
|
||||
docker run -it --name build-"$1" build-"$1"-image
|
||||
docker cp build-"$1":/home/rust/src/target/x86_64-unknown-linux-musl/release/"$1" "$1"
|
||||
docker rm build-"$1"
|
||||
docker rmi build-"$1"-image
|
||||
zip "$1"-"$2".zip "$1"
|
||||
;;
|
||||
*)
|
||||
echo "Building standard release binaries"
|
||||
cargo build --release
|
||||
zip -j "$1"-"$2".zip target/release/"$1"
|
||||
;;
|
||||
esac
|
|
@ -51,6 +51,7 @@ where
|
|||
let mut programs = PROGRAMS.lock().unwrap();
|
||||
// TODO: some kind of smart diff
|
||||
programs.clear();
|
||||
|
||||
let programs_dir = {
|
||||
let mut p = root.as_ref().to_path_buf();
|
||||
p.push("handlers");
|
||||
|
|
|
@ -1,28 +1,18 @@
|
|||
extern crate dip;
|
||||
extern crate hmac;
|
||||
extern crate secstr;
|
||||
extern crate serde_json;
|
||||
extern crate sha1;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate failure;
|
||||
extern crate generic_array;
|
||||
#[macro_use]
|
||||
extern crate structopt;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::io::{self, Read};
|
||||
use std::iter::FromIterator;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
use failure::err_msg;
|
||||
use failure::{err_msg, Error};
|
||||
use generic_array::GenericArray;
|
||||
use hmac::{Hmac, Mac};
|
||||
use secstr::*;
|
||||
use serde::Serialize;
|
||||
use serde_json::{self, Serializer as JsonSerializer, Value as JsonValue};
|
||||
use sha1::Sha1;
|
||||
use structopt::StructOpt;
|
||||
use toml::Value as TomlValue;
|
||||
|
||||
#[derive(StructOpt)]
|
||||
struct Opt {
|
||||
|
@ -60,16 +50,19 @@ fn default_path() -> PathBuf {
|
|||
PathBuf::from(".")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Opt::from_args();
|
||||
let config: Config = serde_json::from_str(&args.config).expect("Could not parse config.");
|
||||
pub fn main(config: &TomlValue, input: &JsonValue) -> Result<JsonValue, Error> {
|
||||
let config_str = {
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
{
|
||||
let mut serializer = JsonSerializer::new(&mut buf);
|
||||
TomlValue::serialize(&config, &mut serializer).unwrap();
|
||||
}
|
||||
String::from_utf8(buf).unwrap()
|
||||
};
|
||||
let config: Config = serde_json::from_str(&config_str)?;
|
||||
|
||||
let mut payload = String::new();
|
||||
io::stdin()
|
||||
.read_to_string(&mut payload)
|
||||
.expect("Could not read from stdin");
|
||||
let payload: Payload = serde_json::from_str(&payload)
|
||||
.expect(&format!("Could not parse stdin into json: '{}'", payload));
|
||||
let payload_str = format!("{}", input);
|
||||
let payload: Payload = serde_json::from_str(&payload_str)?;
|
||||
|
||||
if !config.disable_hmac_verify {
|
||||
let secret = GenericArray::from_iter(config.secret.bytes());
|
||||
|
@ -113,4 +106,5 @@ fn main() {
|
|||
.arg(&target_path)
|
||||
.output()
|
||||
.expect("Could not spawn process to clone");
|
||||
Ok(json!(1))
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
|
@ -12,7 +13,7 @@ use tokio::io::write_all;
|
|||
use tokio_process::CommandExt;
|
||||
use toml::Value as TomlValue;
|
||||
|
||||
use PROGRAMS;
|
||||
use github;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Handler {
|
||||
|
@ -20,10 +21,20 @@ pub struct Handler {
|
|||
pub action: Action,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub enum Action {
|
||||
Builtin(fn(&TomlValue, &JsonValue) -> Result<JsonValue, Error>),
|
||||
Command(String),
|
||||
Exec(PathBuf),
|
||||
Program(String),
|
||||
}
|
||||
|
||||
impl fmt::Debug for Action {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self {
|
||||
Action::Builtin(_) => write!(f, "Builtin"),
|
||||
_ => write!(f, "{:?}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
|
@ -45,17 +56,18 @@ impl Handler {
|
|||
.ok_or(err_msg("'command' is not a string."))?;
|
||||
Action::Command(command.to_owned())
|
||||
}
|
||||
"github" => Action::Builtin(github::main),
|
||||
handler => {
|
||||
let programs = PROGRAMS.lock().unwrap();
|
||||
let program = programs
|
||||
.get(handler)
|
||||
.ok_or(err_msg(format!("'{}' is not a valid executable", handler)))
|
||||
.and_then(|value| {
|
||||
value
|
||||
.canonicalize()
|
||||
.map_err(|_| err_msg("failed to canonicalize the path"))
|
||||
}).map(|value| value.clone())?;
|
||||
Action::Exec(program)
|
||||
// let programs = HANDLERS.lock().unwrap();
|
||||
// let program = programs
|
||||
// .get(handler)
|
||||
// .ok_or(err_msg(format!("'{}' is not a valid executable", handler)))
|
||||
// .and_then(|value| {
|
||||
// value
|
||||
// .canonicalize()
|
||||
// .map_err(|_| err_msg("failed to canonicalize the path"))
|
||||
// }).map(|value| value.clone())?;
|
||||
Action::Program(handler.to_owned())
|
||||
}
|
||||
};
|
||||
let config = config.clone();
|
||||
|
@ -69,7 +81,7 @@ impl Handler {
|
|||
input: JsonValue,
|
||||
) -> impl Future<Item = (PathBuf, JsonValue), Error = Error> {
|
||||
let temp_path_cp = temp_path.clone();
|
||||
let config = {
|
||||
let config_str = {
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
{
|
||||
let mut serializer = JsonSerializer::new(&mut buf);
|
||||
|
@ -85,6 +97,10 @@ impl Handler {
|
|||
};
|
||||
|
||||
let output: Box<Future<Item = JsonValue, Error = Error> + Send> = match action {
|
||||
Action::Builtin(ref func) => {
|
||||
let result = func(&config, &input);
|
||||
Box::new(future::result(result))
|
||||
}
|
||||
Action::Command(ref cmd) => {
|
||||
// TODO: allow some kind of simple variable replacement
|
||||
let mut command = Command::new("/bin/bash");
|
||||
|
@ -111,13 +127,13 @@ impl Handler {
|
|||
});
|
||||
Box::new(result)
|
||||
}
|
||||
Action::Exec(ref path) => {
|
||||
Action::Program(ref path) => {
|
||||
let mut command = Command::new(&path);
|
||||
command_helper(&mut command);
|
||||
let mut child = command
|
||||
.env("DIP_ROOT", "")
|
||||
.arg("--config")
|
||||
.arg(config)
|
||||
.arg(config_str)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -1,7 +1,13 @@
|
|||
//! # Dip
|
||||
|
||||
extern crate hmac;
|
||||
extern crate secstr;
|
||||
extern crate sha1;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate failure;
|
||||
extern crate futures;
|
||||
extern crate generic_array;
|
||||
extern crate hyper;
|
||||
extern crate mktemp;
|
||||
extern crate owning_ref;
|
||||
|
@ -20,6 +26,7 @@ extern crate toml;
|
|||
extern crate walkdir;
|
||||
|
||||
pub mod config;
|
||||
pub mod github;
|
||||
pub mod handler;
|
||||
pub mod hook;
|
||||
pub mod service;
|
||||
|
@ -48,9 +55,8 @@ const URIPATTERN_STR: &str = r"/webhook/(?P<name>[A-Za-z._][A-Za-z0-9._]*)";
|
|||
|
||||
lazy_static! {
|
||||
static ref URIPATTERN: Regex = Regex::new(URIPATTERN_STR).unwrap();
|
||||
static ref HANDLERS: Arc<Mutex<HashMap<String, Handler>>> =
|
||||
static ref PROGRAMS: Arc<Mutex<HashMap<String, PathBuf>>> =
|
||||
Arc::new(Mutex::new(HashMap::new()));
|
||||
static ref PROGRAMS: Mutex<HashMap<String, PathBuf>> = Mutex::new(HashMap::new());
|
||||
static ref HOOKS: Arc<Mutex<HashMap<String, Hook>>> = Arc::new(Mutex::new(HashMap::new()));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue