sitespeed.io/lib/plugins/scp/index.js

140 lines
3.8 KiB
JavaScript

import { join, basename, resolve } from 'node:path';
import { SitespeedioPlugin } from '@sitespeed.io/plugin';
import { readFileSync, remove } from 'fs-extra';
import { Client } from 'node-scp';
import readdir from 'recursive-readdir';
import intel from 'intel';
import { throwIfMissing } from '../../support/util';
const log = intel.getLogger('sitespeedio.plugin.scp');
async function getClient(scpOptions) {
const options = {
host: scpOptions.host,
port: scpOptions.port || 22
};
if (scpOptions.username) {
options.username = scpOptions.username;
}
if (scpOptions.password) {
options.password = scpOptions.password;
}
if (scpOptions.privateKey) {
options.privateKey = readFileSync(scpOptions.privateKey);
}
if (scpOptions.passphrase) {
options.passphrase = scpOptions.passphrase;
}
return await Client(options);
}
async function upload(dir, scpOptions, prefix) {
let client;
try {
client = await getClient(scpOptions);
const directories = prefix.split('/');
let fullPath = '';
for (let dir of directories) {
fullPath += dir + '/';
const doThePathExist = await client.exists(
join(scpOptions.destinationPath, fullPath)
);
if (!doThePathExist) {
await client.mkdir(join(scpOptions.destinationPath, fullPath));
}
}
await client.uploadDir(dir, join(scpOptions.destinationPath, prefix));
} catch (error) {
log.error(error);
throw error;
} finally {
if (client) {
client.close();
}
}
}
async function uploadFiles(files, scpOptions, prefix) {
let client;
try {
client = await getClient(scpOptions);
for (let file of files) {
await client.uploadFile(
file,
join(scpOptions.destinationPath, prefix, basename(file))
);
}
} catch (error) {
log.error(error);
throw error;
} finally {
if (client) {
client.close();
}
}
}
function ignoreDirectories(file, stats) {
return stats.isDirectory();
}
async function uploadLatestFiles(dir, scpOptions, prefix) {
const files = await readdir(dir, [ignoreDirectories]);
return uploadFiles(files, scpOptions, prefix);
}
export default class ScpPlugin extends SitespeedioPlugin {
constructor(options, context, queue) {
super({ name: 'scp', options, context, queue });
}
open(context, options) {
this.scpOptions = options.scp;
this.options = options;
this.make = context.messageMaker('scp').make;
throwIfMissing(
this.scpOptions,
['host', 'destinationPath', 'username'],
'scp'
);
this.storageManager = context.storageManager;
}
async processMessage(message, queue) {
if (message.type === 'sitespeedio.setup') {
// Let other plugins know that the scp plugin is alive
queue.postMessage(this.make('scp.setup'));
} else if (message.type === 'html.finished') {
const make = this.make;
const baseDir = this.storageManager.getBaseDir();
log.info(
`Uploading ${baseDir} using scp bucket, this can take a while ...`
);
try {
await upload(
baseDir,
this.scpOptions,
this.storageManager.getStoragePrefix()
);
if (this.options.copyLatestFilesToBase) {
const rootPath = resolve(baseDir, '..');
const prefix = this.storageManager.getStoragePrefix();
const firstPart = prefix.split('/')[0];
await uploadLatestFiles(rootPath, this.scpOptions, firstPart);
}
log.info('Finished upload using scp');
if (this.scpOptions.removeLocalResult) {
await remove(baseDir);
log.debug(`Removed local files and directory ${baseDir}`);
}
} catch (error) {
queue.postMessage(make('error', error));
log.error('Could not upload using scp', error);
}
queue.postMessage(make('scp.finished'));
}
}
}