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,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Executor Utility
|
|
3
|
+
* Executes system commands with proper error handling and logging
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { spawn, execSync } = require('child_process');
|
|
7
|
+
const logger = require('./logger');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Execute a command synchronously
|
|
11
|
+
* @param {string} command - Command to execute
|
|
12
|
+
* @param {Object} options - Execution options
|
|
13
|
+
* @returns {Object} Result with success status and output
|
|
14
|
+
*/
|
|
15
|
+
function execCommand(command, options = {}) {
|
|
16
|
+
const {
|
|
17
|
+
silent = false,
|
|
18
|
+
showCommand = true,
|
|
19
|
+
throwOnError = false,
|
|
20
|
+
cwd = process.cwd()
|
|
21
|
+
} = options;
|
|
22
|
+
|
|
23
|
+
if (showCommand && !silent) {
|
|
24
|
+
logger.command(command);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const output = execSync(command, {
|
|
29
|
+
encoding: 'utf8',
|
|
30
|
+
stdio: silent ? 'pipe' : 'inherit',
|
|
31
|
+
cwd,
|
|
32
|
+
shell: true
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
success: true,
|
|
37
|
+
output: output ? output.trim() : '',
|
|
38
|
+
code: 0
|
|
39
|
+
};
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (throwOnError) {
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
success: false,
|
|
47
|
+
output: error.message,
|
|
48
|
+
code: error.status || 1,
|
|
49
|
+
error
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Execute a command and capture output silently
|
|
56
|
+
* @param {string} command - Command to execute
|
|
57
|
+
* @returns {Object} Result with output
|
|
58
|
+
*/
|
|
59
|
+
function execSilent(command) {
|
|
60
|
+
try {
|
|
61
|
+
const output = execSync(command, {
|
|
62
|
+
encoding: 'utf8',
|
|
63
|
+
stdio: 'pipe',
|
|
64
|
+
shell: true
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
success: true,
|
|
68
|
+
output: output ? output.trim() : ''
|
|
69
|
+
};
|
|
70
|
+
} catch (error) {
|
|
71
|
+
return {
|
|
72
|
+
success: false,
|
|
73
|
+
output: error.message,
|
|
74
|
+
error
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Execute a command asynchronously with streaming output
|
|
81
|
+
* @param {string} command - Command to execute
|
|
82
|
+
* @param {Array} args - Command arguments
|
|
83
|
+
* @param {Object} options - Execution options
|
|
84
|
+
* @returns {Promise} Resolves when command completes
|
|
85
|
+
*/
|
|
86
|
+
function execAsync(command, args = [], options = {}) {
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
const { showCommand = true, cwd = process.cwd() } = options;
|
|
89
|
+
|
|
90
|
+
const fullCommand = args.length > 0 ? `${command} ${args.join(' ')}` : command;
|
|
91
|
+
|
|
92
|
+
if (showCommand) {
|
|
93
|
+
logger.command(fullCommand);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const child = spawn(command, args, {
|
|
97
|
+
cwd,
|
|
98
|
+
shell: true,
|
|
99
|
+
stdio: 'inherit'
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
child.on('close', (code) => {
|
|
103
|
+
if (code === 0) {
|
|
104
|
+
resolve({ success: true, code });
|
|
105
|
+
} else {
|
|
106
|
+
resolve({ success: false, code });
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
child.on('error', (error) => {
|
|
111
|
+
reject(error);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Check if a command exists
|
|
118
|
+
* @param {string} command - Command to check
|
|
119
|
+
* @returns {boolean} True if command exists
|
|
120
|
+
*/
|
|
121
|
+
function commandExists(command) {
|
|
122
|
+
try {
|
|
123
|
+
const checkCmd =
|
|
124
|
+
process.platform === 'win32' ? `where ${command}` : `which ${command}`;
|
|
125
|
+
|
|
126
|
+
execSync(checkCmd, { stdio: 'pipe' });
|
|
127
|
+
return true;
|
|
128
|
+
} catch {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get command version
|
|
135
|
+
* @param {string} command - Command to check
|
|
136
|
+
* @param {string} versionFlag - Version flag (default: --version)
|
|
137
|
+
* @returns {string|null} Version string or null
|
|
138
|
+
*/
|
|
139
|
+
function getVersion(command, versionFlag = '--version') {
|
|
140
|
+
try {
|
|
141
|
+
const output = execSync(`${command} ${versionFlag}`, {
|
|
142
|
+
encoding: 'utf8',
|
|
143
|
+
stdio: 'pipe'
|
|
144
|
+
});
|
|
145
|
+
// Extract version number from output
|
|
146
|
+
const versionMatch = output.match(/(\d+\.\d+\.?\d*)/);
|
|
147
|
+
return versionMatch ? versionMatch[1] : output.trim().split('\n')[0];
|
|
148
|
+
} catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Run multiple commands in sequence
|
|
155
|
+
* @param {Array} commands - Array of command strings
|
|
156
|
+
* @param {Object} options - Execution options
|
|
157
|
+
* @returns {Object} Result with success status
|
|
158
|
+
*/
|
|
159
|
+
function execSequence(commands, options = {}) {
|
|
160
|
+
const results = [];
|
|
161
|
+
|
|
162
|
+
for (const cmd of commands) {
|
|
163
|
+
const result = execCommand(cmd, options);
|
|
164
|
+
results.push(result);
|
|
165
|
+
|
|
166
|
+
if (!result.success && !options.continueOnError) {
|
|
167
|
+
return {
|
|
168
|
+
success: false,
|
|
169
|
+
results,
|
|
170
|
+
failedAt: cmd
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
success: results.every((r) => r.success),
|
|
177
|
+
results
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Execute a command with sudo/admin privileges
|
|
183
|
+
* @param {string} command - Command to execute
|
|
184
|
+
* @param {Object} options - Execution options
|
|
185
|
+
* @returns {Object} Result
|
|
186
|
+
*/
|
|
187
|
+
function execWithPrivileges(command, options = {}) {
|
|
188
|
+
const platform = process.platform;
|
|
189
|
+
|
|
190
|
+
if (platform === 'win32') {
|
|
191
|
+
// Windows: Command should already be running as admin
|
|
192
|
+
logger.warn('Windows requires running the terminal as Administrator');
|
|
193
|
+
return execCommand(command, options);
|
|
194
|
+
} else {
|
|
195
|
+
// Unix: Use sudo
|
|
196
|
+
return execCommand(`sudo ${command}`, options);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Execute platform-specific command
|
|
202
|
+
* @param {Object} commands - Object with darwin, linux, win32 keys
|
|
203
|
+
* @param {Object} options - Execution options
|
|
204
|
+
* @returns {Object} Result
|
|
205
|
+
*/
|
|
206
|
+
function execPlatformCommand(commands, options = {}) {
|
|
207
|
+
const platform = process.platform;
|
|
208
|
+
const command = commands[platform];
|
|
209
|
+
|
|
210
|
+
if (!command) {
|
|
211
|
+
logger.error(`No command defined for platform: ${platform}`);
|
|
212
|
+
return { success: false, output: 'Platform not supported' };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return execCommand(command, options);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
module.exports = {
|
|
219
|
+
execCommand,
|
|
220
|
+
execSilent,
|
|
221
|
+
execAsync,
|
|
222
|
+
commandExists,
|
|
223
|
+
getVersion,
|
|
224
|
+
execSequence,
|
|
225
|
+
execWithPrivileges,
|
|
226
|
+
execPlatformCommand
|
|
227
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities Index
|
|
3
|
+
* Central export for all utility modules
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const logger = require('./logger');
|
|
7
|
+
const executor = require('./executor');
|
|
8
|
+
const prompts = require('./prompts');
|
|
9
|
+
const verifier = require('./verifier');
|
|
10
|
+
const postinstall = require('./postinstall');
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
logger,
|
|
14
|
+
executor,
|
|
15
|
+
prompts,
|
|
16
|
+
verifier,
|
|
17
|
+
postinstall
|
|
18
|
+
};
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger Utility
|
|
3
|
+
* Provides consistent, colorful console output
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const boxen = require('boxen');
|
|
8
|
+
|
|
9
|
+
const ICONS = {
|
|
10
|
+
success: '✓',
|
|
11
|
+
error: '✗',
|
|
12
|
+
warning: '⚠',
|
|
13
|
+
info: 'ℹ',
|
|
14
|
+
arrow: '→',
|
|
15
|
+
bullet: '•',
|
|
16
|
+
check: '✔',
|
|
17
|
+
cross: '✘',
|
|
18
|
+
star: '★',
|
|
19
|
+
rocket: '🚀',
|
|
20
|
+
wrench: '🔧',
|
|
21
|
+
package: '📦',
|
|
22
|
+
computer: '💻',
|
|
23
|
+
folder: '📁'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Log an info message
|
|
28
|
+
* @param {string} message
|
|
29
|
+
*/
|
|
30
|
+
function info(message) {
|
|
31
|
+
console.log(chalk.blue(`${ICONS.info} ${message}`));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Log a success message
|
|
36
|
+
* @param {string} message
|
|
37
|
+
*/
|
|
38
|
+
function success(message) {
|
|
39
|
+
console.log(chalk.green(`${ICONS.success} ${message}`));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Log an error message
|
|
44
|
+
* @param {string} message
|
|
45
|
+
*/
|
|
46
|
+
function error(message) {
|
|
47
|
+
console.log(chalk.red(`${ICONS.error} ${message}`));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Log a warning message
|
|
52
|
+
* @param {string} message
|
|
53
|
+
*/
|
|
54
|
+
function warn(message) {
|
|
55
|
+
console.log(chalk.yellow(`${ICONS.warning} ${message}`));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Log a step in a process
|
|
60
|
+
* @param {string} message
|
|
61
|
+
*/
|
|
62
|
+
function step(message) {
|
|
63
|
+
console.log(chalk.cyan(`${ICONS.arrow} ${message}`));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Log a command that will be executed
|
|
68
|
+
* @param {string} command
|
|
69
|
+
*/
|
|
70
|
+
function command(cmd) {
|
|
71
|
+
console.log(chalk.gray(` $ ${cmd}`));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Log a section header
|
|
76
|
+
* @param {string} title
|
|
77
|
+
*/
|
|
78
|
+
function section(title) {
|
|
79
|
+
console.log('');
|
|
80
|
+
console.log(chalk.bold.underline(title));
|
|
81
|
+
console.log('');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Log a subsection
|
|
86
|
+
* @param {string} title
|
|
87
|
+
*/
|
|
88
|
+
function subsection(title) {
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log(chalk.bold(` ${title}`));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Log a list item
|
|
95
|
+
* @param {string} message
|
|
96
|
+
* @param {number} indent
|
|
97
|
+
*/
|
|
98
|
+
function listItem(message, indent = 2) {
|
|
99
|
+
const spaces = ' '.repeat(indent);
|
|
100
|
+
console.log(`${spaces}${ICONS.bullet} ${message}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Display a banner/box
|
|
105
|
+
* @param {string} title
|
|
106
|
+
* @param {string} subtitle
|
|
107
|
+
*/
|
|
108
|
+
function banner(title, subtitle = '') {
|
|
109
|
+
const content = subtitle ? `${title}\n${chalk.gray(subtitle)}` : title;
|
|
110
|
+
console.log(
|
|
111
|
+
boxen(content, {
|
|
112
|
+
padding: 1,
|
|
113
|
+
margin: 1,
|
|
114
|
+
borderStyle: 'round',
|
|
115
|
+
borderColor: 'cyan'
|
|
116
|
+
})
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Display platform information
|
|
122
|
+
* @param {Object} platformInfo
|
|
123
|
+
*/
|
|
124
|
+
function displayPlatformInfo(platformInfo) {
|
|
125
|
+
console.log('');
|
|
126
|
+
console.log(
|
|
127
|
+
boxen(
|
|
128
|
+
chalk.bold('System Information\n\n') +
|
|
129
|
+
`${ICONS.computer} OS: ${chalk.cyan(platformInfo.os.name)} (${platformInfo.os.platform})\n` +
|
|
130
|
+
`${ICONS.wrench} Architecture: ${chalk.cyan(platformInfo.architecture.display)}\n` +
|
|
131
|
+
` CPU: ${platformInfo.architecture.cpuModel}\n` +
|
|
132
|
+
` Cores: ${platformInfo.architecture.cores}\n` +
|
|
133
|
+
`${ICONS.folder} Shell: ${chalk.cyan(platformInfo.shell.name)}\n` +
|
|
134
|
+
` Config: ${platformInfo.shell.configFile}\n` +
|
|
135
|
+
`${ICONS.package} Package Manager: ${chalk.cyan(platformInfo.os.packageManager || 'Not detected')}\n` +
|
|
136
|
+
` Node.js: ${platformInfo.nodeVersion}\n` +
|
|
137
|
+
` User: ${platformInfo.username}@${platformInfo.hostname}`,
|
|
138
|
+
{
|
|
139
|
+
padding: 1,
|
|
140
|
+
borderStyle: 'round',
|
|
141
|
+
borderColor: 'green'
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
);
|
|
145
|
+
console.log('');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Display installation summary
|
|
150
|
+
* @param {Array} installed
|
|
151
|
+
* @param {Array} skipped
|
|
152
|
+
* @param {Array} failed
|
|
153
|
+
*/
|
|
154
|
+
function displaySummary(installed, skipped, failed) {
|
|
155
|
+
console.log('');
|
|
156
|
+
console.log(
|
|
157
|
+
boxen(
|
|
158
|
+
chalk.bold('Installation Summary\n\n') +
|
|
159
|
+
chalk.green.bold(`Installed (${installed.length}):\n`) +
|
|
160
|
+
(installed.length > 0
|
|
161
|
+
? installed.map((item) => ` ${ICONS.check} ${item}`).join('\n')
|
|
162
|
+
: ` ${chalk.gray('None')}`) +
|
|
163
|
+
'\n\n' +
|
|
164
|
+
chalk.yellow.bold(`Skipped (${skipped.length}):\n`) +
|
|
165
|
+
(skipped.length > 0
|
|
166
|
+
? skipped.map((item) => ` ${ICONS.arrow} ${item}`).join('\n')
|
|
167
|
+
: ` ${chalk.gray('None')}`) +
|
|
168
|
+
'\n\n' +
|
|
169
|
+
chalk.red.bold(`Failed (${failed.length}):\n`) +
|
|
170
|
+
(failed.length > 0
|
|
171
|
+
? failed.map((item) => ` ${ICONS.cross} ${item}`).join('\n')
|
|
172
|
+
: ` ${chalk.gray('None')}`),
|
|
173
|
+
{
|
|
174
|
+
padding: 1,
|
|
175
|
+
borderStyle: 'round',
|
|
176
|
+
borderColor: failed.length > 0 ? 'red' : 'green'
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
);
|
|
180
|
+
console.log('');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Display success completion message
|
|
185
|
+
*/
|
|
186
|
+
function complete() {
|
|
187
|
+
console.log('');
|
|
188
|
+
console.log(
|
|
189
|
+
boxen(
|
|
190
|
+
chalk.green.bold(`${ICONS.rocket} Setup Complete!\n\n`) +
|
|
191
|
+
chalk.white('Your development environment is ready.\n') +
|
|
192
|
+
chalk.gray('You may need to restart your terminal for all changes to take effect.'),
|
|
193
|
+
{
|
|
194
|
+
padding: 1,
|
|
195
|
+
borderStyle: 'double',
|
|
196
|
+
borderColor: 'green'
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
);
|
|
200
|
+
console.log('');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Create a newline
|
|
205
|
+
*/
|
|
206
|
+
function newline() {
|
|
207
|
+
console.log('');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Display a divider
|
|
212
|
+
*/
|
|
213
|
+
function divider() {
|
|
214
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
module.exports = {
|
|
218
|
+
info,
|
|
219
|
+
success,
|
|
220
|
+
error,
|
|
221
|
+
warn,
|
|
222
|
+
step,
|
|
223
|
+
command,
|
|
224
|
+
section,
|
|
225
|
+
subsection,
|
|
226
|
+
listItem,
|
|
227
|
+
banner,
|
|
228
|
+
displayPlatformInfo,
|
|
229
|
+
displaySummary,
|
|
230
|
+
complete,
|
|
231
|
+
newline,
|
|
232
|
+
divider,
|
|
233
|
+
ICONS,
|
|
234
|
+
chalk
|
|
235
|
+
};
|