check-license-header.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // Copyright 2019-2023 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. const fs = require('fs')
  5. const path = require('path')
  6. const readline = require('readline')
  7. const header = `Copyright 2019-2023 Tauri Programme within The Commons Conservancy
  8. SPDX-License-Identifier: Apache-2.0
  9. SPDX-License-Identifier: MIT`
  10. const bundlerLicense = '// Copyright 2016-2019 Cargo-Bundle developers <https://github.com/burtonageo/cargo-bundle>'
  11. const extensions = ['.rs', '.js', '.ts', '.yml']
  12. const ignore = ['target', 'templates', 'node_modules', 'gen', 'dist', 'bundle.js', 'bundle.global.js']
  13. async function checkFile(file) {
  14. if (extensions.some(e => file.endsWith(e))) {
  15. const fileStream = fs.createReadStream(file)
  16. const rl = readline.createInterface({
  17. input: fileStream,
  18. crlfDelay: Infinity
  19. })
  20. let contents = ``
  21. let i = 0
  22. for await (let line of rl) {
  23. // ignore empty lines, allow shebang and bundler license
  24. if (line.length === 0 || line.startsWith("#!") || line === bundlerLicense) {
  25. continue
  26. }
  27. // strip comment marker
  28. if (line.startsWith('// ')) {
  29. line = line.substring(3)
  30. } else if (line.startsWith('# ')) {
  31. line = line.substring(2)
  32. }
  33. contents += line
  34. if (++i === 3) {
  35. break
  36. }
  37. contents += '\n'
  38. }
  39. if (contents !== header) {
  40. return true
  41. }
  42. }
  43. return false
  44. }
  45. async function check(src) {
  46. const missingHeader = []
  47. for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
  48. const p = path.join(src, entry.name)
  49. if (entry.isSymbolicLink() || ignore.includes(entry.name)) {
  50. continue
  51. }
  52. if (entry.isDirectory()) {
  53. const missing = await check(p)
  54. missingHeader.push(...missing)
  55. } else {
  56. const isMissing = await checkFile(p)
  57. if (isMissing) {
  58. missingHeader.push(p)
  59. }
  60. }
  61. }
  62. return missingHeader
  63. }
  64. const [_bin, _script, ...files] = process.argv
  65. if (files.length > 0) {
  66. async function run() {
  67. const missing = []
  68. for (const f of files) {
  69. const isMissing = await checkFile(f)
  70. if (isMissing) {
  71. missing.push(f)
  72. }
  73. }
  74. if (missing.length > 0) {
  75. console.log(missing.join('\n'))
  76. process.exit(1)
  77. }
  78. }
  79. run()
  80. } else {
  81. check('.').then(missing => {
  82. if (missing.length > 0) {
  83. console.log(missing.join('\n'))
  84. process.exit(1)
  85. }
  86. })
  87. }