metadata.sh 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #!/usr/bin/env bash
  2. set -Eeuo pipefail
  3. workdir="$(readlink -f "$BASH_SOURCE")"
  4. workdir="$(dirname "$workdir")"
  5. cd "$workdir"
  6. jsonFile='metadata.json'
  7. canonicalMetadataFile="./$jsonFile"
  8. export maxCategories=3
  9. self="$(basename "$0")"
  10. usage() {
  11. cat <<EOUSAGE
  12. usage: $self [--write] REPO[...]
  13. eg: $self debian
  14. $self -w python
  15. This script checks a givens repo's metadata.json. It checks formating (providing a diff), checks categories, and can write the formatting changes.
  16. -h, --help Print this help output and exit.
  17. -w, --write Apply json formatting (run without to see the diff that would be applied).
  18. Arguments are the list of repos with a 'metadata.json' in them. 'metadata.json' is expected in every repo.
  19. '.' can also be passed to check the format of the canonical './metadata.json' at
  20. the root of the repo, but the max categories of '-c' is skipped for it.
  21. EOUSAGE
  22. }
  23. # arg handling
  24. opts="$(getopt -o 'hw' --long 'help,write' -- "$@" || { usage >&2 && false; })"
  25. eval set -- "$opts"
  26. write=
  27. while :; do
  28. flag="$1"
  29. shift
  30. case "$flag" in
  31. --help | -h) usage && exit 0 ;;
  32. --write | -w) write=1 ;;
  33. --) break ;;
  34. *)
  35. {
  36. echo "error: unknown flag: $flag"
  37. usage
  38. } >&2
  39. exit 1
  40. ;;
  41. esac
  42. done
  43. repos=( "$@" )
  44. if [ "${#repos[@]}" -eq 0 ]; then
  45. repos=( */ )
  46. fi
  47. repos=( "${repos[@]%/}" )
  48. failures=0
  49. for repo in "${repos[@]}"; do
  50. repoFile="$repo/$jsonFile"
  51. if [ ! -s "$repoFile" ]; then
  52. echo >&2 "error: $repoFile does not exist or is empty"
  53. (( failures++ )) || :
  54. continue
  55. fi
  56. # sort object keys and pretty print with jq as our "cannonical json"
  57. # sort categories array, no duplicates
  58. if ! repoFileJson="$(jq -s --sort-keys '.[0] | .hub.categories |= unique' "$repoFile")"; then
  59. echo >&2 "error parsing '$repoFile'; invalid JSON?"
  60. (( failures++ )) || :
  61. continue
  62. fi
  63. if ! filediff="$(diff -u "$repoFile" <(cat <<<"$repoFileJson"))"; then
  64. cat <<<"$filediff"
  65. if [ -n "$write" ]; then
  66. cat <<<"$repoFileJson" > "$repoFile"
  67. else
  68. (( failures++ )) || :
  69. fi
  70. fi
  71. # TODO also check for required keys and/or types?
  72. # the canonicalMetadataFile doesn't have too many categories since it is the source of categories
  73. # all other metadata.json files must not be more than maxCategories or have categories that aren't in the canonical set
  74. if [ "$repoFile" != "$canonicalMetadataFile" ]; then
  75. export repoFile
  76. if errorText="$(jq -r --slurpfile canonical "$canonicalMetadataFile" '
  77. .hub.categories
  78. | (
  79. length
  80. | if . > (env.maxCategories | tonumber) then
  81. "error: \(env.repoFile): too many categories: \(.) (max \(env.maxCategories))"
  82. else empty end
  83. ),
  84. (
  85. . - $canonical[0].hub.categories
  86. | if length > 0 then
  87. "error: \(env.repoFile): unknown categories \(.)"
  88. else empty end
  89. )
  90. ' "$repoFile")"; then
  91. if [ -n "$errorText" ]; then
  92. echo >&2 "$errorText"
  93. (( failures++ )) || :
  94. fi
  95. else
  96. echo >&2 "error parsing '$repoFile'; invalid JSON?"
  97. (( failures++ )) || :
  98. continue
  99. fi
  100. fi
  101. done
  102. exit "$failures"