Skip to content
Merged
Show file tree
Hide file tree
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
10 changes: 5 additions & 5 deletions packages/cli/src/commands/doctor/checkInstallation.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import semver from 'semver';
import commandExists from 'command-exists';

const PACKAGE_MANAGERS = {
YARN: 'YARN',
NPM: 'NPM',
};
export enum PACKAGE_MANAGERS {
YARN = 'YARN',
NPM = 'NPM',
}

const checkSoftwareInstalled = async (command: string) => {
try {
Expand Down Expand Up @@ -32,4 +32,4 @@ const doesSoftwareNeedToBeFixed = ({
);
};

export {PACKAGE_MANAGERS, checkSoftwareInstalled, doesSoftwareNeedToBeFixed};
export {checkSoftwareInstalled, doesSoftwareNeedToBeFixed};
23 changes: 3 additions & 20 deletions packages/cli/src/commands/doctor/healthchecks/cocoaPods.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,15 @@
import execa from 'execa';
import chalk from 'chalk';
import readline from 'readline';
import wcwidth from 'wcwidth';
import {logger} from '@react-native-community/cli-tools';
import {checkSoftwareInstalled} from '../checkInstallation';
import {
promptCocoaPodsInstallationQuestion,
runSudo,
} from '../../../tools/installPods';
import {removeMessage} from './common';
import {brewInstall} from '../../../tools/brewInstall';
import {HealthCheckInterface} from '../types';

function calculateQuestionSize(promptQuestion: string) {
return Math.max(
1,
Math.ceil(wcwidth(promptQuestion) / (process.stdout.columns || 80)),
);
}

function clearQuestion(promptQuestion: string) {
readline.moveCursor(
process.stdout,
0,
-calculateQuestionSize(promptQuestion),
);
readline.clearScreenDown(process.stdout);
}

export default {
label: 'CocoaPods',
getDiagnostics: async () => ({
Expand All @@ -49,7 +32,7 @@ export default {
const loaderSucceedMessage = `CocoaPods (installed with ${installMethodCapitalized})`;

// Remove the prompt after the question of how to install CocoaPods is answered
clearQuestion(promptQuestion);
removeMessage(promptQuestion);

if (installMethod === 'gem') {
loader.start(loaderInstallationMessage);
Expand All @@ -69,7 +52,7 @@ export default {
return loader.succeed(loaderSucceedMessage);
} catch (error) {
loader.fail();
logger.log(chalk.dim(`\n${error}`));
logger.log(chalk.dim(`\n${error.message}`));

return logger.log(
`An error occured while trying to install CocoaPods. Please try again manually: ${chalk.bold(
Expand Down
21 changes: 19 additions & 2 deletions packages/cli/src/commands/doctor/healthchecks/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import {logger} from '@react-native-community/cli-tools';
import chalk from 'chalk';
import readline from 'readline';
import wcwidth from 'wcwidth';
import stripAnsi from 'strip-ansi';
import {logger} from '@react-native-community/cli-tools';

// Space is necessary to keep correct ordering on screen
const logMessage = (message: string) => logger.log(` ${message}`);
Expand Down Expand Up @@ -34,4 +37,18 @@ const logManualInstallation = ({
}
};

export {logManualInstallation};
// Calculate the size of a message on terminal based on rows
function calculateMessageSize(message: string) {
return Math.max(
1,
Math.ceil(wcwidth(stripAnsi(message)) / (process.stdout.columns || 80)),
);
}

// Clear the message from the terminal
function removeMessage(message: string) {
readline.moveCursor(process.stdout, 0, -calculateMessageSize(message));
readline.clearScreenDown(process.stdout);
}

export {logManualInstallation, removeMessage};
113 changes: 87 additions & 26 deletions packages/cli/src/commands/doctor/healthchecks/iosDeploy.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,119 @@
import execa from 'execa';
import chalk from 'chalk';
// @ts-ignore untyped
import inquirer from 'inquirer';
import {logger} from '@react-native-community/cli-tools';
import {checkSoftwareInstalled, PACKAGE_MANAGERS} from '../checkInstallation';
import {packageManager} from './packageManagers';
import {logManualInstallation} from './common';
import {logManualInstallation, removeMessage} from './common';
import {HealthCheckInterface} from '../types';
import {Ora} from 'ora';

const getInstallationCommand = () => {
const label = 'ios-deploy';

const installationWithYarn = 'yarn global add ios-deploy';
const installationWithNpm = 'npm install ios-deploy --global';

const identifyInstallationCommand = () => {
if (packageManager === PACKAGE_MANAGERS.YARN) {
return 'yarn global add ios-deploy';
return installationWithYarn;
}

if (packageManager === PACKAGE_MANAGERS.NPM) {
return 'npm install ios-deploy --global';
return installationWithNpm;
}

return undefined;
};

const installLibrary = async ({
installationCommand,
packageManagerToUse,
loader,
}: {
installationCommand: string;
packageManagerToUse: 'yarn' | 'npm';
loader: Ora;
}) => {
try {
loader.start(`${label} (installing with ${packageManagerToUse})`);

const installationCommandArgs = installationCommand.split(' ');

await execa(installationCommandArgs[0], installationCommandArgs.splice(1));

loader.succeed(`${label} (installed with ${packageManagerToUse})`);
} catch (error) {
loader.fail();
logger.log(chalk.dim(`\n${error.message}`));

logManualInstallation({
healthcheck: 'ios-deploy',
command: installationCommand,
});
}
};

export default {
label: 'ios-deploy',
label,
isRequired: false,
getDiagnostics: async () => ({
needsToBeFixed: await checkSoftwareInstalled('ios-deploy'),
}),
runAutomaticFix: async ({loader}) => {
const installationCommand = getInstallationCommand();
loader.stop();

const installationCommand = identifyInstallationCommand();

// This means that we couldn't "guess" the package manager
if (installationCommand === undefined) {
loader.fail();
const promptQuestion = `ios-deploy needs to be installed either by ${chalk.bold(
'yarn',
)} ${chalk.reset('or')} ${chalk.bold(
'npm',
)} ${chalk.reset()}, which one do you want to use?`;
const installWithYarn = 'yarn';
const installWithNpm = 'npm';
const skipInstallation = 'Skip installation';

// Then we just print out the URL that the user can head to download the library
logManualInstallation({
healthcheck: 'ios-deploy',
url: 'https://github.com/ios-control/ios-deploy#readme',
});
return;
}
const {chosenPackageManager} = await inquirer.prompt([
{
type: 'list',
name: 'chosenPackageManager',
message: promptQuestion,
choices: [installWithYarn, installWithNpm, skipInstallation],
},
]);

try {
const installationCommandArgs = installationCommand.split(' ');
removeMessage(`? ${promptQuestion} ${chosenPackageManager}`);

await execa(
installationCommandArgs[0],
installationCommandArgs.splice(1),
);
if (chosenPackageManager === skipInstallation) {
loader.fail();

loader.succeed();
} catch (_error) {
loader.fail();
// Then we just print out the URL that the user can head to download the library
logManualInstallation({
healthcheck: 'ios-deploy',
url: 'https://github.com/ios-control/ios-deploy#readme',
});

logManualInstallation({
healthcheck: 'ios-deploy',
command: installationCommand,
return;
}

const shouldInstallWithYarn = chosenPackageManager === installWithYarn;

return installLibrary({
installationCommand: shouldInstallWithYarn
? installationWithYarn
: installationWithNpm,
loader,
packageManagerToUse: chosenPackageManager,
});
}

return installLibrary({
installationCommand,
packageManagerToUse: packageManager!.toLowerCase() as 'yarn' | 'npm',
loader,
});
},
} as HealthCheckInterface;
3 changes: 1 addition & 2 deletions packages/cli/src/tools/installPods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import chalk from 'chalk';
import ora from 'ora';
// @ts-ignore untyped
import inquirer from 'inquirer';
import stripAnsi from 'strip-ansi';
import {logger} from '@react-native-community/cli-tools';
import {NoopLoader} from './loader';
// @ts-ignore untyped
Expand Down Expand Up @@ -74,7 +73,7 @@ async function promptCocoaPodsInstallationQuestion(): Promise<
return {
installMethod: shouldInstallWithGem ? 'gem' : 'homebrew',
// This is used for removing the message in `doctor` after it's answered
promptQuestion: `? ${stripAnsi(promptQuestion)} ${
promptQuestion: `? ${promptQuestion} ${
shouldInstallWithGem ? installWithGem : installWithHomebrew
}`,
};
Expand Down