Skip to content

Instantly share code, notes, and snippets.

@FireyFly
Last active July 22, 2019 10:50
Show Gist options
  • Save FireyFly/18621625dc8d8f6ecf6ddb8e55002c63 to your computer and use it in GitHub Desktop.
Save FireyFly/18621625dc8d8f6ecf6ddb8e55002c63 to your computer and use it in GitHub Desktop.
CLI Utilities
# Stuff for finding out which docker containers are autostarting, and making them not do so
# https://stackoverflow.com/a/45022623/1267058
# Find containers whose RestartPolicy is 'always'--these are the culprits
docker ps -a --format '{{.ID}} {{.Names}}' \
| while read id name; do
policy=$(docker inspect $id | jq -r '.[].HostConfig.RestartPolicy.Name')
printf '%s %-30s %s\n' "$id" "$name" "$policy"
done \
| grep 'always$'
# Disable restart for a container
docker update --restart=no <ID>
#!/bin/bash
DirName="$(basename "$PWD" | tr '[:upper:]' '[:lower:]')"
ServiceName="$1"
ContainerName="$(docker ps --format '{{.Names}}' | grep "${DirName}_${ServiceName}" | head -n 1)"
if [ $# == 0 ]; then
echo >&2 'usage: dsh <service name> [...command]'
exit 1
fi
if [ -z "$ContainerName" ]; then
echo >&2 "error: no container "${DirName}_${ServiceName}" found"
exit 1
fi
shift 1
case $# in
0) docker exec -ti "$ContainerName" /bin/bash ;;
*) docker exec -ti "$ContainerName" "$@" ;;
esac
#!/usr/bin/env node
const util = require('util');
const http = require('http');
const { Transform } = require('stream');
const { spawn } = require('child_process');
function findJSONEnd(str, i) {
if (str[i] !== '{') throw new Error(`findJSONEnd: Expected '{', found '${str[i]}'`);
let j = i + 1, count = 1, mode = 'object';
while (count > 0 && j < str.length) {
if (mode === 'object') {
if (str[j] === '{') count += 1;
else if (str[j] === '}') count -= 1;
else if (str[j] === '"') mode = 'string';
} else if (mode === 'string') {
if (str[j] === '\\') j += 1; // skip escaped char
else if (str[j] === '"') mode = 'object';
}
j += 1;
}
if (j === str.length) return null;
return j;
}
function createJSONObjectArrayTransform() {
let hasReceivedFirst = false;
let residue = '';
return new Transform({
readableObjectMode: true,
readableHighWaterMark: 1,
// TODO: implement _flush, test properly
transform(chunk, encoding, cb) {
let str = residue + chunk;
if (!hasReceivedFirst) {
// TODO: clean this up a bit
while (str.startsWith('Filtering the log data')) {
str = str.replace(/^[^\n]+\n/, '');
}
if (str.length === 0) return cb();
if (str[0] !== '[') return cb(new Error("JSONObjectArrayTransform: expected stream to start with '['"));
str = str.slice(1);
hasReceivedFirst = true;
}
let i = 0;
while (i < str.length) {
const j = findJSONEnd(str, i);
if (j == null) break;
this.push(JSON.parse(str.slice(i, j)));
// TODO: check for ','
i = j + 1;
}
residue = str.slice(i);
cb();
},
});
}
const parseErrorObject = (str) => {
const matches = str.trim().match(/^\{\s*\[(.*)\]\n *line: *(\d+),\n *column: *(\d+),\n *sourceURL: *'(.*)'\s*}$/);
if (matches == null) return null;
const [_, message, line, column, sourceURL] = matches;
return {
message,
line: Number(line),
column: Number(column),
sourceURL,
};
};
const parseFormatStringArgs = (str) => {
if (!/^'.*', '.*(?:'|<…>)$/.test(str)) return null;
const table = { "'": '"', "\\'": "'", '"': '\\"', '<…>': '"' };
try {
return JSON.parse(`[${str.replace(/\\'|'|"|<…>/g, which => table[which])}]`);
} catch (err) {
return null;
}
};
const requestToPromise = req => new Promise((resolve, reject) => {
req.on('response', (res) => {
const chunks = [];
res.on('data', (chunk) => { chunks.push(chunk); });
res.on('end', () => resolve(chunks.join('')));
res.on('error', reject);
});
});
let fetchLines;
{
let cache = {};
fetchLines = async (sourceURL) => {
if (cache.url === sourceURL) return cache.lines;
const content = await requestToPromise(http.get(sourceURL));
cache.url = sourceURL;
cache.lines = content.split('\n');
return cache.lines;
};
}
const asyncLogger = {
promise: Promise.resolve(),
logErrorObject({ timestamp, source }, { message, line, column, sourceURL }) {
const lineIdx = line - 1;
const logSourceLine = (lineno, str) => {
const spaces = Array(8 - String(lineno).length).join(' ');
console.log(util.format('\x1B[36m%s\x1B[m %s', spaces + lineno, str));
};
this.promise = this.promise
.then(() => fetchLines(sourceURL))
.catch((err) => console.error(err))
.then((lines) => {
console.log(util.format('\x1B[33m%s\x1B[m \x1B[32m%s\x1B[m', timestamp, source.symbol));
console.log(' ' + message);
const lineBefore = lines[lineIdx].slice(0, column - 1);
const lineAt = lines[lineIdx][column - 1];
const lineAfter = lines[lineIdx].slice(column);
logSourceLine(line - 2, util.format('\x1B[38;5;241m%s\x1B[m', lines[lineIdx - 2]));
logSourceLine(line - 1, util.format('\x1B[38;5;241m%s\x1B[m', lines[lineIdx - 1]));
logSourceLine(line + 0, util.format('%s\x1B[7m%s\x1B[m%s', lineBefore, lineAt, lineAfter));
logSourceLine(line + 1, util.format('\x1B[38;5;241m%s\x1B[m', lines[lineIdx + 1]));
logSourceLine(line + 2, util.format('\x1B[38;5;241m%s\x1B[m', lines[lineIdx + 2]));
});
},
logMessage({ timestamp, source }, message) {
this.promise = this.promise.then(() => {
console.log(util.format('\x1B[33m%s\x1B[m \x1B[32m%s\x1B[m', timestamp, source.symbol));
console.log(message);
});
},
};
/*
{
traceID,
eventMessage,
eventType,
source, // { symbol, line, image, file }
formatString,
activityIdentifier,
subsystem,
category,
threadID,
senderImageUUID,
backtrace, // { frames: [ ... ] }
processImagePath,
senderImagePath,
timestamp,
machTimestamp,
messageType,
processImageUUID,
processID,
senderProgramCounter,
parentActivityIdentifier,
timezoneName,
}
*/
const indent = (str, n) => {
const spaces = Array(n + 1).join(' ');
return str.split('\n').map(line => spaces + line).join('\n');
}
const trimStacktrace = (str) => {
const lines = str.split('\n');
return lines.filter(line => !/^ +in /.test(line)).join('\n');
};
spawn('xcrun', ['simctl', 'spawn', 'booted', 'log', 'stream', '--source', '--style=json', '--type=log'])
.stdout.pipe(createJSONObjectArrayTransform())
.on('data', (event) => {
const { source, eventMessage } = event;
if (source != null && source.symbol === 'RCTDefaultLogFunction_block_invoke') {
const errorObject = parseErrorObject(eventMessage);
const formatStringArgs = parseFormatStringArgs(eventMessage);
if (errorObject != null) {
asyncLogger.logErrorObject(event, errorObject);
} else if (formatStringArgs != null) {
const message = indent(trimStacktrace(util.format(...formatStringArgs)), 2);
asyncLogger.logMessage(event, message);
} else {
const message = indent(trimStacktrace(eventMessage), 2);
asyncLogger.logMessage(event, message);
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment