@bobfrankston/npmglobalize 1.0.98 → 1.0.100
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/lib.js +72 -9
- package/package.json +1 -1
package/lib.js
CHANGED
|
@@ -116,6 +116,27 @@ function repairGitIndex(cwd) {
|
|
|
116
116
|
return false;
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
/** Parse file paths from git add "Permission denied" / "unable to index file" errors.
|
|
120
|
+
* Matches lines like: error: open("data/PingDB.mdf"): Permission denied
|
|
121
|
+
* and: error: unable to index file 'data/PingDB.mdf' */
|
|
122
|
+
function parseDeniedFiles(errText) {
|
|
123
|
+
const files = [];
|
|
124
|
+
for (const line of errText.split('\n')) {
|
|
125
|
+
// error: open("path"): Permission denied
|
|
126
|
+
let m = line.match(/error:\s*open\(["'](.+?)["']\):\s*Permission denied/i);
|
|
127
|
+
if (m) {
|
|
128
|
+
files.push(m[1]);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
// error: unable to index file 'path'
|
|
132
|
+
m = line.match(/error:\s*unable to index file\s+['"](.+?)['"]/i);
|
|
133
|
+
if (m) {
|
|
134
|
+
files.push(m[1]);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return files;
|
|
139
|
+
}
|
|
119
140
|
/** Get npm command for current platform (npm.cmd on Windows, npm elsewhere) */
|
|
120
141
|
function getNpmCommand() {
|
|
121
142
|
return process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
@@ -878,7 +899,7 @@ export function fixVersionTagMismatch(cwd, pkg, verbose = false) {
|
|
|
878
899
|
return deletedAny;
|
|
879
900
|
}
|
|
880
901
|
/** Wait for a package version to appear on the npm registry */
|
|
881
|
-
function waitForNpmVersion(pkgName, version, maxWaitMs =
|
|
902
|
+
function waitForNpmVersion(pkgName, version, maxWaitMs = 90000) {
|
|
882
903
|
const interval = 3000;
|
|
883
904
|
const maxAttempts = Math.ceil(maxWaitMs / interval);
|
|
884
905
|
process.stdout.write(`Waiting for ${pkgName}@${version} on npm registry`);
|
|
@@ -898,6 +919,16 @@ function waitForNpmVersion(pkgName, version, maxWaitMs = 60000) {
|
|
|
898
919
|
process.stdout.write(' timed out\n');
|
|
899
920
|
return false;
|
|
900
921
|
}
|
|
922
|
+
/** Run npm install -g with retries for registry propagation delay */
|
|
923
|
+
function installGlobalWithRetry(pkgSpec, cwd, maxRetries = 3) {
|
|
924
|
+
let result = runCommand('npm', ['install', '-g', pkgSpec], { cwd, silent: false });
|
|
925
|
+
for (let attempt = 1; attempt < maxRetries && !result.success; attempt++) {
|
|
926
|
+
console.log(colors.yellow(` Retrying install (attempt ${attempt + 1}/${maxRetries}) in 10 seconds...`));
|
|
927
|
+
spawnSafe(process.platform === 'win32' ? 'timeout' : 'sleep', process.platform === 'win32' ? ['/t', '10', '/nobreak'] : ['10'], { stdio: 'pipe', shell: process.platform === 'win32' });
|
|
928
|
+
result = runCommand('npm', ['install', '-g', pkgSpec], { cwd, silent: false });
|
|
929
|
+
}
|
|
930
|
+
return result;
|
|
931
|
+
}
|
|
901
932
|
/** Run a command and return success status */
|
|
902
933
|
export function runCommand(cmd, args, options = {}) {
|
|
903
934
|
const { silent = false, cwd } = options;
|
|
@@ -1265,7 +1296,10 @@ const RECOMMENDED_GITIGNORE = [
|
|
|
1265
1296
|
'.globalize.json5',
|
|
1266
1297
|
'*.log',
|
|
1267
1298
|
'.DS_Store',
|
|
1268
|
-
'Thumbs.db'
|
|
1299
|
+
'Thumbs.db',
|
|
1300
|
+
'*.mdf',
|
|
1301
|
+
'*.ldf',
|
|
1302
|
+
'*.ndf'
|
|
1269
1303
|
];
|
|
1270
1304
|
/** Recommended .npmignore patterns */
|
|
1271
1305
|
const RECOMMENDED_NPMIGNORE = [
|
|
@@ -2537,7 +2571,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2537
2571
|
else if (install) {
|
|
2538
2572
|
waitForNpmVersion(pkgName, pkgVersion);
|
|
2539
2573
|
console.log(`Installing ${pkgName}@${pkgVersion} globally from registry...`);
|
|
2540
|
-
const registryInstallResult =
|
|
2574
|
+
const registryInstallResult = installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd);
|
|
2541
2575
|
if (registryInstallResult.success) {
|
|
2542
2576
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
2543
2577
|
}
|
|
@@ -2578,13 +2612,42 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2578
2612
|
if (nulCount > 0 && verbose) {
|
|
2579
2613
|
console.log(` Removed ${nulCount} 'nul' file(s) (Windows reserved name)`);
|
|
2580
2614
|
}
|
|
2581
|
-
|
|
2615
|
+
let addResult = runCommand('git', ['add', '-A'], { cwd, silent: true });
|
|
2582
2616
|
if (!addResult.success) {
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2617
|
+
const errText = addResult.stderr + addResult.output;
|
|
2618
|
+
const deniedFiles = parseDeniedFiles(errText);
|
|
2619
|
+
if (deniedFiles.length > 0) {
|
|
2620
|
+
console.error(colors.red(`git add failed — ${deniedFiles.length} file(s) locked/permission denied:`));
|
|
2621
|
+
for (const f of deniedFiles) {
|
|
2622
|
+
console.error(colors.red(` ${f}`));
|
|
2623
|
+
}
|
|
2624
|
+
const ok = await confirm('Add these files to .gitignore and retry?', true);
|
|
2625
|
+
if (ok) {
|
|
2626
|
+
const gitignorePath = path.join(cwd, '.gitignore');
|
|
2627
|
+
let gitignoreContent = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf-8') : '';
|
|
2628
|
+
if (gitignoreContent && !gitignoreContent.endsWith('\n'))
|
|
2629
|
+
gitignoreContent += '\n';
|
|
2630
|
+
for (const f of deniedFiles) {
|
|
2631
|
+
gitignoreContent += f + '\n';
|
|
2632
|
+
}
|
|
2633
|
+
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
2634
|
+
console.log(colors.green('✓ Updated .gitignore'));
|
|
2635
|
+
addResult = runCommand('git', ['add', '-A'], { cwd, silent: true });
|
|
2636
|
+
if (addResult.success) {
|
|
2637
|
+
console.log(colors.green('✓ git add succeeded after updating .gitignore'));
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
if (!addResult.success) {
|
|
2641
|
+
return false;
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
else {
|
|
2645
|
+
console.error(colors.red('ERROR: Failed to add files to git:'), errText);
|
|
2646
|
+
if (!force) {
|
|
2647
|
+
return false;
|
|
2648
|
+
}
|
|
2649
|
+
console.log(colors.yellow('Continuing with --force...'));
|
|
2586
2650
|
}
|
|
2587
|
-
console.log(colors.yellow('Continuing with --force...'));
|
|
2588
2651
|
}
|
|
2589
2652
|
let commitResult = runCommand('git', ['commit', '-m', commitMsg], { cwd });
|
|
2590
2653
|
if (!commitResult.success) {
|
|
@@ -3008,7 +3071,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3008
3071
|
console.log(`Installing globally from registry: ${pkgName}@${pkgVersion}...`);
|
|
3009
3072
|
if (!dryRun) {
|
|
3010
3073
|
waitForNpmVersion(pkgName, pkgVersion);
|
|
3011
|
-
const installResult =
|
|
3074
|
+
const installResult = installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd);
|
|
3012
3075
|
if (installResult.success) {
|
|
3013
3076
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
3014
3077
|
}
|