executable_src-clean 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #!/usr/bin/env -S guile --no-auto-compile -e (src-clean) -s
  2. !#
  3. ;;;; src-clean --- Guile script which cleans up src directory
  4. ;;;; Copyright © 2020 Oleg Pykhalov <go.wigust@gmail.com>
  5. ;;;; Released under the GNU GPLv3 or any later version.
  6. (define-module (src-clean)
  7. #:use-module (ice-9 format)
  8. #:use-module (ice-9 ftw)
  9. #:use-module (ice-9 match)
  10. #:use-module (ice-9 popen)
  11. #:use-module (ice-9 popen)
  12. #:use-module (ice-9 rdelim)
  13. #:use-module (srfi srfi-1)
  14. #:use-module (srfi srfi-26)
  15. #:use-module (srfi srfi-37)
  16. #:export (main))
  17. ;;; Commentary:
  18. ;;;
  19. ;;; This script only depends on Guile, which you could get either with Guix:
  20. ;;; guix environment --ad-hoc guile
  21. ;;; or Nix:
  22. ;;; nix-shell -p guile git
  23. ;;;
  24. ;;; src-clean --directory=src --author=go.wigust@gmail.com --ignore=dotfiles,rofi-themes
  25. ;;;
  26. ;;; Code:
  27. (define %options
  28. (let ((display-and-exit-proc (lambda (msg)
  29. (lambda (opt name arg loads)
  30. (display msg) (quit)))))
  31. (list (option '(#\v "version") #f #f
  32. (display-and-exit-proc "src-clean version 0.0.1\n"))
  33. (option '(#\a "author") #t #f
  34. (lambda (opt name arg result)
  35. (alist-cons 'author arg result)))
  36. (option '(#\d "directory") #t #f
  37. (lambda (opt name arg result)
  38. (alist-cons 'directory arg result)))
  39. (option '(#\i "ignore") #t #f
  40. (lambda (opt name arg result)
  41. (alist-cons 'ignore arg result)))
  42. (option '(#\h "help") #f #f
  43. (display-and-exit-proc
  44. "Usage: src-clean ...")))))
  45. (define %default-options
  46. '())
  47. (define (system->string . args)
  48. (let* ((port (apply open-pipe* OPEN_READ args))
  49. (output (read-string port)))
  50. (close-pipe port)
  51. output))
  52. (define %cache-file
  53. (and=> (getenv "HOME")
  54. (lambda (home)
  55. (string-append home "/.cache/src-clean.txt"))))
  56. (define (git-origins directory)
  57. (map (cut string-split <> #\tab)
  58. (string-split (string-trim-right (system->string "git" "-C" directory
  59. "remote" "--verbose"))
  60. #\newline)))
  61. (define (main args)
  62. (define opts
  63. (args-fold (cdr (program-arguments))
  64. %options
  65. (lambda (opt name arg loads)
  66. (error "Unrecognized option `~A'" name))
  67. (lambda (op loads)
  68. (cons op loads))
  69. %default-options))
  70. (define author
  71. (assoc-ref opts 'author))
  72. (define ignore
  73. (and=> (assoc-ref opts 'ignore)
  74. (lambda (ignore)
  75. (string-split (assoc-ref opts 'ignore) #\,))))
  76. (define cache
  77. (open-file %cache-file "a"))
  78. (define cache-existing
  79. (string-split (with-input-from-file %cache-file read-string) #\newline))
  80. (define directories
  81. (let ((directories (let ((directory (assoc-ref opts 'directory)))
  82. (match (scandir directory)
  83. (("." ".." files ...)
  84. (map (cut string-append directory "/" <>)
  85. files))))))
  86. (if ignore
  87. (fold (lambda (directory directories)
  88. (if (any (cut string= directory <>)
  89. (append ignore cache-existing))
  90. directories
  91. (cons directory directories)))
  92. '() directories)
  93. directories)))
  94. (setenv "PAGER" "")
  95. (for-each (lambda (directory)
  96. (format #t "Checking ~s directory...~%" directory)
  97. (if (any (cut string= ".git" <>)
  98. (match (scandir directory)
  99. (("." ".." file ...) file)))
  100. (let ((output (system->string "git" "-C" directory
  101. "log" "--all" "--format=%H"
  102. (string-append "--author=" author))))
  103. (cond ((string-null? output)
  104. (format #t "~s repository does not contain ~a commits.~%" directory author)
  105. (system* "git" "-C" directory "status")
  106. (exit 1))
  107. ((equal? '("") (git-origins directory))
  108. (format #t "No remotes in ~s repository.~%"
  109. directory)
  110. (exit 1))
  111. ((let ((origin (assoc-ref "origin" (git-origins directory))))
  112. (and origin
  113. (string-prefix? "https://github.com/"
  114. origin)))
  115. (format #t "origin's remote in ~s repository is GitHub.~%"
  116. directory)
  117. (exit 1))
  118. ((not (assoc "github" (git-origins directory)))
  119. (format #t "No github remote in ~s repository.~%"
  120. directory)
  121. (exit 1))
  122. (else (with-output-to-port cache
  123. (lambda ()
  124. (display directory)
  125. (newline))))))
  126. ;; TODO: Output to STDERR
  127. (begin (format #t "~s directory is not a Git repository.~%" directory)
  128. (exit 1))))
  129. directories))
  130. ;;; src-clean ends here