-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathpatchCreation.js
More file actions
157 lines (148 loc) · 4.04 KB
/
Copy pathpatchCreation.js
File metadata and controls
157 lines (148 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import { echo, startColor, stopColor } from './ansiUtils';
import { curDir, patchDir, tmpDir, programOptions } from './variables';
import { fetchPackage } from './npmUtils';
import { getConfig } from './utils';
import { ensureDirectoryExists } from './fileUtils';
import fs from 'node:fs';
import path from 'node:path';
import { createTwoFilesPatch } from 'diff';
/**
*
* @param packageNames {Array<String>}
*/
export function createPatches(packageNames)
{
// create patch for each of the provided package names
packageNames.forEach(makePatch);
}
/**
* replace directory separators in package names like "@vue/cli" or "@babel/register"
* @param fn {String}
* @returns {String}
*/
function goodFileName(fn)
{
const pattern = new RegExp('/', 'g');
return fn.replace(pattern, '+');
}
function makePatchName(pkgName, version)
{
return goodFileName(pkgName) + '#' + version + '.patch';
}
/**
* @constant
* @type {import('@types/node').WriteStream} WriteStream
*/
/**
* compare a modified file from the local package to its original counterpart - if they are different, create a patch and append it to the patch stream
* @param pkgName {String}
* @param pathname {String}
* @param patch {WriteStream}
*/
function createPatch(pkgName, pathname, patch)
{
if(pathname === 'package.json' && !programOptions.all) return; // skip "package.json" - comparison is not reliable because NPM reorders keys and also appends many system keys (whose names begin with underscore)
const newFile = path.join(curDir, 'node_modules', pkgName, pathname);
const oldFile = path.join(tmpDir, pkgName, pathname);
const oldStr = fs.existsSync(oldFile) ? fs.readFileSync(oldFile, 'utf8') : '';
const newStr = fs.readFileSync(newFile, 'utf8');
if(oldStr !== newStr) patch.write(createTwoFilesPatch(oldFile.replace(tmpDir,''), newFile.replace(path.join(curDir, 'node_modules'),''), oldStr, newStr));
}
/**
* recursively enumerate all files in the locally installed package
* @param pkgName {String}
* @param src {String}
* @param patch {WriteStream}
*/
function scanFiles(pkgName, src, patch)
{
const files = fs.readdirSync(path.join(curDir, 'node_modules', pkgName, src));
files.forEach(item =>
{
if (item === 'node_modules') return;
const pathname = path.join(src, item);
const stat = fs.lstatSync(path.join(curDir, 'node_modules', pkgName, pathname));
if(stat.isDirectory()) scanFiles(pkgName, pathname, patch);
else createPatch(pkgName, pathname, patch);
});
}
/**
* compare all files from the locally modified package with their original content
* @param pkgName {String}
* @param version {String}
*/
function comparePackages(pkgName, version)
{
const patchFile = makePatchName(pkgName, version);
// Ensure the patches directory exists
ensureDirectoryExists(patchDir);
const stream = fs.createWriteStream(path.join(patchDir, patchFile));
stream.on('error', (err) =>
{
echo(
startColor('redBright'),
'ERROR: ',
stopColor(),
'Could not write patch file ',
startColor('cyanBright'),
patchFile,
stopColor(),
' = ',
startColor('redBright'),
err.message || err,
stopColor()
);
});
stream.cork();
scanFiles(pkgName, '', stream);
stream.uncork();
// Handle 'drain' event if necessary
if (!stream.write(''))
{
stream.once('drain', () => stream.end());
}
else
{
stream.end();
}
echo(
'Successfully created ',
startColor('greenBright'),
patchFile,
stopColor()
);
}
/**
* build a patch for the given package
* @param pkgName {String}
*/
function makePatch(pkgName)
{
echo(
'Creating patch for: ',
startColor('magentaBright'),
pkgName,
stopColor()
);
const cfg = getConfig(pkgName);
if(cfg)
{
fetchPackage(pkgName, cfg.version, comparePackages);
}
else
{
echo(
startColor('redBright'),
'ERROR: ',
stopColor(),
'Could not find the ',
startColor('whiteBright'),
'URL',
stopColor(),
' for ',
startColor('greenBright'),
'tarball',
stopColor()
);
}
}