easy-devops 0.1.0 → 0.1.1
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/cli/managers/nginx-manager.js +84 -12
- package/install.ps1 +239 -130
- package/install.sh +85 -38
- package/package.json +1 -1
|
@@ -222,23 +222,95 @@ async function stopNginx(nginxDir) {
|
|
|
222
222
|
// ─── installNginx ─────────────────────────────────────────────────────────────
|
|
223
223
|
|
|
224
224
|
async function installNginx() {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (result.success) {
|
|
234
|
-
spinner.succeed('nginx installed successfully');
|
|
235
|
-
return { success: true, message: 'nginx installed successfully', output: result.stdout };
|
|
236
|
-
} else {
|
|
225
|
+
if (!isWindows) {
|
|
226
|
+
const spinner = ora('Installing nginx…').start();
|
|
227
|
+
const result = await run('sudo apt-get install -y nginx', { timeout: 120000 });
|
|
228
|
+
if (result.success) {
|
|
229
|
+
spinner.succeed('nginx installed successfully');
|
|
230
|
+
return { success: true, message: 'nginx installed successfully', output: result.stdout };
|
|
231
|
+
}
|
|
237
232
|
spinner.fail('Installation failed');
|
|
238
233
|
console.log(chalk.red(result.stderr || result.stdout));
|
|
239
234
|
console.log(chalk.gray('\n Manual instructions: https://nginx.org/en/docs/install.html\n'));
|
|
240
235
|
return { success: false, message: 'Installation failed', output: result.stderr || result.stdout };
|
|
241
236
|
}
|
|
237
|
+
|
|
238
|
+
// ── Windows ──────────────────────────────────────────────────────────────────
|
|
239
|
+
const spinner = ora('Checking for winget…').start();
|
|
240
|
+
|
|
241
|
+
// Try winget first (available on Windows 10/11 desktop; not on Windows Server by default)
|
|
242
|
+
const wingetCheck = await run('where.exe winget 2>$null');
|
|
243
|
+
const hasWinget = wingetCheck.success && wingetCheck.stdout.trim().length > 0;
|
|
244
|
+
|
|
245
|
+
if (hasWinget) {
|
|
246
|
+
spinner.text = 'Installing nginx via winget…';
|
|
247
|
+
const result = await run(
|
|
248
|
+
'winget install -e --id Nginx.Nginx --accept-package-agreements --accept-source-agreements',
|
|
249
|
+
{ timeout: 120000 },
|
|
250
|
+
);
|
|
251
|
+
if (result.success) {
|
|
252
|
+
spinner.succeed('nginx installed successfully');
|
|
253
|
+
return { success: true, message: 'nginx installed successfully', output: result.stdout };
|
|
254
|
+
}
|
|
255
|
+
spinner.fail('winget install failed');
|
|
256
|
+
console.log(chalk.red(result.stderr || result.stdout));
|
|
257
|
+
console.log(chalk.gray('\n Manual instructions: https://nginx.org/en/docs/install.html\n'));
|
|
258
|
+
return { success: false, message: 'Installation failed', output: result.stderr || result.stdout };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ── Fallback: direct download from nginx.org ─────────────────────────────────
|
|
262
|
+
spinner.text = 'Fetching latest nginx version…';
|
|
263
|
+
|
|
264
|
+
// Try to resolve the current stable version; fall back to a known-good release
|
|
265
|
+
const FALLBACK_VERSION = '1.26.3';
|
|
266
|
+
let nginxVersion = FALLBACK_VERSION;
|
|
267
|
+
|
|
268
|
+
const fetchVersionResult = await run(
|
|
269
|
+
`try { $p=(Invoke-WebRequest -Uri 'https://nginx.org/en/download.html' -UseBasicParsing -TimeoutSec 15).Content; if($p -match 'nginx-(\\d+\\.\\d+\\.\\d+)\\.zip'){$Matches[1]}else{''} } catch { '' }`,
|
|
270
|
+
{ timeout: 20000 },
|
|
271
|
+
);
|
|
272
|
+
const fetched = (fetchVersionResult.stdout || '').trim();
|
|
273
|
+
if (/^\d+\.\d+\.\d+$/.test(fetched)) nginxVersion = fetched;
|
|
274
|
+
|
|
275
|
+
const { nginxDir } = loadConfig();
|
|
276
|
+
const zipUrl = `https://nginx.org/download/nginx-${nginxVersion}.zip`;
|
|
277
|
+
|
|
278
|
+
spinner.text = `Downloading nginx ${nginxVersion}…`;
|
|
279
|
+
|
|
280
|
+
const downloadResult = await run(
|
|
281
|
+
`$ProgressPreference='SilentlyContinue'; Invoke-WebRequest -Uri '${zipUrl}' -OutFile "$env:TEMP\\nginx-${nginxVersion}.zip" -UseBasicParsing -TimeoutSec 120`,
|
|
282
|
+
{ timeout: 130000 },
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
if (!downloadResult.success) {
|
|
286
|
+
spinner.fail('Download failed');
|
|
287
|
+
console.log(chalk.red(downloadResult.stderr || downloadResult.stdout));
|
|
288
|
+
console.log(chalk.gray(`\n Download nginx manually from: https://nginx.org/en/download.html\n`));
|
|
289
|
+
return { success: false, message: 'Download failed', output: downloadResult.stderr || downloadResult.stdout };
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
spinner.text = 'Extracting nginx…';
|
|
293
|
+
|
|
294
|
+
const extractResult = await run(
|
|
295
|
+
`$ProgressPreference='SilentlyContinue'; $tmp="$env:TEMP\\nginx-extract-${nginxVersion}"; if(Test-Path $tmp){Remove-Item -Recurse -Force $tmp}; Expand-Archive -Path "$env:TEMP\\nginx-${nginxVersion}.zip" -DestinationPath $tmp -Force; $src=Join-Path $tmp 'nginx-${nginxVersion}'; if(-not(Test-Path '${nginxDir}')){New-Item -ItemType Directory -Force '${nginxDir}'|Out-Null}; Copy-Item -Path "$src\\*" -Destination '${nginxDir}' -Recurse -Force; Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue; Remove-Item -Force "$env:TEMP\\nginx-${nginxVersion}.zip" -ErrorAction SilentlyContinue`,
|
|
296
|
+
{ timeout: 60000 },
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
if (!extractResult.success) {
|
|
300
|
+
spinner.fail('Extraction failed');
|
|
301
|
+
console.log(chalk.red(extractResult.stderr || extractResult.stdout));
|
|
302
|
+
return { success: false, message: 'Extraction failed', output: extractResult.stderr || extractResult.stdout };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Verify nginx.exe is present
|
|
306
|
+
const verifyResult = await run(`Test-Path '${nginxDir}\\nginx.exe'`);
|
|
307
|
+
if (!verifyResult.success || !verifyResult.stdout.trim().toLowerCase().includes('true')) {
|
|
308
|
+
spinner.fail(`nginx.exe not found in ${nginxDir} after extraction`);
|
|
309
|
+
return { success: false, message: 'nginx.exe not found after extraction' };
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
spinner.succeed(`nginx ${nginxVersion} installed to ${nginxDir}`);
|
|
313
|
+
return { success: true, message: `nginx ${nginxVersion} installed successfully`, output: '' };
|
|
242
314
|
}
|
|
243
315
|
|
|
244
316
|
// ─── showNginxManager ─────────────────────────────────────────────────────────
|
package/install.ps1
CHANGED
|
@@ -63,8 +63,54 @@ function Write-Err { param([string]$msg) Write-Host " ERROR $msg" -Foreg
|
|
|
63
63
|
function Write-Info { param([string]$msg) Write-Host " $msg" -ForegroundColor Gray }
|
|
64
64
|
|
|
65
65
|
function Refresh-Path {
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
# Read NVM vars from User scope, fall back to Machine scope
|
|
67
|
+
# (nvm-windows writes to Machine on system-wide installs)
|
|
68
|
+
$nvmHome = [System.Environment]::GetEnvironmentVariable('NVM_HOME', 'User')
|
|
69
|
+
if (-not $nvmHome) { $nvmHome = [System.Environment]::GetEnvironmentVariable('NVM_HOME', 'Machine') }
|
|
70
|
+
$nvmSymlink = [System.Environment]::GetEnvironmentVariable('NVM_SYMLINK', 'User')
|
|
71
|
+
if (-not $nvmSymlink) { $nvmSymlink = [System.Environment]::GetEnvironmentVariable('NVM_SYMLINK', 'Machine') }
|
|
72
|
+
|
|
73
|
+
if ($nvmHome) { $env:NVM_HOME = $nvmHome }
|
|
74
|
+
if ($nvmSymlink) { $env:NVM_SYMLINK = $nvmSymlink }
|
|
75
|
+
|
|
76
|
+
$raw = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' +
|
|
77
|
+
[System.Environment]::GetEnvironmentVariable('Path', 'User')
|
|
78
|
+
|
|
79
|
+
# Expand literal %NVM_HOME% / %NVM_SYMLINK% tokens nvm-windows may have written
|
|
80
|
+
if ($nvmHome) { $raw = $raw -ireplace [regex]::Escape('%NVM_HOME%'), $nvmHome }
|
|
81
|
+
if ($nvmSymlink) { $raw = $raw -ireplace [regex]::Escape('%NVM_SYMLINK%'), $nvmSymlink }
|
|
82
|
+
|
|
83
|
+
$env:Path = $raw
|
|
84
|
+
|
|
85
|
+
# Ensure NVM_SYMLINK is in PATH even if the registry entry was already absolute
|
|
86
|
+
if ($nvmSymlink -and (Test-Path $nvmSymlink -ErrorAction SilentlyContinue)) {
|
|
87
|
+
if ($env:Path -notlike "*$([regex]::Escape($nvmSymlink))*") {
|
|
88
|
+
$env:Path = "$nvmSymlink;$env:Path"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# Find nvm.exe: checks PATH first, then known install locations
|
|
94
|
+
function Find-NvmExe {
|
|
95
|
+
try {
|
|
96
|
+
$f = (& where.exe nvm 2>$null)
|
|
97
|
+
if ($LASTEXITCODE -eq 0 -and $f) { return 'nvm' }
|
|
98
|
+
} catch {}
|
|
99
|
+
|
|
100
|
+
$candidates = @()
|
|
101
|
+
if ($env:NVM_HOME) { $candidates += Join-Path $env:NVM_HOME 'nvm.exe' }
|
|
102
|
+
if ($env:APPDATA) { $candidates += Join-Path $env:APPDATA 'nvm\nvm.exe' }
|
|
103
|
+
if ($env:ProgramData) { $candidates += Join-Path $env:ProgramData 'nvm\nvm.exe' }
|
|
104
|
+
$candidates += 'C:\ProgramData\nvm\nvm.exe'
|
|
105
|
+
|
|
106
|
+
foreach ($c in $candidates) {
|
|
107
|
+
if (Test-Path $c -ErrorAction SilentlyContinue) {
|
|
108
|
+
$dir = Split-Path $c -Parent
|
|
109
|
+
if ($env:Path -notlike "*$dir*") { $env:Path = "$dir;$env:Path" }
|
|
110
|
+
return $c
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return $null
|
|
68
114
|
}
|
|
69
115
|
|
|
70
116
|
function Get-NodeMajor {
|
|
@@ -204,18 +250,29 @@ function Select-NodeVersion {
|
|
|
204
250
|
}
|
|
205
251
|
|
|
206
252
|
# ─── Detect install mode ──────────────────────────────────────────────────────
|
|
207
|
-
#
|
|
208
|
-
#
|
|
253
|
+
# source = running from a git-cloned project directory -> npm install + npm link
|
|
254
|
+
# update = easy-devops already on PATH -> skip install steps
|
|
255
|
+
# npm = downloaded installer standalone -> npm install -g easy-devops
|
|
256
|
+
|
|
257
|
+
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
258
|
+
$packageJson = Join-Path $scriptDir 'package.json'
|
|
209
259
|
|
|
210
|
-
$
|
|
211
|
-
$
|
|
212
|
-
$existingCmd
|
|
260
|
+
$isSourceMode = $false
|
|
261
|
+
$isAlreadyInstalled = $false
|
|
262
|
+
$existingCmd = $null
|
|
213
263
|
|
|
264
|
+
# Source mode: script dir has this project's package.json
|
|
265
|
+
if (Test-Path $packageJson) {
|
|
266
|
+
try {
|
|
267
|
+
$pkg = Get-Content $packageJson -Raw | ConvertFrom-Json
|
|
268
|
+
if ($pkg.name -eq 'easy-devops') { $isSourceMode = $true }
|
|
269
|
+
} catch {}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
# Already installed: easy-devops on PATH
|
|
214
273
|
try {
|
|
215
274
|
$existingCmd = (& where.exe easy-devops 2>$null)
|
|
216
|
-
if ($LASTEXITCODE -eq 0 -and $existingCmd) {
|
|
217
|
-
$isSourceMode = $false
|
|
218
|
-
}
|
|
275
|
+
if ($LASTEXITCODE -eq 0 -and $existingCmd) { $isAlreadyInstalled = $true }
|
|
219
276
|
} catch {}
|
|
220
277
|
|
|
221
278
|
# ─── Banner ───────────────────────────────────────────────────────────────────
|
|
@@ -225,13 +282,14 @@ Write-Host " ==========================================" -ForegroundColor Cyan
|
|
|
225
282
|
Write-Host " Easy DevOps -- Windows Installer" -ForegroundColor Cyan
|
|
226
283
|
Write-Host " ==========================================" -ForegroundColor Cyan
|
|
227
284
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
Write-Host " Mode:
|
|
231
|
-
Write-Host "
|
|
285
|
+
Write-Host ""
|
|
286
|
+
if ($isAlreadyInstalled) {
|
|
287
|
+
Write-Host " Mode: update (easy-devops already installed at $existingCmd)" -ForegroundColor DarkGray
|
|
288
|
+
Write-Host " Node.js will still be managed; npm steps skipped." -ForegroundColor DarkGray
|
|
289
|
+
} elseif ($isSourceMode) {
|
|
290
|
+
Write-Host " Mode: source (project directory -- npm install + npm link)" -ForegroundColor DarkGray
|
|
232
291
|
} else {
|
|
233
|
-
Write-Host ""
|
|
234
|
-
Write-Host " Mode: source (installing from project directory)" -ForegroundColor DarkGray
|
|
292
|
+
Write-Host " Mode: npm (will run: npm install -g easy-devops)" -ForegroundColor DarkGray
|
|
235
293
|
}
|
|
236
294
|
|
|
237
295
|
# ─── Step 1: Detect system ───────────────────────────────────────────────────
|
|
@@ -307,7 +365,7 @@ if ($KeepNode) {
|
|
|
307
365
|
Write-Warn "Using fallback version $NODE_FALLBACK."
|
|
308
366
|
$script:ltsVersions = @([PSCustomObject]@{ version = "v$NODE_FALLBACK.0.0"; lts = "LTS" })
|
|
309
367
|
}
|
|
310
|
-
Add-Result "Node.js release list" $true "@($script:ltsVersions).Count LTS versions"
|
|
368
|
+
Add-Result "Node.js release list" $true "$(@($script:ltsVersions).Count) LTS versions fetched"
|
|
311
369
|
}
|
|
312
370
|
|
|
313
371
|
# ─── Step 3: Node.js version selection ───────────────────────────────────────
|
|
@@ -404,15 +462,35 @@ if ($NODE_ACTION -eq "keep") {
|
|
|
404
462
|
} else {
|
|
405
463
|
Write-Step "Installing nvm-windows"
|
|
406
464
|
|
|
407
|
-
# Check if nvm-windows is already present
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
$
|
|
465
|
+
# Check if nvm-windows is already present (check PATH + known locations)
|
|
466
|
+
Refresh-Path
|
|
467
|
+
$nvmExeCheck = Find-NvmExe
|
|
468
|
+
if ($nvmExeCheck) {
|
|
469
|
+
try {
|
|
470
|
+
$nvmVersion = (& $nvmExeCheck version 2>$null).Trim()
|
|
471
|
+
if ($nvmVersion) {
|
|
472
|
+
Write-OK "nvm-windows $nvmVersion already installed"
|
|
473
|
+
Add-Result "nvm-windows" $true $nvmVersion
|
|
474
|
+
$nvmReady = $true
|
|
475
|
+
}
|
|
476
|
+
} catch {}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (-not $nvmReady) {
|
|
480
|
+
# After Refresh-Path, try locating nvm at known paths
|
|
481
|
+
Refresh-Path
|
|
482
|
+
$nvmExePath = Find-NvmExe
|
|
483
|
+
if ($nvmExePath) {
|
|
484
|
+
try {
|
|
485
|
+
$nvmVersion = (& $nvmExePath version 2>$null).Trim()
|
|
486
|
+
if ($nvmVersion) {
|
|
487
|
+
Write-OK "nvm-windows $nvmVersion already installed (found after PATH refresh)"
|
|
488
|
+
Add-Result "nvm-windows" $true $nvmVersion
|
|
489
|
+
$nvmReady = $true
|
|
490
|
+
}
|
|
491
|
+
} catch {}
|
|
414
492
|
}
|
|
415
|
-
}
|
|
493
|
+
}
|
|
416
494
|
|
|
417
495
|
if (-not $nvmReady) {
|
|
418
496
|
$skipNvm = $false
|
|
@@ -480,53 +558,60 @@ if ($NODE_ACTION -eq "keep") {
|
|
|
480
558
|
} else {
|
|
481
559
|
Write-Step "Installing Node.js via nvm"
|
|
482
560
|
|
|
483
|
-
if ($nvmReady -and -not $nodeOK) {
|
|
484
|
-
# No compatible Node.js: install chosen version
|
|
561
|
+
if ($nvmReady -and (-not $nodeOK -or $NODE_ACTION -eq "upgrade" -or $NODE_ACTION -eq "switch")) {
|
|
485
562
|
Write-Info "Installing Node.js $NODE_TARGET via nvm..."
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
if
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
$
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
Write-Warn "
|
|
500
|
-
Add-Result "Node.js install" $false "
|
|
563
|
+
$nvmExe = Find-NvmExe
|
|
564
|
+
if (-not $nvmExe) {
|
|
565
|
+
Write-Warn "nvm not found -- open a new terminal and run: nvm install $NODE_TARGET"
|
|
566
|
+
Add-Result "Node.js install" $false "nvm not found"
|
|
567
|
+
} else {
|
|
568
|
+
# IMPORTANT: do NOT pipe nvm output (2>&1 | ...).
|
|
569
|
+
# nvm.exe checks if its stdout is a real console; piping makes it think
|
|
570
|
+
# it is not in a terminal and it shows a GUI dialog instead of running.
|
|
571
|
+
$nvmRunOK = $true
|
|
572
|
+
try {
|
|
573
|
+
& $nvmExe install $NODE_TARGET
|
|
574
|
+
& $nvmExe use $NODE_TARGET
|
|
575
|
+
} catch {
|
|
576
|
+
Write-Warn "nvm error: $_"
|
|
577
|
+
Add-Result "Node.js install" $false "nvm error -- see above"
|
|
578
|
+
$nvmRunOK = $false
|
|
501
579
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
580
|
+
|
|
581
|
+
if ($nvmRunOK) {
|
|
582
|
+
# PATH in this session may still be stale after nvm use.
|
|
583
|
+
# Read NVM_SYMLINK directly from registry and call node.exe by full path.
|
|
584
|
+
Refresh-Path
|
|
585
|
+
$raw = ""
|
|
586
|
+
try { $raw = (& node --version 2>&1).Trim() } catch {}
|
|
587
|
+
|
|
588
|
+
if (-not ($raw -match '^v')) {
|
|
589
|
+
$nvmSym = [System.Environment]::GetEnvironmentVariable('NVM_SYMLINK', 'Machine')
|
|
590
|
+
if (-not $nvmSym) { $nvmSym = [System.Environment]::GetEnvironmentVariable('NVM_SYMLINK', 'User') }
|
|
591
|
+
if ($nvmSym) {
|
|
592
|
+
$nodeExe = Join-Path $nvmSym 'node.exe'
|
|
593
|
+
if (Test-Path $nodeExe -ErrorAction SilentlyContinue) {
|
|
594
|
+
# Add to PATH so npm also works in the rest of this script
|
|
595
|
+
if ($env:Path -notlike "*$([regex]::Escape($nvmSym))*") {
|
|
596
|
+
$env:Path = "$nvmSym;$env:Path"
|
|
597
|
+
}
|
|
598
|
+
try { $raw = (& $nodeExe --version 2>&1).Trim() } catch {}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if ($raw -match '^v') {
|
|
604
|
+
$nodeVersion = $raw
|
|
605
|
+
Write-OK "Node.js $nodeVersion installed and active"
|
|
606
|
+
Add-Result "Node.js install" $true $nodeVersion
|
|
607
|
+
$nodeOK = $true
|
|
608
|
+
} else {
|
|
609
|
+
Write-Warn "Node.js installed but PATH not yet updated in this session"
|
|
610
|
+
Write-Warn "Open a new terminal and run: nvm use $NODE_TARGET"
|
|
611
|
+
Add-Result "Node.js install" $false "PATH refresh needed -- open a new terminal"
|
|
612
|
+
$nodeOK = $false
|
|
613
|
+
}
|
|
525
614
|
}
|
|
526
|
-
} catch {
|
|
527
|
-
Write-Warn "nvm error: $_ -- open a new terminal and run: nvm use $NODE_TARGET"
|
|
528
|
-
Add-Result "Node.js install" $false "Manual step needed"
|
|
529
|
-
$nodeOK = $false
|
|
530
615
|
}
|
|
531
616
|
} elseif (-not $nvmReady -and $nodeOK) {
|
|
532
617
|
# nvm not available but Node >= 18 already present: skip
|
|
@@ -539,82 +624,106 @@ if ($NODE_ACTION -eq "keep") {
|
|
|
539
624
|
}
|
|
540
625
|
}
|
|
541
626
|
|
|
542
|
-
# ───
|
|
627
|
+
# ─── Steps 6 + 7: Install Easy DevOps & register CLI ─────────────────────────
|
|
543
628
|
|
|
544
|
-
if (
|
|
545
|
-
#
|
|
546
|
-
Write-Step "Installing Easy DevOps
|
|
547
|
-
Write-OK "Skipped (
|
|
548
|
-
Add-Result "npm install" $true "Skipped (
|
|
629
|
+
if ($isAlreadyInstalled) {
|
|
630
|
+
# ── Already installed: skip both steps ──────────────────────────────────────
|
|
631
|
+
Write-Step "Installing Easy DevOps"
|
|
632
|
+
Write-OK "Skipped (easy-devops already installed at $existingCmd)"
|
|
633
|
+
Add-Result "npm install" $true "Skipped (already installed)"
|
|
549
634
|
|
|
550
635
|
Write-Step "Registering global command"
|
|
551
|
-
Write-OK "Skipped (
|
|
552
|
-
Add-Result "CLI registered" $true "Skipped (
|
|
553
|
-
} else {
|
|
554
|
-
|
|
555
|
-
# ─── Step 6: npm install ─────────────────────────────────────────────────────
|
|
556
|
-
|
|
557
|
-
Write-Step "Installing Easy DevOps dependencies"
|
|
636
|
+
Write-OK "Skipped (already registered)"
|
|
637
|
+
Add-Result "CLI registered" $true "Skipped (already installed)"
|
|
558
638
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
Write-
|
|
562
|
-
Write-Err "Run this installer from the Easy DevOps project root."
|
|
563
|
-
exit 1
|
|
564
|
-
}
|
|
639
|
+
} elseif ($isSourceMode) {
|
|
640
|
+
# ── Source mode: npm install in project dir + npm link ───────────────────────
|
|
641
|
+
Write-Step "Installing Easy DevOps dependencies"
|
|
565
642
|
|
|
566
|
-
if (-not $nodeOK) {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
} else {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
643
|
+
if (-not $nodeOK) {
|
|
644
|
+
Write-Warn "Skipping -- Node.js is not ready. Open a new terminal and re-run install.ps1."
|
|
645
|
+
Add-Result "npm install" $false "Skipped -- Node.js not ready"
|
|
646
|
+
} else {
|
|
647
|
+
try {
|
|
648
|
+
Push-Location $scriptDir
|
|
649
|
+
Write-Info "Running npm install..."
|
|
650
|
+
& npm install
|
|
651
|
+
if ($LASTEXITCODE -ne 0) {
|
|
652
|
+
Write-Err "npm install failed (exit code $LASTEXITCODE)"
|
|
653
|
+
Add-Result "npm install" $false "Exit code $LASTEXITCODE"
|
|
654
|
+
exit 1
|
|
655
|
+
}
|
|
656
|
+
Write-OK "All dependencies installed"
|
|
657
|
+
Add-Result "npm install" $true ""
|
|
658
|
+
} catch {
|
|
659
|
+
Write-Err "npm install error: $_"
|
|
660
|
+
Add-Result "npm install" $false "$_"
|
|
577
661
|
exit 1
|
|
662
|
+
} finally {
|
|
663
|
+
Pop-Location
|
|
578
664
|
}
|
|
579
|
-
Write-OK "All dependencies installed"
|
|
580
|
-
Add-Result "npm install" $true ""
|
|
581
|
-
} catch {
|
|
582
|
-
Write-Err "npm install error: $_"
|
|
583
|
-
Add-Result "npm install" $false "$_"
|
|
584
|
-
exit 1
|
|
585
|
-
} finally {
|
|
586
|
-
Pop-Location
|
|
587
665
|
}
|
|
588
|
-
}
|
|
589
666
|
|
|
590
|
-
|
|
667
|
+
Write-Step "Registering global command"
|
|
591
668
|
|
|
592
|
-
|
|
669
|
+
if (-not $nodeOK) {
|
|
670
|
+
Write-Warn "Skipping -- Node.js is not ready"
|
|
671
|
+
Add-Result "CLI registered" $false "Skipped -- Node.js not ready"
|
|
672
|
+
} else {
|
|
673
|
+
try {
|
|
674
|
+
Push-Location $scriptDir
|
|
675
|
+
& npm link
|
|
676
|
+
if ($LASTEXITCODE -ne 0) {
|
|
677
|
+
Write-Warn "npm link failed -- CLI won't be globally available"
|
|
678
|
+
Write-Warn "You can still run: node cli/index.js"
|
|
679
|
+
Add-Result "CLI registered" $false "Exit code $LASTEXITCODE"
|
|
680
|
+
} else {
|
|
681
|
+
Write-OK "easy-devops command linked globally"
|
|
682
|
+
Add-Result "CLI registered" $true ""
|
|
683
|
+
}
|
|
684
|
+
} catch {
|
|
685
|
+
Write-Warn "npm link failed: $_ -- run: node cli/index.js"
|
|
686
|
+
Add-Result "CLI registered" $false "$_"
|
|
687
|
+
} finally {
|
|
688
|
+
Pop-Location
|
|
689
|
+
}
|
|
690
|
+
}
|
|
593
691
|
|
|
594
|
-
if (-not $nodeOK) {
|
|
595
|
-
Write-Warn "Skipping -- Node.js is not ready"
|
|
596
|
-
Add-Result "CLI registered" $false "Skipped -- Node.js not ready"
|
|
597
692
|
} else {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
693
|
+
# ── npm global mode: npm install -g easy-devops ──────────────────────────────
|
|
694
|
+
Write-Step "Installing Easy DevOps"
|
|
695
|
+
|
|
696
|
+
if (-not $nodeOK) {
|
|
697
|
+
Write-Warn "Skipping -- Node.js is not ready."
|
|
698
|
+
Write-Warn "Open a new terminal and run: npm install -g easy-devops"
|
|
699
|
+
Add-Result "npm install" $false "Skipped -- Node.js not ready"
|
|
700
|
+
} else {
|
|
701
|
+
try {
|
|
702
|
+
Write-Info "Running npm install -g easy-devops..."
|
|
703
|
+
& npm install -g easy-devops
|
|
704
|
+
if ($LASTEXITCODE -ne 0) {
|
|
705
|
+
Write-Err "npm install -g easy-devops failed (exit code $LASTEXITCODE)"
|
|
706
|
+
Add-Result "npm install" $false "Exit code $LASTEXITCODE"
|
|
707
|
+
exit 1
|
|
708
|
+
}
|
|
709
|
+
Write-OK "easy-devops installed globally"
|
|
710
|
+
Add-Result "npm install" $true "npm install -g easy-devops"
|
|
711
|
+
} catch {
|
|
712
|
+
Write-Err "npm install -g error: $_"
|
|
713
|
+
Add-Result "npm install" $false "$_"
|
|
714
|
+
exit 1
|
|
608
715
|
}
|
|
609
|
-
} catch {
|
|
610
|
-
Write-Warn "npm link failed: $_ -- run: node cli/index.js"
|
|
611
|
-
Add-Result "CLI registered" $false "$_"
|
|
612
|
-
} finally {
|
|
613
|
-
Pop-Location
|
|
614
716
|
}
|
|
615
|
-
}
|
|
616
717
|
|
|
617
|
-
|
|
718
|
+
Write-Step "Registering global command"
|
|
719
|
+
if ($nodeOK) {
|
|
720
|
+
Write-OK "Registered via npm install -g"
|
|
721
|
+
Add-Result "CLI registered" $true "npm install -g"
|
|
722
|
+
} else {
|
|
723
|
+
Write-Warn "Skipped -- Node.js not ready"
|
|
724
|
+
Add-Result "CLI registered" $false "Skipped -- Node.js not ready"
|
|
725
|
+
}
|
|
726
|
+
}
|
|
618
727
|
|
|
619
728
|
# ─── Summary (mirrors install.sh summary block) ───────────────────────────────
|
|
620
729
|
|
package/install.sh
CHANGED
|
@@ -23,11 +23,35 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
23
23
|
EASYDEVOPS_DIR="${EASYDEVOPS_DIR:-$SCRIPT_DIR}"
|
|
24
24
|
|
|
25
25
|
# ---------------------------------------------------------------------------
|
|
26
|
-
# Source lib modules
|
|
26
|
+
# Source lib modules (auto-download if running standalone)
|
|
27
27
|
# ---------------------------------------------------------------------------
|
|
28
28
|
LIB_DIR="$SCRIPT_DIR/lib/installer"
|
|
29
|
+
_LIB_BASE="https://raw.githubusercontent.com/omar00050/Easy-DevOps/main/lib/installer"
|
|
30
|
+
_LIB_MODULES="progress.sh detect.sh node-versions.sh picker.sh nvm-bootstrap.sh"
|
|
31
|
+
|
|
32
|
+
if [ ! -f "$LIB_DIR/progress.sh" ]; then
|
|
33
|
+
printf 'Lib modules not found locally — downloading from GitHub...\n'
|
|
34
|
+
mkdir -p "$LIB_DIR"
|
|
35
|
+
_dl_ok=true
|
|
36
|
+
for _module in $_LIB_MODULES; do
|
|
37
|
+
if command -v curl >/dev/null 2>&1; then
|
|
38
|
+
curl -fsSL "$_LIB_BASE/$_module" -o "$LIB_DIR/$_module" 2>/dev/null || _dl_ok=false
|
|
39
|
+
elif command -v wget >/dev/null 2>&1; then
|
|
40
|
+
wget -q "$_LIB_BASE/$_module" -O "$LIB_DIR/$_module" 2>/dev/null || _dl_ok=false
|
|
41
|
+
else
|
|
42
|
+
printf 'Error: curl or wget is required to download installer modules.\n' >&2
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
done
|
|
46
|
+
if [ "$_dl_ok" = "false" ]; then
|
|
47
|
+
printf 'Error: Failed to download one or more installer modules from GitHub.\n' >&2
|
|
48
|
+
printf 'Check your internet connection and try again.\n' >&2
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
printf 'Modules downloaded.\n\n'
|
|
52
|
+
fi
|
|
29
53
|
|
|
30
|
-
for _module in
|
|
54
|
+
for _module in $_LIB_MODULES; do
|
|
31
55
|
if [ ! -f "$LIB_DIR/$_module" ]; then
|
|
32
56
|
printf 'Error: Required module not found: %s/%s\n' "$LIB_DIR" "$_module" >&2
|
|
33
57
|
exit 1
|
|
@@ -147,19 +171,35 @@ while [ "$#" -gt 0 ]; do
|
|
|
147
171
|
done
|
|
148
172
|
|
|
149
173
|
# ---------------------------------------------------------------------------
|
|
150
|
-
#
|
|
174
|
+
# Install mode detection (mirrors install.ps1 3-mode logic)
|
|
151
175
|
#
|
|
152
|
-
#
|
|
153
|
-
#
|
|
154
|
-
#
|
|
155
|
-
#
|
|
176
|
+
# source : package.json with name=easy-devops found in script dir
|
|
177
|
+
# -> npm install + npm link
|
|
178
|
+
# update : easy-devops already on PATH
|
|
179
|
+
# -> skip install steps
|
|
180
|
+
# npm : standalone download, not in project dir
|
|
181
|
+
# -> npm install -g easy-devops
|
|
156
182
|
# ---------------------------------------------------------------------------
|
|
157
|
-
|
|
183
|
+
SOURCE_MODE=false
|
|
184
|
+
ALREADY_INSTALLED=false
|
|
158
185
|
EXISTING_CMD=""
|
|
159
186
|
|
|
187
|
+
# Source mode: script is running from the project directory
|
|
188
|
+
if [ -f "$SCRIPT_DIR/package.json" ]; then
|
|
189
|
+
if command -v node >/dev/null 2>&1; then
|
|
190
|
+
_pkg_name="$(node -e "try{process.stdout.write(require('$SCRIPT_DIR/package.json').name)}catch(e){}" 2>/dev/null || true)"
|
|
191
|
+
else
|
|
192
|
+
_pkg_name="$(grep -o '"name"[[:space:]]*:[[:space:]]*"[^"]*"' "$SCRIPT_DIR/package.json" 2>/dev/null | grep -o '"[^"]*"$' | tr -d '"' || true)"
|
|
193
|
+
fi
|
|
194
|
+
if [ "$_pkg_name" = "easy-devops" ]; then
|
|
195
|
+
SOURCE_MODE=true
|
|
196
|
+
fi
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
# Already installed: easy-devops command is on PATH
|
|
160
200
|
if command -v easy-devops >/dev/null 2>&1; then
|
|
161
201
|
EXISTING_CMD="$(command -v easy-devops)"
|
|
162
|
-
|
|
202
|
+
ALREADY_INSTALLED=true
|
|
163
203
|
fi
|
|
164
204
|
|
|
165
205
|
# ---------------------------------------------------------------------------
|
|
@@ -171,12 +211,15 @@ printf '║ Easy DevOps -- Bootstrap Installer ║\n'
|
|
|
171
211
|
printf '╚══════════════════════════════════════╝\n'
|
|
172
212
|
printf '\n'
|
|
173
213
|
|
|
174
|
-
if [ "$
|
|
175
|
-
printf ' Mode:
|
|
176
|
-
printf '
|
|
214
|
+
if [ "$ALREADY_INSTALLED" = "true" ]; then
|
|
215
|
+
printf ' Mode: update (easy-devops already installed at %s)\n' "$EXISTING_CMD"
|
|
216
|
+
printf ' Node.js will still be managed; npm steps skipped.\n'
|
|
217
|
+
printf '\n'
|
|
218
|
+
elif [ "$SOURCE_MODE" = "true" ]; then
|
|
219
|
+
printf ' Mode: source (project directory -- npm install + npm link)\n'
|
|
177
220
|
printf '\n'
|
|
178
221
|
else
|
|
179
|
-
printf ' Mode:
|
|
222
|
+
printf ' Mode: npm (will run: npm install -g easy-devops)\n'
|
|
180
223
|
printf '\n'
|
|
181
224
|
fi
|
|
182
225
|
|
|
@@ -369,40 +412,31 @@ else
|
|
|
369
412
|
fi
|
|
370
413
|
|
|
371
414
|
# ---------------------------------------------------------------------------
|
|
372
|
-
#
|
|
415
|
+
# Steps 6 + 7: Install Easy DevOps & register CLI
|
|
373
416
|
# ---------------------------------------------------------------------------
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
417
|
+
|
|
418
|
+
if [ "$ALREADY_INSTALLED" = "true" ]; then
|
|
419
|
+
# ── Already installed: skip both steps ──────────────────────────────────────
|
|
420
|
+
step_done "${STEPS[5]} (skipped -- easy-devops already installed)"
|
|
421
|
+
add_result "npm install" "ok" "Skipped (already installed)"
|
|
422
|
+
step_done "${STEPS[6]} (skipped -- already registered)"
|
|
423
|
+
add_result "CLI registered" "ok" "Skipped (already installed)"
|
|
424
|
+
|
|
425
|
+
elif [ "$SOURCE_MODE" = "true" ]; then
|
|
426
|
+
# ── Source mode: npm install in project dir + npm link ───────────────────────
|
|
378
427
|
step_running "${STEPS[5]}"
|
|
379
428
|
printf 'Running npm install in %s...\n' "$EASYDEVOPS_DIR"
|
|
380
|
-
if !
|
|
429
|
+
if ! (cd "$EASYDEVOPS_DIR" && npm install 2>&1); then
|
|
381
430
|
die "${STEPS[5]}" "npm install failed" \
|
|
382
431
|
"cd $EASYDEVOPS_DIR && npm install" \
|
|
383
432
|
"npm link"
|
|
384
433
|
fi
|
|
385
434
|
step_done "${STEPS[5]}"
|
|
386
435
|
add_result "npm install" "ok" ""
|
|
387
|
-
fi
|
|
388
436
|
|
|
389
|
-
# ---------------------------------------------------------------------------
|
|
390
|
-
# Step 7: npm link -- register global command
|
|
391
|
-
# ---------------------------------------------------------------------------
|
|
392
|
-
if [ "$PACKAGE_MODE" = "true" ]; then
|
|
393
|
-
step_done "${STEPS[6]} (skipped -- package mode)"
|
|
394
|
-
add_result "CLI registered" "ok" "Skipped (package mode)"
|
|
395
|
-
else
|
|
396
437
|
step_running "${STEPS[6]}"
|
|
397
438
|
printf 'Registering global command via npm link...\n'
|
|
398
|
-
|
|
399
|
-
if npm link --prefix "$EASYDEVOPS_DIR" 2>&1; then
|
|
400
|
-
_link_ok=true
|
|
401
|
-
elif (cd "$EASYDEVOPS_DIR" && npm link 2>&1); then
|
|
402
|
-
_link_ok=true
|
|
403
|
-
fi
|
|
404
|
-
|
|
405
|
-
if [ "$_link_ok" = "false" ]; then
|
|
439
|
+
if ! (cd "$EASYDEVOPS_DIR" && npm link 2>&1); then
|
|
406
440
|
die "${STEPS[6]}" "npm link failed -- could not register global command" \
|
|
407
441
|
"cd $EASYDEVOPS_DIR && npm link" \
|
|
408
442
|
"If permission denied, try: sudo npm link"
|
|
@@ -410,13 +444,26 @@ else
|
|
|
410
444
|
|
|
411
445
|
# Verify the command is on PATH
|
|
412
446
|
if ! command -v easy-devops >/dev/null 2>&1; then
|
|
413
|
-
printf 'Warning: easy-devops
|
|
414
|
-
printf 'You may need to open a new terminal or run:\n' >&2
|
|
447
|
+
printf 'Warning: easy-devops not yet on PATH. Open a new terminal or run:\n' >&2
|
|
415
448
|
printf ' export PATH="$(npm bin -g):$PATH"\n' >&2
|
|
416
449
|
fi
|
|
417
|
-
|
|
418
450
|
step_done "${STEPS[6]}"
|
|
419
451
|
add_result "CLI registered" "ok" ""
|
|
452
|
+
|
|
453
|
+
else
|
|
454
|
+
# ── npm global mode: npm install -g easy-devops ──────────────────────────────
|
|
455
|
+
step_running "${STEPS[5]}"
|
|
456
|
+
printf 'Running npm install -g easy-devops...\n'
|
|
457
|
+
if ! npm install -g easy-devops 2>&1; then
|
|
458
|
+
die "${STEPS[5]}" "npm install -g easy-devops failed" \
|
|
459
|
+
"npm install -g easy-devops" \
|
|
460
|
+
"If permission denied, try: sudo npm install -g easy-devops"
|
|
461
|
+
fi
|
|
462
|
+
step_done "${STEPS[5]}"
|
|
463
|
+
add_result "npm install" "ok" "npm install -g easy-devops"
|
|
464
|
+
|
|
465
|
+
step_done "${STEPS[6]} (registered via npm install -g)"
|
|
466
|
+
add_result "CLI registered" "ok" "npm install -g"
|
|
420
467
|
fi
|
|
421
468
|
|
|
422
469
|
# ---------------------------------------------------------------------------
|
package/package.json
CHANGED