From 162ed9a40c2dcac4a70643d8b76b1eaa1aba975b Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Tue, 12 Jul 2022 11:57:24 -0400 Subject: [PATCH 01/30] feat(cli): add migrator for cap3 to cap4 --- cli/src/index.ts | 14 +- cli/src/tasks/migrate.ts | 582 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 595 insertions(+), 1 deletion(-) create mode 100644 cli/src/tasks/migrate.ts diff --git a/cli/src/index.ts b/cli/src/index.ts index c5f1be25c3..c6fe92409d 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -20,7 +20,7 @@ export async function run(): Promise { try { const config = await loadConfig(); runProgram(config); - } catch (e) { + } catch (e: any) { process.exitCode = isFatal(e) ? e.exitCode : 1; logger.error(e.message ? e.message : String(e)); } @@ -224,6 +224,18 @@ export function runProgram(config: Config): void { }), ); + program + .command('migrate') + .description( + 'Migrate your current Capacitor app to the latest major version of Capacitor.', + ) + .action( + wrapAction(async () => { + const { migrateCommand } = await import('./tasks/migrate'); + await migrateCommand(config); + }), + ); + program.arguments('[command]').action( wrapAction(async cmd => { if (typeof cmd === 'undefined') { diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts new file mode 100644 index 0000000000..5ac25f4c01 --- /dev/null +++ b/cli/src/tasks/migrate.ts @@ -0,0 +1,582 @@ +// import c from '../colors'; +import { writeFileSync, readFileSync, existsSync } from 'fs'; +import { join } from 'path'; + +import type { Config } from '../definitions'; +import { fatal } from '../errors'; +import { logger, logPrompt, logSuccess } from '../log'; +import { getCommandOutput } from '../util/subprocess'; + +let allDependencies: { [key: string]: any } = {}; +const libs = [ + '@capacitor/core', + '@capacitor/cli', + '@capacitor/ios', + '@capacitor/android', +]; +const plugins = [ + '@capacitor/action-sheet', + '@capacitor/app', + '@capacitor/app-launcher', + '@capacitor/browser', + '@capacitor/camera', + '@capacitor/clipboard', + '@capacitor/device', + '@capacitor/dialog', + '@capacitor/filesystem', + '@capacitor/geolocation', + '@capacitor/google-maps', + '@capacitor/haptics', + '@capacitor/keyboard', + '@capacitor/local-notifications', + '@capacitor/motion', + '@capacitor/network', + '@capacitor/push-notifications', + '@capacitor/screen-reader', + '@capacitor/share', + '@capacitor/splash-screen', + '@capacitor/status-bar', + '@capacitor/text-zoom', + '@capacitor/toast', +]; +let configData: Config | null = null; +const coreVersion = '^4.0.0-beta.2'; +const pluginVersion = '^4.0.0-beta.2'; + +export async function migrateCommand(config: Config): Promise { + configData = config; + allDependencies = { + ...(configData ? configData.app.package.dependencies : {}), + ...(configData ? configData.app.package.devDependencies : {}), + }; + + const daysLeft = daysUntil(new Date('11/01/2022')); + let warning = `Google Play Store requires a minimum target of SDK 31 by 1st November 2022`; + if (daysLeft > 0) { + warning += ` (${daysLeft} days left)`; + } + + const { migrateconfirm } = await logPrompt( + `Capacitor 4 sets a deployment target of iOS 13 and Android 12 (SDK 32). \n${warning}\n`, + { + type: 'text', + name: 'migrateconfirm', + message: `Are you sure you want to migrate? (Y/n)`, + initial: 'y', + }, + ); + + if (migrateconfirm === 'y') { + logger.info(`Migrating to Capacitor ${coreVersion}...`); + try { + if (configData === null) { + fatal('Config data missing'); + } + await installLatestNPMLibs(); + await migrateStoragePluginToPreferences(); + + if (allDependencies['@capacitor/ios']) { + // Set deployment target to 13.0 + updateFile( + join('ios', 'App', 'App.xcodeproj', 'project.pbxproj'), + 'IPHONEOS_DEPLOYMENT_TARGET = ', + ';', + '13.0', + ); + // Update Podfile to 13.0 + updateFile( + join('ios', 'App', 'Podfile'), + `platform :ios, '`, + `'`, + '13.0', + ); + // Remove touchesBegan + updateFile( + join('ios', 'App', 'App', 'AppDelegate.swift'), + `override func touchesBegan`, + `}`, + ); + // Remove NSAppTransportSecurity + removeKey( + join(configData.app.rootDir, 'ios', 'App', 'App', 'info.plist'), + 'NSAppTransportSecurity', + ); + // Remove USE_PUSH + replacePush( + join( + configData.app.rootDir, + 'ios', + 'App', + 'App.xcodeproj', + 'project.pbxproj', + ), + ); + // Remove from App Delegate + removeInFile( + join(configData.app.rootDir, 'ios', 'App', 'App', 'AppDelegate.swift'), + `#if USE_PUSH`, + `#endif`, + ); + } + + if (allDependencies['@capacitor/android']) { + // AndroidManifest.xml add attribute: 0) { + logger.info( + `IMPORTANT: Review https://next.capacitorjs.com/docs/updating/4-0#plugins for breaking changes in these plugins that you use: ${broken.join( + ', ', + )}.`, + ); + } + if (allDependencies['@capacitor/android']) { + logger.info( + 'Warning: The Android Gradle plugin was updated and it requires Java 11 to run. You may need to select this in Android Studio.', + ); + } +} + +function updateAndroidManifest(filename: string) { + const txt = readFile(filename); + if (!txt) { + return; + } + + // AndroidManifest.xml add attribute: tag`); + return; + } + writeFileSync(filename, replaced, 'utf-8'); + logger.info( + `Migrated AndroidManifest.xml by adding android:exported attribute to Activity.`, + ); +} + +function updateBuildGradle(filename: string) { + // In build.gradle add dependencies: + // classpath 'com.android.tools.build:gradle:7.2.1' + // classpath 'com.google.gms:google-services:4.3.10' + const txt = readFile(filename); + if (!txt) { + return; + } + const neededDeps: { [key: string]: string } = { + 'com.android.tools.build:gradle': '7.2.1', + 'com.google.gms:google-services': '4.3.10', + }; + let replaced = txt; + + for (const dep of Object.keys(neededDeps)) { + if (!replaced.includes(`classpath '${dep}`)) { + replaced = txt.replace( + 'dependencies {', + `dependencies {\n classpath '${dep}:${neededDeps[dep]}'`, + ); + } else { + // Update + replaced = setAllStringIn( + replaced, + `classpath '${dep}:`, + `'`, + neededDeps[dep], + ); + logger.info(`Migrated build.gradle set ${dep} = ${neededDeps[dep]}.`); + } + } + + // Replace jcenter() + const lines = replaced.split('\n'); + let inRepositories = false; + let hasMavenCentral = false; + let final = ''; + for (const line of lines) { + if (line.includes('repositories {')) { + inRepositories = true; + hasMavenCentral = false; + } else if (line.trim() == '}') { + // Make sure we have mavenCentral() + if (inRepositories && !hasMavenCentral) { + final += ' mavenCentral()\n'; + logger.info(`Migrated build.gradle added mavenCentral().`); + } + inRepositories = false; + } + if (inRepositories && line.trim() === 'mavenCentral()') { + hasMavenCentral = true; + } + if (inRepositories && line.trim() === 'jcenter()') { + // skip jCentral() + logger.info(`Migrated build.gradle removed jcenter().`); + } else { + final += line + '\n'; + } + } + + if (txt !== final) { + writeFileSync(filename, final, 'utf-8'); + return; + } +} + +function readFile(filename: string): string | undefined { + try { + if (!existsSync(filename)) { + logger.error(`Unable to find ${filename}. Try updating it manually`); + return; + } + return readFileSync(filename, 'utf-8'); + } catch (err) { + logger.error( + `Unable to read ${filename}. Verify it is not already open. ${err}`, + ); + } +} + +function updateAppBuildGradle(filename: string) { + const txt = readFile(filename); + if (!txt) { + return; + } + if (txt.includes('androidx.coordinatorlayout:coordinatorlayout:')) { + return; + } + + const replaced = txt.replace( + 'dependencies {', + 'dependencies {\n implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"', + ); + // const lines = txt.split('\n'); + writeFileSync(filename, replaced, 'utf-8'); + logger.info( + `Migrated ${filename} by adding androidx.coordinatorlayout dependency.`, + ); +} + +function updateGradleWrapper(filename: string) { + const txt = readFile(filename); + if (!txt) { + return; + } + let replaced = txt; + if (replaced.includes('gradle-7.0-all.zip')) { + replaced = setAllStringIn( + replaced, + 'distributionUrl=', + '\n', + // eslint-disable-next-line no-useless-escape + `https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip`, + ); + writeFileSync(filename, replaced, 'utf-8'); + logger.info( + `Migrated gradle-wrapper.properties by updating gradle version from 7.0 to 7.4.2.`, + ); + } +} + +function updateGitIgnore(filename: string, lines: string[]) { + const txt = readFile(filename); + if (!txt) { + return; + } + let replaced = txt; + for (const line of lines) { + if (!replaced.includes(line)) { + replaced += line + '\n'; + } + } + if (replaced !== txt) { + writeFileSync(filename, replaced, 'utf-8'); + logger.info(`Migrated .gitignore by adding generated config files.`); + } +} + +function updateFile( + filename: string, + textStart: string, + textEnd: string, + replacement?: string, + skipIfNotFound?: boolean, +): boolean { + if (configData === null) { + return false; + } + const path = join(configData.app.rootDir, filename); + let txt = readFile(path); + if (!txt) { + return false; + } + if (txt.includes(textStart)) { + if (replacement) { + txt = setAllStringIn(txt, textStart, textEnd, replacement); + writeFileSync(path, txt, { encoding: 'utf-8' }); + } else { + // Replacing in code so we need to count the number of brackets to find the end of the function in swift + const lines = txt.split('\n'); + let replaced = ''; + let keep = true; + let brackets = 0; + for (const line of lines) { + if (line.includes(textStart)) { + keep = false; + } + if (!keep) { + brackets += (line.match(/{/g) || []).length; + brackets -= (line.match(/}/g) || []).length; + if (brackets == 0) { + keep = true; + } + } else { + replaced += line + '\n'; + } + } + writeFileSync(path, replaced, { encoding: 'utf-8' }); + } + const message = replacement ? `${textStart} => ${replacement}` : ''; + logger.info(`Migrated ${filename} ${message}.`); + return true; + } else if (!skipIfNotFound) { + logger.error( + `Unable to find "${textStart}" in ${filename}. Try updating it manually`, + ); + } + + return false; +} + +function setAllStringIn( + data: string, + start: string, + end: string, + replacement: string, +): string { + let position = 0; + let result = data; + let replaced = true; + while (replaced) { + const foundIdx = result.indexOf(start, position); + if (foundIdx == -1) { + replaced = false; + } else { + const idx = foundIdx + start.length; + position = idx + replacement.length; + result = + result.substring(0, idx) + + replacement + + result.substring(result.indexOf(end, idx)); + } + } + return result; +} + +function removeInFile(filename: string, startLine: string, endLine: string) { + const txt = readFile(filename); + if (!txt) { + return; + } + let changed = false; + let lines = txt.split('\n'); + let removing = false; + lines = lines.filter(line => { + if (line.includes(endLine)) { + removing = false; + return false; + } + if (line.includes(startLine)) { + removing = true; + changed = true; + } + return !removing; + }); + if (changed) { + writeFileSync(filename, lines.join('\n'), 'utf-8'); + logger.info(`Migrated ${filename} by removing ${startLine}.`); + } +} + +function replacePush(filename: string) { + const txt = readFile(filename); + if (!txt) { + return; + } + let replaced = txt; + replaced = replaced.replace('DEBUG USE_PUSH', 'DEBUG'); + replaced = replaced.replace('USE_PUSH', '""'); + if (replaced != txt) { + writeFileSync(filename, replaced, 'utf-8'); + logger.info(`Migrated ${filename} by removing USE_PUSH.`); + } +} + +function removeKey(filename: string, key: string) { + const txt = readFile(filename); + if (!txt) { + return; + } + let lines = txt.split('\n'); + let removed = false; + let removing = false; + lines = lines.filter(line => { + if (removing && line.includes('')) { + removing = false; + return false; + } + if (line.includes(`${key} Date: Tue, 12 Jul 2022 12:11:57 -0400 Subject: [PATCH 02/30] chore: fmt --- cli/src/tasks/migrate.ts | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 5ac25f4c01..7e418d33b9 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -51,13 +51,16 @@ export async function migrateCommand(config: Config): Promise { }; const daysLeft = daysUntil(new Date('11/01/2022')); - let warning = `Google Play Store requires a minimum target of SDK 31 by 1st November 2022`; + let googlePlayWarning = `Google Play Store requires a minimum target of SDK 31 by 1st November 2022`; if (daysLeft > 0) { - warning += ` (${daysLeft} days left)`; + googlePlayWarning += ` (${daysLeft} days left)`; } + const monorepoWarning = + 'Please note this tool is not intended for use in a mono-repo enviroment, please check out the Ionic vscode extension for this functionality.'; + const { migrateconfirm } = await logPrompt( - `Capacitor 4 sets a deployment target of iOS 13 and Android 12 (SDK 32). \n${warning}\n`, + `Capacitor 4 sets a deployment target of iOS 13 and Android 12 (SDK 32). \n${googlePlayWarning} \n${monorepoWarning} \n`, { type: 'text', name: 'migrateconfirm', @@ -74,7 +77,7 @@ export async function migrateCommand(config: Config): Promise { } await installLatestNPMLibs(); await migrateStoragePluginToPreferences(); - + if (allDependencies['@capacitor/ios']) { // Set deployment target to 13.0 updateFile( @@ -113,12 +116,18 @@ export async function migrateCommand(config: Config): Promise { ); // Remove from App Delegate removeInFile( - join(configData.app.rootDir, 'ios', 'App', 'App', 'AppDelegate.swift'), + join( + configData.app.rootDir, + 'ios', + 'App', + 'App', + 'AppDelegate.swift', + ), `#if USE_PUSH`, `#endif`, ); } - + if (allDependencies['@capacitor/android']) { // AndroidManifest.xml add attribute: { `App/App/capacitor.config.json`, `App/App/config.xml`, ]); - + // Variables gradle const variables: { [key: string]: any } = { minSdkVersion: 22, @@ -197,10 +206,10 @@ export async function migrateCommand(config: Config): Promise { } } } - + // Ran Cap Sync await getCommandOutput('npx', ['cap', 'sync']); - + writeBreakingChanges(); logSuccess( `Migration to Capacitor ${coreVersion} is complete. Run and test your app!`, From 282c9693566310b131cf5866ba9fd228c1f7712d Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Tue, 12 Jul 2022 12:17:13 -0400 Subject: [PATCH 03/30] chore: verbage --- cli/src/tasks/migrate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 7e418d33b9..11962960d2 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -51,7 +51,7 @@ export async function migrateCommand(config: Config): Promise { }; const daysLeft = daysUntil(new Date('11/01/2022')); - let googlePlayWarning = `Google Play Store requires a minimum target of SDK 31 by 1st November 2022`; + let googlePlayWarning = `Google Play Store requires a minimum target of SDK 31 by the 1st November 2022`; if (daysLeft > 0) { googlePlayWarning += ` (${daysLeft} days left)`; } From 18bd9bb3a1cd7977bbc038f7e1ceaf48745fa304 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Tue, 12 Jul 2022 13:11:33 -0400 Subject: [PATCH 04/30] chore: version fix for betas --- cli/src/tasks/migrate.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 11962960d2..098138dfb5 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -40,8 +40,8 @@ const plugins = [ '@capacitor/toast', ]; let configData: Config | null = null; -const coreVersion = '^4.0.0-beta.2'; -const pluginVersion = '^4.0.0-beta.2'; +const coreVersion = '4.0.0-beta.2'; +const pluginVersion = '4.0.0-beta.2'; export async function migrateCommand(config: Config): Promise { configData = config; From ce89d60ded997e965871def313598151e21cdd93 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Tue, 12 Jul 2022 14:14:09 -0400 Subject: [PATCH 05/30] chore: cleanup --- cli/src/tasks/migrate.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 098138dfb5..808d547127 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -1,4 +1,3 @@ -// import c from '../colors'; import { writeFileSync, readFileSync, existsSync } from 'fs'; import { join } from 'path'; From 250fb9d29af97a4ba466d93da559118e908c0c12 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Mon, 18 Jul 2022 12:47:59 -0400 Subject: [PATCH 06/30] chore: touch ups for spinners and funcs --- cli/src/tasks/migrate.ts | 467 +++++++++++++++++++++++---------------- 1 file changed, 273 insertions(+), 194 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 808d547127..eb6351fe25 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -1,6 +1,7 @@ import { writeFileSync, readFileSync, existsSync } from 'fs'; import { join } from 'path'; +import { runTask } from '../common'; import type { Config } from '../definitions'; import { fatal } from '../errors'; import { logger, logPrompt, logSuccess } from '../log'; @@ -39,8 +40,8 @@ const plugins = [ '@capacitor/toast', ]; let configData: Config | null = null; -const coreVersion = '4.0.0-beta.2'; -const pluginVersion = '4.0.0-beta.2'; +const coreVersion = 'next'; +const pluginVersion = 'next'; export async function migrateCommand(config: Config): Promise { configData = config; @@ -58,8 +59,10 @@ export async function migrateCommand(config: Config): Promise { const monorepoWarning = 'Please note this tool is not intended for use in a mono-repo enviroment, please check out the Ionic vscode extension for this functionality.'; + logger.info(monorepoWarning) + const { migrateconfirm } = await logPrompt( - `Capacitor 4 sets a deployment target of iOS 13 and Android 12 (SDK 32). \n${googlePlayWarning} \n${monorepoWarning} \n`, + `Capacitor 4 sets a deployment target of iOS 13 and Android 12 (SDK 32). \n${googlePlayWarning} \n`, { type: 'text', name: 'migrateconfirm', @@ -68,148 +71,209 @@ export async function migrateCommand(config: Config): Promise { }, ); - if (migrateconfirm === 'y') { - logger.info(`Migrating to Capacitor ${coreVersion}...`); + if (typeof migrateconfirm === 'string' && migrateconfirm.toLowerCase() === 'y') { try { if (configData === null) { fatal('Config data missing'); } - await installLatestNPMLibs(); - await migrateStoragePluginToPreferences(); - if (allDependencies['@capacitor/ios']) { + const { npmInstallConfirm } = await logPrompt( + `Would you like the migrator to run npm install to install the latest versions of capacitor packages? (Those using other package managers should answer N)`, + { + type: 'text', + name: 'npmInstallConfirm', + message: `Run Npm Install? (Y/n)`, + initial: 'y', + }, + ); + const runNpmInstall = typeof npmInstallConfirm === 'string' && npmInstallConfirm.toLowerCase() === 'y'; + + await runTask(`Installing Latest NPM Modules.`, () => { + return installLatestNPMLibs(runNpmInstall); + }); + + await runTask(`Migrating @capacitor/storage to @capacitor/preferences.`, () => { + return migrateStoragePluginToPreferences(runNpmInstall); + }); + + if (allDependencies['@capacitor/ios'] && existsSync(join(configData.app.rootDir, 'ios'))) { // Set deployment target to 13.0 - updateFile( - join('ios', 'App', 'App.xcodeproj', 'project.pbxproj'), - 'IPHONEOS_DEPLOYMENT_TARGET = ', - ';', - '13.0', - ); + await runTask(`Migrating deployment target to 13.0.`, () => { + return updateFile( + join('ios', 'App', 'App.xcodeproj', 'project.pbxproj'), + 'IPHONEOS_DEPLOYMENT_TARGET = ', + ';', + '13.0', + ); + }); + // Update Podfile to 13.0 - updateFile( - join('ios', 'App', 'Podfile'), - `platform :ios, '`, - `'`, - '13.0', - ); + await runTask(`Migrating Podfile to 13.0.`, () => { + return updateFile( + join('ios', 'App', 'Podfile'), + `platform :ios, '`, + `'`, + '13.0', + ); + }); + // Remove touchesBegan - updateFile( - join('ios', 'App', 'App', 'AppDelegate.swift'), - `override func touchesBegan`, - `}`, - ); + await runTask(`Migrating AppDelegate.swift by removing touchesBegan.`, () => { + return updateFile( + join('ios', 'App', 'App', 'AppDelegate.swift'), + `override func touchesBegan`, + `}`, + ); + }); + // Remove NSAppTransportSecurity - removeKey( - join(configData.app.rootDir, 'ios', 'App', 'App', 'info.plist'), - 'NSAppTransportSecurity', - ); + await runTask(`Migrating info.plist by removing NSAppTransportSecurity key.`, () => { + return removeKey( + join(configData!.app.rootDir, 'ios', 'App', 'App', 'info.plist'), + 'NSAppTransportSecurity', + ); + }); + // Remove USE_PUSH - replacePush( - join( - configData.app.rootDir, - 'ios', - 'App', - 'App.xcodeproj', - 'project.pbxproj', - ), - ); + await runTask(`Migrating by removing USE_PUSH.`, () => { + return replacePush( + join( + configData!.app.rootDir, + 'ios', + 'App', + 'App.xcodeproj', + 'project.pbxproj', + ), + ); + }); + // Remove from App Delegate - removeInFile( - join( - configData.app.rootDir, - 'ios', - 'App', - 'App', - 'AppDelegate.swift', - ), - `#if USE_PUSH`, - `#endif`, - ); + await runTask(`Migrating App Delegate.`, () => { + return replaceIfUsePush(); + }); + } - if (allDependencies['@capacitor/android']) { + if (allDependencies['@capacitor/android'] && existsSync(join(configData.app.rootDir, 'android'))) { // AndroidManifest.xml add attribute: { + return updateAndroidManifest( + join( + configData!.app.rootDir, + 'android', + 'app', + 'src', + 'main', + 'AndroidManifest.xml', + ), + ); + }); + // Update build.gradle - updateBuildGradle( - join(configData.app.rootDir, 'android', 'build.gradle'), - ); - updateAppBuildGradle( - join(configData.app.rootDir, 'android', 'app', 'build.gradle'), + const { leaveJCenterPrompt } = await logPrompt( + `Some projects still require JCenter to function. If your project does, please answer yes below.`, + { + type: 'text', + name: 'leaveJCenterPrompt', + message: `Keep JCenter if present? (y/N)`, + initial: 'n', + }, ); + await runTask(`Migrating build.gradle file.`, () => { + return updateBuildGradle( + join(configData!.app.rootDir, 'android', 'build.gradle'), + typeof leaveJCenterPrompt === 'string' && leaveJCenterPrompt.toLowerCase() === 'y' + ); + }); + + // Update app.gradle + await runTask(`Migrating app.gradle file.`, () => { + return updateAppBuildGradle( + join(configData!.app.rootDir, 'android', 'app', 'build.gradle'), + ); + }); + // Update gradle-wrapper.properties - updateGradleWrapper( - join( - configData.app.rootDir, - 'android', - 'gradle', - 'wrapper', - 'gradle-wrapper.properties', - ), - ); - // Update .gitIgnore - updateGitIgnore(join(configData.app.rootDir, 'android', '.gitignore'), [ - `# Generated Config files`, - `app/src/main/assets/capacitor.config.json`, - `app/src/main/assets/capacitor.plugins.json`, - `app/src/main/res/xml/config.xml`, - ]); + await runTask(`Migrating gradle-wrapper.properties by updating gradle version from 7.0 to 7.4.2.`, () => { + return updateGradleWrapper( + join( + configData!.app.rootDir, + 'android', + 'gradle', + 'wrapper', + 'gradle-wrapper.properties', + ), + ); + }); + // Update .gitIgnore - updateGitIgnore(join(configData.app.rootDir, 'ios', '.gitignore'), [ - `# Generated Config files`, - `App/App/capacitor.config.json`, - `App/App/config.xml`, - ]); - + await runTask(`Migrating .gitignore files by adding generated config files.`, () => { + return (async () => { + await updateGitIgnore(join(configData!.app.rootDir, 'android', '.gitignore'), [ + `# Generated Config files`, + `app/src/main/assets/capacitor.config.json`, + `app/src/main/assets/capacitor.plugins.json`, + `app/src/main/res/xml/config.xml`, + ]); + await updateGitIgnore(join(configData!.app.rootDir, 'ios', '.gitignore'), [ + `# Generated Config files`, + `App/App/capacitor.config.json`, + `App/App/config.xml`, + ]); + })(); + }); + // Variables gradle - const variables: { [key: string]: any } = { - minSdkVersion: 22, - compileSdkVersion: 32, - targetSdkVersion: 32, - androidxActivityVersion: '1.4.0', - androidxAppCompatVersion: '1.4.1', - androidxCoordinatorLayoutVersion: '1.2.0', - androidxCoreVersion: '1.7.0', - androidxFragmentVersion: '1.4.1', - junitVersion: '4.13.2', - androidxJunitVersion: '1.1.3', - androidxEspressoCoreVersion: '3.4.0', - cordovaAndroidVersion: '10.1.1', - }; - for (const variable of Object.keys(variables)) { - if ( - !updateFile( - join('android', 'variables.gradle'), - `${variable} = '`, - `'`, - variables[variable].toString(), - true, - ) - ) { - updateFile( - join('android', 'variables.gradle'), - `${variable} = `, - `\n`, - variables[variable].toString(), - true, - ); - } - } + await runTask(`Migrating variables.gradle file.`, () => { + return (async (): Promise => { + const variables: { [key: string]: any } = { + minSdkVersion: 22, + compileSdkVersion: 32, + targetSdkVersion: 32, + androidxActivityVersion: '1.4.0', + androidxAppCompatVersion: '1.4.2', + androidxCoordinatorLayoutVersion: '1.2.0', + androidxCoreVersion: '1.8.0', + androidxFragmentVersion: '1.4.1', + junitVersion: '4.13.2', + androidxJunitVersion: '1.1.3', + androidxEspressoCoreVersion: '3.4.0', + cordovaAndroidVersion: '10.1.1', + }; + for (const variable of Object.keys(variables)) { + if ( + !(await updateFile( + join('android', 'variables.gradle'), + `${variable} = '`, + `'`, + variables[variable].toString(), + true, + )) + ) { + await updateFile( + join('android', 'variables.gradle'), + `${variable} = `, + `\n`, + variables[variable].toString(), + true, + ); + } + } + })(); + }); + } - // Ran Cap Sync - await getCommandOutput('npx', ['cap', 'sync']); + // Run Cap Sync + await runTask(`Running cap sync.`, () => { + return getCommandOutput('npx', ['cap', 'sync']); + }); + + // Write all breaking changes + await runTask(`Writing breaking changes.`, () => { + return writeBreakingChanges(); + }); - writeBreakingChanges(); logSuccess( `Migration to Capacitor ${coreVersion} is complete. Run and test your app!`, ); @@ -227,7 +291,7 @@ function daysUntil(date_1: Date) { return Math.ceil(difference / (1000 * 3600 * 24)); } -async function installLatestNPMLibs() { +async function installLatestNPMLibs(runInstall: boolean) { const result: string[] = []; for (const lib of libs) { if (allDependencies[lib]) { @@ -241,21 +305,29 @@ async function installLatestNPMLibs() { } } - await getCommandOutput('npm', ['i', ...result]); + if (runInstall) { + await getCommandOutput('npm', ['i', ...result]); + } else { + logger.info(`Please run an install command with your package manager of choice with the following:`); + logger.info(` ${result.join(' ')}`); + } } -async function migrateStoragePluginToPreferences() { +async function migrateStoragePluginToPreferences(runInstall: boolean) { if (allDependencies['@capacitor/storage']) { - await getCommandOutput('npm', ['uninstall', '@capacitor/storage']); - await getCommandOutput('npm', [ - 'i', - `@capacitor/preferences@${pluginVersion}`, - ]); - logger.info('Migrated @capacitor/storage to @capacitor/preferences.'); + if (runInstall) { + await getCommandOutput('npm', ['uninstall', '@capacitor/storage']); + await getCommandOutput('npm', [ + 'i', + `@capacitor/preferences@${pluginVersion}`, + ]); + } else { + logger.info(`Please manually uninstall @capacitor/storage and replace it with @capacitor/preferences@${pluginVersion}`); + } } } -function writeBreakingChanges() { +async function writeBreakingChanges() { const breaking = [ '@capacitor/storage', '@capacitor/camera', @@ -282,33 +354,41 @@ function writeBreakingChanges() { } } -function updateAndroidManifest(filename: string) { +async function updateAndroidManifest(filename: string) { const txt = readFile(filename); if (!txt) { return; } + const hasAndroidExportedAlreadySet = (new RegExp(/]*(android:exported=")[^>]*)>/g)).test(txt); + let isAndroidExportedSetToFalse = false; + if (hasAndroidExportedAlreadySet) { + isAndroidExportedSetToFalse = (new RegExp(/]*(android:exported="false")[^>]*)>/g)).test(txt); + } + // AndroidManifest.xml add attribute: tag`); return; } writeFileSync(filename, replaced, 'utf-8'); - logger.info( - `Migrated AndroidManifest.xml by adding android:exported attribute to Activity.`, - ); } -function updateBuildGradle(filename: string) { +async function updateBuildGradle(filename: string, leaveJCenter: boolean) { // In build.gradle add dependencies: // classpath 'com.android.tools.build:gradle:7.2.1' // classpath 'com.google.gms:google-services:4.3.10' @@ -336,7 +416,7 @@ function updateBuildGradle(filename: string) { `'`, neededDeps[dep], ); - logger.info(`Migrated build.gradle set ${dep} = ${neededDeps[dep]}.`); + logger.info(`Set ${dep} = ${neededDeps[dep]}.`); } } @@ -353,16 +433,16 @@ function updateBuildGradle(filename: string) { // Make sure we have mavenCentral() if (inRepositories && !hasMavenCentral) { final += ' mavenCentral()\n'; - logger.info(`Migrated build.gradle added mavenCentral().`); + logger.info(`Added mavenCentral().`); } inRepositories = false; } if (inRepositories && line.trim() === 'mavenCentral()') { hasMavenCentral = true; } - if (inRepositories && line.trim() === 'jcenter()') { + if (inRepositories && line.trim() === 'jcenter()' && !leaveJCenter) { // skip jCentral() - logger.info(`Migrated build.gradle removed jcenter().`); + logger.info(`Removed jcenter().`); } else { final += line + '\n'; } @@ -388,7 +468,7 @@ function readFile(filename: string): string | undefined { } } -function updateAppBuildGradle(filename: string) { +async function updateAppBuildGradle(filename: string) { const txt = readFile(filename); if (!txt) { return; @@ -403,33 +483,24 @@ function updateAppBuildGradle(filename: string) { ); // const lines = txt.split('\n'); writeFileSync(filename, replaced, 'utf-8'); - logger.info( - `Migrated ${filename} by adding androidx.coordinatorlayout dependency.`, - ); } -function updateGradleWrapper(filename: string) { +async function updateGradleWrapper(filename: string) { const txt = readFile(filename); if (!txt) { return; } - let replaced = txt; - if (replaced.includes('gradle-7.0-all.zip')) { - replaced = setAllStringIn( - replaced, - 'distributionUrl=', - '\n', - // eslint-disable-next-line no-useless-escape - `https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip`, - ); - writeFileSync(filename, replaced, 'utf-8'); - logger.info( - `Migrated gradle-wrapper.properties by updating gradle version from 7.0 to 7.4.2.`, - ); - } + const replaced = setAllStringIn( + txt, + 'distributionUrl=', + '\n', + // eslint-disable-next-line no-useless-escape + `https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip`, + ); + writeFileSync(filename, replaced, 'utf-8'); } -function updateGitIgnore(filename: string, lines: string[]) { +async function updateGitIgnore(filename: string, lines: string[]) { const txt = readFile(filename); if (!txt) { return; @@ -442,17 +513,16 @@ function updateGitIgnore(filename: string, lines: string[]) { } if (replaced !== txt) { writeFileSync(filename, replaced, 'utf-8'); - logger.info(`Migrated .gitignore by adding generated config files.`); } } -function updateFile( +async function updateFile( filename: string, textStart: string, textEnd: string, replacement?: string, skipIfNotFound?: boolean, -): boolean { +): Promise { if (configData === null) { return false; } @@ -487,8 +557,6 @@ function updateFile( } writeFileSync(path, replaced, { encoding: 'utf-8' }); } - const message = replacement ? `${textStart} => ${replacement}` : ''; - logger.info(`Migrated ${filename} ${message}.`); return true; } else if (!skipIfNotFound) { logger.error( @@ -524,32 +592,45 @@ function setAllStringIn( return result; } -function removeInFile(filename: string, startLine: string, endLine: string) { +async function replaceIfUsePush() { + const startLine = '#if USE_PUSH'; + const endLine = '#endif'; + const filename = join( + configData!.app.rootDir, + 'ios', + 'App', + 'App', + 'AppDelegate.swift', + ) const txt = readFile(filename); if (!txt) { return; } - let changed = false; - let lines = txt.split('\n'); - let removing = false; - lines = lines.filter(line => { - if (line.includes(endLine)) { - removing = false; - return false; + const lines = txt.split('\n'); + let startLineIndex: number | null = null; + let endLineIndex: number | null = null; + for(const [key, item] of lines.entries()) { + if (item.includes(startLine)) { + startLineIndex = key; + break; } - if (line.includes(startLine)) { - removing = true; - changed = true; + } + if (startLineIndex !== null) { + for(const [key, item] of lines.entries()) { + if (item.includes(endLine) && key > startLineIndex) { + endLineIndex = key; + break; + } + } + if (endLineIndex !== null) { + lines[endLineIndex] = ''; + lines[startLineIndex] = ''; + writeFileSync(filename, lines.join('\n'), 'utf-8'); } - return !removing; - }); - if (changed) { - writeFileSync(filename, lines.join('\n'), 'utf-8'); - logger.info(`Migrated ${filename} by removing ${startLine}.`); } } -function replacePush(filename: string) { +async function replacePush(filename: string) { const txt = readFile(filename); if (!txt) { return; @@ -559,11 +640,10 @@ function replacePush(filename: string) { replaced = replaced.replace('USE_PUSH', '""'); if (replaced != txt) { writeFileSync(filename, replaced, 'utf-8'); - logger.info(`Migrated ${filename} by removing USE_PUSH.`); } } -function removeKey(filename: string, key: string) { +async function removeKey(filename: string, key: string) { const txt = readFile(filename); if (!txt) { return; @@ -585,6 +665,5 @@ function removeKey(filename: string, key: string) { if (removed) { writeFileSync(filename, lines.join('\n'), 'utf-8'); - logger.info(`Migrated info.plist by removing ${key} key.`); } } From ce13427ff8adb8499cdb81c0ec3f533952befdbc Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Mon, 18 Jul 2022 12:52:31 -0400 Subject: [PATCH 07/30] chore: fmt --- cli/src/tasks/migrate.ts | 205 ++++++++++++++++++++++++--------------- 1 file changed, 125 insertions(+), 80 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index eb6351fe25..382554b14f 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -59,7 +59,7 @@ export async function migrateCommand(config: Config): Promise { const monorepoWarning = 'Please note this tool is not intended for use in a mono-repo enviroment, please check out the Ionic vscode extension for this functionality.'; - logger.info(monorepoWarning) + logger.info(monorepoWarning); const { migrateconfirm } = await logPrompt( `Capacitor 4 sets a deployment target of iOS 13 and Android 12 (SDK 32). \n${googlePlayWarning} \n`, @@ -71,7 +71,10 @@ export async function migrateCommand(config: Config): Promise { }, ); - if (typeof migrateconfirm === 'string' && migrateconfirm.toLowerCase() === 'y') { + if ( + typeof migrateconfirm === 'string' && + migrateconfirm.toLowerCase() === 'y' + ) { try { if (configData === null) { fatal('Config data missing'); @@ -86,17 +89,25 @@ export async function migrateCommand(config: Config): Promise { initial: 'y', }, ); - const runNpmInstall = typeof npmInstallConfirm === 'string' && npmInstallConfirm.toLowerCase() === 'y'; + const runNpmInstall = + typeof npmInstallConfirm === 'string' && + npmInstallConfirm.toLowerCase() === 'y'; await runTask(`Installing Latest NPM Modules.`, () => { return installLatestNPMLibs(runNpmInstall); }); - await runTask(`Migrating @capacitor/storage to @capacitor/preferences.`, () => { - return migrateStoragePluginToPreferences(runNpmInstall); - }); + await runTask( + `Migrating @capacitor/storage to @capacitor/preferences.`, + () => { + return migrateStoragePluginToPreferences(runNpmInstall); + }, + ); - if (allDependencies['@capacitor/ios'] && existsSync(join(configData.app.rootDir, 'ios'))) { + if ( + allDependencies['@capacitor/ios'] && + existsSync(join(configData.app.rootDir, 'ios')) + ) { // Set deployment target to 13.0 await runTask(`Migrating deployment target to 13.0.`, () => { return updateFile( @@ -106,7 +117,7 @@ export async function migrateCommand(config: Config): Promise { '13.0', ); }); - + // Update Podfile to 13.0 await runTask(`Migrating Podfile to 13.0.`, () => { return updateFile( @@ -116,24 +127,30 @@ export async function migrateCommand(config: Config): Promise { '13.0', ); }); - + // Remove touchesBegan - await runTask(`Migrating AppDelegate.swift by removing touchesBegan.`, () => { - return updateFile( - join('ios', 'App', 'App', 'AppDelegate.swift'), - `override func touchesBegan`, - `}`, - ); - }); - + await runTask( + `Migrating AppDelegate.swift by removing touchesBegan.`, + () => { + return updateFile( + join('ios', 'App', 'App', 'AppDelegate.swift'), + `override func touchesBegan`, + `}`, + ); + }, + ); + // Remove NSAppTransportSecurity - await runTask(`Migrating info.plist by removing NSAppTransportSecurity key.`, () => { - return removeKey( - join(configData!.app.rootDir, 'ios', 'App', 'App', 'info.plist'), - 'NSAppTransportSecurity', - ); - }); - + await runTask( + `Migrating info.plist by removing NSAppTransportSecurity key.`, + () => { + return removeKey( + join(configData!.app.rootDir, 'ios', 'App', 'App', 'info.plist'), + 'NSAppTransportSecurity', + ); + }, + ); + // Remove USE_PUSH await runTask(`Migrating by removing USE_PUSH.`, () => { return replacePush( @@ -146,29 +163,34 @@ export async function migrateCommand(config: Config): Promise { ), ); }); - + // Remove from App Delegate await runTask(`Migrating App Delegate.`, () => { return replaceIfUsePush(); }); - } - if (allDependencies['@capacitor/android'] && existsSync(join(configData.app.rootDir, 'android'))) { + if ( + allDependencies['@capacitor/android'] && + existsSync(join(configData.app.rootDir, 'android')) + ) { // AndroidManifest.xml add attribute: { - return updateAndroidManifest( - join( - configData!.app.rootDir, - 'android', - 'app', - 'src', - 'main', - 'AndroidManifest.xml', - ), - ); - }); - + await runTask( + `Migrating AndroidManifest.xml by adding android:exported attribute to Activity.`, + () => { + return updateAndroidManifest( + join( + configData!.app.rootDir, + 'android', + 'app', + 'src', + 'main', + 'AndroidManifest.xml', + ), + ); + }, + ); + // Update build.gradle const { leaveJCenterPrompt } = await logPrompt( `Some projects still require JCenter to function. If your project does, please answer yes below.`, @@ -182,47 +204,60 @@ export async function migrateCommand(config: Config): Promise { await runTask(`Migrating build.gradle file.`, () => { return updateBuildGradle( join(configData!.app.rootDir, 'android', 'build.gradle'), - typeof leaveJCenterPrompt === 'string' && leaveJCenterPrompt.toLowerCase() === 'y' + typeof leaveJCenterPrompt === 'string' && + leaveJCenterPrompt.toLowerCase() === 'y', ); }); - + // Update app.gradle await runTask(`Migrating app.gradle file.`, () => { return updateAppBuildGradle( join(configData!.app.rootDir, 'android', 'app', 'build.gradle'), ); }); - + // Update gradle-wrapper.properties - await runTask(`Migrating gradle-wrapper.properties by updating gradle version from 7.0 to 7.4.2.`, () => { - return updateGradleWrapper( - join( - configData!.app.rootDir, - 'android', - 'gradle', - 'wrapper', - 'gradle-wrapper.properties', - ), - ); - }); - + await runTask( + `Migrating gradle-wrapper.properties by updating gradle version from 7.0 to 7.4.2.`, + () => { + return updateGradleWrapper( + join( + configData!.app.rootDir, + 'android', + 'gradle', + 'wrapper', + 'gradle-wrapper.properties', + ), + ); + }, + ); + // Update .gitIgnore - await runTask(`Migrating .gitignore files by adding generated config files.`, () => { - return (async () => { - await updateGitIgnore(join(configData!.app.rootDir, 'android', '.gitignore'), [ - `# Generated Config files`, - `app/src/main/assets/capacitor.config.json`, - `app/src/main/assets/capacitor.plugins.json`, - `app/src/main/res/xml/config.xml`, - ]); - await updateGitIgnore(join(configData!.app.rootDir, 'ios', '.gitignore'), [ - `# Generated Config files`, - `App/App/capacitor.config.json`, - `App/App/config.xml`, - ]); - })(); - }); - + await runTask( + `Migrating .gitignore files by adding generated config files.`, + () => { + return (async () => { + await updateGitIgnore( + join(configData!.app.rootDir, 'android', '.gitignore'), + [ + `# Generated Config files`, + `app/src/main/assets/capacitor.config.json`, + `app/src/main/assets/capacitor.plugins.json`, + `app/src/main/res/xml/config.xml`, + ], + ); + await updateGitIgnore( + join(configData!.app.rootDir, 'ios', '.gitignore'), + [ + `# Generated Config files`, + `App/App/capacitor.config.json`, + `App/App/config.xml`, + ], + ); + })(); + }, + ); + // Variables gradle await runTask(`Migrating variables.gradle file.`, () => { return (async (): Promise => { @@ -261,7 +296,6 @@ export async function migrateCommand(config: Config): Promise { } })(); }); - } // Run Cap Sync @@ -308,7 +342,9 @@ async function installLatestNPMLibs(runInstall: boolean) { if (runInstall) { await getCommandOutput('npm', ['i', ...result]); } else { - logger.info(`Please run an install command with your package manager of choice with the following:`); + logger.info( + `Please run an install command with your package manager of choice with the following:`, + ); logger.info(` ${result.join(' ')}`); } } @@ -322,7 +358,9 @@ async function migrateStoragePluginToPreferences(runInstall: boolean) { `@capacitor/preferences@${pluginVersion}`, ]); } else { - logger.info(`Please manually uninstall @capacitor/storage and replace it with @capacitor/preferences@${pluginVersion}`); + logger.info( + `Please manually uninstall @capacitor/storage and replace it with @capacitor/preferences@${pluginVersion}`, + ); } } } @@ -360,10 +398,14 @@ async function updateAndroidManifest(filename: string) { return; } - const hasAndroidExportedAlreadySet = (new RegExp(/]*(android:exported=")[^>]*)>/g)).test(txt); + const hasAndroidExportedAlreadySet = new RegExp( + /]*(android:exported=")[^>]*)>/g, + ).test(txt); let isAndroidExportedSetToFalse = false; if (hasAndroidExportedAlreadySet) { - isAndroidExportedSetToFalse = (new RegExp(/]*(android:exported="false")[^>]*)>/g)).test(txt); + isAndroidExportedSetToFalse = new RegExp( + /]*(android:exported="false")[^>]*)>/g, + ).test(txt); } // AndroidManifest.xml add attribute: tag`); @@ -601,7 +646,7 @@ async function replaceIfUsePush() { 'App', 'App', 'AppDelegate.swift', - ) + ); const txt = readFile(filename); if (!txt) { return; @@ -609,14 +654,14 @@ async function replaceIfUsePush() { const lines = txt.split('\n'); let startLineIndex: number | null = null; let endLineIndex: number | null = null; - for(const [key, item] of lines.entries()) { + for (const [key, item] of lines.entries()) { if (item.includes(startLine)) { startLineIndex = key; break; } } if (startLineIndex !== null) { - for(const [key, item] of lines.entries()) { + for (const [key, item] of lines.entries()) { if (item.includes(endLine) && key > startLineIndex) { endLineIndex = key; break; From 0846e12b7ccb51a8158b518126305153fafc8359 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 20 Jul 2022 10:03:27 -0400 Subject: [PATCH 08/30] chore: modify packagejson replacements --- cli/src/tasks/migrate.ts | 101 ++++++++++++++------------------------- 1 file changed, 36 insertions(+), 65 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 382554b14f..ee6dd379e6 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -50,11 +50,8 @@ export async function migrateCommand(config: Config): Promise { ...(configData ? configData.app.package.devDependencies : {}), }; - const daysLeft = daysUntil(new Date('11/01/2022')); - let googlePlayWarning = `Google Play Store requires a minimum target of SDK 31 by the 1st November 2022`; - if (daysLeft > 0) { - googlePlayWarning += ` (${daysLeft} days left)`; - } + const iosProjectDirAbs = config.ios.platformDirAbs; + const androidProjectDirAbs = config.android.platformDirAbs; const monorepoWarning = 'Please note this tool is not intended for use in a mono-repo enviroment, please check out the Ionic vscode extension for this functionality.'; @@ -62,7 +59,7 @@ export async function migrateCommand(config: Config): Promise { logger.info(monorepoWarning); const { migrateconfirm } = await logPrompt( - `Capacitor 4 sets a deployment target of iOS 13 and Android 12 (SDK 32). \n${googlePlayWarning} \n`, + `Capacitor 4 sets a deployment target of iOS 13 and Android 12 (SDK 32). \n`, { type: 'text', name: 'migrateconfirm', @@ -94,7 +91,7 @@ export async function migrateCommand(config: Config): Promise { npmInstallConfirm.toLowerCase() === 'y'; await runTask(`Installing Latest NPM Modules.`, () => { - return installLatestNPMLibs(runNpmInstall); + return installLatestNPMLibs(runNpmInstall, config); }); await runTask( @@ -106,12 +103,12 @@ export async function migrateCommand(config: Config): Promise { if ( allDependencies['@capacitor/ios'] && - existsSync(join(configData.app.rootDir, 'ios')) + existsSync(iosProjectDirAbs) ) { // Set deployment target to 13.0 await runTask(`Migrating deployment target to 13.0.`, () => { return updateFile( - join('ios', 'App', 'App.xcodeproj', 'project.pbxproj'), + join(iosProjectDirAbs, 'App', 'App.xcodeproj', 'project.pbxproj'), 'IPHONEOS_DEPLOYMENT_TARGET = ', ';', '13.0', @@ -121,7 +118,7 @@ export async function migrateCommand(config: Config): Promise { // Update Podfile to 13.0 await runTask(`Migrating Podfile to 13.0.`, () => { return updateFile( - join('ios', 'App', 'Podfile'), + join(iosProjectDirAbs, 'App', 'Podfile'), `platform :ios, '`, `'`, '13.0', @@ -133,7 +130,7 @@ export async function migrateCommand(config: Config): Promise { `Migrating AppDelegate.swift by removing touchesBegan.`, () => { return updateFile( - join('ios', 'App', 'App', 'AppDelegate.swift'), + join(iosProjectDirAbs, 'App', 'App', 'AppDelegate.swift'), `override func touchesBegan`, `}`, ); @@ -145,7 +142,7 @@ export async function migrateCommand(config: Config): Promise { `Migrating info.plist by removing NSAppTransportSecurity key.`, () => { return removeKey( - join(configData!.app.rootDir, 'ios', 'App', 'App', 'info.plist'), + join(iosProjectDirAbs, 'App', 'App', 'info.plist'), 'NSAppTransportSecurity', ); }, @@ -155,8 +152,7 @@ export async function migrateCommand(config: Config): Promise { await runTask(`Migrating by removing USE_PUSH.`, () => { return replacePush( join( - configData!.app.rootDir, - 'ios', + iosProjectDirAbs, 'App', 'App.xcodeproj', 'project.pbxproj', @@ -180,8 +176,7 @@ export async function migrateCommand(config: Config): Promise { () => { return updateAndroidManifest( join( - configData!.app.rootDir, - 'android', + androidProjectDirAbs, 'app', 'src', 'main', @@ -203,7 +198,7 @@ export async function migrateCommand(config: Config): Promise { ); await runTask(`Migrating build.gradle file.`, () => { return updateBuildGradle( - join(configData!.app.rootDir, 'android', 'build.gradle'), + join(androidProjectDirAbs, 'build.gradle'), typeof leaveJCenterPrompt === 'string' && leaveJCenterPrompt.toLowerCase() === 'y', ); @@ -212,7 +207,7 @@ export async function migrateCommand(config: Config): Promise { // Update app.gradle await runTask(`Migrating app.gradle file.`, () => { return updateAppBuildGradle( - join(configData!.app.rootDir, 'android', 'app', 'build.gradle'), + join(androidProjectDirAbs, 'app', 'build.gradle'), ); }); @@ -222,8 +217,7 @@ export async function migrateCommand(config: Config): Promise { () => { return updateGradleWrapper( join( - configData!.app.rootDir, - 'android', + androidProjectDirAbs, 'gradle', 'wrapper', 'gradle-wrapper.properties', @@ -232,32 +226,6 @@ export async function migrateCommand(config: Config): Promise { }, ); - // Update .gitIgnore - await runTask( - `Migrating .gitignore files by adding generated config files.`, - () => { - return (async () => { - await updateGitIgnore( - join(configData!.app.rootDir, 'android', '.gitignore'), - [ - `# Generated Config files`, - `app/src/main/assets/capacitor.config.json`, - `app/src/main/assets/capacitor.plugins.json`, - `app/src/main/res/xml/config.xml`, - ], - ); - await updateGitIgnore( - join(configData!.app.rootDir, 'ios', '.gitignore'), - [ - `# Generated Config files`, - `App/App/capacitor.config.json`, - `App/App/config.xml`, - ], - ); - })(); - }, - ); - // Variables gradle await runTask(`Migrating variables.gradle file.`, () => { return (async (): Promise => { @@ -278,7 +246,7 @@ export async function migrateCommand(config: Config): Promise { for (const variable of Object.keys(variables)) { if ( !(await updateFile( - join('android', 'variables.gradle'), + join(androidProjectDirAbs, 'variables.gradle'), `${variable} = '`, `'`, variables[variable].toString(), @@ -286,7 +254,7 @@ export async function migrateCommand(config: Config): Promise { )) ) { await updateFile( - join('android', 'variables.gradle'), + join(androidProjectDirAbs, 'variables.gradle'), `${variable} = `, `\n`, variables[variable].toString(), @@ -319,38 +287,41 @@ export async function migrateCommand(config: Config): Promise { } } -function daysUntil(date_1: Date) { - const date_2 = new Date(); - const difference = date_1.getTime() - date_2.getTime(); - return Math.ceil(difference / (1000 * 3600 * 24)); -} -async function installLatestNPMLibs(runInstall: boolean) { - const result: string[] = []; - for (const lib of libs) { - if (allDependencies[lib]) { - result.push(`${lib}@${coreVersion}`); + +async function installLatestNPMLibs(runInstall: boolean, cfg: Config) { + const pkgJsonPath = join(cfg.app.rootDir, 'package.json'); + const pkgJson: any = JSON.parse(readFileSync(pkgJsonPath, 'utf-8')); + + for (const devDepKey of pkgJson['devDependencies'].keys()) { + if (libs.includes(devDepKey)) { + pkgJson['devDependencies'][devDepKey] = coreVersion + } else if (plugins.includes(devDepKey)) { + pkgJson['devDependencies'][devDepKey] = pluginVersion } } - - for (const plugin of plugins) { - if (allDependencies[plugin]) { - result.push(`${plugin}@${pluginVersion}`); + for (const depKey of pkgJson['dependencies'].keys()) { + if (libs.includes(depKey)) { + pkgJson['dependencies'][depKey] = coreVersion + } else if (plugins.includes(depKey)) { + pkgJson['dependencies'][depKey] = pluginVersion } } + writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2), {encoding: 'utf-8'}); + if (runInstall) { - await getCommandOutput('npm', ['i', ...result]); + await getCommandOutput('npm', ['i']); } else { logger.info( - `Please run an install command with your package manager of choice with the following:`, + `Please run an install command with your package manager of choice. (ex: yarn install)`, ); - logger.info(` ${result.join(' ')}`); } } async function migrateStoragePluginToPreferences(runInstall: boolean) { if (allDependencies['@capacitor/storage']) { + logger.info('NOTE: @capacitor/storage was renamed to @capacitor/preferences, please be sure to replace occurances in your code.') if (runInstall) { await getCommandOutput('npm', ['uninstall', '@capacitor/storage']); await getCommandOutput('npm', [ From 7008edc04bc5c80d5aee410582fdde1a9ef0dd5a Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 20 Jul 2022 10:15:13 -0400 Subject: [PATCH 09/30] chore: fmt --- cli/src/tasks/migrate.ts | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index ee6dd379e6..6ef78632f8 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -101,10 +101,7 @@ export async function migrateCommand(config: Config): Promise { }, ); - if ( - allDependencies['@capacitor/ios'] && - existsSync(iosProjectDirAbs) - ) { + if (allDependencies['@capacitor/ios'] && existsSync(iosProjectDirAbs)) { // Set deployment target to 13.0 await runTask(`Migrating deployment target to 13.0.`, () => { return updateFile( @@ -151,12 +148,7 @@ export async function migrateCommand(config: Config): Promise { // Remove USE_PUSH await runTask(`Migrating by removing USE_PUSH.`, () => { return replacePush( - join( - iosProjectDirAbs, - 'App', - 'App.xcodeproj', - 'project.pbxproj', - ), + join(iosProjectDirAbs, 'App', 'App.xcodeproj', 'project.pbxproj'), ); }); @@ -287,28 +279,28 @@ export async function migrateCommand(config: Config): Promise { } } - - async function installLatestNPMLibs(runInstall: boolean, cfg: Config) { const pkgJsonPath = join(cfg.app.rootDir, 'package.json'); const pkgJson: any = JSON.parse(readFileSync(pkgJsonPath, 'utf-8')); for (const devDepKey of pkgJson['devDependencies'].keys()) { if (libs.includes(devDepKey)) { - pkgJson['devDependencies'][devDepKey] = coreVersion + pkgJson['devDependencies'][devDepKey] = coreVersion; } else if (plugins.includes(devDepKey)) { - pkgJson['devDependencies'][devDepKey] = pluginVersion + pkgJson['devDependencies'][devDepKey] = pluginVersion; } } for (const depKey of pkgJson['dependencies'].keys()) { if (libs.includes(depKey)) { - pkgJson['dependencies'][depKey] = coreVersion + pkgJson['dependencies'][depKey] = coreVersion; } else if (plugins.includes(depKey)) { - pkgJson['dependencies'][depKey] = pluginVersion + pkgJson['dependencies'][depKey] = pluginVersion; } } - writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2), {encoding: 'utf-8'}); + writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2), { + encoding: 'utf-8', + }); if (runInstall) { await getCommandOutput('npm', ['i']); @@ -321,7 +313,9 @@ async function installLatestNPMLibs(runInstall: boolean, cfg: Config) { async function migrateStoragePluginToPreferences(runInstall: boolean) { if (allDependencies['@capacitor/storage']) { - logger.info('NOTE: @capacitor/storage was renamed to @capacitor/preferences, please be sure to replace occurances in your code.') + logger.info( + 'NOTE: @capacitor/storage was renamed to @capacitor/preferences, please be sure to replace occurances in your code.', + ); if (runInstall) { await getCommandOutput('npm', ['uninstall', '@capacitor/storage']); await getCommandOutput('npm', [ From 28a99225de5588fa26bf188fd19569a1c9e29e54 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 20 Jul 2022 11:06:44 -0400 Subject: [PATCH 10/30] chore: use paths from config object --- cli/src/tasks/migrate.ts | 104 ++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 62 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 6ef78632f8..2344c4814a 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -39,20 +39,19 @@ const plugins = [ '@capacitor/text-zoom', '@capacitor/toast', ]; -let configData: Config | null = null; const coreVersion = 'next'; const pluginVersion = 'next'; export async function migrateCommand(config: Config): Promise { - configData = config; + if (config === null) { + fatal('Config data missing'); + } + allDependencies = { - ...(configData ? configData.app.package.dependencies : {}), - ...(configData ? configData.app.package.devDependencies : {}), + ...config.app.package.dependencies, + ...config.app.package.devDependencies, }; - const iosProjectDirAbs = config.ios.platformDirAbs; - const androidProjectDirAbs = config.android.platformDirAbs; - const monorepoWarning = 'Please note this tool is not intended for use in a mono-repo enviroment, please check out the Ionic vscode extension for this functionality.'; @@ -73,10 +72,6 @@ export async function migrateCommand(config: Config): Promise { migrateconfirm.toLowerCase() === 'y' ) { try { - if (configData === null) { - fatal('Config data missing'); - } - const { npmInstallConfirm } = await logPrompt( `Would you like the migrator to run npm install to install the latest versions of capacitor packages? (Those using other package managers should answer N)`, { @@ -101,11 +96,15 @@ export async function migrateCommand(config: Config): Promise { }, ); - if (allDependencies['@capacitor/ios'] && existsSync(iosProjectDirAbs)) { + if ( + allDependencies['@capacitor/ios'] && + existsSync(config.ios.platformDirAbs) + ) { // Set deployment target to 13.0 await runTask(`Migrating deployment target to 13.0.`, () => { return updateFile( - join(iosProjectDirAbs, 'App', 'App.xcodeproj', 'project.pbxproj'), + config, + join(config.ios.nativeXcodeProjDirAbs, 'project.pbxproj'), 'IPHONEOS_DEPLOYMENT_TARGET = ', ';', '13.0', @@ -115,7 +114,8 @@ export async function migrateCommand(config: Config): Promise { // Update Podfile to 13.0 await runTask(`Migrating Podfile to 13.0.`, () => { return updateFile( - join(iosProjectDirAbs, 'App', 'Podfile'), + config, + join(config.ios.nativeProjectDirAbs, 'Podfile'), `platform :ios, '`, `'`, '13.0', @@ -127,7 +127,8 @@ export async function migrateCommand(config: Config): Promise { `Migrating AppDelegate.swift by removing touchesBegan.`, () => { return updateFile( - join(iosProjectDirAbs, 'App', 'App', 'AppDelegate.swift'), + config, + join(config.ios.nativeTargetDirAbs, 'AppDelegate.swift'), `override func touchesBegan`, `}`, ); @@ -139,7 +140,7 @@ export async function migrateCommand(config: Config): Promise { `Migrating info.plist by removing NSAppTransportSecurity key.`, () => { return removeKey( - join(iosProjectDirAbs, 'App', 'App', 'info.plist'), + join(config.ios.nativeTargetDirAbs, 'info.plist'), 'NSAppTransportSecurity', ); }, @@ -148,32 +149,26 @@ export async function migrateCommand(config: Config): Promise { // Remove USE_PUSH await runTask(`Migrating by removing USE_PUSH.`, () => { return replacePush( - join(iosProjectDirAbs, 'App', 'App.xcodeproj', 'project.pbxproj'), + join(config.ios.nativeXcodeProjDirAbs, 'project.pbxproj'), ); }); // Remove from App Delegate await runTask(`Migrating App Delegate.`, () => { - return replaceIfUsePush(); + return replaceIfUsePush(config); }); } if ( allDependencies['@capacitor/android'] && - existsSync(join(configData.app.rootDir, 'android')) + existsSync(config.android.platformDirAbs) ) { // AndroidManifest.xml add attribute: { return updateAndroidManifest( - join( - androidProjectDirAbs, - 'app', - 'src', - 'main', - 'AndroidManifest.xml', - ), + join(config.android.srcMainDirAbs, 'AndroidManifest.xml'), ); }, ); @@ -190,7 +185,7 @@ export async function migrateCommand(config: Config): Promise { ); await runTask(`Migrating build.gradle file.`, () => { return updateBuildGradle( - join(androidProjectDirAbs, 'build.gradle'), + join(config.android.platformDirAbs, 'build.gradle'), typeof leaveJCenterPrompt === 'string' && leaveJCenterPrompt.toLowerCase() === 'y', ); @@ -199,7 +194,7 @@ export async function migrateCommand(config: Config): Promise { // Update app.gradle await runTask(`Migrating app.gradle file.`, () => { return updateAppBuildGradle( - join(androidProjectDirAbs, 'app', 'build.gradle'), + join(config.android.appDirAbs, 'build.gradle'), ); }); @@ -209,7 +204,7 @@ export async function migrateCommand(config: Config): Promise { () => { return updateGradleWrapper( join( - androidProjectDirAbs, + config.android.platformDirAbs, 'gradle', 'wrapper', 'gradle-wrapper.properties', @@ -238,7 +233,8 @@ export async function migrateCommand(config: Config): Promise { for (const variable of Object.keys(variables)) { if ( !(await updateFile( - join(androidProjectDirAbs, 'variables.gradle'), + config, + join(config.android.platformDirAbs, 'variables.gradle'), `${variable} = '`, `'`, variables[variable].toString(), @@ -246,7 +242,8 @@ export async function migrateCommand(config: Config): Promise { )) ) { await updateFile( - join(androidProjectDirAbs, 'variables.gradle'), + config, + join(config.android.platformDirAbs, 'variables.gradle'), `${variable} = `, `\n`, variables[variable].toString(), @@ -279,18 +276,22 @@ export async function migrateCommand(config: Config): Promise { } } -async function installLatestNPMLibs(runInstall: boolean, cfg: Config) { - const pkgJsonPath = join(cfg.app.rootDir, 'package.json'); - const pkgJson: any = JSON.parse(readFileSync(pkgJsonPath, 'utf-8')); +async function installLatestNPMLibs(runInstall: boolean, config: Config) { + const pkgJsonPath = join(config.app.rootDir, 'package.json'); + const pkgJsonFile = readFile(pkgJsonPath); + if (!pkgJsonFile) { + return; + } + const pkgJson: any = JSON.parse(pkgJsonFile); - for (const devDepKey of pkgJson['devDependencies'].keys()) { + for (const devDepKey of Object.keys(pkgJson['devDependencies'])) { if (libs.includes(devDepKey)) { pkgJson['devDependencies'][devDepKey] = coreVersion; } else if (plugins.includes(devDepKey)) { pkgJson['devDependencies'][devDepKey] = pluginVersion; } } - for (const depKey of pkgJson['dependencies'].keys()) { + for (const depKey of Object.keys(pkgJson['dependencies'])) { if (libs.includes(depKey)) { pkgJson['dependencies'][depKey] = coreVersion; } else if (plugins.includes(depKey)) { @@ -510,33 +511,18 @@ async function updateGradleWrapper(filename: string) { writeFileSync(filename, replaced, 'utf-8'); } -async function updateGitIgnore(filename: string, lines: string[]) { - const txt = readFile(filename); - if (!txt) { - return; - } - let replaced = txt; - for (const line of lines) { - if (!replaced.includes(line)) { - replaced += line + '\n'; - } - } - if (replaced !== txt) { - writeFileSync(filename, replaced, 'utf-8'); - } -} - async function updateFile( + config: Config, filename: string, textStart: string, textEnd: string, replacement?: string, skipIfNotFound?: boolean, ): Promise { - if (configData === null) { + if (config === null) { return false; } - const path = join(configData.app.rootDir, filename); + const path = filename; let txt = readFile(path); if (!txt) { return false; @@ -602,16 +588,10 @@ function setAllStringIn( return result; } -async function replaceIfUsePush() { +async function replaceIfUsePush(config: Config) { const startLine = '#if USE_PUSH'; const endLine = '#endif'; - const filename = join( - configData!.app.rootDir, - 'ios', - 'App', - 'App', - 'AppDelegate.swift', - ); + const filename = join(config.ios.nativeTargetDirAbs, 'AppDelegate.swift'); const txt = readFile(filename); if (!txt) { return; From 0a9ec7dbc265fedd646ecab4630482a6dca42334 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 20 Jul 2022 15:51:15 -0400 Subject: [PATCH 11/30] chore: get variables from template --- cli/src/tasks/migrate.ts | 117 ++++++++++++++++++++++++++++++++------- cli/src/util/fs.ts | 23 ++++++++ 2 files changed, 119 insertions(+), 21 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 2344c4814a..25f22f4a2f 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -1,12 +1,15 @@ -import { writeFileSync, readFileSync, existsSync } from 'fs'; +import { writeFileSync, readFileSync, existsSync } from '@ionic/utils-fs'; import { join } from 'path'; import { runTask } from '../common'; import type { Config } from '../definitions'; import { fatal } from '../errors'; import { logger, logPrompt, logSuccess } from '../log'; +import { deleteFolderRecursive } from '../util/fs'; import { getCommandOutput } from '../util/subprocess'; +import { extractTemplate } from '../util/template'; +// eslint-disable-next-line prefer-const let allDependencies: { [key: string]: any } = {}; const libs = [ '@capacitor/core', @@ -47,6 +50,20 @@ export async function migrateCommand(config: Config): Promise { fatal('Config data missing'); } + const variablesAndClasspaths: + | { + 'variables': any; + 'com.android.tools.build:gradle': string; + 'com.google.gms:google-services': string; + } + | undefined = await getAndroidVarriablesAndClasspaths(config); + + if (!variablesAndClasspaths) { + fatal('Variable and Classpath info could not be read.'); + } + + //* + allDependencies = { ...config.app.package.dependencies, ...config.app.package.devDependencies, @@ -188,6 +205,7 @@ export async function migrateCommand(config: Config): Promise { join(config.android.platformDirAbs, 'build.gradle'), typeof leaveJCenterPrompt === 'string' && leaveJCenterPrompt.toLowerCase() === 'y', + variablesAndClasspaths, ); }); @@ -216,28 +234,16 @@ export async function migrateCommand(config: Config): Promise { // Variables gradle await runTask(`Migrating variables.gradle file.`, () => { return (async (): Promise => { - const variables: { [key: string]: any } = { - minSdkVersion: 22, - compileSdkVersion: 32, - targetSdkVersion: 32, - androidxActivityVersion: '1.4.0', - androidxAppCompatVersion: '1.4.2', - androidxCoordinatorLayoutVersion: '1.2.0', - androidxCoreVersion: '1.8.0', - androidxFragmentVersion: '1.4.1', - junitVersion: '4.13.2', - androidxJunitVersion: '1.1.3', - androidxEspressoCoreVersion: '3.4.0', - cordovaAndroidVersion: '10.1.1', - }; - for (const variable of Object.keys(variables)) { + for (const variable of Object.keys( + variablesAndClasspaths.variables, + )) { if ( !(await updateFile( config, join(config.android.platformDirAbs, 'variables.gradle'), `${variable} = '`, `'`, - variables[variable].toString(), + variablesAndClasspaths.variables[variable].toString(), true, )) ) { @@ -246,7 +252,7 @@ export async function migrateCommand(config: Config): Promise { join(config.android.platformDirAbs, 'variables.gradle'), `${variable} = `, `\n`, - variables[variable].toString(), + variablesAndClasspaths.variables[variable].toString(), true, ); } @@ -274,6 +280,7 @@ export async function migrateCommand(config: Config): Promise { } else { fatal(`User canceled migration.`); } + //*/ } async function installLatestNPMLibs(runInstall: boolean, config: Config) { @@ -399,7 +406,15 @@ async function updateAndroidManifest(filename: string) { writeFileSync(filename, replaced, 'utf-8'); } -async function updateBuildGradle(filename: string, leaveJCenter: boolean) { +async function updateBuildGradle( + filename: string, + leaveJCenter: boolean, + variablesAndClasspaths: { + 'variables': any; + 'com.android.tools.build:gradle': string; + 'com.google.gms:google-services': string; + }, +) { // In build.gradle add dependencies: // classpath 'com.android.tools.build:gradle:7.2.1' // classpath 'com.google.gms:google-services:4.3.10' @@ -408,8 +423,10 @@ async function updateBuildGradle(filename: string, leaveJCenter: boolean) { return; } const neededDeps: { [key: string]: string } = { - 'com.android.tools.build:gradle': '7.2.1', - 'com.google.gms:google-services': '4.3.10', + 'com.android.tools.build:gradle': + variablesAndClasspaths['com.android.tools.build:gradle'], + 'com.google.gms:google-services': + variablesAndClasspaths['com.google.gms:google-services'], }; let replaced = txt; @@ -465,6 +482,64 @@ async function updateBuildGradle(filename: string, leaveJCenter: boolean) { } } +async function getAndroidVarriablesAndClasspaths(config: Config) { + const tempAndroidTemplateFolder = join( + config.cli.assetsDirAbs, + 'tempAndroidTemplate', + ); + await extractTemplate( + config.cli.assets.android.platformTemplateArchiveAbs, + tempAndroidTemplateFolder, + ); + const variablesGradleFile = readFile( + join(tempAndroidTemplateFolder, 'variables.gradle'), + ); + const buildGradleFile = readFile( + join(tempAndroidTemplateFolder, 'build.gradle'), + ); + if (!variablesGradleFile || !buildGradleFile) { + return; + } + deleteFolderRecursive(tempAndroidTemplateFolder); + + const firstIndxOfCATBGV = + buildGradleFile.indexOf(`classpath 'com.android.tools.build:gradle:`) + 42; + const firstIndxOfCGGGS = + buildGradleFile.indexOf(`com.google.gms:google-services:`) + 31; + const comAndroidToolsBuildGradleVersion = + '' + + buildGradleFile.substring( + firstIndxOfCATBGV, + buildGradleFile.indexOf("'", firstIndxOfCATBGV), + ); + const comGoogleGmsGoogleServices = + '' + + buildGradleFile.substring( + firstIndxOfCGGGS, + buildGradleFile.indexOf("'", firstIndxOfCGGGS), + ); + + const variablesGradleAsJSON = JSON.parse( + variablesGradleFile + .replace('ext ', '') + .replace(/=/g, ':') + .replace(/\n/g, ',') + .replace(/,([^:]+):/g, function (_k, p1) { + return `,"${p1}":`; + }) + .replace('{,', '{') + .replace(',}', '}') + .replace(/\s/g, '') + .replace(/'/g, '"'), + ); + + return { + 'variables': variablesGradleAsJSON, + 'com.android.tools.build:gradle': comAndroidToolsBuildGradleVersion, + 'com.google.gms:google-services': comGoogleGmsGoogleServices, + }; +} + function readFile(filename: string): string | undefined { try { if (!existsSync(filename)) { diff --git a/cli/src/util/fs.ts b/cli/src/util/fs.ts index b5c12e4b6d..ed2acc4bce 100644 --- a/cli/src/util/fs.ts +++ b/cli/src/util/fs.ts @@ -1,3 +1,26 @@ +import { + existsSync, + lstatSync, + readdirSync, + rmdirSync, + unlinkSync, +} from '@ionic/utils-fs'; +import { join } from 'path'; + export const convertToUnixPath = (path: string): string => { return path.replace(/\\/g, '/'); }; + +export const deleteFolderRecursive = (directoryPath: any): void => { + if (existsSync(directoryPath)) { + readdirSync(directoryPath).forEach((file, index) => { + const curPath = join(directoryPath, file); + if (lstatSync(curPath).isDirectory()) { + deleteFolderRecursive(curPath); + } else { + unlinkSync(curPath); + } + }); + rmdirSync(directoryPath); + } +}; From a9fa88f26d15f4eaad4d8069e5bb9b009888f34f Mon Sep 17 00:00:00 2001 From: Mike Summerfeldt <20338451+IT-MikeS@users.noreply.github.com> Date: Tue, 26 Jul 2022 12:22:25 -0400 Subject: [PATCH 12/30] Update cli/src/tasks/migrate.ts Co-authored-by: jcesarmobile --- cli/src/tasks/migrate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 25f22f4a2f..8d3bb46aa3 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -157,7 +157,7 @@ export async function migrateCommand(config: Config): Promise { `Migrating info.plist by removing NSAppTransportSecurity key.`, () => { return removeKey( - join(config.ios.nativeTargetDirAbs, 'info.plist'), + join(config.ios.nativeTargetDirAbs, 'Info.plist'), 'NSAppTransportSecurity', ); }, From 1e0c3998e63b71099698e31649deb0572ceb5594 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 12:18:02 -0400 Subject: [PATCH 13/30] chore: add android 12 splash and podfile postinstall --- cli/src/tasks/migrate.ts | 122 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 5 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 8d3bb46aa3..4a369936b0 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -8,6 +8,7 @@ import { logger, logPrompt, logSuccess } from '../log'; import { deleteFolderRecursive } from '../util/fs'; import { getCommandOutput } from '../util/subprocess'; import { extractTemplate } from '../util/template'; +import { readXML } from '../util/xml'; // eslint-disable-next-line prefer-const let allDependencies: { [key: string]: any } = {}; @@ -139,6 +140,10 @@ export async function migrateCommand(config: Config): Promise { ); }); + await runTask(`Migrating Podfile to use post_install script.`, () => { + return podfileAssertDeploymentTarget(join(config.ios.nativeProjectDirAbs, 'Podfile')); + }); + // Remove touchesBegan await runTask( `Migrating AppDelegate.swift by removing touchesBegan.`, @@ -154,7 +159,7 @@ export async function migrateCommand(config: Config): Promise { // Remove NSAppTransportSecurity await runTask( - `Migrating info.plist by removing NSAppTransportSecurity key.`, + `Migrating Info.plist by removing NSAppTransportSecurity key.`, () => { return removeKey( join(config.ios.nativeTargetDirAbs, 'Info.plist'), @@ -259,6 +264,16 @@ export async function migrateCommand(config: Config): Promise { } })(); }); + + // remove init + await runTask('Migrating MainActivity by removing init().', () => { + return removeOldInitAndroid(config); + }); + + // add new splashscreen + await runTask('Migrate to Android 12 Splashscreen.', () => { + return addNewSplashScreen(config); + }) } // Run Cap Sync @@ -394,10 +409,7 @@ async function updateAndroidManifest(filename: string) { ' android:exported="true"', ); } else { - replaced = txt.replace( - 'android:exported="false"', - 'android:exported="true"', - ); + logger.info(`Found 'android:exported="false"' in your AndroidManifest.xml, if this is not intentional please update it manually to "true".`) } if (txt == replaced) { logger.error(`Unable to update Android Manifest. Missing tag`); @@ -732,3 +744,103 @@ async function removeKey(filename: string, key: string) { writeFileSync(filename, lines.join('\n'), 'utf-8'); } } + +async function podfileAssertDeploymentTarget(filename: string) { + const txt = readFile(filename); + if (!txt) { + return; + } + let replaced = `require_relative '../node_modules/@capacitor/ios/scripts/pods_helpers'\n\n` + txt; + replaced = replaced + `\n\npost_install do |installer|\n assertDeploymentTarget(installer)\n end\n`; + writeFileSync(filename, replaced, 'utf-8'); +} + +async function removeOldInitAndroid(config: Config) { + const xmlData = await readXML(join(config.android.srcMainDirAbs, 'AndroidManifest.xml')); + const manifestNode: any = xmlData.manifest; + const applicationChildNodes: any[] = manifestNode.application; + let mainActivityClassPath = ''; + const mainApplicationNode = applicationChildNodes.find( + applicationChildNode => { + const activityChildNodes: any[] = applicationChildNode.activity; + if (!Array.isArray(activityChildNodes)) { + return false; + } + + const mainActivityNode = activityChildNodes.find(activityChildNode => { + const intentFilterChildNodes: any[] = + activityChildNode['intent-filter']; + if (!Array.isArray(intentFilterChildNodes)) { + return false; + } + + return intentFilterChildNodes.find(intentFilterChildNode => { + const actionChildNodes: any[] = intentFilterChildNode.action; + if (!Array.isArray(actionChildNodes)) { + return false; + } + + const mainActionChildNode = actionChildNodes.find(actionChildNode => { + const androidName = actionChildNode.$['android:name']; + return androidName === 'android.intent.action.MAIN'; + }); + + if (!mainActionChildNode) { + return false; + } + + const categoryChildNodes: any[] = intentFilterChildNode.category; + if (!Array.isArray(categoryChildNodes)) { + return false; + } + + return categoryChildNodes.find(categoryChildNode => { + const androidName = categoryChildNode.$['android:name']; + return androidName === 'android.intent.category.LAUNCHER'; + }); + }); + }); + + if (mainActivityNode) { + mainActivityClassPath = mainActivityNode.$['android:name']; + } + + return mainActivityNode; + }, + ); + const mainActivityClassName: any = mainActivityClassPath.split('.').pop(); + const mainActivityClassFileName = `${mainActivityClassName}.java`; + const mainActivityClassFilePath = join(join(config.android.srcMainDirAbs, 'java'), mainActivityClassFileName); + + let data = readFile(mainActivityClassFilePath); + + if (data) { + const bindex = data.indexOf('this.init(savedInstanceState'); + if (bindex == -1) return; + const eindex = data.indexOf('}});', bindex) + 4; + + data = data.replace(data.substring(bindex, eindex), ""); + + writeFileSync(mainActivityClassFilePath, data); + } +} + +async function addNewSplashScreen(config: Config) { + const varsPath = join(config.android.platformDirAbs, 'variables.gradle'); + let varsGradle = readFile(varsPath); + const buildPath = join(config.android.appDirAbs, 'build.gradle'); + let buildGradle = readFile(buildPath); + const stylePath = join(config.android.srcMainDirAbs, 'res', 'values', 'styles.xml'); + let stylesXml = readFile(stylePath); + + if (!varsGradle || !buildGradle || !stylesXml) return; + + stylesXml = stylesXml.replace('AppTheme.NoActionBar', 'Theme.SplashScreen'); + writeFileSync(stylePath, stylesXml); + + varsGradle = varsGradle.replace('}', ` coreSplashScreenVersion = '1.0.0-rc01'\n}`); + writeFileSync(varsPath, varsGradle); + + buildGradle = buildGradle.replace('implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"', `implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"\n implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"\n`); + writeFileSync(buildPath, buildGradle); +} From 1bcb6ce7537fad79881684dd41ef6104c9d4a2c0 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 12:26:34 -0400 Subject: [PATCH 14/30] chore: npm install fix --- cli/package.json | 3 ++- cli/src/tasks/migrate.ts | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cli/package.json b/cli/package.json index 1de02f3cd8..2cb35c9d90 100644 --- a/cli/package.json +++ b/cli/package.json @@ -56,6 +56,7 @@ "open": "^8.4.0", "plist": "^3.0.5", "prompts": "^2.4.2", + "rimraf": "^3.0.2", "semver": "^7.3.7", "tar": "^6.1.11", "tslib": "^2.4.0", @@ -66,12 +67,12 @@ "@types/jest": "^26.0.4", "@types/plist": "^3.0.2", "@types/prompts": "^2.0.14", + "@types/rimraf": "^3.0.2", "@types/semver": "^7.3.10", "@types/tar": "^6.1.1", "@types/tmp": "^0.2.3", "@types/xml2js": "0.4.5", "jest": "^26.1.0", - "rimraf": "^3.0.2", "tmp": "^0.2.1", "ts-jest": "^26.1.3", "typescript": "~4.1.2" diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 4a369936b0..9f11246316 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -1,5 +1,6 @@ import { writeFileSync, readFileSync, existsSync } from '@ionic/utils-fs'; import { join } from 'path'; +import rimraf from 'rimraf'; import { runTask } from '../common'; import type { Config } from '../definitions'; @@ -326,6 +327,8 @@ async function installLatestNPMLibs(runInstall: boolean, config: Config) { }); if (runInstall) { + rimraf.sync(join(config.app.rootDir, 'package-lock.json')); + rimraf.sync(join(config.app.rootDir, 'node_modules/@capacitor/!(cli)')); await getCommandOutput('npm', ['i']); } else { logger.info( From 046e46f37626168ffa4d4457fe36522c3ed6364b Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 12:26:59 -0400 Subject: [PATCH 15/30] chore: fmt --- cli/src/tasks/migrate.ts | 50 +++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 9f11246316..6c3ce3efc6 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -142,7 +142,9 @@ export async function migrateCommand(config: Config): Promise { }); await runTask(`Migrating Podfile to use post_install script.`, () => { - return podfileAssertDeploymentTarget(join(config.ios.nativeProjectDirAbs, 'Podfile')); + return podfileAssertDeploymentTarget( + join(config.ios.nativeProjectDirAbs, 'Podfile'), + ); }); // Remove touchesBegan @@ -274,7 +276,7 @@ export async function migrateCommand(config: Config): Promise { // add new splashscreen await runTask('Migrate to Android 12 Splashscreen.', () => { return addNewSplashScreen(config); - }) + }); } // Run Cap Sync @@ -412,7 +414,9 @@ async function updateAndroidManifest(filename: string) { ' android:exported="true"', ); } else { - logger.info(`Found 'android:exported="false"' in your AndroidManifest.xml, if this is not intentional please update it manually to "true".`) + logger.info( + `Found 'android:exported="false"' in your AndroidManifest.xml, if this is not intentional please update it manually to "true".`, + ); } if (txt == replaced) { logger.error(`Unable to update Android Manifest. Missing tag`); @@ -753,13 +757,19 @@ async function podfileAssertDeploymentTarget(filename: string) { if (!txt) { return; } - let replaced = `require_relative '../node_modules/@capacitor/ios/scripts/pods_helpers'\n\n` + txt; - replaced = replaced + `\n\npost_install do |installer|\n assertDeploymentTarget(installer)\n end\n`; + let replaced = + `require_relative '../node_modules/@capacitor/ios/scripts/pods_helpers'\n\n` + + txt; + replaced = + replaced + + `\n\npost_install do |installer|\n assertDeploymentTarget(installer)\n end\n`; writeFileSync(filename, replaced, 'utf-8'); } async function removeOldInitAndroid(config: Config) { - const xmlData = await readXML(join(config.android.srcMainDirAbs, 'AndroidManifest.xml')); + const xmlData = await readXML( + join(config.android.srcMainDirAbs, 'AndroidManifest.xml'), + ); const manifestNode: any = xmlData.manifest; const applicationChildNodes: any[] = manifestNode.application; let mainActivityClassPath = ''; @@ -813,16 +823,19 @@ async function removeOldInitAndroid(config: Config) { ); const mainActivityClassName: any = mainActivityClassPath.split('.').pop(); const mainActivityClassFileName = `${mainActivityClassName}.java`; - const mainActivityClassFilePath = join(join(config.android.srcMainDirAbs, 'java'), mainActivityClassFileName); - + const mainActivityClassFilePath = join( + join(config.android.srcMainDirAbs, 'java'), + mainActivityClassFileName, + ); + let data = readFile(mainActivityClassFilePath); if (data) { const bindex = data.indexOf('this.init(savedInstanceState'); if (bindex == -1) return; const eindex = data.indexOf('}});', bindex) + 4; - - data = data.replace(data.substring(bindex, eindex), ""); + + data = data.replace(data.substring(bindex, eindex), ''); writeFileSync(mainActivityClassFilePath, data); } @@ -833,7 +846,12 @@ async function addNewSplashScreen(config: Config) { let varsGradle = readFile(varsPath); const buildPath = join(config.android.appDirAbs, 'build.gradle'); let buildGradle = readFile(buildPath); - const stylePath = join(config.android.srcMainDirAbs, 'res', 'values', 'styles.xml'); + const stylePath = join( + config.android.srcMainDirAbs, + 'res', + 'values', + 'styles.xml', + ); let stylesXml = readFile(stylePath); if (!varsGradle || !buildGradle || !stylesXml) return; @@ -841,9 +859,15 @@ async function addNewSplashScreen(config: Config) { stylesXml = stylesXml.replace('AppTheme.NoActionBar', 'Theme.SplashScreen'); writeFileSync(stylePath, stylesXml); - varsGradle = varsGradle.replace('}', ` coreSplashScreenVersion = '1.0.0-rc01'\n}`); + varsGradle = varsGradle.replace( + '}', + ` coreSplashScreenVersion = '1.0.0-rc01'\n}`, + ); writeFileSync(varsPath, varsGradle); - buildGradle = buildGradle.replace('implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"', `implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"\n implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"\n`); + buildGradle = buildGradle.replace( + 'implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"', + `implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"\n implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"\n`, + ); writeFileSync(buildPath, buildGradle); } From 575c142561b4976822ad24e748fa03a4893b5001 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 12:38:50 -0400 Subject: [PATCH 16/30] chore: activity path fix --- cli/src/tasks/migrate.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 6c3ce3efc6..77399da988 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -822,9 +822,12 @@ async function removeOldInitAndroid(config: Config) { }, ); const mainActivityClassName: any = mainActivityClassPath.split('.').pop(); + const mainActivityPathArray = mainActivityClassPath.split('.'); + mainActivityPathArray.pop(); const mainActivityClassFileName = `${mainActivityClassName}.java`; const mainActivityClassFilePath = join( join(config.android.srcMainDirAbs, 'java'), + ...mainActivityPathArray, mainActivityClassFileName, ); From b316fc7a52702db86561349fd9f8eba639fcf2dd Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 12:43:03 -0400 Subject: [PATCH 17/30] chore: post_install add if already exists --- cli/src/tasks/migrate.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 77399da988..0855a246f9 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -760,9 +760,16 @@ async function podfileAssertDeploymentTarget(filename: string) { let replaced = `require_relative '../node_modules/@capacitor/ios/scripts/pods_helpers'\n\n` + txt; - replaced = - replaced + - `\n\npost_install do |installer|\n assertDeploymentTarget(installer)\n end\n`; + if (replaced.includes('post_install do |installer|')) { + replaced = replaced.replace( + 'post_install do |installer|', + `post_install do |installer|\n assertDeploymentTarget(installer)\n`, + ); + } else { + replaced = + replaced + + `\n\npost_install do |installer|\n assertDeploymentTarget(installer)\n end\n`; + } writeFileSync(filename, replaced, 'utf-8'); } From 2c2999b8732d7cea415cb3e1758ff92e1ef14d03 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 12:45:49 -0400 Subject: [PATCH 18/30] chore: remove comment for init() --- cli/src/tasks/migrate.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 0855a246f9..7ed8dc395e 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -847,6 +847,8 @@ async function removeOldInitAndroid(config: Config) { data = data.replace(data.substring(bindex, eindex), ''); + data = data.replace('// Initializes the Bridge', ''); + writeFileSync(mainActivityClassFilePath, data); } } From 5ffdb6e40c4f8ef29914db200b518735bfdcc0b9 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 12:51:05 -0400 Subject: [PATCH 19/30] chore: path fix for require_relative --- cli/src/tasks/migrate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 7ed8dc395e..63d93d94b8 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -758,7 +758,7 @@ async function podfileAssertDeploymentTarget(filename: string) { return; } let replaced = - `require_relative '../node_modules/@capacitor/ios/scripts/pods_helpers'\n\n` + + `require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'\n\n` + txt; if (replaced.includes('post_install do |installer|')) { replaced = replaced.replace( From ebdb36d28e9d0493e2845b3a2ff733cb65d9ecc0 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 12:55:51 -0400 Subject: [PATCH 20/30] chore: look for already migrated post_install --- cli/src/tasks/migrate.ts | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 63d93d94b8..e3124d98a4 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -757,14 +757,23 @@ async function podfileAssertDeploymentTarget(filename: string) { if (!txt) { return; } - let replaced = - `require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'\n\n` + - txt; + let replaced = txt; + if ( + !replaced.includes( + `require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers`, + ) + ) { + replaced = + `require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'\n\n` + + txt; + } if (replaced.includes('post_install do |installer|')) { - replaced = replaced.replace( - 'post_install do |installer|', - `post_install do |installer|\n assertDeploymentTarget(installer)\n`, - ); + if (!replaced.includes(`assertDeploymentTarget(installer)`)) { + replaced = replaced.replace( + 'post_install do |installer|', + `post_install do |installer|\n assertDeploymentTarget(installer)\n`, + ); + } } else { replaced = replaced + From 0dbdf4b2cb32f58362ef27ea758a769e2af840ba Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 12:59:35 -0400 Subject: [PATCH 21/30] chore: fmt --- cli/src/tasks/migrate.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index e3124d98a4..a5d152e8c6 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -771,13 +771,13 @@ async function podfileAssertDeploymentTarget(filename: string) { if (!replaced.includes(`assertDeploymentTarget(installer)`)) { replaced = replaced.replace( 'post_install do |installer|', - `post_install do |installer|\n assertDeploymentTarget(installer)\n`, + `post_install do |installer|\n assertDeploymentTarget(installer)\n`, ); } } else { replaced = replaced + - `\n\npost_install do |installer|\n assertDeploymentTarget(installer)\n end\n`; + `\n\npost_install do |installer|\n assertDeploymentTarget(installer)\nend\n`; } writeFileSync(filename, replaced, 'utf-8'); } From 7c0ccd642a1aff3a4cf07858491b075be45402ba Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 13:13:36 -0400 Subject: [PATCH 22/30] chore: remove unused var --- cli/src/tasks/migrate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index a5d152e8c6..1bffd123ee 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -789,7 +789,7 @@ async function removeOldInitAndroid(config: Config) { const manifestNode: any = xmlData.manifest; const applicationChildNodes: any[] = manifestNode.application; let mainActivityClassPath = ''; - const mainApplicationNode = applicationChildNodes.find( + applicationChildNodes.find( applicationChildNode => { const activityChildNodes: any[] = applicationChildNode.activity; if (!Array.isArray(activityChildNodes)) { From bbc77b63e4d3a587d4fc927332b2142002d733c1 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 13:15:27 -0400 Subject: [PATCH 23/30] chore: remove more unused --- cli/src/util/fs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/util/fs.ts b/cli/src/util/fs.ts index ed2acc4bce..f98a302270 100644 --- a/cli/src/util/fs.ts +++ b/cli/src/util/fs.ts @@ -13,7 +13,7 @@ export const convertToUnixPath = (path: string): string => { export const deleteFolderRecursive = (directoryPath: any): void => { if (existsSync(directoryPath)) { - readdirSync(directoryPath).forEach((file, index) => { + readdirSync(directoryPath).forEach((file) => { const curPath = join(directoryPath, file); if (lstatSync(curPath).isDirectory()) { deleteFolderRecursive(curPath); From 9d2de4cdf30050e54a1eddb52d11b73f8ca5e636 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 13:24:17 -0400 Subject: [PATCH 24/30] chore: move app build.gradle edit logic --- cli/src/tasks/migrate.ts | 79 +++++++++++++++++----------------------- cli/src/util/fs.ts | 2 +- 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 1bffd123ee..bb0304a8f3 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -584,7 +584,7 @@ async function updateAppBuildGradle(filename: string) { const replaced = txt.replace( 'dependencies {', - 'dependencies {\n implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"', + 'dependencies {\n implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"\n implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"', ); // const lines = txt.split('\n'); writeFileSync(filename, replaced, 'utf-8'); @@ -789,54 +789,51 @@ async function removeOldInitAndroid(config: Config) { const manifestNode: any = xmlData.manifest; const applicationChildNodes: any[] = manifestNode.application; let mainActivityClassPath = ''; - applicationChildNodes.find( - applicationChildNode => { - const activityChildNodes: any[] = applicationChildNode.activity; - if (!Array.isArray(activityChildNodes)) { + applicationChildNodes.find(applicationChildNode => { + const activityChildNodes: any[] = applicationChildNode.activity; + if (!Array.isArray(activityChildNodes)) { + return false; + } + + const mainActivityNode = activityChildNodes.find(activityChildNode => { + const intentFilterChildNodes: any[] = activityChildNode['intent-filter']; + if (!Array.isArray(intentFilterChildNodes)) { return false; } - const mainActivityNode = activityChildNodes.find(activityChildNode => { - const intentFilterChildNodes: any[] = - activityChildNode['intent-filter']; - if (!Array.isArray(intentFilterChildNodes)) { + return intentFilterChildNodes.find(intentFilterChildNode => { + const actionChildNodes: any[] = intentFilterChildNode.action; + if (!Array.isArray(actionChildNodes)) { return false; } - return intentFilterChildNodes.find(intentFilterChildNode => { - const actionChildNodes: any[] = intentFilterChildNode.action; - if (!Array.isArray(actionChildNodes)) { - return false; - } - - const mainActionChildNode = actionChildNodes.find(actionChildNode => { - const androidName = actionChildNode.$['android:name']; - return androidName === 'android.intent.action.MAIN'; - }); + const mainActionChildNode = actionChildNodes.find(actionChildNode => { + const androidName = actionChildNode.$['android:name']; + return androidName === 'android.intent.action.MAIN'; + }); - if (!mainActionChildNode) { - return false; - } + if (!mainActionChildNode) { + return false; + } - const categoryChildNodes: any[] = intentFilterChildNode.category; - if (!Array.isArray(categoryChildNodes)) { - return false; - } + const categoryChildNodes: any[] = intentFilterChildNode.category; + if (!Array.isArray(categoryChildNodes)) { + return false; + } - return categoryChildNodes.find(categoryChildNode => { - const androidName = categoryChildNode.$['android:name']; - return androidName === 'android.intent.category.LAUNCHER'; - }); + return categoryChildNodes.find(categoryChildNode => { + const androidName = categoryChildNode.$['android:name']; + return androidName === 'android.intent.category.LAUNCHER'; }); }); + }); - if (mainActivityNode) { - mainActivityClassPath = mainActivityNode.$['android:name']; - } + if (mainActivityNode) { + mainActivityClassPath = mainActivityNode.$['android:name']; + } - return mainActivityNode; - }, - ); + return mainActivityNode; + }); const mainActivityClassName: any = mainActivityClassPath.split('.').pop(); const mainActivityPathArray = mainActivityClassPath.split('.'); mainActivityPathArray.pop(); @@ -865,8 +862,6 @@ async function removeOldInitAndroid(config: Config) { async function addNewSplashScreen(config: Config) { const varsPath = join(config.android.platformDirAbs, 'variables.gradle'); let varsGradle = readFile(varsPath); - const buildPath = join(config.android.appDirAbs, 'build.gradle'); - let buildGradle = readFile(buildPath); const stylePath = join( config.android.srcMainDirAbs, 'res', @@ -875,7 +870,7 @@ async function addNewSplashScreen(config: Config) { ); let stylesXml = readFile(stylePath); - if (!varsGradle || !buildGradle || !stylesXml) return; + if (!varsGradle || !stylesXml) return; stylesXml = stylesXml.replace('AppTheme.NoActionBar', 'Theme.SplashScreen'); writeFileSync(stylePath, stylesXml); @@ -885,10 +880,4 @@ async function addNewSplashScreen(config: Config) { ` coreSplashScreenVersion = '1.0.0-rc01'\n}`, ); writeFileSync(varsPath, varsGradle); - - buildGradle = buildGradle.replace( - 'implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"', - `implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"\n implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"\n`, - ); - writeFileSync(buildPath, buildGradle); } diff --git a/cli/src/util/fs.ts b/cli/src/util/fs.ts index f98a302270..dc8aeb3555 100644 --- a/cli/src/util/fs.ts +++ b/cli/src/util/fs.ts @@ -13,7 +13,7 @@ export const convertToUnixPath = (path: string): string => { export const deleteFolderRecursive = (directoryPath: any): void => { if (existsSync(directoryPath)) { - readdirSync(directoryPath).forEach((file) => { + readdirSync(directoryPath).forEach(file => { const curPath = join(directoryPath, file); if (lstatSync(curPath).isDirectory()) { deleteFolderRecursive(curPath); From a48c1232ce29828195deff029d22aff6a826e954 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 13:30:30 -0400 Subject: [PATCH 25/30] chore: only add if not exists --- cli/src/tasks/migrate.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index bb0304a8f3..50caa2a403 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -875,9 +875,11 @@ async function addNewSplashScreen(config: Config) { stylesXml = stylesXml.replace('AppTheme.NoActionBar', 'Theme.SplashScreen'); writeFileSync(stylePath, stylesXml); - varsGradle = varsGradle.replace( - '}', - ` coreSplashScreenVersion = '1.0.0-rc01'\n}`, - ); - writeFileSync(varsPath, varsGradle); + if (!varsGradle.includes(`coreSplashScreenVersion = `)) { + varsGradle = varsGradle.replace( + '}', + ` coreSplashScreenVersion = '1.0.0-rc01'\n}`, + ); + writeFileSync(varsPath, varsGradle); + } } From 12148ad6f8ace42ca6a66312e022c7e5fe72f1d2 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 13:38:15 -0400 Subject: [PATCH 26/30] chore: check for each dep --- cli/src/tasks/migrate.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 50caa2a403..a2a0ccec74 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -578,16 +578,23 @@ async function updateAppBuildGradle(filename: string) { if (!txt) { return; } - if (txt.includes('androidx.coordinatorlayout:coordinatorlayout:')) { - return; + let replaced = txt; + if (!txt.includes('androidx.coordinatorlayout:coordinatorlayout:')) { + replaced = replaced.replace( + 'dependencies {', + 'dependencies {\n implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"', + ); + } + if (!txt.includes('androidx.core:core-splashscreen:')) { + replaced = replaced.replace( + 'dependencies {', + 'dependencies {\n implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"', + ); } - - const replaced = txt.replace( - 'dependencies {', - 'dependencies {\n implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"\n implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"', - ); // const lines = txt.split('\n'); - writeFileSync(filename, replaced, 'utf-8'); + if (replaced !== txt) { + writeFileSync(filename, replaced, 'utf-8'); + } } async function updateGradleWrapper(filename: string) { From 98b521e44b00e1bcab979b58994aa4d0e3ad477f Mon Sep 17 00:00:00 2001 From: Mike Summerfeldt <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 13:41:59 -0400 Subject: [PATCH 27/30] Update cli/src/tasks/migrate.ts Co-authored-by: jcesarmobile --- cli/src/tasks/migrate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index a2a0ccec74..6898c513af 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -218,7 +218,7 @@ export async function migrateCommand(config: Config): Promise { }); // Update app.gradle - await runTask(`Migrating app.gradle file.`, () => { + await runTask(`Migrating app/build.gradle file.`, () => { return updateAppBuildGradle( join(config.android.appDirAbs, 'build.gradle'), ); From b81a46c23df850cac4cb9cc2334e6314edf5ed4e Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 14:31:41 -0400 Subject: [PATCH 28/30] chore: fmt --- cli/src/tasks/migrate.ts | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 6898c513af..9b54f89fab 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -156,6 +156,8 @@ export async function migrateCommand(config: Config): Promise { join(config.ios.nativeTargetDirAbs, 'AppDelegate.swift'), `override func touchesBegan`, `}`, + undefined, + true, ); }, ); @@ -255,7 +257,7 @@ export async function migrateCommand(config: Config): Promise { true, )) ) { - await updateFile( + const didWork = await updateFile( config, join(config.android.platformDirAbs, 'variables.gradle'), `${variable} = `, @@ -263,6 +265,13 @@ export async function migrateCommand(config: Config): Promise { variablesAndClasspaths.variables[variable].toString(), true, ); + if (!didWork) { + let file = readFile(join(config.android.platformDirAbs, 'variables.gradle')); + if (file) { + file = file.replace('ext {', `ext {\n ${variable} = '${variablesAndClasspaths.variables[variable].toString()}'`); + writeFileSync(join(config.android.platformDirAbs, 'variables.gradle'), file); + } + } } } })(); @@ -273,6 +282,8 @@ export async function migrateCommand(config: Config): Promise { return removeOldInitAndroid(config); }); + rimraf.sync(join(config.android.appDirAbs, 'build')); + // add new splashscreen await runTask('Migrate to Android 12 Splashscreen.', () => { return addNewSplashScreen(config); @@ -411,7 +422,7 @@ async function updateAndroidManifest(filename: string) { txt, ' Date: Wed, 27 Jul 2022 14:32:02 -0400 Subject: [PATCH 29/30] chore: more fmt --- cli/src/tasks/migrate.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 9b54f89fab..68e6e57ba3 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -266,10 +266,20 @@ export async function migrateCommand(config: Config): Promise { true, ); if (!didWork) { - let file = readFile(join(config.android.platformDirAbs, 'variables.gradle')); + let file = readFile( + join(config.android.platformDirAbs, 'variables.gradle'), + ); if (file) { - file = file.replace('ext {', `ext {\n ${variable} = '${variablesAndClasspaths.variables[variable].toString()}'`); - writeFileSync(join(config.android.platformDirAbs, 'variables.gradle'), file); + file = file.replace( + 'ext {', + `ext {\n ${variable} = '${variablesAndClasspaths.variables[ + variable + ].toString()}'`, + ); + writeFileSync( + join(config.android.platformDirAbs, 'variables.gradle'), + file, + ); } } } @@ -890,5 +900,4 @@ async function addNewSplashScreen(config: Config) { stylesXml = stylesXml.replace('AppTheme.NoActionBar', 'Theme.SplashScreen'); writeFileSync(stylePath, stylesXml); - } From d9db66e8fb725d7631d9e7790b2bc592783e5e79 Mon Sep 17 00:00:00 2001 From: IT-MikeS <20338451+IT-MikeS@users.noreply.github.com> Date: Wed, 27 Jul 2022 14:33:14 -0400 Subject: [PATCH 30/30] chore: use latest --- cli/src/tasks/migrate.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/tasks/migrate.ts b/cli/src/tasks/migrate.ts index 68e6e57ba3..69318d886d 100644 --- a/cli/src/tasks/migrate.ts +++ b/cli/src/tasks/migrate.ts @@ -44,8 +44,8 @@ const plugins = [ '@capacitor/text-zoom', '@capacitor/toast', ]; -const coreVersion = 'next'; -const pluginVersion = 'next'; +const coreVersion = 'latest'; +const pluginVersion = 'latest'; export async function migrateCommand(config: Config): Promise { if (config === null) {