feat(02-04): implement buildRmmScript pure function
- Imports CONFIG_DIR and buildRcloneInstallBlock from ps-helpers.ts - Uses \$ErrorActionPreference = 'Stop' for RMM platform exit code surfacing - Creates config directory idempotently with Test-Path guard - Writes rclone.conf using [System.IO.File]::WriteAllText UTF-8 no-BOM - Conditionally includes rclone download block based on includeInstall flag - All 6 rmm-script.test.ts assertions pass GREEN
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
// src/generators/rmm-script.ts
|
||||
// Generator for RMM (Remote Monitoring and Management) PowerShell deployment scripts.
|
||||
// Compatible with NinjaRMM, Datto, ConnectWise, and similar RMM platforms.
|
||||
// Runs as SYSTEM. Idempotent (safe to re-run).
|
||||
|
||||
import type { WizardState } from '../store/types';
|
||||
import { CONFIG_DIR, buildRcloneInstallBlock } from './ps-helpers';
|
||||
|
||||
export function buildRmmScript(state: WizardState): string {
|
||||
const configDir = CONFIG_DIR[state.deployment.configPath];
|
||||
const confContent = buildRcloneConfContent(state);
|
||||
const installBlock = state.deployment.includeInstall
|
||||
? buildRcloneInstallBlock(configDir)
|
||||
: '';
|
||||
|
||||
return [
|
||||
`# RMM Deployment Script — compatible with NinjaRMM, Datto, ConnectWise`,
|
||||
`# Runs as SYSTEM. Idempotent (safe to re-run).`,
|
||||
`$ErrorActionPreference = 'Stop'`,
|
||||
``,
|
||||
`$configDir = '${configDir}'`,
|
||||
`$configPath = "$configDir\\rclone.conf"`,
|
||||
``,
|
||||
`# Idempotent: create directory if it doesn't exist`,
|
||||
`if (-not (Test-Path $configDir)) {`,
|
||||
` New-Item -ItemType Directory -Path $configDir -Force | Out-Null`,
|
||||
`}`,
|
||||
``,
|
||||
`# Write config using UTF-8 no-BOM encoding`,
|
||||
`# Note: Set-Content -Encoding UTF8 in PS 5.1 writes UTF-8 WITH BOM — do not use`,
|
||||
`$confContent = @'`,
|
||||
confContent.trimEnd(),
|
||||
`'@`,
|
||||
`[System.IO.File]::WriteAllText($configPath, $confContent, [System.Text.UTF8Encoding]::new($false))`,
|
||||
installBlock,
|
||||
``,
|
||||
`exit 0`,
|
||||
].join('\n') + '\n';
|
||||
}
|
||||
|
||||
// Build the rclone.conf content string to embed in the here-string.
|
||||
// Inlined here (not imported from rclone-conf.ts) to keep the file self-contained
|
||||
// and avoid any circular dependency risk.
|
||||
function buildRcloneConfContent(state: WizardState): string {
|
||||
const RCLONE_TYPE_MAP: Record<string, string> = {
|
||||
azureblob: 'azureblob',
|
||||
s3: 's3',
|
||||
's3-compatible': 's3',
|
||||
};
|
||||
const { name, backendType, params } = state.remote;
|
||||
const rcloneType = backendType ? RCLONE_TYPE_MAP[backendType] : 'unknown';
|
||||
const lines: string[] = [`[${name}]`, `type = ${rcloneType}`];
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
if (value !== '') lines.push(`${key} = ${value}`);
|
||||
}
|
||||
return lines.join('\n') + '\n';
|
||||
}
|
||||
Reference in New Issue
Block a user