├── .editorconfig ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── README.md ├── assets └── logo.png ├── config.json.sample ├── sample.json └── src ├── deployer.rs ├── dispatcher.rs ├── hook_configuration.rs ├── main.rs └── tools.rs /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | 9 | [*.rs] 10 | charset = utf-8 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | config.json 3 | logs 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "small-deployer" 3 | version = "0.1.1" 4 | dependencies = [ 5 | "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", 6 | "openssl 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", 7 | "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", 8 | "slack-hook 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 9 | "small-logger 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 10 | "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", 11 | ] 12 | 13 | [[package]] 14 | name = "bitflags" 15 | version = "0.7.0" 16 | source = "registry+https://github.com/rust-lang/crates.io-index" 17 | 18 | [[package]] 19 | name = "cookie" 20 | version = "0.2.5" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | dependencies = [ 23 | "openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", 26 | "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 27 | ] 28 | 29 | [[package]] 30 | name = "core-foundation" 31 | version = "0.2.2" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | dependencies = [ 34 | "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 35 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 36 | ] 37 | 38 | [[package]] 39 | name = "core-foundation-sys" 40 | version = "0.2.2" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | dependencies = [ 43 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 44 | ] 45 | 46 | [[package]] 47 | name = "curl" 48 | version = "0.3.4" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | dependencies = [ 51 | "curl-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 52 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 53 | "openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)", 54 | ] 55 | 56 | [[package]] 57 | name = "curl-sys" 58 | version = "0.2.1" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | dependencies = [ 61 | "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", 62 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 63 | "libz-sys 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 64 | "openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)", 65 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 66 | ] 67 | 68 | [[package]] 69 | name = "gcc" 70 | version = "0.3.35" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | 73 | [[package]] 74 | name = "gdi32-sys" 75 | version = "0.2.0" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | dependencies = [ 78 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 79 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 80 | ] 81 | 82 | [[package]] 83 | name = "getopts" 84 | version = "0.2.14" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | 87 | [[package]] 88 | name = "hpack" 89 | version = "0.2.0" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | dependencies = [ 92 | "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 93 | ] 94 | 95 | [[package]] 96 | name = "httparse" 97 | version = "1.1.2" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | 100 | [[package]] 101 | name = "hyper" 102 | version = "0.9.10" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | dependencies = [ 105 | "cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", 106 | "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 107 | "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 108 | "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 109 | "mime 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 110 | "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 111 | "openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)", 112 | "openssl-verify 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 113 | "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", 114 | "security-framework 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 115 | "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 116 | "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", 117 | "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 118 | "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 119 | "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 120 | "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 121 | ] 122 | 123 | [[package]] 124 | name = "idna" 125 | version = "0.1.0" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | dependencies = [ 128 | "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 129 | "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 130 | "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 131 | ] 132 | 133 | [[package]] 134 | name = "kernel32-sys" 135 | version = "0.2.2" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | dependencies = [ 138 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 139 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 140 | ] 141 | 142 | [[package]] 143 | name = "language-tags" 144 | version = "0.2.2" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | 147 | [[package]] 148 | name = "lazy_static" 149 | version = "0.2.1" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | 152 | [[package]] 153 | name = "libc" 154 | version = "0.2.15" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | 157 | [[package]] 158 | name = "libressl-pnacl-sys" 159 | version = "2.1.6" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | dependencies = [ 162 | "pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)", 163 | ] 164 | 165 | [[package]] 166 | name = "libz-sys" 167 | version = "1.0.5" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | dependencies = [ 170 | "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", 171 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 172 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 173 | ] 174 | 175 | [[package]] 176 | name = "log" 177 | version = "0.3.6" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | 180 | [[package]] 181 | name = "matches" 182 | version = "0.1.2" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | 185 | [[package]] 186 | name = "mime" 187 | version = "0.2.2" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | dependencies = [ 190 | "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 191 | ] 192 | 193 | [[package]] 194 | name = "num_cpus" 195 | version = "0.2.13" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | dependencies = [ 198 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 199 | ] 200 | 201 | [[package]] 202 | name = "openssl" 203 | version = "0.7.14" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | dependencies = [ 206 | "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 207 | "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", 208 | "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 209 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 210 | "openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)", 211 | "openssl-sys-extras 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)", 212 | ] 213 | 214 | [[package]] 215 | name = "openssl" 216 | version = "0.8.2" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | dependencies = [ 219 | "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 220 | "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 221 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 222 | "openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)", 223 | ] 224 | 225 | [[package]] 226 | name = "openssl-sys" 227 | version = "0.7.17" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | dependencies = [ 230 | "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 231 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 232 | "libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 233 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 234 | "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 235 | ] 236 | 237 | [[package]] 238 | name = "openssl-sys-extras" 239 | version = "0.7.14" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | dependencies = [ 242 | "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", 243 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 244 | "openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)", 245 | ] 246 | 247 | [[package]] 248 | name = "openssl-verify" 249 | version = "0.1.0" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | dependencies = [ 252 | "openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)", 253 | ] 254 | 255 | [[package]] 256 | name = "pkg-config" 257 | version = "0.3.8" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | 260 | [[package]] 261 | name = "pnacl-build-helper" 262 | version = "1.4.10" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | dependencies = [ 265 | "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 266 | ] 267 | 268 | [[package]] 269 | name = "rand" 270 | version = "0.3.14" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | dependencies = [ 273 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 274 | ] 275 | 276 | [[package]] 277 | name = "rustc-serialize" 278 | version = "0.3.19" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | 281 | [[package]] 282 | name = "rustc_version" 283 | version = "0.1.7" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | dependencies = [ 286 | "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", 287 | ] 288 | 289 | [[package]] 290 | name = "security-framework" 291 | version = "0.1.8" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | dependencies = [ 294 | "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 295 | "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 296 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 297 | "security-framework-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 298 | ] 299 | 300 | [[package]] 301 | name = "security-framework-sys" 302 | version = "0.1.8" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | dependencies = [ 305 | "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 306 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 307 | ] 308 | 309 | [[package]] 310 | name = "semver" 311 | version = "0.1.20" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | 314 | [[package]] 315 | name = "slack-hook" 316 | version = "0.1.3" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | dependencies = [ 319 | "curl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 320 | "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 321 | "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", 322 | ] 323 | 324 | [[package]] 325 | name = "small-logger" 326 | version = "0.2.1" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | dependencies = [ 329 | "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", 330 | "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", 331 | "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", 332 | ] 333 | 334 | [[package]] 335 | name = "solicit" 336 | version = "0.4.4" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | dependencies = [ 339 | "hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 340 | "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 341 | ] 342 | 343 | [[package]] 344 | name = "tempdir" 345 | version = "0.3.5" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | dependencies = [ 348 | "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 349 | ] 350 | 351 | [[package]] 352 | name = "time" 353 | version = "0.1.35" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | dependencies = [ 356 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 357 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 358 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 359 | ] 360 | 361 | [[package]] 362 | name = "traitobject" 363 | version = "0.0.1" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | 366 | [[package]] 367 | name = "typeable" 368 | version = "0.1.2" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | 371 | [[package]] 372 | name = "unicase" 373 | version = "1.4.0" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | dependencies = [ 376 | "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 377 | ] 378 | 379 | [[package]] 380 | name = "unicode-bidi" 381 | version = "0.2.3" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | dependencies = [ 384 | "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 385 | ] 386 | 387 | [[package]] 388 | name = "unicode-normalization" 389 | version = "0.1.2" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | 392 | [[package]] 393 | name = "url" 394 | version = "1.2.0" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | dependencies = [ 397 | "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 398 | "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 399 | ] 400 | 401 | [[package]] 402 | name = "user32-sys" 403 | version = "0.2.0" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | dependencies = [ 406 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 407 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 408 | ] 409 | 410 | [[package]] 411 | name = "winapi" 412 | version = "0.2.8" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | 415 | [[package]] 416 | name = "winapi-build" 417 | version = "0.1.1" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | 420 | [metadata] 421 | "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" 422 | "checksum cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e3d6405328b6edb412158b3b7710e2634e23f3614b9bb1c412df7952489a626" 423 | "checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd" 424 | "checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5" 425 | "checksum curl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "57c58544275bf49a13c61bdec09b2459e5f917d57a16fee556dc172f4b5f97fd" 426 | "checksum curl-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3da1d4b92dc22964e4b098c9e5863abfb9126d2c619bbeefb7eaa4ae63adbc5" 427 | "checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312" 428 | "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" 429 | "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" 430 | "checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58" 431 | "checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae" 432 | "checksum hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "eb27e8a3e8f17ac43ffa41bbda9cf5ad3f9f13ef66fa4873409d4902310275f7" 433 | "checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" 434 | "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 435 | "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" 436 | "checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f" 437 | "checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2" 438 | "checksum libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cbc058951ab6a3ef35ca16462d7642c4867e6403520811f28537a4e2f2db3e71" 439 | "checksum libz-sys 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ab80d82d16acfbf5c0e731297db302378896c0cffbc428dddc61d995a82e15cf" 440 | "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" 441 | "checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e" 442 | "checksum mime 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5c93a4bd787ddc6e7833c519b73a50883deb5863d76d9b71eb8216fb7f94e66" 443 | "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" 444 | "checksum openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "c4117b6244aac42ed0150a6019b4d953d28247c5dd6ae6f46ae469b5f2318733" 445 | "checksum openssl 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3b91dce772231efb76fc817068957b62b737e499794be05bbfbad356b8ccccf7" 446 | "checksum openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)" = "89c47ee94c352eea9ddaf8e364be7f978a3bb6d66d73176572484238dd5a5c3f" 447 | "checksum openssl-sys-extras 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "11c5e1dba7d3d03d80f045bf0d60111dc69213b67651e7c889527a3badabb9fa" 448 | "checksum openssl-verify 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed86cce894f6b0ed4572e21eb34026f1dc8869cb9ee3869029131bc8c3feb2d" 449 | "checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa" 450 | "checksum pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "61c9231d31aea845007443d62fcbb58bb6949ab9c18081ee1e09920e0cf1118b" 451 | "checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5" 452 | "checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b" 453 | "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" 454 | "checksum security-framework 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0b0fdc8ce5be3ef84c4d96ccb2303eddeeb03c513279c94fe692d1e19553d04e" 455 | "checksum security-framework-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "bf1f0e9f54b681c0b62c72ddc772a3558621a648e13a29dfc2ec1135f82f7d26" 456 | "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" 457 | "checksum slack-hook 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "28dad7bf216668b06569da0a8828bf60600ca30ccdb4210de3d17740b2cf9155" 458 | "checksum small-logger 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d1d5b2d7faddc9e59e6b460fefcbb572f348a729c0f112df32815732e2da94e0" 459 | "checksum solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "172382bac9424588d7840732b250faeeef88942e37b6e35317dce98cafdd75b2" 460 | "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" 461 | "checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af" 462 | "checksum traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07eaeb7689bb7fca7ce15628319635758eda769fed481ecfe6686ddef2600616" 463 | "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" 464 | "checksum unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a5906ca2b98c799f4b1ab4557b76367ebd6ae5ef14930ec841c74aed5f3764" 465 | "checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f" 466 | "checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" 467 | "checksum url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afe9ec54bc4db14bc8744b7fed060d785ac756791450959b2248443319d5b119" 468 | "checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" 469 | "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 470 | "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 471 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | version = "0.1.2" 3 | authors = ["Pierre Baillet "] 4 | 5 | name = "small-deployer" 6 | description = "A small git webhook server that can be used to trigger deploys. Send notification in slack." 7 | repository = "https://github.com/octplane/small-deployer" 8 | 9 | keywords = ["deploy", "github", "gitlab", "hook", "slack"] 10 | readme = "README.md" 11 | 12 | license= "MIT" 13 | 14 | [dependencies] 15 | rustc-serialize = "0.3" 16 | time = "~0.1.33" 17 | 18 | slack-hook = "0.1.2" 19 | small-logger = "0.2.0" 20 | openssl = "0.8.2" 21 | 22 | [dependencies.hyper] 23 | version = "0.9.10" 24 | features = ["security-framework"] 25 | 26 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM schickling/rust:latest 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y libcurl4-openssl-dev 5 | 6 | CMD /bin/bash 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Pierre Baillet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Small Deployer 2 | 3 | 4 | ![](assets/logo.png) 5 | 6 | 7 | 8 | This is a git webhook client in rust. It can be used to deploy your application automatically or anything you'd like to run after a commit. 9 | 10 | Current compatible with Github and Gitlab hooks. 11 | 12 | [![Clippy Linting Result](http://clippy.bashy.io/github/octplane/small-deployer/master/badge.svg)](http://clippy.bashy.io/github/octplane/small-deployer/master/log) 13 | 14 | # FEATURES 15 | 16 | - listens on /hook/ port 5000 for http requests 17 | - matches project name against configured project in config.json 18 | - runs the corresponding command and arguments as configured in config.json 19 | - dumps the result of this run in console, including stderr, stdout 20 | - can send the result of the the run on slack 21 | - allow at most one deploy per application at the same time: if there are two commits arriving at the same time, the second one will be put on hold until the first deploy has completed. Also, if two commits arrive during a deploy, the deployer will only deploy one more time, not twice. 22 | - support branch commits to deploy the same application with several branches 23 | 24 | 25 |
26 | 27 | # BUILD INSIDE DOCKER 28 | 29 | docker run --rm -it -v $(pwd):/source octplane/rust 30 | 31 | apt-get update && apt-get install -y libcurl4-gnutls-dev 32 | cargo build 33 | 34 | # RUN 35 | 36 | - cargo run 37 | 38 | # TEST 39 | 40 | Test a sample commit: 41 | 42 | curl -X POST -d @sample.json http://127.0.0.1:5000/hook/ 43 | 44 | # TODO 45 | 46 | - integrate with logger: 47 | - outputs: deploy preamble: 48 | - hook information (branch, commit, date, user) 49 | - pwd 50 | - starts web interface 51 | -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/octplane/small-deployer/ec22d4902a035774a0c605b6a2d4f965d9b90487/assets/logo.png -------------------------------------------------------------------------------- /config.json.sample: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": [{ 3 | "name": "Diaspora", 4 | "branch": "dev", 5 | "action": { 6 | "cmd": "ls", 7 | "parms": ["pipo"], 8 | "pwd": "." 9 | } 10 | }], 11 | "slack": { 12 | "webhook_url": "https://hooks.slack.com/services/T040LJ90Y/B04U5X/ZdcHYgx7XSsMBza5IG0kdcHYgFYPl", 13 | "channel": "#deploys", 14 | "username": "Deployr", 15 | "icon_url": "", 16 | "icon_emoji": ":computer:" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "before": "95790bf891e76fee5e1747ab589903a6a1f80f22", 3 | "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", 4 | "ref": "refs/heads/master", 5 | "user_id": 4, 6 | "user_name": "John Smith", 7 | "user_email": "john@example.com", 8 | "project_id": 15, 9 | "repository": { 10 | "name": "Diaspora", 11 | "url": "git@example.com:mike/diasporadiaspora.git", 12 | "description": "", 13 | "homepage": "http://example.com/mike/diaspora", 14 | "git_http_url":"http://example.com/mike/diaspora.git", 15 | "git_ssh_url":"git@example.com:mike/diaspora.git", 16 | "visibility_level":0 17 | }, 18 | "commits": [ 19 | { 20 | "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", 21 | "message": "Update Catalan translation to e38cb41.", 22 | "timestamp": "2011-12-12T14:27:31+02:00", 23 | "url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", 24 | "author": { 25 | "name": "Jordi Mallach", 26 | "email": "jordi@softcatala.org" 27 | } 28 | }, 29 | { 30 | "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", 31 | "message": "fixed readme", 32 | "timestamp": "2012-01-03T23:36:29+02:00", 33 | "url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", 34 | "author": { 35 | "name": "GitLab dev user", 36 | "email": "gitlabdev@dv6700.(none)" 37 | } 38 | } 39 | ], 40 | "total_commits_count": 4 41 | } 42 | -------------------------------------------------------------------------------- /src/deployer.rs: -------------------------------------------------------------------------------- 1 | use std::os::unix::prelude::*; 2 | use std::sync::mpsc::{TryRecvError, Receiver}; 3 | use std::convert::AsRef; 4 | use small_logger::runner; 5 | 6 | use std::ops::Sub; 7 | 8 | use time; 9 | 10 | use slack_hook::{Slack, Payload, PayloadTemplate}; 11 | use hook_configuration::{HookConfig, HookAction, SlackConfiguration}; 12 | use tools::to_string; 13 | 14 | #[derive(Clone)] 15 | #[allow(dead_code)] 16 | pub enum DeployMessage { 17 | Deploy(HookConfig), 18 | Exit, 19 | } 20 | 21 | pub struct Deployer { 22 | pub name: String, 23 | pub conf: HookAction, 24 | pub slack: Option, 25 | } 26 | 27 | impl Deployer { 28 | pub fn run(&self, rx: Receiver) { 29 | self.log("Starting deployer."); 30 | while { 31 | let deploy_instruction = rx.recv(); 32 | match deploy_instruction { 33 | Ok(DeployMessage::Deploy(_)) => { 34 | let mut extra_deploy_instruction; 35 | while { 36 | extra_deploy_instruction = rx.try_recv(); 37 | match extra_deploy_instruction { 38 | Ok(DeployMessage::Deploy(_)) => true, 39 | Ok(DeployMessage::Exit) => false, 40 | Err(TryRecvError::Empty) => false, 41 | Err(TryRecvError::Disconnected) => false, 42 | } 43 | } {} 44 | 45 | self.deploy(); 46 | true 47 | } 48 | Ok(DeployMessage::Exit) => false, 49 | Err(e) => { 50 | println!("Error: {}", e); 51 | false 52 | } 53 | } 54 | } {} 55 | self.log("Stopping deployer."); 56 | } 57 | 58 | fn deploy(&self) { 59 | let hk = self.conf.clone(); 60 | 61 | self.message(format!("Starting Deploy for {}.", self.name)); 62 | let r = runner::Runner; 63 | 64 | // FIXME: modify small-logger to get duration from inner runner. 65 | let start_time = time::now(); 66 | let status = r.run(&hk.cmd, 67 | hk.parms, 68 | "./logs".into(), 69 | format!("deployer_{}", self.name), 70 | Some(hk.pwd)); 71 | let end_time = time::now(); 72 | let duration = end_time.sub(start_time); 73 | 74 | match status { 75 | Ok(estatus) => { 76 | if estatus.success() { 77 | let log_message = format!(":sunny: {} deployed successfully in {}s.", 78 | self.name, 79 | duration.num_seconds()); 80 | self.log(log_message.as_ref()); 81 | self.message(log_message); 82 | } else { 83 | match estatus.code() { 84 | Some(exit_code) => { 85 | self.log(format!("Deploy failed with status {}.", exit_code).as_ref()); 86 | self.message(format!(":umbrella: {} deployed failed.", self.name)); 87 | } 88 | None => { 89 | match estatus.signal() { 90 | Some(signal_value) => { 91 | self.log(format!("Deploy was interrupted with signal {}.", 92 | signal_value) 93 | .as_ref()) 94 | } 95 | None => self.log("This should never happen."), 96 | } 97 | } 98 | } 99 | } 100 | } 101 | Err(e) => println!("An error occured: {:?}", e), 102 | } 103 | } 104 | 105 | fn log(&self, info: &str) { 106 | println!("[{}][{}][system] {}", 107 | to_string(time::now()), 108 | self.log_name(), 109 | info); 110 | } 111 | 112 | fn log_name(&self) -> String { 113 | format!("deployer-{}", self.name) 114 | } 115 | 116 | fn message(&self, message: String) { 117 | match self.slack { 118 | Some(ref conf) => { 119 | // http://www.emoji-cheat-sheet.com/ 120 | let slack = Slack::new(conf.webhook_url.as_ref()); 121 | let p = Payload::new(PayloadTemplate::Complete { 122 | text: Some(message.as_ref()), 123 | channel: Some(conf.channel.as_ref()), 124 | username: Some(conf.username.as_ref()), 125 | icon_url: match conf.icon_url { 126 | None => None, 127 | Some(ref s) => Some(s.as_ref()), 128 | }, 129 | icon_emoji: match conf.icon_emoji { 130 | None => None, 131 | Some(ref s) => Some(s.as_ref()), 132 | }, 133 | attachments: None, 134 | unfurl_links: Some(true), 135 | link_names: Some(false), 136 | }); 137 | 138 | match slack.send(&p) { 139 | Ok(()) => self.log("Sent notification to slack."), 140 | Err(x) => println!("ERR: {:?}", x), 141 | } 142 | } 143 | None => {} 144 | } 145 | 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/dispatcher.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::thread; 3 | 4 | use std::sync::mpsc::{Receiver, Sender, channel}; 5 | use time; 6 | use std::convert::AsRef; 7 | 8 | use hook_configuration::HookConfiguration; 9 | use deployer::{DeployMessage, Deployer}; 10 | use tools::to_string; 11 | 12 | pub struct Dispatcher { 13 | pub config: HookConfiguration, 14 | } 15 | 16 | impl Dispatcher { 17 | pub fn run(&self, rx: Receiver) { 18 | let mut to_workers: HashMap> = HashMap::new(); 19 | let mut workers: HashMap = HashMap::new(); 20 | for conf in &self.config.hooks { 21 | 22 | let worker = Deployer { 23 | name: conf.worker_name(), 24 | conf: conf.action.clone(), 25 | slack: (&self).config.slack.clone(), 26 | }; 27 | workers.insert(conf.worker_name(), worker); 28 | } 29 | 30 | for (name, worker) in workers.into_iter() { 31 | let (tx, rx) = channel(); 32 | to_workers.insert(name.clone(), tx); 33 | 34 | thread::spawn(move || { 35 | worker.run(rx); 36 | }); 37 | } 38 | 39 | self.log("Starting dispatcher."); 40 | while let Ok(data) = rx.recv() { 41 | match data { 42 | DeployMessage::Deploy(hk) => { 43 | let wname = hk.worker_name(); 44 | self.log(format!("Want to deploy {}.", wname).as_ref()); 45 | match to_workers.get(&wname).unwrap().send(DeployMessage::Deploy(hk)) { 46 | Err(e) => { 47 | println!("[{}][system] Send to deployer {} failed: {}.", 48 | to_string(time::now()), 49 | wname, 50 | e.to_string()) 51 | } 52 | _ => {} 53 | } 54 | } 55 | DeployMessage::Exit => println!("We should exit."), 56 | } 57 | } 58 | self.log("Stopping dispatcher."); 59 | } 60 | 61 | fn name(&self) -> String { 62 | "dispatcher".to_string() 63 | } 64 | 65 | fn log(&self, info: &str) { 66 | println!("[{}][{}][system] {}", 67 | to_string(time::now()), 68 | self.name(), 69 | info); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/hook_configuration.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Clone)] 3 | #[derive(RustcDecodable)] 4 | pub struct HookConfiguration { 5 | pub hooks: Vec, 6 | pub slack: Option, 7 | } 8 | 9 | #[derive(Clone)] 10 | #[derive(RustcDecodable)] 11 | pub struct SlackConfiguration { 12 | pub webhook_url: String, 13 | pub channel: String, 14 | pub username: String, 15 | pub icon_url: Option, 16 | pub icon_emoji: Option, 17 | } 18 | 19 | #[derive(Clone)] 20 | #[derive(RustcDecodable)] 21 | pub struct HookConfig { 22 | pub name: String, 23 | pub branch: Option, 24 | pub action: HookAction, 25 | } 26 | 27 | impl HookConfig { 28 | pub fn worker_name(&self) -> String { 29 | let b = self.branch.clone().unwrap_or("all".to_string()); 30 | format!("{}-{}", self.name, b) 31 | } 32 | } 33 | 34 | #[derive(Clone)] 35 | #[derive(RustcDecodable)] 36 | pub struct HookAction { 37 | pub cmd: String, 38 | pub parms: Vec, 39 | pub pwd: String, 40 | } 41 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(custom_attribute, custom_derive, plugin)] 2 | 3 | extern crate hyper; 4 | extern crate time; 5 | extern crate slack_hook; 6 | extern crate rustc_serialize; 7 | extern crate small_logger; 8 | 9 | use std::io::prelude::*; 10 | use std::fs::File; 11 | use std::thread; 12 | use std::convert::AsRef; 13 | 14 | use hyper::server::Server; 15 | use hyper::server::Request; 16 | use hyper::server::Response; 17 | use hyper::uri::RequestUri; 18 | use hyper::net::Fresh; 19 | use hyper::server::Handler; 20 | use std::path::Path; 21 | 22 | use std::sync::{Mutex, Arc}; 23 | use std::sync::mpsc::{Sender, channel}; 24 | 25 | use rustc_serialize::json::Json; 26 | use rustc_serialize::json; 27 | 28 | use dispatcher::Dispatcher; 29 | use hook_configuration::HookConfiguration; 30 | use deployer::DeployMessage; 31 | 32 | mod hook_configuration; 33 | mod dispatcher; 34 | mod deployer; 35 | mod tools; 36 | 37 | pub struct GitHook { 38 | content: Json, 39 | } 40 | 41 | impl GitHook { 42 | fn repository_name(&self) -> &str { 43 | let path = ["repository", "name"]; 44 | self.content.find_path(&path).unwrap().as_string().unwrap() 45 | } 46 | fn reference(&self) -> &str { 47 | self.content.find("ref").unwrap().as_string().unwrap() 48 | } 49 | fn branch(&self) -> &str { 50 | self.reference().trim_left_matches("refs/heads/") 51 | } 52 | } 53 | 54 | pub struct Daemon { 55 | intercom: Arc>>, 56 | config: HookConfiguration, 57 | } 58 | 59 | impl Handler for Daemon { 60 | fn handle(&self, req: Request, res: Response) { 61 | 62 | let mut s = String::new(); 63 | let mut myreq = req; 64 | if myreq.uri == RequestUri::AbsolutePath("/hook/".to_string()) { 65 | match myreq.read_to_string(&mut s) { 66 | Ok(_) => { 67 | println!("Got payload {}", s); 68 | let decode = Json::from_str(s.as_ref()); 69 | 70 | match decode { 71 | Ok(decoded) => { 72 | let gh = GitHook { content: decoded }; 73 | 74 | let repo_name = gh.repository_name(); 75 | let branch = gh.branch(); 76 | 77 | match self.config 78 | .hooks 79 | .iter() 80 | .filter(|&binding| if repo_name == binding.name { 81 | match binding.branch.clone() { 82 | Some(target_branch) => branch == target_branch, 83 | None => true, 84 | } 85 | } else { 86 | false 87 | }) 88 | .next() { 89 | Some(hk) => { 90 | let _ = self.intercom 91 | .lock() 92 | .unwrap() 93 | .send(DeployMessage::Deploy(hk.clone())); 94 | } 95 | None => println!("No hook for {}/{}", repo_name, branch), 96 | } 97 | } 98 | Err(e) => { 99 | println!("Error while parsing http: {:?}", e); 100 | println!("{}", s); 101 | } 102 | } 103 | } 104 | _ => {} 105 | } 106 | } 107 | 108 | let mut res = res.start().unwrap(); 109 | res.write_all(b"OK.").unwrap(); 110 | res.end().unwrap(); 111 | } 112 | } 113 | 114 | 115 | pub fn main() { 116 | 117 | let mut json_config = String::new(); 118 | 119 | let config_location = &Path::new("config.json"); 120 | 121 | match File::open(config_location) { 122 | Err(err) => { 123 | panic!("Error during config file read: {:?}. {}", 124 | config_location, 125 | err.to_string()) 126 | } 127 | Ok(icf) => { 128 | let mut config_file = icf; 129 | config_file.read_to_string(&mut json_config).ok().unwrap() 130 | } 131 | }; 132 | 133 | let config: HookConfiguration = match json::decode(json_config.as_ref()) { 134 | Err(err) => { 135 | println!("Error while parsing config file:"); 136 | println!("{}", err); 137 | println!("{}", json_config); 138 | panic!("Sorry."); 139 | } 140 | Ok(content) => content, 141 | }; 142 | 143 | let (tx, rx) = channel(); 144 | 145 | let dispatcher = Dispatcher { config: config.clone() }; 146 | thread::spawn(move || { 147 | dispatcher.run(rx); 148 | }); 149 | let handler = Daemon { 150 | config: config, 151 | intercom: Arc::new(Mutex::new(tx)), 152 | }; 153 | 154 | let port = 5000; 155 | println!("Starting up, listening on port {}.", port); 156 | let _ = Server::http(format!("127.0.0.1:{}", port).as_str()).unwrap().handle(handler); 157 | 158 | } 159 | -------------------------------------------------------------------------------- /src/tools.rs: -------------------------------------------------------------------------------- 1 | use time; 2 | 3 | pub fn to_string(ti: time::Tm) -> String { 4 | let format = "%Y-%m-%d %T.%f"; 5 | let mut ts = time::strftime(format, &ti).ok().unwrap(); 6 | let l = ts.len(); 7 | ts.truncate(l - 6); 8 | ts 9 | } 10 | --------------------------------------------------------------------------------