Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abiltity to specify command to run in SSH command #17

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 59 additions & 20 deletions lib/commands/stack/ssh.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const IDLE_INTERVAL = 30_000;

const INITIAL_SIZE_WAIT = 700;

function connect( data ) {
function connect( data, porcelain = false ) {
let idleTimer;
let lastWasNewline = true;
let startedSshControl = false;
Expand Down Expand Up @@ -85,7 +85,6 @@ function connect( data ) {

msg += char;
}

session.write( msg );
} );
}, 1000 );
Expand All @@ -109,11 +108,28 @@ function connect( data ) {
}

const message = reason ? `${ reason }. Disconnected.` : 'Disconnected.';
process.stderr.write( message );
if ( ! porcelain ) {
process.stdout.write( message );
}
session.close();
process.exit();
} );

let firstOutput = true;
session.on( 'output', ( data ) => {

// If this is the first output chunk and we're in porcelain mode, strip the initial 2 lines
// this contain somethign like:
// exec sudo sandbox-exec 'clear; $command'
// sh-4.2$ exec sudo sandbox-exec 'clear; $command'
if ( porcelain && firstOutput ) {
data = data.split( '\n' ).slice(2).join('\n').trim();
}
Comment on lines +121 to +127
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something you can do here is use the clear itself; it outputs the ANSI control characters for clearing, so you can split on that. Even cleaner, change the backend command to output just the one code with something like

exec sudo sandbox-exec "printf '\033[2J'; $command"

And then here, data.split( '033[2J', 2 )[1]

firstOutput = false;
// Strip the ANSI escape codes if we're in porcelain mode.
if ( porcelain ) {
data = data.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
}
Comment on lines +129 to +132
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't really safe to do

process.stdout.write( data );
} );
}
Expand All @@ -123,39 +139,62 @@ const handler = function ( argv ) {

getStack( argv ).then( stack => {
const v = new Vantage( config );

const status = new ora( `Starting session on ${stack}` );
status.start();

if ( ! argv.command ) {
status.start();
}

const url = `stack/applications/${stack}/cli/sessions`;
v.fetch( url, { method: 'POST' } ).then( resp => {
const args = {
motd: ! argv.command,
};

if ( argv.command ) {
// Set the SHELL_PIPE=1 env var when running the command if the current process is piped.
args.command = `${ process.stdout.isTTY ? '' : 'SHELL_PIPE=1 ' }${ argv.command }`;
}

const options = {
method: 'POST',
body: JSON.stringify( args ),
headers: {
'Content-Type': 'application/json',
},
};

v.fetch( url, options ).then( resp => {
// hm-stack currently returns a 500 for invalid stacks, so we have to
// assume any failure is a 404: https://github.com/humanmade/hm-stack/issues/367
if ( ! resp.ok ) {
status.fail( `Invalid stack ${stack}` );
return;
}

return resp.json().then( data => {
return resp.text().then( text => {
const data = JSON.parse( text );
status.stop();
connect( data );
});
connect( data, !! argv.command );
} );
}).catch( e => {
status.fail( `Could not fetch details for ${stack}` );
status.fail( `Could create session ${stack} (${e.message})` );
throw e;
});
} );
};

module.exports = {
command: 'ssh [stack]',
description: 'SSH into a stack.',
builder: subcommand => {
subcommand.option( 'app-server', {
description: 'Use an app server instead of the sandbox.',
default: false,
type: 'boolean',
} );
},
command: 'ssh [stack]',
description: 'SSH into a stack.',
builder: subcommand => {
subcommand.option( 'app-server', {
description: 'Use an app server instead of the sandbox.',
default: false,
type: 'boolean',
} );
subcommand.option( 'command', {
description: 'Run a given command and exit.',
type: 'string',
} );
},
handler,
};