Skip to content

Commit

Permalink
Show help for configs allowed for subcommands and flags. (#55)
Browse files Browse the repository at this point in the history
Co-authored-by: Priyansh Garg <[email protected]>
  • Loading branch information
itsspriyansh and garg3133 authored Sep 3, 2024
1 parent f4304f1 commit 51c3e20
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 40 deletions.
7 changes: 4 additions & 3 deletions src/commands/android/androidSetup.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import colors from 'ansi-colors';
import boxen from 'boxen';
import {execSync} from 'child_process';
import * as dotenv from 'dotenv';
import fs from 'fs';
import os from 'os';
import path from 'path';
import untildify from 'untildify';
import {prompt} from 'inquirer';
import boxen from 'boxen';

import Logger from '../../logger';
import {getPlatformName, symbols} from '../../utils';
Expand All @@ -15,18 +15,19 @@ import {
ABI, AVAILABLE_OPTIONS, BINARY_TO_PACKAGE_NAME, DEFAULT_CHROME_VERSIONS,
DEFAULT_FIREFOX_VERSION, NIGHTWATCH_AVD, SETUP_CONFIG_QUES
} from './constants';
import DOWNLOADS from './downloads.json';
import {AndroidSetupResult, Options, OtherInfo, Platform, SdkBinary, SetupConfigs} from './interfaces';
import {getSubcommandHelp} from './subcommands/help';
import {
checkJavaInstallation, downloadFirefoxAndroid, downloadWithProgressBar,
getAllAvailableOptions, getBinaryLocation, getBinaryNameForOS,
getFirefoxApkName, getLatestVersion, getSdkRootFromEnv, getSubcommandHelp
getFirefoxApkName, getLatestVersion, getSdkRootFromEnv
} from './utils/common';
import {
downloadAndSetupAndroidSdk, downloadSdkBuildTools, execBinarySync,
getBuildToolsAvailableVersions, getDefaultAndroidSdkRoot, installPackagesUsingSdkManager
} from './utils/sdk';

import DOWNLOADS from './downloads.json';


export class AndroidSetup {
Expand Down
4 changes: 2 additions & 2 deletions src/commands/android/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const AVAILABLE_SUBCOMMANDS: AvailableSubcommands = {
}]
},
install: {
description: 'Install APK or AVD on a device',
description: 'Install system images, AVDs, or APKs on a device',
flags: [
{
name: 'avd',
Expand All @@ -73,7 +73,7 @@ export const AVAILABLE_SUBCOMMANDS: AvailableSubcommands = {
{
name: 'deviceId',
alias: ['s'],
description: 'Id of the device to install the APK',
description: 'Id of the device to install the APK to if multiple devices are connected',
usageHelp: 'device_id'
}
]
Expand Down
2 changes: 1 addition & 1 deletion src/commands/android/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import colors from 'ansi-colors';
import {AndroidSetup} from './androidSetup';
import {Options} from './interfaces';
import {AndroidSubcommand} from './subcommands';
import {getSubcommandHelp} from './utils/common';
import {getSubcommandHelp} from './subcommands/help';
import {AndroidDotCommand} from './dotcommands';

export function handleAndroidCommand(args: string[], options: Options, argv: string[]): void {
Expand Down
121 changes: 111 additions & 10 deletions src/commands/android/subcommands/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import colors from 'ansi-colors';

import Logger from '../../../logger';
import {AVAILABLE_SUBCOMMANDS} from '../constants';
import {Subcommand} from './interfaces';
import {CliConfig, Subcommand} from './interfaces';

export function showHelp(subcommand: string) {
const subcmd = AVAILABLE_SUBCOMMANDS[subcommand];

const subcmdFlagUsage = subcmd.flags?.length ? ' [flag]' : '';
const subcmdFlagUsage = subcmd.flags.length ? ' [flag]' : '';
Logger.log(`Usage: ${colors.cyan(`npx @nightwatch/mobile-helper android ${subcommand}${subcmdFlagUsage} [configs]`)}\n`);

const subcmdFlagsHelp = getSubcommandFlagsHelp(subcmd);
Expand All @@ -17,18 +17,119 @@ export function showHelp(subcommand: string) {
}
}

export const getSubcommandFlagsHelp = (subcmd: Subcommand) => {
export const getSubcommandHelp = (): string => {
let output = '';
const longest = (xs: string[]) => Math.max.apply(null, xs.map(x => x.length));

if (subcmd.flags && subcmd.flags.length > 0) {
const optionLongest = longest(subcmd.flags.map(flag => `--${flag.name}`));
subcmd.flags.forEach(flag => {
const flagStr = `--${flag.name}`;
const optionPadding = new Array(Math.max(optionLongest - flagStr.length + 3, 0)).join('.');
output += ` ${flagStr} ${colors.grey(optionPadding)} ${colors.gray(flag.description)}\n`;
output += `Usage: ${colors.cyan('npx @nightwatch/mobile-helper android SUBCOMMAND [flag] [configs]')}\n`;
output += ' Perform common Android SDK operations using subcommands.\n\n';
output += `${colors.yellow('Subcommands (with available flags and configs):')}\n`;

// A subcommand can allow multiple flags to facilitate different workflows, and each flag can
// allow multiple configs to customize the workflow.
// But, if a subcommand has a single workflow, then it doesn't require any flag and can have
// multiple configs directly associated with the subcommand itself.
Object.keys(AVAILABLE_SUBCOMMANDS).forEach(subcommand => {
const subcmd = AVAILABLE_SUBCOMMANDS[subcommand];

const subcmdFlagsUsage = subcmd.flags?.map(flag => `[--${flag.name}]`).join(' ') || '';
const subcmdConfigsUsage = generateConfigsUsageString(subcmd.cliConfigs || []);

// Display the subcommand name along with flags in the format:
// 'subcommand [--flag1] [--flag2]'
// OR
// Display the subcommand name along with direct configs in the format:
// 'subcommand [--config1 <usageHelp>] [--config2 <usageHelp>]'
output += ` ${colors.cyan(subcommand)} ${subcmdFlagsUsage}${subcmdConfigsUsage}\n`;
output += ` ${colors.gray(subcmd.description)}\n`;

// Append a list of configs allowed for the subcommand, along with their aliases and description.
if (subcmd.cliConfigs) {
const configsWithAlias = getConfigsWithAlias(subcmd.cliConfigs);

subcmd.cliConfigs.forEach((config, idx) => {
const padding = generatePadding(configsWithAlias, configsWithAlias[idx].length);
output += ` ${configsWithAlias[idx]} ${colors.grey(padding)} ${colors.gray(config.description)}\n`;
});
}

output += getSubcommandFlagsHelp(subcmd);
output += '\n';
});

return output;
};

/**
* Display a list of flags followed by their allowed configs for a subcommand.
*/
export const getSubcommandFlagsHelp = (subcmd: Subcommand): string => {
let output = '';

if (subcmd.flags.length) {
// Generate a list of flags usage with configs in the format:
// '--flag1 [--config11 <usageHelp>] [--config12 <usageHelp>]',
// '--flag2 [--config21 <usageHelp>] [--config22 <usageHelp>]'
const flagsUsageWithConfigs = subcmd.flags.map((flag) => {
let flagHelp = `--${flag.name}`;

if (flag.cliConfigs) {
flagHelp += ' ' + generateConfigsUsageString(flag.cliConfigs);
}

return flagHelp;
});

// Generate final help output for each flag.
subcmd.flags.forEach((flag, idx) => {
const padding = generatePadding(flagsUsageWithConfigs, flagsUsageWithConfigs[idx].length);
output += ` ${flagsUsageWithConfigs[idx]} ${colors.grey(padding)} ${colors.gray(flag.description)}\n`;

// Append a list of configs allowed for the flag, along with their aliases and description.
if (flag.cliConfigs) {
const configsWithAlias = getConfigsWithAlias(flag.cliConfigs);

flag.cliConfigs.forEach((config, idx) => {
const padding = generatePadding(configsWithAlias, configsWithAlias[idx].length);
output += ` ${configsWithAlias[idx]} ${colors.grey(padding)} ${colors.gray(config.description)}\n`;
});
}
});
}

return output;
};

/*
* Generate a string of configs in the format:
* [--config1 <usageHelp>] [--config2 <usageHelp>] ...
*/
const generateConfigsUsageString = (configs: CliConfig[]): string => {
let configsStr = '';
configs.forEach(config => {
configsStr += `[--${config.name} <${config.usageHelp}>]`;
});

return configsStr;
};

/**
* Generate a list of configs with their aliases in the format:
* '--config1 | -c11 | -c12',
* '--config2 | -c21 | -c22'
*/
const getConfigsWithAlias = (configs: CliConfig[]): string[] => {
const configsWithAlias = configs.map(config => {
const configAlias = config.alias.map(alias => `-${alias}`).join(' | ');

return `--${config.name}` + (configAlias ? ` | ${configAlias}` : '');
});

return configsWithAlias;
};

const generatePadding = (array: string[], length: number): string => {
const longest = (xs: string[]) => Math.max.apply(null, xs.map(x => x.length));
const padding = new Array(Math.max(longest(array) - length + 3, 0)).join('.');

return padding;
};
3 changes: 2 additions & 1 deletion src/commands/android/subcommands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import Logger from '../../../logger';
import {getPlatformName} from '../../../utils';
import {AVAILABLE_SUBCOMMANDS} from '../constants';
import {Options, Platform} from '../interfaces';
import {checkJavaInstallation, getSdkRootFromEnv, getSubcommandHelp} from '../utils/common';
import {checkJavaInstallation, getSdkRootFromEnv} from '../utils/common';
import {getSubcommandHelp} from './help';
import {connect} from './connect';
import {showHelp} from './help';
import {install} from './install';
Expand Down
24 changes: 1 addition & 23 deletions src/commands/android/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@ import which from 'which';
import Logger from '../../../logger';
import {symbols} from '../../../utils';
import {
ABI, AVAILABLE_OPTIONS, AVAILABLE_SUBCOMMANDS,
DEFAULT_CHROME_VERSIONS, DEFAULT_FIREFOX_VERSION, SDK_BINARY_LOCATIONS
ABI, AVAILABLE_OPTIONS, DEFAULT_CHROME_VERSIONS, DEFAULT_FIREFOX_VERSION, SDK_BINARY_LOCATIONS
} from '../constants';
import {Platform, SdkBinary} from '../interfaces';
import {getSubcommandFlagsHelp} from '../subcommands/help';

export const getAllAvailableOptions = () => {
const mainOptions = Object.keys(AVAILABLE_OPTIONS);
Expand Down Expand Up @@ -212,23 +210,3 @@ export const checkJavaInstallation = (cwd: string): boolean => {
return false;
}
};

export const getSubcommandHelp = (): string => {
let output = '';

output += `Usage: ${colors.cyan('npx @nightwatch/mobile-helper android SUBCOMMAND [flag] [configs]')}\n`;
output += ' Perform common Android SDK operations using subcommands.\n\n';
output += `${colors.yellow('Subcommands (with available flags and configs):')}\n`;

Object.keys(AVAILABLE_SUBCOMMANDS).forEach(subcommand => {
const subcmd = AVAILABLE_SUBCOMMANDS[subcommand];
const subcmdOptions = subcmd.flags?.map(flag => `[--${flag.name}]`).join(' ') || '';

output += ` ${colors.cyan(subcommand)} ${subcmdOptions}\n`;
output += ` ${colors.gray(subcmd.description)}\n`;

output += getSubcommandFlagsHelp(subcmd);
});

return output;
};

0 comments on commit 51c3e20

Please sign in to comment.