diff --git a/Cargo.toml b/Cargo.toml index 9b5c08722..6684e16b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ tokio-core = "0.1.7" tokio-io = "0.1.1" tokio-process = "0.1.2" tokio-timer = "0.1.1" -toml = "0.4.1" +toml = "0.4.6" url = "1.1" walkdir = "2" regex = "0.2.10" diff --git a/config.toml b/config.toml index 9392f8262..045a86c63 100644 --- a/config.toml +++ b/config.toml @@ -24,10 +24,16 @@ github-repos = ["brson/hello-rs"] # These sections allows to customize how crater treats specific crates/repos # # The available options for each crate/repo are: -# - skip (bool): ignore this crate/repo -# - skip-tests (bool): don't run tests in this crate/repo -# - quiet (bool): don't kill after two minutes without output -# +# - skip (bool): ignore this crate/repo +# - skip-tests (bool): don't run tests in this crate/repo +# - quiet (bool): don't kill after two minutes without output +# - update-lockfile (bool): update the lockfile even if the crate has one +# - broken (bool): treat a Crater error on this crate/repo as a build +# failure (typically the crate is broken in an +# unusual way and we want to indicate the failure +# is 'permissible', while still building it if the +# failure is resolved in the future) + # Please add a comment along with each entry explaining the reasons of the # changes, thanks! @@ -60,6 +66,7 @@ advpack-sys = { skip = true } #automatic aerial = { skip = true } #automatic aerospike = { skip-tests = true } #automatic af_unix = { skip = true } #automatic +afl = { broken = true } # dependency yanked afl-plugin = { skip = true } #automatic afl-sys = { skip-tests = true } #automatic ahadmin-sys = { skip = true } #automatic @@ -347,6 +354,7 @@ cargo_rub = { skip = true } #automatic carto = { skip = true } #automatic cassandra = { skip = true } #automatic cassandra-cpp = { skip = true } #automatic +cassandra-sys = { broken = true } # dependency yanked cast = { skip = true } #automatic castle-game = { skip = true } #automatic catalog = { skip-tests = true } #automatic @@ -482,7 +490,7 @@ cplex-sys = { skip = true } #automatic cplx = { skip = true } #automatic cppStream = { skip = true } #automatic cpp_codegen = { skip = true } #automatic -cpp_demangle = { skip-tests = true } #automatic +cpp_demangle = { broken = true } # dependency yanked cpp_to_rust = { skip = true } #automatic cpr = { skip-tests = true } #automatic cpuid = { skip = true } #automatic @@ -943,12 +951,14 @@ from_error_scope = { skip-tests = true } #automatic fromxml = { skip = true } #automatic fs-utils = { skip-tests = true } #automatic fs_extra = { skip-tests = true } #automatic +fsevent = { broken = true } # dependency yanked fswatch = { skip = true } #automatic ftdi = { skip = true } #automatic ftp = { skip-tests = true } #automatic fts = { skip-tests = true } #automatic fun = { skip = true } #automatic functional = { skip = true } #automatic +fungtaai = { broken = true } # dependency yanked fuse = { skip = true } #automatic fuse_mt = { skip = true } #automatic futures-await-syn = { skip-tests = true } #automatic @@ -984,6 +994,7 @@ gears-cli = { skip = true } #automatic generic-dns-update = { skip = true } #automatic genetic = { skip = true } #automatic geocode = { skip-tests = true } # depends on network +geogrid = { broken = true } # invalid Cargo.toml geomprim2d = { skip = true } #automatic geoshaper = { skip = true } #automatic get_errno = { skip = true } #automatic @@ -1018,6 +1029,7 @@ gitx = { skip = true } #automatic glib = { slow = true } # tests slow to run glide = { skip = true } #automatic glium = { slow = true } # tests build time close to 2 minutes +glium_macros = { broken = true } # broken tarball glm = { skip-tests = true } #automatic glmf32-sys = { skip = true } #automatic glop = { skip = true } #automatic @@ -1054,17 +1066,23 @@ google-cloudkms1 = { skip-tests = true } #automatic google-cloudkms1_beta1 = { skip-tests = true } #automatic google-cloudresourcemanager1 = { skip-tests = true } #automatic google-cloudresourcemanager1_beta1 = { skip-tests = true } #automatic +google-cloudsearch1 = { broken = true } # broken tarball google-cloudtasks2_beta2 = { skip-tests = true } #automatic google-container1 = { skip-tests = true } #automatic google-container1_beta1 = { skip = true } #automatic +google-dataflow1_b4 = { broken = true } # broken tarball google-datastore1_beta2 = { skip = true } #automatic +google-deploymentmanager2_beta1 = { broken = true } # broken tarball +google-dfareporting2 = { broken = true } # broken tarball google-dfareporting2d7-cli = { skip = true } #automatic google-dialogflow2_beta1 = { skip-tests = true } #automatic google-dlp2_beta1 = { skip-tests = true } #automatic +google-dns1_beta1 = { broken = true } # broken tarball google-firestore1_beta1 = { skip-tests = true } #automatic google-freebase1 = { skip = true } #automatic google-freebase1_sandbox = { skip = true } #automatic google-genomics1 = { skip-tests = true } #automatic +google-genomics1_beta2 = { broken = true } # broken tarball google-geo = { skip = true } #automatic google-iam1 = { skip-tests = true } #automatic google-kgsearch1-cli = { skip = true } #automatic @@ -1168,6 +1186,7 @@ hdf5-rs = { skip = true } #automatic hdfs = { skip = true } #automatic he_di = { skip = true } #automatic he_di_derive = { skip = true } #automatic +he_di_internals = { broken = true } # dependency yanked heapsize_plugin = { skip = true } #automatic heartbeat = { skip = true } #automatic heartbeats-simple = { skip-tests = true } #automatic @@ -1425,6 +1444,7 @@ libarchive3-sys = { skip = true } #automatic libb2-sys = { skip = true } #automatic libbgmrank = { skip = true } #automatic libbindgen = { skip = true } #automatic +libbreakpad-client-sys = { broken = true } # broken tarball libcapstone = { skip = true } #automatic libcapstone-sys = { skip = true } #automatic libcryptsetup-sys = { skip = true } #automatic @@ -1437,6 +1457,7 @@ libfa-sys = { skip = true } #automatic libfabric = { skip = true } #automatic libflo_cmdline_host = { skip-tests = true } #automatic libflo_func = { skip-tests = true } #automatic +libfoo-test = { broken = true } # dependency yanked libftdi1-sys = { skip = true } #automatic libfuzzy-sys = { skip = true } # flaky build libgcrypt-sys = { skip = true } #automatic @@ -1516,6 +1537,7 @@ lion = { skip-tests = true } #automatic liquidfun = { skip = true } #automatic liste = { skip = true } #automatic lit = { skip-tests = true } #automatic +live2d = { broken = true } # dependency yanked livesplit-core = { skip = true } #automatic llang = { skip = true } #automatic lldb = { skip = true } #automatic @@ -1643,6 +1665,7 @@ might-be-minified = { skip-tests = true } #automatic milagro-crypto = { skip-tests = true } # flaky test (segfaults) millefeuille = { skip = true } #automatic min_max_macros = { skip-tests = true } #automatic +minc = { broken = true } # dependency yanked mincore-sys = { skip = true } #automatic mincore_downlevel-sys = { skip = true } #automatic minidump = { skip-tests = true } #automatic @@ -1748,6 +1771,7 @@ muiload-sys = { skip = true } #automatic multi-input = { skip = true } #automatic multi-logger = { skip = true } #automatic multidim = { skip = true } #automatic +multihash = { broken = true } # dependency yanked multiinput = { skip = true } #automatic multitooth = { skip = true } #automatic must = { skip-tests = true } #automatic @@ -1977,6 +2001,7 @@ palarust = { skip = true } #automatic pam = { skip = true } #automatic pam_groupmap = { skip = true } #automatic pandoc_types = { skip-tests = true } #automatic +pangocairo = { broken = true } # dependency yanked panini_codegen = { skip = true } #automatic panini_macros = { skip = true } #automatic panini_macros_snapshot = { skip = true } #automatic @@ -2066,6 +2091,7 @@ plumbum = { skip = true } #automatic pluto = { skip = true } #automatic ply-rs = { skip-tests = true } #automatic pmap = { skip = true } #automatic +pnet = { broken = true } # missing feature pnet_macros_plugin = { skip = true } #automatic pnetlink = { skip = true } #automatic png_encode_mini = { skip-tests = true } #automatic @@ -2251,6 +2277,8 @@ replace-map = { skip = true } #automatic repose = { skip = true } #automatic reproto = { skip = true } #automatic reproto-path-parser = { skip = true } #automatic +reql = { broken = true } # dependency yanked +reql-io = { broken = true } # dependency yanked rerast_macros = { skip-tests = true } #automatic reru = { skip-tests = true } #automatic resources_package = { skip = true } #automatic @@ -2304,6 +2332,7 @@ rotor = { skip = true } #automatic rotor-stream = { skip = true } #automatic roulette = { skip-tests = true } #automatic rovr = { skip = true } #automatic +rpc = { broken = true } # missing Cargo.toml rpcexts-sys = { skip = true } #automatic rpcns4-sys = { skip = true } #automatic rpcperf_workload = { skip = true } #automatic @@ -2365,6 +2394,7 @@ rula = { skip = true } #automatic rules = { skip = true } #automatic rulinalg = { skip-tests = true } #automatic rum = { skip = true } #automatic +ruma-signatures = { broken = true } # dependency yanked rumblebars = { skip = true } #automatic rumblebars-rustlex = { skip = true } #automatic rumblebars-rustlex_codegen = { skip = true } #automatic @@ -2376,6 +2406,7 @@ rung_vm = { skip = true } #automatic runwhen = { skip = true } #automatic ruplicity = { skip = true } #automatic rurust = { skip = true } #automatic +rusoto = { broken = true } # dependency yanked rusql = { skip = true } #automatic rust-3d = { skip = true } #automatic rust-GSL = { skip = true } #automatic @@ -2455,6 +2486,7 @@ rusty-keys = { skip = true } #automatic rusty_ally = { skip = true } #automatic rusty_hearth = { skip = true } #automatic rustyham = { skip = true } #automatic +rustysecrets-cli = { broken = true } # dependency yanked rvs-c-api = { skip-tests = true } #automatic rvs-parser = { skip-tests = true } #automatic rwc = { skip = true } #automatic @@ -2503,12 +2535,14 @@ scoped_allocator = { skip = true } #automatic scopeguard = { skip-tests = true } #automatic score = { skip = true } #automatic scout = { skip-tests = true } #automatic +scram = { broken = true } # dependency yanked screen-framing = { skip = true } #automatic screenruster = { skip = true } #automatic screenshot = { skip = true } #automatic scribe = { skip-tests = true } #automatic scrnsave-sys = { skip = true } #automatic scrnsavw-sys = { skip = true } #automatic +scroll = { broken = true } # dependency yanked sdc = { skip-tests = true } #automatic sdf = { skip = true } #automatic se_rs_ial = { skip = true } #automatic @@ -2553,6 +2587,7 @@ sfc-sys = { skip = true } #automatic sfml-modstream = { skip = true } #automatic sfnt2woff-zopfli-sys = { skip = true } #automatic sg3 = { skip = true } #automatic +sgxs = { broken = true } # dependency yanked sgxs-tools = { skip = true } #automatic sha = { skip = true } #automatic sha1-hasher = { skip = true } #automatic @@ -2564,6 +2599,7 @@ sharepoint = { skip-tests = true } #automatic shcore-sys = { skip = true } #automatic shdocvw-sys = { skip = true } #automatic sheesy-cli = { skip = true } #automatic +sheesy-extract = { broken = true } # dependency yanked sheesy-vault = { skip = true } #automatic shfolder-sys = { skip = true } #automatic shiny = { skip = true } #automatic @@ -2581,6 +2617,7 @@ sigrok-sys = { skip = true } #automatic silk = { slow = true } # tests slow to run silverknife = { skip = true } #automatic simavr-sys = { skip = true } #automatic +simd = { broken = true } # missing feature simdop = { skip = true } #automatic simple = { skip = true } #automatic simple-cgi = { skip = true } #automatic @@ -2714,6 +2751,7 @@ strong_rc = { skip = true } #automatic strophe = { skip = true } #automatic strsafe-sys = { skip = true } #automatic strscan = { skip = true } #automatic +structopt = { broken = true } # missing feature structuredquery-sys = { skip = true } #automatic subotai = { skip = true } #automatic subprocess-communicate = { skip-tests = true } #automatic @@ -2843,6 +2881,7 @@ to = { skip = true } #automatic toa-find = { skip-tests = true } #automatic tobii-sys = { skip = true } #automatic tofu = { skip = true } #automatic +tokio = { broken = true } # missing feature tokio-batch = { skip-tests = true } #automatic tokio-file = { skip = true } #automatic tokio-http2 = { skip = true } #automatic @@ -2851,9 +2890,11 @@ tokio-memcache = { skip-tests = true } #automatic tokio-postgres = { skip-tests = true } #automatic tokio-process = { skip-tests = true } #automatic tokio-rpc = { skip = true } #automatic +tokio-rustls = { broken = true } # missing feature tokio-smtp = { skip = true } #automatic tokio-thrift-codegen = { skip-tests = true } #automatic tokio-uds-proto = { skip-tests = true } #automatic +tokio-zmq = { broken = true } # missing feature tokyocabinet-sys = { skip = true } #automatic tomcrypt-sys = { skip-tests = true } #automatic toml_document = { skip = true } #automatic @@ -3159,6 +3200,7 @@ xmodem = { skip-tests = true } #automatic xmpp-addr = { skip-tests = true } #automatic xolehlp-sys = { skip = true } #automatic xor_name = { skip = true } #automatic +xoroshiro = { broken = true } # dependency yanked xplm = { skip = true } #automatic xpsprint-sys = { skip = true } #automatic xpsupport = { skip = true } #automatic @@ -3247,6 +3289,7 @@ zyre-sys = { skip = true } #automatic "Bobo1239/rust-vst-demo" = { skip = true } #automatic "BookOwl/rusty-markov" = { skip = true } #automatic "BrainBlasted/Trumpet" = { skip = true } #automatic +"BurntSushi/cargo-benchcmp" = { update-lockfile = true } # outdated lockfile "BygoneWorlds/telepipe" = { skip = true } #automatic "CSM-Dream-Team/final-project" = { skip = true } #automatic "CanalTP/mimirsbrunn" = { skip = true } #automatic @@ -3311,6 +3354,7 @@ zyre-sys = { skip = true } #automatic "JuanPotato/botato" = { skip = true } #automatic "KaiserKyle/Rust_Chip8" = { skip = true } #automatic "Keats/gutenberg" = { skip = true } #automatic +"KeenS/cargo-pack-docker" = { update-lockfile = true } # outdated lockfile "KeenS/webml" = { skip = true } #automatic "Kerollmops/particle-system-rs" = { skip = true } #automatic "KeyboardFire/babble" = { skip = true } #automatic @@ -3431,6 +3475,7 @@ zyre-sys = { skip = true } #automatic "acmiyaguchi/rust-tinywm" = { skip = true } #automatic "adamgreig/asfmrs" = { skip = true } #automatic "adamwilbert/Rust-Guessing-Game" = { skip = true } #automatic +"adfaure/batsim.rs" = { update-lockfile = true } # outdated lockfile "adinapoli/profiv" = { skip = true } #automatic "adinapoli/viktor" = { skip = true } #automatic "agatan/yoin" = { skip = true } #automatic @@ -3476,6 +3521,7 @@ zyre-sys = { skip = true } #automatic "antifuchs/tmux_min_attacher" = { skip = true } #automatic "antiochp/grin-keybase-wallet" = { skip = true } #automatic "antoyo/titanium" = { skip = true } #automatic +"anvie/litcrypt.rs" = { broken = true } # path-only dependency "aochagavia/Rust-Sudoku-Solver" = { skip = true } #automatic "aochagavia/rocket" = { skip = true } #automatic "aochagavia/rocket_wasm" = { skip = true } #automatic @@ -3541,6 +3587,7 @@ zyre-sys = { skip = true } #automatic "ca1ek/tetrahedrane" = { skip = true } #automatic "campaul/shovel" = { skip = true } #automatic "cantsin/pcg" = { skip = true } #automatic +"cardoe/cargo-bitbake" = { update-lockfile = true } # outdated lockfile "carllerche/tokio-examples" = { skip = true } #automatic "cbiffle/httpd1" = { skip = true } #automatic "cdbfoster/takkerus" = { skip = true } #automatic @@ -3577,6 +3624,7 @@ zyre-sys = { skip = true } #automatic "compass-rs/compass" = { skip = true } #automatic "computermouth/slapfight" = { skip = true } #automatic "conradkdotcom/rooster" = { skip = true } #automatic +"cora32/Linkcrawl" = { update-lockfile = true } # outdated lockfile "coredump-ch/coredumpbot" = { skip = true } #automatic "coredump-ch/mdr" = { skip = true } #automatic "cptroot/gnu-efi" = { skip = true } #automatic @@ -3584,6 +3632,7 @@ zyre-sys = { skip = true } #automatic "cracell/objects-in-space" = { skip = true } #automatic "crazymykl/rust-koans" = { skip = true } #automatic "creativcoder/graphin" = { skip = true } #automatic +"creators/cli.sudoku.rs" = { update-lockfile = true } # outdated lockfile "cristeahub/hvilkenukeerdet" = { skip = true } #automatic "cristianoliveira/funzzy" = { skip = true } #automatic "cristicbz/treebank-tokenizer" = { skip = true } #automatic @@ -3636,6 +3685,7 @@ zyre-sys = { skip = true } #automatic "dguenther/rustchip" = { skip = true } #automatic "dixego/motherbase_name_generator" = { skip = true } #automatic "djc/rust-sign" = { skip = true } #automatic +"djmcgill/form" = { update-lockfile = true } # outdated lockfile "dlecan/rpi-management-api" = { skip = true } #automatic "dndx/pitot" = { skip = true } #automatic "dominictassio/peacock_panel" = { skip = true } #automatic @@ -3668,6 +3718,7 @@ zyre-sys = { skip = true } #automatic "ef4/advent-of-code" = { skip = true } #automatic "eightbitraptor/bwt-rust" = { skip = true } #automatic "elsuizo/RSIS_Rust" = { skip = true } #automatic +"emabee/rust-hdbconnect" = { update-lockfile = true } # outdated lockfile "emk/rust-slow-iteration-demo" = { skip = true } #automatic "emk/substudy" = { skip-tests = true } #automatic "emreyaren/zero85" = { skip = true } #automatic @@ -3693,6 +3744,7 @@ zyre-sys = { skip = true } #automatic "fehrenbach/tuner" = { skip = true } #automatic "fengalin/media-toc" = { skip = true } #automatic "fenhl/lore-seeker-discord" = { skip = true } #automatic +"fiirhok/mailcheck.rs" = { update-lockfile = true } # outdated lockfile "fitzgen/clife" = { skip = true } #automatic "fitzgen/oxischeme" = { skip = true } #automatic "fitzgen/preduce" = { skip = true } #automatic @@ -3703,7 +3755,9 @@ zyre-sys = { skip = true } #automatic "folsen/rustfest2017" = { skip = true } #automatic "fosu/myceline" = { skip = true } #automatic "fosu/psilocybin" = { skip = true } #automatic +"frankier/suchalotofdata" = { update-lockfile = true } # outdated lockfile "frankmcsherry/COST" = { skip = true } #automatic +"frewsxcv/alert-after" = { update-lockfile = true } # outdated lockfile "friktor/git4telegram" = { skip = true } #automatic "fschutt/osmpg" = { skip = true } #automatic "funmaker/mandelrust" = { skip = true } #automatic @@ -3806,6 +3860,8 @@ zyre-sys = { skip = true } #automatic "jamesmunns/pide" = { skip = true } #automatic "jamespharaoh/btrfs-dedupe" = { skip = true } #automatic "jamespharaoh/rzbackup" = { skip = true } #automatic +"jamii/imp" = { update-lockfile = true } # outdated lockfile +"japaric/swap-ld" = { update-lockfile = true } # outdated lockfile "jasonwhite/button-rs" = { skip = true } #automatic "jasonwyatt/braid-lib" = { skip = true } #automatic "jauhien/iron-kaleidoscope" = { skip = true } #automatic @@ -3838,6 +3894,7 @@ zyre-sys = { skip = true } #automatic "jroblak/rustproj" = { skip = true } #automatic "jroesch/rustv" = { skip = true } #automatic "jstnlef/rustris" = { skip = true } #automatic +"jswrenn/beep" = { update-lockfile = true } # outdated lockfile "jswrenn/rustylog" = { skip = true } #automatic "jtianling/toc-auto-add" = { skip = true } #automatic "juanibiapina/forust" = { skip = true } #automatic @@ -3946,6 +4003,7 @@ zyre-sys = { skip = true } #automatic "mattkuo/rusty-chips" = { skip = true } #automatic "mattyhall/timmy" = { skip = true } #automatic "maufl/uip" = { skip = true } #automatic +"max6cn/Kaleidoscope.rs" = { update-lockfile = true } # outdated lockfile "mcgoo/vcpkg-rs" = { skip = true } #automatic "mchesser/pikemon" = { skip = true } #automatic "mchesser/snake-rs" = { skip = true } #automatic @@ -3954,6 +4012,7 @@ zyre-sys = { skip = true } #automatic "mdespuits/rust-playpen" = { skip = true } #automatic "mdg/leema" = { skip = true } #automatic "megamsys/meg" = { skip = true } #automatic +"megamsys/megam_api.rs" = { update-lockfile = true } # outdated lockfile "megamsys/rust_cli" = { skip = true } #automatic "mehcode/xchip" = { skip = true } #automatic "mgattozzi/cargo-wa" = { skip = true } #automatic @@ -3978,6 +4037,8 @@ zyre-sys = { skip = true } #automatic "mkpankov/parse-rust" = { skip = true } #automatic "mkpankov/rusty_boy" = { skip = true } #automatic "mlsteele/bittles" = { skip = true } #automatic +"mmacedoeu/csvtoredis" = { update-lockfile = true } # outdated lockfile +"mmacedoeu/csvtoredis.rs" = { update-lockfile = true } # outdated lockfile "mmstick/fontfinder" = { skip = true } #automatic "mmueller/advent2017" = { skip = true } #automatic "mneumann/izhikevich-neurons" = { skip = true } #automatic @@ -4030,6 +4091,7 @@ zyre-sys = { skip = true } #automatic "ogham/exa" = { skip = true } #automatic "ohazi/opengl-demo-rust" = { skip = true } #automatic "ojacobson/rust-mount-demo" = { skip = true } #automatic +"olegakbarov/cali" = { update-lockfile = true } # outdated lockfile "onur/at-rust" = { skip = true } #automatic "opensourcegeek/stest" = { skip = true } #automatic "oracal/rust-gumbo" = { skip = true } #automatic @@ -4053,6 +4115,7 @@ zyre-sys = { skip = true } #automatic "passy/ordered-jobs-kata-rust" = { skip = true } #automatic "paulusx/text_generator" = { skip = true } #automatic "pcwalton/sprocketnes" = { skip = true } #automatic +"pdpi/synth.rs" = { update-lockfile = true } # outdated lockfile "pelmers/geoshaper" = { skip = true } #automatic "pengowen123/horde_survival" = { skip = true } #automatic "pepyakin/chipster" = { skip = true } #automatic @@ -4149,6 +4212,7 @@ zyre-sys = { skip = true } #automatic "rust-lang/rust-playpen" = { skip-tests = true } #automatic "rustamatics/rumo" = { skip = true } #automatic "rustmore/rumenu" = { skip = true } #automatic +"rustoscript.js/rs-parser" = { update-lockfile = true } # outdated lockfile "rustyhorde/goopd" = { skip = true } #automatic "rustyhorde/twists" = { skip = true } #automatic "ruuda/claxon" = { skip-tests = true } #automatic @@ -4228,6 +4292,7 @@ zyre-sys = { skip = true } #automatic "steveklabnik/geekout2016" = { skip = true } #automatic "steveklabnik/parse-example" = { skip = true } #automatic "steveklabnik/rustbook" = { skip = true } #automatic +"steveklabnik/rustdoc" = { update-lockfile = true } # outdated lockfile "sticnarf/shunter-chnroutes" = { skip = true } #automatic "stratis-storage/stratisd" = { skip = true } #automatic "stuarthicks/otp" = { skip = true } #automatic @@ -4270,6 +4335,7 @@ zyre-sys = { skip = true } #automatic "trixnz/rustsym" = { skip = true } #automatic "tschottdorf/findus" = { skip = true } #automatic "tsurai/data-mining-rs" = { skip = true } #automatic +"ttacon/github.rs" = { update-lockfile = true } # outdated lockfile "twincitiespublictelevision/mm_api_notify" = { skip = true } #automatic "txus/lambada-rs" = { skip = true } #automatic "tylerwhall/tis-100-rs" = { skip = true } #automatic @@ -4289,6 +4355,7 @@ zyre-sys = { skip = true } #automatic "vilhalmer/gosh" = { skip = true } #automatic "viperscape/font-atlas-example" = { skip = true } #automatic "viperscape/rust-irc" = { skip = true } #automatic +"vitiral/artifact" = { broken = true } # path-only dependency "vityafx/urlshortener-cli" = { skip = true } #automatic "vlthr/accord" = { skip = true } #automatic "vmchale/project-init" = { skip = true } #automatic diff --git a/docs/cli-usage.md b/docs/cli-usage.md index 7f49d6ebc..78657c64c 100644 --- a/docs/cli-usage.md +++ b/docs/cli-usage.md @@ -12,8 +12,7 @@ own rustup installation, crate mirrors, etc. ``` cargo run -- prepare-local --docker-env mini cargo run -- define-ex --crate-select=demo --cap-lints=forbid stable beta -cargo run -- prepare-ex -cargo run -- run +cargo run -- run-graph --threads NUM_CPUS cargo run -- gen-report work/ex/default/ ``` @@ -36,9 +35,8 @@ defaults to `default`. Here's what each of the steps does: * `define-ex` - defines a new experiment performing a build-test experiment on the 'demo' set of crates. -* `prepare-ex` - fetches repos from github and captures their commit - shas, downloads all crates, hacks up Cargo.toml files, captures - lockfiles, fetches all dependencies, and prepares toolchains. +* `run-graph` - executes the experiment. You can control the number of parallel + tasks executed with the `--threads` flag. * `run` - runs tests on crates in the experiment, against both toolchains diff --git a/docs/legacy-workflow.md b/docs/legacy-workflow.md index b30738ba9..859137d1d 100644 --- a/docs/legacy-workflow.md +++ b/docs/legacy-workflow.md @@ -113,31 +113,14 @@ the sheet that does not have a status of 'Complete' or 'Failed'. necessarily the same date as retrieved in the `BETA_VERSION` command). - Run `cargo run --release -- define-ex --crate-select=full --ex EX_NAME EX_START EX_END`. This will complete in a few seconds. - - Run `cargo run --release -- prepare-ex --ex EX_NAME`. - - Change status to 'Preparing'. + - Run `cargo run --release -- run-graph --threads 8 --ex EX_NAME`. + - Change status to 'Running'. - Update either the PR or the person requesting the run to let them know the run has started. - Go to next run. - - Preparing - - Log onto appropriate box and connect to multiplexer. - - Switch to the `master` multiplexer window. - - If preparation is ongoing, go to next run. - - If preparation failed, fix it. Known errors: - - "missing sha for ..." - remove the referenced repository from `gh-apps.txt` - and `gh-candidates.txt` (may be present in one or both). Make the same - change locally and make a PR against Crater. Use - `cargo run --release -- delete-all-target-dirs --ex EX_NAME` and - `cargo run --release -- delete-ex --ex EX_NAME`, then jump to start of 'Pending'. - - Switch to the `tc1` multiplexer window. - - Run `cargo run --release -- run-tc --ex EX_NAME EX_START`. - - Switch to the `tc2` multiplexer window. - - Run `cargo run --release -- run-tc --ex EX_NAME EX_END`. - - Go to next run. - Running - Log onto appropriate box and connect to multiplexer. - Switch to the `master` multiplexer window. - - If the run is ongoing in either the `tc1` or `tc2` multiplexer - windows, go to next run. - - Switch to the `master` multiplexer window. + - If the run is ongoing go to next run. - Run `du -sh work/ex/EX_NAME`, output should be <2GB. If not: - Run `find work/ex/EX_NAME -type f -size +100M | xargs --no-run-if-empty du -sh`, there will likely only be a couple of files listed and they should be in the `res` directory. diff --git a/gh-apps.txt b/gh-apps.txt index 31f76e982..44f237d01 100644 --- a/gh-apps.txt +++ b/gh-apps.txt @@ -838,7 +838,6 @@ https://github.com/fosu/myceline https://github.com/fosu/psilocybin https://github.com/fourohfour/richter https://github.com/fralalonde/dipstick -https://github.com/frankier/suchalotofdata https://github.com/frankmcsherry/COST https://github.com/franleplant/syntaxis_lexer.rs https://github.com/frewsxcv/alert-after @@ -1024,7 +1023,6 @@ https://github.com/jakubtuchol/ls https://github.com/jamesmunns/pide https://github.com/jamespharaoh/btrfs-dedupe https://github.com/jamespharaoh/rzbackup -https://github.com/jamii/imp https://github.com/japaric/itm https://github.com/japaric/particle-tools https://github.com/japaric/sc-gen @@ -1411,7 +1409,6 @@ https://github.com/ohazi/opengl-demo-rust https://github.com/ohua-dev/ohua-rust-runtime https://github.com/ojacobson/rust-mount-demo https://github.com/oldsj/backup-rs -https://github.com/olegakbarov/cali https://github.com/onefrankguy/chifir https://github.com/onelson/loose-coupling https://github.com/onur/at-rust @@ -1739,11 +1736,11 @@ https://github.com/starlingjs/starling https://github.com/stevej/keymaster https://github.com/steveklabnik/GPACalc.rs https://github.com/steveklabnik/cryptopals +https://github.com/steveklabnik/doxidize https://github.com/steveklabnik/echo https://github.com/steveklabnik/geekout2016 https://github.com/steveklabnik/parse-example https://github.com/steveklabnik/rustbook -https://github.com/steveklabnik/rustdoc https://github.com/steveklabnik/semver.crates.io https://github.com/stewart/rff https://github.com/sticnarf/shunter-chnroutes diff --git a/gh-candidates.txt b/gh-candidates.txt index c26079ff7..c5b11975a 100644 --- a/gh-candidates.txt +++ b/gh-candidates.txt @@ -3301,7 +3301,6 @@ fralalonde/advent-of-code-2017 fralalonde/dipstick francesca64/hotwatch frankier/fst-extra-aut -frankier/suchalotofdata frankmcsherry/COST frankmcsherry/columnar frankmcsherry/dataflow-join @@ -3908,7 +3907,6 @@ jamesmunns/pide jamespharaoh/btrfs-dedupe jamespharaoh/rzbackup jameysharp/weighted-regexp-rs -jamii/imp jamiltron/learn_gfx_2d jamorton/loccr jamorton/rust-dcpu16 @@ -5491,7 +5489,6 @@ ojacobson/rust-mount-demo ojhp/zed oldmacnut/sgt_initramfs oldsj/backup-rs -olegakbarov/cali oli-obk/camera_capture oli-obk/pandoc-ast oli-obk/quine-mc_cluskey @@ -6824,6 +6821,7 @@ steveklabnik/GPACalc.rs steveklabnik/compass-rust steveklabnik/core_mini_http.rs steveklabnik/cryptopals +steveklabnik/doxidize steveklabnik/echo steveklabnik/escape_html steveklabnik/for_bbatha @@ -6836,7 +6834,6 @@ steveklabnik/redis steveklabnik/ruby.rs steveklabnik/rust-issue-17417 steveklabnik/rustbook -steveklabnik/rustdoc steveklabnik/rustque steveklabnik/semver steveklabnik/semver-parser diff --git a/src/agent/results.rs b/src/agent/results.rs index 1cfce07da..61afac45a 100644 --- a/src/agent/results.rs +++ b/src/agent/results.rs @@ -25,7 +25,7 @@ impl<'a> ResultsUploader<'a> { } impl<'a> WriteResults for ResultsUploader<'a> { - fn already_executed( + fn get_result( &self, _ex: &Experiment, _toolchain: &Toolchain, diff --git a/src/cli.rs b/src/cli.rs index 25f26ab6c..fdf0aa02d 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -253,10 +253,11 @@ impl Crater { )?; } Crater::PrepareEx { ref ex } => { + let config = Config::load()?; let ex = ex::Experiment::load(&ex.0)?; let db = FileDB::default(); - ex.prepare_shared(&db)?; - ex.prepare_local()?; + ex.prepare_shared(&config, &db)?; + ex.prepare_local(&config)?; } Crater::CopyEx { ref ex1, ref ex2 } => { ex::copy(&ex1.0, &ex2.0)?; diff --git a/src/config.rs b/src/config.rs index b01a6cbbe..9e4779331 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,6 +17,10 @@ pub struct CrateConfig { pub skip_tests: bool, #[serde(default = "default_false")] pub quiet: bool, + #[serde(default = "default_false")] + pub update_lockfile: bool, + #[serde(default = "default_false")] + pub broken: bool, } fn default_false() -> bool { @@ -82,6 +86,16 @@ impl Config { self.crate_config(c).map(|c| c.quiet).unwrap_or(false) } + pub fn should_update_lockfile(&self, c: &Crate) -> bool { + self.crate_config(c) + .map(|c| c.update_lockfile) + .unwrap_or(false) + } + + pub fn is_broken(&self, c: &Crate) -> bool { + self.crate_config(c).map(|c| c.broken).unwrap_or(false) + } + pub fn demo_crates(&self) -> &DemoCrates { &self.demo_crates } diff --git a/src/crates.rs b/src/crates.rs index de01aa455..276023031 100644 --- a/src/crates.rs +++ b/src/crates.rs @@ -129,30 +129,10 @@ pub fn prepare(list: &[Crate]) -> Result<()> { info!("preparing {} crates", list.len()); let mut successes = 0; for krate in list { - let dir = krate.dir(); - match *krate { - Crate::Registry(ref details) => { - let r = dl_registry(&details.name, &details.version, &dir) - .chain_err(|| format!("unable to download {}", krate)); - if let Err(e) = r { - util::report_error(&e); - } else { - successes += 1; - } - // crates.io doesn't rate limit. Go fast - } - Crate::GitHub(ref repo) => { - info!( - "cloning GitHub repo {} to {}...", - repo.slug(), - dir.display() - ); - if let Err(e) = util::copy_dir(&repo.mirror_dir(), &dir) { - util::report_error(&e); - } else { - successes += 1; - } - } + if let Err(e) = prepare_crate(krate) { + util::report_error(&e); + } else { + successes += 1; } } @@ -163,6 +143,27 @@ pub fn prepare(list: &[Crate]) -> Result<()> { Ok(()) } +pub fn prepare_crate(krate: &Crate) -> Result<()> { + let dir = krate.dir(); + match *krate { + Crate::Registry(ref details) => { + // crates.io doesn't rate limit. Go fast + dl_registry(&details.name, &details.version, &dir) + .chain_err(|| format!("unable to download {}", krate))?; + } + Crate::GitHub(ref repo) => { + info!( + "cloning GitHub repo {} to {}...", + repo.slug(), + dir.display() + ); + util::copy_dir(&repo.mirror_dir(), &dir)?; + } + } + + Ok(()) +} + fn dl_registry(name: &str, vers: &str, dir: &Path) -> Result<()> { if dir.exists() { info!( diff --git a/src/ex.rs b/src/ex.rs index d35f42e24..68f2a13c1 100644 --- a/src/ex.rs +++ b/src/ex.rs @@ -176,21 +176,31 @@ impl Experiment { Ok(()) } - pub fn prepare_shared(&self, db: &DB) -> Result<()> { + pub fn prepare_shared(&self, config: &Config, db: &DB) -> Result<()> { self.fetch_repo_crates()?; capture_shas(self, &self.crates, db)?; crates::prepare(&self.crates)?; frob_tomls(self, &self.crates)?; - capture_lockfiles(self, &self.crates, &Toolchain::Dist("stable".into()), false)?; + capture_lockfiles( + config, + self, + &self.crates, + &Toolchain::Dist("stable".into()), + )?; Ok(()) } - pub fn prepare_local(&self) -> Result<()> { + pub fn prepare_local(&self, config: &Config) -> Result<()> { // Local experiment prep delete_all_target_dirs(&self.name)?; ex_run::delete_all_results(&self.name)?; - fetch_deps(self, &self.crates, &Toolchain::Dist("stable".into()))?; + fetch_deps( + config, + self, + &self.crates, + &Toolchain::Dist("stable".into()), + )?; prepare_all_toolchains(self)?; Ok(()) @@ -204,23 +214,28 @@ impl Experiment { } } -#[cfg_attr(feature = "cargo-clippy", allow(match_ref_pats))] pub fn frob_tomls(ex: &Experiment, crates: &[Crate]) -> Result<()> { for krate in crates { - if let Crate::Registry(ref details) = *krate { - fs::create_dir_all(&froml_dir(&ex.name))?; - let out = froml_path(&ex.name, &details.name, &details.version); - let r = toml_frobber::frob_toml(&krate.dir(), &details.name, &details.version, &out); - if let Err(e) = r { - info!("couldn't frob: {}", e); - util::report_error(&e); - } + if let Err(e) = frob_toml(ex, krate) { + info!("couldn't frob: {}", e); + util::report_error(&e); } } Ok(()) } +#[cfg_attr(feature = "cargo-clippy", allow(match_ref_pats))] +pub fn frob_toml(ex: &Experiment, krate: &Crate) -> Result<()> { + if let Crate::Registry(ref details) = *krate { + fs::create_dir_all(&froml_dir(&ex.name))?; + let out = froml_path(&ex.name, &details.name, &details.version); + toml_frobber::frob_toml(&krate.dir(), &details.name, &details.version, &out)?; + } + + Ok(()) +} + pub fn capture_shas(ex: &Experiment, crates: &[Crate], db: &DB) -> Result<()> { for krate in crates { if let Crate::GitHub(ref repo) = *krate { @@ -318,33 +333,13 @@ where } pub fn capture_lockfiles( + config: &Config, ex: &Experiment, crates: &[Crate], toolchain: &Toolchain, - recapture_existing: bool, ) -> Result<()> { - fs::create_dir_all(&lockfile_dir(&ex.name))?; - for c in crates { - if c.dir().join("Cargo.lock").exists() { - info!("crate {} has a lockfile. skipping", c); - continue; - } - let captured_lockfile = lockfile(&ex.name, c); - if let Err(e) = captured_lockfile { - util::report_error(&e); - continue; - } - let captured_lockfile = captured_lockfile.expect(""); - if captured_lockfile.exists() && !recapture_existing { - info!("skipping existing lockfile for {}", c); - continue; - } - let r = with_work_crate(ex, toolchain, c, |path| { - with_frobbed_toml(ex, c, path)?; - capture_lockfile(ex, c, path, toolchain) - }).chain_err(|| format!("failed to generate lockfile for {}", c)); - if let Err(e) = r { + if let Err(e) = capture_lockfile(config, ex, c, toolchain) { util::report_error(&e); } } @@ -352,7 +347,28 @@ pub fn capture_lockfiles( Ok(()) } -fn capture_lockfile( +pub fn capture_lockfile( + config: &Config, + ex: &Experiment, + krate: &Crate, + toolchain: &Toolchain, +) -> Result<()> { + fs::create_dir_all(&lockfile_dir(&ex.name))?; + + if !config.should_update_lockfile(krate) && krate.dir().join("Cargo.lock").exists() { + info!("crate {} has a lockfile. skipping", krate); + return Ok(()); + } + + with_work_crate(ex, toolchain, krate, |path| { + with_frobbed_toml(ex, krate, path)?; + capture_lockfile_inner(ex, krate, path, toolchain) + }).chain_err(|| format!("failed to generate lockfile for {}", krate))?; + + Ok(()) +} + +fn capture_lockfile_inner( ex: &Experiment, krate: &Crate, path: &Path, @@ -382,12 +398,20 @@ fn capture_lockfile( Ok(()) } -pub fn with_captured_lockfile(ex: &Experiment, krate: &Crate, path: &Path) -> Result<()> { +pub fn with_captured_lockfile( + config: &Config, + ex: &Experiment, + krate: &Crate, + path: &Path, +) -> Result<()> { + let src_lockfile = &lockfile(&ex.name, krate)?; let dst_lockfile = &path.join("Cargo.lock"); - if dst_lockfile.exists() { + + // Only use the local lockfile if it wasn't overridden + if !config.should_update_lockfile(krate) && dst_lockfile.exists() { return Ok(()); } - let src_lockfile = &lockfile(&ex.name, krate)?; + if src_lockfile.exists() { info!("using lockfile {}", src_lockfile.display()); fs::copy(src_lockfile, dst_lockfile).chain_err(|| { @@ -402,20 +426,14 @@ pub fn with_captured_lockfile(ex: &Experiment, krate: &Crate, path: &Path) -> Re Ok(()) } -pub fn fetch_deps(ex: &Experiment, crates: &[Crate], toolchain: &Toolchain) -> Result<()> { +pub fn fetch_deps( + config: &Config, + ex: &Experiment, + crates: &[Crate], + toolchain: &Toolchain, +) -> Result<()> { for c in crates { - let r = with_work_crate(ex, toolchain, c, |path| { - with_frobbed_toml(ex, c, path)?; - with_captured_lockfile(ex, c, path)?; - - let args = &["fetch", "--locked", "--manifest-path", "Cargo.toml"]; - toolchain - .run_cargo(ex, path, args, CargoState::Unlocked, false) - .chain_err(|| format!("unable to fetch deps for {}", c))?; - - Ok(()) - }); - if let Err(e) = r { + if let Err(e) = fetch_crate_deps(config, ex, c, toolchain) { util::report_error(&e); } } @@ -423,6 +441,25 @@ pub fn fetch_deps(ex: &Experiment, crates: &[Crate], toolchain: &Toolchain) -> R Ok(()) } +pub fn fetch_crate_deps( + config: &Config, + ex: &Experiment, + krate: &Crate, + toolchain: &Toolchain, +) -> Result<()> { + with_work_crate(ex, toolchain, krate, |path| { + with_frobbed_toml(ex, krate, path)?; + with_captured_lockfile(config, ex, krate, path)?; + + let args = &["fetch", "--locked", "--manifest-path", "Cargo.toml"]; + toolchain + .run_cargo(ex, path, args, CargoState::Unlocked, false) + .chain_err(|| format!("unable to fetch deps for {}", krate))?; + + Ok(()) + }) +} + pub fn prepare_all_toolchains(ex: &Experiment) -> Result<()> { for tc in &ex.toolchains { tc.prepare()?; diff --git a/src/ex_run.rs b/src/ex_run.rs index 6b7b2f50d..781dfa337 100644 --- a/src/ex_run.rs +++ b/src/ex_run.rs @@ -77,7 +77,16 @@ fn run_exts(ex: &Experiment, tcs: &[Toolchain], config: &Config) -> Result<()> { }; for tc in tcs { - let r = run_test("testing", ex, tc, c, &db, config.is_quiet(c), test_fn); + let r = run_test( + config, + "testing", + ex, + tc, + c, + &db, + config.is_quiet(c), + test_fn, + ); match r { Err(ref e) => { @@ -126,6 +135,10 @@ fn run_exts(ex: &Experiment, tcs: &[Toolchain], config: &Config) -> Result<()> { result: TestResult::TestPass, .. }) => sum_test_pass += 1, + Ok(RunTestResult { + result: TestResult::Error, + .. + }) => unreachable!("error results are not supported with legacy run"), } let elapsed = Instant::now().duration_since(start_time).as_secs(); @@ -181,7 +194,9 @@ pub struct RunTestResult { pub skipped: bool, } +#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] pub fn run_test( + config: &Config, action: &str, ex: &Experiment, tc: &Toolchain, @@ -190,7 +205,7 @@ pub fn run_test( quiet: bool, test_fn: fn(&Experiment, &Path, &Toolchain, bool) -> Result, ) -> Result { - if let Some(res) = db.already_executed(ex, tc, krate)? { + if let Some(res) = db.get_result(ex, tc, krate)? { info!("skipping crate {}. existing result: {}", krate, res); Ok(RunTestResult { result: res, @@ -199,7 +214,7 @@ pub fn run_test( } else { with_work_crate(ex, tc, krate, |source_path| { with_frobbed_toml(ex, krate, source_path)?; - with_captured_lockfile(ex, krate, source_path)?; + with_captured_lockfile(config, ex, krate, source_path)?; db.record_result(ex, tc, krate, || { info!( diff --git a/src/lib.rs b/src/lib.rs index 8e1581419..f1e6a9e8a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,7 @@ extern crate tokio_core; extern crate tokio_io; extern crate tokio_process; extern crate tokio_timer; +#[cfg_attr(test, macro_use)] extern crate toml; #[macro_use] extern crate url; diff --git a/src/report/mod.rs b/src/report/mod.rs index 3dd03edd1..e2abeab74 100644 --- a/src/report/mod.rs +++ b/src/report/mod.rs @@ -51,6 +51,7 @@ enum Comparison { Fixed, Skipped, Unknown, + Error, SameBuildFail, SameTestFail, SameTestSkipped, @@ -209,11 +210,11 @@ fn crate_to_name(c: &Crate, shas: &HashMap) -> Result format!("{}-{}", details.name, details.version), Crate::GitHub(ref repo) => { - let sha = shas - .get(repo) - .ok_or_else(|| format!("missing sha for GitHub repo {}", repo.slug()))? - .as_str(); - format!("{}.{}.{}", repo.org, repo.name, sha) + if let Some(sha) = shas.get(repo) { + format!("{}.{}.{}", repo.org, repo.name, sha) + } else { + format!("{}.{}", repo.org, repo.name) + } } }) } @@ -225,11 +226,11 @@ fn crate_to_url(c: &Crate, shas: &HashMap) -> Result details.name, details.version ), Crate::GitHub(ref repo) => { - let sha = shas - .get(repo) - .ok_or_else(|| format!("missing sha for GitHub repo {}", repo.slug()))? - .as_str(); - format!("https://github.com/{}/{}/tree/{}", repo.org, repo.name, sha) + if let Some(sha) = shas.get(repo) { + format!("https://github.com/{}/{}/tree/{}", repo.org, repo.name, sha) + } else { + format!("https://github.com/{}/{}", repo.org, repo.name) + } } }) } @@ -258,6 +259,7 @@ fn compare( | (&TestPass, &BuildFail) | (&TestSkipped, &BuildFail) | (&TestFail, &BuildFail) => Comparison::Regressed, + (&Error, _) | (_, &Error) => Comparison::Error, (&TestFail, &TestSkipped) | (&TestPass, &TestSkipped) | (&TestSkipped, &TestFail) @@ -536,6 +538,14 @@ mod tests { TestPass + BuildFail = Regressed, TestSkipped + BuildFail = Regressed, TestFail + BuildFail = Regressed, + Error + TestPass = Error, + Error + TestSkipped = Error, + Error + TestFail = Error, + Error + BuildFail = Error, + TestPass + Error = Error, + TestSkipped + Error = Error, + TestFail + Error = Error, + BuildFail + Error = Error, ] ); @@ -547,6 +557,8 @@ mod tests { skip: true, skip_tests: false, quiet: false, + update_lockfile: false, + broken: false, }, ); assert_eq!(compare(&config, ®, &None, &None), Comparison::Skipped); diff --git a/src/results/file.rs b/src/results/file.rs index 539d84036..a1192cc7d 100644 --- a/src/results/file.rs +++ b/src/results/file.rs @@ -90,7 +90,7 @@ impl ReadResults for FileDB { } impl WriteResults for FileDB { - fn already_executed( + fn get_result( &self, ex: &Experiment, toolchain: &Toolchain, diff --git a/src/results/mod.rs b/src/results/mod.rs index d2d68525a..fbbb083db 100644 --- a/src/results/mod.rs +++ b/src/results/mod.rs @@ -28,7 +28,7 @@ pub trait ReadResults { } pub trait WriteResults { - fn already_executed( + fn get_result( &self, ex: &Experiment, toolchain: &Toolchain, @@ -56,4 +56,5 @@ string_enum!(pub enum TestResult { TestFail => "test-fail", TestSkipped => "test-skipped", TestPass => "test-pass", + Error => "error", }); diff --git a/src/run_graph.rs b/src/run_graph.rs index 3acd5fd4f..5d020a0cc 100644 --- a/src/run_graph.rs +++ b/src/run_graph.rs @@ -3,20 +3,16 @@ use crossbeam; use errors::*; use ex::{self, ExMode, Experiment}; use file; -use petgraph::dot::Dot; -use petgraph::graph::{Graph, NodeIndex}; -use petgraph::visit::EdgeRef; -use petgraph::Direction; -use results::WriteResults; +use petgraph::{dot::Dot, graph::NodeIndex, stable_graph::StableDiGraph, Direction}; +use results::{TestResult, WriteResults}; use std::fmt; -use std::mem; use std::path::Path; -use std::sync::Mutex; +use std::sync::{Arc, Mutex}; use tasks::{Task, TaskStep}; +use util; pub enum Node { - Task(Task), - RunningTask, + Task { task: Arc, running: bool }, CrateCompleted, Root, } @@ -24,8 +20,11 @@ pub enum Node { impl fmt::Debug for Node { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Node::Task(ref task) => write!(f, "{:?}", task)?, - Node::RunningTask => write!(f, "running task")?, + Node::Task { ref task, running } => if running { + write!(f, "running: {:?}", task)?; + } else { + write!(f, "{:?}", task)?; + }, Node::CrateCompleted => write!(f, "crate completed")?, Node::Root => write!(f, "root")?, } @@ -34,33 +33,33 @@ impl fmt::Debug for Node { } enum WalkResult { - Task(NodeIndex, Task), + Task(NodeIndex, Arc), Blocked, NotBlocked, } #[derive(Default)] pub struct TasksGraph { - graph: Graph, + graph: StableDiGraph, root: NodeIndex, - completed_root: NodeIndex, } impl TasksGraph { pub fn new() -> Self { - let mut graph = Graph::new(); + let mut graph = StableDiGraph::new(); let root = graph.add_node(Node::Root); - let completed_root = graph.add_node(Node::Root); - TasksGraph { - graph, - root, - completed_root, - } + TasksGraph { graph, root } } pub fn add_task(&mut self, task: Task, deps: &[NodeIndex]) -> NodeIndex { - self.add_node(Node::Task(task), deps) + self.add_node( + Node::Task { + task: Arc::new(task), + running: false, + }, + deps, + ) } pub fn add_crate(&mut self, deps: &[NodeIndex]) -> NodeIndex { @@ -79,66 +78,107 @@ impl TasksGraph { id } - pub fn next_task(&mut self) -> Option<(NodeIndex, Task)> { + pub fn next_task( + &mut self, + ex: &Experiment, + db: &DB, + ) -> Option<(NodeIndex, Arc)> { let root = self.root; - if let WalkResult::Task(id, task) = self.walk_graph(root) { + // Should recurse a maximum of one time, since completed nodes should have been removed + // from the graph + if let WalkResult::Task(id, task) = self.walk_graph(root, ex, db) { Some((id, task)) } else { None } } - fn walk_graph(&mut self, node: NodeIndex) -> WalkResult { - let mut dependencies = 0; + fn walk_graph( + &mut self, + node: NodeIndex, + ex: &Experiment, + db: &DB, + ) -> WalkResult { + // Ensure tasks are only executed if needed + let mut already_executed = false; + if let Node::Task { + ref task, + running: false, + } = self.graph[node] + { + if !task.needs_exec(ex, db) { + already_executed = true; + } + } + if already_executed { + self.mark_as_completed(node); + return WalkResult::NotBlocked; + } // Try to check for the dependencies of this node // The list is collected to make the borrowchecker happy let mut neighbors = self.graph.neighbors(node).collect::>(); for neighbor in neighbors.drain(..) { - match self.walk_graph(neighbor) { + match self.walk_graph(neighbor, ex, db) { WalkResult::Task(id, task) => return WalkResult::Task(id, task), - WalkResult::Blocked => dependencies += 1, + WalkResult::Blocked => return WalkResult::Blocked, WalkResult::NotBlocked => {} } } - if dependencies == 0 { - match self.graph[node] { - Node::Task(_) => { - let content = mem::replace(&mut self.graph[node], Node::RunningTask); - if let Node::Task(task) = content { - WalkResult::Task(node, task) - } else { - unreachable!(); - } - } - Node::RunningTask => WalkResult::Blocked, - Node::CrateCompleted => { - // All the steps for this crate were completed - self.mark_as_completed(node); - WalkResult::NotBlocked - } - Node::Root => WalkResult::NotBlocked, + let mut delete = false; + let result = match self.graph[node] { + Node::Task { running: true, .. } => WalkResult::Blocked, + Node::Task { + ref task, + ref mut running, + } => { + *running = true; + WalkResult::Task(node, task.clone()) } - } else { - WalkResult::Blocked + Node::CrateCompleted => { + // All the steps for this crate were completed + delete = true; + WalkResult::NotBlocked + } + Node::Root => WalkResult::NotBlocked, + }; + + // This is done after the match to avoid borrowck issues + if delete { + self.mark_as_completed(node); } + + result } pub fn mark_as_completed(&mut self, node: NodeIndex) { - // Remove all the edges from this node, and move the node to the completed root. - // The node is not removed because node IDs are not stable, so removing one node changes - // the ID of the other ones. - let mut edges = self + self.graph.remove_node(node); + } + + pub fn mark_as_failed( + &mut self, + node: NodeIndex, + ex: &Experiment, + db: &DB, + error: &Error, + result: TestResult, + ) -> Result<()> { + let mut children = self .graph - .edges_directed(node, Direction::Incoming) - .map(|e| e.id()) + .neighbors_directed(node, Direction::Incoming) .collect::>(); - for edge in edges.drain(..) { - self.graph.remove_edge(edge); + for child in children.drain(..) { + self.mark_as_failed(child, ex, db, error, result)?; + } + + match self.graph[node] { + Node::Task { ref task, .. } => task.mark_as_failed(ex, db, error, result)?, + Node::CrateCompleted | Node::Root => return Ok(()), } - self.graph.add_edge(self.completed_root, node, ()); + self.mark_as_completed(node); + Ok(()) } } @@ -218,11 +258,25 @@ pub fn run_ex( let join = scope.builder().name(name).spawn(|| -> Result<()> { // This uses a `loop` instead of a `while let` to avoid locking the graph too much loop { - let option_task = graph.lock().unwrap().next_task(); + let option_task = graph.lock().unwrap().next_task(ex, db); if let Some((id, task)) = option_task { info!("running task: {:?}", task); - task.run(ex, db)?; - graph.lock().unwrap().mark_as_completed(id); + if let Err(e) = task.run(config, ex, db) { + error!("task failed, marking childs as failed too: {:?}", task); + util::report_error(&e); + + let result = if config.is_broken(&task.krate) { + TestResult::BuildFail + } else { + TestResult::Error + }; + graph + .lock() + .unwrap() + .mark_as_failed(id, ex, db, &e, result)?; + } else { + graph.lock().unwrap().mark_as_completed(id); + } } else { break; } @@ -242,7 +296,7 @@ pub fn run_ex( // Only the root node must be present let mut g = graph.lock().unwrap(); - assert!(g.next_task().is_none()); + assert!(g.next_task(ex, db).is_none()); assert_eq!(g.graph.neighbors(g.root).count(), 0); Ok(()) diff --git a/src/tasks.rs b/src/tasks.rs index fcca9f5d6..0d4c91257 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -1,9 +1,10 @@ +use config::Config; use crates::{self, Crate}; use errors::*; use ex::{self, Experiment}; use ex_run; use git; -use results::WriteResults; +use results::{TestResult, WriteResults}; use std::fmt; use toolchain::Toolchain; use util; @@ -58,18 +59,66 @@ impl fmt::Debug for Task { } impl Task { - pub fn run(&self, ex: &Experiment, db: &DB) -> Result<()> { + pub fn needs_exec(&self, ex: &Experiment, db: &DB) -> bool { + // If an error happens while checking if the task should be executed, the error is ignored + // and the function returns true. match self.step { - TaskStep::Prepare => self.run_prepare(ex, db), - TaskStep::BuildAndTest { ref tc, quiet } => self.run_build_and_test(ex, tc, db, quiet), - TaskStep::BuildOnly { ref tc, quiet } => self.run_build_only(ex, tc, db, quiet), - TaskStep::CheckOnly { ref tc, quiet } => self.run_check_only(ex, tc, db, quiet), - TaskStep::UnstableFeatures { ref tc } => self.run_unstable_features(ex, db, tc), + // The prepare step should always be executed. + // It will not be executed if all the dependent tasks are already executed, since the + // runner will not reach the prepare task in that case. + TaskStep::Prepare => true, + // Build tasks should only be executed if there are no results for them + TaskStep::BuildAndTest { ref tc, .. } + | TaskStep::BuildOnly { ref tc, .. } + | TaskStep::CheckOnly { ref tc, .. } + | TaskStep::UnstableFeatures { ref tc } => { + db.get_result(ex, tc, &self.krate).unwrap_or(None).is_none() + } + } + } + + pub fn mark_as_failed( + &self, + ex: &Experiment, + db: &DB, + err: &Error, + result: TestResult, + ) -> Result<()> { + match self.step { + TaskStep::Prepare => {} + TaskStep::BuildAndTest { ref tc, .. } + | TaskStep::BuildOnly { ref tc, .. } + | TaskStep::CheckOnly { ref tc, .. } + | TaskStep::UnstableFeatures { ref tc } => { + db.record_result(ex, tc, &self.krate, || { + error!("this task or one of its parent failed!"); + util::report_error(err); + Ok(result) + })?; + } + } + + Ok(()) + } + + pub fn run(&self, config: &Config, ex: &Experiment, db: &DB) -> Result<()> { + match self.step { + TaskStep::Prepare => self.run_prepare(config, ex, db), + TaskStep::BuildAndTest { ref tc, quiet } => { + self.run_build_and_test(config, ex, tc, db, quiet) + } + TaskStep::BuildOnly { ref tc, quiet } => self.run_build_only(config, ex, tc, db, quiet), + TaskStep::CheckOnly { ref tc, quiet } => self.run_check_only(config, ex, tc, db, quiet), + TaskStep::UnstableFeatures { ref tc } => self.run_unstable_features(config, ex, db, tc), } } - fn run_prepare(&self, ex: &Experiment, db: &DB) -> Result<()> { - let krate = [self.krate.clone()]; + fn run_prepare( + &self, + config: &Config, + ex: &Experiment, + db: &DB, + ) -> Result<()> { let stable = Toolchain::Dist("stable".into()); // Fetch repository data if it's a git repo @@ -78,25 +127,27 @@ impl Task { util::report_error(&e); } - ex::capture_shas(ex, &krate, db)?; + ex::capture_shas(ex, &[self.krate.clone()], db)?; } - crates::prepare(&krate)?; - ex::frob_tomls(ex, &krate)?; - ex::capture_lockfiles(ex, &krate, &stable, false)?; - ex::fetch_deps(ex, &krate, &stable)?; + crates::prepare_crate(&self.krate)?; + ex::frob_toml(ex, &self.krate)?; + ex::capture_lockfile(config, ex, &self.krate, &stable)?; + ex::fetch_crate_deps(config, ex, &self.krate, &stable)?; Ok(()) } fn run_build_and_test( &self, + config: &Config, ex: &Experiment, tc: &Toolchain, db: &DB, quiet: bool, ) -> Result<()> { ex_run::run_test( + config, "testing", ex, tc, @@ -109,12 +160,14 @@ impl Task { fn run_build_only( &self, + config: &Config, ex: &Experiment, tc: &Toolchain, db: &DB, quiet: bool, ) -> Result<()> { ex_run::run_test( + config, "testing", ex, tc, @@ -127,12 +180,14 @@ impl Task { fn run_check_only( &self, + config: &Config, ex: &Experiment, tc: &Toolchain, db: &DB, quiet: bool, ) -> Result<()> { ex_run::run_test( + config, "checking", ex, tc, @@ -145,11 +200,13 @@ impl Task { fn run_unstable_features( &self, + config: &Config, ex: &Experiment, db: &DB, tc: &Toolchain, ) -> Result<()> { ex_run::run_test( + config, "checking", ex, tc, diff --git a/src/toml_frobber.rs b/src/toml_frobber.rs index 63b5e3357..625c8b796 100644 --- a/src/toml_frobber.rs +++ b/src/toml_frobber.rs @@ -10,20 +10,65 @@ pub fn frob_toml(dir: &Path, name: &str, vers: &str, out: &Path) -> Result<()> { let mut toml: Table = toml::from_str(&toml_str) .chain_err(|| Error::from(format!("unable to parse Cargo.toml at {}", dir.display())))?; + if frob_table(&mut toml, name, vers) { + let toml = Value::Table(toml); + file::write_string(out, &format!("{}", toml))?; + + info!("frobbed toml written to {}", out.display()); + } + + Ok(()) +} + +#[cfg_attr(feature = "cargo-clippy", allow(useless_let_if_seq))] +pub fn frob_table(table: &mut Table, name: &str, vers: &str) -> bool { + let mut changed = false; + + // Frob top-level dependencies + if frob_dependencies(table, name, vers) { + changed = true; + } + + // Frob target-specific dependencies + if let Some(&mut Value::Table(ref mut targets)) = table.get_mut("target") { + for (_, target) in targets.iter_mut() { + if let Value::Table(ref mut target_table) = *target { + if frob_dependencies(target_table, name, vers) { + changed = true; + } + } + } + } + + // Eliminate workspaces + if table.remove("workspace").is_some() { + info!("removing workspace from {}-{}", name, vers); + changed = true; + } + + // Eliminate parent workspaces + if let Some(&mut Value::Table(ref mut package)) = table.get_mut("package") { + if package.remove("workspace").is_some() { + info!("removing parent workspace from {}-{}", name, vers); + changed = true; + } + } + + changed +} + +fn frob_dependencies(table: &mut Table, name: &str, vers: &str) -> bool { let mut changed = false; // Convert path dependencies to registry dependencies for section in &["dependencies", "dev-dependencies", "build-dependencies"] { - let maybe_deps = toml.get_mut(*section); - if let Some(&mut Value::Table(ref mut deps)) = maybe_deps { + if let Some(&mut Value::Table(ref mut deps)) = table.get_mut(*section) { // Iterate through the "name = { ... }", removing any "path" // keys in the dependency definition for (dep_name, v) in deps.iter_mut() { if let Value::Table(ref mut dep_props) = *v { - if dep_props.contains_key("path") { - info!("removing path from {} in {}-{}", dep_name, name, vers); - } if dep_props.remove("path").is_some() { + info!("removing path from {} in {}-{}", dep_name, name, vers); changed = true; } } @@ -31,18 +76,73 @@ pub fn frob_toml(dir: &Path, name: &str, vers: &str, out: &Path) -> Result<()> { } } - // Eliminate workspaces - if toml.remove("workspace").is_some() { - info!("removing workspace from {}-{}", name, vers); - changed = true; - } + changed +} - if changed { - let toml = Value::Table(toml); - file::write_string(out, &format!("{}", toml))?; +#[cfg(test)] +mod tests { + use super::frob_table; - info!("frobbed toml written to {}", out.display()); + #[test] + fn test_frob_table_noop() { + let mut toml = toml! { + [package] + name = "foo" + version = "1.0" + + [dependencies] + bar = "1.0" + + [dev-dependencies] + baz = "1.0" + + [target."cfg(unix)".dependencies] + quux = "1.0" + }; + + let result = toml.clone(); + + assert!(!frob_table(toml.as_table_mut().unwrap(), "foo", "1.0")); + assert_eq!(toml, result); } - Ok(()) + #[test] + fn test_frob_table_changes() { + let mut toml = toml! { + [package] + name = "foo" + version = "1.0" + workspace = ".." + + [dependencies] + bar = { version = "1.0", path = "../bar" } + + [dev-dependencies] + baz = { version = "1.0", path = "../baz" } + + [target."cfg(unix)".dependencies] + quux = { version = "1.0", path = "../quux" } + + [workspace] + members = [] + }; + + let result = toml! { + [package] + name = "foo" + version = "1.0" + + [dependencies] + bar = { version = "1.0" } + + [dev-dependencies] + baz = { version = "1.0" } + + [target."cfg(unix)".dependencies] + quux = { version = "1.0" } + }; + + assert!(frob_table(toml.as_table_mut().unwrap(), "foo", "1.0")); + assert_eq!(toml, result); + } } diff --git a/src/toolchain.rs b/src/toolchain.rs index 06d7945e7..b8db4c667 100644 --- a/src/toolchain.rs +++ b/src/toolchain.rs @@ -57,7 +57,15 @@ impl Toolchain { } pub fn target_dir(&self, ex_name: &str) -> PathBuf { - ex_target_dir(ex_name).join(self.to_string()) + let mut dir = ex_target_dir(ex_name); + + if let Some(thread) = ::std::thread::current().name() { + dir = dir.join(thread); + } else { + dir = dir.join("shared"); + } + + dir.join(self.to_string()) } pub fn run_cargo( diff --git a/static/report.css b/static/report.css index 7bca4faad..58807c1cc 100644 --- a/static/report.css +++ b/static/report.css @@ -57,6 +57,10 @@ th { background: repeating-linear-gradient(-45deg, #494b4a, #494b4a 15px, #555 15px, #555 30px); } +.errors { + background: #d77026; +} + #controls { line-height: 3.5em; margin-bottom: 2rem; diff --git a/static/report.js b/static/report.js index e87859d11..e7fda2e4c 100644 --- a/static/report.js +++ b/static/report.js @@ -58,6 +58,7 @@ function begin(config, results) { let sameTestSkippedEl = document.querySelector("#c-same-test-skipped .count"); let sameTestPassEl = document.querySelector("#c-same-test-pass .count"); let skippedEl = document.querySelector("#c-skipped .count"); + let errorsEl = document.querySelector("#c-errors .count"); regressedEl.innerHTML = summary.regressed; fixedEl.innerHTML = summary.fixed; @@ -67,6 +68,7 @@ function begin(config, results) { sameTestSkippedEl.innerHTML = summary.sameTestSkipped; sameTestPassEl.innerHTML = summary.sameTestPass; skippedEl.innerHTML = summary.skipped; + errorsEl.innerHTML = summary.errors; // Creating the document will take a second. Lay out the summary first. let results_ = results; @@ -101,38 +103,42 @@ function calcSummary(results) { let sameTestSkipped = 0; let sameTestPass = 0; let skipped = 0; + let errors = 0; for (crate of results.crates) { - if (crate.res == "Regressed") { - regressed += 1; - } else if (crate.res == "Fixed") { - fixed += 1; - } else if (crate.res == "Unknown") { - unknown += 1; - } else if (crate.res == "SameBuildFail") { - sameBuildFail += 1; - } else if (crate.res == "SameTestFail") { - sameTestFail += 1; - } else if (crate.res == "SameTestSkipped") { - sameTestSkipped += 1; - } else if (crate.res == "SameTestPass") { - sameTestPass += 1; - } else if (crate.res == "Skipped") { - skipped += 1; - } else { - throw "unknown test status"; - } + if (crate.res == "Regressed") { + regressed += 1; + } else if (crate.res == "Fixed") { + fixed += 1; + } else if (crate.res == "Unknown") { + unknown += 1; + } else if (crate.res == "SameBuildFail") { + sameBuildFail += 1; + } else if (crate.res == "SameTestFail") { + sameTestFail += 1; + } else if (crate.res == "SameTestSkipped") { + sameTestSkipped += 1; + } else if (crate.res == "SameTestPass") { + sameTestPass += 1; + } else if (crate.res == "Skipped") { + skipped += 1; + } else if (crate.res == "Error") { + errors += 1; + } else { + throw "unknown test status"; + } } return { - regressed: regressed, - fixed: fixed, - unknown: unknown, - sameBuildFail: sameBuildFail, - sameTestFail: sameTestFail, - sameTestSkipped: sameTestSkipped, - sameTestPass: sameTestPass, - skipped: skipped, + regressed: regressed, + fixed: fixed, + unknown: unknown, + sameBuildFail: sameBuildFail, + sameTestFail: sameTestFail, + sameTestSkipped: sameTestSkipped, + sameTestPass: sameTestPass, + skipped: skipped, + errors: errors, }; } @@ -190,6 +196,8 @@ function jsonCrateResToCss(res) { return "same-test-pass"; } else if (res == "Skipped") { return "skipped"; + } else if (res == "Error") { + return "errors"; } else { throw "unknown test status"; } @@ -214,6 +222,8 @@ function parseRunResult(crate_res, res) { result = "test-skipped"; } else if (res.res == "TestPass") { result = "test-pass"; + } else if (res.res == "Error") { + result = "error"; } else { throw "unknown test status"; } diff --git a/template/report.html b/template/report.html index d9dc0362c..f07db6ffe 100644 --- a/template/report.html +++ b/template/report.html @@ -44,6 +44,10 @@ unknown + + errors + +
build-fail