azure-pipelines-task-lib 3.3.1 → 4.0.0-preview
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 +22 -22
- package/README.md +74 -74
- package/Strings/resources.resjson/de-DE/resources.resjson +34 -34
- package/Strings/resources.resjson/es-ES/resources.resjson +34 -34
- package/Strings/resources.resjson/fr-FR/resources.resjson +34 -34
- package/Strings/resources.resjson/ja-JP/resources.resjson +34 -34
- package/ThirdPartyNotice.txt +1114 -1114
- package/internal.d.ts +130 -130
- package/internal.js +885 -885
- package/lib.json +37 -37
- package/mock-answer.d.ts +55 -55
- package/mock-answer.js +41 -41
- package/mock-run.d.ts +44 -44
- package/mock-run.js +92 -92
- package/mock-task.d.ts +111 -111
- package/mock-task.js +447 -447
- package/mock-test.d.ts +28 -28
- package/mock-test.js +298 -298
- package/mock-toolrunner.d.ts +41 -41
- package/mock-toolrunner.js +268 -268
- package/package.json +49 -49
- package/task.d.ts +718 -718
- package/task.js +2003 -2003
- package/taskcommand.d.ts +10 -10
- package/taskcommand.js +103 -103
- package/toolrunner.d.ts +159 -159
- package/toolrunner.js +967 -967
- package/vault.d.ts +10 -10
- package/vault.js +71 -71
package/internal.js
CHANGED
|
@@ -1,885 +1,885 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports._exposeCertSettings = exports._exposeProxySettings = exports._normalizeSeparators = exports._isRooted = exports._getDirectoryName = exports._ensureRooted = exports._isUncPath = exports._loadData = exports._ensurePatternRooted = exports._getFindInfoFromPattern = exports._cloneMatchOptions = exports._legacyFindFiles_convertPatternToRegExp = exports._which = exports._checkPath = exports._exist = exports._debug = exports._error = exports._warning = exports._command = exports._getVariableKey = exports._getVariable = exports._loc = exports._setResourcePath = exports._setErrStream = exports._setStdStream = exports._writeLine = exports._endsWith = exports._startsWith = exports._vault = exports._knownVariableMap = void 0;
|
|
4
|
-
var fs = require("fs");
|
|
5
|
-
var path = require("path");
|
|
6
|
-
var os = require("os");
|
|
7
|
-
var minimatch = require("minimatch");
|
|
8
|
-
var util = require("util");
|
|
9
|
-
var tcm = require("./taskcommand");
|
|
10
|
-
var vm = require("./vault");
|
|
11
|
-
var semver = require("semver");
|
|
12
|
-
var crypto = require("crypto");
|
|
13
|
-
/**
|
|
14
|
-
* Hash table of known variable info. The formatted env var name is the lookup key.
|
|
15
|
-
*
|
|
16
|
-
* The purpose of this hash table is to keep track of known variables. The hash table
|
|
17
|
-
* needs to be maintained for multiple reasons:
|
|
18
|
-
* 1) to distinguish between env vars and job vars
|
|
19
|
-
* 2) to distinguish between secret vars and public
|
|
20
|
-
* 3) to know the real variable name and not just the formatted env var name.
|
|
21
|
-
*/
|
|
22
|
-
exports._knownVariableMap = {};
|
|
23
|
-
//-----------------------------------------------------
|
|
24
|
-
// Validation Checks
|
|
25
|
-
//-----------------------------------------------------
|
|
26
|
-
// async await needs generators in node 4.x+
|
|
27
|
-
if (semver.lt(process.versions.node, '4.2.0')) {
|
|
28
|
-
_warning('Tasks require a new agent. Upgrade your agent or node to 4.2.0 or later');
|
|
29
|
-
}
|
|
30
|
-
//-----------------------------------------------------
|
|
31
|
-
// String convenience
|
|
32
|
-
//-----------------------------------------------------
|
|
33
|
-
function _startsWith(str, start) {
|
|
34
|
-
return str.slice(0, start.length) == start;
|
|
35
|
-
}
|
|
36
|
-
exports._startsWith = _startsWith;
|
|
37
|
-
function _endsWith(str, end) {
|
|
38
|
-
return str.slice(-end.length) == end;
|
|
39
|
-
}
|
|
40
|
-
exports._endsWith = _endsWith;
|
|
41
|
-
//-----------------------------------------------------
|
|
42
|
-
// General Helpers
|
|
43
|
-
//-----------------------------------------------------
|
|
44
|
-
var _outStream = process.stdout;
|
|
45
|
-
var _errStream = process.stderr;
|
|
46
|
-
function _writeLine(str) {
|
|
47
|
-
_outStream.write(str + os.EOL);
|
|
48
|
-
}
|
|
49
|
-
exports._writeLine = _writeLine;
|
|
50
|
-
function _setStdStream(stdStream) {
|
|
51
|
-
_outStream = stdStream;
|
|
52
|
-
}
|
|
53
|
-
exports._setStdStream = _setStdStream;
|
|
54
|
-
function _setErrStream(errStream) {
|
|
55
|
-
_errStream = errStream;
|
|
56
|
-
}
|
|
57
|
-
exports._setErrStream = _setErrStream;
|
|
58
|
-
//-----------------------------------------------------
|
|
59
|
-
// Loc Helpers
|
|
60
|
-
//-----------------------------------------------------
|
|
61
|
-
var _locStringCache = {};
|
|
62
|
-
var _resourceFiles = {};
|
|
63
|
-
var _libResourceFileLoaded = false;
|
|
64
|
-
var _resourceCulture = 'en-US';
|
|
65
|
-
function _loadResJson(resjsonFile) {
|
|
66
|
-
var resJson;
|
|
67
|
-
if (_exist(resjsonFile)) {
|
|
68
|
-
var resjsonContent = fs.readFileSync(resjsonFile, 'utf8').toString();
|
|
69
|
-
// remove BOM
|
|
70
|
-
if (resjsonContent.indexOf('\uFEFF') == 0) {
|
|
71
|
-
resjsonContent = resjsonContent.slice(1);
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
resJson = JSON.parse(resjsonContent);
|
|
75
|
-
}
|
|
76
|
-
catch (err) {
|
|
77
|
-
_debug('unable to parse resjson with err: ' + err.message);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
_debug('.resjson file not found: ' + resjsonFile);
|
|
82
|
-
}
|
|
83
|
-
return resJson;
|
|
84
|
-
}
|
|
85
|
-
function _loadLocStrings(resourceFile, culture) {
|
|
86
|
-
var locStrings = {};
|
|
87
|
-
if (_exist(resourceFile)) {
|
|
88
|
-
var resourceJson = require(resourceFile);
|
|
89
|
-
if (resourceJson && resourceJson.hasOwnProperty('messages')) {
|
|
90
|
-
var locResourceJson;
|
|
91
|
-
// load up resource resjson for different culture
|
|
92
|
-
var localizedResourceFile = path.join(path.dirname(resourceFile), 'Strings', 'resources.resjson');
|
|
93
|
-
var upperCulture = culture.toUpperCase();
|
|
94
|
-
var cultures = [];
|
|
95
|
-
try {
|
|
96
|
-
cultures = fs.readdirSync(localizedResourceFile);
|
|
97
|
-
}
|
|
98
|
-
catch (ex) { }
|
|
99
|
-
for (var i = 0; i < cultures.length; i++) {
|
|
100
|
-
if (cultures[i].toUpperCase() == upperCulture) {
|
|
101
|
-
localizedResourceFile = path.join(localizedResourceFile, cultures[i], 'resources.resjson');
|
|
102
|
-
if (_exist(localizedResourceFile)) {
|
|
103
|
-
locResourceJson = _loadResJson(localizedResourceFile);
|
|
104
|
-
}
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
for (var key in resourceJson.messages) {
|
|
109
|
-
if (locResourceJson && locResourceJson.hasOwnProperty('loc.messages.' + key)) {
|
|
110
|
-
locStrings[key] = locResourceJson['loc.messages.' + key];
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
locStrings[key] = resourceJson.messages[key];
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
_warning('LIB_ResourceFile does not exist');
|
|
120
|
-
}
|
|
121
|
-
return locStrings;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Sets the location of the resources json. This is typically the task.json file.
|
|
125
|
-
* Call once at the beginning of the script before any calls to loc.
|
|
126
|
-
* @param path Full path to the json.
|
|
127
|
-
* @param ignoreWarnings Won't throw warnings if path already set.
|
|
128
|
-
* @returns void
|
|
129
|
-
*/
|
|
130
|
-
function _setResourcePath(path, ignoreWarnings) {
|
|
131
|
-
if (ignoreWarnings === void 0) { ignoreWarnings = false; }
|
|
132
|
-
if (process.env['TASKLIB_INPROC_UNITS']) {
|
|
133
|
-
_resourceFiles = {};
|
|
134
|
-
_libResourceFileLoaded = false;
|
|
135
|
-
_locStringCache = {};
|
|
136
|
-
_resourceCulture = 'en-US';
|
|
137
|
-
}
|
|
138
|
-
if (!_resourceFiles[path]) {
|
|
139
|
-
_checkPath(path, 'resource file path');
|
|
140
|
-
_resourceFiles[path] = path;
|
|
141
|
-
_debug('adding resource file: ' + path);
|
|
142
|
-
_resourceCulture = _getVariable('system.culture') || _resourceCulture;
|
|
143
|
-
var locStrs = _loadLocStrings(path, _resourceCulture);
|
|
144
|
-
for (var key in locStrs) {
|
|
145
|
-
//cache loc string
|
|
146
|
-
_locStringCache[key] = locStrs[key];
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
if (ignoreWarnings) {
|
|
151
|
-
_debug(_loc('LIB_ResourceFileAlreadySet', path));
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
_warning(_loc('LIB_ResourceFileAlreadySet', path));
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
exports._setResourcePath = _setResourcePath;
|
|
159
|
-
/**
|
|
160
|
-
* Gets the localized string from the json resource file. Optionally formats with additional params.
|
|
161
|
-
*
|
|
162
|
-
* @param key key of the resources string in the resource file
|
|
163
|
-
* @param param additional params for formatting the string
|
|
164
|
-
* @returns string
|
|
165
|
-
*/
|
|
166
|
-
function _loc(key) {
|
|
167
|
-
var param = [];
|
|
168
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
169
|
-
param[_i - 1] = arguments[_i];
|
|
170
|
-
}
|
|
171
|
-
if (!_libResourceFileLoaded) {
|
|
172
|
-
// merge loc strings from azure-pipelines-task-lib.
|
|
173
|
-
var libResourceFile = path.join(__dirname, 'lib.json');
|
|
174
|
-
var libLocStrs = _loadLocStrings(libResourceFile, _resourceCulture);
|
|
175
|
-
for (var libKey in libLocStrs) {
|
|
176
|
-
//cache azure-pipelines-task-lib loc string
|
|
177
|
-
_locStringCache[libKey] = libLocStrs[libKey];
|
|
178
|
-
}
|
|
179
|
-
_libResourceFileLoaded = true;
|
|
180
|
-
}
|
|
181
|
-
var locString;
|
|
182
|
-
;
|
|
183
|
-
if (_locStringCache.hasOwnProperty(key)) {
|
|
184
|
-
locString = _locStringCache[key];
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
if (Object.keys(_resourceFiles).length <= 0) {
|
|
188
|
-
_warning("Resource file haven't been set, can't find loc string for key: " + key);
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
_warning("Can't find loc string for key: " + key);
|
|
192
|
-
}
|
|
193
|
-
locString = key;
|
|
194
|
-
}
|
|
195
|
-
if (param.length > 0) {
|
|
196
|
-
return util.format.apply(this, [locString].concat(param));
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
return locString;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
exports._loc = _loc;
|
|
203
|
-
//-----------------------------------------------------
|
|
204
|
-
// Input Helpers
|
|
205
|
-
//-----------------------------------------------------
|
|
206
|
-
/**
|
|
207
|
-
* Gets a variable value that is defined on the build/release definition or set at runtime.
|
|
208
|
-
*
|
|
209
|
-
* @param name name of the variable to get
|
|
210
|
-
* @returns string
|
|
211
|
-
*/
|
|
212
|
-
function _getVariable(name) {
|
|
213
|
-
var varval;
|
|
214
|
-
// get the metadata
|
|
215
|
-
var info;
|
|
216
|
-
var key = _getVariableKey(name);
|
|
217
|
-
if (exports._knownVariableMap.hasOwnProperty(key)) {
|
|
218
|
-
info = exports._knownVariableMap[key];
|
|
219
|
-
}
|
|
220
|
-
if (info && info.secret) {
|
|
221
|
-
// get the secret value
|
|
222
|
-
varval = exports._vault.retrieveSecret('SECRET_' + key);
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
// get the public value
|
|
226
|
-
varval = process.env[key];
|
|
227
|
-
// fallback for pre 2.104.1 agent
|
|
228
|
-
if (!varval && name.toUpperCase() == 'AGENT.JOBSTATUS') {
|
|
229
|
-
varval = process.env['agent.jobstatus'];
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
_debug(name + '=' + varval);
|
|
233
|
-
return varval;
|
|
234
|
-
}
|
|
235
|
-
exports._getVariable = _getVariable;
|
|
236
|
-
function _getVariableKey(name) {
|
|
237
|
-
if (!name) {
|
|
238
|
-
throw new Error(_loc('LIB_ParameterIsRequired', 'name'));
|
|
239
|
-
}
|
|
240
|
-
return name.replace(/\./g, '_').replace(/ /g, '_').toUpperCase();
|
|
241
|
-
}
|
|
242
|
-
exports._getVariableKey = _getVariableKey;
|
|
243
|
-
//-----------------------------------------------------
|
|
244
|
-
// Cmd Helpers
|
|
245
|
-
//-----------------------------------------------------
|
|
246
|
-
function _command(command, properties, message) {
|
|
247
|
-
var taskCmd = new tcm.TaskCommand(command, properties, message);
|
|
248
|
-
_writeLine(taskCmd.toString());
|
|
249
|
-
}
|
|
250
|
-
exports._command = _command;
|
|
251
|
-
function _warning(message) {
|
|
252
|
-
_command('task.issue', { 'type': 'warning' }, message);
|
|
253
|
-
}
|
|
254
|
-
exports._warning = _warning;
|
|
255
|
-
function _error(message) {
|
|
256
|
-
_command('task.issue', { 'type': 'error' }, message);
|
|
257
|
-
}
|
|
258
|
-
exports._error = _error;
|
|
259
|
-
function _debug(message) {
|
|
260
|
-
_command('task.debug', null, message);
|
|
261
|
-
}
|
|
262
|
-
exports._debug = _debug;
|
|
263
|
-
// //-----------------------------------------------------
|
|
264
|
-
// // Disk Functions
|
|
265
|
-
// //-----------------------------------------------------
|
|
266
|
-
/**
|
|
267
|
-
* Returns whether a path exists.
|
|
268
|
-
*
|
|
269
|
-
* @param path path to check
|
|
270
|
-
* @returns boolean
|
|
271
|
-
*/
|
|
272
|
-
function _exist(path) {
|
|
273
|
-
var exist = false;
|
|
274
|
-
try {
|
|
275
|
-
exist = !!(path && fs.statSync(path) != null);
|
|
276
|
-
}
|
|
277
|
-
catch (err) {
|
|
278
|
-
if (err && err.code === 'ENOENT') {
|
|
279
|
-
exist = false;
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
throw err;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return exist;
|
|
286
|
-
}
|
|
287
|
-
exports._exist = _exist;
|
|
288
|
-
/**
|
|
289
|
-
* Checks whether a path exists.
|
|
290
|
-
* If the path does not exist, it will throw.
|
|
291
|
-
*
|
|
292
|
-
* @param p path to check
|
|
293
|
-
* @param name name only used in error message to identify the path
|
|
294
|
-
* @returns void
|
|
295
|
-
*/
|
|
296
|
-
function _checkPath(p, name) {
|
|
297
|
-
_debug('check path : ' + p);
|
|
298
|
-
if (!_exist(p)) {
|
|
299
|
-
throw new Error(_loc('LIB_PathNotFound', name, p));
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
exports._checkPath = _checkPath;
|
|
303
|
-
/**
|
|
304
|
-
* Returns path of a tool had the tool actually been invoked. Resolves via paths.
|
|
305
|
-
* If you check and the tool does not exist, it will throw.
|
|
306
|
-
*
|
|
307
|
-
* @param tool name of the tool
|
|
308
|
-
* @param check whether to check if tool exists
|
|
309
|
-
* @returns string
|
|
310
|
-
*/
|
|
311
|
-
function _which(tool, check) {
|
|
312
|
-
if (!tool) {
|
|
313
|
-
throw new Error('parameter \'tool\' is required');
|
|
314
|
-
}
|
|
315
|
-
// recursive when check=true
|
|
316
|
-
if (check) {
|
|
317
|
-
var result = _which(tool, false);
|
|
318
|
-
if (result) {
|
|
319
|
-
return result;
|
|
320
|
-
}
|
|
321
|
-
else {
|
|
322
|
-
if (process.platform == 'win32') {
|
|
323
|
-
throw new Error(_loc('LIB_WhichNotFound_Win', tool));
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
throw new Error(_loc('LIB_WhichNotFound_Linux', tool));
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
_debug("which '" + tool + "'");
|
|
331
|
-
try {
|
|
332
|
-
// build the list of extensions to try
|
|
333
|
-
var extensions = [];
|
|
334
|
-
if (process.platform == 'win32' && process.env['PATHEXT']) {
|
|
335
|
-
for (var _i = 0, _a = process.env['PATHEXT'].split(path.delimiter); _i < _a.length; _i++) {
|
|
336
|
-
var extension = _a[_i];
|
|
337
|
-
if (extension) {
|
|
338
|
-
extensions.push(extension);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
// if it's rooted, return it if exists. otherwise return empty.
|
|
343
|
-
if (_isRooted(tool)) {
|
|
344
|
-
var filePath = _tryGetExecutablePath(tool, extensions);
|
|
345
|
-
if (filePath) {
|
|
346
|
-
_debug("found: '" + filePath + "'");
|
|
347
|
-
return filePath;
|
|
348
|
-
}
|
|
349
|
-
_debug('not found');
|
|
350
|
-
return '';
|
|
351
|
-
}
|
|
352
|
-
// if any path separators, return empty
|
|
353
|
-
if (tool.indexOf('/') >= 0 || (process.platform == 'win32' && tool.indexOf('\\') >= 0)) {
|
|
354
|
-
_debug('not found');
|
|
355
|
-
return '';
|
|
356
|
-
}
|
|
357
|
-
// build the list of directories
|
|
358
|
-
//
|
|
359
|
-
// Note, technically "where" checks the current directory on Windows. From a task lib perspective,
|
|
360
|
-
// it feels like we should not do this. Checking the current directory seems like more of a use
|
|
361
|
-
// case of a shell, and the which() function exposed by the task lib should strive for consistency
|
|
362
|
-
// across platforms.
|
|
363
|
-
var directories = [];
|
|
364
|
-
if (process.env['PATH']) {
|
|
365
|
-
for (var _b = 0, _c = process.env['PATH'].split(path.delimiter); _b < _c.length; _b++) {
|
|
366
|
-
var p = _c[_b];
|
|
367
|
-
if (p) {
|
|
368
|
-
directories.push(p);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
// return the first match
|
|
373
|
-
for (var _d = 0, directories_1 = directories; _d < directories_1.length; _d++) {
|
|
374
|
-
var directory = directories_1[_d];
|
|
375
|
-
var filePath = _tryGetExecutablePath(directory + path.sep + tool, extensions);
|
|
376
|
-
if (filePath) {
|
|
377
|
-
_debug("found: '" + filePath + "'");
|
|
378
|
-
return filePath;
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
_debug('not found');
|
|
382
|
-
return '';
|
|
383
|
-
}
|
|
384
|
-
catch (err) {
|
|
385
|
-
throw new Error(_loc('LIB_OperationFailed', 'which', err.message));
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
exports._which = _which;
|
|
389
|
-
/**
|
|
390
|
-
* Best effort attempt to determine whether a file exists and is executable.
|
|
391
|
-
* @param filePath file path to check
|
|
392
|
-
* @param extensions additional file extensions to try
|
|
393
|
-
* @return if file exists and is executable, returns the file path. otherwise empty string.
|
|
394
|
-
*/
|
|
395
|
-
function _tryGetExecutablePath(filePath, extensions) {
|
|
396
|
-
try {
|
|
397
|
-
// test file exists
|
|
398
|
-
var stats = fs.statSync(filePath);
|
|
399
|
-
if (stats.isFile()) {
|
|
400
|
-
if (process.platform == 'win32') {
|
|
401
|
-
// on Windows, test for valid extension
|
|
402
|
-
var isExecutable = false;
|
|
403
|
-
var fileName = path.basename(filePath);
|
|
404
|
-
var dotIndex = fileName.lastIndexOf('.');
|
|
405
|
-
if (dotIndex >= 0) {
|
|
406
|
-
var upperExt_1 = fileName.substr(dotIndex).toUpperCase();
|
|
407
|
-
if (extensions.some(function (validExt) { return validExt.toUpperCase() == upperExt_1; })) {
|
|
408
|
-
return filePath;
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
else {
|
|
413
|
-
if (isUnixExecutable(stats)) {
|
|
414
|
-
return filePath;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
catch (err) {
|
|
420
|
-
if (err.code != 'ENOENT') {
|
|
421
|
-
_debug("Unexpected error attempting to determine if executable file exists '" + filePath + "': " + err);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
// try each extension
|
|
425
|
-
var originalFilePath = filePath;
|
|
426
|
-
for (var _i = 0, extensions_1 = extensions; _i < extensions_1.length; _i++) {
|
|
427
|
-
var extension = extensions_1[_i];
|
|
428
|
-
var found = false;
|
|
429
|
-
var filePath_1 = originalFilePath + extension;
|
|
430
|
-
try {
|
|
431
|
-
var stats = fs.statSync(filePath_1);
|
|
432
|
-
if (stats.isFile()) {
|
|
433
|
-
if (process.platform == 'win32') {
|
|
434
|
-
// preserve the case of the actual file (since an extension was appended)
|
|
435
|
-
try {
|
|
436
|
-
var directory = path.dirname(filePath_1);
|
|
437
|
-
var upperName = path.basename(filePath_1).toUpperCase();
|
|
438
|
-
for (var _a = 0, _b = fs.readdirSync(directory); _a < _b.length; _a++) {
|
|
439
|
-
var actualName = _b[_a];
|
|
440
|
-
if (upperName == actualName.toUpperCase()) {
|
|
441
|
-
filePath_1 = path.join(directory, actualName);
|
|
442
|
-
break;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
catch (err) {
|
|
447
|
-
_debug("Unexpected error attempting to determine the actual case of the file '" + filePath_1 + "': " + err);
|
|
448
|
-
}
|
|
449
|
-
return filePath_1;
|
|
450
|
-
}
|
|
451
|
-
else {
|
|
452
|
-
if (isUnixExecutable(stats)) {
|
|
453
|
-
return filePath_1;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
catch (err) {
|
|
459
|
-
if (err.code != 'ENOENT') {
|
|
460
|
-
_debug("Unexpected error attempting to determine if executable file exists '" + filePath_1 + "': " + err);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
return '';
|
|
465
|
-
}
|
|
466
|
-
// on Mac/Linux, test the execute bit
|
|
467
|
-
// R W X R W X R W X
|
|
468
|
-
// 256 128 64 32 16 8 4 2 1
|
|
469
|
-
function isUnixExecutable(stats) {
|
|
470
|
-
return (stats.mode & 1) > 0 || ((stats.mode & 8) > 0 && stats.gid === process.getgid()) || ((stats.mode & 64) > 0 && stats.uid === process.getuid());
|
|
471
|
-
}
|
|
472
|
-
function _legacyFindFiles_convertPatternToRegExp(pattern) {
|
|
473
|
-
pattern = (process.platform == 'win32' ? pattern.replace(/\\/g, '/') : pattern) // normalize separator on Windows
|
|
474
|
-
.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') // regex escape - from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
|
|
475
|
-
.replace(/\\\/\\\*\\\*\\\//g, '((\/.+/)|(\/))') // replace directory globstar, e.g. /hello/**/world
|
|
476
|
-
.replace(/\\\*\\\*/g, '.*') // replace remaining globstars with a wildcard that can span directory separators, e.g. /hello/**dll
|
|
477
|
-
.replace(/\\\*/g, '[^\/]*') // replace asterisks with a wildcard that cannot span directory separators, e.g. /hello/*.dll
|
|
478
|
-
.replace(/\\\?/g, '[^\/]'); // replace single character wildcards, e.g. /hello/log?.dll
|
|
479
|
-
pattern = "^" + pattern + "$";
|
|
480
|
-
var flags = process.platform == 'win32' ? 'i' : '';
|
|
481
|
-
return new RegExp(pattern, flags);
|
|
482
|
-
}
|
|
483
|
-
exports._legacyFindFiles_convertPatternToRegExp = _legacyFindFiles_convertPatternToRegExp;
|
|
484
|
-
function _cloneMatchOptions(matchOptions) {
|
|
485
|
-
return {
|
|
486
|
-
debug: matchOptions.debug,
|
|
487
|
-
nobrace: matchOptions.nobrace,
|
|
488
|
-
noglobstar: matchOptions.noglobstar,
|
|
489
|
-
dot: matchOptions.dot,
|
|
490
|
-
noext: matchOptions.noext,
|
|
491
|
-
nocase: matchOptions.nocase,
|
|
492
|
-
nonull: matchOptions.nonull,
|
|
493
|
-
matchBase: matchOptions.matchBase,
|
|
494
|
-
nocomment: matchOptions.nocomment,
|
|
495
|
-
nonegate: matchOptions.nonegate,
|
|
496
|
-
flipNegate: matchOptions.flipNegate
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
exports._cloneMatchOptions = _cloneMatchOptions;
|
|
500
|
-
function _getFindInfoFromPattern(defaultRoot, pattern, matchOptions) {
|
|
501
|
-
// parameter validation
|
|
502
|
-
if (!defaultRoot) {
|
|
503
|
-
throw new Error('getFindRootFromPattern() parameter defaultRoot cannot be empty');
|
|
504
|
-
}
|
|
505
|
-
if (!pattern) {
|
|
506
|
-
throw new Error('getFindRootFromPattern() parameter pattern cannot be empty');
|
|
507
|
-
}
|
|
508
|
-
if (!matchOptions.nobrace) {
|
|
509
|
-
throw new Error('getFindRootFromPattern() expected matchOptions.nobrace to be true');
|
|
510
|
-
}
|
|
511
|
-
// for the sake of determining the findPath, pretend nocase=false
|
|
512
|
-
matchOptions = _cloneMatchOptions(matchOptions);
|
|
513
|
-
matchOptions.nocase = false;
|
|
514
|
-
// check if basename only and matchBase=true
|
|
515
|
-
if (matchOptions.matchBase &&
|
|
516
|
-
!_isRooted(pattern) &&
|
|
517
|
-
(process.platform == 'win32' ? pattern.replace(/\\/g, '/') : pattern).indexOf('/') < 0) {
|
|
518
|
-
return {
|
|
519
|
-
adjustedPattern: pattern,
|
|
520
|
-
findPath: defaultRoot,
|
|
521
|
-
statOnly: false,
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
// the technique applied by this function is to use the information on the Minimatch object determine
|
|
525
|
-
// the findPath. Minimatch breaks the pattern into path segments, and exposes information about which
|
|
526
|
-
// segments are literal vs patterns.
|
|
527
|
-
//
|
|
528
|
-
// note, the technique currently imposes a limitation for drive-relative paths with a glob in the
|
|
529
|
-
// first segment, e.g. C:hello*/world. it's feasible to overcome this limitation, but is left unsolved
|
|
530
|
-
// for now.
|
|
531
|
-
var minimatchObj = new minimatch.Minimatch(pattern, matchOptions);
|
|
532
|
-
// the "set" property is an array of arrays of parsed path segment info. the outer array should only
|
|
533
|
-
// contain one item, otherwise something went wrong. brace expansion can result in multiple arrays,
|
|
534
|
-
// but that should be turned off by the time this function is reached.
|
|
535
|
-
if (minimatchObj.set.length != 1) {
|
|
536
|
-
throw new Error('getFindRootFromPattern() expected Minimatch(...).set.length to be 1. Actual: ' + minimatchObj.set.length);
|
|
537
|
-
}
|
|
538
|
-
var literalSegments = [];
|
|
539
|
-
for (var _i = 0, _a = minimatchObj.set[0]; _i < _a.length; _i++) {
|
|
540
|
-
var parsedSegment = _a[_i];
|
|
541
|
-
if (typeof parsedSegment == 'string') {
|
|
542
|
-
// the item is a string when the original input for the path segment does not contain any
|
|
543
|
-
// unescaped glob characters.
|
|
544
|
-
//
|
|
545
|
-
// note, the string here is already unescaped (i.e. glob escaping removed), so it is ready
|
|
546
|
-
// to pass to find() as-is. for example, an input string 'hello\\*world' => 'hello*world'.
|
|
547
|
-
literalSegments.push(parsedSegment);
|
|
548
|
-
continue;
|
|
549
|
-
}
|
|
550
|
-
break;
|
|
551
|
-
}
|
|
552
|
-
// join the literal segments back together. Minimatch converts '\' to '/' on Windows, then squashes
|
|
553
|
-
// consequetive slashes, and finally splits on slash. this means that UNC format is lost, but can
|
|
554
|
-
// be detected from the original pattern.
|
|
555
|
-
var joinedSegments = literalSegments.join('/');
|
|
556
|
-
if (joinedSegments && process.platform == 'win32' && _startsWith(pattern.replace(/\\/g, '/'), '//')) {
|
|
557
|
-
joinedSegments = '/' + joinedSegments; // restore UNC format
|
|
558
|
-
}
|
|
559
|
-
// determine the find path
|
|
560
|
-
var findPath;
|
|
561
|
-
if (_isRooted(pattern)) { // the pattern was rooted
|
|
562
|
-
findPath = joinedSegments;
|
|
563
|
-
}
|
|
564
|
-
else if (joinedSegments) { // the pattern was not rooted, and literal segments were found
|
|
565
|
-
findPath = _ensureRooted(defaultRoot, joinedSegments);
|
|
566
|
-
}
|
|
567
|
-
else { // the pattern was not rooted, and no literal segments were found
|
|
568
|
-
findPath = defaultRoot;
|
|
569
|
-
}
|
|
570
|
-
// clean up the path
|
|
571
|
-
if (findPath) {
|
|
572
|
-
findPath = _getDirectoryName(_ensureRooted(findPath, '_')); // hack to remove unnecessary trailing slash
|
|
573
|
-
findPath = _normalizeSeparators(findPath); // normalize slashes
|
|
574
|
-
}
|
|
575
|
-
return {
|
|
576
|
-
adjustedPattern: _ensurePatternRooted(defaultRoot, pattern),
|
|
577
|
-
findPath: findPath,
|
|
578
|
-
statOnly: literalSegments.length == minimatchObj.set[0].length,
|
|
579
|
-
};
|
|
580
|
-
}
|
|
581
|
-
exports._getFindInfoFromPattern = _getFindInfoFromPattern;
|
|
582
|
-
function _ensurePatternRooted(root, p) {
|
|
583
|
-
if (!root) {
|
|
584
|
-
throw new Error('ensurePatternRooted() parameter "root" cannot be empty');
|
|
585
|
-
}
|
|
586
|
-
if (!p) {
|
|
587
|
-
throw new Error('ensurePatternRooted() parameter "p" cannot be empty');
|
|
588
|
-
}
|
|
589
|
-
if (_isRooted(p)) {
|
|
590
|
-
return p;
|
|
591
|
-
}
|
|
592
|
-
// normalize root
|
|
593
|
-
root = _normalizeSeparators(root);
|
|
594
|
-
// escape special glob characters
|
|
595
|
-
root = (process.platform == 'win32' ? root : root.replace(/\\/g, '\\\\')) // escape '\' on OSX/Linux
|
|
596
|
-
.replace(/(\[)(?=[^\/]+\])/g, '[[]') // escape '[' when ']' follows within the path segment
|
|
597
|
-
.replace(/\?/g, '[?]') // escape '?'
|
|
598
|
-
.replace(/\*/g, '[*]') // escape '*'
|
|
599
|
-
.replace(/\+\(/g, '[+](') // escape '+('
|
|
600
|
-
.replace(/@\(/g, '[@](') // escape '@('
|
|
601
|
-
.replace(/!\(/g, '[!]('); // escape '!('
|
|
602
|
-
return _ensureRooted(root, p);
|
|
603
|
-
}
|
|
604
|
-
exports._ensurePatternRooted = _ensurePatternRooted;
|
|
605
|
-
//-------------------------------------------------------------------
|
|
606
|
-
// Populate the vault with sensitive data. Inputs and Endpoints
|
|
607
|
-
//-------------------------------------------------------------------
|
|
608
|
-
function _loadData() {
|
|
609
|
-
// in agent, prefer TempDirectory then workFolder.
|
|
610
|
-
// In interactive dev mode, it won't be
|
|
611
|
-
var keyPath = _getVariable("agent.TempDirectory") || _getVariable("agent.workFolder") || process.cwd();
|
|
612
|
-
exports._vault = new vm.Vault(keyPath);
|
|
613
|
-
exports._knownVariableMap = {};
|
|
614
|
-
_debug('loading inputs and endpoints');
|
|
615
|
-
var loaded = 0;
|
|
616
|
-
for (var envvar in process.env) {
|
|
617
|
-
if (_startsWith(envvar, 'INPUT_') ||
|
|
618
|
-
_startsWith(envvar, 'ENDPOINT_AUTH_') ||
|
|
619
|
-
_startsWith(envvar, 'SECUREFILE_TICKET_') ||
|
|
620
|
-
_startsWith(envvar, 'SECRET_') ||
|
|
621
|
-
_startsWith(envvar, 'VSTS_TASKVARIABLE_')) {
|
|
622
|
-
// Record the secret variable metadata. This is required by getVariable to know whether
|
|
623
|
-
// to retrieve the value from the vault. In a 2.104.1 agent or higher, this metadata will
|
|
624
|
-
// be overwritten when the VSTS_SECRET_VARIABLES env var is processed below.
|
|
625
|
-
if (_startsWith(envvar, 'SECRET_')) {
|
|
626
|
-
var variableName = envvar.substring('SECRET_'.length);
|
|
627
|
-
if (variableName) {
|
|
628
|
-
// This is technically not the variable name (has underscores instead of dots),
|
|
629
|
-
// but it's good enough to make getVariable work in a pre-2.104.1 agent where
|
|
630
|
-
// the VSTS_SECRET_VARIABLES env var is not defined.
|
|
631
|
-
exports._knownVariableMap[_getVariableKey(variableName)] = { name: variableName, secret: true };
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
// store the secret
|
|
635
|
-
var value = process.env[envvar];
|
|
636
|
-
if (value) {
|
|
637
|
-
++loaded;
|
|
638
|
-
_debug('loading ' + envvar);
|
|
639
|
-
exports._vault.storeSecret(envvar, value);
|
|
640
|
-
delete process.env[envvar];
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
_debug('loaded ' + loaded);
|
|
645
|
-
// store public variable metadata
|
|
646
|
-
var names;
|
|
647
|
-
try {
|
|
648
|
-
names = JSON.parse(process.env['VSTS_PUBLIC_VARIABLES'] || '[]');
|
|
649
|
-
}
|
|
650
|
-
catch (err) {
|
|
651
|
-
throw new Error('Failed to parse VSTS_PUBLIC_VARIABLES as JSON. ' + err); // may occur during interactive testing
|
|
652
|
-
}
|
|
653
|
-
names.forEach(function (name) {
|
|
654
|
-
exports._knownVariableMap[_getVariableKey(name)] = { name: name, secret: false };
|
|
655
|
-
});
|
|
656
|
-
delete process.env['VSTS_PUBLIC_VARIABLES'];
|
|
657
|
-
// store secret variable metadata
|
|
658
|
-
try {
|
|
659
|
-
names = JSON.parse(process.env['VSTS_SECRET_VARIABLES'] || '[]');
|
|
660
|
-
}
|
|
661
|
-
catch (err) {
|
|
662
|
-
throw new Error('Failed to parse VSTS_SECRET_VARIABLES as JSON. ' + err); // may occur during interactive testing
|
|
663
|
-
}
|
|
664
|
-
names.forEach(function (name) {
|
|
665
|
-
exports._knownVariableMap[_getVariableKey(name)] = { name: name, secret: true };
|
|
666
|
-
});
|
|
667
|
-
delete process.env['VSTS_SECRET_VARIABLES'];
|
|
668
|
-
// avoid loading twice (overwrites .taskkey)
|
|
669
|
-
global['_vsts_task_lib_loaded'] = true;
|
|
670
|
-
}
|
|
671
|
-
exports._loadData = _loadData;
|
|
672
|
-
//--------------------------------------------------------------------------------
|
|
673
|
-
// Internal path helpers.
|
|
674
|
-
//--------------------------------------------------------------------------------
|
|
675
|
-
/**
|
|
676
|
-
* Defines if path is unc-path.
|
|
677
|
-
*
|
|
678
|
-
* @param path a path to a file.
|
|
679
|
-
* @returns true if path starts with double backslash, otherwise returns false.
|
|
680
|
-
*/
|
|
681
|
-
function _isUncPath(path) {
|
|
682
|
-
return /^\\\\[^\\]/.test(path);
|
|
683
|
-
}
|
|
684
|
-
exports._isUncPath = _isUncPath;
|
|
685
|
-
function _ensureRooted(root, p) {
|
|
686
|
-
if (!root) {
|
|
687
|
-
throw new Error('ensureRooted() parameter "root" cannot be empty');
|
|
688
|
-
}
|
|
689
|
-
if (!p) {
|
|
690
|
-
throw new Error('ensureRooted() parameter "p" cannot be empty');
|
|
691
|
-
}
|
|
692
|
-
if (_isRooted(p)) {
|
|
693
|
-
return p;
|
|
694
|
-
}
|
|
695
|
-
if (process.platform == 'win32' && root.match(/^[A-Z]:$/i)) { // e.g. C:
|
|
696
|
-
return root + p;
|
|
697
|
-
}
|
|
698
|
-
// ensure root ends with a separator
|
|
699
|
-
if (_endsWith(root, '/') || (process.platform == 'win32' && _endsWith(root, '\\'))) {
|
|
700
|
-
// root already ends with a separator
|
|
701
|
-
}
|
|
702
|
-
else {
|
|
703
|
-
root += path.sep; // append separator
|
|
704
|
-
}
|
|
705
|
-
return root + p;
|
|
706
|
-
}
|
|
707
|
-
exports._ensureRooted = _ensureRooted;
|
|
708
|
-
/**
|
|
709
|
-
* Determines the parent path and trims trailing slashes (when safe). Path separators are normalized
|
|
710
|
-
* in the result. This function works similar to the .NET System.IO.Path.GetDirectoryName() method.
|
|
711
|
-
* For example, C:\hello\world\ returns C:\hello\world (trailing slash removed). Returns empty when
|
|
712
|
-
* no higher directory can be determined.
|
|
713
|
-
*/
|
|
714
|
-
function _getDirectoryName(p) {
|
|
715
|
-
// short-circuit if empty
|
|
716
|
-
if (!p) {
|
|
717
|
-
return '';
|
|
718
|
-
}
|
|
719
|
-
// normalize separators
|
|
720
|
-
p = _normalizeSeparators(p);
|
|
721
|
-
// on Windows, the goal of this function is to match the behavior of
|
|
722
|
-
// [System.IO.Path]::GetDirectoryName(), e.g.
|
|
723
|
-
// C:/ =>
|
|
724
|
-
// C:/hello => C:\
|
|
725
|
-
// C:/hello/ => C:\hello
|
|
726
|
-
// C:/hello/world => C:\hello
|
|
727
|
-
// C:/hello/world/ => C:\hello\world
|
|
728
|
-
// C: =>
|
|
729
|
-
// C:hello => C:
|
|
730
|
-
// C:hello/ => C:hello
|
|
731
|
-
// / =>
|
|
732
|
-
// /hello => \
|
|
733
|
-
// /hello/ => \hello
|
|
734
|
-
// //hello =>
|
|
735
|
-
// //hello/ =>
|
|
736
|
-
// //hello/world =>
|
|
737
|
-
// //hello/world/ => \\hello\world
|
|
738
|
-
//
|
|
739
|
-
// unfortunately, path.dirname() can't simply be used. for example, on Windows
|
|
740
|
-
// it yields different results from Path.GetDirectoryName:
|
|
741
|
-
// C:/ => C:/
|
|
742
|
-
// C:/hello => C:/
|
|
743
|
-
// C:/hello/ => C:/
|
|
744
|
-
// C:/hello/world => C:/hello
|
|
745
|
-
// C:/hello/world/ => C:/hello
|
|
746
|
-
// C: => C:
|
|
747
|
-
// C:hello => C:
|
|
748
|
-
// C:hello/ => C:
|
|
749
|
-
// / => /
|
|
750
|
-
// /hello => /
|
|
751
|
-
// /hello/ => /
|
|
752
|
-
// //hello => /
|
|
753
|
-
// //hello/ => /
|
|
754
|
-
// //hello/world => //hello/world
|
|
755
|
-
// //hello/world/ => //hello/world/
|
|
756
|
-
// //hello/world/again => //hello/world/
|
|
757
|
-
// //hello/world/again/ => //hello/world/
|
|
758
|
-
// //hello/world/again/again => //hello/world/again
|
|
759
|
-
// //hello/world/again/again/ => //hello/world/again
|
|
760
|
-
if (process.platform == 'win32') {
|
|
761
|
-
if (/^[A-Z]:\\?[^\\]+$/i.test(p)) { // e.g. C:\hello or C:hello
|
|
762
|
-
return p.charAt(2) == '\\' ? p.substring(0, 3) : p.substring(0, 2);
|
|
763
|
-
}
|
|
764
|
-
else if (/^[A-Z]:\\?$/i.test(p)) { // e.g. C:\ or C:
|
|
765
|
-
return '';
|
|
766
|
-
}
|
|
767
|
-
var lastSlashIndex = p.lastIndexOf('\\');
|
|
768
|
-
if (lastSlashIndex < 0) { // file name only
|
|
769
|
-
return '';
|
|
770
|
-
}
|
|
771
|
-
else if (p == '\\') { // relative root
|
|
772
|
-
return '';
|
|
773
|
-
}
|
|
774
|
-
else if (lastSlashIndex == 0) { // e.g. \\hello
|
|
775
|
-
return '\\';
|
|
776
|
-
}
|
|
777
|
-
else if (/^\\\\[^\\]+(\\[^\\]*)?$/.test(p)) { // UNC root, e.g. \\hello or \\hello\ or \\hello\world
|
|
778
|
-
return '';
|
|
779
|
-
}
|
|
780
|
-
return p.substring(0, lastSlashIndex); // e.g. hello\world => hello or hello\world\ => hello\world
|
|
781
|
-
// note, this means trailing slashes for non-root directories
|
|
782
|
-
// (i.e. not C:\, \, or \\unc\) will simply be removed.
|
|
783
|
-
}
|
|
784
|
-
// OSX/Linux
|
|
785
|
-
if (p.indexOf('/') < 0) { // file name only
|
|
786
|
-
return '';
|
|
787
|
-
}
|
|
788
|
-
else if (p == '/') {
|
|
789
|
-
return '';
|
|
790
|
-
}
|
|
791
|
-
else if (_endsWith(p, '/')) {
|
|
792
|
-
return p.substring(0, p.length - 1);
|
|
793
|
-
}
|
|
794
|
-
return path.dirname(p);
|
|
795
|
-
}
|
|
796
|
-
exports._getDirectoryName = _getDirectoryName;
|
|
797
|
-
/**
|
|
798
|
-
* On OSX/Linux, true if path starts with '/'. On Windows, true for paths like:
|
|
799
|
-
* \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases).
|
|
800
|
-
*/
|
|
801
|
-
function _isRooted(p) {
|
|
802
|
-
p = _normalizeSeparators(p);
|
|
803
|
-
if (!p) {
|
|
804
|
-
throw new Error('isRooted() parameter "p" cannot be empty');
|
|
805
|
-
}
|
|
806
|
-
if (process.platform == 'win32') {
|
|
807
|
-
return _startsWith(p, '\\') || // e.g. \ or \hello or \\hello
|
|
808
|
-
/^[A-Z]:/i.test(p); // e.g. C: or C:\hello
|
|
809
|
-
}
|
|
810
|
-
return _startsWith(p, '/'); // e.g. /hello
|
|
811
|
-
}
|
|
812
|
-
exports._isRooted = _isRooted;
|
|
813
|
-
function _normalizeSeparators(p) {
|
|
814
|
-
p = p || '';
|
|
815
|
-
if (process.platform == 'win32') {
|
|
816
|
-
// convert slashes on Windows
|
|
817
|
-
p = p.replace(/\//g, '\\');
|
|
818
|
-
// remove redundant slashes
|
|
819
|
-
var isUnc = /^\\\\+[^\\]/.test(p); // e.g. \\hello
|
|
820
|
-
return (isUnc ? '\\' : '') + p.replace(/\\\\+/g, '\\'); // preserve leading // for UNC
|
|
821
|
-
}
|
|
822
|
-
// remove redundant slashes
|
|
823
|
-
return p.replace(/\/\/+/g, '/');
|
|
824
|
-
}
|
|
825
|
-
exports._normalizeSeparators = _normalizeSeparators;
|
|
826
|
-
//-----------------------------------------------------
|
|
827
|
-
// Expose proxy information to vsts-node-api
|
|
828
|
-
//-----------------------------------------------------
|
|
829
|
-
function _exposeProxySettings() {
|
|
830
|
-
var proxyUrl = _getVariable('Agent.ProxyUrl');
|
|
831
|
-
if (proxyUrl && proxyUrl.length > 0) {
|
|
832
|
-
var proxyUsername = _getVariable('Agent.ProxyUsername');
|
|
833
|
-
var proxyPassword = _getVariable('Agent.ProxyPassword');
|
|
834
|
-
var proxyBypassHostsJson = _getVariable('Agent.ProxyBypassList');
|
|
835
|
-
global['_vsts_task_lib_proxy_url'] = proxyUrl;
|
|
836
|
-
global['_vsts_task_lib_proxy_username'] = proxyUsername;
|
|
837
|
-
global['_vsts_task_lib_proxy_bypass'] = proxyBypassHostsJson;
|
|
838
|
-
global['_vsts_task_lib_proxy_password'] = _exposeTaskLibSecret('proxy', proxyPassword || '');
|
|
839
|
-
_debug('expose agent proxy configuration.');
|
|
840
|
-
global['_vsts_task_lib_proxy'] = true;
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
exports._exposeProxySettings = _exposeProxySettings;
|
|
844
|
-
//-----------------------------------------------------
|
|
845
|
-
// Expose certificate information to vsts-node-api
|
|
846
|
-
//-----------------------------------------------------
|
|
847
|
-
function _exposeCertSettings() {
|
|
848
|
-
var ca = _getVariable('Agent.CAInfo');
|
|
849
|
-
if (ca) {
|
|
850
|
-
global['_vsts_task_lib_cert_ca'] = ca;
|
|
851
|
-
}
|
|
852
|
-
var clientCert = _getVariable('Agent.ClientCert');
|
|
853
|
-
if (clientCert) {
|
|
854
|
-
var clientCertKey = _getVariable('Agent.ClientCertKey');
|
|
855
|
-
var clientCertArchive = _getVariable('Agent.ClientCertArchive');
|
|
856
|
-
var clientCertPassword = _getVariable('Agent.ClientCertPassword');
|
|
857
|
-
global['_vsts_task_lib_cert_clientcert'] = clientCert;
|
|
858
|
-
global['_vsts_task_lib_cert_key'] = clientCertKey;
|
|
859
|
-
global['_vsts_task_lib_cert_archive'] = clientCertArchive;
|
|
860
|
-
global['_vsts_task_lib_cert_passphrase'] = _exposeTaskLibSecret('cert', clientCertPassword || '');
|
|
861
|
-
}
|
|
862
|
-
if (ca || clientCert) {
|
|
863
|
-
_debug('expose agent certificate configuration.');
|
|
864
|
-
global['_vsts_task_lib_cert'] = true;
|
|
865
|
-
}
|
|
866
|
-
var skipCertValidation = _getVariable('Agent.SkipCertValidation') || 'false';
|
|
867
|
-
if (skipCertValidation) {
|
|
868
|
-
global['_vsts_task_lib_skip_cert_validation'] = skipCertValidation.toUpperCase() === 'TRUE';
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
exports._exposeCertSettings = _exposeCertSettings;
|
|
872
|
-
// We store the encryption key on disk and hold the encrypted content and key file in memory
|
|
873
|
-
// return base64encoded<keyFilePath>:base64encoded<encryptedContent>
|
|
874
|
-
// downstream vsts-node-api will retrieve the secret later
|
|
875
|
-
function _exposeTaskLibSecret(keyFile, secret) {
|
|
876
|
-
if (secret) {
|
|
877
|
-
var encryptKey = crypto.randomBytes(256);
|
|
878
|
-
var cipher = crypto.createCipher("aes-256-ctr", encryptKey);
|
|
879
|
-
var encryptedContent = cipher.update(secret, "utf8", "hex");
|
|
880
|
-
encryptedContent += cipher.final("hex");
|
|
881
|
-
var storageFile = path.join(_getVariable('Agent.TempDirectory') || _getVariable("agent.workFolder") || process.cwd(), keyFile);
|
|
882
|
-
fs.writeFileSync(storageFile, encryptKey.toString('base64'), { encoding: 'utf8' });
|
|
883
|
-
return new Buffer(storageFile).toString('base64') + ':' + new Buffer(encryptedContent).toString('base64');
|
|
884
|
-
}
|
|
885
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports._exposeCertSettings = exports._exposeProxySettings = exports._normalizeSeparators = exports._isRooted = exports._getDirectoryName = exports._ensureRooted = exports._isUncPath = exports._loadData = exports._ensurePatternRooted = exports._getFindInfoFromPattern = exports._cloneMatchOptions = exports._legacyFindFiles_convertPatternToRegExp = exports._which = exports._checkPath = exports._exist = exports._debug = exports._error = exports._warning = exports._command = exports._getVariableKey = exports._getVariable = exports._loc = exports._setResourcePath = exports._setErrStream = exports._setStdStream = exports._writeLine = exports._endsWith = exports._startsWith = exports._vault = exports._knownVariableMap = void 0;
|
|
4
|
+
var fs = require("fs");
|
|
5
|
+
var path = require("path");
|
|
6
|
+
var os = require("os");
|
|
7
|
+
var minimatch = require("minimatch");
|
|
8
|
+
var util = require("util");
|
|
9
|
+
var tcm = require("./taskcommand");
|
|
10
|
+
var vm = require("./vault");
|
|
11
|
+
var semver = require("semver");
|
|
12
|
+
var crypto = require("crypto");
|
|
13
|
+
/**
|
|
14
|
+
* Hash table of known variable info. The formatted env var name is the lookup key.
|
|
15
|
+
*
|
|
16
|
+
* The purpose of this hash table is to keep track of known variables. The hash table
|
|
17
|
+
* needs to be maintained for multiple reasons:
|
|
18
|
+
* 1) to distinguish between env vars and job vars
|
|
19
|
+
* 2) to distinguish between secret vars and public
|
|
20
|
+
* 3) to know the real variable name and not just the formatted env var name.
|
|
21
|
+
*/
|
|
22
|
+
exports._knownVariableMap = {};
|
|
23
|
+
//-----------------------------------------------------
|
|
24
|
+
// Validation Checks
|
|
25
|
+
//-----------------------------------------------------
|
|
26
|
+
// async await needs generators in node 4.x+
|
|
27
|
+
if (semver.lt(process.versions.node, '4.2.0')) {
|
|
28
|
+
_warning('Tasks require a new agent. Upgrade your agent or node to 4.2.0 or later');
|
|
29
|
+
}
|
|
30
|
+
//-----------------------------------------------------
|
|
31
|
+
// String convenience
|
|
32
|
+
//-----------------------------------------------------
|
|
33
|
+
function _startsWith(str, start) {
|
|
34
|
+
return str.slice(0, start.length) == start;
|
|
35
|
+
}
|
|
36
|
+
exports._startsWith = _startsWith;
|
|
37
|
+
function _endsWith(str, end) {
|
|
38
|
+
return str.slice(-end.length) == end;
|
|
39
|
+
}
|
|
40
|
+
exports._endsWith = _endsWith;
|
|
41
|
+
//-----------------------------------------------------
|
|
42
|
+
// General Helpers
|
|
43
|
+
//-----------------------------------------------------
|
|
44
|
+
var _outStream = process.stdout;
|
|
45
|
+
var _errStream = process.stderr;
|
|
46
|
+
function _writeLine(str) {
|
|
47
|
+
_outStream.write(str + os.EOL);
|
|
48
|
+
}
|
|
49
|
+
exports._writeLine = _writeLine;
|
|
50
|
+
function _setStdStream(stdStream) {
|
|
51
|
+
_outStream = stdStream;
|
|
52
|
+
}
|
|
53
|
+
exports._setStdStream = _setStdStream;
|
|
54
|
+
function _setErrStream(errStream) {
|
|
55
|
+
_errStream = errStream;
|
|
56
|
+
}
|
|
57
|
+
exports._setErrStream = _setErrStream;
|
|
58
|
+
//-----------------------------------------------------
|
|
59
|
+
// Loc Helpers
|
|
60
|
+
//-----------------------------------------------------
|
|
61
|
+
var _locStringCache = {};
|
|
62
|
+
var _resourceFiles = {};
|
|
63
|
+
var _libResourceFileLoaded = false;
|
|
64
|
+
var _resourceCulture = 'en-US';
|
|
65
|
+
function _loadResJson(resjsonFile) {
|
|
66
|
+
var resJson;
|
|
67
|
+
if (_exist(resjsonFile)) {
|
|
68
|
+
var resjsonContent = fs.readFileSync(resjsonFile, 'utf8').toString();
|
|
69
|
+
// remove BOM
|
|
70
|
+
if (resjsonContent.indexOf('\uFEFF') == 0) {
|
|
71
|
+
resjsonContent = resjsonContent.slice(1);
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
resJson = JSON.parse(resjsonContent);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
_debug('unable to parse resjson with err: ' + err.message);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
_debug('.resjson file not found: ' + resjsonFile);
|
|
82
|
+
}
|
|
83
|
+
return resJson;
|
|
84
|
+
}
|
|
85
|
+
function _loadLocStrings(resourceFile, culture) {
|
|
86
|
+
var locStrings = {};
|
|
87
|
+
if (_exist(resourceFile)) {
|
|
88
|
+
var resourceJson = require(resourceFile);
|
|
89
|
+
if (resourceJson && resourceJson.hasOwnProperty('messages')) {
|
|
90
|
+
var locResourceJson;
|
|
91
|
+
// load up resource resjson for different culture
|
|
92
|
+
var localizedResourceFile = path.join(path.dirname(resourceFile), 'Strings', 'resources.resjson');
|
|
93
|
+
var upperCulture = culture.toUpperCase();
|
|
94
|
+
var cultures = [];
|
|
95
|
+
try {
|
|
96
|
+
cultures = fs.readdirSync(localizedResourceFile);
|
|
97
|
+
}
|
|
98
|
+
catch (ex) { }
|
|
99
|
+
for (var i = 0; i < cultures.length; i++) {
|
|
100
|
+
if (cultures[i].toUpperCase() == upperCulture) {
|
|
101
|
+
localizedResourceFile = path.join(localizedResourceFile, cultures[i], 'resources.resjson');
|
|
102
|
+
if (_exist(localizedResourceFile)) {
|
|
103
|
+
locResourceJson = _loadResJson(localizedResourceFile);
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
for (var key in resourceJson.messages) {
|
|
109
|
+
if (locResourceJson && locResourceJson.hasOwnProperty('loc.messages.' + key)) {
|
|
110
|
+
locStrings[key] = locResourceJson['loc.messages.' + key];
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
locStrings[key] = resourceJson.messages[key];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
_warning('LIB_ResourceFile does not exist');
|
|
120
|
+
}
|
|
121
|
+
return locStrings;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Sets the location of the resources json. This is typically the task.json file.
|
|
125
|
+
* Call once at the beginning of the script before any calls to loc.
|
|
126
|
+
* @param path Full path to the json.
|
|
127
|
+
* @param ignoreWarnings Won't throw warnings if path already set.
|
|
128
|
+
* @returns void
|
|
129
|
+
*/
|
|
130
|
+
function _setResourcePath(path, ignoreWarnings) {
|
|
131
|
+
if (ignoreWarnings === void 0) { ignoreWarnings = false; }
|
|
132
|
+
if (process.env['TASKLIB_INPROC_UNITS']) {
|
|
133
|
+
_resourceFiles = {};
|
|
134
|
+
_libResourceFileLoaded = false;
|
|
135
|
+
_locStringCache = {};
|
|
136
|
+
_resourceCulture = 'en-US';
|
|
137
|
+
}
|
|
138
|
+
if (!_resourceFiles[path]) {
|
|
139
|
+
_checkPath(path, 'resource file path');
|
|
140
|
+
_resourceFiles[path] = path;
|
|
141
|
+
_debug('adding resource file: ' + path);
|
|
142
|
+
_resourceCulture = _getVariable('system.culture') || _resourceCulture;
|
|
143
|
+
var locStrs = _loadLocStrings(path, _resourceCulture);
|
|
144
|
+
for (var key in locStrs) {
|
|
145
|
+
//cache loc string
|
|
146
|
+
_locStringCache[key] = locStrs[key];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
if (ignoreWarnings) {
|
|
151
|
+
_debug(_loc('LIB_ResourceFileAlreadySet', path));
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
_warning(_loc('LIB_ResourceFileAlreadySet', path));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports._setResourcePath = _setResourcePath;
|
|
159
|
+
/**
|
|
160
|
+
* Gets the localized string from the json resource file. Optionally formats with additional params.
|
|
161
|
+
*
|
|
162
|
+
* @param key key of the resources string in the resource file
|
|
163
|
+
* @param param additional params for formatting the string
|
|
164
|
+
* @returns string
|
|
165
|
+
*/
|
|
166
|
+
function _loc(key) {
|
|
167
|
+
var param = [];
|
|
168
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
169
|
+
param[_i - 1] = arguments[_i];
|
|
170
|
+
}
|
|
171
|
+
if (!_libResourceFileLoaded) {
|
|
172
|
+
// merge loc strings from azure-pipelines-task-lib.
|
|
173
|
+
var libResourceFile = path.join(__dirname, 'lib.json');
|
|
174
|
+
var libLocStrs = _loadLocStrings(libResourceFile, _resourceCulture);
|
|
175
|
+
for (var libKey in libLocStrs) {
|
|
176
|
+
//cache azure-pipelines-task-lib loc string
|
|
177
|
+
_locStringCache[libKey] = libLocStrs[libKey];
|
|
178
|
+
}
|
|
179
|
+
_libResourceFileLoaded = true;
|
|
180
|
+
}
|
|
181
|
+
var locString;
|
|
182
|
+
;
|
|
183
|
+
if (_locStringCache.hasOwnProperty(key)) {
|
|
184
|
+
locString = _locStringCache[key];
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
if (Object.keys(_resourceFiles).length <= 0) {
|
|
188
|
+
_warning("Resource file haven't been set, can't find loc string for key: " + key);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
_warning("Can't find loc string for key: " + key);
|
|
192
|
+
}
|
|
193
|
+
locString = key;
|
|
194
|
+
}
|
|
195
|
+
if (param.length > 0) {
|
|
196
|
+
return util.format.apply(this, [locString].concat(param));
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
return locString;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
exports._loc = _loc;
|
|
203
|
+
//-----------------------------------------------------
|
|
204
|
+
// Input Helpers
|
|
205
|
+
//-----------------------------------------------------
|
|
206
|
+
/**
|
|
207
|
+
* Gets a variable value that is defined on the build/release definition or set at runtime.
|
|
208
|
+
*
|
|
209
|
+
* @param name name of the variable to get
|
|
210
|
+
* @returns string
|
|
211
|
+
*/
|
|
212
|
+
function _getVariable(name) {
|
|
213
|
+
var varval;
|
|
214
|
+
// get the metadata
|
|
215
|
+
var info;
|
|
216
|
+
var key = _getVariableKey(name);
|
|
217
|
+
if (exports._knownVariableMap.hasOwnProperty(key)) {
|
|
218
|
+
info = exports._knownVariableMap[key];
|
|
219
|
+
}
|
|
220
|
+
if (info && info.secret) {
|
|
221
|
+
// get the secret value
|
|
222
|
+
varval = exports._vault.retrieveSecret('SECRET_' + key);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
// get the public value
|
|
226
|
+
varval = process.env[key];
|
|
227
|
+
// fallback for pre 2.104.1 agent
|
|
228
|
+
if (!varval && name.toUpperCase() == 'AGENT.JOBSTATUS') {
|
|
229
|
+
varval = process.env['agent.jobstatus'];
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
_debug(name + '=' + varval);
|
|
233
|
+
return varval;
|
|
234
|
+
}
|
|
235
|
+
exports._getVariable = _getVariable;
|
|
236
|
+
function _getVariableKey(name) {
|
|
237
|
+
if (!name) {
|
|
238
|
+
throw new Error(_loc('LIB_ParameterIsRequired', 'name'));
|
|
239
|
+
}
|
|
240
|
+
return name.replace(/\./g, '_').replace(/ /g, '_').toUpperCase();
|
|
241
|
+
}
|
|
242
|
+
exports._getVariableKey = _getVariableKey;
|
|
243
|
+
//-----------------------------------------------------
|
|
244
|
+
// Cmd Helpers
|
|
245
|
+
//-----------------------------------------------------
|
|
246
|
+
function _command(command, properties, message) {
|
|
247
|
+
var taskCmd = new tcm.TaskCommand(command, properties, message);
|
|
248
|
+
_writeLine(taskCmd.toString());
|
|
249
|
+
}
|
|
250
|
+
exports._command = _command;
|
|
251
|
+
function _warning(message) {
|
|
252
|
+
_command('task.issue', { 'type': 'warning' }, message);
|
|
253
|
+
}
|
|
254
|
+
exports._warning = _warning;
|
|
255
|
+
function _error(message) {
|
|
256
|
+
_command('task.issue', { 'type': 'error' }, message);
|
|
257
|
+
}
|
|
258
|
+
exports._error = _error;
|
|
259
|
+
function _debug(message) {
|
|
260
|
+
_command('task.debug', null, message);
|
|
261
|
+
}
|
|
262
|
+
exports._debug = _debug;
|
|
263
|
+
// //-----------------------------------------------------
|
|
264
|
+
// // Disk Functions
|
|
265
|
+
// //-----------------------------------------------------
|
|
266
|
+
/**
|
|
267
|
+
* Returns whether a path exists.
|
|
268
|
+
*
|
|
269
|
+
* @param path path to check
|
|
270
|
+
* @returns boolean
|
|
271
|
+
*/
|
|
272
|
+
function _exist(path) {
|
|
273
|
+
var exist = false;
|
|
274
|
+
try {
|
|
275
|
+
exist = !!(path && fs.statSync(path) != null);
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
if (err && err.code === 'ENOENT') {
|
|
279
|
+
exist = false;
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
throw err;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return exist;
|
|
286
|
+
}
|
|
287
|
+
exports._exist = _exist;
|
|
288
|
+
/**
|
|
289
|
+
* Checks whether a path exists.
|
|
290
|
+
* If the path does not exist, it will throw.
|
|
291
|
+
*
|
|
292
|
+
* @param p path to check
|
|
293
|
+
* @param name name only used in error message to identify the path
|
|
294
|
+
* @returns void
|
|
295
|
+
*/
|
|
296
|
+
function _checkPath(p, name) {
|
|
297
|
+
_debug('check path : ' + p);
|
|
298
|
+
if (!_exist(p)) {
|
|
299
|
+
throw new Error(_loc('LIB_PathNotFound', name, p));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
exports._checkPath = _checkPath;
|
|
303
|
+
/**
|
|
304
|
+
* Returns path of a tool had the tool actually been invoked. Resolves via paths.
|
|
305
|
+
* If you check and the tool does not exist, it will throw.
|
|
306
|
+
*
|
|
307
|
+
* @param tool name of the tool
|
|
308
|
+
* @param check whether to check if tool exists
|
|
309
|
+
* @returns string
|
|
310
|
+
*/
|
|
311
|
+
function _which(tool, check) {
|
|
312
|
+
if (!tool) {
|
|
313
|
+
throw new Error('parameter \'tool\' is required');
|
|
314
|
+
}
|
|
315
|
+
// recursive when check=true
|
|
316
|
+
if (check) {
|
|
317
|
+
var result = _which(tool, false);
|
|
318
|
+
if (result) {
|
|
319
|
+
return result;
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
if (process.platform == 'win32') {
|
|
323
|
+
throw new Error(_loc('LIB_WhichNotFound_Win', tool));
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
throw new Error(_loc('LIB_WhichNotFound_Linux', tool));
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
_debug("which '" + tool + "'");
|
|
331
|
+
try {
|
|
332
|
+
// build the list of extensions to try
|
|
333
|
+
var extensions = [];
|
|
334
|
+
if (process.platform == 'win32' && process.env['PATHEXT']) {
|
|
335
|
+
for (var _i = 0, _a = process.env['PATHEXT'].split(path.delimiter); _i < _a.length; _i++) {
|
|
336
|
+
var extension = _a[_i];
|
|
337
|
+
if (extension) {
|
|
338
|
+
extensions.push(extension);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// if it's rooted, return it if exists. otherwise return empty.
|
|
343
|
+
if (_isRooted(tool)) {
|
|
344
|
+
var filePath = _tryGetExecutablePath(tool, extensions);
|
|
345
|
+
if (filePath) {
|
|
346
|
+
_debug("found: '" + filePath + "'");
|
|
347
|
+
return filePath;
|
|
348
|
+
}
|
|
349
|
+
_debug('not found');
|
|
350
|
+
return '';
|
|
351
|
+
}
|
|
352
|
+
// if any path separators, return empty
|
|
353
|
+
if (tool.indexOf('/') >= 0 || (process.platform == 'win32' && tool.indexOf('\\') >= 0)) {
|
|
354
|
+
_debug('not found');
|
|
355
|
+
return '';
|
|
356
|
+
}
|
|
357
|
+
// build the list of directories
|
|
358
|
+
//
|
|
359
|
+
// Note, technically "where" checks the current directory on Windows. From a task lib perspective,
|
|
360
|
+
// it feels like we should not do this. Checking the current directory seems like more of a use
|
|
361
|
+
// case of a shell, and the which() function exposed by the task lib should strive for consistency
|
|
362
|
+
// across platforms.
|
|
363
|
+
var directories = [];
|
|
364
|
+
if (process.env['PATH']) {
|
|
365
|
+
for (var _b = 0, _c = process.env['PATH'].split(path.delimiter); _b < _c.length; _b++) {
|
|
366
|
+
var p = _c[_b];
|
|
367
|
+
if (p) {
|
|
368
|
+
directories.push(p);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// return the first match
|
|
373
|
+
for (var _d = 0, directories_1 = directories; _d < directories_1.length; _d++) {
|
|
374
|
+
var directory = directories_1[_d];
|
|
375
|
+
var filePath = _tryGetExecutablePath(directory + path.sep + tool, extensions);
|
|
376
|
+
if (filePath) {
|
|
377
|
+
_debug("found: '" + filePath + "'");
|
|
378
|
+
return filePath;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
_debug('not found');
|
|
382
|
+
return '';
|
|
383
|
+
}
|
|
384
|
+
catch (err) {
|
|
385
|
+
throw new Error(_loc('LIB_OperationFailed', 'which', err.message));
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
exports._which = _which;
|
|
389
|
+
/**
|
|
390
|
+
* Best effort attempt to determine whether a file exists and is executable.
|
|
391
|
+
* @param filePath file path to check
|
|
392
|
+
* @param extensions additional file extensions to try
|
|
393
|
+
* @return if file exists and is executable, returns the file path. otherwise empty string.
|
|
394
|
+
*/
|
|
395
|
+
function _tryGetExecutablePath(filePath, extensions) {
|
|
396
|
+
try {
|
|
397
|
+
// test file exists
|
|
398
|
+
var stats = fs.statSync(filePath);
|
|
399
|
+
if (stats.isFile()) {
|
|
400
|
+
if (process.platform == 'win32') {
|
|
401
|
+
// on Windows, test for valid extension
|
|
402
|
+
var isExecutable = false;
|
|
403
|
+
var fileName = path.basename(filePath);
|
|
404
|
+
var dotIndex = fileName.lastIndexOf('.');
|
|
405
|
+
if (dotIndex >= 0) {
|
|
406
|
+
var upperExt_1 = fileName.substr(dotIndex).toUpperCase();
|
|
407
|
+
if (extensions.some(function (validExt) { return validExt.toUpperCase() == upperExt_1; })) {
|
|
408
|
+
return filePath;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
if (isUnixExecutable(stats)) {
|
|
414
|
+
return filePath;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
catch (err) {
|
|
420
|
+
if (err.code != 'ENOENT') {
|
|
421
|
+
_debug("Unexpected error attempting to determine if executable file exists '" + filePath + "': " + err);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
// try each extension
|
|
425
|
+
var originalFilePath = filePath;
|
|
426
|
+
for (var _i = 0, extensions_1 = extensions; _i < extensions_1.length; _i++) {
|
|
427
|
+
var extension = extensions_1[_i];
|
|
428
|
+
var found = false;
|
|
429
|
+
var filePath_1 = originalFilePath + extension;
|
|
430
|
+
try {
|
|
431
|
+
var stats = fs.statSync(filePath_1);
|
|
432
|
+
if (stats.isFile()) {
|
|
433
|
+
if (process.platform == 'win32') {
|
|
434
|
+
// preserve the case of the actual file (since an extension was appended)
|
|
435
|
+
try {
|
|
436
|
+
var directory = path.dirname(filePath_1);
|
|
437
|
+
var upperName = path.basename(filePath_1).toUpperCase();
|
|
438
|
+
for (var _a = 0, _b = fs.readdirSync(directory); _a < _b.length; _a++) {
|
|
439
|
+
var actualName = _b[_a];
|
|
440
|
+
if (upperName == actualName.toUpperCase()) {
|
|
441
|
+
filePath_1 = path.join(directory, actualName);
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
catch (err) {
|
|
447
|
+
_debug("Unexpected error attempting to determine the actual case of the file '" + filePath_1 + "': " + err);
|
|
448
|
+
}
|
|
449
|
+
return filePath_1;
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
if (isUnixExecutable(stats)) {
|
|
453
|
+
return filePath_1;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
catch (err) {
|
|
459
|
+
if (err.code != 'ENOENT') {
|
|
460
|
+
_debug("Unexpected error attempting to determine if executable file exists '" + filePath_1 + "': " + err);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return '';
|
|
465
|
+
}
|
|
466
|
+
// on Mac/Linux, test the execute bit
|
|
467
|
+
// R W X R W X R W X
|
|
468
|
+
// 256 128 64 32 16 8 4 2 1
|
|
469
|
+
function isUnixExecutable(stats) {
|
|
470
|
+
return (stats.mode & 1) > 0 || ((stats.mode & 8) > 0 && stats.gid === process.getgid()) || ((stats.mode & 64) > 0 && stats.uid === process.getuid());
|
|
471
|
+
}
|
|
472
|
+
function _legacyFindFiles_convertPatternToRegExp(pattern) {
|
|
473
|
+
pattern = (process.platform == 'win32' ? pattern.replace(/\\/g, '/') : pattern) // normalize separator on Windows
|
|
474
|
+
.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') // regex escape - from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
|
|
475
|
+
.replace(/\\\/\\\*\\\*\\\//g, '((\/.+/)|(\/))') // replace directory globstar, e.g. /hello/**/world
|
|
476
|
+
.replace(/\\\*\\\*/g, '.*') // replace remaining globstars with a wildcard that can span directory separators, e.g. /hello/**dll
|
|
477
|
+
.replace(/\\\*/g, '[^\/]*') // replace asterisks with a wildcard that cannot span directory separators, e.g. /hello/*.dll
|
|
478
|
+
.replace(/\\\?/g, '[^\/]'); // replace single character wildcards, e.g. /hello/log?.dll
|
|
479
|
+
pattern = "^" + pattern + "$";
|
|
480
|
+
var flags = process.platform == 'win32' ? 'i' : '';
|
|
481
|
+
return new RegExp(pattern, flags);
|
|
482
|
+
}
|
|
483
|
+
exports._legacyFindFiles_convertPatternToRegExp = _legacyFindFiles_convertPatternToRegExp;
|
|
484
|
+
function _cloneMatchOptions(matchOptions) {
|
|
485
|
+
return {
|
|
486
|
+
debug: matchOptions.debug,
|
|
487
|
+
nobrace: matchOptions.nobrace,
|
|
488
|
+
noglobstar: matchOptions.noglobstar,
|
|
489
|
+
dot: matchOptions.dot,
|
|
490
|
+
noext: matchOptions.noext,
|
|
491
|
+
nocase: matchOptions.nocase,
|
|
492
|
+
nonull: matchOptions.nonull,
|
|
493
|
+
matchBase: matchOptions.matchBase,
|
|
494
|
+
nocomment: matchOptions.nocomment,
|
|
495
|
+
nonegate: matchOptions.nonegate,
|
|
496
|
+
flipNegate: matchOptions.flipNegate
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
exports._cloneMatchOptions = _cloneMatchOptions;
|
|
500
|
+
function _getFindInfoFromPattern(defaultRoot, pattern, matchOptions) {
|
|
501
|
+
// parameter validation
|
|
502
|
+
if (!defaultRoot) {
|
|
503
|
+
throw new Error('getFindRootFromPattern() parameter defaultRoot cannot be empty');
|
|
504
|
+
}
|
|
505
|
+
if (!pattern) {
|
|
506
|
+
throw new Error('getFindRootFromPattern() parameter pattern cannot be empty');
|
|
507
|
+
}
|
|
508
|
+
if (!matchOptions.nobrace) {
|
|
509
|
+
throw new Error('getFindRootFromPattern() expected matchOptions.nobrace to be true');
|
|
510
|
+
}
|
|
511
|
+
// for the sake of determining the findPath, pretend nocase=false
|
|
512
|
+
matchOptions = _cloneMatchOptions(matchOptions);
|
|
513
|
+
matchOptions.nocase = false;
|
|
514
|
+
// check if basename only and matchBase=true
|
|
515
|
+
if (matchOptions.matchBase &&
|
|
516
|
+
!_isRooted(pattern) &&
|
|
517
|
+
(process.platform == 'win32' ? pattern.replace(/\\/g, '/') : pattern).indexOf('/') < 0) {
|
|
518
|
+
return {
|
|
519
|
+
adjustedPattern: pattern,
|
|
520
|
+
findPath: defaultRoot,
|
|
521
|
+
statOnly: false,
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
// the technique applied by this function is to use the information on the Minimatch object determine
|
|
525
|
+
// the findPath. Minimatch breaks the pattern into path segments, and exposes information about which
|
|
526
|
+
// segments are literal vs patterns.
|
|
527
|
+
//
|
|
528
|
+
// note, the technique currently imposes a limitation for drive-relative paths with a glob in the
|
|
529
|
+
// first segment, e.g. C:hello*/world. it's feasible to overcome this limitation, but is left unsolved
|
|
530
|
+
// for now.
|
|
531
|
+
var minimatchObj = new minimatch.Minimatch(pattern, matchOptions);
|
|
532
|
+
// the "set" property is an array of arrays of parsed path segment info. the outer array should only
|
|
533
|
+
// contain one item, otherwise something went wrong. brace expansion can result in multiple arrays,
|
|
534
|
+
// but that should be turned off by the time this function is reached.
|
|
535
|
+
if (minimatchObj.set.length != 1) {
|
|
536
|
+
throw new Error('getFindRootFromPattern() expected Minimatch(...).set.length to be 1. Actual: ' + minimatchObj.set.length);
|
|
537
|
+
}
|
|
538
|
+
var literalSegments = [];
|
|
539
|
+
for (var _i = 0, _a = minimatchObj.set[0]; _i < _a.length; _i++) {
|
|
540
|
+
var parsedSegment = _a[_i];
|
|
541
|
+
if (typeof parsedSegment == 'string') {
|
|
542
|
+
// the item is a string when the original input for the path segment does not contain any
|
|
543
|
+
// unescaped glob characters.
|
|
544
|
+
//
|
|
545
|
+
// note, the string here is already unescaped (i.e. glob escaping removed), so it is ready
|
|
546
|
+
// to pass to find() as-is. for example, an input string 'hello\\*world' => 'hello*world'.
|
|
547
|
+
literalSegments.push(parsedSegment);
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
// join the literal segments back together. Minimatch converts '\' to '/' on Windows, then squashes
|
|
553
|
+
// consequetive slashes, and finally splits on slash. this means that UNC format is lost, but can
|
|
554
|
+
// be detected from the original pattern.
|
|
555
|
+
var joinedSegments = literalSegments.join('/');
|
|
556
|
+
if (joinedSegments && process.platform == 'win32' && _startsWith(pattern.replace(/\\/g, '/'), '//')) {
|
|
557
|
+
joinedSegments = '/' + joinedSegments; // restore UNC format
|
|
558
|
+
}
|
|
559
|
+
// determine the find path
|
|
560
|
+
var findPath;
|
|
561
|
+
if (_isRooted(pattern)) { // the pattern was rooted
|
|
562
|
+
findPath = joinedSegments;
|
|
563
|
+
}
|
|
564
|
+
else if (joinedSegments) { // the pattern was not rooted, and literal segments were found
|
|
565
|
+
findPath = _ensureRooted(defaultRoot, joinedSegments);
|
|
566
|
+
}
|
|
567
|
+
else { // the pattern was not rooted, and no literal segments were found
|
|
568
|
+
findPath = defaultRoot;
|
|
569
|
+
}
|
|
570
|
+
// clean up the path
|
|
571
|
+
if (findPath) {
|
|
572
|
+
findPath = _getDirectoryName(_ensureRooted(findPath, '_')); // hack to remove unnecessary trailing slash
|
|
573
|
+
findPath = _normalizeSeparators(findPath); // normalize slashes
|
|
574
|
+
}
|
|
575
|
+
return {
|
|
576
|
+
adjustedPattern: _ensurePatternRooted(defaultRoot, pattern),
|
|
577
|
+
findPath: findPath,
|
|
578
|
+
statOnly: literalSegments.length == minimatchObj.set[0].length,
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
exports._getFindInfoFromPattern = _getFindInfoFromPattern;
|
|
582
|
+
function _ensurePatternRooted(root, p) {
|
|
583
|
+
if (!root) {
|
|
584
|
+
throw new Error('ensurePatternRooted() parameter "root" cannot be empty');
|
|
585
|
+
}
|
|
586
|
+
if (!p) {
|
|
587
|
+
throw new Error('ensurePatternRooted() parameter "p" cannot be empty');
|
|
588
|
+
}
|
|
589
|
+
if (_isRooted(p)) {
|
|
590
|
+
return p;
|
|
591
|
+
}
|
|
592
|
+
// normalize root
|
|
593
|
+
root = _normalizeSeparators(root);
|
|
594
|
+
// escape special glob characters
|
|
595
|
+
root = (process.platform == 'win32' ? root : root.replace(/\\/g, '\\\\')) // escape '\' on OSX/Linux
|
|
596
|
+
.replace(/(\[)(?=[^\/]+\])/g, '[[]') // escape '[' when ']' follows within the path segment
|
|
597
|
+
.replace(/\?/g, '[?]') // escape '?'
|
|
598
|
+
.replace(/\*/g, '[*]') // escape '*'
|
|
599
|
+
.replace(/\+\(/g, '[+](') // escape '+('
|
|
600
|
+
.replace(/@\(/g, '[@](') // escape '@('
|
|
601
|
+
.replace(/!\(/g, '[!]('); // escape '!('
|
|
602
|
+
return _ensureRooted(root, p);
|
|
603
|
+
}
|
|
604
|
+
exports._ensurePatternRooted = _ensurePatternRooted;
|
|
605
|
+
//-------------------------------------------------------------------
|
|
606
|
+
// Populate the vault with sensitive data. Inputs and Endpoints
|
|
607
|
+
//-------------------------------------------------------------------
|
|
608
|
+
function _loadData() {
|
|
609
|
+
// in agent, prefer TempDirectory then workFolder.
|
|
610
|
+
// In interactive dev mode, it won't be
|
|
611
|
+
var keyPath = _getVariable("agent.TempDirectory") || _getVariable("agent.workFolder") || process.cwd();
|
|
612
|
+
exports._vault = new vm.Vault(keyPath);
|
|
613
|
+
exports._knownVariableMap = {};
|
|
614
|
+
_debug('loading inputs and endpoints');
|
|
615
|
+
var loaded = 0;
|
|
616
|
+
for (var envvar in process.env) {
|
|
617
|
+
if (_startsWith(envvar, 'INPUT_') ||
|
|
618
|
+
_startsWith(envvar, 'ENDPOINT_AUTH_') ||
|
|
619
|
+
_startsWith(envvar, 'SECUREFILE_TICKET_') ||
|
|
620
|
+
_startsWith(envvar, 'SECRET_') ||
|
|
621
|
+
_startsWith(envvar, 'VSTS_TASKVARIABLE_')) {
|
|
622
|
+
// Record the secret variable metadata. This is required by getVariable to know whether
|
|
623
|
+
// to retrieve the value from the vault. In a 2.104.1 agent or higher, this metadata will
|
|
624
|
+
// be overwritten when the VSTS_SECRET_VARIABLES env var is processed below.
|
|
625
|
+
if (_startsWith(envvar, 'SECRET_')) {
|
|
626
|
+
var variableName = envvar.substring('SECRET_'.length);
|
|
627
|
+
if (variableName) {
|
|
628
|
+
// This is technically not the variable name (has underscores instead of dots),
|
|
629
|
+
// but it's good enough to make getVariable work in a pre-2.104.1 agent where
|
|
630
|
+
// the VSTS_SECRET_VARIABLES env var is not defined.
|
|
631
|
+
exports._knownVariableMap[_getVariableKey(variableName)] = { name: variableName, secret: true };
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
// store the secret
|
|
635
|
+
var value = process.env[envvar];
|
|
636
|
+
if (value) {
|
|
637
|
+
++loaded;
|
|
638
|
+
_debug('loading ' + envvar);
|
|
639
|
+
exports._vault.storeSecret(envvar, value);
|
|
640
|
+
delete process.env[envvar];
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
_debug('loaded ' + loaded);
|
|
645
|
+
// store public variable metadata
|
|
646
|
+
var names;
|
|
647
|
+
try {
|
|
648
|
+
names = JSON.parse(process.env['VSTS_PUBLIC_VARIABLES'] || '[]');
|
|
649
|
+
}
|
|
650
|
+
catch (err) {
|
|
651
|
+
throw new Error('Failed to parse VSTS_PUBLIC_VARIABLES as JSON. ' + err); // may occur during interactive testing
|
|
652
|
+
}
|
|
653
|
+
names.forEach(function (name) {
|
|
654
|
+
exports._knownVariableMap[_getVariableKey(name)] = { name: name, secret: false };
|
|
655
|
+
});
|
|
656
|
+
delete process.env['VSTS_PUBLIC_VARIABLES'];
|
|
657
|
+
// store secret variable metadata
|
|
658
|
+
try {
|
|
659
|
+
names = JSON.parse(process.env['VSTS_SECRET_VARIABLES'] || '[]');
|
|
660
|
+
}
|
|
661
|
+
catch (err) {
|
|
662
|
+
throw new Error('Failed to parse VSTS_SECRET_VARIABLES as JSON. ' + err); // may occur during interactive testing
|
|
663
|
+
}
|
|
664
|
+
names.forEach(function (name) {
|
|
665
|
+
exports._knownVariableMap[_getVariableKey(name)] = { name: name, secret: true };
|
|
666
|
+
});
|
|
667
|
+
delete process.env['VSTS_SECRET_VARIABLES'];
|
|
668
|
+
// avoid loading twice (overwrites .taskkey)
|
|
669
|
+
global['_vsts_task_lib_loaded'] = true;
|
|
670
|
+
}
|
|
671
|
+
exports._loadData = _loadData;
|
|
672
|
+
//--------------------------------------------------------------------------------
|
|
673
|
+
// Internal path helpers.
|
|
674
|
+
//--------------------------------------------------------------------------------
|
|
675
|
+
/**
|
|
676
|
+
* Defines if path is unc-path.
|
|
677
|
+
*
|
|
678
|
+
* @param path a path to a file.
|
|
679
|
+
* @returns true if path starts with double backslash, otherwise returns false.
|
|
680
|
+
*/
|
|
681
|
+
function _isUncPath(path) {
|
|
682
|
+
return /^\\\\[^\\]/.test(path);
|
|
683
|
+
}
|
|
684
|
+
exports._isUncPath = _isUncPath;
|
|
685
|
+
function _ensureRooted(root, p) {
|
|
686
|
+
if (!root) {
|
|
687
|
+
throw new Error('ensureRooted() parameter "root" cannot be empty');
|
|
688
|
+
}
|
|
689
|
+
if (!p) {
|
|
690
|
+
throw new Error('ensureRooted() parameter "p" cannot be empty');
|
|
691
|
+
}
|
|
692
|
+
if (_isRooted(p)) {
|
|
693
|
+
return p;
|
|
694
|
+
}
|
|
695
|
+
if (process.platform == 'win32' && root.match(/^[A-Z]:$/i)) { // e.g. C:
|
|
696
|
+
return root + p;
|
|
697
|
+
}
|
|
698
|
+
// ensure root ends with a separator
|
|
699
|
+
if (_endsWith(root, '/') || (process.platform == 'win32' && _endsWith(root, '\\'))) {
|
|
700
|
+
// root already ends with a separator
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
root += path.sep; // append separator
|
|
704
|
+
}
|
|
705
|
+
return root + p;
|
|
706
|
+
}
|
|
707
|
+
exports._ensureRooted = _ensureRooted;
|
|
708
|
+
/**
|
|
709
|
+
* Determines the parent path and trims trailing slashes (when safe). Path separators are normalized
|
|
710
|
+
* in the result. This function works similar to the .NET System.IO.Path.GetDirectoryName() method.
|
|
711
|
+
* For example, C:\hello\world\ returns C:\hello\world (trailing slash removed). Returns empty when
|
|
712
|
+
* no higher directory can be determined.
|
|
713
|
+
*/
|
|
714
|
+
function _getDirectoryName(p) {
|
|
715
|
+
// short-circuit if empty
|
|
716
|
+
if (!p) {
|
|
717
|
+
return '';
|
|
718
|
+
}
|
|
719
|
+
// normalize separators
|
|
720
|
+
p = _normalizeSeparators(p);
|
|
721
|
+
// on Windows, the goal of this function is to match the behavior of
|
|
722
|
+
// [System.IO.Path]::GetDirectoryName(), e.g.
|
|
723
|
+
// C:/ =>
|
|
724
|
+
// C:/hello => C:\
|
|
725
|
+
// C:/hello/ => C:\hello
|
|
726
|
+
// C:/hello/world => C:\hello
|
|
727
|
+
// C:/hello/world/ => C:\hello\world
|
|
728
|
+
// C: =>
|
|
729
|
+
// C:hello => C:
|
|
730
|
+
// C:hello/ => C:hello
|
|
731
|
+
// / =>
|
|
732
|
+
// /hello => \
|
|
733
|
+
// /hello/ => \hello
|
|
734
|
+
// //hello =>
|
|
735
|
+
// //hello/ =>
|
|
736
|
+
// //hello/world =>
|
|
737
|
+
// //hello/world/ => \\hello\world
|
|
738
|
+
//
|
|
739
|
+
// unfortunately, path.dirname() can't simply be used. for example, on Windows
|
|
740
|
+
// it yields different results from Path.GetDirectoryName:
|
|
741
|
+
// C:/ => C:/
|
|
742
|
+
// C:/hello => C:/
|
|
743
|
+
// C:/hello/ => C:/
|
|
744
|
+
// C:/hello/world => C:/hello
|
|
745
|
+
// C:/hello/world/ => C:/hello
|
|
746
|
+
// C: => C:
|
|
747
|
+
// C:hello => C:
|
|
748
|
+
// C:hello/ => C:
|
|
749
|
+
// / => /
|
|
750
|
+
// /hello => /
|
|
751
|
+
// /hello/ => /
|
|
752
|
+
// //hello => /
|
|
753
|
+
// //hello/ => /
|
|
754
|
+
// //hello/world => //hello/world
|
|
755
|
+
// //hello/world/ => //hello/world/
|
|
756
|
+
// //hello/world/again => //hello/world/
|
|
757
|
+
// //hello/world/again/ => //hello/world/
|
|
758
|
+
// //hello/world/again/again => //hello/world/again
|
|
759
|
+
// //hello/world/again/again/ => //hello/world/again
|
|
760
|
+
if (process.platform == 'win32') {
|
|
761
|
+
if (/^[A-Z]:\\?[^\\]+$/i.test(p)) { // e.g. C:\hello or C:hello
|
|
762
|
+
return p.charAt(2) == '\\' ? p.substring(0, 3) : p.substring(0, 2);
|
|
763
|
+
}
|
|
764
|
+
else if (/^[A-Z]:\\?$/i.test(p)) { // e.g. C:\ or C:
|
|
765
|
+
return '';
|
|
766
|
+
}
|
|
767
|
+
var lastSlashIndex = p.lastIndexOf('\\');
|
|
768
|
+
if (lastSlashIndex < 0) { // file name only
|
|
769
|
+
return '';
|
|
770
|
+
}
|
|
771
|
+
else if (p == '\\') { // relative root
|
|
772
|
+
return '';
|
|
773
|
+
}
|
|
774
|
+
else if (lastSlashIndex == 0) { // e.g. \\hello
|
|
775
|
+
return '\\';
|
|
776
|
+
}
|
|
777
|
+
else if (/^\\\\[^\\]+(\\[^\\]*)?$/.test(p)) { // UNC root, e.g. \\hello or \\hello\ or \\hello\world
|
|
778
|
+
return '';
|
|
779
|
+
}
|
|
780
|
+
return p.substring(0, lastSlashIndex); // e.g. hello\world => hello or hello\world\ => hello\world
|
|
781
|
+
// note, this means trailing slashes for non-root directories
|
|
782
|
+
// (i.e. not C:\, \, or \\unc\) will simply be removed.
|
|
783
|
+
}
|
|
784
|
+
// OSX/Linux
|
|
785
|
+
if (p.indexOf('/') < 0) { // file name only
|
|
786
|
+
return '';
|
|
787
|
+
}
|
|
788
|
+
else if (p == '/') {
|
|
789
|
+
return '';
|
|
790
|
+
}
|
|
791
|
+
else if (_endsWith(p, '/')) {
|
|
792
|
+
return p.substring(0, p.length - 1);
|
|
793
|
+
}
|
|
794
|
+
return path.dirname(p);
|
|
795
|
+
}
|
|
796
|
+
exports._getDirectoryName = _getDirectoryName;
|
|
797
|
+
/**
|
|
798
|
+
* On OSX/Linux, true if path starts with '/'. On Windows, true for paths like:
|
|
799
|
+
* \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases).
|
|
800
|
+
*/
|
|
801
|
+
function _isRooted(p) {
|
|
802
|
+
p = _normalizeSeparators(p);
|
|
803
|
+
if (!p) {
|
|
804
|
+
throw new Error('isRooted() parameter "p" cannot be empty');
|
|
805
|
+
}
|
|
806
|
+
if (process.platform == 'win32') {
|
|
807
|
+
return _startsWith(p, '\\') || // e.g. \ or \hello or \\hello
|
|
808
|
+
/^[A-Z]:/i.test(p); // e.g. C: or C:\hello
|
|
809
|
+
}
|
|
810
|
+
return _startsWith(p, '/'); // e.g. /hello
|
|
811
|
+
}
|
|
812
|
+
exports._isRooted = _isRooted;
|
|
813
|
+
function _normalizeSeparators(p) {
|
|
814
|
+
p = p || '';
|
|
815
|
+
if (process.platform == 'win32') {
|
|
816
|
+
// convert slashes on Windows
|
|
817
|
+
p = p.replace(/\//g, '\\');
|
|
818
|
+
// remove redundant slashes
|
|
819
|
+
var isUnc = /^\\\\+[^\\]/.test(p); // e.g. \\hello
|
|
820
|
+
return (isUnc ? '\\' : '') + p.replace(/\\\\+/g, '\\'); // preserve leading // for UNC
|
|
821
|
+
}
|
|
822
|
+
// remove redundant slashes
|
|
823
|
+
return p.replace(/\/\/+/g, '/');
|
|
824
|
+
}
|
|
825
|
+
exports._normalizeSeparators = _normalizeSeparators;
|
|
826
|
+
//-----------------------------------------------------
|
|
827
|
+
// Expose proxy information to vsts-node-api
|
|
828
|
+
//-----------------------------------------------------
|
|
829
|
+
function _exposeProxySettings() {
|
|
830
|
+
var proxyUrl = _getVariable('Agent.ProxyUrl');
|
|
831
|
+
if (proxyUrl && proxyUrl.length > 0) {
|
|
832
|
+
var proxyUsername = _getVariable('Agent.ProxyUsername');
|
|
833
|
+
var proxyPassword = _getVariable('Agent.ProxyPassword');
|
|
834
|
+
var proxyBypassHostsJson = _getVariable('Agent.ProxyBypassList');
|
|
835
|
+
global['_vsts_task_lib_proxy_url'] = proxyUrl;
|
|
836
|
+
global['_vsts_task_lib_proxy_username'] = proxyUsername;
|
|
837
|
+
global['_vsts_task_lib_proxy_bypass'] = proxyBypassHostsJson;
|
|
838
|
+
global['_vsts_task_lib_proxy_password'] = _exposeTaskLibSecret('proxy', proxyPassword || '');
|
|
839
|
+
_debug('expose agent proxy configuration.');
|
|
840
|
+
global['_vsts_task_lib_proxy'] = true;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
exports._exposeProxySettings = _exposeProxySettings;
|
|
844
|
+
//-----------------------------------------------------
|
|
845
|
+
// Expose certificate information to vsts-node-api
|
|
846
|
+
//-----------------------------------------------------
|
|
847
|
+
function _exposeCertSettings() {
|
|
848
|
+
var ca = _getVariable('Agent.CAInfo');
|
|
849
|
+
if (ca) {
|
|
850
|
+
global['_vsts_task_lib_cert_ca'] = ca;
|
|
851
|
+
}
|
|
852
|
+
var clientCert = _getVariable('Agent.ClientCert');
|
|
853
|
+
if (clientCert) {
|
|
854
|
+
var clientCertKey = _getVariable('Agent.ClientCertKey');
|
|
855
|
+
var clientCertArchive = _getVariable('Agent.ClientCertArchive');
|
|
856
|
+
var clientCertPassword = _getVariable('Agent.ClientCertPassword');
|
|
857
|
+
global['_vsts_task_lib_cert_clientcert'] = clientCert;
|
|
858
|
+
global['_vsts_task_lib_cert_key'] = clientCertKey;
|
|
859
|
+
global['_vsts_task_lib_cert_archive'] = clientCertArchive;
|
|
860
|
+
global['_vsts_task_lib_cert_passphrase'] = _exposeTaskLibSecret('cert', clientCertPassword || '');
|
|
861
|
+
}
|
|
862
|
+
if (ca || clientCert) {
|
|
863
|
+
_debug('expose agent certificate configuration.');
|
|
864
|
+
global['_vsts_task_lib_cert'] = true;
|
|
865
|
+
}
|
|
866
|
+
var skipCertValidation = _getVariable('Agent.SkipCertValidation') || 'false';
|
|
867
|
+
if (skipCertValidation) {
|
|
868
|
+
global['_vsts_task_lib_skip_cert_validation'] = skipCertValidation.toUpperCase() === 'TRUE';
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
exports._exposeCertSettings = _exposeCertSettings;
|
|
872
|
+
// We store the encryption key on disk and hold the encrypted content and key file in memory
|
|
873
|
+
// return base64encoded<keyFilePath>:base64encoded<encryptedContent>
|
|
874
|
+
// downstream vsts-node-api will retrieve the secret later
|
|
875
|
+
function _exposeTaskLibSecret(keyFile, secret) {
|
|
876
|
+
if (secret) {
|
|
877
|
+
var encryptKey = crypto.randomBytes(256);
|
|
878
|
+
var cipher = crypto.createCipher("aes-256-ctr", encryptKey);
|
|
879
|
+
var encryptedContent = cipher.update(secret, "utf8", "hex");
|
|
880
|
+
encryptedContent += cipher.final("hex");
|
|
881
|
+
var storageFile = path.join(_getVariable('Agent.TempDirectory') || _getVariable("agent.workFolder") || process.cwd(), keyFile);
|
|
882
|
+
fs.writeFileSync(storageFile, encryptKey.toString('base64'), { encoding: 'utf8' });
|
|
883
|
+
return new Buffer(storageFile).toString('base64') + ':' + new Buffer(encryptedContent).toString('base64');
|
|
884
|
+
}
|
|
885
|
+
}
|