aboutsummaryrefslogtreecommitdiff
path: root/hooked/src/main.rs
blob: 7e3349921dab2f50f29f12533c5dd772af81c53f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! git hook manager tool

#[cfg(windows)]
use anyhow::bail;
use anyhow::Result;
use log::*;
use shared::find_root;
#[cfg(not(windows))]
use std::os::unix::fs::{
  symlink,
  PermissionsExt,
};
#[cfg(windows)]
use std::os::windows::fs::symlink_file;
use std::{
  env,
  fs,
  io::Write,
};

const HOOKS: [&str; 18] = [
  "applypatch-msg",
  "post-applypatch",
  "pre-commit",
  "prepare-commit-msg",
  "commit-msg",
  "post-commit",
  "pre-rebase",
  "post-checkout",
  "post-merge",
  "pre-push",
  "pre-receive",
  "update",
  "post-receive",
  "post-update",
  "push-to-checkout",
  "pre-auto-gc",
  "post-rewrite",
  "sendemail-validate",
];

#[derive(structopt::StructOpt)]
enum Args {
  /// Initialize the repo to use ticket
  Init,
}

#[paw::main]
fn main(args: Args) {
  env::var("RUST_LOG")
    .ok()
    .map_or_else(|| env::set_var("RUST_LOG", "info"), drop);
  pretty_env_logger::init();
  if let Err(e) = match args {
    Args::Init => init(),
  } {
    error!("{}", e);
    std::process::exit(1);
  }
}

fn init() -> Result<()> {
  #[cfg(windows)]
  bail!("Windows is currently unsupported!");

  let root = find_root()?;
  let git_hooks = &root.join(".git").join("hooks");
  debug!("git_hooks base path: {}", git_hooks.display());
  let root = root.join(".dev-suite").join("hooked");
  debug!("root base path: {}", root.display());
  fs::create_dir_all(&root)?;

  for hook in &HOOKS {
    let path = &root.join(hook);
    debug!("dev-suite hook path: {}", path.display());
    let git_hook = &git_hooks.join(hook);
    debug!("git_hook path: {}", git_hook.display());

    if path.exists() {
      debug!("git hook {} already exists. Skipping creation.", hook);
    } else {
      debug!("Creating dev-suite hook.");
      let mut file = fs::File::create(&path)?;
      trace!("File created.");
      let mut perms = file.metadata()?.permissions();
      debug!("Setting dev-suite hook to be executable.");
      perms.set_mode(0o755);
      file.set_permissions(perms)?;
      trace!("Permissions were set.");
      file.write_all(b"#! /bin/bash")?;
      debug!("Writing data to file.");
      debug!("Created git hook {}.", hook);
    }
    let path = path.canonicalize()?;

    if !git_hook.exists() {
      debug!("Symlinking git hook {}.", hook);
      #[cfg(not(windows))]
      symlink(&path, &git_hook)?;
      #[cfg(windows)]
      symlink_file(&path, &git_hook)?;
      trace!("Symlinked git hook {} to .dev-suite/hooked/{}.", hook, hook);
    }
  }
  info!(
    "Created and symlinked tickets to .git/hooks from {}.",
    root.display()
  );

  Ok(())
}