summaryrefslogtreecommitdiffstats
path: root/git-difme.scm
blob: d696085370082648990d21bfe690d7f18f29a6e0 (plain) (blame)
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
112
113
114
115
116
117
118
119
120
121
122
;; coding: utf-8
;; license: gnu gpl version 3 or higher.
;; copyright 2016 rsiddharth <s@ricketyspace.net>

(define-module (git-difme)
  #:use-module (ice-9 popen)
  #:use-module (ice-9 rdelim)
  #:export (main))

;;;; utils

;;; following macro from (guix build utils) module.
;;; copyright 2012 Ludovic Courtès <ludo@gnu.org>
;;; commit b0e0d0e99f

(define-syntax-rule (with-directory-excursion dir body ...)
  "run BODY with DIR as the process's current directory."
  (let ((init (getcwd)))
    (dynamic-wind
      (lambda () (chdir dir))
      (lambda () body ...)
      (lambda () (chdir init)))))

(define (difme-exec cmd)
  "execute CMD and return output as a list of strings."
  (let* ((port (open-input-pipe cmd))
         (out (read-string port))
         (out-lst (map string-trim-both
                       (delete "" (string-split out #\newline)))))
    (close-pipe port)
    out-lst))

;;;; configuration
(define (load-config path)
  "load configuration file from PATH.

errors out if PATH does not exists."
  (if (file-exists? path)
      (load path)
      (error "config not found at" path)))

(define (get-config-path)
  "return configuration file path as a string."
  (string-append (getenv "HOME") "/.config/git-difme/config"))

(define (get-difme-repos)
  "return difme repos returned by `difme-repos` function.

`difme-repos` is defined in the configuration file; this function
loads the configuration file and then evals the `difme-repos`
function."
  (let ((path (get-config-path)))
    (load-config path)
    (eval '(difme-repos) (interaction-environment))))

;;;; git interfaces
(define (staged-files repo)
  "return list of staged files in REPO."
  (let ((cmd "git diff --name-only --cached"))
    (with-directory-excursion repo
      (difme-exec cmd))))

(define (difme-status repo)
  "do `git status` on the REPO and return output as a list.

if the output from `git status` is:

 M .asoundrc
 D .config/i3/config

the returned list will be in the following format:

     ((\"M\" . \".asoundrc\") (\"D\" . \".config/i3/config\"))

if there is no output from `git status`, then an empty list will be
returned."
  (let ((cmd "git status --porcelain"))
    (define (process line)
      (let* ((parts (string-split line #\space))
             (type (car parts))
             (file (cadr parts)))
        (cons type file)))
    (with-directory-excursion repo
      (map process (difme-exec cmd)))))

(define (difme-stage repo file)
"stage FILE in REPO."
  (let ((cmd (string-append "git add " file)))
    (with-directory-excursion repo
      (difme-exec cmd))))

(define (difme-commit repo msg)
"do `git commit` on REPO.

the commit message will be MSG followed by a list of files staged for
this commit.

if files `foo.org`, `bar.scm` and `frob.el` are staged for the commit,
the commit message will be in the following format:

    MSG

    files:
    - foo.org
    - bar.scm
    - frob.el"
  (let* ((msg (string-append
               msg "\n\nfiles:\n - "
               (string-join (staged-files repo) "\n - ")))
        (cmd (string-append "git commit -m '" msg "'")))
    (with-directory-excursion repo
      (difme-exec cmd))))

(define (difme-push repo)
  "do `git push` REPO to its default upstream remote."
  (let ((cmd "git push"))
    (with-directory-excursion repo
      (difme-exec cmd))))

;;;; main
(define (main srcs)
  srcs)