26
26
import json
27
27
import logging
28
28
import os
29
+ import re
30
+ import shutil
29
31
import subprocess
30
32
import sys
31
33
@@ -52,9 +54,17 @@ def main():
52
54
scheme = flags ['-scheme' ]
53
55
xcresult_path = find_xcresult_path (project , scheme )
54
56
55
- log_id = find_log_id (xcresult_path )
56
- log = export_log (xcresult_path , log_id )
57
- sys .stdout .write (log )
57
+ version = find_xcode_major_version ()
58
+ if version <= 10 :
59
+ files = find_legacy_log_files (xcresult_path )
60
+ cat_files (files , sys .stdout )
61
+
62
+ else :
63
+ # Xcode 11 and up ship xcresult tool which standardizes the xcresult format
64
+ # but also makes it harder to deal with.
65
+ log_id = find_log_id (xcresult_path )
66
+ log = export_log (xcresult_path , log_id )
67
+ sys .stdout .write (log )
58
68
59
69
60
70
# Most flags on the xcodebuild command-line are uninteresting, so only pull
@@ -114,7 +124,7 @@ def find_xcresult_path(project, scheme):
114
124
"""
115
125
project_path = find_project_path (project )
116
126
bundle_dir = os .path .join (project_path , 'Logs/Test' )
117
- prefix = 'Run- ' + scheme + '-'
127
+ prefix = re . compile ( '([^-]*)- ' + re . escape ( scheme ) + '-' )
118
128
119
129
_logger .debug ('Logging for xcresult bundles in %s' , bundle_dir )
120
130
xcresult = find_newest_matching_prefix (bundle_dir , prefix )
@@ -136,7 +146,7 @@ def find_project_path(project):
136
146
The path containing the newest project output.
137
147
"""
138
148
path = os .path .expanduser ('~/Library/Developer/Xcode/DerivedData' )
139
- prefix = project + '-'
149
+ prefix = re . compile ( re . escape ( project ) + '-' )
140
150
141
151
# DerivedData has directories like Firestore-csljdukzqbozahdjizcvrfiufrkb. Use
142
152
# the most recent one if there are more than one such directory matching the
@@ -155,7 +165,7 @@ def find_newest_matching_prefix(path, prefix):
155
165
156
166
Args:
157
167
path: A directory to list
158
- prefix: The starting part of any filename to consider
168
+ prefix: A regular expression that matches the filenames to consider
159
169
160
170
Returns:
161
171
The path to the newest entry in the directory whose basename starts with
@@ -164,7 +174,7 @@ def find_newest_matching_prefix(path, prefix):
164
174
entries = os .listdir (path )
165
175
result = None
166
176
for entry in entries :
167
- if entry . startswith ( prefix ):
177
+ if prefix . match ( entry ):
168
178
fq_entry = os .path .join (path , entry )
169
179
if result is None :
170
180
result = fq_entry
@@ -177,6 +187,34 @@ def find_newest_matching_prefix(path, prefix):
177
187
return result
178
188
179
189
190
+ def find_legacy_log_files (xcresult_path ):
191
+ """Finds the log files produced by Xcode 10 and below."""
192
+
193
+ result = []
194
+
195
+ for root , dirs , files in os .walk (xcresult_path , topdown = True ):
196
+ for file in files :
197
+ if file .endswith ('.txt' ):
198
+ file = os .path .join (root , file )
199
+ result .append (file )
200
+
201
+ # Sort the files by creation time.
202
+ result .sort (key = lambda f : os .stat (f ).st_ctime )
203
+ return result
204
+
205
+
206
+ def cat_files (files , output ):
207
+ """Reads the contents of all the files and copies them to the output.
208
+
209
+ Args:
210
+ files: A list of filenames
211
+ output: A file-like object in which all the data should be copied.
212
+ """
213
+ for file in files :
214
+ with open (file , 'r' ) as fd :
215
+ shutil .copyfileobj (fd , output )
216
+
217
+
180
218
def find_log_id (xcresult_path ):
181
219
"""Finds the id of the last action's logs.
182
220
@@ -229,6 +267,18 @@ def collect_log_output(activity_log, result):
229
267
collect_log_output (subsection , result )
230
268
231
269
270
+ def find_xcode_major_version ():
271
+ """Determines the major version number of Xcode."""
272
+ cmd = ['xcodebuild' , '-version' ]
273
+ command_trace .log (cmd )
274
+
275
+ result = str (subprocess .check_output (cmd ))
276
+ version = result .split ('\n ' , 1 )[0 ]
277
+ version = re .sub (r'Xcode ' , '' , version )
278
+ version = re .sub (r'\..*' , '' , version )
279
+ return int (version )
280
+
281
+
232
282
def xcresulttool (* args ):
233
283
"""Runs xcresulttool and returns its output as a string."""
234
284
cmd = ['xcrun' , 'xcresulttool' ]
0 commit comments