Files
api/plugin/builder/build-txz.ts
Eli Bosley ce61fee41c feat: improve local dev with install path (#1221)
- also add better watcher support

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added a helper that displays a local installation URL to simplify
setting up the plugin.

- **Chores**
- Updated service and container port configurations to ensure consistent
network connectivity (changed from 8080 to 5858).
- Refined container management to gracefully handle running instances
during startup.
- Improved build and installation routines for streamlined deployment
and enhanced reliability.
- Enhanced documentation to clarify installation and usage instructions
for better user experience.
- Introduced a new document outlining development workflows for better
guidance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1209561202532053
2025-03-17 09:44:10 -04:00

124 lines
3.7 KiB
TypeScript

import { join } from "path";
import { $, cd } from "zx";
import { existsSync } from "node:fs";
import { readdir } from "node:fs/promises";
import { getTxzName, pluginName, startingDir } from "./utils/consts";
import { setupTxzEnv, TxzEnv } from "./cli/setup-txz-environment";
import { cleanupTxzFiles } from "./utils/cleanup";
// Recursively search for manifest files
const findManifestFiles = async (dir: string): Promise<string[]> => {
try {
const entries = await readdir(dir, { withFileTypes: true });
const files: string[] = [];
for (const entry of entries) {
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
try {
files.push(...(await findManifestFiles(fullPath)));
} catch (error) {
// Log and continue if a subdirectory can't be read
console.warn(`Warning: Could not read directory ${fullPath}: ${error.message}`);
}
} else if (
entry.isFile() &&
(entry.name === "manifest.json" || entry.name === "ui.manifest.json")
) {
files.push(entry.name);
}
}
return files;
} catch (error) {
if (error.code === 'ENOENT') {
console.warn(`Directory does not exist: ${dir}`);
return [];
}
throw error; // Re-throw other errors
}
};
const validateSourceDir = async (validatedEnv: TxzEnv) => {
if (!validatedEnv.ci) {
console.log("Validating TXZ source directory");
}
const sourceDir = join(startingDir, "source");
if (!existsSync(sourceDir)) {
throw new Error(`Source directory ${sourceDir} does not exist`);
}
// Validate existence of webcomponent files:
// source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components
const webcomponentDir = join(
sourceDir,
"dynamix.unraid.net",
"usr",
"local",
"emhttp",
"plugins",
"dynamix.my.servers",
"unraid-components"
);
if (!existsSync(webcomponentDir)) {
throw new Error(`Webcomponent directory ${webcomponentDir} does not exist`);
}
const manifestFiles = await findManifestFiles(webcomponentDir);
const hasManifest = manifestFiles.includes("manifest.json");
const hasUiManifest = manifestFiles.includes("ui.manifest.json");
if (!hasManifest || !hasUiManifest) {
console.log("Existing Manifest Files:", manifestFiles);
throw new Error(
`Webcomponents must contain both "ui.manifest.json" and "manifest.json" - be sure to have run pnpm build:wc in unraid-ui`
);
}
const apiDir = join(
startingDir,
"source",
pluginName,
"usr",
"local",
"unraid-api"
);
if (!existsSync(apiDir)) {
throw new Error(`API directory ${apiDir} does not exist`);
}
const packageJson = join(apiDir, "package.json");
if (!existsSync(packageJson)) {
throw new Error(`API package.json file ${packageJson} does not exist`);
}
// Now CHMOD the api/dist directory files to allow execution
await $`chmod +x ${apiDir}/dist/*.js`;
};
const buildTxz = async (validatedEnv: TxzEnv) => {
await validateSourceDir(validatedEnv);
const txzPath = join(validatedEnv.txzOutputDir, getTxzName());
// Create package - must be run from within the pre-pack directory
// Use cd option to run command from prePackDir
await cd(join(startingDir, "source", pluginName));
$.verbose = true;
await $`${join(startingDir, "scripts/makepkg")} --chown y --compress -${
validatedEnv.compress
} --linkadd y ${txzPath}`;
$.verbose = false;
await cd(startingDir);
};
const main = async () => {
try {
const validatedEnv = await setupTxzEnv(process.argv);
await cleanupTxzFiles();
await buildTxz(validatedEnv);
} catch (error) {
console.error(error);
process.exit(1);
}
};
await main();