Browse Source

build: add basic linting for the patches folder to ensure that .patches match the state on disk (#18615)

Samuel Attard 5 years ago
parent
commit
00d18917d0
1 changed files with 51 additions and 3 deletions
  1. 51 3
      script/lint.js

+ 51 - 3
script/lint.js

@@ -133,12 +133,60 @@ const LINTERS = [ {
       process.exit(1)
     }
   }
+}, {
+  key: 'patches',
+  roots: ['patches'],
+  test: () => true,
+  run: () => {
+    const patchesDir = path.resolve(__dirname, '../patches')
+    for (const patchTarget of fs.readdirSync(patchesDir)) {
+      const targetDir = path.resolve(patchesDir, patchTarget)
+      // If the config does not exist that is OK, we just skip this dir
+      const targetConfig = path.resolve(targetDir, 'config.json')
+      if (!fs.existsSync(targetConfig)) continue
+
+      const config = JSON.parse(fs.readFileSync(targetConfig, 'utf8'))
+      for (const key of Object.keys(config)) {
+        // The directory the config points to should exist
+        const targetPatchesDir = path.resolve(__dirname, '../../..', key)
+        if (!fs.existsSync(targetPatchesDir)) throw new Error(`target patch directory: "${targetPatchesDir}" does not exist`)
+        // We need a .patches file
+        const dotPatchesPath = path.resolve(targetPatchesDir, '.patches')
+        if (!fs.existsSync(dotPatchesPath)) throw new Error(`.patches file: "${dotPatchesPath}" does not exist`)
+
+        // Read the patch list
+        const patchFileList = fs.readFileSync(dotPatchesPath, 'utf8').trim().split('\n')
+        const patchFileSet = new Set(patchFileList)
+        patchFileList.reduce((seen, file) => {
+          if (seen.has(file)) {
+            throw new Error(`'${file}' is listed in ${dotPatchesPath} more than once`)
+          }
+          return seen.add(file)
+        }, new Set())
+        if (patchFileList.length !== patchFileSet.size) throw new Error('each patch file should only be in the .patches file once')
+        for (const file of fs.readdirSync(targetPatchesDir)) {
+          // Ignore the .patches file and READMEs
+          if (file === '.patches' || file === 'README.md') continue
+
+          if (!patchFileSet.has(file)) {
+            throw new Error(`Expected the .patches file at "${dotPatchesPath}" to contain a patch file ("${file}") present in the directory but it did not`)
+          }
+          patchFileSet.delete(file)
+        }
+
+        // If anything is left in this set, it means it did not exist on disk
+        if (patchFileSet.size > 0) {
+          throw new Error(`Expected all the patch files listed in the .patches file at "${dotPatchesPath}" to exist but some did not:\n${JSON.stringify([...patchFileSet.values()], null, 2)}`)
+        }
+      }
+    }
+  }
 }]
 
 function parseCommandLine () {
   let help
   const opts = minimist(process.argv.slice(2), {
-    boolean: [ 'c++', 'objc', 'javascript', 'python', 'gn', 'help', 'changed', 'fix', 'verbose', 'only' ],
+    boolean: [ 'c++', 'objc', 'javascript', 'python', 'gn', 'patches', 'help', 'changed', 'fix', 'verbose', 'only' ],
     alias: { 'c++': ['cc', 'cpp', 'cxx'], javascript: ['js', 'es'], python: 'py', changed: 'c', help: 'h', verbose: 'v' },
     unknown: arg => { help = true }
   })
@@ -221,8 +269,8 @@ async function main () {
   const opts = parseCommandLine()
 
   // no mode specified? run 'em all
-  if (!opts['c++'] && !opts.javascript && !opts.python && !opts.gn) {
-    opts['c++'] = opts.javascript = opts.python = opts.gn = true
+  if (!opts['c++'] && !opts.javascript && !opts.python && !opts.gn && !opts.patches) {
+    opts['c++'] = opts.javascript = opts.python = opts.gn = opts.patches = true
   }
 
   const linters = LINTERS.filter(x => opts[x.key])