|
|
|
@ -1,3 +1,8 @@ |
|
|
|
|
/* |
|
|
|
|
Useful system level functions for use in build commands. It's mostly things like |
|
|
|
|
detecting if two files changed, doing globs on Windows and Unix, and various |
|
|
|
|
file operations that you need. |
|
|
|
|
*/ |
|
|
|
|
import fg from "fast-glob"; |
|
|
|
|
import fs from "fs"; |
|
|
|
|
import assert from "assert"; |
|
|
|
@ -6,7 +11,12 @@ import Path from "path"; |
|
|
|
|
import { execSync } from "child_process"; |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
Fixes some common problems with fast-glob on windows. |
|
|
|
|
Fixes some common problems with `fast-glob` on windows. I removes |
|
|
|
|
leading "C:\" from paths and replaces all of the `\\` with `/`. |
|
|
|
|
|
|
|
|
|
__BUG__: This obviously won't work if you're on a different drive than C:. |
|
|
|
|
|
|
|
|
|
+ `path string` -- The path/glob pattern to use. |
|
|
|
|
*/ |
|
|
|
|
export const glob = (path) => { |
|
|
|
|
if(process.platform === "win32") { |
|
|
|
@ -19,6 +29,17 @@ export const glob = (path) => { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
Detects if two files have changed. This is used to avoid |
|
|
|
|
writing or working on files that don't need it, similar |
|
|
|
|
to the Unix make utility. |
|
|
|
|
|
|
|
|
|
___FOOTGUN___: It uses the stat.mtimeMs which may or may not be |
|
|
|
|
the most reliable way to detect differences. |
|
|
|
|
|
|
|
|
|
+ `source string` -- The source path. |
|
|
|
|
+ `target string` -- The target path. |
|
|
|
|
*/ |
|
|
|
|
export const changed = (source, target) => { |
|
|
|
|
// we want the source to error if it doesn't exist
|
|
|
|
|
const s_stat = fs.statSync(source); |
|
|
|
@ -28,7 +49,11 @@ export const changed = (source, target) => { |
|
|
|
|
return !t_stat || s_stat.mtimeMs > t_stat.mtimeMs; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Makes a directory recursively. */ |
|
|
|
|
/* |
|
|
|
|
Makes a directory recursively, kind of like `mkdir -p`. |
|
|
|
|
|
|
|
|
|
+ `dir string` -- The full path to the final directory to create. |
|
|
|
|
*/ |
|
|
|
|
export const mkdir = (dir) => { |
|
|
|
|
if(!fs.existsSync(dir)) { |
|
|
|
|
log.debug(`making dir ${dir}`); |
|
|
|
@ -37,13 +62,8 @@ export const mkdir = (dir) => { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
Given any path to a file, makes sure all its directories are in place. |
|
|
|
|
|
|
|
|
|
Example: |
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
console.log("PRINT"); |
|
|
|
|
``` |
|
|
|
|
Given any path to a file, makes sure all its directories are in place. This will |
|
|
|
|
only the directory to the file, and then calls `mkdir` on it to create the path. |
|
|
|
|
|
|
|
|
|
- `param string` -- path to file |
|
|
|
|
*/ |
|
|
|
@ -52,7 +72,14 @@ export const mkdir_to = (target) => { |
|
|
|
|
mkdir(dirs.dir); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Convenience function that makes sure the dir is there then writes the data. */ |
|
|
|
|
/* |
|
|
|
|
Convenience function that makes sure the dir is there then writes the data. |
|
|
|
|
It's a combination of `mkdir_to` and `fs.writeFileSync` and exists because |
|
|
|
|
these two operations are so common. |
|
|
|
|
|
|
|
|
|
+ `target string` -- Path to the file to write. |
|
|
|
|
+ `data string|buffer|etc.` -- Anything that `fs.writeFileSync` can take as file contents. |
|
|
|
|
*/ |
|
|
|
|
export const write = (target, data) => { |
|
|
|
|
mkdir_to(target); |
|
|
|
|
fs.writeFileSync(target, data); |
|
|
|
@ -61,7 +88,12 @@ export const write = (target, data) => { |
|
|
|
|
/* |
|
|
|
|
Like write but does an OS copy after making the target dir. When given a |
|
|
|
|
filter it will give the filter function the arguments, let it return contents, |
|
|
|
|
then write those instead of a copy. |
|
|
|
|
then write those instead of a copy. This will create the target file's path |
|
|
|
|
with `mkdir_to`. |
|
|
|
|
|
|
|
|
|
+ `src string` -- Source file path. |
|
|
|
|
+ `dest string` -- Destination path. |
|
|
|
|
+ `filter cb(src, dest, raw_data)` -- A function that can modify the data before it's written. |
|
|
|
|
*/ |
|
|
|
|
export const copy = (src, dest, filter=null) => { |
|
|
|
|
mkdir_to(dest); |
|
|
|
@ -70,7 +102,8 @@ export const copy = (src, dest, filter=null) => { |
|
|
|
|
try { |
|
|
|
|
let raw_data = fs.readFileSync(src); |
|
|
|
|
let data = filter(src, dest, raw_data); |
|
|
|
|
write(dest, data); |
|
|
|
|
|
|
|
|
|
fs.writeFileSync(dest, data); |
|
|
|
|
} catch (error) { |
|
|
|
|
log.error(error, "Problem with filter write in copy"); |
|
|
|
|
} |
|
|
|
@ -79,6 +112,12 @@ export const copy = (src, dest, filter=null) => { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
Removes a file, optionally ignoring any errors. |
|
|
|
|
|
|
|
|
|
+ `file_name string` -- The path to the file to remove. |
|
|
|
|
+ `ignore boolean (false)` -- Whether to ignore errors removing the file. |
|
|
|
|
*/ |
|
|
|
|
export const rm = (file_name, ignore=false) => { |
|
|
|
|
log.warn("Deleting file", file_name); |
|
|
|
|
try { |
|
|
|
@ -93,27 +132,35 @@ export const rm = (file_name, ignore=false) => { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export const index_rollup = (src_index, target_index, contents, key) => { |
|
|
|
|
let index = JSON.parse(fs.readFileSync(src_index)); |
|
|
|
|
|
|
|
|
|
index[key] = glob(contents).map(f => JSON.parse(fs.readFileSync(f))); |
|
|
|
|
assert(index[key] !== undefined, `Attempt to load contents into ${key} for ${src_index} failed with undefined.`); |
|
|
|
|
|
|
|
|
|
write(target_index, JSON.stringify(index)); |
|
|
|
|
|
|
|
|
|
return index; |
|
|
|
|
} |
|
|
|
|
/* |
|
|
|
|
Executes a command, and mostly just logs the command then run |
|
|
|
|
execSync with the same options. |
|
|
|
|
|
|
|
|
|
+ `cmd string` -- Command to run. |
|
|
|
|
+ `opts Object` -- Options for `execSync`. |
|
|
|
|
*/ |
|
|
|
|
export const exec = (cmd, opts) => { |
|
|
|
|
log.info(`EXEC ${cmd}`); |
|
|
|
|
return execSync(cmd, opts); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
Similar to `exec` but it is _interactive_ because it reroutes this process's stderr, |
|
|
|
|
stdout, and stdin to the process. If you find you can't ctrl-c then use this. The |
|
|
|
|
options set are: |
|
|
|
|
|
|
|
|
|
``` |
|
|
|
|
{stdio: [process.stdout, process.stderr, process.stdin]} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
+ `cmd string` -- The command to run. |
|
|
|
|
+ `opts Object` -- Additional options to set for the exec command. |
|
|
|
|
*/ |
|
|
|
|
export const exec_i = (cmd, opts={}) => { |
|
|
|
|
return exec(cmd, {stdio: [process.stdout, process.stderr, process.stdin], ...opts}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default { |
|
|
|
|
index_rollup, rm, exec, changed, mkdir, mkdir_to, write, copy, exec_i, glob |
|
|
|
|
rm, exec, changed, mkdir, mkdir_to, write, copy, exec_i, glob |
|
|
|
|
} |
|
|
|
|