balena-supervisor/sync-debug.js
Cameron Diver 37ea6a9283 Fix invocation of livepush with sync-debug
Change-type: patch
Signed-off-by: Cameron Diver <cameron@balena.io>
2019-07-23 15:00:39 +01:00

131 lines
3.4 KiB
JavaScript
Executable File

#!/usr/bin/env node
if (!process.argv[2] || ['help', '-h', '--help'].includes(process.argv[2])) {
console.log(`
Sync changes in the javascript code to a running local mode supervisor on a device on the local network
Usage:
./sync-debug.js <device IP>
Note that the device should be running a debug image.
`);
process.exit(1);
}
const ip = process.argv[2];
const { Livepush } = require('livepush');
const { fs } = require('mz');
const dockerode = require('dockerode');
const chokidar = require('chokidar');
const _ = require('lodash');
let lastReadTimestamp = null;
const setupLogs = async (containerId, docker) => {
const container = docker.getContainer(containerId);
const stream = await container.logs({
stdout: true,
stderr: true,
follow: true,
timestamps: true,
// We start from 0, as we risk not getting any logs to
// properly seed the value if the host and remote times differ
since: lastReadTimestamp != null ? lastReadTimestamp : 0,
});
stream.on('data', chunk => {
const { message, timestamp } = extractMessage(chunk);
lastReadTimestamp = Math.floor(timestamp.getTime() / 1000);
process.stdout.write(message);
});
stream.on('end', () => {
setupLogs(containerId, docker);
});
};
function extractMessage(msgBuf) {
// Non-tty message format from:
// https://docs.docker.com/engine/api/v1.30/#operation/ContainerAttach
if (_.includes([0, 1, 2], msgBuf[0])) {
// Take the header from this message, and parse it as normal
msgBuf = msgBuf.slice(8);
}
const str = msgBuf.toString();
const space = str.indexOf(' ');
return {
timestamp: new Date(str.slice(0, space)),
message: str.slice(space + 1),
};
}
const docker = new dockerode({
host: ip,
port: 2375,
});
let changedFiles = [];
let deletedFiles = [];
const performLivepush = _.debounce(async livepush => {
await livepush.performLivepush(changedFiles, deletedFiles);
changedFiles = [];
deletedFiles = [];
}, 1000);
(async () => {
console.log('Starting up...');
// Get the supervisor container id
const container = await docker.getContainer('resin_supervisor').inspect();
console.log('Supervisor container id: ', container.Id);
const containerId = container.Id;
const image = container.Image;
setupLogs(containerId, docker);
const livepush = await Livepush.init(
await fs.readFile('Dockerfile.debug'),
'.',
containerId,
// a bit of a hack, as the multistage images aren't
// present, but it shouldn't make a difference as these
// will never change
_.times(6, () => image),
docker,
);
chokidar
.watch('.', {
ignored: /((^|[\/\\])\..|node_modules.*)/,
ignoreInitial: false,
})
.on('add', path => {
changedFiles.push(path);
performLivepush(livepush, containerId, docker);
})
.on('change', path => {
changedFiles.push(path);
performLivepush(livepush, containerId, docker);
})
.on('unlink', path => {
deletedFiles.push(path);
performLivepush(livepush, containerId, docker);
});
livepush.on('commandExecute', ({ command }) => {
console.log('SYNC: executing:', command);
});
livepush.on('commandOutput', ({ output }) => {
const message = output.data.toString();
if (message.trim().length !== 0) {
process.stdout.write(`\t${message}`);
}
});
livepush.on('commandReturn', ({ returnCode }) => {
if (returnCode !== 0) {
console.log(`\tSYNC: Command return non zero exit status: ${returnCode}`);
}
});
livepush.on('containerRestart', () => {
console.log('SYNC: Restarting container...');
});
})();