Skip to content

Commit

Permalink
Add NinjaBuilder.outputDir
Browse files Browse the repository at this point in the history
Add a way for `@ninjutsu-build/*` packages to run from a different
working directory from where the final `.ninja` file will be written to.

This is because all plugins assume that their dependent scripts and
executables reside in the `node_modules` folder in the current working
directory.  However, we (personally) would like to move our
`configure.mjs` script to a `configure` folder to avoid a top-level
`node_modules` directory and to keep the root directory clean.  In order
to support this the plugins will need to know to put the `configure`
directory in the paths to scripts/executables found in the
`configure/node_modules` directory.

This change does not fix any plugins at the moment, only change the core
`NinjaBuilder` component.  The plugins will be fixed in future commits.
  • Loading branch information
elliotgoodrich committed Apr 9, 2024
1 parent 89b70c6 commit a3c594e
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ninjutsu-build/core",
"version": "0.8.7",
"version": "0.8.8",
"description": "Easily create ninja build files with this TypeScript library (https://ninja-build.org/)",
"author": "Elliot Goodrich",
"scripts": {
Expand Down
15 changes: 15 additions & 0 deletions packages/core/src/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ test("constructor", () => {
{
const ninja = new NinjaBuilder();
assert.equal(ninja.output, "");
assert.equal(ninja.outputDir, ".");
}
{
const ninja = new NinjaBuilder({ builddir: "output" });
Expand Down Expand Up @@ -104,6 +105,20 @@ extra = 12
`,
);
}
{
const ninja = new NinjaBuilder(
{
builddir: "output",
},
"final/output/dir",
);
assert.equal(
ninja.output,
`builddir = output
`,
);
assert.equal(ninja.outputDir, "final/output/dir");
}
});

test("comments", () => {
Expand Down
71 changes: 71 additions & 0 deletions packages/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,10 +319,24 @@ export class NinjaBuilder {
*/
output: string;

/**
* Return the target output path passed to the constructor, which indicates where the resulting
* `.ninja` file will be saved to. This is used by plugins to resolve the correct path to
* scripts and executables.
*/
outputDir: string;

/**
* Create a `NinjaBuilder` that builds a ninja file into the `output` property and write any
* properties of the specified `variables` as top-level variables.
*
* The `outputDir` argument specifies where the resulting `.ninja` file will be written to. This
* can either be an absolute path to a directory or a relative path to the current working
* directory. If `outputDir` is incorrect then the paths to scripts and executables found within
* `node_modules` generated by the plugins will be incorrect. Note that `outputDir` will not
* modify the `in` or `out` parameters passed in to rules, these will need to continue to be
* relative to the directory of where the `.ninja` file is written.
*
* @example
* ```ts
* import { NinjaBuilder } from "@ninjutsu-build/core";
Expand Down Expand Up @@ -366,9 +380,65 @@ export class NinjaBuilder {
* ninja_required_version = 1.1
* builddir = .mybuilddir
* ```
*
* @example
* If you want keep the scripts used to generate the `.ninja` file in a separate `configure`
* folder with a `package.json` file, then all of the plugins and dependencies will be
* installed to `configure/node_modules/`. However, you most likely still want to write
* the generated `.ninja` file to the root directory of your project.
*
* Given the below `run.js` file inside the `configure` folder,
*
* ```ts
* import { NinjaBuilder } from "@ninjutsu-build/core";
*
* const ninja = new NinjaBuilder();
* // ...
* console.log(ninja.output);
* ```
*
* it can be run like so,
*
* ```bash
* $ node configure/run.js > build.ninja
* ```
*
* and as the current working directory of `node` is the same where we write the `build.ninja`
* file, everything works out with correct paths to executables and scripts within the ninja rules.
*
* However, if we ran from the `configure` directory then we would be missing the `configure`
* directory in the generated paths to exectuables and scripts in `node_modules`,
*
* ```bash
* $ cd configure && node run.js > ../build.ninja
* ```
*
* If you wish to run your scripts from a different directory than where the resulting `.ninja`
* file will live, then passing in the output directory as a command line argument to forward it
* to the `NinjaBuilder` constructor is a more resilent way,
*
* ```ts
* // configure/run.js
* import { NinjaBuilder } from "@ninjutsu-build/core";
* import { writeDirSync } from "node:fs";
* import { join } from "node:path";
*
* const outDir = process.argv[2];
* const ninja = new NinjaBuilder({}, outDir);
* // ...
* writeFileSync(join(outDir, "build.ninja"), ninja.output);
* ```
*
* Then both the following commands would generate correct and identical `build.ninja` files,
*
* ```bash
* $ node configure/run.js .
* $ cd configure && node run.js ..
* ```
*/
constructor(
variables: { ninja_required_version?: string; builddir?: string } = {},
outputDir = ".",
) {
this.output = "";
for (const name in variables) {
Expand All @@ -377,6 +447,7 @@ export class NinjaBuilder {
this.output += name + " = " + value + "\n";
}
}
this.outputDir = outputDir;
}

/**
Expand Down

0 comments on commit a3c594e

Please sign in to comment.