appium-xcode 4.0.4 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/xcode.js CHANGED
@@ -1,141 +1,133 @@
1
- import { util, fs, plist, logger } from '@appium/support';
1
+ import { fs, logger } from '@appium/support';
2
2
  import path from 'path';
3
3
  import { retry } from 'asyncbox';
4
4
  import _ from 'lodash';
5
- import { parse as parsePlistData } from 'plist';
6
5
  import { exec } from 'teen_process';
7
6
  import semver from 'semver';
7
+ import {
8
+ runXcrunCommand, findAppPaths, XCRUN_TIMEOUT, readXcodePlist
9
+ } from './helpers';
8
10
 
9
-
10
- const env = process.env;
11
-
12
- const XCRUN_TIMEOUT = 15000;
13
- const XCODE_SUBDIR = '/Contents/Developer';
14
- const DEFAULT_NUMBER_OF_RETRIES = 3;
11
+ const DEFAULT_NUMBER_OF_RETRIES = 2;
12
+ const XCODE_BUNDLE_ID = 'com.apple.dt.Xcode';
15
13
 
16
14
  const log = logger.getLogger('Xcode');
17
15
 
16
+ /**
17
+ * Retrieves the full path to Xcode Developer subfolder via xcode-select
18
+ *
19
+ * @param {number} timeout The maximum timeout for xcode-select execution
20
+ * @returns {Promise<string>} Full path to Xcode Developer subfolder
21
+ * @throws {Error} If it is not possible to retrieve a proper path
22
+ */
23
+ async function getPathFromXcodeSelect (timeout = XCRUN_TIMEOUT) {
24
+ const generateErrorMessage = async (prefix) => {
25
+ const xcodePaths = await findAppPaths(XCODE_BUNDLE_ID);
26
+ if (_.isEmpty(xcodePaths)) {
27
+ return `${prefix}. Consider installing Xcode to address this issue.`;
28
+ }
18
29
 
19
- function hasExpectedSubDir (path) {
20
- return path.substring(path.length - XCODE_SUBDIR.length) === XCODE_SUBDIR;
21
- }
30
+ const proposals = xcodePaths.map((p) => ` sudo xcode-select -s "${path.join(p, 'Contents', 'Developer')}"`);
31
+ return `${prefix}. ` +
32
+ `Consider running${proposals.length > 1 ? ' any of' : ''}:\n${'\n'.join(proposals)}\nto address this issue.`;
33
+ };
22
34
 
23
- async function runXcrunCommand (args, timeout = XCRUN_TIMEOUT) {
35
+ let stdout;
24
36
  try {
25
- const res = await exec('xcrun', args, {timeout});
26
- if (_.isUndefined(res)) {
27
- throw new Error(`Nothing returned from trying to run 'xcrun ${args.join(' ')}'`);
28
- }
29
- return res;
30
- } catch (err) {
31
- // the true error can be hidden within the stderr
32
- if (err.stderr) {
33
- err.message = `${err.message}: ${err.stderr}`;
34
- }
35
-
36
- throw err;
37
+ ({stdout} = await exec('xcode-select', ['--print-path'], {timeout}));
38
+ } catch (e) {
39
+ log.errorAndThrow(`Cannot determine the path to Xcode by running 'xcode-select -p' command. ` +
40
+ `Original error: ${e.stderr || e.message}`);
37
41
  }
38
- }
39
-
40
- async function getPathFromSymlink (failMessage) {
41
- // Node's invocation of xcode-select sometimes flakes and returns an empty string.
42
- // Not clear why. As a workaround, Appium can reliably deduce the version in use by checking
43
- // the locations xcode-select uses to store the selected version's path. This should be 100%
44
- // reliable so long as the link locations remain the same. However, since we're relying on
45
- // hardcoded paths, this approach will break the next time Apple changes the symlink location.
46
- log.warn(`Finding XcodePath by symlink because ${failMessage}`);
47
-
48
- const symlinkPath = '/var/db/xcode_select_link';
49
- const legacySymlinkPath = '/usr/share/xcode-select/xcode_dir_link'; // Xcode < 5.x
50
- let xcodePath = null;
51
-
52
- // xcode-select allows users to override its settings with the DEVELOPER_DIR env var,
53
- // so check that first
54
- if (util.hasContent(env.DEVELOPER_DIR)) {
55
- const customPath = hasExpectedSubDir(env.DEVELOPER_DIR)
56
- ? env.DEVELOPER_DIR
57
- : env.DEVELOPER_DIR + XCODE_SUBDIR;
58
-
59
- if (await fs.exists(customPath)) {
60
- xcodePath = customPath;
61
- } else {
62
- let mesg = `Could not find path to Xcode, environment variable ` +
63
- `DEVELOPER_DIR set to: ${env.DEVELOPER_DIR} ` +
64
- `but no Xcode found`;
65
- log.warn(mesg);
66
- throw new Error(mesg);
67
- }
68
- } else if (await fs.exists(symlinkPath)) {
69
- xcodePath = await fs.readlink(symlinkPath);
70
- } else if (await fs.exists(legacySymlinkPath)) {
71
- xcodePath = await fs.readlink(legacySymlinkPath);
42
+ // trim and remove trailing slash
43
+ const developerRoot = stdout.replace(/\/$/, '').trim();
44
+ if (!developerRoot) {
45
+ log.errorAndThrow(await generateErrorMessage(`'xcode-select -p' returned an empty string`));
72
46
  }
73
-
74
- if (xcodePath) {
75
- return xcodePath.replace(new RegExp('/$'), '').trim();
47
+ // xcode-select might also return a path to command line tools
48
+ const {CFBundleIdentifier} = await readXcodePlist(developerRoot);
49
+ if (CFBundleIdentifier === XCODE_BUNDLE_ID) {
50
+ return developerRoot;
76
51
  }
77
52
 
78
- // We should only get here is we failed to capture xcode-select's stdout and our
79
- // other checks failed. Either Apple has moved the symlink to a new location or the user
80
- // is not using the default install. 99.999% chance it's the latter, so issue a warning
81
- // should we ever hit the edge case.
82
- let msg = `Could not find path to Xcode by symlinks located in ${symlinkPath}, or ${legacySymlinkPath}`;
83
- log.warn(msg);
84
- throw new Error(msg);
53
+ log.errorAndThrow(await generateErrorMessage(`'${developerRoot}' is not a valid Xcode path`));
85
54
  }
86
55
 
87
- async function getPathFromXcodeSelect (timeout = XCRUN_TIMEOUT) {
88
- let {stdout} = await exec('xcode-select', ['--print-path'], {timeout});
89
-
90
- // trim and remove trailing slash
91
- const xcodeFolderPath = stdout.replace(/\/$/, '').trim();
92
-
93
- if (!util.hasContent(xcodeFolderPath)) {
94
- log.errorAndThrow('xcode-select returned an empty string');
56
+ /**
57
+ * Retrieves the full path to Xcode Developer subfolder via DEVELOPER_DIR environment variable
58
+ *
59
+ * @returns {Promise<string>} Full path to Xcode Developer subfolder
60
+ * @throws {Error} If it is not possible to retrieve a proper path
61
+ */
62
+ async function getPathFromDeveloperDir () {
63
+ const developerRoot = process.env.DEVELOPER_DIR;
64
+ const {CFBundleIdentifier} = await readXcodePlist(developerRoot);
65
+ if (CFBundleIdentifier === XCODE_BUNDLE_ID) {
66
+ return developerRoot;
95
67
  }
96
68
 
97
- if (await fs.exists(xcodeFolderPath)) {
98
- return xcodeFolderPath;
99
- } else {
100
- const msg = `xcode-select could not find xcode. Path '${xcodeFolderPath}' does not exist.`;
101
- log.errorAndThrow(msg);
102
- }
69
+ log.errorAndThrow(`The path to Xcode Developer dir '${developerRoot}' provided in DEVELOPER_DIR ` +
70
+ `environment variable is not a valid path`);
103
71
  }
104
72
 
73
+ /**
74
+ * Retrieves the full path to Xcode Developer subfolder.
75
+ * If DEVELOPER_DIR environment variable is provided then its value has a priority.
76
+ *
77
+ * @property {number} timeout [15000] The maximum timeout for xcode-select execution
78
+ * @returns {string} Full path to Xcode Developer subfolder
79
+ * @throws {Error} If there was an error while retrieving the path.
80
+ */
105
81
  const getPath = _.memoize(function getPath (timeout = XCRUN_TIMEOUT) {
106
- // first we try using xcode-select to find the path
107
- // then we try using the symlinks that Apple has by default
108
- return (async () => {
109
- try {
110
- return await getPathFromXcodeSelect(timeout);
111
- } catch (e) {
112
- return await getPathFromSymlink(e.message);
113
- }
114
- })();
82
+ return process.env.DEVELOPER_DIR ? getPathFromDeveloperDir() : getPathFromXcodeSelect(timeout);
115
83
  });
116
84
 
117
-
85
+ /**
86
+ * Retrieves Xcode version
87
+ *
88
+ * @param {number} timeout [15000] Timeout of milliseconds to wait for terminal commands.
89
+ * @returns {Promise<import("semver").SemVer | null>} Xcode version
90
+ * @throws {Error} If there was a failure while retrieving the version
91
+ */
118
92
  async function getVersionWithoutRetry (timeout = XCRUN_TIMEOUT) {
119
- const xcodePath = await getPath(timeout);
120
-
93
+ const developerPath = await getPath(timeout);
121
94
  // we want to read the CFBundleShortVersionString from Xcode's plist.
122
- // It should be in /[root]/XCode.app/Contents/
123
- const plistPath = path.resolve(xcodePath, '..', 'Info.plist');
124
-
125
- if (!await fs.exists(plistPath)) {
126
- throw new Error(`Could not get Xcode version. ${plistPath} does not exist on disk.`);
127
- }
128
-
129
- const version = await plist.parsePlistFile(plistPath);
130
- return semver.coerce(version.CFBundleShortVersionString);
95
+ const {CFBundleShortVersionString} = await readXcodePlist(developerPath);
96
+ return semver.coerce(CFBundleShortVersionString);
131
97
  }
132
98
 
99
+ /**
100
+ * Retrieves Xcode version or the cached one if called more than once
101
+ *
102
+ * @param {number} retries [2] How many retries to apply for version retrieval
103
+ * @param {number} timeout [15000] Timeout of milliseconds to wait for terminal commands
104
+ * @returns {Promise<import("semver").SemVer | null>} Xcode version
105
+ * @throws {Error} If there was a failure while retrieving the version
106
+ */
133
107
  const getVersionMemoized = _.memoize(
134
108
  function getVersionMemoized (retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {
135
109
  return retry(retries, getVersionWithoutRetry, timeout);
136
110
  }
137
111
  );
138
112
 
113
+ /**
114
+ * @typedef {Object} XcodeVersion
115
+ * @property {string} versionString Xcode version as a string
116
+ * @property {number} versionFloat Xcode version as a float number
117
+ * @property {number} major Major number of Xcode version
118
+ * @property {number} minor Minor number of Xcode version
119
+ * @property {number?} patch Patch number of Xcode version (if exists)
120
+ */
121
+
122
+ /**
123
+ * Retrieves Xcode version
124
+ *
125
+ * @param {boolean} parse [false] Whether to parse the version to a XcodeVersion version
126
+ * @param {number} retries [2] How many retries to apply for getting the version number
127
+ * @param {number} timeout [15000] Timeout of milliseconds to wait for terminal commands
128
+ * @returns {Promise<XcodeVersion | string>} Xcode version depending on the value of `parse` flag
129
+ * @throws {Error} If there was a failure while retrieving the version
130
+ */
139
131
  async function getVersion (parse = false, retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {
140
132
  const version = await getVersionMemoized(retries, timeout);
141
133
  // xcode version strings are not exactly semver string: patch versions of 0
@@ -157,37 +149,11 @@ async function getVersion (parse = false, retries = DEFAULT_NUMBER_OF_RETRIES, t
157
149
  };
158
150
  }
159
151
 
160
- async function getCommandLineToolsVersion () {
161
- // there are a number of different ways that the CLI tools version has been
162
- // represented. Try them from most reliable to least, falling down the chain
163
- const getVersionFunctions = [
164
- async () => {
165
- let pkg = (await exec('pkgutil', ['--pkgs=com.apple.pkg.DevSDK_.*'])).stdout;
166
- return (await exec('pkgutil', [`--pkg-info=${pkg.trim()}`])).stdout;
167
- },
168
- async () => (await exec('pkgutil', [`--pkg-info=com.apple.pkg.CLTools_Executables`])).stdout,
169
- async () => (await exec('pkgutil', [`--pkg-info=com.apple.pkg.DeveloperToolsCLI`])).stdout,
170
- ];
171
- let stdout;
172
- for (let getVersion of getVersionFunctions) {
173
- try {
174
- stdout = await getVersion();
175
- break;
176
- } catch (ign) {
177
- stdout = '';
178
- }
179
- }
180
-
181
- // stdout should have a line like `version: 8.0.0.0.1.1472435881`
182
- let match = /^version: (.+)$/m.exec(stdout); // https://regex101.com/r/HV3x4d/1
183
- return match ? match[1] : undefined;
184
- }
185
-
186
152
  /**
187
153
  * Check https://trac.macports.org/wiki/XcodeVersionInfo
188
154
  * to see the actual mapping between clang and other components.
189
155
  *
190
- * @returns {?string} The actual Clang version in x.x.x.x or x.x.x format,
156
+ * @returns {Promise<string?>} The actual Clang version in x.x.x.x or x.x.x format,
191
157
  * which is supplied with Command Line Tools. `null` is returned
192
158
  * if CLT are not installed.
193
159
  */
@@ -208,170 +174,71 @@ async function getClangVersion () {
208
174
  return match[1];
209
175
  }
210
176
 
211
- async function getAutomationTraceTemplatePathWithoutRetry (timeout = XCRUN_TIMEOUT) {
212
- const xcodePath = await getPath(timeout);
213
-
214
- // for ios 8 and up, the file extension for AutiomationInstrument changed.
215
- // rather than waste time getting the iOSSDKVersion, just get both paths and see which one exists
216
- const extensions = ['xrplugin', 'bundle'];
217
- const pathPrefix = path.resolve(xcodePath, '../Applications/Instruments.app/Contents/PlugIns');
218
- const pathSuffix = 'Contents/Resources/Automation.tracetemplate';
219
- let automationTraceTemplatePaths = [
220
- path.resolve(pathPrefix, `AutomationInstrument.${extensions[0]}`, pathSuffix),
221
- path.resolve(pathPrefix, `AutomationInstrument.${extensions[1]}`, pathSuffix)
222
- ];
223
-
224
- if (await fs.exists(automationTraceTemplatePaths[0])) {
225
- return automationTraceTemplatePaths[0];
226
- }
227
-
228
- if (await fs.exists(automationTraceTemplatePaths[1])) {
229
- return automationTraceTemplatePaths[1];
230
- }
231
-
232
- const msg = 'Could not find Automation.tracetemplate in any of the following' +
233
- `locations ${automationTraceTemplatePaths.toString()}`;
234
- log.error(msg);
235
- throw new Error(msg);
236
-
237
- }
238
-
239
- const getAutomationTraceTemplatePath = _.memoize(
240
- function getAutomationTraceTemplatePath (retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {
241
- return retry(retries, getAutomationTraceTemplatePathWithoutRetry, timeout);
242
- }
243
- );
244
-
177
+ /**
178
+ * Retrieves the maximum version of iOS SDK supported by the installed Xcode
179
+ *
180
+ * @param {number} timeout [15000] Timeout of milliseconds to wait for terminal commands
181
+ * @returns {string} The SDK version
182
+ * @throws {Error} If the SDK version number cannot be determined
183
+ */
245
184
  async function getMaxIOSSDKWithoutRetry (timeout = XCRUN_TIMEOUT) {
246
- const version = await getVersion(false, DEFAULT_NUMBER_OF_RETRIES, timeout);
247
- if (version[0] === '4') {
248
- return '6.1';
249
- }
250
-
251
185
  const args = ['--sdk', 'iphonesimulator', '--show-sdk-version'];
252
186
  const {stdout} = await runXcrunCommand(args, timeout);
253
-
254
187
  const sdkVersion = stdout.trim();
255
188
  const match = /\d.\d/.exec(stdout);
256
-
257
189
  if (!match) {
258
190
  throw new Error(`xcrun returned a non-numeric iOS SDK version: '${sdkVersion}'`);
259
191
  }
260
-
261
192
  return sdkVersion;
262
193
  }
263
194
 
264
- async function getMaxIOSSDKFromXcodeVersion (timeout = XCRUN_TIMEOUT) {
265
- const version = await getVersion(true, DEFAULT_NUMBER_OF_RETRIES, timeout);
266
- // as of now, the iOS version associated with an Xcode version is
267
- // just the Xcode version + 2
268
- return `${version.major + 2}.${version.minor}`;
269
- }
270
-
195
+ /**
196
+ * Retrieves the maximum version of iOS SDK supported by the installed Xcode
197
+ *
198
+ * @param {number} timeout [15000] Timeout of milliseconds to wait for terminal commands
199
+ * @param {number} retries [2] The maximum number of retries
200
+ * @returns {string} The SDK version
201
+ * @throws {Error} If the SDK version number cannot be determined
202
+ */
271
203
  const getMaxIOSSDK = _.memoize(
272
204
  function getMaxIOSSDK (retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {
273
- try {
274
- return retry(retries, getMaxIOSSDKWithoutRetry, timeout);
275
- } catch (err) {
276
- log.warn(`Unable to retrieve maximum iOS version: ${err.message}`);
277
- log.warn('Guessing from Xcode version');
278
- return getMaxIOSSDKFromXcodeVersion(timeout);
279
- }
205
+ return retry(retries, getMaxIOSSDKWithoutRetry, timeout);
280
206
  }
281
207
  );
282
208
 
209
+ /**
210
+ * Retrieves the maximum version of tvOS SDK supported by the installed Xcode
211
+ *
212
+ * @param {number} timeout [15000] Timeout of milliseconds to wait for terminal commands
213
+ * @returns {string} The SDK version
214
+ * @throws {Error} If the SDK version number cannot be determined
215
+ */
283
216
  async function getMaxTVOSSDKWithoutRetry (timeout = XCRUN_TIMEOUT) {
284
217
  const args = ['--sdk', 'appletvsimulator', '--show-sdk-version'];
285
218
  const {stdout} = await runXcrunCommand(args, timeout);
286
-
287
219
  const sdkVersion = stdout.trim();
288
-
289
220
  if (isNaN(parseFloat(sdkVersion))) {
290
221
  throw new Error(`xcrun returned a non-numeric tvOS SDK version: '${sdkVersion}'`);
291
222
  }
292
-
293
223
  return sdkVersion;
294
224
  }
295
225
 
226
+ /**
227
+ * Retrieves the maximum version of tvOS SDK supported by the installed Xcode
228
+ *
229
+ * @param {number} timeout [15000] Timeout of milliseconds to wait for terminal commands
230
+ * @param {number} retries [2] The maximum number of retries
231
+ * @returns {string} The SDK version
232
+ * @throws {Error} If the SDK version number cannot be determined
233
+ */
296
234
  const getMaxTVOSSDK = _.memoize(
297
235
  function getMaxTVOSSDK (retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {
298
236
  return retry(retries, getMaxTVOSSDKWithoutRetry, timeout);
299
237
  }
300
238
  );
301
239
 
302
- async function getConnectedDevices (timeout = XCRUN_TIMEOUT) {
303
- const cmd = '/usr/sbin/system_profiler';
304
- const args = ['-xml', 'SPUSBDataType'];
305
- let {stdout} = await exec(cmd, args, {timeout});
306
- let plistContent = parsePlistData(stdout);
307
-
308
- let devicesFound = [];
309
- let entriesToSearch = [plistContent[0]];
310
- while (entriesToSearch.length > 0) {
311
- let currentEntry = entriesToSearch.pop();
312
- if (currentEntry instanceof Array) {
313
- entriesToSearch = entriesToSearch.concat(currentEntry);
314
- } else if ((currentEntry._name &&
315
- currentEntry._name.substring(0, 4) === 'iPad') ||
316
- (currentEntry._name &&
317
- currentEntry._name.substring(0, 6) === 'iPhone') ||
318
- (currentEntry._name && _.includes(currentEntry._name, 'Apple TV'))) {
319
- let deviceInfo = {
320
- name: currentEntry._name,
321
- udid: currentEntry.serial_num,
322
- productId: currentEntry.product_id,
323
- deviceVersion: currentEntry.bcd_device
324
- };
325
- devicesFound.push(deviceInfo);
326
- } else if (currentEntry._items) {
327
- entriesToSearch = entriesToSearch.concat(currentEntry._items);
328
- }
329
- }
330
- return devicesFound;
331
- }
332
-
333
- async function getInstrumentsPathWithoutRetry (timeout = XCRUN_TIMEOUT) {
334
- const args = ['-find', 'instruments'];
335
- let {stdout} = await runXcrunCommand(args, timeout);
336
-
337
- if (!stdout) {
338
- stdout = '';
339
- }
340
-
341
- let instrumentsPath = stdout.trim();
342
-
343
- if (!instrumentsPath) {
344
- throw new Error(`Could not find path to instruments binary using 'xcrun ${args.join(' ')}'`);
345
- }
346
-
347
- return instrumentsPath;
348
- }
349
-
350
- const getInstrumentsPath = _.memoize(
351
- function getInstrumentsPath (retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {
352
- return retry(retries, getInstrumentsPathWithoutRetry, timeout);
353
- }
354
- );
355
-
356
- function clearInternalCache () {
357
-
358
- // memoized functions
359
- const memoized = [
360
- getPath, getVersionMemoized, getAutomationTraceTemplatePath, getMaxIOSSDK,
361
- getMaxTVOSSDK, getInstrumentsPath,
362
- ];
363
-
364
- memoized.forEach((f) => {
365
- if (f.cache) {
366
- f.cache = new _.memoize.Cache();
367
- }
368
- });
369
- }
370
-
371
240
  export {
372
- getPath, getVersion, getAutomationTraceTemplatePath, getMaxIOSSDK,
373
- getAutomationTraceTemplatePathWithoutRetry, getMaxIOSSDKWithoutRetry,
374
- getConnectedDevices, clearInternalCache, getInstrumentsPath,
375
- getCommandLineToolsVersion, getMaxTVOSSDK, getMaxTVOSSDKWithoutRetry,
376
- getClangVersion,
241
+ getPath, getVersion, getMaxIOSSDK, getMaxIOSSDKWithoutRetry,
242
+ getMaxTVOSSDK, getMaxTVOSSDKWithoutRetry, getClangVersion,
243
+ getPathFromDeveloperDir, getPathFromXcodeSelect,
377
244
  };
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "ios",
7
7
  "xcode"
8
8
  ],
9
- "version": "4.0.4",
9
+ "version": "5.0.0",
10
10
  "author": "Appium Contributors",
11
11
  "license": "Apache-2.0",
12
12
  "repository": {
@@ -33,7 +33,7 @@
33
33
  "CHANGELOG.md"
34
34
  ],
35
35
  "dependencies": {
36
- "@appium/support": "^2.55.3",
36
+ "@appium/support": "^3.0.0",
37
37
  "@babel/runtime": "^7.0.0",
38
38
  "asyncbox": "^2.3.0",
39
39
  "lodash": "^4.17.4",
@@ -1 +0,0 @@
1
- {"version":3,"file":"xcode.js","names":["env","process","XCRUN_TIMEOUT","XCODE_SUBDIR","DEFAULT_NUMBER_OF_RETRIES","log","logger","getLogger","hasExpectedSubDir","path","substring","length","runXcrunCommand","args","timeout","res","exec","_","isUndefined","Error","join","err","stderr","message","getPathFromSymlink","failMessage","warn","symlinkPath","legacySymlinkPath","xcodePath","util","hasContent","DEVELOPER_DIR","customPath","fs","exists","mesg","readlink","replace","RegExp","trim","msg","getPathFromXcodeSelect","stdout","xcodeFolderPath","errorAndThrow","getPath","memoize","e","getVersionWithoutRetry","plistPath","resolve","version","plist","parsePlistFile","semver","coerce","CFBundleShortVersionString","getVersionMemoized","retries","retry","getVersion","parse","versionString","patch","major","minor","versionFloat","parseFloat","undefined","toString","getCommandLineToolsVersion","getVersionFunctions","pkg","ign","match","getClangVersion","which","info","getAutomationTraceTemplatePathWithoutRetry","extensions","pathPrefix","pathSuffix","automationTraceTemplatePaths","error","getAutomationTraceTemplatePath","getMaxIOSSDKWithoutRetry","sdkVersion","getMaxIOSSDKFromXcodeVersion","getMaxIOSSDK","getMaxTVOSSDKWithoutRetry","isNaN","getMaxTVOSSDK","getConnectedDevices","cmd","plistContent","parsePlistData","devicesFound","entriesToSearch","currentEntry","pop","Array","concat","_name","includes","deviceInfo","name","udid","serial_num","productId","product_id","deviceVersion","bcd_device","push","_items","getInstrumentsPathWithoutRetry","instrumentsPath","getInstrumentsPath","clearInternalCache","memoized","forEach","f","cache","Cache"],"sources":["../../lib/xcode.js"],"sourcesContent":["import { util, fs, plist, logger } from '@appium/support';\nimport path from 'path';\nimport { retry } from 'asyncbox';\nimport _ from 'lodash';\nimport { parse as parsePlistData } from 'plist';\nimport { exec } from 'teen_process';\nimport semver from 'semver';\n\n\nconst env = process.env;\n\nconst XCRUN_TIMEOUT = 15000;\nconst XCODE_SUBDIR = '/Contents/Developer';\nconst DEFAULT_NUMBER_OF_RETRIES = 3;\n\nconst log = logger.getLogger('Xcode');\n\n\nfunction hasExpectedSubDir (path) {\n return path.substring(path.length - XCODE_SUBDIR.length) === XCODE_SUBDIR;\n}\n\nasync function runXcrunCommand (args, timeout = XCRUN_TIMEOUT) {\n try {\n const res = await exec('xcrun', args, {timeout});\n if (_.isUndefined(res)) {\n throw new Error(`Nothing returned from trying to run 'xcrun ${args.join(' ')}'`);\n }\n return res;\n } catch (err) {\n // the true error can be hidden within the stderr\n if (err.stderr) {\n err.message = `${err.message}: ${err.stderr}`;\n }\n\n throw err;\n }\n}\n\nasync function getPathFromSymlink (failMessage) {\n // Node's invocation of xcode-select sometimes flakes and returns an empty string.\n // Not clear why. As a workaround, Appium can reliably deduce the version in use by checking\n // the locations xcode-select uses to store the selected version's path. This should be 100%\n // reliable so long as the link locations remain the same. However, since we're relying on\n // hardcoded paths, this approach will break the next time Apple changes the symlink location.\n log.warn(`Finding XcodePath by symlink because ${failMessage}`);\n\n const symlinkPath = '/var/db/xcode_select_link';\n const legacySymlinkPath = '/usr/share/xcode-select/xcode_dir_link'; // Xcode < 5.x\n let xcodePath = null;\n\n // xcode-select allows users to override its settings with the DEVELOPER_DIR env var,\n // so check that first\n if (util.hasContent(env.DEVELOPER_DIR)) {\n const customPath = hasExpectedSubDir(env.DEVELOPER_DIR)\n ? env.DEVELOPER_DIR\n : env.DEVELOPER_DIR + XCODE_SUBDIR;\n\n if (await fs.exists(customPath)) {\n xcodePath = customPath;\n } else {\n let mesg = `Could not find path to Xcode, environment variable ` +\n `DEVELOPER_DIR set to: ${env.DEVELOPER_DIR} ` +\n `but no Xcode found`;\n log.warn(mesg);\n throw new Error(mesg);\n }\n } else if (await fs.exists(symlinkPath)) {\n xcodePath = await fs.readlink(symlinkPath);\n } else if (await fs.exists(legacySymlinkPath)) {\n xcodePath = await fs.readlink(legacySymlinkPath);\n }\n\n if (xcodePath) {\n return xcodePath.replace(new RegExp('/$'), '').trim();\n }\n\n // We should only get here is we failed to capture xcode-select's stdout and our\n // other checks failed. Either Apple has moved the symlink to a new location or the user\n // is not using the default install. 99.999% chance it's the latter, so issue a warning\n // should we ever hit the edge case.\n let msg = `Could not find path to Xcode by symlinks located in ${symlinkPath}, or ${legacySymlinkPath}`;\n log.warn(msg);\n throw new Error(msg);\n}\n\nasync function getPathFromXcodeSelect (timeout = XCRUN_TIMEOUT) {\n let {stdout} = await exec('xcode-select', ['--print-path'], {timeout});\n\n // trim and remove trailing slash\n const xcodeFolderPath = stdout.replace(/\\/$/, '').trim();\n\n if (!util.hasContent(xcodeFolderPath)) {\n log.errorAndThrow('xcode-select returned an empty string');\n }\n\n if (await fs.exists(xcodeFolderPath)) {\n return xcodeFolderPath;\n } else {\n const msg = `xcode-select could not find xcode. Path '${xcodeFolderPath}' does not exist.`;\n log.errorAndThrow(msg);\n }\n}\n\nconst getPath = _.memoize(function getPath (timeout = XCRUN_TIMEOUT) {\n // first we try using xcode-select to find the path\n // then we try using the symlinks that Apple has by default\n return (async () => {\n try {\n return await getPathFromXcodeSelect(timeout);\n } catch (e) {\n return await getPathFromSymlink(e.message);\n }\n })();\n});\n\n\nasync function getVersionWithoutRetry (timeout = XCRUN_TIMEOUT) {\n const xcodePath = await getPath(timeout);\n\n // we want to read the CFBundleShortVersionString from Xcode's plist.\n // It should be in /[root]/XCode.app/Contents/\n const plistPath = path.resolve(xcodePath, '..', 'Info.plist');\n\n if (!await fs.exists(plistPath)) {\n throw new Error(`Could not get Xcode version. ${plistPath} does not exist on disk.`);\n }\n\n const version = await plist.parsePlistFile(plistPath);\n return semver.coerce(version.CFBundleShortVersionString);\n}\n\nconst getVersionMemoized = _.memoize(\n function getVersionMemoized (retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {\n return retry(retries, getVersionWithoutRetry, timeout);\n }\n);\n\nasync function getVersion (parse = false, retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {\n const version = await getVersionMemoized(retries, timeout);\n // xcode version strings are not exactly semver string: patch versions of 0\n // are removed (e.g., '10.0.0' => '10.0')\n const versionString = version.patch > 0 ? version.version : `${version.major}.${version.minor}`;\n if (!parse) {\n return versionString;\n }\n\n return {\n versionString,\n versionFloat: parseFloat(versionString),\n major: version.major,\n minor: version.minor,\n patch: version.patch > 0 ? version.patch : undefined,\n toString () {\n return versionString;\n },\n };\n}\n\nasync function getCommandLineToolsVersion () {\n // there are a number of different ways that the CLI tools version has been\n // represented. Try them from most reliable to least, falling down the chain\n const getVersionFunctions = [\n async () => {\n let pkg = (await exec('pkgutil', ['--pkgs=com.apple.pkg.DevSDK_.*'])).stdout;\n return (await exec('pkgutil', [`--pkg-info=${pkg.trim()}`])).stdout;\n },\n async () => (await exec('pkgutil', [`--pkg-info=com.apple.pkg.CLTools_Executables`])).stdout,\n async () => (await exec('pkgutil', [`--pkg-info=com.apple.pkg.DeveloperToolsCLI`])).stdout,\n ];\n let stdout;\n for (let getVersion of getVersionFunctions) {\n try {\n stdout = await getVersion();\n break;\n } catch (ign) {\n stdout = '';\n }\n }\n\n // stdout should have a line like `version: 8.0.0.0.1.1472435881`\n let match = /^version: (.+)$/m.exec(stdout); // https://regex101.com/r/HV3x4d/1\n return match ? match[1] : undefined;\n}\n\n/**\n * Check https://trac.macports.org/wiki/XcodeVersionInfo\n * to see the actual mapping between clang and other components.\n *\n * @returns {?string} The actual Clang version in x.x.x.x or x.x.x format,\n * which is supplied with Command Line Tools. `null` is returned\n * if CLT are not installed.\n */\nasync function getClangVersion () {\n try {\n await fs.which('clang');\n } catch (e) {\n log.info('Cannot find clang executable on the local system. ' +\n 'Are Xcode Command Line Tools installed?');\n return null;\n }\n const {stdout} = await exec('clang', ['--version']);\n const match = /clang-([0-9.]+)/.exec(stdout);\n if (!match) {\n log.info(`Cannot parse clang version from ${stdout}`);\n return null;\n }\n return match[1];\n}\n\nasync function getAutomationTraceTemplatePathWithoutRetry (timeout = XCRUN_TIMEOUT) {\n const xcodePath = await getPath(timeout);\n\n // for ios 8 and up, the file extension for AutiomationInstrument changed.\n // rather than waste time getting the iOSSDKVersion, just get both paths and see which one exists\n const extensions = ['xrplugin', 'bundle'];\n const pathPrefix = path.resolve(xcodePath, '../Applications/Instruments.app/Contents/PlugIns');\n const pathSuffix = 'Contents/Resources/Automation.tracetemplate';\n let automationTraceTemplatePaths = [\n path.resolve(pathPrefix, `AutomationInstrument.${extensions[0]}`, pathSuffix),\n path.resolve(pathPrefix, `AutomationInstrument.${extensions[1]}`, pathSuffix)\n ];\n\n if (await fs.exists(automationTraceTemplatePaths[0])) {\n return automationTraceTemplatePaths[0];\n }\n\n if (await fs.exists(automationTraceTemplatePaths[1])) {\n return automationTraceTemplatePaths[1];\n }\n\n const msg = 'Could not find Automation.tracetemplate in any of the following' +\n `locations ${automationTraceTemplatePaths.toString()}`;\n log.error(msg);\n throw new Error(msg);\n\n}\n\nconst getAutomationTraceTemplatePath = _.memoize(\n function getAutomationTraceTemplatePath (retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {\n return retry(retries, getAutomationTraceTemplatePathWithoutRetry, timeout);\n }\n);\n\nasync function getMaxIOSSDKWithoutRetry (timeout = XCRUN_TIMEOUT) {\n const version = await getVersion(false, DEFAULT_NUMBER_OF_RETRIES, timeout);\n if (version[0] === '4') {\n return '6.1';\n }\n\n const args = ['--sdk', 'iphonesimulator', '--show-sdk-version'];\n const {stdout} = await runXcrunCommand(args, timeout);\n\n const sdkVersion = stdout.trim();\n const match = /\\d.\\d/.exec(stdout);\n\n if (!match) {\n throw new Error(`xcrun returned a non-numeric iOS SDK version: '${sdkVersion}'`);\n }\n\n return sdkVersion;\n}\n\nasync function getMaxIOSSDKFromXcodeVersion (timeout = XCRUN_TIMEOUT) {\n const version = await getVersion(true, DEFAULT_NUMBER_OF_RETRIES, timeout);\n // as of now, the iOS version associated with an Xcode version is\n // just the Xcode version + 2\n return `${version.major + 2}.${version.minor}`;\n}\n\nconst getMaxIOSSDK = _.memoize(\n function getMaxIOSSDK (retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {\n try {\n return retry(retries, getMaxIOSSDKWithoutRetry, timeout);\n } catch (err) {\n log.warn(`Unable to retrieve maximum iOS version: ${err.message}`);\n log.warn('Guessing from Xcode version');\n return getMaxIOSSDKFromXcodeVersion(timeout);\n }\n }\n);\n\nasync function getMaxTVOSSDKWithoutRetry (timeout = XCRUN_TIMEOUT) {\n const args = ['--sdk', 'appletvsimulator', '--show-sdk-version'];\n const {stdout} = await runXcrunCommand(args, timeout);\n\n const sdkVersion = stdout.trim();\n\n if (isNaN(parseFloat(sdkVersion))) {\n throw new Error(`xcrun returned a non-numeric tvOS SDK version: '${sdkVersion}'`);\n }\n\n return sdkVersion;\n}\n\nconst getMaxTVOSSDK = _.memoize(\n function getMaxTVOSSDK (retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {\n return retry(retries, getMaxTVOSSDKWithoutRetry, timeout);\n }\n);\n\nasync function getConnectedDevices (timeout = XCRUN_TIMEOUT) {\n const cmd = '/usr/sbin/system_profiler';\n const args = ['-xml', 'SPUSBDataType'];\n let {stdout} = await exec(cmd, args, {timeout});\n let plistContent = parsePlistData(stdout);\n\n let devicesFound = [];\n let entriesToSearch = [plistContent[0]];\n while (entriesToSearch.length > 0) {\n let currentEntry = entriesToSearch.pop();\n if (currentEntry instanceof Array) {\n entriesToSearch = entriesToSearch.concat(currentEntry);\n } else if ((currentEntry._name &&\n currentEntry._name.substring(0, 4) === 'iPad') ||\n (currentEntry._name &&\n currentEntry._name.substring(0, 6) === 'iPhone') ||\n (currentEntry._name && _.includes(currentEntry._name, 'Apple TV'))) {\n let deviceInfo = {\n name: currentEntry._name,\n udid: currentEntry.serial_num,\n productId: currentEntry.product_id,\n deviceVersion: currentEntry.bcd_device\n };\n devicesFound.push(deviceInfo);\n } else if (currentEntry._items) {\n entriesToSearch = entriesToSearch.concat(currentEntry._items);\n }\n }\n return devicesFound;\n}\n\nasync function getInstrumentsPathWithoutRetry (timeout = XCRUN_TIMEOUT) {\n const args = ['-find', 'instruments'];\n let {stdout} = await runXcrunCommand(args, timeout);\n\n if (!stdout) {\n stdout = '';\n }\n\n let instrumentsPath = stdout.trim();\n\n if (!instrumentsPath) {\n throw new Error(`Could not find path to instruments binary using 'xcrun ${args.join(' ')}'`);\n }\n\n return instrumentsPath;\n}\n\nconst getInstrumentsPath = _.memoize(\n function getInstrumentsPath (retries = DEFAULT_NUMBER_OF_RETRIES, timeout = XCRUN_TIMEOUT) {\n return retry(retries, getInstrumentsPathWithoutRetry, timeout);\n }\n);\n\nfunction clearInternalCache () {\n\n // memoized functions\n const memoized = [\n getPath, getVersionMemoized, getAutomationTraceTemplatePath, getMaxIOSSDK,\n getMaxTVOSSDK, getInstrumentsPath,\n ];\n\n memoized.forEach((f) => {\n if (f.cache) {\n f.cache = new _.memoize.Cache();\n }\n });\n}\n\nexport {\n getPath, getVersion, getAutomationTraceTemplatePath, getMaxIOSSDK,\n getAutomationTraceTemplatePathWithoutRetry, getMaxIOSSDKWithoutRetry,\n getConnectedDevices, clearInternalCache, getInstrumentsPath,\n getCommandLineToolsVersion, getMaxTVOSSDK, getMaxTVOSSDKWithoutRetry,\n getClangVersion,\n};\n"],"mappings":"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"}