@codehance/rapid-stack
Version:
A modern full-stack development toolkit for rapid application development
305 lines (270 loc) ⢠11.9 kB
JavaScript
'use strict';
const { execSync } = require('child_process');
const BaseGenerator = require('../base');
const path = require('path');
const fs = require('fs');
const os = require('os');
const { getShellConfig, addEnvVarsToShellConfig, getSourceCommand } = require('../../lib/utils');
module.exports = class extends BaseGenerator {
constructor(args, opts) {
super(args, opts);
}
async initializing() {
this.log('\n' + '='.repeat(80));
this.log('đ¤ Android Project Setup');
this.log('='.repeat(80));
// Check if frontend directory exists
const frontendDir = path.join(process.cwd(), 'frontend');
if (!fs.existsSync(frontendDir)) {
this.log('\nâ Frontend directory not found!');
this.log('='.repeat(80));
this.log('\nPlease ensure you have generated a frontend project and it is in the current directory.');
this.log('\nTo generate a frontend project, run:');
this.log(' rapid build:frontend');
this.log('\nAfter generating the frontend project, run this command again.');
this.log('\n' + '='.repeat(80) + '\n');
process.exit(1);
}
// Check for Android Studio installation
try {
const androidStudioPath = '/Applications/Android Studio.app';
if (fs.existsSync(androidStudioPath)) {
this.log('\nâ Android Studio is installed');
} else {
this.log('\nâ Android Studio is not installed!');
const installAnswer = await this.prompt([
{
type: 'confirm',
name: 'installAndroidStudio',
message: 'Would you like to install Android Studio now?',
default: true
}
]);
if (installAnswer.installAndroidStudio) {
this.log('\nâ ď¸ Android Studio must be installed from the official website.');
this.log('Please follow these steps:');
this.log('1. Visit https://developer.android.com/studio');
this.log('2. Download Android Studio for macOS');
this.log('3. Open the downloaded .dmg file');
this.log('4. Drag Android Studio to the Applications folder');
this.log('5. Open Android Studio and complete the setup wizard');
this.log('6. Run this command again');
this.log('\n' + '='.repeat(80) + '\n');
process.exit(1);
} else {
this.log('\nâ ď¸ Android Studio installation skipped.');
this.log('Please install Android Studio manually and run this command again.');
this.log('\n' + '='.repeat(80) + '\n');
process.exit(1);
}
}
} catch (error) {
this.log('\nâ Error checking Android Studio installation:');
this.log(error.message);
process.exit(1);
}
// Check for Java installation
try {
const javaVersion = execSync('java -version', { encoding: 'utf8' }).trim();
this.log(`\nâ Java is installed: ${javaVersion.split('\n')[0]}`);
} catch (error) {
this.log('\nâ Java is not installed!');
const installAnswer = await this.prompt([
{
type: 'confirm',
name: 'installJava',
message: 'Would you like to install Java now?',
default: true
}
]);
if (installAnswer.installJava) {
this.log('\nâ ď¸ Java must be installed using Homebrew.');
this.log('Please follow these steps:');
this.log('1. Install Homebrew if not already installed:');
this.log(' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"');
this.log('2. Install Java:');
this.log(' brew install openjdk');
this.log('3. Run this command again');
this.log('\n' + '='.repeat(80) + '\n');
process.exit(1);
} else {
this.log('\nâ ď¸ Java installation skipped.');
this.log('Please install Java manually and run this command again.');
this.log('\n' + '='.repeat(80) + '\n');
process.exit(1);
}
}
// Check for Android SDK
try {
const androidHome = process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT;
if (androidHome && fs.existsSync(androidHome)) {
this.log('\nâ Android SDK is installed');
} else {
// Check if the environment variables are defined in the shell config
const { path: shellConfig } = getShellConfig();
const configPath = shellConfig.replace('~', os.homedir());
const existingConfig = fs.existsSync(configPath) ? fs.readFileSync(configPath, 'utf8') : '';
if (existingConfig.includes('ANDROID_HOME')) {
// Environment variables are defined but not sourced in current session
this.log('\nâ ď¸ Android SDK configuration exists but needs to be sourced');
this.log('Sourcing configuration...');
try {
const { execSync } = require('child_process');
const sourceCmd = getSourceCommand(shellConfig);
execSync(sourceCmd, { stdio: 'inherit' });
this.log('â Configuration sourced successfully');
} catch (sourceError) {
this.log('\nâ Failed to source configuration:');
this.log(sourceError.message);
this.log('\nPlease run the following command manually:');
this.log(` ${getSourceCommand(shellConfig)}`);
this.log('\nThen run this generator again.');
this.log('\n' + '='.repeat(80) + '\n');
process.exit(1);
}
} else {
this.log('\nâ Android SDK is not properly configured!');
const installAnswer = await this.prompt([
{
type: 'confirm',
name: 'configureSDK',
message: 'Would you like to configure Android SDK environment variables now?',
default: true
}
]);
if (installAnswer.configureSDK) {
// Get shell configuration
const { type: shellType, path: shellConfig, detectedShell } = getShellConfig();
if (shellType === 'unknown') {
this.log('\nâ ď¸ Unknown shell type detected. Defaulting to bash configuration.');
this.log(`Detected shell: ${detectedShell}`);
}
// Create the environment variables
const envVars = [
'# Android SDK Configuration',
'export ANDROID_HOME=$HOME/Library/Android/sdk',
'export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools'
];
try {
const success = addEnvVarsToShellConfig(shellConfig, envVars);
if (!success) {
this.log(`\nâ ď¸ Android SDK configuration already exists in ${shellConfig}`);
this.log('Using existing configuration...');
// Continue with the rest of the setup
this.log('\nContinuing with Android setup...');
} else {
this.log(`\nâ Environment variables added to ${shellConfig}`);
this.log('Configuration has been automatically sourced.');
// Continue with the rest of the setup
this.log('\nContinuing with Android setup...');
}
} catch (error) {
this.log('\nâ Failed to configure Android SDK environment variables:');
this.log(error.message);
this.log('\nPlease add these lines manually to your shell configuration file:');
this.log(envVars.join('\n'));
this.log('\nAfter adding the lines, run:');
this.log(` ${getSourceCommand(shellConfig)}`);
this.log('\nThen run this generator again.');
this.log('\n' + '='.repeat(80) + '\n');
process.exit(1);
}
} else {
this.log('\nâ ď¸ Android SDK configuration skipped.');
this.log('Please configure the environment variables manually and run this command again.');
this.log('\n' + '='.repeat(80) + '\n');
process.exit(1);
}
}
}
} catch (error) {
this.log('\nâ Error checking Android SDK:');
this.log(error.message);
process.exit(1);
}
}
async prompting() {
// Placeholder for future prompts
this.log('\nđ§ Android generator is under development');
this.log('More features will be added soon!');
}
async install() {
this.log('\n' + '='.repeat(80));
this.log('đ ď¸ Setting up Android project');
this.log('='.repeat(80));
// Store the original directory
const originalDir = process.cwd();
const frontendDir = path.join(originalDir, 'frontend');
try {
// Check if frontend directory exists
if (!fs.existsSync(frontendDir)) {
throw new Error('Frontend directory not found. Please run this command from the root of your Rapid Stack project.');
}
// Change to frontend directory
process.chdir(frontendDir);
this.log(`\nđ Working in: ${frontendDir}`);
// Remove existing android directory
this.log('\nđď¸ Removing existing Android directory...');
execSync('rm -rf android', { stdio: 'inherit' });
this.log('â Android directory removed');
// Add Android platform
this.log('\nđą Adding Android platform...');
execSync('npx cap add android', { stdio: 'inherit' });
this.log('â Android platform added');
// Build the project
this.log('\nđď¸ Building project...');
execSync('npm run build', { stdio: 'inherit' });
this.log('â Project built successfully');
// Sync Android project
this.log('\nđ Syncing Android project...');
execSync('npx cap sync android', { stdio: 'inherit' });
this.log('â Android project synced');
// Return to original directory
process.chdir(originalDir);
this.log('\n' + '='.repeat(80));
this.log('đ Android setup completed successfully!');
this.log('='.repeat(80));
// Ask if user wants to open the project in Android Studio
const openAnswer = await this.prompt([
{
type: 'confirm',
name: 'openAndroidStudio',
message: 'Would you like to open the project in Android Studio now?',
default: true
}
]);
if (openAnswer.openAndroidStudio) {
await this._openAndroidStudioProject(frontendDir);
} else {
this.log('\nNext steps:');
this.log('\n1. Configure your signing certificates in Android Studio');
this.log('2. Build and run your app');
}
this.log('\n' + '='.repeat(80) + '\n');
} catch (error) {
// Ensure we return to original directory even if there's an error
process.chdir(originalDir);
this.log('\n' + '='.repeat(80));
this.log('â Error setting up Android project:');
this.log('='.repeat(80));
this.log('\nError details:');
this.log(error.message);
this.log('\nPlease check the error above and try again.');
this.log('\n' + '='.repeat(80) + '\n');
process.exit(1);
}
}
async _openAndroidStudioProject(frontendDir) {
try {
this.log('\nđ Opening project in Android Studio...');
process.chdir(frontendDir);
execSync('npx cap open android', { stdio: 'inherit' });
this.log('â Project opened in Android Studio');
} catch (error) {
this.log('\nâ ď¸ Could not open project in Android Studio:');
this.log(error.message);
this.log('\nYou can try opening it manually with:');
this.log(' npx cap open android');
}
}
};