auto-dev-setup 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +191 -0
- package/bin/auto-setup.js +13 -0
- package/package.json +58 -0
- package/src/cli.js +295 -0
- package/src/config/extensions.js +51 -0
- package/src/index.js +16 -0
- package/src/platform/detector.js +240 -0
- package/src/platform/index.js +36 -0
- package/src/platform/linux.js +412 -0
- package/src/platform/macos.js +348 -0
- package/src/platform/windows.js +334 -0
- package/src/stacks/base.js +47 -0
- package/src/stacks/index.js +16 -0
- package/src/stacks/java.js +232 -0
- package/src/stacks/python.js +433 -0
- package/src/stacks/web.js +208 -0
- package/src/utils/executor.js +227 -0
- package/src/utils/index.js +18 -0
- package/src/utils/logger.js +235 -0
- package/src/utils/postinstall.js +295 -0
- package/src/utils/prompts.js +168 -0
- package/src/utils/verifier.js +204 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform Detection Module
|
|
3
|
+
* Detects OS, CPU architecture, and default shell
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Detect the operating system
|
|
11
|
+
* @returns {Object} OS information
|
|
12
|
+
*/
|
|
13
|
+
function detectOS() {
|
|
14
|
+
const platform = process.platform;
|
|
15
|
+
|
|
16
|
+
const osMap = {
|
|
17
|
+
darwin: {
|
|
18
|
+
name: 'macOS',
|
|
19
|
+
platform: 'darwin',
|
|
20
|
+
packageManager: 'brew',
|
|
21
|
+
icon: '🍎'
|
|
22
|
+
},
|
|
23
|
+
linux: {
|
|
24
|
+
name: 'Linux',
|
|
25
|
+
platform: 'linux',
|
|
26
|
+
packageManager: detectLinuxPackageManager(),
|
|
27
|
+
distro: detectLinuxDistro(),
|
|
28
|
+
icon: '🐧'
|
|
29
|
+
},
|
|
30
|
+
win32: {
|
|
31
|
+
name: 'Windows',
|
|
32
|
+
platform: 'win32',
|
|
33
|
+
packageManager: detectWindowsPackageManager(),
|
|
34
|
+
icon: '🪟'
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return osMap[platform] || {
|
|
39
|
+
name: 'Unknown',
|
|
40
|
+
platform: platform,
|
|
41
|
+
packageManager: null,
|
|
42
|
+
icon: '❓'
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Detect Linux distribution
|
|
48
|
+
* @returns {string} Distribution name
|
|
49
|
+
*/
|
|
50
|
+
function detectLinuxDistro() {
|
|
51
|
+
if (process.platform !== 'linux') return null;
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// Try to read /etc/os-release
|
|
55
|
+
const osRelease = require('fs').readFileSync('/etc/os-release', 'utf8');
|
|
56
|
+
const idMatch = osRelease.match(/^ID=(.*)$/m);
|
|
57
|
+
if (idMatch) {
|
|
58
|
+
return idMatch[1].replace(/"/g, '').toLowerCase();
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
// Fallback to checking package managers
|
|
62
|
+
try {
|
|
63
|
+
execSync('which apt', { stdio: 'pipe' });
|
|
64
|
+
return 'debian';
|
|
65
|
+
} catch {
|
|
66
|
+
try {
|
|
67
|
+
execSync('which dnf', { stdio: 'pipe' });
|
|
68
|
+
return 'fedora';
|
|
69
|
+
} catch {
|
|
70
|
+
try {
|
|
71
|
+
execSync('which pacman', { stdio: 'pipe' });
|
|
72
|
+
return 'arch';
|
|
73
|
+
} catch {
|
|
74
|
+
return 'unknown';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return 'unknown';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Detect Linux package manager
|
|
84
|
+
* @returns {string} Package manager command
|
|
85
|
+
*/
|
|
86
|
+
function detectLinuxPackageManager() {
|
|
87
|
+
if (process.platform !== 'linux') return null;
|
|
88
|
+
|
|
89
|
+
const managers = [
|
|
90
|
+
{ cmd: 'apt', name: 'apt' },
|
|
91
|
+
{ cmd: 'dnf', name: 'dnf' },
|
|
92
|
+
{ cmd: 'yum', name: 'yum' },
|
|
93
|
+
{ cmd: 'pacman', name: 'pacman' },
|
|
94
|
+
{ cmd: 'zypper', name: 'zypper' },
|
|
95
|
+
{ cmd: 'apk', name: 'apk' }
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
for (const manager of managers) {
|
|
99
|
+
try {
|
|
100
|
+
execSync(`which ${manager.cmd}`, { stdio: 'pipe' });
|
|
101
|
+
return manager.name;
|
|
102
|
+
} catch {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Detect Windows package manager
|
|
111
|
+
* @returns {string} Package manager command
|
|
112
|
+
*/
|
|
113
|
+
function detectWindowsPackageManager() {
|
|
114
|
+
if (process.platform !== 'win32') return null;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
execSync('winget --version', { stdio: 'pipe' });
|
|
118
|
+
return 'winget';
|
|
119
|
+
} catch {
|
|
120
|
+
try {
|
|
121
|
+
execSync('choco --version', { stdio: 'pipe' });
|
|
122
|
+
return 'choco';
|
|
123
|
+
} catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Detect CPU architecture
|
|
131
|
+
* @returns {Object} Architecture information
|
|
132
|
+
*/
|
|
133
|
+
function detectArchitecture() {
|
|
134
|
+
const arch = process.arch;
|
|
135
|
+
const cpus = os.cpus();
|
|
136
|
+
|
|
137
|
+
const archMap = {
|
|
138
|
+
x64: 'x86_64 (64-bit)',
|
|
139
|
+
arm64: 'ARM64 (Apple Silicon / ARM)',
|
|
140
|
+
arm: 'ARM (32-bit)',
|
|
141
|
+
ia32: 'x86 (32-bit)'
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
arch: arch,
|
|
146
|
+
display: archMap[arch] || arch,
|
|
147
|
+
cpuModel: cpus.length > 0 ? cpus[0].model : 'Unknown',
|
|
148
|
+
cores: cpus.length
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Detect default shell
|
|
154
|
+
* @returns {Object} Shell information
|
|
155
|
+
*/
|
|
156
|
+
function detectShell() {
|
|
157
|
+
const platform = process.platform;
|
|
158
|
+
let shell = process.env.SHELL || '';
|
|
159
|
+
let configFile = '';
|
|
160
|
+
|
|
161
|
+
if (platform === 'win32') {
|
|
162
|
+
// Windows shell detection
|
|
163
|
+
if (process.env.PSModulePath) {
|
|
164
|
+
shell = 'powershell';
|
|
165
|
+
configFile = '$PROFILE';
|
|
166
|
+
} else {
|
|
167
|
+
shell = 'cmd';
|
|
168
|
+
configFile = 'N/A';
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
// Unix-like shell detection
|
|
172
|
+
const shellName = shell.split('/').pop();
|
|
173
|
+
|
|
174
|
+
const configFiles = {
|
|
175
|
+
zsh: '~/.zshrc',
|
|
176
|
+
bash: '~/.bashrc',
|
|
177
|
+
fish: '~/.config/fish/config.fish',
|
|
178
|
+
sh: '~/.profile'
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
configFile = configFiles[shellName] || '~/.profile';
|
|
182
|
+
shell = shellName;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
name: shell,
|
|
187
|
+
path: process.env.SHELL || 'N/A',
|
|
188
|
+
configFile: configFile
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Check if running with elevated privileges
|
|
194
|
+
* @returns {boolean} True if admin/root
|
|
195
|
+
*/
|
|
196
|
+
function isElevated() {
|
|
197
|
+
if (process.platform === 'win32') {
|
|
198
|
+
try {
|
|
199
|
+
execSync('net session', { stdio: 'pipe' });
|
|
200
|
+
return true;
|
|
201
|
+
} catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
return process.getuid && process.getuid() === 0;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Get complete platform information
|
|
211
|
+
* @returns {Object} Complete platform details
|
|
212
|
+
*/
|
|
213
|
+
function getPlatformInfo() {
|
|
214
|
+
const osInfo = detectOS();
|
|
215
|
+
const archInfo = detectArchitecture();
|
|
216
|
+
const shellInfo = detectShell();
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
os: osInfo,
|
|
220
|
+
architecture: archInfo,
|
|
221
|
+
shell: shellInfo,
|
|
222
|
+
hostname: os.hostname(),
|
|
223
|
+
username: os.userInfo().username,
|
|
224
|
+
homedir: os.homedir(),
|
|
225
|
+
isElevated: isElevated(),
|
|
226
|
+
nodeVersion: process.version,
|
|
227
|
+
platform: process.platform
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
module.exports = {
|
|
232
|
+
detectOS,
|
|
233
|
+
detectArchitecture,
|
|
234
|
+
detectShell,
|
|
235
|
+
detectLinuxDistro,
|
|
236
|
+
detectLinuxPackageManager,
|
|
237
|
+
detectWindowsPackageManager,
|
|
238
|
+
isElevated,
|
|
239
|
+
getPlatformInfo
|
|
240
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform Index
|
|
3
|
+
* Central export for platform modules
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const detector = require('./detector');
|
|
7
|
+
const macos = require('./macos');
|
|
8
|
+
const linux = require('./linux');
|
|
9
|
+
const windows = require('./windows');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get the appropriate platform module
|
|
13
|
+
* @returns {Object} Platform-specific module
|
|
14
|
+
*/
|
|
15
|
+
function getPlatformModule() {
|
|
16
|
+
const platform = process.platform;
|
|
17
|
+
|
|
18
|
+
switch (platform) {
|
|
19
|
+
case 'darwin':
|
|
20
|
+
return macos;
|
|
21
|
+
case 'linux':
|
|
22
|
+
return linux;
|
|
23
|
+
case 'win32':
|
|
24
|
+
return windows;
|
|
25
|
+
default:
|
|
26
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
detector,
|
|
32
|
+
macos,
|
|
33
|
+
linux,
|
|
34
|
+
windows,
|
|
35
|
+
getPlatformModule
|
|
36
|
+
};
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linux Platform Installer
|
|
3
|
+
* Handles Linux-specific installations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { execCommand, execSilent, commandExists } = require('../utils/executor');
|
|
7
|
+
const logger = require('../utils/logger');
|
|
8
|
+
const { detectLinuxDistro, detectLinuxPackageManager } = require('./detector');
|
|
9
|
+
const ora = require('ora');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get the appropriate install command for the detected package manager
|
|
13
|
+
* @param {string} packageManager - Package manager name
|
|
14
|
+
* @param {string} packageName - Package to install
|
|
15
|
+
* @returns {string} Install command
|
|
16
|
+
*/
|
|
17
|
+
function getInstallCommand(packageManager, packageName) {
|
|
18
|
+
const commands = {
|
|
19
|
+
apt: `sudo apt-get install -y ${packageName}`,
|
|
20
|
+
dnf: `sudo dnf install -y ${packageName}`,
|
|
21
|
+
yum: `sudo yum install -y ${packageName}`,
|
|
22
|
+
pacman: `sudo pacman -S --noconfirm ${packageName}`,
|
|
23
|
+
zypper: `sudo zypper install -y ${packageName}`,
|
|
24
|
+
apk: `sudo apk add ${packageName}`
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return commands[packageManager] || null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get package name mapping for different distros
|
|
32
|
+
* @param {string} packageManager - Package manager
|
|
33
|
+
* @param {string} genericName - Generic package name
|
|
34
|
+
* @returns {string} Distro-specific package name
|
|
35
|
+
*/
|
|
36
|
+
function getPackageName(packageManager, genericName) {
|
|
37
|
+
const packageMap = {
|
|
38
|
+
nodejs: {
|
|
39
|
+
apt: 'nodejs',
|
|
40
|
+
dnf: 'nodejs',
|
|
41
|
+
pacman: 'nodejs',
|
|
42
|
+
zypper: 'nodejs',
|
|
43
|
+
apk: 'nodejs'
|
|
44
|
+
},
|
|
45
|
+
npm: {
|
|
46
|
+
apt: 'npm',
|
|
47
|
+
dnf: 'npm',
|
|
48
|
+
pacman: 'npm',
|
|
49
|
+
zypper: 'npm',
|
|
50
|
+
apk: 'npm'
|
|
51
|
+
},
|
|
52
|
+
python: {
|
|
53
|
+
apt: 'python3',
|
|
54
|
+
dnf: 'python3',
|
|
55
|
+
pacman: 'python',
|
|
56
|
+
zypper: 'python3',
|
|
57
|
+
apk: 'python3'
|
|
58
|
+
},
|
|
59
|
+
pip: {
|
|
60
|
+
apt: 'python3-pip',
|
|
61
|
+
dnf: 'python3-pip',
|
|
62
|
+
pacman: 'python-pip',
|
|
63
|
+
zypper: 'python3-pip',
|
|
64
|
+
apk: 'py3-pip'
|
|
65
|
+
},
|
|
66
|
+
java: {
|
|
67
|
+
apt: 'openjdk-17-jdk',
|
|
68
|
+
dnf: 'java-17-openjdk-devel',
|
|
69
|
+
pacman: 'jdk-openjdk',
|
|
70
|
+
zypper: 'java-17-openjdk-devel',
|
|
71
|
+
apk: 'openjdk17'
|
|
72
|
+
},
|
|
73
|
+
vscode: {
|
|
74
|
+
apt: 'code',
|
|
75
|
+
dnf: 'code',
|
|
76
|
+
pacman: 'code',
|
|
77
|
+
zypper: 'code',
|
|
78
|
+
apk: 'code'
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return packageMap[genericName]?.[packageManager] || genericName;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Update package manager cache
|
|
87
|
+
* @param {string} packageManager - Package manager
|
|
88
|
+
* @returns {Object} Result
|
|
89
|
+
*/
|
|
90
|
+
async function updatePackageCache(packageManager) {
|
|
91
|
+
logger.step('Updating package cache...');
|
|
92
|
+
|
|
93
|
+
const commands = {
|
|
94
|
+
apt: 'sudo apt-get update',
|
|
95
|
+
dnf: 'sudo dnf check-update || true',
|
|
96
|
+
yum: 'sudo yum check-update || true',
|
|
97
|
+
pacman: 'sudo pacman -Sy',
|
|
98
|
+
zypper: 'sudo zypper refresh',
|
|
99
|
+
apk: 'sudo apk update'
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const command = commands[packageManager];
|
|
103
|
+
if (!command) {
|
|
104
|
+
logger.warn(`Unknown package manager: ${packageManager}`);
|
|
105
|
+
return { success: false };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const result = execCommand(command, { silent: true });
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Install a package using the system package manager
|
|
114
|
+
* @param {string} packageName - Package to install
|
|
115
|
+
* @param {string} displayName - Display name for logging
|
|
116
|
+
* @returns {Object} Installation result
|
|
117
|
+
*/
|
|
118
|
+
async function installPackage(packageName, displayName = null) {
|
|
119
|
+
const name = displayName || packageName;
|
|
120
|
+
const packageManager = detectLinuxPackageManager();
|
|
121
|
+
|
|
122
|
+
if (!packageManager) {
|
|
123
|
+
logger.error('No supported package manager found');
|
|
124
|
+
return { success: false, skipped: false };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
logger.step(`Checking ${name}...`);
|
|
128
|
+
|
|
129
|
+
// Check if already installed
|
|
130
|
+
if (commandExists(packageName)) {
|
|
131
|
+
logger.success(`${name} already installed`);
|
|
132
|
+
return { success: true, skipped: true };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const distroPackage = getPackageName(packageManager, packageName);
|
|
136
|
+
const command = getInstallCommand(packageManager, distroPackage);
|
|
137
|
+
|
|
138
|
+
if (!command) {
|
|
139
|
+
logger.error(`Unsupported package manager: ${packageManager}`);
|
|
140
|
+
return { success: false, skipped: false };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
logger.step(`Installing ${name}...`);
|
|
144
|
+
const result = execCommand(command);
|
|
145
|
+
|
|
146
|
+
if (result.success) {
|
|
147
|
+
logger.success(`${name} installed successfully`);
|
|
148
|
+
return { success: true, skipped: false };
|
|
149
|
+
} else {
|
|
150
|
+
logger.error(`Failed to install ${name}`);
|
|
151
|
+
return { success: false, skipped: false };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Install Git
|
|
157
|
+
*/
|
|
158
|
+
async function installGit() {
|
|
159
|
+
return installPackage('git', 'Git');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Install curl
|
|
164
|
+
*/
|
|
165
|
+
async function installCurl() {
|
|
166
|
+
return installPackage('curl', 'curl');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Install Node.js and npm
|
|
171
|
+
*/
|
|
172
|
+
async function installNode() {
|
|
173
|
+
const packageManager = detectLinuxPackageManager();
|
|
174
|
+
|
|
175
|
+
// For apt-based systems, use NodeSource repository for latest LTS
|
|
176
|
+
if (packageManager === 'apt') {
|
|
177
|
+
logger.step('Setting up NodeSource repository for Node.js LTS...');
|
|
178
|
+
|
|
179
|
+
// Check if Node.js is already installed
|
|
180
|
+
if (commandExists('node')) {
|
|
181
|
+
logger.success('Node.js already installed');
|
|
182
|
+
return { success: true, skipped: true };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Install curl first if needed
|
|
186
|
+
if (!commandExists('curl')) {
|
|
187
|
+
await installCurl();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Add NodeSource repository
|
|
191
|
+
const setupResult = execCommand(
|
|
192
|
+
'curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -'
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
if (!setupResult.success) {
|
|
196
|
+
logger.warn('Failed to set up NodeSource repository, using system Node.js');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return installPackage('nodejs', 'Node.js');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// For other package managers, install directly
|
|
203
|
+
const nodeResult = await installPackage('nodejs', 'Node.js');
|
|
204
|
+
const npmResult = await installPackage('npm', 'npm');
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
success: nodeResult.success && npmResult.success,
|
|
208
|
+
skipped: nodeResult.skipped && npmResult.skipped
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Install Visual Studio Code
|
|
214
|
+
*/
|
|
215
|
+
async function installVSCode() {
|
|
216
|
+
const packageManager = detectLinuxPackageManager();
|
|
217
|
+
|
|
218
|
+
logger.step('Checking Visual Studio Code...');
|
|
219
|
+
|
|
220
|
+
if (commandExists('code')) {
|
|
221
|
+
logger.success('Visual Studio Code already installed');
|
|
222
|
+
return { success: true, skipped: true };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
logger.step('Installing Visual Studio Code...');
|
|
226
|
+
|
|
227
|
+
if (packageManager === 'apt') {
|
|
228
|
+
// Add Microsoft repository for Debian/Ubuntu
|
|
229
|
+
execCommand(
|
|
230
|
+
'wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /tmp/packages.microsoft.gpg'
|
|
231
|
+
);
|
|
232
|
+
execCommand(
|
|
233
|
+
'sudo install -D -o root -g root -m 644 /tmp/packages.microsoft.gpg /etc/apt/keyrings/packages.microsoft.gpg'
|
|
234
|
+
);
|
|
235
|
+
execCommand(
|
|
236
|
+
'sudo sh -c \'echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list\''
|
|
237
|
+
);
|
|
238
|
+
execCommand('sudo apt-get update');
|
|
239
|
+
return installPackage('code', 'Visual Studio Code');
|
|
240
|
+
} else if (packageManager === 'dnf' || packageManager === 'yum') {
|
|
241
|
+
// Add Microsoft repository for Fedora/RHEL
|
|
242
|
+
execCommand('sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc');
|
|
243
|
+
execCommand(
|
|
244
|
+
'sudo sh -c \'echo -e "[code]\\nname=Visual Studio Code\\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\\nenabled=1\\ngpgcheck=1\\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/vscode.repo\''
|
|
245
|
+
);
|
|
246
|
+
return installPackage('code', 'Visual Studio Code');
|
|
247
|
+
} else if (packageManager === 'pacman') {
|
|
248
|
+
// For Arch, use yay or install from AUR
|
|
249
|
+
if (commandExists('yay')) {
|
|
250
|
+
const result = execCommand('yay -S --noconfirm visual-studio-code-bin');
|
|
251
|
+
if (result.success) {
|
|
252
|
+
logger.success('Visual Studio Code installed successfully');
|
|
253
|
+
return { success: true, skipped: false };
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
logger.warn(
|
|
257
|
+
'Please install Visual Studio Code from AUR: yay -S visual-studio-code-bin'
|
|
258
|
+
);
|
|
259
|
+
return { success: false, skipped: false };
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
logger.warn('Please install Visual Studio Code manually from https://code.visualstudio.com/');
|
|
263
|
+
return { success: false, skipped: false };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Enable VS Code CLI
|
|
268
|
+
*/
|
|
269
|
+
async function enableVSCodeCli() {
|
|
270
|
+
// On Linux, VS Code CLI should be available after installation
|
|
271
|
+
if (commandExists('code')) {
|
|
272
|
+
logger.success('VS Code CLI already available');
|
|
273
|
+
return { success: true, skipped: true };
|
|
274
|
+
}
|
|
275
|
+
return { success: false, skipped: false };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Install Python
|
|
280
|
+
*/
|
|
281
|
+
async function installPython() {
|
|
282
|
+
const pythonResult = await installPackage('python3', 'Python');
|
|
283
|
+
const pipResult = await installPackage('python3-pip', 'pip');
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
success: pythonResult.success && pipResult.success,
|
|
287
|
+
skipped: pythonResult.skipped && pipResult.skipped
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Install Java (OpenJDK)
|
|
293
|
+
*/
|
|
294
|
+
async function installJava() {
|
|
295
|
+
const packageManager = detectLinuxPackageManager();
|
|
296
|
+
const javaPackage = getPackageName(packageManager, 'java');
|
|
297
|
+
|
|
298
|
+
const result = await installPackage(javaPackage, 'OpenJDK');
|
|
299
|
+
|
|
300
|
+
if (result.success && !result.skipped) {
|
|
301
|
+
// Set JAVA_HOME
|
|
302
|
+
logger.step('Configuring JAVA_HOME...');
|
|
303
|
+
|
|
304
|
+
const javaPath = execSilent('dirname $(dirname $(readlink -f $(which java)))');
|
|
305
|
+
if (javaPath.success && javaPath.output) {
|
|
306
|
+
const shellConfig = process.env.SHELL?.includes('zsh')
|
|
307
|
+
? '~/.zshrc'
|
|
308
|
+
: '~/.bashrc';
|
|
309
|
+
execCommand(
|
|
310
|
+
`echo 'export JAVA_HOME="${javaPath.output}"' >> ${shellConfig}`
|
|
311
|
+
);
|
|
312
|
+
logger.success('JAVA_HOME configured');
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Install core build tools
|
|
321
|
+
*/
|
|
322
|
+
async function installBuildTools() {
|
|
323
|
+
const packageManager = detectLinuxPackageManager();
|
|
324
|
+
|
|
325
|
+
logger.step('Installing core build tools...');
|
|
326
|
+
|
|
327
|
+
const buildPackages = {
|
|
328
|
+
apt: 'build-essential',
|
|
329
|
+
dnf: '@development-tools',
|
|
330
|
+
pacman: 'base-devel',
|
|
331
|
+
zypper: '-t pattern devel_basis',
|
|
332
|
+
apk: 'build-base'
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const pkg = buildPackages[packageManager];
|
|
336
|
+
if (!pkg) return { success: true, skipped: true };
|
|
337
|
+
|
|
338
|
+
const command = getInstallCommand(packageManager, pkg);
|
|
339
|
+
const result = execCommand(command);
|
|
340
|
+
|
|
341
|
+
return result;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Run base system setup for Linux
|
|
346
|
+
*/
|
|
347
|
+
async function setupBase() {
|
|
348
|
+
const results = {
|
|
349
|
+
installed: [],
|
|
350
|
+
skipped: [],
|
|
351
|
+
failed: []
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const packageManager = detectLinuxPackageManager();
|
|
355
|
+
if (!packageManager) {
|
|
356
|
+
logger.error('No supported package manager detected');
|
|
357
|
+
return results;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
logger.info(`Detected package manager: ${packageManager}`);
|
|
361
|
+
|
|
362
|
+
// Update package cache
|
|
363
|
+
await updatePackageCache(packageManager);
|
|
364
|
+
|
|
365
|
+
// Install build tools
|
|
366
|
+
const buildResult = await installBuildTools();
|
|
367
|
+
if (buildResult.success) {
|
|
368
|
+
results.installed.push('Build Tools');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Install Git
|
|
372
|
+
const gitResult = await installGit();
|
|
373
|
+
if (gitResult.success) {
|
|
374
|
+
(gitResult.skipped ? results.skipped : results.installed).push('Git');
|
|
375
|
+
} else {
|
|
376
|
+
results.failed.push('Git');
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Install curl
|
|
380
|
+
const curlResult = await installCurl();
|
|
381
|
+
if (curlResult.success) {
|
|
382
|
+
(curlResult.skipped ? results.skipped : results.installed).push('curl');
|
|
383
|
+
} else {
|
|
384
|
+
results.failed.push('curl');
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Install wget
|
|
388
|
+
const wgetResult = await installPackage('wget', 'wget');
|
|
389
|
+
if (wgetResult.success) {
|
|
390
|
+
(wgetResult.skipped ? results.skipped : results.installed).push('wget');
|
|
391
|
+
} else {
|
|
392
|
+
results.failed.push('wget');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return results;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
module.exports = {
|
|
399
|
+
getInstallCommand,
|
|
400
|
+
getPackageName,
|
|
401
|
+
updatePackageCache,
|
|
402
|
+
installPackage,
|
|
403
|
+
installGit,
|
|
404
|
+
installCurl,
|
|
405
|
+
installNode,
|
|
406
|
+
installVSCode,
|
|
407
|
+
enableVSCodeCli,
|
|
408
|
+
installPython,
|
|
409
|
+
installJava,
|
|
410
|
+
installBuildTools,
|
|
411
|
+
setupBase
|
|
412
|
+
};
|