Skip to content

Commit e9135a6

Browse files
authored
Fix xcresult log output in Travis (#5645)
* Remove code folding and raw log output Code folds were interacting poorly with Travis and causing output to be lost. This was causing xcresult log output to be lost. Travis terminates jobs that exceed its maximum log output length, so showing raw log output could cause failing jobs to be killed for unrelated reasons. * Fix xcresult_logs when run against non-Run configurations The leading part of the name can be "Run" or "Test" or others. * Add support for Xcode 10 xcreult bundles
1 parent 885f296 commit e9135a6

File tree

2 files changed

+61
-56
lines changed

2 files changed

+61
-56
lines changed

scripts/build.sh

Lines changed: 4 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ function RunXcodebuild() {
114114

115115
result=0
116116
xcodebuild "$@" | tee xcodebuild.log | "${xcpretty_cmd[@]}" || result=$?
117+
117118
if [[ $result == 65 ]]; then
118119
ExportLogs "$@"
119120

@@ -123,12 +124,9 @@ function RunXcodebuild() {
123124
result=0
124125
xcodebuild "$@" | tee xcodebuild.log | "${xcpretty_cmd[@]}" || result=$?
125126
fi
126-
if [[ $result != 0 ]]; then
127127

128-
echo "xcodebuild exited with $result; raw log follows" 1>&2
129-
OpenFold Raw log
130-
cat xcodebuild.log
131-
CloseFold
128+
if [[ $result != 0 ]]; then
129+
echo "xcodebuild exited with $result" 1>&2
132130

133131
ExportLogs "$@"
134132
return $result
@@ -137,50 +135,7 @@ function RunXcodebuild() {
137135

138136
# Exports any logs output captured in the xcresult
139137
function ExportLogs() {
140-
OpenFold XCResult
141-
142-
exporter="${scripts_dir}/xcresult_logs.py"
143-
python "$exporter" "$@"
144-
145-
CloseFold
146-
}
147-
148-
current_group=none
149-
current_fold=0
150-
151-
# Prints a command for CI environments to group log output in the logs
152-
# presentation UI.
153-
function OpenFold() {
154-
description="$*"
155-
current_group="$(echo "$description" | tr '[A-Z] ' '[a-z]_')"
156-
157-
if [[ -n "${GITHUB_ACTIONS:-}" ]]; then
158-
echo "::group::description"
159-
160-
elif [[ -n "${TRAVIS:-}" ]]; then
161-
# Travis wants groups to be numbered.
162-
current_group="${current_group}.${current_fold}"
163-
let current_fold++
164-
165-
# Show description in yellow.
166-
echo "travis_fold:start:${current_group}\033[33;1m${description}\033[0m"
167-
168-
else
169-
echo "===== $description Start ====="
170-
fi
171-
}
172-
173-
# Closes the current fold opened by `OpenFold`.
174-
function CloseFold() {
175-
if [[ -n "${GITHUB_ACTIONS:-}" ]]; then
176-
echo "::endgroup::"
177-
178-
elif [[ -n "${TRAVIS:-}" ]]; then
179-
echo "travis_fold:end:${current_group}"
180-
181-
else
182-
echo "===== $description End ====="
183-
fi
138+
python "${scripts_dir}/xcresult_logs.py" "$@"
184139
}
185140

186141
if [[ "$xcode_major" -lt 11 ]]; then

scripts/xcresult_logs.py

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import json
2727
import logging
2828
import os
29+
import re
30+
import shutil
2931
import subprocess
3032
import sys
3133

@@ -52,9 +54,17 @@ def main():
5254
scheme = flags['-scheme']
5355
xcresult_path = find_xcresult_path(project, scheme)
5456

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)
5868

5969

6070
# Most flags on the xcodebuild command-line are uninteresting, so only pull
@@ -114,7 +124,7 @@ def find_xcresult_path(project, scheme):
114124
"""
115125
project_path = find_project_path(project)
116126
bundle_dir = os.path.join(project_path, 'Logs/Test')
117-
prefix = 'Run-' + scheme + '-'
127+
prefix = re.compile('([^-]*)-' + re.escape(scheme) + '-')
118128

119129
_logger.debug('Logging for xcresult bundles in %s', bundle_dir)
120130
xcresult = find_newest_matching_prefix(bundle_dir, prefix)
@@ -136,7 +146,7 @@ def find_project_path(project):
136146
The path containing the newest project output.
137147
"""
138148
path = os.path.expanduser('~/Library/Developer/Xcode/DerivedData')
139-
prefix = project + '-'
149+
prefix = re.compile(re.escape(project) + '-')
140150

141151
# DerivedData has directories like Firestore-csljdukzqbozahdjizcvrfiufrkb. Use
142152
# 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):
155165
156166
Args:
157167
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
159169
160170
Returns:
161171
The path to the newest entry in the directory whose basename starts with
@@ -164,7 +174,7 @@ def find_newest_matching_prefix(path, prefix):
164174
entries = os.listdir(path)
165175
result = None
166176
for entry in entries:
167-
if entry.startswith(prefix):
177+
if prefix.match(entry):
168178
fq_entry = os.path.join(path, entry)
169179
if result is None:
170180
result = fq_entry
@@ -177,6 +187,34 @@ def find_newest_matching_prefix(path, prefix):
177187
return result
178188

179189

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+
180218
def find_log_id(xcresult_path):
181219
"""Finds the id of the last action's logs.
182220
@@ -229,6 +267,18 @@ def collect_log_output(activity_log, result):
229267
collect_log_output(subsection, result)
230268

231269

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+
232282
def xcresulttool(*args):
233283
"""Runs xcresulttool and returns its output as a string."""
234284
cmd = ['xcrun', 'xcresulttool']

0 commit comments

Comments
 (0)