140 lines
3.8 KiB
JavaScript
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'));
|
|
}
|
|
}
|
|
}
|