Skip to content

Commit 8545629

Browse files
feat: drop support for macOS Sierra and below
Drop support for macOS Sierra and below as we are no longer testing this OS. Drop a line on stderr on each CLI command and inform the user that this OS is not supported. Change the public API (getSystemWarnings) to return objects with information about the severity of the warnings. This way the consumer can decide how to handle the warnings. Fix an issue when getting macOS version from System Profile - the code was not working when version has two numbers (10.14 for example). Add new method in logger that allows printing to stderr. It should be used instead of `console.error`, so we can make the code testable.
1 parent fc5dba3 commit 8545629

14 files changed

+95
-35
lines changed

lib/commands/debug.ts

+7
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ export class DebugIOSCommand implements ICommand {
135135
private $platformService: IPlatformService,
136136
private $options: IOptions,
137137
private $injector: IInjector,
138+
private $sysInfo: ISysInfo,
138139
private $projectData: IProjectData,
139140
$iosDeviceOperations: IIOSDeviceOperations,
140141
$iOSSimulatorLogProvider: Mobile.IiOSSimulatorLogProvider) {
@@ -161,6 +162,12 @@ export class DebugIOSCommand implements ICommand {
161162
this.$errors.fail(`Timeout option specifies the seconds NativeScript CLI will wait to find the inspector socket port from device's logs. Must be a number.`);
162163
}
163164

165+
if (this.$options.inspector) {
166+
const macOSWarning = await this.$sysInfo.getMacOSWarningMessage();
167+
if (macOSWarning && macOSWarning.severity === SystemWarningsSeverity.high) {
168+
this.$errors.fail(`You cannot use NativeScript Inspector on this OS. To use it, please update your OS.`);
169+
}
170+
}
164171
const result = await this.debugPlatformCommand.canExecute(args);
165172
return result;
166173
}

lib/common/declarations.d.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,12 @@ interface IDeviceLiveSyncService extends IDeviceLiveSyncServiceBase {
11431143
afterInstallApplicationAction?(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[]): Promise<boolean>;
11441144
}
11451145

1146+
interface ISystemWarning {
1147+
message: string;
1148+
severity: SystemWarningsSeverity;
1149+
toString?: () => string;
1150+
}
1151+
11461152
interface ISysInfo {
11471153
getSysInfo(config?: NativeScriptDoctor.ISysInfoConfig): Promise<NativeScriptDoctor.ISysInfoData>;
11481154
/**
@@ -1163,15 +1169,15 @@ interface ISysInfo {
11631169

11641170
/**
11651171
* Gets all global warnings for the current environment, for example Node.js version compatibility, OS compatibility, etc.
1166-
* @return {Promise<string[]>} All warnings. Empty array is returned in case the system is setup correctly.
1172+
* @return {Promise<ISystemWarning[]>} All warnings. Empty array is returned in case the system is setup correctly.
11671173
*/
1168-
getSystemWarnings(): Promise<string[]>;
1174+
getSystemWarnings(): Promise<ISystemWarning[]>;
11691175

11701176
/**
11711177
* Gets warning message for current macOS version.
11721178
* @return {Promise<string>} Message in case the current macOS version is deprecated, null otherwise.
11731179
*/
1174-
getMacOSWarningMessage(): Promise<string>;
1180+
getMacOSWarningMessage(): Promise<ISystemWarning>;
11751181

11761182
/**
11771183
* Returns the value of engines.node key from CLI's package.json file.

lib/common/definitions/logger.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ interface ILogger {
1616
prepare(item: any): string;
1717
printInfoMessageOnSameLine(message: string): void;
1818
printMsgWithTimeout(message: string, timeout: number): Promise<void>;
19+
printOnStderr(formatStr?: any, ...args: any[]): void;
1920
}

lib/common/host-info.ts

+1-11
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,7 @@ export class HostInfo implements IHostInfo {
5757
try {
5858
const systemProfileOutput = await this.$childProcess.exec(systemProfileCommand);
5959

60-
// Output of command is similar to:
61-
/*
62-
Software:
63-
64-
System Software Overview:
65-
66-
System Version: macOS 10.13.3 (17D47)
67-
Kernel Version: Darwin 17.4.0
68-
Time since boot: 68 days 22:12
69-
*/
70-
const versionRegExp = /System Version:\s+?macOS\s+?(\d+\.\d+)\.\d+\s+/g;
60+
const versionRegExp = /System Version:\s+?macOS\s+?(\d+\.\d+)(\.\d+)?\s+/g;
7161
const regExpMatchers = versionRegExp.exec(systemProfileOutput);
7262
const macOSVersion = regExpMatchers && regExpMatchers[1];
7363
if (macOSVersion) {

lib/common/logger.ts

+6
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ export class Logger implements ILogger {
148148
this.write(formattedMessage);
149149
}
150150

151+
public printOnStderr(...args: string[]): void {
152+
if (process.stderr) {
153+
process.stderr.write(util.format.apply(null, args));
154+
}
155+
}
156+
151157
private getPasswordEncodedArguments(args: string[]): string[] {
152158
return _.map(args, argument => {
153159
if (typeof argument === 'string' && !!argument.match(/password/i)) {

lib/common/test/unit-tests/host-info.ts

+21
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,27 @@ describe("hostInfo", () => {
6565
assert.equal(calledCommand, "system_profiler SPSoftwareDataType -detailLevel mini");
6666
});
6767

68+
it("returns correct macOS version based on system_profile, when version has two numbers only", async () => {
69+
const testInjector = createTestInjector();
70+
const hostInfo = testInjector.resolve<IHostInfo>("hostInfo");
71+
const childProcess = testInjector.resolve<IChildProcess>("childProcess");
72+
let calledCommand = "";
73+
childProcess.exec = async (command: string, options?: any, execOptions?: IExecOptions): Promise<any> => {
74+
calledCommand = command;
75+
return `Software:
76+
77+
System Software Overview:
78+
79+
System Version: macOS 10.14 (18A391)
80+
Kernel Version: Darwin 18.0.0
81+
Time since boot: 1 day 5:52`;
82+
};
83+
84+
const macOSVersion = await hostInfo.getMacOSVersion();
85+
assert.deepEqual(macOSVersion, "10.14");
86+
assert.equal(calledCommand, "system_profiler SPSoftwareDataType -detailLevel mini");
87+
});
88+
6889
it("returns correct macOS version when system_profile call throws", async () => {
6990
const testInjector = createTestInjector();
7091
const hostInfo = testInjector.resolve<IHostInfo>("hostInfo");

lib/common/test/unit-tests/stubs.ts

+4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ export class CommonLoggerStub implements ILogger {
4141
printMarkdown(message: string): void {
4242
this.output += message;
4343
}
44+
45+
printOnStderr(...args: string[]): void {
46+
// nothing to do here
47+
}
4448
}
4549

4650
export class ErrorsStub implements IErrors {

lib/common/verify-node-version.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ export function verifyNodeVersion(): void {
4848
}
4949

5050
var nodeWarning = getNodeWarning();
51-
if (nodeWarning) {
52-
console.warn((os.EOL + nodeWarning + os.EOL).yellow.bold);
51+
if (nodeWarning && nodeWarning.message) {
52+
console.warn((`${os.EOL}${nodeWarning.message}${os.EOL}`).yellow.bold);
5353
}
5454
}
5555

56-
export function getNodeWarning(): string {
56+
export function getNodeWarning(): ISystemWarning {
5757
var verificationOpts = getNodeVersionOpts();
5858
var cliName = verificationOpts.cliName;
5959
var supportedVersionsRange = verificationOpts.supportedVersionsRange;
@@ -78,6 +78,9 @@ export function getNodeWarning(): string {
7878
}
7979
}
8080

81-
return warningMessage;
81+
return {
82+
message: warningMessage,
83+
severity: SystemWarningsSeverity.medium
84+
};
8285
}
8386
/* tslint:enable */

lib/constants.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,10 @@ export class AssetConstants {
186186
export class MacOSVersions {
187187
public static Sierra = "10.12";
188188
public static HighSierra = "10.13";
189+
public static Mojave = "10.14";
189190
}
190191

191-
export const MacOSDeprecationStringFormat = "Support for macOS %s is deprecated and will be removed in one of the next releases of NativeScript. Please, upgrade to the latest macOS version.";
192+
export const MacOSDeprecationStringFormat = "NativeScript does not support macOS %s and some functionality may not work. Please, upgrade to the latest macOS version.";
192193
export const PROGRESS_PRIVACY_POLICY_URL = "https://www.progress.com/legal/privacy-policy";
193194
export class SubscribeForNewsletterMessages {
194195
public static AgreeToReceiveEmailMsg = "I agree".green.bold + " to receive email communications from Progress Software or its Partners (`https://www.progress.com/partners/partner-directory`)," +

lib/definitions/system-warnings.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare const enum SystemWarningsSeverity {
2+
medium = "medium",
3+
high = "high"
4+
}

lib/nativescript-cli.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@ import { settlePromises } from "./common/helpers";
2626
const $sysInfo = $injector.resolve<ISysInfo>("sysInfo");
2727
const macOSWarning = await $sysInfo.getMacOSWarningMessage();
2828
if (macOSWarning) {
29-
const message = EOL + macOSWarning + EOL ;
30-
logger.warn(message);
29+
const message = `${EOL}${macOSWarning.message}${EOL}`;
30+
if (macOSWarning.severity === SystemWarningsSeverity.high) {
31+
logger.printOnStderr(message.red.bold);
32+
} else {
33+
logger.warn(message);
34+
}
3135
}
3236

3337
const commandDispatcher: ICommandDispatcher = $injector.resolve("commandDispatcher");

lib/sys-info.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,17 @@ export class SysInfo implements ISysInfo {
3535
}
3636

3737
@exported("sysInfo")
38-
public async getSystemWarnings(): Promise<string[]> {
39-
const warnings: string[] = [];
38+
public async getSystemWarnings(): Promise<ISystemWarning[]> {
39+
const warnings: ISystemWarning[] = [];
4040
const macOSWarningMessage = await this.getMacOSWarningMessage();
4141
if (macOSWarningMessage) {
42+
macOSWarningMessage.toString = function() { return this.message; };
4243
warnings.push(macOSWarningMessage);
4344
}
4445

4546
const nodeWarning = getNodeWarning();
4647
if (nodeWarning) {
48+
nodeWarning.toString = function() { return this.message; };
4749
warnings.push(nodeWarning);
4850
}
4951

@@ -57,10 +59,13 @@ export class SysInfo implements ISysInfo {
5759
return jsonContent && jsonContent.engines && jsonContent.engines.node;
5860
}
5961

60-
public async getMacOSWarningMessage(): Promise<string> {
62+
public async getMacOSWarningMessage(): Promise<ISystemWarning> {
6163
const macOSVersion = await this.$hostInfo.getMacOSVersion();
6264
if (macOSVersion && macOSVersion < MacOSVersions.HighSierra) {
63-
return format(MacOSDeprecationStringFormat, macOSVersion);
65+
return {
66+
message: format(MacOSDeprecationStringFormat, macOSVersion),
67+
severity: SystemWarningsSeverity.high
68+
};
6469
}
6570

6671
return null;

test/stubs.ts

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export class LoggerStub implements ILogger {
4242
}
4343

4444
printMarkdown(message: string): void { }
45+
46+
printOnStderr(...args: string[]): void {
47+
// nothing to do here
48+
}
4549
}
4650

4751
export class ProcessServiceStub implements IProcessService {

test/sys-info.ts

+14-10
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ describe("sysInfo", () => {
3232
};
3333

3434
describe("getSystemWarnings", () => {
35-
const getSystemWarnings = async (opts?: { nodeJsWarning?: string, macOSDeprecatedVersion?: string }): Promise<string[]> => {
36-
sandbox.stub(verifyNodeVersion, "getNodeWarning").returns(opts && opts.nodeJsWarning);
35+
const getSystemWarnings = async (opts?: { nodeJsWarning?: string, macOSDeprecatedVersion?: string }): Promise<ISystemWarning[]> => {
36+
sandbox.stub(verifyNodeVersion, "getNodeWarning").returns(opts && opts.nodeJsWarning ? { message: opts.nodeJsWarning, severity: SystemWarningsSeverity.medium } : null);
3737

3838
const testInjector = createTestInjector();
3939
const $hostInfo = testInjector.resolve<IHostInfo>("hostInfo");
@@ -50,28 +50,31 @@ describe("sysInfo", () => {
5050

5151
it("returns correct single warning when macOS version is deprecated", async () => {
5252
const macOSDeprecatedVersion = MacOSVersions.Sierra;
53-
const macOSWarning = format(MacOSDeprecationStringFormat, macOSDeprecatedVersion);
53+
const macOSWarning = { message: format(MacOSDeprecationStringFormat, macOSDeprecatedVersion), severity: SystemWarningsSeverity.high };
5454
const warnings = await getSystemWarnings({ macOSDeprecatedVersion });
55+
_.each(warnings, warning => delete warning.toString);
5556
assert.deepEqual(warnings, [macOSWarning]);
5657
});
5758

5859
it("returns correct single warning when Node.js version is deprecated", async () => {
59-
const nodeJsWarning = "Node.js Warning";
60-
const warnings = await getSystemWarnings({ nodeJsWarning });
60+
const nodeJsWarning = { message: "Node.js Warning", severity: SystemWarningsSeverity.medium };
61+
const warnings = await getSystemWarnings({ nodeJsWarning: nodeJsWarning.message });
62+
_.each(warnings, warning => delete warning.toString);
6163
assert.deepEqual(warnings, [nodeJsWarning]);
6264
});
6365

6466
it("returns correct warnings when both Node.js and macOS versions are deprecated", async () => {
6567
const macOSDeprecatedVersion = MacOSVersions.Sierra;
66-
const macOSWarning = format(MacOSDeprecationStringFormat, macOSDeprecatedVersion);
67-
const nodeJsWarning = "Node.js Warning";
68-
const warnings = await getSystemWarnings({ macOSDeprecatedVersion, nodeJsWarning });
68+
const macOSWarning = { message: format(MacOSDeprecationStringFormat, macOSDeprecatedVersion), severity: SystemWarningsSeverity.high };
69+
const nodeJsWarning = { message: "Node.js Warning", severity: SystemWarningsSeverity.medium };
70+
const warnings = await getSystemWarnings({ macOSDeprecatedVersion, nodeJsWarning: nodeJsWarning.message });
71+
_.each(warnings, warning => delete warning.toString);
6972
assert.deepEqual(warnings, [macOSWarning, nodeJsWarning]);
7073
});
7174
});
7275

7376
describe("getMacOSWarningMessage", () => {
74-
const getMacOSWarning = async (macOSDeprecatedVersion?: string): Promise<string> => {
77+
const getMacOSWarning = async (macOSDeprecatedVersion?: string): Promise<ISystemWarning> => {
7578
sandbox.stub(verifyNodeVersion, "getNodeWarning").returns(null);
7679

7780
const testInjector = createTestInjector();
@@ -89,8 +92,9 @@ describe("sysInfo", () => {
8992

9093
it("returns correct single warning when macOS version is deprecated", async () => {
9194
const macOSDeprecatedVersion = MacOSVersions.Sierra;
92-
const macOSWarning = format(MacOSDeprecationStringFormat, macOSDeprecatedVersion);
95+
const macOSWarning: ISystemWarning = { message: format(MacOSDeprecationStringFormat, macOSDeprecatedVersion), severity: SystemWarningsSeverity.high };
9396
const warning = await getMacOSWarning(macOSDeprecatedVersion);
97+
delete warning.toString;
9498
assert.deepEqual(warning, macOSWarning);
9599
});
96100
});

0 commit comments

Comments
 (0)