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

fix: Improve tiapp sdk-version handling #693

Merged
merged 1 commit into from
Oct 4, 2024
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
48 changes: 41 additions & 7 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { basename, dirname, join } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { unique } from './util/unique.js';
import { ticonfig } from './util/ticonfig.js';
import { initSDK } from './util/tisdk.js';
import { initSDK, typeLabels } from './util/tisdk.js';
import { expand } from './util/expand.js';
import { arrayify } from './util/arrayify.js';
import * as version from './util/version.js';
Expand Down Expand Up @@ -818,7 +818,14 @@ export class CLI {
await Promise.all(paths.map(p => this.scanHooks(p)));
}

await this.loadSDK({ cmdName, cwd });
try {
await this.loadSDK({ cmdName, cwd });
} catch (err) {
if (sdkCommands[cmdName]) {
throw err;
}
// if it's not a sdk command, then it's ok if the SDK failed to load
}
await this.loadCommand(cmd);
});

Expand Down Expand Up @@ -1044,7 +1051,8 @@ export class CLI {
installPath,
sdk,
sdkPaths,
sdks
sdks,
tiappSdkVersion
} = await initSDK({
config: this.config,
cwd,
Expand All @@ -1069,10 +1077,36 @@ export class CLI {
this.sdk = sdk;
this.argv.sdk = sdk?.name;

if (sdkCommands[cmdName] && !sdk) {
throw new TiError('No Titanium SDKs found', {
after: `You can download the latest Titanium SDK by running: ${cyan('titanium sdk install')}`
});
if (sdkCommands[cmdName]) {
const hasSDKs = Object.keys(sdks).length > 0;
if (!hasSDKs || !sdk) {
if (hasSDKs && tiappSdkVersion) {
throw new TiError(`The <sdk-version> in the tiapp.xml is set to "${tiappSdkVersion}", but this version is not installed`, {
after: `Available SDKs:\n${Object.values(sdks).map(sdk => ` ${cyan(sdk.name.padEnd(24))} ${gray(typeLabels[sdk.type])}`).join('\n')}`
});
}

throw new TiError('No Titanium SDKs found', {
after: `You can download the latest Titanium SDK by running: ${cyan('titanium sdk install')}`
});
}

try {
// check if the sdk is compatible with our version of node
sdk.packageJson = await fs.readJson(join(sdk.path, 'package.json'));

const current = process.versions.node;
const required = sdk.packageJson.vendorDependencies.node;
const supported = version.satisfies(current, required, true);

if (supported === false) {
throw new TiError(`Titanium SDK v${sdk.name} is incompatible with Node.js v${current}`, {
after: `Please install Node.js ${version.parseMax(required)} in order to use this version of the Titanium SDK.`
});
}
} catch (e) {
// do nothing
}
}

// render the banner
Expand Down
256 changes: 133 additions & 123 deletions src/util/setup-screens.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class SetupScreens {
let screen;
while (screen = this[`${next}Screen`]) {
next = (await screen.call(this)) || 'mainmenu';
this.logger.trace(`Next screen: ${next}`);
this.cli.debugLogger.trace(`Next screen: ${next}`);
}
}

Expand Down Expand Up @@ -162,7 +162,7 @@ export class SetupScreens {
{
type: prev => prev ? 'text' : null,
message: 'Path to the Android SDK',
initial: this.config.get('android.sdkPath', data?.android.sdk?.path),
initial: this.config.get('android.sdkPath', data?.android?.sdk?.path),
name: 'androidSdkPath',
validate: value => {
if (!value) {
Expand Down Expand Up @@ -291,158 +291,168 @@ export class SetupScreens {
busy.stop();
}

const distPPLabel = 'dist provisioning';
const len = distPPLabel.length;

if (Object.keys(data.ios.xcode).length) {
ok('Xcode'.padEnd(len), 'installed', `(${
Object
.keys(data.ios.xcode)
.filter(ver => ver !== '__selected__')
.map(ver => data.ios.xcode[ver].version)
.sort()
.join(', ')
})`);

const iosSdks = {};
for (const ver of Object.keys(data.ios.xcode)) {
if (ver !== '__selected__') {
for (const v of data.ios.xcode[ver].sdks) {
iosSdks[v] = 1;
if (data.ios) {
const distPPLabel = 'dist provisioning';
const len = distPPLabel.length;

if (Object.keys(data.ios.xcode).length) {
ok('Xcode'.padEnd(len), 'installed', `(${
Object
.keys(data.ios.xcode)
.filter(ver => ver !== '__selected__')
.map(ver => data.ios.xcode[ver].version)
.sort()
.join(', ')
})`);

const iosSdks = {};
for (const ver of Object.keys(data.ios.xcode)) {
if (ver !== '__selected__') {
for (const v of data.ios.xcode[ver].sdks) {
iosSdks[v] = 1;
}
}
}
}
if (Object.keys(iosSdks).length) {
ok('iOS SDK'.padEnd(len), 'installed', `(${Object.keys(iosSdks).sort().join(', ')})`);
if (Object.keys(iosSdks).length) {
ok('iOS SDK'.padEnd(len), 'installed', `(${Object.keys(iosSdks).sort().join(', ')})`);
} else {
warn('iOS SDK'.padEnd(len), 'no iOS SDKs found');
}
} else {
warn('iOS SDK'.padEnd(len), 'no iOS SDKs found');
warn('Xcode'.padEnd(len), 'no Xcode installations found');
warn('iOS SDK'.padEnd(len), 'no Xcode installations found');
}
} else {
warn('Xcode'.padEnd(len), 'no Xcode installations found');
warn('iOS SDK'.padEnd(len), 'no Xcode installations found');
}

if (data.ios.certs.wwdr) {
ok('WWDR cert'.padEnd(len), 'installed');
} else {
warn('WWDR cert'.padEnd(len), 'not found');
}
if (data.ios.certs.wwdr) {
ok('WWDR cert'.padEnd(len), 'installed');
} else {
warn('WWDR cert'.padEnd(len), 'not found');
}

let devCerts = 0;
let distCerts = 0;
let devCerts = 0;
let distCerts = 0;

for (const keychain of Object.keys(data.ios.certs.keychains)) {
if (data.ios.certs.keychains[keychain].developer) {
for (const i of data.ios.certs.keychains[keychain].developer) {
if (!Object.hasOwn(i, 'invalid') || i.invalid === false) {
devCerts++;
for (const keychain of Object.keys(data.ios.certs.keychains)) {
if (data.ios.certs.keychains[keychain].developer) {
for (const i of data.ios.certs.keychains[keychain].developer) {
if (!Object.hasOwn(i, 'invalid') || i.invalid === false) {
devCerts++;
}
}
}
}
if (data.ios.certs.keychains[keychain].distribution) {
for (const i of data.ios.certs.keychains[keychain].distribution) {
if (!Object.hasOwn(i, 'invalid') || i.invalid === false) {
distCerts++;
if (data.ios.certs.keychains[keychain].distribution) {
for (const i of data.ios.certs.keychains[keychain].distribution) {
if (!Object.hasOwn(i, 'invalid') || i.invalid === false) {
distCerts++;
}
}
}
}
}

if (devCerts) {
ok('developer cert'.padEnd(len), 'installed', `(${devCerts} found)`);
} else {
warn('developer cert'.padEnd(len), 'not found');
}
if (devCerts) {
ok('developer cert'.padEnd(len), 'installed', `(${devCerts} found)`);
} else {
warn('developer cert'.padEnd(len), 'not found');
}

if (distCerts) {
ok('distribution cert'.padEnd(len), 'installed', `(${distCerts} found)`);
} else {
warn('distribution cert'.padEnd(len), 'not found');
}
if (distCerts) {
ok('distribution cert'.padEnd(len), 'installed', `(${distCerts} found)`);
} else {
warn('distribution cert'.padEnd(len), 'not found');
}

const devPP = data.ios.provisioning.development.filter(i => {
return !Object.hasOwn(i, 'expired') || i.expired === false;
}).length;
if (devPP) {
ok('dev provisioning'.padEnd(len), 'installed', `(${devPP} found)`);
} else {
warn('dev provisioning'.padEnd(len), 'not found');
}
const devPP = data.ios.provisioning.development.filter(i => {
return !Object.hasOwn(i, 'expired') || i.expired === false;
}).length;
if (devPP) {
ok('dev provisioning'.padEnd(len), 'installed', `(${devPP} found)`);
} else {
warn('dev provisioning'.padEnd(len), 'not found');
}

const distPP = data.ios.provisioning.distribution.filter(i => {
return !Object.hasOwn(i, 'expired') || i.expired === false;
}).length + data.ios.provisioning.adhoc.filter(i => {
return !Object.hasOwn(i, 'expired') || i.expired === false;
}).length + data.ios.provisioning.enterprise.filter(i => {
return !Object.hasOwn(i, 'expired') || i.expired === false;
}).length;
if (distPP) {
ok(distPPLabel, 'installed', `(${distPP} found)`);
const distPP = data.ios.provisioning.distribution.filter(i => {
return !Object.hasOwn(i, 'expired') || i.expired === false;
}).length + data.ios.provisioning.adhoc.filter(i => {
return !Object.hasOwn(i, 'expired') || i.expired === false;
}).length + data.ios.provisioning.enterprise.filter(i => {
return !Object.hasOwn(i, 'expired') || i.expired === false;
}).length;
if (distPP) {
ok(distPPLabel, 'installed', `(${distPP} found)`);
} else {
warn(distPPLabel, 'not found');
}
} else {
warn(distPPLabel, 'not found');
log(yellow(' A Titanium SDK must be installed to detect Android environment'));
log(` To install the latest SDK, run: ${cyan('titanium sdk install')}`);
}
log();
}

log('Android Environment');
if (data.android.sdk?.path) {
ok('sdk', 'installed', `(${data.android.sdk.path})`);

if (data.android.sdk.platformTools && data.android.sdk.platformTools.path) {
if (data.android.sdk.platformTools.supported === 'maybe') {
warn('platform tools', `untested version ${data.android.sdk.platformTools.version}; may or may not work`);
} else if (data.android.sdk.platformTools.supported) {
ok('platform tools', 'installed', `(v${data.android.sdk.platformTools.version})`);
} else {
bad('platform tools', `unsupported version ${data.android.sdk.platformTools.version}`);
if (data.android) {
if (data.android.sdk?.path) {
ok('sdk', 'installed', `(${data.android.sdk.path})`);

if (data.android.sdk.platformTools && data.android.sdk.platformTools.path) {
if (data.android.sdk.platformTools.supported === 'maybe') {
warn('platform tools', `untested version ${data.android.sdk.platformTools.version}; may or may not work`);
} else if (data.android.sdk.platformTools.supported) {
ok('platform tools', 'installed', `(v${data.android.sdk.platformTools.version})`);
} else {
bad('platform tools', `unsupported version ${data.android.sdk.platformTools.version}`);
}
}
}

if (data.android.sdk.buildTools && data.android.sdk.buildTools.path) {
if (data.android.sdk.buildTools.supported === 'maybe') {
warn('build tools', `untested version ${data.android.sdk.buildTools.version}; may or may not work`);
} else if (data.android.sdk.buildTools.supported) {
ok('build tools', 'installed', `(v${data.android.sdk.buildTools.version})`);
} else {
bad('build tools', `unsupported version ${data.android.sdk.buildTools.version}`);
if (data.android.sdk.buildTools && data.android.sdk.buildTools.path) {
if (data.android.sdk.buildTools.supported === 'maybe') {
warn('build tools', `untested version ${data.android.sdk.buildTools.version}; may or may not work`);
} else if (data.android.sdk.buildTools.supported) {
ok('build tools', 'installed', `(v${data.android.sdk.buildTools.version})`);
} else {
bad('build tools', `unsupported version ${data.android.sdk.buildTools.version}`);
}
}
}

if (data.android.sdk.executables) {
if (data.android.sdk.executables.adb) {
ok('adb', 'installed', data.android.sdk.executables.adb);
} else {
bad('adb', '"adb" executable not found; please reinstall Android SDK');
}
if (data.android.sdk.executables.emulator) {
ok('emulator', 'installed', data.android.sdk.executables.emulator);
} else {
bad('emulator', '"emulator" executable not found; please reinstall Android SDK');
if (data.android.sdk.executables) {
if (data.android.sdk.executables.adb) {
ok('adb', 'installed', data.android.sdk.executables.adb);
} else {
bad('adb', '"adb" executable not found; please reinstall Android SDK');
}
if (data.android.sdk.executables.emulator) {
ok('emulator', 'installed', data.android.sdk.executables.emulator);
} else {
bad('emulator', '"emulator" executable not found; please reinstall Android SDK');
}
}
} else {
warn('sdk', 'Android SDK not found');
}
} else {
warn('sdk', 'Android SDK not found');
}

if (data.android.targets && Object.keys(data.android.targets).length) {
ok('targets', 'installed', `(${Object.keys(data.android.targets).length} found)`);
} else {
warn('targets', 'no targets found');
}
if (data.android.targets && Object.keys(data.android.targets).length) {
ok('targets', 'installed', `(${Object.keys(data.android.targets).length} found)`);
} else {
warn('targets', 'no targets found');
}

if (data.android.emulators?.length) {
ok('emulators', 'installed', `(${data.android.emulators.length} found)`);
} else {
warn('emulators', 'no emulators found');
}
if (data.android.emulators?.length) {
ok('emulators', 'installed', `(${data.android.emulators.length} found)`);
} else {
warn('emulators', 'no emulators found');
}

if (data.android.ndk) {
ok('ndk', 'installed', `(${data.android.ndk.version})`);
if (data.android.ndk.executables) {
ok('ndk-build', 'installed', `(${data.android.ndk.executables.ndkbuild})`);
if (data.android.ndk) {
ok('ndk', 'installed', `(${data.android.ndk.version})`);
if (data.android.ndk.executables) {
ok('ndk-build', 'installed', `(${data.android.ndk.executables.ndkbuild})`);
}
} else {
warn('ndk', 'Android NDK not found');
}
} else {
warn('ndk', 'Android NDK not found');
log(yellow(' A Titanium SDK must be installed to detect Android environment'));
log(` To install the latest SDK, run: ${cyan('titanium sdk install')}`);
}

log(); // end android
Expand Down Expand Up @@ -722,7 +732,7 @@ export class SetupScreens {
{
type: 'text',
message: 'Path to the Android SDK',
initial: this.config.get('android.sdkPath', data?.android.sdk?.path),
initial: this.config.get('android.sdkPath', data?.android?.sdk?.path),
name: 'androidSdkPath',
validate: value => {
if (!value) {
Expand Down Expand Up @@ -753,7 +763,7 @@ export class SetupScreens {
{
type: prev => prev ? 'text' : null,
message: 'Path to the Android NDK',
initial: this.config.get('android.ndkPath', data?.android.ndk?.path),
initial: this.config.get('android.ndkPath', data?.android?.ndk?.path),
name: 'androidNdkPath',
validate: value => {
if (!value) {
Expand Down
Loading
Loading