1
1
import chalk from "chalk"
2
2
import { join , dirname , resolve } from "./path"
3
- import { basename } from "path"
4
3
import { spawnSafeSync } from "./spawnSafe"
5
4
import { PackageManager } from "./detectPackageManager"
6
5
import { removeIgnoredFiles } from "./filterFiles"
@@ -12,10 +11,6 @@ import {
12
11
mkdirpSync ,
13
12
realpathSync ,
14
13
renameSync ,
15
- /*
16
- lstatSync,
17
- readlinkSync,
18
- */
19
14
} from "fs-extra"
20
15
import { sync as rimraf } from "rimraf"
21
16
import { copySync } from "fs-extra"
@@ -35,11 +30,12 @@ import {
35
30
maybePrintIssueCreationPrompt ,
36
31
openIssueCreationLink ,
37
32
} from "./createIssue"
38
- import { quote as shlexQuote } from "shlex "
33
+ import { spawnSync } from "child_process "
39
34
35
+ // globals are set in src/index.ts
40
36
const isVerbose = global . patchPackageIsVerbose
41
37
const isDebug = global . patchPackageIsDebug
42
- const isTest = process . env . NODE_ENV == 'test'
38
+ const patchPackageVersion = global . patchPackageVersion
43
39
44
40
function printNoPackageFoundError (
45
41
packageName : string ,
@@ -331,12 +327,17 @@ in the format <major>.<minor>.<patch>, for example: "${packageDetails.name}": "$
331
327
}
332
328
}
333
329
334
- const git = ( ...args : string [ ] ) =>
335
- spawnSafeSync ( "git" , args , {
330
+ function git ( ...args : string [ ] ) {
331
+ if ( isDebug ) {
332
+ const argsStr = JSON . stringify ( [ "git" , ...args ] )
333
+ console . log ( `patch-package/makePatch: spawn: args = ${ argsStr } + workdir = ${ tmpRepo . name } ` )
334
+ }
335
+ return spawnSafeSync ( "git" , args , {
336
336
cwd : tmpRepo . name ,
337
337
env : { ...process . env , HOME : tmpRepo . name } ,
338
338
maxBuffer : 1024 * 1024 * 100 ,
339
339
} )
340
+ }
340
341
341
342
// remove nested node_modules just to be safe
342
343
rimraf ( join ( tmpRepoPackagePath , "node_modules" ) )
@@ -347,6 +348,8 @@ in the format <major>.<minor>.<patch>, for example: "${packageDetails.name}": "$
347
348
console . info ( chalk . grey ( "•" ) , "Diffing your files with clean files" )
348
349
writeFileSync ( join ( tmpRepo . name , ".gitignore" ) , "!/node_modules\n\n" )
349
350
git ( "init" )
351
+ // TODO use env-vars for "git commit"
352
+ // GIT_{COMMITTER,AUTHOR}_{NAME,EMAIL}
350
353
git ( "config" , "--local" , "user.name" , "patch-package" )
351
354
git ( "config" , "--local" , "user.email" , "patch@pack.age" )
352
355
@@ -355,39 +358,84 @@ in the format <major>.<minor>.<patch>, for example: "${packageDetails.name}": "$
355
358
removeIgnoredFiles ( tmpRepoPackagePath , includePaths , excludePaths )
356
359
357
360
git ( "add" , "-f" , packageDetails . path )
361
+ if ( isVerbose ) {
362
+ console . log ( `git status:\n` + git ( "status" ) . stdout . toString ( ) )
363
+ }
358
364
git ( "commit" , "--allow-empty" , "-m" , "init" )
359
365
360
366
// replace package with user's version
367
+ if ( isVerbose ) {
368
+ console . log ( `patch-package/makePatch: remove all files in ${ tmpRepoPackagePath } ` )
369
+ }
361
370
rimraf ( tmpRepoPackagePath )
362
371
363
372
if ( isVerbose ) {
364
- console . log (
365
- `patch-package/makePatch: copy ${ realpathSync (
366
- packagePath ,
367
- ) } to ${ tmpRepoPackagePath } `,
368
- )
373
+ console . log ( `patch-package/makePatch: git status:\n` + git ( "status" ) . stdout . toString ( ) )
369
374
}
370
375
371
376
// pnpm installs packages as symlinks, copySync would copy only the symlink
377
+ // with pnpm, realpath resolves to ./node_modules/.pnpm/${name}@${version}
372
378
const srcPath = realpathSync ( packagePath )
379
+ if ( isVerbose ) {
380
+ console . log (
381
+ `patch-package/makePatch: copy ${ srcPath } to ${ tmpRepoPackagePath } + skip ${ srcPath } /node_modules/` ,
382
+ )
383
+ }
373
384
copySync ( srcPath , tmpRepoPackagePath , {
374
385
filter : ( path ) => {
375
- return ! path . startsWith ( srcPath + "/node_modules/" )
386
+ const doCopy = ! path . startsWith ( srcPath + "/node_modules/" )
387
+ if ( isVerbose ) {
388
+ if ( doCopy ) {
389
+ console . log ( `patch-package/makePatch: copySync: copy file ${ path } ` )
390
+ }
391
+ else {
392
+ console . log ( `patch-package/makePatch: copySync: skip file ${ path } ` )
393
+ }
394
+ }
395
+ return doCopy
376
396
} ,
377
397
} )
378
398
399
+ if ( isDebug ) {
400
+ // list files
401
+ // NOTE this works only on linux
402
+ console . log ( `patch-package/makePatch: files in srcPath = ${ srcPath } ` )
403
+ console . log ( spawnSync ( 'find' , [ '.' ] , { cwd : srcPath , encoding : 'utf8' } ) . stdout )
404
+ console . log ( `patch-package/makePatch: files in tmpRepoPackagePath = ${ tmpRepoPackagePath } ` )
405
+ console . log ( spawnSync ( 'find' , [ '.' ] , { cwd : tmpRepoPackagePath , encoding : 'utf8' } ) . stdout )
406
+ }
407
+
379
408
// remove nested node_modules just to be safe
380
409
rimraf ( join ( tmpRepoPackagePath , "node_modules" ) )
410
+
381
411
// remove .git just to be safe
412
+ // NOTE this removes ./node_modules/${dependencyName}/.git not ./.git
382
413
rimraf ( join ( tmpRepoPackagePath , ".git" ) )
383
414
384
415
// also remove ignored files like before
416
+ // for example, remove package.json
417
+ // TODO support patching package.json via semantic json diff
385
418
// use CLI options --exclude and --include
419
+
420
+ if ( isDebug ) {
421
+ console . log ( `patch-package/makePatch: removing ignored files in tmpRepoPackagePath = ${ tmpRepoPackagePath } :` )
422
+ }
386
423
removeIgnoredFiles ( tmpRepoPackagePath , includePaths , excludePaths )
387
424
425
+ if ( isDebug ) {
426
+ // list files
427
+ // NOTE this works only on linux
428
+ console . log ( `patch-package/makePatch: files in tmpRepoPackagePath = ${ tmpRepoPackagePath } :` )
429
+ console . log ( spawnSync ( 'find' , [ '.' , '-type' , 'f' ] , { cwd : tmpRepoPackagePath , encoding : 'utf8' } ) . stdout )
430
+ }
431
+
388
432
// stage all files
389
433
git ( "add" , "-f" , packageDetails . path )
390
434
435
+ if ( isVerbose ) {
436
+ console . log ( `patch-package/makePatch: git status:\n` + git ( "status" ) . stdout . toString ( ) )
437
+ }
438
+
391
439
const ignorePaths = [ "package-lock.json" , "pnpm-lock.yaml" ]
392
440
393
441
// get diff of changes
@@ -473,44 +521,19 @@ in the format <major>.<minor>.<patch>, for example: "${packageDetails.name}": "$
473
521
}
474
522
} )
475
523
476
- const patchPackageVersion = require ( "../package.json" ) . version
477
-
478
524
// patchfiles are parsed in patch/parse.ts function parsePatchLines
479
525
// -> header comments are ignored
480
526
let diffHeader = ""
481
527
diffHeader += `# generated by patch-package ${ patchPackageVersion } \n`
482
528
diffHeader += `#\n`
483
- const prettyArgv = process . argv . slice ( )
484
- if ( prettyArgv [ 0 ] . match ( / n o d e / ) ) {
485
- prettyArgv [ 0 ] = "npx"
486
- }
487
- if ( prettyArgv [ 1 ] . match ( / p a t c h - p a c k a g e / ) ) {
488
- prettyArgv [ 1 ] = "patch-package"
489
- }
490
- diffHeader += `# command:\n`
491
- diffHeader += `# ${ prettyArgv . map ( ( a ) => shlexQuote ( a ) ) . join ( " " ) } \n`
492
- diffHeader += `#\n`
493
- diffHeader += `# declared package:\n`
494
- // TODO rename resolvedVersion.version to declaredVersion
495
- const declaredPackageStr = (
496
- isTest ? ( ( ) => {
497
- const v = resolvedVersion . version
498
- const b = basename ( v )
499
- if ( b != v ) return `file:/mocked/path/to/${ b } ` // mock path // TODO keep the relative path? as declared in /package.json. see getPackageResolution "resolve relative file path"
500
- return v
501
- } ) ( ) :
529
+ if ( isDebug ) {
502
530
resolvedVersion . version
503
- )
504
- diffHeader += `# ${ packageDetails . name } : ${ declaredPackageStr } \n`
505
- /* redundant. this is visible from command, sample: npx patch-package wrap-ansi/string-width -> packageNames: wrap-ansi, string-width
506
- if (packageDetails.packageNames.length > 1) {
507
- diffHeader += `#\n`
508
- diffHeader += `# package names:\n`
509
- packageDetails.packageNames.forEach((packageName) => {
510
- diffHeader += `# ${packageName}\n`
511
- })
512
531
}
513
- */
532
+ diffHeader += `# declared package:\n`
533
+ diffHeader += `# ${ packageDetails . name } : ${ resolvedVersion . declaredVersion } \n`
534
+ // NOTE: we do *not* include the locked version from package-lock.json or yarn.lock or pnpm-lock.yaml or ...
535
+ // because patch-package should work with all package managers (should be manager-agnostic)
536
+ // users can pin versions in package.json
514
537
diffHeader += `#\n`
515
538
516
539
const patchFileName = createPatchFileName ( {
0 commit comments