diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 5d479429e25fe..266800b083f32 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -66,6 +66,11 @@ on: required: false type: string default: 'ignore-artifacts' + save-recordings: + description: Save desktop recordings + required: false + type: boolean + default: false jobs: bazel: @@ -140,7 +145,7 @@ jobs: with: bazelrc: common --color=yes - name: Setup Fluxbox and Xvfb - if: inputs.os == 'ubuntu' && inputs.browser != '' + if: inputs.os == 'ubuntu' && (inputs.browser != '' || inputs.save-recordings) run: | sudo apt-get -y install fluxbox Xvfb :99 & @@ -182,3 +187,17 @@ jobs: name: ${{ inputs.artifact-name }} path: changes.patch retention-days: 6 + - name: Save recordings (Windows) + if: inputs.save-recordings && inputs.os == 'windows' + uses: actions/upload-artifact@v4 + with: + name: recordings-win + path: C:\Users\runneradmin\.cache\selenium\recordings\*.* + retention-days: 6 + - name: Save recordings (Linux) + if: inputs.save-recordings && inputs.os == 'ubuntu' + uses: actions/upload-artifact@v4 + with: + name: recordings-linux + path: /home/runner/.cache/selenium/recordings/*.* + retention-days: 6 diff --git a/.github/workflows/ci-rust.yml b/.github/workflows/ci-rust.yml index 6b165b69cc05f..97701e3c4ccfc 100644 --- a/.github/workflows/ci-rust.yml +++ b/.github/workflows/ci-rust.yml @@ -41,6 +41,7 @@ jobs: cache-key: rust-test os: ${{ matrix.os }} run: bazel test --test_env=RUST_BACKTRACE=full --test_env=RUST_TEST_NOCAPTURE=1 --flaky_test_attempts=3 //rust/... + save-recordings: true windows-stable: name: "Windows Stable" diff --git a/rust/Cargo.Bazel.lock b/rust/Cargo.Bazel.lock index b7a16a58cce67..c67fb8b514e96 100644 --- a/rust/Cargo.Bazel.lock +++ b/rust/Cargo.Bazel.lock @@ -1,5 +1,5 @@ { - "checksum": "9c5df13665bbb4442be9c8674c176e8324d597425d8da1f20e952cea268d6168", + "checksum": "7d75ecfab3b52d1d58721f87d2f3c5447aa0c2894f43756bb2671a0e7005a3cf", "crates": { "addr2line 0.21.0": { "name": "addr2line", @@ -773,7 +773,7 @@ "target": "bzip2" }, { - "id": "chrono 0.4.38", + "id": "chrono 0.4.39", "target": "chrono" }, { @@ -1373,6 +1373,156 @@ ], "license_file": "LICENSE" }, + "bindgen 0.69.5": { + "name": "bindgen", + "version": "0.69.5", + "package_url": "https://github.com/rust-lang/rust-bindgen", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/bindgen/0.69.5/download", + "sha256": "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" + } + }, + "targets": [ + { + "Library": { + "crate_name": "bindgen", + "crate_root": "lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "bindgen", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "logging", + "prettyplease", + "runtime", + "which-rustfmt" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "bindgen 0.69.5", + "target": "build_script_build" + }, + { + "id": "bitflags 2.5.0", + "target": "bitflags" + }, + { + "id": "cexpr 0.6.0", + "target": "cexpr" + }, + { + "id": "clang-sys 1.8.1", + "target": "clang_sys" + }, + { + "id": "itertools 0.12.1", + "target": "itertools" + }, + { + "id": "lazy_static 1.5.0", + "target": "lazy_static" + }, + { + "id": "lazycell 1.3.0", + "target": "lazycell" + }, + { + "id": "log 0.4.22", + "target": "log" + }, + { + "id": "prettyplease 0.2.25", + "target": "prettyplease" + }, + { + "id": "proc-macro2 1.0.92", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.37", + "target": "quote" + }, + { + "id": "regex 1.11.1", + "target": "regex" + }, + { + "id": "rustc-hash 1.1.0", + "target": "rustc_hash" + }, + { + "id": "shlex 1.3.0", + "target": "shlex" + }, + { + "id": "syn 2.0.90", + "target": "syn" + }, + { + "id": "which 4.4.2", + "target": "which" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.69.5" + }, + "build_script_attrs": { + "compile_data_glob": [ + "**" + ], + "data_glob": [ + "**" + ], + "link_deps": { + "common": [ + { + "id": "clang-sys 1.8.1", + "target": "clang_sys" + }, + { + "id": "prettyplease 0.2.25", + "target": "prettyplease" + } + ], + "selects": {} + } + }, + "license": "BSD-3-Clause", + "license_ids": [ + "BSD-3-Clause" + ], + "license_file": "LICENSE" + }, "bit-set 0.6.0": { "name": "bit-set", "version": "0.6.0", @@ -2039,79 +2189,16 @@ "id": "jobserver 0.1.31", "target": "jobserver" }, + { + "id": "libc 0.2.168", + "target": "libc" + }, { "id": "shlex 1.3.0", "target": "shlex" } ], - "selects": { - "aarch64-apple-darwin": [ - { - "id": "libc 0.2.168", - "target": "libc" - } - ], - "aarch64-unknown-linux-gnu": [ - { - "id": "libc 0.2.168", - "target": "libc" - } - ], - "aarch64-unknown-nixos-gnu": [ - { - "id": "libc 0.2.168", - "target": "libc" - } - ], - "arm-unknown-linux-gnueabi": [ - { - "id": "libc 0.2.168", - "target": "libc" - } - ], - "i686-unknown-linux-gnu": [ - { - "id": "libc 0.2.168", - "target": "libc" - } - ], - "powerpc-unknown-linux-gnu": [ - { - "id": "libc 0.2.168", - "target": "libc" - } - ], - "s390x-unknown-linux-gnu": [ - { - "id": "libc 0.2.168", - "target": "libc" - } - ], - "x86_64-apple-darwin": [ - { - "id": "libc 0.2.168", - "target": "libc" - } - ], - "x86_64-unknown-freebsd": [ - { - "id": "libc 0.2.168", - "target": "libc" - } - ], - "x86_64-unknown-linux-gnu": [ - { - "id": "libc 0.2.168", - "target": "libc" - } - ], - "x86_64-unknown-nixos-gnu": [ - { - "id": "libc 0.2.168", - "target": "libc" - } - ] - } + "selects": {} }, "edition": "2018", "version": "1.1.30" @@ -2123,6 +2210,54 @@ ], "license_file": "LICENSE-APACHE" }, + "cexpr 0.6.0": { + "name": "cexpr", + "version": "0.6.0", + "package_url": "https://github.com/jethrogb/rust-cexpr", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/cexpr/0.6.0/download", + "sha256": "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" + } + }, + "targets": [ + { + "Library": { + "crate_name": "cexpr", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "cexpr", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "nom 7.1.3", + "target": "nom" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.6.0" + }, + "license": "Apache-2.0/MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, "cfb 0.7.3": { "name": "cfb", "version": "0.7.3", @@ -2217,14 +2352,14 @@ ], "license_file": "LICENSE-APACHE" }, - "chrono 0.4.38": { + "chrono 0.4.39": { "name": "chrono", - "version": "0.4.38", + "version": "0.4.39", "package_url": "https://github.com/chronotope/chrono", "repository": { "Http": { - "url": "https://static.crates.io/crates/chrono/0.4.38/download", - "sha256": "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" + "url": "https://static.crates.io/crates/chrono/0.4.39/download", + "sha256": "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" } }, "targets": [ @@ -2468,7 +2603,7 @@ } }, "edition": "2021", - "version": "0.4.38" + "version": "0.4.39" }, "license": "MIT OR Apache-2.0", "license_ids": [ @@ -2477,20 +2612,20 @@ ], "license_file": "LICENSE.txt" }, - "clap 4.5.23": { - "name": "clap", - "version": "4.5.23", - "package_url": "https://github.com/clap-rs/clap", + "clang-sys 1.8.1": { + "name": "clang-sys", + "version": "1.8.1", + "package_url": "https://github.com/KyleMayes/clang-sys", "repository": { "Http": { - "url": "https://static.crates.io/crates/clap/4.5.23/download", - "sha256": "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" + "url": "https://static.crates.io/crates/clang-sys/1.8.1/download", + "sha256": "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" } }, "targets": [ { "Library": { - "crate_name": "clap", + "crate_name": "clang_sys", "crate_root": "src/lib.rs", "srcs": { "allow_empty": true, @@ -2499,20 +2634,124 @@ ] } } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } } ], - "library_target_name": "clap", + "library_target_name": "clang_sys", "common_attrs": { "compile_data_glob": [ "**" ], "crate_features": { "common": [ - "cargo", - "color", - "default", - "derive", - "error-context", + "clang_3_5", + "clang_3_6", + "clang_3_7", + "clang_3_8", + "clang_3_9", + "clang_4_0", + "clang_5_0", + "clang_6_0", + "libloading", + "runtime" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "clang-sys 1.8.1", + "target": "build_script_build" + }, + { + "id": "glob 0.3.1", + "target": "glob" + }, + { + "id": "libc 0.2.168", + "target": "libc" + }, + { + "id": "libloading 0.8.6", + "target": "libloading" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "1.8.1" + }, + "build_script_attrs": { + "compile_data_glob": [ + "**" + ], + "data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "glob 0.3.1", + "target": "glob" + } + ], + "selects": {} + }, + "links": "clang" + }, + "license": "Apache-2.0", + "license_ids": [ + "Apache-2.0" + ], + "license_file": "LICENSE.txt" + }, + "clap 4.5.23": { + "name": "clap", + "version": "4.5.23", + "package_url": "https://github.com/clap-rs/clap", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/clap/4.5.23/download", + "sha256": "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" + } + }, + "targets": [ + { + "Library": { + "crate_name": "clap", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "clap", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "cargo", + "color", + "default", + "derive", + "error-context", "help", "std", "suggestions", @@ -2881,7 +3120,7 @@ "deps": { "common": [ { - "id": "chrono 0.4.38", + "id": "chrono 0.4.39", "target": "chrono" }, { @@ -3298,7 +3537,7 @@ "target": "bytes" }, { - "id": "chrono 0.4.38", + "id": "chrono 0.4.39", "target": "chrono" }, { @@ -5877,6 +6116,56 @@ ], "license_file": "LICENSE-APACHE" }, + "home 0.5.11": { + "name": "home", + "version": "0.5.11", + "package_url": "https://github.com/rust-lang/cargo", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/home/0.5.11/download", + "sha256": "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" + } + }, + "targets": [ + { + "Library": { + "crate_name": "home", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "home", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [], + "selects": { + "cfg(windows)": [ + { + "id": "windows-sys 0.59.0", + "target": "windows_sys" + } + ] + } + }, + "edition": "2021", + "version": "0.5.11" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, "http 1.1.0": { "name": "http", "version": "1.1.0", @@ -7785,6 +8074,54 @@ ], "license_file": "LICENSE-APACHE" }, + "itertools 0.12.1": { + "name": "itertools", + "version": "0.12.1", + "package_url": "https://github.com/rust-itertools/itertools", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/itertools/0.12.1/download", + "sha256": "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" + } + }, + "targets": [ + { + "Library": { + "crate_name": "itertools", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "itertools", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "either 1.12.0", + "target": "either" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.12.1" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, "itoa 1.0.11": { "name": "itoa", "version": "1.0.11", @@ -7922,20 +8259,20 @@ ], "license_file": "LICENSE-APACHE" }, - "libc 0.2.168": { - "name": "libc", - "version": "0.2.168", - "package_url": "https://github.com/rust-lang/libc", + "kill_tree 0.2.4": { + "name": "kill_tree", + "version": "0.2.4", + "package_url": "https://github.com/oneofthezombies/kill-tree", "repository": { "Http": { - "url": "https://static.crates.io/crates/libc/0.2.168/download", - "sha256": "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" + "url": "https://static.crates.io/crates/kill_tree/0.2.4/download", + "sha256": "f3879339076ac4da142cc852d91693462927cbc99773b5ea422e4834e68c4ff2" } }, "targets": [ { "Library": { - "crate_name": "libc", + "crate_name": "kill_tree", "crate_root": "src/lib.rs", "srcs": { "allow_empty": true, @@ -7958,84 +8295,46 @@ } } ], - "library_target_name": "libc", + "library_target_name": "kill_tree", "common_attrs": { "compile_data_glob": [ "**" ], "crate_features": { "common": [ - "default", - "std" + "blocking", + "default" ], - "selects": { - "aarch64-apple-darwin": [ - "extra_traits" - ], - "aarch64-apple-ios": [ - "extra_traits" - ], - "aarch64-apple-ios-sim": [ - "extra_traits" - ], - "aarch64-linux-android": [ - "extra_traits" - ], - "aarch64-unknown-fuchsia": [ - "extra_traits" - ], - "aarch64-unknown-nto-qnx710": [ - "extra_traits" - ], - "armv7-linux-androideabi": [ - "extra_traits" - ], - "i686-apple-darwin": [ - "extra_traits" - ], - "i686-linux-android": [ - "extra_traits" - ], - "i686-unknown-freebsd": [ - "extra_traits" - ], - "powerpc-unknown-linux-gnu": [ - "extra_traits" - ], - "s390x-unknown-linux-gnu": [ - "extra_traits" - ], - "wasm32-wasip1": [ - "extra_traits" - ], - "x86_64-apple-darwin": [ - "extra_traits" - ], - "x86_64-apple-ios": [ - "extra_traits" - ], - "x86_64-linux-android": [ - "extra_traits" - ], - "x86_64-unknown-freebsd": [ - "extra_traits" - ], - "x86_64-unknown-fuchsia": [ - "extra_traits" - ] - } + "selects": {} }, "deps": { "common": [ { - "id": "libc 0.2.168", + "id": "kill_tree 0.2.4", "target": "build_script_build" + }, + { + "id": "tracing 0.1.40", + "target": "tracing" } ], - "selects": {} + "selects": { + "cfg(unix)": [ + { + "id": "nix 0.27.1", + "target": "nix" + } + ], + "cfg(windows)": [ + { + "id": "windows 0.52.0", + "target": "windows" + } + ] + } }, "edition": "2021", - "version": "0.2.168" + "version": "0.2.4" }, "build_script_attrs": { "compile_data_glob": [ @@ -8043,15 +8342,318 @@ ], "data_glob": [ "**" - ] - }, - "license": "MIT OR Apache-2.0", - "license_ids": [ - "Apache-2.0", + ], + "deps": { + "common": [], + "selects": { + "cfg(target_os = \"macos\")": [ + { + "id": "bindgen 0.69.5", + "target": "bindgen" + } + ] + } + } + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": null + }, + "lazy_static 1.5.0": { + "name": "lazy_static", + "version": "1.5.0", + "package_url": "https://github.com/rust-lang-nursery/lazy-static.rs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/lazy_static/1.5.0/download", + "sha256": "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + } + }, + "targets": [ + { + "Library": { + "crate_name": "lazy_static", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "lazy_static", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2015", + "version": "1.5.0" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "lazycell 1.3.0": { + "name": "lazycell", + "version": "1.3.0", + "package_url": "https://github.com/indiv0/lazycell", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/lazycell/1.3.0/download", + "sha256": "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + } + }, + "targets": [ + { + "Library": { + "crate_name": "lazycell", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "lazycell", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2015", + "version": "1.3.0" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "libc 0.2.168": { + "name": "libc", + "version": "0.2.168", + "package_url": "https://github.com/rust-lang/libc", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/libc/0.2.168/download", + "sha256": "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" + } + }, + "targets": [ + { + "Library": { + "crate_name": "libc", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "libc", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": { + "aarch64-apple-darwin": [ + "extra_traits" + ], + "aarch64-apple-ios": [ + "extra_traits" + ], + "aarch64-apple-ios-sim": [ + "extra_traits" + ], + "aarch64-linux-android": [ + "extra_traits" + ], + "aarch64-pc-windows-msvc": [ + "extra_traits" + ], + "aarch64-unknown-fuchsia": [ + "extra_traits" + ], + "aarch64-unknown-linux-gnu": [ + "extra_traits" + ], + "aarch64-unknown-nixos-gnu": [ + "extra_traits" + ], + "aarch64-unknown-nto-qnx710": [ + "extra_traits" + ], + "arm-unknown-linux-gnueabi": [ + "extra_traits" + ], + "armv7-linux-androideabi": [ + "extra_traits" + ], + "armv7-unknown-linux-gnueabi": [ + "extra_traits" + ], + "i686-apple-darwin": [ + "extra_traits" + ], + "i686-linux-android": [ + "extra_traits" + ], + "i686-pc-windows-msvc": [ + "extra_traits" + ], + "i686-unknown-freebsd": [ + "extra_traits" + ], + "i686-unknown-linux-gnu": [ + "extra_traits" + ], + "powerpc-unknown-linux-gnu": [ + "extra_traits" + ], + "s390x-unknown-linux-gnu": [ + "extra_traits" + ], + "wasm32-wasip1": [ + "extra_traits" + ], + "x86_64-apple-darwin": [ + "extra_traits" + ], + "x86_64-apple-ios": [ + "extra_traits" + ], + "x86_64-linux-android": [ + "extra_traits" + ], + "x86_64-pc-windows-msvc": [ + "extra_traits" + ], + "x86_64-unknown-freebsd": [ + "extra_traits" + ], + "x86_64-unknown-fuchsia": [ + "extra_traits" + ], + "x86_64-unknown-linux-gnu": [ + "extra_traits" + ], + "x86_64-unknown-nixos-gnu": [ + "extra_traits" + ] + } + }, + "deps": { + "common": [ + { + "id": "libc 0.2.168", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.2.168" + }, + "build_script_attrs": { + "compile_data_glob": [ + "**" + ], + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", "MIT" ], "license_file": "LICENSE-APACHE" }, + "libloading 0.8.6": { + "name": "libloading", + "version": "0.8.6", + "package_url": "https://github.com/nagisa/rust_libloading/", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/libloading/0.8.6/download", + "sha256": "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" + } + }, + "targets": [ + { + "Library": { + "crate_name": "libloading", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "libloading", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [], + "selects": { + "cfg(unix)": [ + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + } + ], + "cfg(windows)": [ + { + "id": "windows-targets 0.52.6", + "target": "windows_targets" + } + ] + } + }, + "edition": "2015", + "version": "0.8.6" + }, + "license": "ISC", + "license_ids": [ + "ISC" + ], + "license_file": "LICENSE" + }, "libredox 0.1.3": { "name": "libredox", "version": "0.1.3", @@ -8631,7 +9233,46 @@ "targets": [ { "Library": { - "crate_name": "mime", + "crate_name": "mime", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "mime", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2015", + "version": "0.3.17" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "minimal-lexical 0.2.1": { + "name": "minimal-lexical", + "version": "0.2.1", + "package_url": "https://github.com/Alexhuszagh/minimal-lexical", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/minimal-lexical/0.2.1/download", + "sha256": "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + } + }, + "targets": [ + { + "Library": { + "crate_name": "minimal_lexical", "crate_root": "src/lib.rs", "srcs": { "allow_empty": true, @@ -8642,15 +9283,21 @@ } } ], - "library_target_name": "mime", + "library_target_name": "minimal_lexical", "common_attrs": { "compile_data_glob": [ "**" ], - "edition": "2015", - "version": "0.3.17" + "crate_features": { + "common": [ + "std" + ], + "selects": {} + }, + "edition": "2018", + "version": "0.2.1" }, - "license": "MIT OR Apache-2.0", + "license": "MIT/Apache-2.0", "license_ids": [ "Apache-2.0", "MIT" @@ -8841,6 +9488,127 @@ ], "license_file": "LICENSE" }, + "nix 0.27.1": { + "name": "nix", + "version": "0.27.1", + "package_url": "https://github.com/nix-rust/nix", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/nix/0.27.1/download", + "sha256": "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" + } + }, + "targets": [ + { + "Library": { + "crate_name": "nix", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "nix", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "process", + "signal" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "bitflags 2.5.0", + "target": "bitflags" + }, + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + }, + { + "id": "libc 0.2.168", + "target": "libc" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.27.1" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, + "nom 7.1.3": { + "name": "nom", + "version": "7.1.3", + "package_url": "https://github.com/Geal/nom", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/nom/7.1.3/download", + "sha256": "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" + } + }, + "targets": [ + { + "Library": { + "crate_name": "nom", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "nom", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "alloc", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "memchr 2.7.4", + "target": "memchr" + }, + { + "id": "minimal-lexical 0.2.1", + "target": "minimal_lexical" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "7.1.3" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, "nt-time 0.8.1": { "name": "nt-time", "version": "0.8.1", @@ -9062,150 +9830,54 @@ } ], "selects": {} - }, - "edition": "2018", - "version": "0.32.2" - }, - "license": "Apache-2.0 OR MIT", - "license_ids": [ - "Apache-2.0", - "MIT" - ], - "license_file": "LICENSE-APACHE" - }, - "once_cell 1.19.0": { - "name": "once_cell", - "version": "1.19.0", - "package_url": "https://github.com/matklad/once_cell", - "repository": { - "Http": { - "url": "https://static.crates.io/crates/once_cell/1.19.0/download", - "sha256": "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - } - }, - "targets": [ - { - "Library": { - "crate_name": "once_cell", - "crate_root": "src/lib.rs", - "srcs": { - "allow_empty": true, - "include": [ - "**/*.rs" - ] - } - } - } - ], - "library_target_name": "once_cell", - "common_attrs": { - "compile_data_glob": [ - "**" - ], - "crate_features": { - "common": [ - "alloc", - "race", - "std" - ], - "selects": { - "aarch64-apple-darwin": [ - "default" - ], - "aarch64-apple-ios": [ - "default" - ], - "aarch64-apple-ios-sim": [ - "default" - ], - "aarch64-linux-android": [ - "default" - ], - "aarch64-pc-windows-msvc": [ - "default" - ], - "aarch64-unknown-fuchsia": [ - "default" - ], - "aarch64-unknown-linux-gnu": [ - "default" - ], - "aarch64-unknown-nixos-gnu": [ - "default" - ], - "aarch64-unknown-nto-qnx710": [ - "default" - ], - "arm-unknown-linux-gnueabi": [ - "default" - ], - "armv7-linux-androideabi": [ - "default" - ], - "armv7-unknown-linux-gnueabi": [ - "default" - ], - "i686-apple-darwin": [ - "default" - ], - "i686-linux-android": [ - "default" - ], - "i686-pc-windows-msvc": [ - "default" - ], - "i686-unknown-freebsd": [ - "default" - ], - "i686-unknown-linux-gnu": [ - "default" - ], - "powerpc-unknown-linux-gnu": [ - "default" - ], - "riscv32imc-unknown-none-elf": [ - "default" - ], - "riscv64gc-unknown-none-elf": [ - "default" - ], - "s390x-unknown-linux-gnu": [ - "default" - ], - "thumbv7em-none-eabi": [ - "default" - ], - "thumbv8m.main-none-eabi": [ - "default" - ], - "x86_64-apple-darwin": [ - "default" - ], - "x86_64-apple-ios": [ - "default" - ], - "x86_64-linux-android": [ - "default" - ], - "x86_64-pc-windows-msvc": [ - "default" - ], - "x86_64-unknown-freebsd": [ - "default" - ], - "x86_64-unknown-fuchsia": [ - "default" - ], - "x86_64-unknown-linux-gnu": [ - "default" - ], - "x86_64-unknown-nixos-gnu": [ - "default" - ], - "x86_64-unknown-none": [ - "default" - ] + }, + "edition": "2018", + "version": "0.32.2" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "once_cell 1.19.0": { + "name": "once_cell", + "version": "1.19.0", + "package_url": "https://github.com/matklad/once_cell", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/once_cell/1.19.0/download", + "sha256": "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + } + }, + "targets": [ + { + "Library": { + "crate_name": "once_cell", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } } + } + ], + "library_target_name": "once_cell", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "alloc", + "default", + "race", + "std" + ], + "selects": {} }, "edition": "2021", "version": "1.19.0" @@ -9807,6 +10479,89 @@ ], "license_file": "LICENSE-APACHE" }, + "prettyplease 0.2.25": { + "name": "prettyplease", + "version": "0.2.25", + "package_url": "https://github.com/dtolnay/prettyplease", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/prettyplease/0.2.25/download", + "sha256": "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" + } + }, + "targets": [ + { + "Library": { + "crate_name": "prettyplease", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "prettyplease", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "verbatim" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "prettyplease 0.2.25", + "target": "build_script_build" + }, + { + "id": "proc-macro2 1.0.92", + "target": "proc_macro2" + }, + { + "id": "syn 2.0.90", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.2.25" + }, + "build_script_attrs": { + "compile_data_glob": [ + "**" + ], + "data_glob": [ + "**" + ], + "links": "prettyplease02" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, "proc-macro2 1.0.92": { "name": "proc-macro2", "version": "1.0.92", @@ -12319,6 +13074,52 @@ ], "license_file": "LICENSE-APACHE" }, + "rustc-hash 1.1.0": { + "name": "rustc-hash", + "version": "1.1.0", + "package_url": "https://github.com/rust-lang-nursery/rustc-hash", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/rustc-hash/1.1.0/download", + "sha256": "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + } + }, + "targets": [ + { + "Library": { + "crate_name": "rustc_hash", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "rustc_hash", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, + "edition": "2015", + "version": "1.1.0" + }, + "license": "Apache-2.0/MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, "rustc-hash 2.0.0": { "name": "rustc-hash", "version": "2.0.0", @@ -12450,13 +13251,112 @@ "crate_features": { "common": [ "alloc", - "default", "fs", "libc-extra-traits", - "std", - "use-libc-auxv" + "std" ], - "selects": {} + "selects": { + "aarch64-apple-darwin": [ + "default", + "use-libc-auxv" + ], + "aarch64-apple-ios": [ + "default", + "use-libc-auxv" + ], + "aarch64-apple-ios-sim": [ + "default", + "use-libc-auxv" + ], + "aarch64-linux-android": [ + "default", + "use-libc-auxv" + ], + "aarch64-unknown-fuchsia": [ + "default", + "use-libc-auxv" + ], + "aarch64-unknown-linux-gnu": [ + "default", + "use-libc-auxv" + ], + "aarch64-unknown-nixos-gnu": [ + "default", + "use-libc-auxv" + ], + "aarch64-unknown-nto-qnx710": [ + "default", + "use-libc-auxv" + ], + "arm-unknown-linux-gnueabi": [ + "default", + "use-libc-auxv" + ], + "armv7-linux-androideabi": [ + "default", + "use-libc-auxv" + ], + "armv7-unknown-linux-gnueabi": [ + "default", + "use-libc-auxv" + ], + "i686-apple-darwin": [ + "default", + "use-libc-auxv" + ], + "i686-linux-android": [ + "default", + "use-libc-auxv" + ], + "i686-unknown-freebsd": [ + "default", + "use-libc-auxv" + ], + "i686-unknown-linux-gnu": [ + "default", + "use-libc-auxv" + ], + "powerpc-unknown-linux-gnu": [ + "default", + "use-libc-auxv" + ], + "s390x-unknown-linux-gnu": [ + "default", + "use-libc-auxv" + ], + "wasm32-wasip1": [ + "default", + "use-libc-auxv" + ], + "x86_64-apple-darwin": [ + "default", + "use-libc-auxv" + ], + "x86_64-apple-ios": [ + "default", + "use-libc-auxv" + ], + "x86_64-linux-android": [ + "default", + "use-libc-auxv" + ], + "x86_64-unknown-freebsd": [ + "default", + "use-libc-auxv" + ], + "x86_64-unknown-fuchsia": [ + "default", + "use-libc-auxv" + ], + "x86_64-unknown-linux-gnu": [ + "default", + "use-libc-auxv" + ], + "x86_64-unknown-nixos-gnu": [ + "default", + "use-libc-auxv" + ] + } }, "deps": { "common": [ @@ -12481,7 +13381,51 @@ "target": "libc" } ], - "aarch64-apple-ios": [ + "aarch64-apple-ios": [ + { + "id": "errno 0.3.10", + "target": "errno", + "alias": "libc_errno" + }, + { + "id": "libc 0.2.168", + "target": "libc" + } + ], + "aarch64-apple-ios-sim": [ + { + "id": "errno 0.3.10", + "target": "errno", + "alias": "libc_errno" + }, + { + "id": "libc 0.2.168", + "target": "libc" + } + ], + "aarch64-linux-android": [ + { + "id": "errno 0.3.10", + "target": "errno", + "alias": "libc_errno" + }, + { + "id": "libc 0.2.168", + "target": "libc" + } + ], + "aarch64-pc-windows-msvc": [ + { + "id": "errno 0.3.10", + "target": "errno", + "alias": "libc_errno" + }, + { + "id": "libc 0.2.168", + "target": "libc" + } + ], + "aarch64-unknown-fuchsia": [ { "id": "errno 0.3.10", "target": "errno", @@ -12492,7 +13436,7 @@ "target": "libc" } ], - "aarch64-apple-ios-sim": [ + "aarch64-unknown-linux-gnu": [ { "id": "errno 0.3.10", "target": "errno", @@ -12503,7 +13447,7 @@ "target": "libc" } ], - "aarch64-linux-android": [ + "aarch64-unknown-nixos-gnu": [ { "id": "errno 0.3.10", "target": "errno", @@ -12514,7 +13458,7 @@ "target": "libc" } ], - "aarch64-unknown-fuchsia": [ + "aarch64-unknown-nto-qnx710": [ { "id": "errno 0.3.10", "target": "errno", @@ -12525,7 +13469,7 @@ "target": "libc" } ], - "aarch64-unknown-nto-qnx710": [ + "arm-unknown-linux-gnueabi": [ { "id": "errno 0.3.10", "target": "errno", @@ -12603,6 +13547,17 @@ "target": "libc" } ], + "i686-pc-windows-msvc": [ + { + "id": "errno 0.3.10", + "target": "errno", + "alias": "libc_errno" + }, + { + "id": "libc 0.2.168", + "target": "libc" + } + ], "i686-unknown-freebsd": [ { "id": "errno 0.3.10", @@ -12614,6 +13569,17 @@ "target": "libc" } ], + "i686-unknown-linux-gnu": [ + { + "id": "errno 0.3.10", + "target": "errno", + "alias": "libc_errno" + }, + { + "id": "libc 0.2.168", + "target": "libc" + } + ], "powerpc-unknown-linux-gnu": [ { "id": "errno 0.3.10", @@ -12680,6 +13646,17 @@ "target": "libc" } ], + "x86_64-pc-windows-msvc": [ + { + "id": "errno 0.3.10", + "target": "errno", + "alias": "libc_errno" + }, + { + "id": "libc 0.2.168", + "target": "libc" + } + ], "x86_64-unknown-freebsd": [ { "id": "errno 0.3.10", @@ -12701,6 +13678,28 @@ "id": "libc 0.2.168", "target": "libc" } + ], + "x86_64-unknown-linux-gnu": [ + { + "id": "errno 0.3.10", + "target": "errno", + "alias": "libc_errno" + }, + { + "id": "libc 0.2.168", + "target": "libc" + } + ], + "x86_64-unknown-nixos-gnu": [ + { + "id": "errno 0.3.10", + "target": "errno", + "alias": "libc_errno" + }, + { + "id": "libc 0.2.168", + "target": "libc" + } ] } }, @@ -13242,6 +14241,10 @@ "id": "bzip2 0.5.0", "target": "bzip2" }, + { + "id": "chrono 0.4.39", + "target": "chrono" + }, { "id": "clap 4.5.23", "target": "clap" @@ -13347,9 +14350,17 @@ "id": "is_executable 1.0.4", "target": "is_executable" }, + { + "id": "kill_tree 0.2.4", + "target": "kill_tree" + }, { "id": "rstest 0.19.0", "target": "rstest" + }, + { + "id": "wait-timeout 0.2.0", + "target": "wait_timeout" } ], "selects": {} @@ -16940,7 +17951,10 @@ ], "crate_features": { "common": [ - "std" + "attributes", + "default", + "std", + "tracing-attributes" ], "selects": {} }, @@ -16958,6 +17972,15 @@ "selects": {} }, "edition": "2018", + "proc_macro_deps": { + "common": [ + { + "id": "tracing-attributes 0.1.28", + "target": "tracing_attributes" + } + ], + "selects": {} + }, "version": "0.1.40" }, "license": "MIT", @@ -16966,6 +17989,61 @@ ], "license_file": "LICENSE" }, + "tracing-attributes 0.1.28": { + "name": "tracing-attributes", + "version": "0.1.28", + "package_url": "https://github.com/tokio-rs/tracing", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/tracing-attributes/0.1.28/download", + "sha256": "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "tracing_attributes", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "tracing_attributes", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.92", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.37", + "target": "quote" + }, + { + "id": "syn 2.0.90", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.1.28" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, "tracing-core 0.1.32": { "name": "tracing-core", "version": "0.1.32", @@ -18261,6 +19339,70 @@ ], "license_file": "LICENSE" }, + "which 4.4.2": { + "name": "which", + "version": "4.4.2", + "package_url": "https://github.com/harryfei/which-rs.git", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/which/4.4.2/download", + "sha256": "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" + } + }, + "targets": [ + { + "Library": { + "crate_name": "which", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "which", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "either 1.12.0", + "target": "either" + }, + { + "id": "rustix 0.38.42", + "target": "rustix" + } + ], + "selects": { + "cfg(any(windows, unix, target_os = \"redox\"))": [ + { + "id": "home 0.5.11", + "target": "home" + } + ], + "cfg(windows)": [ + { + "id": "once_cell 1.19.0", + "target": "once_cell" + } + ] + } + }, + "edition": "2021", + "version": "4.4.2" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE.txt" + }, "which 7.0.1": { "name": "which", "version": "7.0.1", @@ -18605,6 +19747,70 @@ ], "license_file": null }, + "windows 0.52.0": { + "name": "windows", + "version": "0.52.0", + "package_url": "https://github.com/microsoft/windows-rs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/windows/0.52.0/download", + "sha256": "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" + } + }, + "targets": [ + { + "Library": { + "crate_name": "windows", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "windows", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "Win32", + "Win32_Foundation", + "Win32_System", + "Win32_System_Diagnostics", + "Win32_System_Diagnostics_ToolHelp", + "Win32_System_Threading", + "default" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "windows-core 0.52.0", + "target": "windows_core" + }, + { + "id": "windows-targets 0.52.6", + "target": "windows_targets" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.52.0" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "license-apache-2.0" + }, "windows-core 0.52.0": { "name": "windows-core", "version": "0.52.0", @@ -18634,6 +19840,12 @@ "compile_data_glob": [ "**" ], + "crate_features": { + "common": [ + "default" + ], + "selects": {} + }, "deps": { "common": [ { @@ -20434,7 +21646,7 @@ "target": "bytes" }, { - "id": "chrono 0.4.38", + "id": "chrono 0.4.39", "target": "chrono" }, { @@ -21881,6 +23093,11 @@ "x86_64-unknown-linux-gnu", "x86_64-unknown-nixos-gnu" ], + "cfg(target_os = \"macos\")": [ + "aarch64-apple-darwin", + "i686-apple-darwin", + "x86_64-apple-darwin" + ], "cfg(target_os = \"redox\")": [], "cfg(target_os = \"wasi\")": [ "wasm32-wasip1" @@ -21998,6 +23215,7 @@ "anyhow 1.0.95", "apple-flat-package 0.20.0", "bzip2 0.5.0", + "chrono 0.4.39", "clap 4.5.23", "debpkg 0.6.0", "directories 5.0.1", @@ -22025,7 +23243,9 @@ "direct_dev_deps": [ "assert_cmd 2.0.16", "is_executable 1.0.4", - "rstest 0.19.0" + "kill_tree 0.2.4", + "rstest 0.19.0", + "wait-timeout 0.2.0" ], "unused_patches": [] } diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 5ab197c2eda4a..f6604864dda42 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -230,6 +230,29 @@ dependencies = [ "smallvec", ] +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags 2.5.0", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn", + "which 4.4.2", +] + [[package]] name = "bit-set" version = "0.6.0" @@ -337,6 +360,15 @@ dependencies = [ "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfb" version = "0.7.3" @@ -356,9 +388,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -369,6 +401,17 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.23" @@ -893,6 +936,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "http" version = "1.1.0" @@ -1216,6 +1268,15 @@ version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -1240,12 +1301,46 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kill_tree" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3879339076ac4da142cc852d91693462927cbc99773b5ea422e4834e68c4ff2" +dependencies = [ + "bindgen", + "nix", + "tracing", + "windows", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + [[package]] name = "libredox" version = "0.1.3" @@ -1327,6 +1422,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -1357,6 +1458,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nt-time" version = "0.8.1" @@ -1476,6 +1598,16 @@ dependencies = [ "termtree", ] +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.92" @@ -1495,7 +1627,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.0.0", "rustls", "socket2", "thiserror 1.0.69", @@ -1512,7 +1644,7 @@ dependencies = [ "bytes", "rand", "ring", - "rustc-hash", + "rustc-hash 2.0.0", "rustls", "slab", "thiserror 1.0.69", @@ -1721,6 +1853,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hash" version = "2.0.0" @@ -1833,6 +1971,7 @@ dependencies = [ "apple-flat-package", "assert_cmd", "bzip2 0.5.0", + "chrono", "clap", "debpkg", "directories", @@ -1843,6 +1982,7 @@ dependencies = [ "fs_extra", "infer 0.16.0", "is_executable", + "kill_tree", "log", "regex", "reqwest", @@ -1854,8 +1994,9 @@ dependencies = [ "tempfile", "tokio", "toml", + "wait-timeout", "walkdir", - "which", + "which 7.0.1", "xz2", "zip", ] @@ -2312,9 +2453,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -2514,6 +2667,18 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "which" version = "7.0.1" @@ -2557,6 +2722,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.52.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 139f929c94126..d18678401c3fb 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -38,11 +38,14 @@ apple-flat-package = "0.20.0" which = "7.0.1" fs2 = "0.4.3" fs_extra = "1.3.0" +chrono = "0.4.39" [dev-dependencies] assert_cmd = "2.0.16" rstest = "0.19.0" is_executable = "1.0.4" +wait-timeout = "0.2.0" +kill_tree = "0.2.4" [profile.release] opt-level = 'z' # Optimize for size diff --git a/rust/src/ffmpeg.rs b/rust/src/ffmpeg.rs new file mode 100644 index 0000000000000..8eb01958c4957 --- /dev/null +++ b/rust/src/ffmpeg.rs @@ -0,0 +1,235 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use crate::config::OS::{LINUX, MACOS, WINDOWS}; +use crate::downloads::download_to_tmp_folder; +use crate::files::{ + compose_driver_path_in_cache, create_parent_path_if_not_exists, get_filename_with_extension, + path_to_string, uncompress_tar, unzip, +}; +use crate::lock::Lock; +use crate::logger::Logger; +use crate::shell::{run_shell_command_with_stderr, Command}; +use crate::{format_five_args, format_four_args, format_one_arg, format_two_args, ENV_DISPLAY}; +use anyhow::{anyhow, Error}; +use reqwest::Client; +use std::fs::File; +use std::path::{Path, PathBuf}; +use std::{env, fs}; +use xz2::read::XzDecoder; + +pub const FFMPEG_NAME: &str = "ffmpeg"; +const FFMPEG_DEFAULT_VERSION: &str = "7.1"; +const FFMPEG_WINDOWS_RELEASE_URL: &str = + "https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-{}-essentials_build.7z"; +const FFMPEG_LINUX_RELEASE_URL: &str = "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-n{}-latest-linux64-gpl-{}.tar.xz"; +const FFMPEG_MACOS_RELEASE_URL: &str = "https://evermeet.cx/ffmpeg/ffmpeg-{}.zip"; +const FFMPEG_RECORD_DESKTOP_WINDOWS_COMMAND: &str = "{} -f gdigrab -i desktop -r {} -c:v {} -y {}"; +const FFMPEG_RECORD_DESKTOP_LINUX_COMMAND: &str = "{} -f x11grab -i {} -r {} -c:v {} -y {}"; +const FFMPEG_RECORD_DESKTOP_MACOS_COMMAND: &str = "{} -f avfoundation -i 0 -r {} -c:v {} -y {}"; +const FFMPEG_RECORD_FRAME_RATE: &str = "30"; +const FFMPEG_RECORD_VIDEO_CODEC: &str = "mpeg4"; +const FFMPEG_RECORDING_EXTENSION: &str = "avi"; +const FFMPEG_RECORDING_FOLDER: &str = "recordings"; +const FFMPEG_DEFAULT_DISPLAY: &str = ":0"; + +pub fn download_ffmpeg( + ffmpeg_version: String, + http_client: &Client, + os: &str, + log: &Logger, + cache_path: PathBuf, +) -> Result<(), Error> { + let ffmpeg_url = get_ffmpeg_url(os, &ffmpeg_version)?; + let ffmpeg_path_in_cache = get_ffmpeg_path_in_cache(&ffmpeg_version, os, cache_path)?; + let ffmpeg_name_with_extension = get_filename_with_extension(FFMPEG_NAME, os); + + let mut lock = Lock::acquire( + log, + &ffmpeg_path_in_cache, + Some(ffmpeg_name_with_extension.clone()), + )?; + if !lock.exists() && ffmpeg_path_in_cache.exists() { + log.debug(format!( + "{} is already in cache: {}", + FFMPEG_NAME, + ffmpeg_path_in_cache.display() + )); + return Ok(()); + } + + log.debug(format!( + "Downloading {} {} from {}", + FFMPEG_NAME, ffmpeg_version, &ffmpeg_url + )); + let (_tmp_folder, driver_zip_file) = download_to_tmp_folder(http_client, ffmpeg_url, log)?; + uncompress_ffmpeg( + &driver_zip_file, + &ffmpeg_path_in_cache, + log, + os, + ffmpeg_name_with_extension, + &ffmpeg_version, + )?; + + lock.release(); + Ok(()) +} + +pub fn get_ffmpeg_version() -> String { + FFMPEG_DEFAULT_VERSION.to_string() +} + +pub fn get_ffmpeg_path_in_cache( + ffmpeg_version: &str, + os: &str, + cache_path: PathBuf, +) -> Result { + Ok(compose_driver_path_in_cache( + cache_path, + FFMPEG_NAME, + os, + get_platform_label(os), + ffmpeg_version, + )) +} + +fn get_platform_label(os: &str) -> &str { + if WINDOWS.is(os) { + "win64" + } else if MACOS.is(os) { + "mac-x64" + } else { + "linux64" + } +} + +fn get_recording_command(os: &str) -> &str { + if WINDOWS.is(os) { + FFMPEG_RECORD_DESKTOP_WINDOWS_COMMAND + } else if MACOS.is(os) { + FFMPEG_RECORD_DESKTOP_MACOS_COMMAND + } else { + FFMPEG_RECORD_DESKTOP_LINUX_COMMAND + } +} + +fn get_ffmpeg_url(os: &str, ffmpeg_version: &str) -> Result { + let driver_url = if WINDOWS.is(os) { + format_one_arg(FFMPEG_WINDOWS_RELEASE_URL, ffmpeg_version) + } else if MACOS.is(os) { + format_one_arg(FFMPEG_MACOS_RELEASE_URL, ffmpeg_version) + } else { + format_two_args(FFMPEG_LINUX_RELEASE_URL, ffmpeg_version, ffmpeg_version) + }; + Ok(driver_url) +} + +pub fn uncompress_ffmpeg( + compressed_file: &str, + target: &Path, + log: &Logger, + os: &str, + ffmpeg_name_with_extension: String, + ffmpeg_version: &str, +) -> Result<(), Error> { + if WINDOWS.is(os) { + // 7z + let src_path = Path::new(compressed_file); + let zip_parent = src_path.parent().unwrap(); + sevenz_rust::decompress_file(src_path, zip_parent)?; + let ffmpeg_binary = format!( + r"{}\ffmpeg-{}-essentials_build\bin\{}", + path_to_string(zip_parent), + ffmpeg_version, + ffmpeg_name_with_extension + ); + fs::rename(&ffmpeg_binary, path_to_string(target))?; + } else if MACOS.is(os) { + // zip + unzip( + compressed_file, + target, + log, + Some(ffmpeg_name_with_extension), + )?; + } else { + // tar.xz + let src_file = File::open(compressed_file)?; + let zip_parent = Path::new(compressed_file).parent().unwrap(); + uncompress_tar(&mut XzDecoder::new(src_file), zip_parent, log)?; + let ffmpeg_binary = format!( + r"{}/bin/{}", + path_to_string(zip_parent), + ffmpeg_name_with_extension + ); + fs::rename(&ffmpeg_binary, path_to_string(target))?; + } + Ok(()) +} + +fn get_recording_name() -> String { + let now = chrono::Local::now(); + now.format("%Y-%m-%d_%H-%M-%S").to_string() + "." + FFMPEG_RECORDING_EXTENSION +} + +pub fn record_desktop_with_ffmpeg( + ffmpeg_path: PathBuf, + os: &str, + log: &Logger, + cache_path: PathBuf, +) -> Result<(), Error> { + let recording_target = cache_path + .join(FFMPEG_RECORDING_FOLDER) + .join(get_recording_name()); + let recording_name = path_to_string(&recording_target); + create_parent_path_if_not_exists(&recording_target)?; + + log.debug(format!( + "Recording desktop with {} to {}", + FFMPEG_NAME, &recording_name + )); + let command = if LINUX.is(os) { + let mut env_display = env::var(ENV_DISPLAY).unwrap_or_default(); + if env_display.is_empty() { + log.warn(format!( + "The env {} is empty. Using default value {}", + ENV_DISPLAY, FFMPEG_DEFAULT_DISPLAY + )); + env_display = FFMPEG_DEFAULT_DISPLAY.to_string(); + } + Command::new_single(format_five_args( + get_recording_command(os), + &path_to_string(&ffmpeg_path), + &env_display, + FFMPEG_RECORD_FRAME_RATE, + FFMPEG_RECORD_VIDEO_CODEC, + &recording_name, + )) + } else { + Command::new_single(format_four_args( + get_recording_command(os), + &path_to_string(&ffmpeg_path), + FFMPEG_RECORD_FRAME_RATE, + FFMPEG_RECORD_VIDEO_CODEC, + &recording_name, + )) + }; + run_shell_command_with_stderr(log, os, command, true).unwrap(); + + return Err(anyhow!("Command for recording desktop terminated")); +} diff --git a/rust/src/files.rs b/rust/src/files.rs index 8dc208a3cfb85..d85ad07de2ddd 100644 --- a/rust/src/files.rs +++ b/rust/src/files.rs @@ -176,10 +176,9 @@ pub fn uncompress_sfx(compressed_file: &str, target: &Path, log: &Logger) -> Res let index_7z = header.ok_or(anyhow!("Incorrect SFX (self extracting exe) file"))?; let file_reader = Cursor::new(&file_bytes[index_7z..]); sevenz_rust::decompress(file_reader, zip_parent).unwrap(); - let zip_parent_str = path_to_string(zip_parent); let core_str = format!(r"{}\core", zip_parent_str); - move_folder_content(&core_str, &target, &log)?; + move_folder_content(&core_str, target, log)?; Ok(()) } @@ -294,7 +293,7 @@ pub fn uncompress_deb( fs::remove_file(Path::new(&link)).unwrap_or_default(); } - move_folder_content(&opt_edge_str, &target, &log)?; + move_folder_content(&opt_edge_str, target, log)?; Ok(()) } @@ -506,10 +505,10 @@ pub fn compose_driver_path_in_cache( .join(driver_name) .join(arch_folder) .join(driver_version) - .join(get_driver_filename(driver_name, os)) + .join(get_filename_with_extension(driver_name, os)) } -pub fn get_driver_filename(driver_name: &str, os: &str) -> String { +pub fn get_filename_with_extension(driver_name: &str, os: &str) -> String { format!("{}{}", driver_name, get_binary_extension(os)) } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index a2c2411bcb763..25c4bb356b446 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -20,9 +20,13 @@ use crate::config::OS::{MACOS, WINDOWS}; use crate::config::{str_to_os, ManagerConfig}; use crate::downloads::download_to_tmp_folder; use crate::edge::{EdgeManager, EDGEDRIVER_NAME, EDGE_NAMES, WEBVIEW2_NAME}; +use crate::ffmpeg::{ + download_ffmpeg, get_ffmpeg_path_in_cache, get_ffmpeg_version, record_desktop_with_ffmpeg, + FFMPEG_NAME, +}; use crate::files::{ capitalize, collect_files_from_cache, create_path_if_not_exists, default_cache_folder, - find_latest_from_cache, get_binary_extension, path_to_string, + find_latest_from_cache, get_binary_extension, get_filename_with_extension, path_to_string, }; use crate::files::{parse_version, uncompress, BrowserPath}; use crate::firefox::{FirefoxManager, FIREFOX_NAME, GECKODRIVER_NAME}; @@ -55,6 +59,7 @@ pub mod chrome; pub mod config; pub mod downloads; pub mod edge; +pub mod ffmpeg; pub mod files; pub mod firefox; pub mod grid; @@ -94,6 +99,7 @@ pub const SINGLE_QUOTE: &str = "'"; pub const ENV_PROGRAM_FILES: &str = "PROGRAMFILES"; pub const ENV_PROGRAM_FILES_X86: &str = "PROGRAMFILES(X86)"; pub const ENV_LOCALAPPDATA: &str = "LOCALAPPDATA"; +pub const ENV_DISPLAY: &str = "DISPLAY"; pub const ENV_X86: &str = " (x86)"; pub const ARCH_X86: &str = "x86"; pub const ARCH_AMD64: &str = "amd64"; @@ -189,7 +195,7 @@ pub trait SeleniumManager { let driver_name_with_extension = self.get_driver_name_with_extension(); let mut lock = Lock::acquire( - &self.get_logger(), + self.get_logger(), &driver_path_in_cache, Some(driver_name_with_extension.clone()), )?; @@ -322,7 +328,7 @@ pub trait SeleniumManager { } let browser_path_in_cache = self.get_browser_path_in_cache()?; - let mut lock = Lock::acquire(&self.get_logger(), &browser_path_in_cache, None)?; + let mut lock = Lock::acquire(self.get_logger(), &browser_path_in_cache, None)?; if !lock.exists() && browser_binary_path.exists() { self.get_logger().debug(format!( "Browser already in cache: {}", @@ -347,7 +353,7 @@ pub trait SeleniumManager { uncompress( &driver_zip_file, &browser_path_in_cache, - &self.get_logger(), + self.get_logger(), self.get_os(), None, browser_label_for_download, @@ -896,6 +902,24 @@ pub trait SeleniumManager { Ok(()) } + fn record_desktop(&mut self, ffmpeg: bool, record: bool) -> Result<(), Error> { + let mut ffmpeg_path: Option = None; + if ffmpeg { + ffmpeg_path = Some(self.get_or_download_ffmpeg()?); + } + if record { + let cache_path = self.get_cache_path()?.unwrap_or_default(); + self.set_fallback_driver_from_cache(false); + record_desktop_with_ffmpeg( + ffmpeg_path.unwrap_or(self.get_or_download_ffmpeg()?), + self.get_os(), + self.get_logger(), + cache_path, + )?; + } + Ok(()) + } + fn check_error_with_driver_in_path( &mut self, is_driver_in_path: &bool, @@ -1052,19 +1076,11 @@ pub trait SeleniumManager { } fn get_driver_name_with_extension(&self) -> String { - format!( - "{}{}", - self.get_driver_name(), - get_binary_extension(self.get_os()) - ) + get_filename_with_extension(self.get_driver_name(), self.get_os()) } fn get_browser_name_with_extension(&self) -> String { - format!( - "{}{}", - self.get_browser_name(), - get_binary_extension(self.get_os()) - ) + get_filename_with_extension(self.get_browser_name(), self.get_os()) } fn general_request_browser_version( @@ -1582,6 +1598,29 @@ pub trait SeleniumManager { fn set_fallback_driver_from_cache(&mut self, fallback_driver_from_cache: bool) { self.get_config_mut().fallback_driver_from_cache = fallback_driver_from_cache; } + + fn get_or_download_ffmpeg(&self) -> Result { + let ffmpeg_version = get_ffmpeg_version(); + let cache_path = self.get_cache_path()?.unwrap_or_default(); + let ffmpeg_path_in_cache = + get_ffmpeg_path_in_cache(&ffmpeg_version, self.get_os(), cache_path.clone())?; + + if ffmpeg_path_in_cache.exists() { + self.get_logger().debug(format!( + "{} {} already in the cache", + FFMPEG_NAME, ffmpeg_version + )); + } else { + download_ffmpeg( + ffmpeg_version, + self.get_http_client(), + self.get_os(), + self.get_logger(), + cache_path, + )?; + } + Ok(ffmpeg_path_in_cache) + } } // ---------------------------------------------------------- @@ -1663,6 +1702,30 @@ pub fn format_three_args(string: &str, arg1: &str, arg2: &str, arg3: &str) -> St .replacen("{}", arg3, 1) } +pub fn format_four_args(string: &str, arg1: &str, arg2: &str, arg3: &str, arg4: &str) -> String { + string + .replacen("{}", arg1, 1) + .replacen("{}", arg2, 1) + .replacen("{}", arg3, 1) + .replacen("{}", arg4, 1) +} + +pub fn format_five_args( + string: &str, + arg1: &str, + arg2: &str, + arg3: &str, + arg4: &str, + arg5: &str, +) -> String { + string + .replacen("{}", arg1, 1) + .replacen("{}", arg2, 1) + .replacen("{}", arg3, 1) + .replacen("{}", arg4, 1) + .replacen("{}", arg5, 1) +} + // ---------------------------------------------------------- // Private functions // ---------------------------------------------------------- diff --git a/rust/src/main.rs b/rust/src/main.rs index d9dc868742116..1c3f8d3e10175 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -155,6 +155,14 @@ struct Cli { /// Not using browsers found in the PATH #[clap(long)] skip_browser_in_path: bool, + + /// Manage FFMPEG static build + #[clap(long)] + ffmpeg: bool, + + /// Record desktop (using FFMPEG) + #[clap(long)] + record: bool, } fn main() { @@ -164,6 +172,8 @@ fn main() { let debug = cli.debug || BooleanKey("debug", false).get_value(); let trace = cli.trace || BooleanKey("trace", false).get_value(); + let ffmpeg = cli.ffmpeg || BooleanKey("ffmpeg", false).get_value(); + let record = cli.record || BooleanKey("record", false).get_value(); let log_level = StringKey(vec!["log-level"], &cli.log_level.unwrap_or_default()).get_value(); let log = Logger::create(&cli.output, debug, trace, &log_level); let grid = cli.grid; @@ -175,6 +185,12 @@ fn main() { if driver_name.is_empty() { driver_name = StringKey(vec!["driver"], "").get_value(); } + if record { + // If record is set, we actually don't need a browser or driver, but still we need a manager + // to be coherent with the SM setup. Therefore, we use Chrome Manager by default, although + // the browser or driver will not be resolved + browser_name = "chrome".to_string(); + } let mut selenium_manager: Box = if !browser_name.is_empty() { get_manager_by_browser(browser_name).unwrap_or_else(|err| { @@ -239,6 +255,7 @@ fn main() { selenium_manager .set_timeout(cli.timeout) .and_then(|_| selenium_manager.set_proxy(cli.proxy.unwrap_or_default())) + .and_then(|_| selenium_manager.record_desktop(ffmpeg, record)) .and_then(|_| selenium_manager.stats()) .and_then(|_| selenium_manager.setup()) .map(|driver_path| { diff --git a/rust/src/shell.rs b/rust/src/shell.rs index 203ba693a8924..fcb4ce3f25ecd 100644 --- a/rust/src/shell.rs +++ b/rust/src/shell.rs @@ -68,23 +68,49 @@ pub fn run_shell_command_with_log( log: &Logger, os: &str, command: Command, +) -> Result { + run_shell_command_with_stderr(log, os, command, false) +} + +pub fn run_shell_command_with_stderr( + log: &Logger, + os: &str, + command: Command, + stderr: bool, ) -> Result { log.debug(format!("Running command: {}", command.display())); - let output = run_shell_command_by_os(os, command)?; + let output = run_shell_command_by_os_stderr(os, command, stderr)?; log.debug(format!("Output: {:?}", output)); Ok(output) } pub fn run_shell_command_by_os(os: &str, command: Command) -> Result { + run_shell_command_by_os_stderr(os, command, false) +} + +pub fn run_shell_command_by_os_stderr( + os: &str, + command: Command, + stderr: bool, +) -> Result { let (shell, flag) = if WINDOWS.is(os) { ("cmd", "/c") } else { ("sh", "-c") }; - run_shell_command(shell, flag, command) + run_shell_command_stderr(shell, flag, command, stderr) } pub fn run_shell_command(shell: &str, flag: &str, command: Command) -> Result { + run_shell_command_stderr(shell, flag, command, false) +} + +pub fn run_shell_command_stderr( + shell: &str, + flag: &str, + command: Command, + stderr: bool, +) -> Result { let mut process = std::process::Command::new(shell); process.arg(flag); @@ -96,7 +122,11 @@ pub fn run_shell_command(shell: &str, flag: &str, command: Command) -> Result &str { diff --git a/rust/tests/common.rs b/rust/tests/common.rs index eb65568d0b7b2..4d7b5feb58647 100644 --- a/rust/tests/common.rs +++ b/rust/tests/common.rs @@ -28,7 +28,12 @@ use std::path::Path; #[allow(dead_code)] pub fn get_selenium_manager() -> Command { - Command::new(env!("CARGO_BIN_EXE_selenium-manager")) + Command::new(get_sm_binary()) +} + +#[allow(dead_code)] +pub fn get_sm_binary() -> String { + env!("CARGO_BIN_EXE_selenium-manager").to_string() } #[allow(dead_code)] diff --git a/rust/tests/record_tests.rs b/rust/tests/record_tests.rs new file mode 100644 index 0000000000000..0861b49c98ec0 --- /dev/null +++ b/rust/tests/record_tests.rs @@ -0,0 +1,48 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use crate::common::{get_selenium_manager, get_sm_binary}; + +use kill_tree::blocking::kill_tree; +use std::process::Command; +use std::time::Duration; +use wait_timeout::ChildExt; + +mod common; + +#[test] +fn test_record() { + let mut cmd = get_selenium_manager(); + cmd.args(["--browser", "chrome", "--ffmpeg", "--debug"]) + .assert() + .success() + .code(0); + + let mut child = Command::new(get_sm_binary()) + .args(["--record", "--debug"]) + .spawn() + .unwrap(); + let record_time_sec = Duration::from_secs(10); + let status_code = match child.wait_timeout(record_time_sec).unwrap() { + Some(status) => status.code(), + None => { + kill_tree(child.id()).unwrap(); + child.wait().unwrap().code() + } + }; + println!("Recording test status code: {:?}", status_code); +}