.run-format.zsh 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. #!/usr/bin/env zsh
  2. builtin emulate -L zsh
  3. setopt EXTENDED_GLOB
  4. setopt PUSHD_SILENT
  5. setopt ERR_EXIT
  6. setopt ERR_RETURN
  7. setopt NO_UNSET
  8. setopt PIPE_FAIL
  9. setopt NO_AUTO_PUSHD
  10. setopt NO_PUSHD_IGNORE_DUPS
  11. setopt FUNCTION_ARGZERO
  12. ## Enable for script debugging
  13. # setopt WARN_CREATE_GLOBAL
  14. # setopt WARN_NESTED_VAR
  15. # setopt XTRACE
  16. autoload -Uz is-at-least && if ! is-at-least 5.2; then
  17. print -u2 -PR "%F{1}${funcstack[1]##*/}:%f Running on Zsh version %B${ZSH_VERSION}%b, but Zsh %B5.2%b is the minimum supported version. Upgrade zsh to fix this issue."
  18. exit 1
  19. fi
  20. invoke_formatter() {
  21. if (( # < 1 )) {
  22. log_error "Usage invoke_formatter [formatter_name]"
  23. exit 2
  24. }
  25. local formatter="${1}"
  26. shift
  27. local -a source_files=(${@})
  28. case ${formatter} {
  29. clang)
  30. if (( ${+commands[clang-format-19]} )) {
  31. local formatter=clang-format-19
  32. } elif (( ${+commands[clang-format]} )) {
  33. local formatter=clang-format
  34. } else {
  35. log_error "No viable clang-format version found (required 19.1.1)"
  36. exit 2
  37. }
  38. local -a formatter_version=($(${formatter} --version))
  39. if ! is-at-least 19.1.1 ${formatter_version[-1]}; then
  40. log_error "clang-format is not version 19.1.1 or above (found ${formatter_version[-1]}."
  41. exit 2
  42. fi
  43. if ! is-at-least ${formatter_version[-1]} 19.1.1; then
  44. log_error "clang-format is more recent than version 19.1.1 (found ${formatter_version[-1]})."
  45. exit 2
  46. fi
  47. if (( ! #source_files )) source_files=((libobs|libobs-*|frontend|plugins|deps|shared)/**/*.(c|cpp|h|hpp|m|mm)(.N))
  48. source_files=(${source_files:#*/(obs-websocket/deps|decklink/*/decklink-sdk|mac-syphon/syphon-framework|libdshowcapture)/*})
  49. local -a format_args=(-style=file -fallback-style=none)
  50. if (( _loglevel > 2 )) format_args+=(--verbose)
  51. check_files() {
  52. local -i num_failures=0
  53. local -a source_files=($@)
  54. local file
  55. local -a format_args=(-style=file -fallback-style=none)
  56. if (( _loglevel > 2 )) format_args+=(--verbose)
  57. local -a command=(${formatter} ${format_args})
  58. for file (${source_files}) {
  59. if ! ${command} "${file}" | diff -q "${file}" - &> /dev/null; then
  60. log_error "${file} requires formatting changes."
  61. if (( fail_on_error == 2 )) return 2;
  62. num_failures=$(( num_failures + 1 ))
  63. fi
  64. }
  65. if (( num_failures && fail_on_error == 1 )) return 2
  66. }
  67. format_files() {
  68. local -a source_files=($@)
  69. if (( ${#source_files} )) {
  70. local -a format_args=(-style=file -fallback-style=none -i)
  71. if (( _loglevel > 2 )) format_args+=(--verbose)
  72. "${formatter}" ${format_args} ${source_files}
  73. }
  74. }
  75. ;;
  76. gersemi)
  77. local formatter=gersemi
  78. if (( ${+commands[gersemi]} )) {
  79. local gersemi_version=($(gersemi --version))
  80. if ! is-at-least 0.12.0 ${gersemi_version[2]}; then
  81. log_error "gersemi is not version 0.12.0 or above (found ${gersemi_version[2]}."
  82. exit 2
  83. fi
  84. }
  85. if (( ! #source_files )) source_files=(CMakeLists.txt (libobs|libobs-*|frontend|plugins|deps|shared|cmake|test)/**/(CMakeLists.txt|*.cmake)(.N))
  86. source_files=(${source_files:#*/(jansson|decklink/*/decklink-sdk|obs-websocket|obs-browser|libdshowcapture)/*})
  87. source_files=(${source_files:#(cmake/Modules/*|*/legacy.cmake)})
  88. check_files() {
  89. local -i num_failures=0
  90. local -a source_files=($@)
  91. local file
  92. local -a command=(${formatter} -c --no-cache ${source_files})
  93. if (( ${#source_files} )) {
  94. while read -r line; do
  95. local -a line_tokens=(${(z)line})
  96. file=${line_tokens[1]//*obs-studio\//}
  97. log_error "${file} requires formatting changes."
  98. if (( fail_on_error == 2 )) return 2
  99. num_failures=$(( num_failures + 1 ))
  100. done < <(${command} 2>&1)
  101. if (( num_failures && fail_on_error == 1 )) return 2
  102. }
  103. }
  104. format_files() {
  105. local -a source_files=($@)
  106. if (( ${#source_files} )) {
  107. "${formatter}" -i ${source_files}
  108. }
  109. }
  110. ;;
  111. swift)
  112. local formatter=swift-format
  113. if (( ${+commands[swift-format]} )) {
  114. local swift_format_version=$(swift-format --version)
  115. if ! is-at-least 508.0.0 ${swift_format_version}; then
  116. log_error "swift-format is not version 508.0.0 or above (found ${swift_format_version})."
  117. exit 2
  118. fi
  119. } else {
  120. log_error "No viable swift-format version found (required 508.0.0)"
  121. exit 2
  122. }
  123. if (( ! #source_files )) source_files=((libobs|libobs-*|frontend|plugins)/**/*.swift(.N))
  124. check_files() {
  125. local -i num_failures=0
  126. local -a source_files=($@)
  127. local file
  128. local -a format_args=()
  129. local -a command=(${formatter} ${format_args})
  130. for file (${source_files}) {
  131. if ! "${command}" "${file}" | diff -q "${file}" - &> /dev/null; then
  132. log_error "${file} requires formatting changes."
  133. if (( fail_on_error == 2 )) return 2;
  134. num_failures=$(( num_failures + 1 ))
  135. fi
  136. }
  137. if (( num_failures && fail_on_error == 1 )) return 2
  138. }
  139. format_files() {
  140. local -a source_files=($@)
  141. if (( ${#source_files} )) {
  142. local -a format_args=(-i)
  143. "${formatter}" ${format_args} ${source_files}
  144. }
  145. }
  146. ;;
  147. *) log_error "Invalid formatter specified: ${1}. Valid options are clang-format, gersemi, and swift-format."; exit 2 ;;
  148. }
  149. local file
  150. local -i num_failures=0
  151. if (( check_only )) {
  152. if (( ${+functions[check_files]} )) {
  153. check_files ${source_files}
  154. } else {
  155. log_error "No format check function defined for formatter '${formatter}'"
  156. exit 2
  157. }
  158. } else {
  159. if (( ${+functions[format_files]} )) {
  160. format_files ${source_files}
  161. } else {
  162. log_error "No format function defined for formatter '${formatter}'"
  163. exit 2
  164. }
  165. }
  166. }
  167. run_format() {
  168. if (( ! ${+SCRIPT_HOME} )) typeset -g SCRIPT_HOME=${ZSH_ARGZERO:A:h}
  169. if (( ! ${+FORMATTER_NAME} )) typeset -g FORMATTER_NAME=${${(s:-:)ZSH_ARGZERO:t:r}[2]}
  170. typeset -g host_os=${${(L)$(uname -s)}//darwin/macos}
  171. local -i fail_on_error=0
  172. local -i check_only=0
  173. local -i verbosity=1
  174. local -r _version='1.0.0'
  175. fpath=("${SCRIPT_HOME}/.functions" ${fpath})
  176. autoload -Uz set_loglevel log_info log_error log_output log_status log_warning
  177. local -r _usage="
  178. Usage: %B${functrace[1]%:*}%b <option>
  179. %BOptions%b:
  180. %F{yellow} Formatting options%f
  181. -----------------------------------------------------------------------------
  182. %B-c | --check%b Check only, no actual formatting takes place
  183. %F{yellow} Output options%f
  184. -----------------------------------------------------------------------------
  185. %B-v | --verbose%b Verbose (more detailed output)
  186. %B--fail-[never|error] Fail script never/on formatting change - default: %B%F{green}never%f%b
  187. %B--debug%b Debug (very detailed and added output)
  188. %F{yellow} General options%f
  189. -----------------------------------------------------------------------------
  190. %B-h | --help%b Print this usage help
  191. %B-V | --version%b Print script version information"
  192. local -a args
  193. while (( # )) {
  194. case ${1} {
  195. -c|--check) check_only=1; shift ;;
  196. -v|--verbose) (( verbosity += 1 )); shift ;;
  197. -h|--help) log_output ${_usage}; exit 0 ;;
  198. -V|--version) print -Pr "${_version}"; exit 0 ;;
  199. --debug) verbosity=3; shift ;;
  200. --fail-never)
  201. fail_on_error=0
  202. shift
  203. ;;
  204. --fail-error)
  205. fail_on_error=1
  206. shift
  207. ;;
  208. --fail-fast)
  209. fail_on_error=2
  210. shift
  211. ;;
  212. *)
  213. args+=($@)
  214. break
  215. ;;
  216. }
  217. }
  218. set -- ${(@)args}
  219. set_loglevel ${verbosity}
  220. invoke_formatter ${FORMATTER_NAME} ${args}
  221. }
  222. run_format ${@}