@dxatscale/sfprofiles
Version:
Salesforce Profile management
113 lines (99 loc) • 4.96 kB
text/typescript
import { Connection, Org, SfdxProject } from '@salesforce/core';
import { Sfpowerkit } from '@utils/sfpowerkit';
import SFPLogger, {LoggerLevel } from '@dxatscale/sfp-logger';
import { parentPort, workerData } from 'worker_threads';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as xml2js from 'xml2js';
import * as util from 'util';
import ProfileWriter from '@impl/metadata/writer/profileWriter';
import Profile from '@impl/metadata/schema';
import ProfileComponentReconciler from './profileComponentReconciler';
import { MetadataResolver, SourceComponent } from '@salesforce/source-deploy-retrieve';
import { ProfileSourceFile } from './profileActions';
import _ from 'lodash';
export default class ReconcileWorker {
conn: Connection;
public constructor(private targetOrg: string, private isSourceOnly: boolean) {}
public async reconcile(profilesToReconcile: ProfileSourceFile[], destFolder: string) {
//Init Cache for each worker thread from file system
Sfpowerkit.initCache();
if (this.targetOrg) {
const org = await Org.create({ aliasOrUsername: this.targetOrg });
this.conn = org.getConnection();
} else {
//Load all local components from source to database
await this.loadAllLocalComponents();
}
let result: string[] = [];
for (let count = 0; count < profilesToReconcile.length; count++) {
let reconciledProfile = await this.reconcileProfileJob(profilesToReconcile[count], destFolder);
result.push(reconciledProfile[0]);
}
return result;
}
private async loadAllLocalComponents() {
const resolver = new MetadataResolver();
const project = await SfdxProject.resolve();
let packageDirectories = project.getPackageDirectories();
for (const packageDirectory of packageDirectories) {
const components = resolver.getComponentsFromPath(packageDirectory.path);
for (const component of components) {
this.loadComponentsTocache(component);
}
}
}
private loadComponentsTocache(component:SourceComponent){
Sfpowerkit.addToCache(`SOURCE_${component.type.name}_${component.fullName}`, true);
Sfpowerkit.addToCache(`${component.type.name}_SOURCE_CACHE_AVAILABLE`, true);
let children:SourceComponent[] = component.getChildren();
for (const child of children) {
this.loadComponentsTocache(child);
}
}
public reconcileProfileJob(profileComponent: ProfileSourceFile, destFolder: string): Promise<string[]> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let reconcilePromise = new Promise<string[]>((resolve, reject) => {
let result: string[] = []; // Handle result of command execution
let profileXmlString = fs.readFileSync(profileComponent.path);
const parser = new xml2js.Parser({ explicitArray: true });
const parseString = util.promisify(parser.parseString) as _.Function1<xml2js.convertableToString, Promise<{ Profile: Profile }>>;
parseString(profileXmlString)
.then((parseResult) => {
let profileWriter = new ProfileWriter();
const profileObj: Profile = profileWriter.toProfile(parseResult.Profile); // as Profile
return profileObj;
})
.then((profileObj) => {
return new ProfileComponentReconciler(this.conn, this.isSourceOnly).reconcileProfileComponents(
profileObj,
profileComponent.name
);
})
.then((profileObj) => {
//write profile back
let outputFile = profileComponent.path;
if (destFolder != null) {
outputFile = path.join(destFolder, path.basename(profileComponent.path));
}
let profileWriter = new ProfileWriter();
profileWriter.writeProfile(profileObj, outputFile);
result.push(outputFile);
resolve(result);
return result;
})
.catch((error) => {
SFPLogger.log(
'Error while processing file ' + profileComponent + '. ERROR Message: ' + error.message,
LoggerLevel.ERROR
);
});
});
return reconcilePromise;
}
}
Sfpowerkit.setLogLevel(workerData.loglevel, workerData.isJsonFormatEnabled);
let reconcileWorker = new ReconcileWorker(workerData.targetOrg, workerData.isSourceOnly);
reconcileWorker.reconcile(workerData.profileChunk, workerData.destFolder).then((result) => {
parentPort.postMessage(result);
})