Skip to content

Commit e6e5dc0

Browse files
committed
ci: Improve log output (mainly Travis).
* Bring back colors on Travis, which was disabled since rust-lang#39036. Append --color=always to cargo when running in CI environment. * Removed `set -x` in the shell scripts. The `retry` function already prints which command it is running, add `-x` just add noise to the output. * Support travis_fold/travis_time. Matching pairs of these allow Travis CI to collapse the output in between. This greatly cut down the unnecessary "successful" output one need to scroll through before finding the failed statement.
1 parent 1a1ea25 commit e6e5dc0

File tree

10 files changed

+225
-16
lines changed

10 files changed

+225
-16
lines changed

.travis.yml

+7-6
Original file line numberDiff line numberDiff line change
@@ -152,20 +152,21 @@ before_script:
152152
echo "#### Disk usage before running script:";
153153
df -h;
154154
du . | sort -nr | head -n100
155-
156-
script:
157155
- >
158156
if [ "$ALLOW_PR" = "" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then
159-
echo skipping, not a full build
157+
export RUN_SCRIPT="echo 'skipping, not a full build'";
160158
else
161-
stamp src/ci/init_repo.sh . "$HOME/rustsrc" &&
159+
RUN_SCRIPT="stamp src/ci/init_repo.sh . $HOME/rustsrc";
162160
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
163-
stamp src/ci/run.sh;
161+
export RUN_SCRIPT="$RUN_SCRIPT && stamp src/ci/run.sh";
164162
else
165-
stamp src/ci/docker/run.sh $IMAGE;
163+
export RUN_SCRIPT="$RUN_SCRIPT && stamp src/ci/docker/run.sh $IMAGE";
166164
fi
167165
fi
168166
167+
script:
168+
- sh -x -c "$RUN_SCRIPT"
169+
169170
after_success:
170171
- >
171172
echo "#### Build successful; Disk usage after running script:";

src/bootstrap/check.rs

+9
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ pub fn cargo(build: &Build, stage: u32, host: &str) {
124124
/// otherwise just implements a few lint-like checks that are specific to the
125125
/// compiler itself.
126126
pub fn tidy(build: &Build, host: &str) {
127+
let _folder = build.fold_output(|| "tidy");
127128
println!("tidy check ({})", host);
128129
let compiler = Compiler::new(0, host);
129130
let mut cmd = build.tool_cmd(&compiler, "tidy");
@@ -148,6 +149,7 @@ pub fn compiletest(build: &Build,
148149
target: &str,
149150
mode: &str,
150151
suite: &str) {
152+
let _folder = build.fold_output(|| format!("test_{}", suite));
151153
println!("Check compiletest suite={} mode={} ({} -> {})",
152154
suite, mode, compiler.host, target);
153155
let mut cmd = Command::new(build.tool(&Compiler::new(0, compiler.host),
@@ -278,6 +280,8 @@ pub fn compiletest(build: &Build,
278280
cmd.arg("--android-cross-path").arg("");
279281
}
280282

283+
build.ci_env.force_coloring_in_ci(&mut cmd);
284+
281285
let _time = util::timeit();
282286
build.run(&mut cmd);
283287
}
@@ -292,6 +296,7 @@ pub fn docs(build: &Build, compiler: &Compiler) {
292296
// tests for all files that end in `*.md`
293297
let mut stack = vec![build.src.join("src/doc")];
294298
let _time = util::timeit();
299+
let _folder = build.fold_output(|| "test_docs");
295300

296301
while let Some(p) = stack.pop() {
297302
if p.is_dir() {
@@ -325,6 +330,7 @@ pub fn docs(build: &Build, compiler: &Compiler) {
325330
/// generate a markdown file from the error indexes of the code base which is
326331
/// then passed to `rustdoc --test`.
327332
pub fn error_index(build: &Build, compiler: &Compiler) {
333+
let _folder = build.fold_output(|| "test_error_index");
328334
println!("Testing error-index stage{}", compiler.stage);
329335

330336
let dir = testdir(build, compiler.host);
@@ -384,6 +390,9 @@ pub fn krate(build: &Build,
384390
}
385391
_ => panic!("can only test libraries"),
386392
};
393+
let _folder = build.fold_output(|| {
394+
format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, name)
395+
});
387396
println!("{} {} stage{} ({} -> {})", test_kind, name, compiler.stage,
388397
compiler.host, target);
389398

src/bootstrap/compile.rs

+4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub fn std(build: &Build, target: &str, compiler: &Compiler) {
4141
let libdir = build.sysroot_libdir(compiler, target);
4242
t!(fs::create_dir_all(&libdir));
4343

44+
let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
4445
println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
4546
compiler.host, target);
4647

@@ -192,6 +193,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st
192193
/// the build using the `compiler` targeting the `target` architecture. The
193194
/// artifacts created will also be linked into the sysroot directory.
194195
pub fn test(build: &Build, target: &str, compiler: &Compiler) {
196+
let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
195197
println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
196198
compiler.host, target);
197199
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
@@ -228,6 +230,7 @@ pub fn test_link(build: &Build,
228230
/// the `compiler` targeting the `target` architecture. The artifacts
229231
/// created will also be linked into the sysroot directory.
230232
pub fn rustc(build: &Build, target: &str, compiler: &Compiler) {
233+
let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
231234
println!("Building stage{} compiler artifacts ({} -> {})",
232235
compiler.stage, compiler.host, target);
233236

@@ -435,6 +438,7 @@ pub fn maybe_clean_tools(build: &Build, stage: u32, target: &str, mode: Mode) {
435438
/// This will build the specified tool with the specified `host` compiler in
436439
/// `stage` into the normal cargo output directory.
437440
pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) {
441+
let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool));
438442
println!("Building stage{} tool {} ({})", stage, tool, target);
439443

440444
let compiler = Compiler::new(stage, &build.config.build);

src/bootstrap/lib.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ use std::process::Command;
9090

9191
use build_helper::{run_silent, run_suppressed, output, mtime};
9292

93-
use util::{exe, libdir, add_lib_path};
93+
use util::{exe, libdir, add_lib_path, OutputFolder, CiEnv};
9494

9595
mod cc;
9696
mod channel;
@@ -179,6 +179,7 @@ pub struct Build {
179179
crates: HashMap<String, Crate>,
180180
is_sudo: bool,
181181
src_is_git: bool,
182+
ci_env: CiEnv,
182183
}
183184

184185
#[derive(Debug)]
@@ -272,6 +273,7 @@ impl Build {
272273
lldb_python_dir: None,
273274
is_sudo: is_sudo,
274275
src_is_git: src_is_git,
276+
ci_env: CiEnv::current(),
275277
}
276278
}
277279

@@ -507,6 +509,9 @@ impl Build {
507509
if self.config.vendor || self.is_sudo {
508510
cargo.arg("--frozen");
509511
}
512+
513+
self.ci_env.force_coloring_in_ci(&mut cargo);
514+
510515
return cargo
511516
}
512517

@@ -1011,6 +1016,19 @@ impl Build {
10111016
"nightly" | _ => true,
10121017
}
10131018
}
1019+
1020+
/// Fold the output of the commands after this method into a group. The fold
1021+
/// ends when the returned object is dropped. Folding can only be used in
1022+
/// the Travis CI environment.
1023+
pub fn fold_output<D, F>(&self, name: F) -> Option<OutputFolder>
1024+
where D: Into<String>, F: FnOnce() -> D
1025+
{
1026+
if self.ci_env == CiEnv::Travis {
1027+
Some(OutputFolder::new(name().into()))
1028+
} else {
1029+
None
1030+
}
1031+
}
10141032
}
10151033

10161034
impl<'a> Compiler<'a> {

src/bootstrap/native.rs

+2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ pub fn llvm(build: &Build, target: &str) {
6363
drop(fs::remove_dir_all(&out_dir));
6464
}
6565

66+
let _folder = build.fold_output(|| "llvm");
6667
println!("Building LLVM for {}", target);
6768
let _time = util::timeit();
6869
t!(fs::create_dir_all(&out_dir));
@@ -218,6 +219,7 @@ pub fn test_helpers(build: &Build, target: &str) {
218219
return
219220
}
220221

222+
let _folder = build.fold_output(|| "build_test_helpers");
221223
println!("Building test helpers");
222224
t!(fs::create_dir_all(&dst));
223225
let mut cfg = gcc::Config::new();

src/bootstrap/util.rs

+101-2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
use std::env;
1717
use std::ffi::OsString;
1818
use std::fs;
19-
use std::io;
19+
use std::io::{self, Write};
2020
use std::path::{Path, PathBuf};
2121
use std::process::Command;
22-
use std::time::Instant;
22+
use std::time::{SystemTime, Instant};
2323

2424
use filetime::{self, FileTime};
2525

@@ -324,3 +324,102 @@ pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
324324
}
325325
}
326326
}
327+
328+
/// An RAII structure that indicates all output until this instance is dropped
329+
/// is part of the same group.
330+
///
331+
/// On Travis CI, these output will be folded by default, together with the
332+
/// elapsed time in this block. This reduces noise from unnecessary logs,
333+
/// allowing developers to quickly identify the error.
334+
///
335+
/// Travis CI supports folding by printing `travis_fold:start:<name>` and
336+
/// `travis_fold:end:<name>` around the block. Time elapsed is recognized
337+
/// similarly with `travis_time:[start|end]:<name>`. These are undocumented, but
338+
/// can easily be deduced from source code of the [Travis build commands].
339+
///
340+
/// [Travis build commands]:
341+
/// https://github.com/travis-ci/travis-build/blob/f603c0089/lib/travis/build/templates/header.sh
342+
pub struct OutputFolder {
343+
name: String,
344+
start_time: SystemTime, // we need SystemTime to get the UNIX timestamp.
345+
}
346+
347+
impl OutputFolder {
348+
/// Creates a new output folder with the given group name.
349+
pub fn new(name: String) -> OutputFolder {
350+
// "\r" moves the cursor to the beginning of the line, and "\x1b[0K" is
351+
// the ANSI escape code to clear from the cursor to end of line.
352+
// Travis seems to have trouble when _not_ using "\r\x1b[0K", that will
353+
// randomly put lines to the top of the webpage.
354+
print!("travis_fold:start:{0}\r\x1b[0Ktravis_time:start:{0}\r\x1b[0K", name);
355+
OutputFolder {
356+
name,
357+
start_time: SystemTime::now(),
358+
}
359+
}
360+
}
361+
362+
impl Drop for OutputFolder {
363+
fn drop(&mut self) {
364+
use std::time::*;
365+
use std::u64;
366+
367+
fn to_nanos(duration: Result<Duration, SystemTimeError>) -> u64 {
368+
match duration {
369+
Ok(d) => d.as_secs() * 1_000_000_000 + d.subsec_nanos() as u64,
370+
Err(_) => u64::MAX,
371+
}
372+
}
373+
374+
let end_time = SystemTime::now();
375+
let duration = end_time.duration_since(self.start_time);
376+
let start = self.start_time.duration_since(UNIX_EPOCH);
377+
let finish = end_time.duration_since(UNIX_EPOCH);
378+
println!(
379+
"travis_fold:end:{0}\r\x1b[0K\n\
380+
travis_time:end:{0}:start={1},finish={2},duration={3}\r\x1b[0K",
381+
self.name,
382+
to_nanos(start),
383+
to_nanos(finish),
384+
to_nanos(duration)
385+
);
386+
io::stdout().flush().unwrap();
387+
}
388+
}
389+
390+
/// The CI environment rustbuild is running in. This mainly affects how the logs
391+
/// are printed.
392+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
393+
pub enum CiEnv {
394+
/// Not a CI environment.
395+
None,
396+
/// The Travis CI environment, for Linux (including Docker) and macOS builds.
397+
Travis,
398+
/// The AppVeyor environment, for Windows builds.
399+
AppVeyor,
400+
}
401+
402+
impl CiEnv {
403+
/// Obtains the current CI environment.
404+
pub fn current() -> CiEnv {
405+
if env::var("TRAVIS").ok().map_or(false, |e| &*e == "true") {
406+
CiEnv::Travis
407+
} else if env::var("APPVEYOR").ok().map_or(false, |e| &*e == "True") {
408+
CiEnv::AppVeyor
409+
} else {
410+
CiEnv::None
411+
}
412+
}
413+
414+
/// If in a CI environment, forces the command to run with colors.
415+
pub fn force_coloring_in_ci(self, cmd: &mut Command) {
416+
if self != CiEnv::None {
417+
// Due to use of stamp/docker, the output stream of rustbuild is not
418+
// a TTY in CI, so coloring is by-default turned off.
419+
// The explicit `TERM=xterm` environment is needed for
420+
// `--color always` to actually work. This env var was lost when
421+
// compiling through the Makefile. Very strange.
422+
cmd.env("TERM", "xterm").args(&["--color", "always"]);
423+
}
424+
}
425+
}

src/ci/docker/run.sh

+7
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ root_dir="`dirname $src_dir`"
2121

2222
source "$ci_dir/shared.sh"
2323

24+
travis_fold start build_docker
25+
travis_time_start
26+
2427
if [ -f "$docker_dir/$image/Dockerfile" ]; then
2528
retry docker \
2629
build \
@@ -44,6 +47,9 @@ else
4447
exit 1
4548
fi
4649

50+
travis_fold end build_docker
51+
travis_time_finish
52+
4753
objdir=$root_dir/obj
4854

4955
mkdir -p $HOME/.cargo
@@ -72,6 +78,7 @@ exec docker \
7278
--env DEPLOY=$DEPLOY \
7379
--env DEPLOY_ALT=$DEPLOY_ALT \
7480
--env LOCAL_USER_ID=`id -u` \
81+
--env TRAVIS=${TRAVIS-false} \
7582
--volume "$HOME/.cargo:/cargo" \
7683
--volume "$HOME/rustsrc:$HOME/rustsrc" \
7784
--privileged \

src/ci/init_repo.sh

+19-2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ set -o errexit
1313
set -o pipefail
1414
set -o nounset
1515

16-
set -o xtrace
17-
1816
ci_dir=$(cd $(dirname $0) && pwd)
1917
. "$ci_dir/shared.sh"
2018

19+
travis_fold start init_repo
20+
2121
REPO_DIR="$1"
2222
CACHE_DIR="$2"
2323

@@ -38,6 +38,7 @@ fi
3838

3939
# Wipe the cache if it's not valid, or mark it as invalid while we update it
4040
if [ ! -f "$cache_valid_file" ]; then
41+
echo "Invalid cache, wiping ($cache_valid_file missing)"
4142
rm -rf "$CACHE_DIR"
4243
mkdir "$CACHE_DIR"
4344
else
@@ -54,10 +55,14 @@ else
5455
rm -rf "$CACHE_DIR"
5556
mkdir "$CACHE_DIR"
5657
else
58+
echo "Valid cache ($cache_valid_file exists)"
5759
rm "$cache_valid_file"
5860
fi
5961
fi
6062

63+
travis_fold start update_cache
64+
travis_time_start
65+
6166
# Update the cache (a pristine copy of the rust source master)
6267
if [ ! -d "$cache_src_dir/.git" ]; then
6368
retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \
@@ -69,8 +74,15 @@ retry sh -c "cd $cache_src_dir && \
6974
git submodule deinit -f . && git submodule sync && git submodule update --init"
7075

7176
# Cache was updated without errors, mark it as valid
77+
echo "Refreshed cache (touch $cache_valid_file)"
7278
touch "$cache_valid_file"
7379

80+
travis_fold end update_cache
81+
travis_time_finish
82+
83+
travis_fold start update_submodules
84+
travis_time_start
85+
7486
# Update the submodules of the repo we're in, using the pristine repo as
7587
# a cache for any object files
7688
# No, `git submodule foreach` won't work:
@@ -94,3 +106,8 @@ for module in $modules; do
94106
retry sh -c "git submodule deinit -f $module && \
95107
git submodule update --init --reference $cache_src_dir/$module $module"
96108
done
109+
110+
travis_fold end update_submodules
111+
travis_time_finish
112+
113+
travis_fold end init_repo

0 commit comments

Comments
 (0)