100 Commits

Author SHA1 Message Date
Sylvestre Ledru 9db1eab1d0 Revert "cargo-dist: generate more targets"
This reverts commit 80b993141b.
2024-09-12 10:10:47 +02:00
Sylvestre Ledru 2392acfad1 Merge pull request #84 from cakebaker/fix_clippy_warnings
Fix clippy warnings in tests
2024-09-06 10:05:13 +02:00
Daniel Hofstetter 2a899a9fc7 Fix clippy warnings in tests
from needless_borrows_for_generic_args lint
2024-09-06 09:27:53 +02:00
Sylvestre Ledru 6ec8370b4b Merge pull request #70 from oSoMoN/grcov-instrumentation-based-coverage
Use the instrumentation-based code coverage implementation
2024-09-06 08:54:32 +02:00
Olivier Tilloy dbabf399d5 Use the instrumentation-based code coverage implementation 2024-08-16 00:35:46 +02:00
Daniel Hofstetter b815162b80 Merge pull request #83 from uutils/renovate/assert_cmd-2.x-lockfile
Update Rust crate assert_cmd to v2.0.16
2024-08-09 08:08:54 +02:00
renovate[bot] 12b205e655 Update Rust crate assert_cmd to v2.0.16 2024-08-09 03:18:54 +00:00
Daniel Hofstetter 8a6504dd83 Merge pull request #82 from uutils/renovate/tempfile-3.x-lockfile
Update Rust crate tempfile to v3.12.0
2024-08-07 08:08:29 +02:00
renovate[bot] 67ef43083a Update Rust crate tempfile to v3.12.0 2024-08-06 23:23:06 +00:00
Daniel Hofstetter b1738538a8 Merge pull request #81 from uutils/renovate/tempfile-3.x-lockfile
Update Rust crate tempfile to v3.11.0
2024-08-03 07:01:16 +02:00
renovate[bot] eea6b62b20 Update Rust crate tempfile to v3.11.0 2024-08-02 22:18:35 +00:00
Daniel Hofstetter f08a3bf512 Merge pull request #80 from uutils/renovate/regex-1.x-lockfile
Update Rust crate regex to v1.10.6
2024-08-02 18:41:22 +02:00
renovate[bot] e55ee893dd Update Rust crate regex to v1.10.6 2024-08-02 16:27:14 +00:00
Olivier Tilloy 24245ee098 Merge pull request #78 from uutils/renovate/assert_cmd-2.x-lockfile
Update Rust crate assert_cmd to v2.0.15
2024-07-28 15:12:16 +00:00
Olivier Tilloy 11f815a7c2 Merge pull request #79 from uutils/renovate/predicates-3.x-lockfile
Update Rust crate predicates to v3.1.2
2024-07-28 15:11:13 +00:00
renovate[bot] e9a8141618 Update Rust crate predicates to v3.1.2 2024-07-25 17:59:30 +00:00
renovate[bot] c9a756eb43 Update Rust crate assert_cmd to v2.0.15 2024-07-25 14:28:54 +00:00
Sylvestre Ledru 468c4bf934 Merge pull request #63 from oSoMoN/io-error-msg
Make error message consistent with GNU diff's implementation when failing to read input file(s)
2024-06-27 14:16:10 +02:00
Daniel Hofstetter 1e8fdd58d9 Merge pull request #77 from uutils/renovate/regex-1.x-lockfile
Update Rust crate regex to v1.10.5
2024-06-09 15:59:55 +02:00
renovate[bot] e98b5e179e Update Rust crate regex to v1.10.5 2024-06-09 13:30:51 +00:00
Sylvestre Ledru 1901982375 Merge pull request #76 from uutils/renovate/unicode-width-0.x-lockfile
Update Rust crate unicode-width to v0.1.13
2024-06-04 20:40:56 +02:00
renovate[bot] eee6f49920 Update Rust crate unicode-width to v0.1.13 2024-06-04 17:06:50 +00:00
Olivier Tilloy 8a3a977d2c Update the expected error message for Windows 2024-06-04 14:57:50 +02:00
Olivier Tilloy fa4e0c6097 Make error message consistent with GNU diff's implementation when failing to read input file(s) 2024-06-04 14:57:50 +02:00
Sylvestre Ledru d362046ae5 release v0.4.2 2024-05-19 19:09:05 +02:00
Daniel Hofstetter 7964afa336 Merge pull request #74 from uutils/cargo-dist
cargo-dist: generate more targets
2024-05-19 12:40:07 +02:00
Sylvestre Ledru 80b993141b cargo-dist: generate more targets 2024-05-19 11:59:26 +02:00
Daniel Hofstetter d922313c8c Merge pull request #71 from uutils/renovate/libfuzzer-sys-0.x
Update Rust crate libfuzzer-sys to 0.4.7
2024-05-01 13:37:01 +02:00
Daniel Hofstetter 3e246ab36c Merge pull request #72 from uutils/renovate/pretty_assertions-1.x
Update Rust crate pretty_assertions to 1.4.0
2024-05-01 13:29:09 +02:00
renovate[bot] 4b70969ff1 Update Rust crate pretty_assertions to 1.4.0 2024-05-01 09:56:55 +00:00
renovate[bot] 767c6f6c4a Update Rust crate libfuzzer-sys to 0.4.7 2024-05-01 09:56:50 +00:00
Sylvestre Ledru 1f896ca1ac Merge pull request #69 from oSoMoN/cargo-dist-version-0.13.3
CI: Update 'cargo dist' to version 0.13.3
2024-05-01 08:31:36 +02:00
Olivier Tilloy 713bd210ab CI: Update 'cargo dist' to version 0.13.3 2024-04-30 23:55:49 +02:00
Olivier Tilloy 61314eaf4e Merge pull request #65 from uutils/renovate/unicode-width-0.x
Update Rust crate unicode-width to 0.1.12
2024-04-30 18:47:39 +02:00
renovate[bot] bf9147733d Update Rust crate unicode-width to 0.1.12 2024-04-30 05:30:32 +00:00
Daniel Hofstetter ce8457cbdb Merge pull request #67 from oSoMoN/macos-ci-install-gpatch
CI: install GNU patch on MacOS (fixes #66)
2024-04-30 07:14:02 +02:00
Olivier Tilloy df778c610b CI: install GNU patch on MacOS (fixes #66) 2024-04-29 22:55:08 +02:00
Sylvestre Ledru d92132e721 version 0.4.1 2024-04-27 13:12:58 +02:00
Sylvestre Ledru 99d4d02985 add missing copyright 2024-04-27 13:12:16 +02:00
Olivier Tilloy e7dc6558c6 Merge pull request #56 from TanmayPatil105/handle-directory-input
Handle directory-file and file-directory comparisons in the diff
2024-04-23 22:40:28 +02:00
Tanmay Patil 8c6a648aef Merge branch 'main' into handle-directory-input 2024-04-23 23:11:31 +05:30
Tanmay Patil 0304391bc5 Create test files in temporary directory 2024-04-23 22:44:06 +05:30
Sylvestre Ledru 8de0ca60d1 Merge pull request #52 from oSoMoN/long-options
Handle long option names for the supported output styles…
2024-04-23 18:44:47 +02:00
Sylvestre Ledru 43b9c524d9 Merge pull request #62 from oSoMoN/integration-no-hardcoded-filename
Un-hardcode a test filename in an integration test (fixes #61)
2024-04-23 18:36:33 +02:00
Olivier Tilloy 3dc3fdf5cd Un-hardcode a test filename in an integration test (fixes #61) 2024-04-23 18:00:56 +02:00
Olivier Tilloy b7261a43f4 Break out the logic to match context/unified diff params into separate functions, for improved readability 2024-04-22 18:01:00 +02:00
Olivier Tilloy 37fe1ae808 Handle --normal, -e and --ed options 2024-04-22 18:01:00 +02:00
Olivier Tilloy 22d973fce6 Parse all valid arguments accepted by GNU diff to request a regular context (with an optional number of lines) 2024-04-22 18:01:00 +02:00
Olivier Tilloy fe28610f21 Parse all valid arguments accepted by GNU diff to request a unified context (with an optional number of lines) 2024-04-22 18:01:00 +02:00
Sylvestre Ledru 3a8eddfe2c Fix typos 2024-04-21 16:07:01 +02:00
Tanmay Patil 476e69ee20 Windows: Fix tests 2024-04-21 18:06:15 +05:30
Tanmay Patil 65993d6a13 Add tests for diff FILE DIRECTORY 2024-04-21 16:10:48 +05:30
Tanmay Patil 39d2ece187 Handle directory-file and file-directory comparisons in the diff
GNU diff treats `diff DIRECTORY FILE` as `diff DIRECTORY/FILE FILE`
2024-04-21 16:10:48 +05:30
Sylvestre Ledru 46a26e896b Merge pull request #58 from oSoMoN/ed-diff-tests-fix-path
Move test assertions in the cfg block where they belong (fixes #3)
2024-04-21 09:37:58 +02:00
Olivier Tilloy 14799eea89 Move test assertions in the cfg block where they belong 2024-04-21 00:13:52 +02:00
Olivier Tilloy 831348d1fc Fix file path in ed diff tests 2024-04-21 00:12:43 +02:00
Sylvestre Ledru 00a5c0ba44 Merge pull request #57 from oSoMoN/windows-fix-path-for-ci
CI: On Windows, use GNU's patch.exe instead of Strawberry Perl patch
2024-04-20 19:44:40 +02:00
Olivier Tilloy bf104648c1 CI: On Windows, use GNU's patch.exe instead of Strawberry Perl patch 2024-04-20 19:30:34 +02:00
Olivier Tilloy 5669f164b3 Merge pull request #34 from uutils/renovate/regex-1.x
Update Rust crate regex to 1.10.4
2024-04-17 19:19:00 +02:00
Sylvestre Ledru 11bf271666 Merge pull request #9 from uutils/renovate/codecov-codecov-action-4.x
Update codecov/codecov-action action to v4
2024-04-16 22:18:53 +02:00
renovate[bot] 674974d5e6 Update Rust crate regex to 1.10.4 2024-04-16 19:54:53 +00:00
Sylvestre Ledru 2ba35db431 Merge pull request #4 from uutils/renovate/diff-0.x
Update Rust crate diff to 0.1.13
2024-04-16 21:53:45 +02:00
renovate[bot] fcec7277c9 Update codecov/codecov-action action to v4 2024-04-16 19:35:04 +00:00
renovate[bot] b8efad6b90 Update Rust crate diff to 0.1.13 2024-04-16 19:35:01 +00:00
Sylvestre Ledru 68e2f51983 Merge pull request #54 from uutils/renovate/chrono-0.x
Update Rust crate chrono to 0.4.38
2024-04-16 21:34:16 +02:00
Sylvestre Ledru 4edaee190f Merge pull request #55 from oSoMoN/use-codecov-token
Use the private Codecov token stored as a secret,
2024-04-16 21:34:01 +02:00
Olivier Tilloy 7f7821f558 Use the private Codecov token stored as a secret,
to work around rate-limiting issues like https://github.com/codecov/codecov-action/issues/557
2024-04-16 18:37:59 +02:00
renovate[bot] 1149a247dd Update Rust crate chrono to 0.4.38 2024-04-16 16:20:52 +00:00
Olivier Tilloy 1b311c6673 Merge pull request #33 from TanmayPatil105/context-diff-modification-time
Display modification times of input files in context and unified diff
2024-04-16 18:20:00 +02:00
Tanmay Patil aedd0684d1 Replace only the first two occurences of timestamp regex 2024-04-16 10:41:38 +05:30
Tanmay Patil 54c02bdf0b Use NamedTempFile instead of manually creating files 2024-04-16 10:17:09 +05:30
Tanmay Patil ba7cb0aef9 Do not create dummy files
Since we now returning SystemTime::now() for invalid file input,
there is no need to crate dummy files
2024-04-14 22:56:37 +05:30
Tanmay Patil 33783d094e Improve tests 2024-04-14 17:16:53 +05:30
Tanmay Patil 900e1c3a68 Tests: Replace modification time in diff with "TIMESTAMP" placeholder 2024-04-14 13:43:30 +05:30
Tanmay Patil 0a77fe12b9 Add tests for get_modification_time function 2024-04-13 21:31:13 +05:30
Tanmay Patil 86bd05c739 Merge branch 'context-diff-modification-time' of github.com:TanmayPatil105/diffutils into context-diff-modification-time 2024-04-10 22:31:09 +05:30
Tanmay Patil 00e18a6b0c Define assert_diff_eq macro for context&unified diff comparison 2024-04-10 22:20:48 +05:30
Tanmay f6eb0835b0 Merge branch 'main' into context-diff-modification-time 2024-04-10 22:13:18 +05:30
Sylvestre Ledru be66ff3299 Merge pull request #47 from oSoMoN/handle-stdin-filename
Handle the rewrite of "-" to "/dev/stdin" in main to leave the filenames unchanged (fixes #46)
2024-04-09 09:53:53 +02:00
Olivier Tilloy e1c319f96b Add an integration test for reading from "/dev/stdin" on unix-like systems 2024-04-08 22:36:14 +02:00
Olivier Tilloy 84ad116845 Use io::stdin() to read from standard input in a portable manner 2024-04-08 20:21:24 +02:00
Olivier Tilloy 6dc34fed44 Handle the rewrite of "-" to "/dev/stdin" in main to leave the filenames unchanged (fixes #46) 2024-04-08 20:21:24 +02:00
Sylvestre Ledru 9507ca28d7 Merge pull request #51 from oSoMoN/unit-tests-for-conflicting-output-style
Unit test to verify that conflicting output styles result in an error
2024-04-06 08:47:53 +02:00
Olivier Tilloy c325291696 Unit test to verify that conflicting output styles result in an error 2024-04-05 23:22:26 +02:00
Olivier Tilloy c08e0b6e1f Merge pull request #25 from uutils/renovate/tempfile-3.x
chore(deps): update rust crate tempfile to 3.10.1
2024-04-04 22:50:50 +02:00
Tanmay Patil 72da7fca40 Show current time if fs::metadata errors 2024-04-04 20:01:11 +05:30
Tanmay 61fb0657c1 Merge branch 'main' into context-diff-modification-time 2024-04-04 19:56:13 +05:30
Sylvestre Ledru 096aa1dad9 Merge pull request #50 from cakebaker/disable_tests_using_ed_on_windows
Disable tests on Windows that use `ed`
2024-04-04 08:48:41 +02:00
Daniel Hofstetter 2d9e625a5b Disable tests on Windows that use ed 2024-04-04 08:30:54 +02:00
Daniel Hofstetter d863fe443a Merge pull request #48 from uutils/clip
Run clippy pedantic fixes
2024-04-04 07:45:18 +02:00
renovate[bot] 6be94d8683 chore(deps): update rust crate tempfile to 3.10.1 2024-04-03 22:31:44 +00:00
Sylvestre Ledru 44ef772e4a release: version 0.4.0 2024-04-04 00:30:46 +02:00
Sylvestre Ledru bbfca84e17 chore: wow shiny new cargo-dist CI 2024-04-04 00:29:50 +02:00
Tanmay Patil a3a372ff36 Display modification times of input files in unified diff 2024-04-04 00:13:41 +05:30
Tanmay Patil 5b814f8530 Fix tests 2024-04-03 10:50:52 +05:30
Tanmay Patil 88a7568b52 Merge branch 'main' into context-diff-modification-time 2024-04-01 13:05:37 +05:30
Tanmay Patil 80c9944bf7 Create foo/bar in target/context-diff 2024-03-31 22:57:51 +05:30
Sylvestre Ledru 043c5f9493 Merge branch 'main' into context-diff-modification-time 2024-03-31 16:17:23 +02:00
Tanmay Patil 9ff8f89626 Fix tests 2024-03-31 16:14:44 +05:30
Tanmay Patil 42eb15b87a Display modification times of input files in context diff
Fixes #31
2024-03-27 22:46:23 +05:30
18 changed files with 1326 additions and 297 deletions
+21 -6
View File
@@ -28,6 +28,13 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
- name: install GNU patch on MacOS
if: runner.os == 'macOS'
run: brew install gpatch
- name: set up PATH on Windows
# Needed to use GNU's patch.exe instead of Strawberry Perl patch
if: runner.os == 'Windows'
run: echo "C:\Program Files\Git\usr\bin" >> $env:GITHUB_PATH
- run: cargo test - run: cargo test
fmt: fmt:
@@ -103,13 +110,22 @@ jobs:
- name: rust toolchain ~ install - name: rust toolchain ~ install
uses: dtolnay/rust-toolchain@nightly uses: dtolnay/rust-toolchain@nightly
- run: rustup component add llvm-tools-preview
- name: install GNU patch on MacOS
if: runner.os == 'macOS'
run: brew install gpatch
- name: set up PATH on Windows
# Needed to use GNU's patch.exe instead of Strawberry Perl patch
if: runner.os == 'Windows'
run: echo "C:\Program Files\Git\usr\bin" >> $env:GITHUB_PATH
- name: Test - name: Test
run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-fail-fast run: cargo test ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-fail-fast
env: env:
CARGO_INCREMENTAL: "0" CARGO_INCREMENTAL: "0"
RUSTC_WRAPPER: "" RUSTC_WRAPPER: ""
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" RUSTFLAGS: "-Cinstrument-coverage -Zcoverage-options=branch -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
RUSTDOCFLAGS: "-Cpanic=abort" RUSTDOCFLAGS: "-Cpanic=abort"
LLVM_PROFILE_FILE: "diffutils-%p-%m.profraw"
- name: "`grcov` ~ install" - name: "`grcov` ~ install"
id: build_grcov id: build_grcov
shell: bash shell: bash
@@ -137,15 +153,14 @@ jobs:
COVERAGE_REPORT_FILE="${COVERAGE_REPORT_DIR}/lcov.info" COVERAGE_REPORT_FILE="${COVERAGE_REPORT_DIR}/lcov.info"
mkdir -p "${COVERAGE_REPORT_DIR}" mkdir -p "${COVERAGE_REPORT_DIR}"
# display coverage files # display coverage files
grcov . --output-type files --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()" | sort --unique grcov . --output-type files --binary-path "${COVERAGE_REPORT_DIR}" | sort --unique
# generate coverage report # generate coverage report
grcov . --output-type lcov --output-path "${COVERAGE_REPORT_FILE}" --branch --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()" grcov . --output-type lcov --output-path "${COVERAGE_REPORT_FILE}" --binary-path "${COVERAGE_REPORT_DIR}" --branch
echo "report=${COVERAGE_REPORT_FILE}" >> $GITHUB_OUTPUT echo "report=${COVERAGE_REPORT_FILE}" >> $GITHUB_OUTPUT
- name: Upload coverage results (to Codecov.io) - name: Upload coverage results (to Codecov.io)
uses: codecov/codecov-action@v3 uses: codecov/codecov-action@v4
# if: steps.vars.outputs.HAS_CODECOV_TOKEN
with: with:
# token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
file: ${{ steps.coverage.outputs.report }} file: ${{ steps.coverage.outputs.report }}
## flags: IntegrationTests, UnitTests, ${{ steps.vars.outputs.CODECOV_FLAGS }} ## flags: IntegrationTests, UnitTests, ${{ steps.vars.outputs.CODECOV_FLAGS }}
flags: ${{ steps.vars.outputs.CODECOV_FLAGS }} flags: ${{ steps.vars.outputs.CODECOV_FLAGS }}
+271
View File
@@ -0,0 +1,271 @@
# Copyright 2022-2024, axodotdev
# SPDX-License-Identifier: MIT or Apache-2.0
#
# CI that:
#
# * checks for a Git Tag that looks like a release
# * builds artifacts with cargo-dist (archives, installers, hashes)
# * uploads those artifacts to temporary workflow zip
# * on success, uploads the artifacts to a GitHub Release
#
# Note that the GitHub Release will be created with a generated
# title/body based on your changelogs.
name: Release
permissions:
contents: write
# This task will run whenever you push a git tag that looks like a version
# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc.
# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where
# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION
# must be a Cargo-style SemVer Version (must have at least major.minor.patch).
#
# If PACKAGE_NAME is specified, then the announcement will be for that
# package (erroring out if it doesn't have the given version or isn't cargo-dist-able).
#
# If PACKAGE_NAME isn't specified, then the announcement will be for all
# (cargo-dist-able) packages in the workspace with that version (this mode is
# intended for workspaces with only one dist-able package, or with all dist-able
# packages versioned/released in lockstep).
#
# If you push multiple tags at once, separate instances of this workflow will
# spin up, creating an independent announcement for each one. However, GitHub
# will hard limit this to 3 tags per commit, as it will assume more tags is a
# mistake.
#
# If there's a prerelease-style suffix to the version, then the release(s)
# will be marked as a prerelease.
on:
push:
tags:
- '**[0-9]+.[0-9]+.[0-9]+*'
pull_request:
jobs:
# Run 'cargo dist plan' (or host) to determine what tasks we need to do
plan:
runs-on: ubuntu-latest
outputs:
val: ${{ steps.plan.outputs.manifest }}
tag: ${{ !github.event.pull_request && github.ref_name || '' }}
tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }}
publishing: ${{ !github.event.pull_request }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install cargo-dist
# we specify bash to get pipefail; it guards against the `curl` command
# failing. otherwise `sh` won't catch that `curl` returned non-0
shell: bash
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.13.3/cargo-dist-installer.sh | sh"
# sure would be cool if github gave us proper conditionals...
# so here's a doubly-nested ternary-via-truthiness to try to provide the best possible
# functionality based on whether this is a pull_request, and whether it's from a fork.
# (PRs run on the *source* but secrets are usually on the *target* -- that's *good*
# but also really annoying to build CI around when it needs secrets to work right.)
- id: plan
run: |
cargo dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json
echo "cargo dist ran successfully"
cat plan-dist-manifest.json
echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT"
- name: "Upload dist-manifest.json"
uses: actions/upload-artifact@v4
with:
name: artifacts-plan-dist-manifest
path: plan-dist-manifest.json
# Build and packages all the platform-specific things
build-local-artifacts:
name: build-local-artifacts (${{ join(matrix.targets, ', ') }})
# Let the initial task tell us to not run (currently very blunt)
needs:
- plan
if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }}
strategy:
fail-fast: false
# Target platforms/runners are computed by cargo-dist in create-release.
# Each member of the matrix has the following arguments:
#
# - runner: the github runner
# - dist-args: cli flags to pass to cargo dist
# - install-dist: expression to run to install cargo-dist on the runner
#
# Typically there will be:
# - 1 "global" task that builds universal installers
# - N "local" tasks that build each platform's binaries and platform-specific installers
matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }}
runs-on: ${{ matrix.runner }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json
steps:
- name: enable windows longpaths
run: |
git config --global core.longpaths true
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: swatinem/rust-cache@v2
with:
key: ${{ join(matrix.targets, '-') }}
- name: Install cargo-dist
run: ${{ matrix.install_dist }}
# Get the dist-manifest
- name: Fetch local artifacts
uses: actions/download-artifact@v4
with:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
- name: Install dependencies
run: |
${{ matrix.packages_install }}
- name: Build artifacts
run: |
# Actually do builds and make zips and whatnot
cargo dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json
echo "cargo dist ran successfully"
- id: cargo-dist
name: Post-build
# We force bash here just because github makes it really hard to get values up
# to "real" actions without writing to env-vars, and writing to env-vars has
# inconsistent syntax between shell and powershell.
shell: bash
run: |
# Parse out what we just built and upload it to scratch storage
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
- name: "Upload artifacts"
uses: actions/upload-artifact@v4
with:
name: artifacts-build-local-${{ join(matrix.targets, '_') }}
path: |
${{ steps.cargo-dist.outputs.paths }}
${{ env.BUILD_MANIFEST_NAME }}
# Build and package all the platform-agnostic(ish) things
build-global-artifacts:
needs:
- plan
- build-local-artifacts
runs-on: "ubuntu-20.04"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install cargo-dist
shell: bash
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.13.3/cargo-dist-installer.sh | sh"
# Get all the local artifacts for the global tasks to use (for e.g. checksums)
- name: Fetch local artifacts
uses: actions/download-artifact@v4
with:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
- id: cargo-dist
shell: bash
run: |
cargo dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json
echo "cargo dist ran successfully"
# Parse out what we just built and upload it to scratch storage
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
- name: "Upload artifacts"
uses: actions/upload-artifact@v4
with:
name: artifacts-build-global
path: |
${{ steps.cargo-dist.outputs.paths }}
${{ env.BUILD_MANIFEST_NAME }}
# Determines if we should publish/announce
host:
needs:
- plan
- build-local-artifacts
- build-global-artifacts
# Only run if we're "publishing", and only if local and global didn't fail (skipped is fine)
if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: "ubuntu-20.04"
outputs:
val: ${{ steps.host.outputs.manifest }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install cargo-dist
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.13.3/cargo-dist-installer.sh | sh"
# Fetch artifacts from scratch-storage
- name: Fetch artifacts
uses: actions/download-artifact@v4
with:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
# This is a harmless no-op for GitHub Releases, hosting for that happens in "announce"
- id: host
shell: bash
run: |
cargo dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json
echo "artifacts uploaded and released successfully"
cat dist-manifest.json
echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT"
- name: "Upload dist-manifest.json"
uses: actions/upload-artifact@v4
with:
# Overwrite the previous copy
name: artifacts-dist-manifest
path: dist-manifest.json
# Create a GitHub Release while uploading all files to it
announce:
needs:
- plan
- host
# use "always() && ..." to allow us to wait for all publish jobs while
# still allowing individual publish jobs to skip themselves (for prereleases).
# "host" however must run to completion, no skipping allowed!
if: ${{ always() && needs.host.result == 'success' }}
runs-on: "ubuntu-20.04"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: "Download GitHub Artifacts"
uses: actions/download-artifact@v4
with:
pattern: artifacts-*
path: artifacts
merge-multiple: true
- name: Cleanup
run: |
# Remove the granular manifests
rm -f artifacts/*-dist-manifest.json
- name: Create GitHub Release
uses: ncipollo/release-action@v1
with:
tag: ${{ needs.plan.outputs.tag }}
name: ${{ fromJson(needs.host.outputs.val).announcement_title }}
body: ${{ fromJson(needs.host.outputs.val).announcement_github_body }}
prerelease: ${{ fromJson(needs.host.outputs.val).announcement_is_prerelease }}
artifacts: "artifacts/*"
Generated
+205 -32
View File
@@ -11,6 +11,21 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.6" version = "1.0.6"
@@ -19,13 +34,14 @@ checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
[[package]] [[package]]
name = "assert_cmd" name = "assert_cmd"
version = "2.0.14" version = "2.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8" checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"bstr", "bstr",
"doc-comment", "doc-comment",
"libc",
"predicates", "predicates",
"predicates-core", "predicates-core",
"predicates-tree", "predicates-tree",
@@ -55,12 +71,44 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "bumpalo"
version = "3.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
[[package]]
name = "cc"
version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]] [[package]]
name = "diff" name = "diff"
version = "0.1.13" version = "0.1.13"
@@ -75,9 +123,10 @@ checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]] [[package]]
name = "diffutils" name = "diffutils"
version = "0.3.0" version = "0.4.2"
dependencies = [ dependencies = [
"assert_cmd", "assert_cmd",
"chrono",
"diff", "diff",
"predicates", "predicates",
"pretty_assertions", "pretty_assertions",
@@ -100,7 +149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@@ -118,6 +167,38 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "iana-time-zone"
version = "0.1.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "js-sys"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
dependencies = [
"wasm-bindgen",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.153" version = "0.2.153"
@@ -130,6 +211,12 @@ version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.1" version = "2.7.1"
@@ -152,10 +239,16 @@ dependencies = [
] ]
[[package]] [[package]]
name = "predicates" name = "once_cell"
version = "3.1.0" version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "predicates"
version = "3.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"difflib", "difflib",
@@ -211,9 +304,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.3" version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -248,7 +341,7 @@ dependencies = [
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@@ -293,14 +386,15 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.10.0" version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
"once_cell",
"rustix", "rustix",
"windows-sys", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@@ -317,9 +411,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.11" version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
[[package]] [[package]]
name = "wait-timeout" name = "wait-timeout"
@@ -330,6 +424,60 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "wasm-bindgen"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@@ -361,6 +509,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"
@@ -371,14 +528,24 @@ dependencies = [
] ]
[[package]] [[package]]
name = "windows-targets" name = "windows-sys"
version = "0.52.2" version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d98532992affa02e52709d5b4d145a3668ae10d9081eea4a7f26f719a8476f71" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm",
"windows_aarch64_msvc", "windows_aarch64_msvc",
"windows_i686_gnu", "windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc", "windows_i686_msvc",
"windows_x86_64_gnu", "windows_x86_64_gnu",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm",
@@ -387,45 +554,51 @@ dependencies = [
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7269c1442e75af9fa59290383f7665b828efc76c429cc0b7f2ecb33cf51ebae" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f70ab2cebf332b7ecbdd98900c2da5298a8c862472fb35c75fc297eabb9d89b8" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "679f235acf6b1639408c0f6db295697a19d103b0cdc88146aa1b992c580c647d" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3480ac194b55ae274a7e135c21645656825da4a7f5b6e9286291b2113c94a78b" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42c46bab241c121402d1cb47d028ea3680ee2f359dcc287482dcf7fdddc73363" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc885a4332ee1afb9a1bacf11514801011725570d35675abc229ce7e3afe4d20" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e440c60457f84b0bee09208e62acc7ade264b38c4453f6312b8c9ab1613e73c" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]] [[package]]
name = "yansi" name = "yansi"
+25 -6
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "diffutils" name = "diffutils"
version = "0.3.0" version = "0.4.2"
edition = "2021" edition = "2021"
description = "A CLI app for generating diff files" description = "A CLI app for generating diff files"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@@ -15,13 +15,32 @@ name = "diffutils"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
diff = "0.1.10" chrono = "0.4.38"
regex = "1.10.3" diff = "0.1.13"
regex = "1.10.4"
same-file = "1.0.6" same-file = "1.0.6"
unicode-width = "0.1.11" unicode-width = "0.1.12"
[dev-dependencies] [dev-dependencies]
pretty_assertions = "1" pretty_assertions = "1.4.0"
assert_cmd = "2.0.14" assert_cmd = "2.0.14"
predicates = "3.1.0" predicates = "3.1.0"
tempfile = "3.10.0" tempfile = "3.10.1"
# The profile that 'cargo dist' will build with
[profile.dist]
inherits = "release"
lto = "thin"
# Config for 'cargo dist'
[workspace.metadata.dist]
# The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax)
cargo-dist-version = "0.13.3"
# CI backends to support
ci = ["github"]
# The installers to generate for each app
installers = []
# Target platforms to build apps for (Rust target-triple syntax)
targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
# Publish jobs to run in CI
pr-run-mode = "plan"
+3
View File
@@ -1,3 +1,6 @@
Copyright (c) Michael Howell
Copyright (c) uutils developers
Apache License Apache License
Version 2.0, January 2004 Version 2.0, January 2004
http://www.apache.org/licenses/ http://www.apache.org/licenses/
+3
View File
@@ -1,3 +1,6 @@
Copyright (c) Michael Howell
Copyright (c) uutils developers
Permission is hereby granted, free of charge, to any Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the documentation files (the "Software"), to deal in the
+1 -1
View File
@@ -9,7 +9,7 @@ edition = "2018"
cargo-fuzz = true cargo-fuzz = true
[dependencies] [dependencies]
libfuzzer-sys = "0.4" libfuzzer-sys = "0.4.7"
diffutils = { path = "../" } diffutils = { path = "../" }
# Prevent this from interfering with workspaces # Prevent this from interfering with workspaces
+36 -27
View File
@@ -8,6 +8,7 @@ use std::io::Write;
use crate::params::Params; use crate::params::Params;
use crate::utils::do_write_line; use crate::utils::do_write_line;
use crate::utils::get_modification_time;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum DiffLine { pub enum DiffLine {
@@ -267,10 +268,14 @@ fn make_diff(
#[must_use] #[must_use]
pub fn diff(expected: &[u8], actual: &[u8], params: &Params) -> Vec<u8> { pub fn diff(expected: &[u8], actual: &[u8], params: &Params) -> Vec<u8> {
let from_modified_time = get_modification_time(&params.from.to_string_lossy());
let to_modified_time = get_modification_time(&params.to.to_string_lossy());
let mut output = format!( let mut output = format!(
"*** {0}\t\n--- {1}\t\n", "*** {0}\t{1}\n--- {2}\t{3}\n",
params.from.to_string_lossy(), params.from.to_string_lossy(),
params.to.to_string_lossy() from_modified_time,
params.to.to_string_lossy(),
to_modified_time
) )
.into_bytes(); .into_bytes();
let diff_results = make_diff(expected, actual, params.context_count, params.brief); let diff_results = make_diff(expected, actual, params.context_count, params.brief);
@@ -434,26 +439,26 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
File::create(&format!("{target}/ab.diff")) File::create(format!("{target}/ab.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alef")).unwrap(); let mut fa = File::create(format!("{target}/alef")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/bet")).unwrap(); let mut fb = File::create(format!("{target}/bet")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.arg("--context") .arg("--context")
.stdin(File::open(&format!("{target}/ab.diff")).unwrap()) .stdin(File::open(format!("{target}/ab.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alef")).unwrap(); let alef = fs::read(format!("{target}/alef")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -515,26 +520,26 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
File::create(&format!("{target}/ab_.diff")) File::create(format!("{target}/ab_.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alef_")).unwrap(); let mut fa = File::create(format!("{target}/alef_")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/bet_")).unwrap(); let mut fb = File::create(format!("{target}/bet_")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.arg("--context") .arg("--context")
.stdin(File::open(&format!("{target}/ab_.diff")).unwrap()) .stdin(File::open(format!("{target}/ab_.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alef_")).unwrap(); let alef = fs::read(format!("{target}/alef_")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -599,26 +604,26 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
File::create(&format!("{target}/abx.diff")) File::create(format!("{target}/abx.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alefx")).unwrap(); let mut fa = File::create(format!("{target}/alefx")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/betx")).unwrap(); let mut fb = File::create(format!("{target}/betx")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.arg("--context") .arg("--context")
.stdin(File::open(&format!("{target}/abx.diff")).unwrap()) .stdin(File::open(format!("{target}/abx.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alefx")).unwrap(); let alef = fs::read(format!("{target}/alefx")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -686,26 +691,26 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
File::create(&format!("{target}/abr.diff")) File::create(format!("{target}/abr.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alefr")).unwrap(); let mut fa = File::create(format!("{target}/alefr")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/betr")).unwrap(); let mut fb = File::create(format!("{target}/betr")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.arg("--context") .arg("--context")
.stdin(File::open(&format!("{target}/abr.diff")).unwrap()) .stdin(File::open(format!("{target}/abr.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alefr")).unwrap(); let alef = fs::read(format!("{target}/alefr")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -717,6 +722,8 @@ mod tests {
#[test] #[test]
fn test_stop_early() { fn test_stop_early() {
use crate::assert_diff_eq;
let from_filename = "foo"; let from_filename = "foo";
let from = ["a", "b", "c", ""].join("\n"); let from = ["a", "b", "c", ""].join("\n");
let to_filename = "bar"; let to_filename = "bar";
@@ -731,9 +738,10 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
let expected_full = [ let expected_full = [
"*** foo\t", "*** foo\tTIMESTAMP",
"--- bar\t", "--- bar\tTIMESTAMP",
"***************", "***************",
"*** 1,3 ****", "*** 1,3 ****",
" a", " a",
@@ -746,7 +754,7 @@ mod tests {
"", "",
] ]
.join("\n"); .join("\n");
assert_eq!(diff_full, expected_full.as_bytes()); assert_diff_eq!(diff_full, expected_full);
let diff_brief = diff( let diff_brief = diff(
from.as_bytes(), from.as_bytes(),
@@ -758,8 +766,9 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
let expected_brief = ["*** foo\t", "--- bar\t", ""].join("\n");
assert_eq!(diff_brief, expected_brief.as_bytes()); let expected_brief = ["*** foo\tTIMESTAMP", "--- bar\tTIMESTAMP", ""].join("\n");
assert_diff_eq!(diff_brief, expected_brief);
let nodiff_full = diff( let nodiff_full = diff(
from.as_bytes(), from.as_bytes(),
+55 -46
View File
@@ -188,9 +188,8 @@ mod tests {
for &d in &[0, 1, 2] { for &d in &[0, 1, 2] {
for &e in &[0, 1, 2] { for &e in &[0, 1, 2] {
for &f in &[0, 1, 2] { for &f in &[0, 1, 2] {
use std::fs::{self, File}; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::process::Command;
let mut alef = Vec::new(); let mut alef = Vec::new();
let mut bet = Vec::new(); let mut bet = Vec::new();
alef.write_all(if a == 0 { b"a\n" } else { b"b\n" }) alef.write_all(if a == 0 { b"a\n" } else { b"b\n" })
@@ -226,26 +225,30 @@ mod tests {
// This test diff is intentionally reversed. // This test diff is intentionally reversed.
// We want it to turn the alef into bet. // We want it to turn the alef into bet.
let diff = diff_w(&alef, &bet, &format!("{target}/alef")).unwrap(); let diff = diff_w(&alef, &bet, &format!("{target}/alef")).unwrap();
File::create("target/ab.ed") File::create(format!("{target}/ab.ed"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alef")).unwrap(); let mut fa = File::create(format!("{target}/alef")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/bet")).unwrap(); let mut fb = File::create(format!("{target}/bet")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("ed") #[cfg(not(windows))] // there's no ed on windows
.arg(&format!("{target}/alef")) {
.stdin(File::open("target/ab.ed").unwrap()) use std::process::Command;
.output() let output = Command::new("ed")
.unwrap(); .arg(format!("{target}/alef"))
assert!(output.status.success(), "{output:?}"); .stdin(File::open(format!("{target}/ab.ed")).unwrap())
//println!("{}", String::from_utf8_lossy(&output.stdout)); .output()
//println!("{}", String::from_utf8_lossy(&output.stderr)); .unwrap();
let alef = fs::read(&format!("{target}/alef")).unwrap(); assert!(output.status.success(), "{output:?}");
assert_eq!(alef, bet); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = std::fs::read(format!("{target}/alef")).unwrap();
assert_eq!(alef, bet);
}
} }
} }
} }
@@ -265,9 +268,8 @@ mod tests {
for &d in &[0, 1, 2] { for &d in &[0, 1, 2] {
for &e in &[0, 1, 2] { for &e in &[0, 1, 2] {
for &f in &[0, 1, 2] { for &f in &[0, 1, 2] {
use std::fs::{self, File}; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::process::Command;
let mut alef = Vec::new(); let mut alef = Vec::new();
let mut bet = Vec::new(); let mut bet = Vec::new();
alef.write_all(if a == 0 { b"\n" } else { b"b\n" }).unwrap(); alef.write_all(if a == 0 { b"\n" } else { b"b\n" }).unwrap();
@@ -296,27 +298,31 @@ mod tests {
} }
// This test diff is intentionally reversed. // This test diff is intentionally reversed.
// We want it to turn the alef into bet. // We want it to turn the alef into bet.
let diff = diff_w(&alef, &bet, "target/alef_").unwrap(); let diff = diff_w(&alef, &bet, &format!("{target}/alef_")).unwrap();
File::create("target/ab_.ed") File::create(format!("{target}/ab_.ed"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create("target/alef_").unwrap(); let mut fa = File::create(format!("{target}/alef_")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/bet_")).unwrap(); let mut fb = File::create(format!("{target}/bet_")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("ed") #[cfg(not(windows))] // there's no ed on windows
.arg("target/alef_") {
.stdin(File::open("target/ab_.ed").unwrap()) use std::process::Command;
.output() let output = Command::new("ed")
.unwrap(); .arg(format!("{target}/alef_"))
assert!(output.status.success(), "{output:?}"); .stdin(File::open(format!("{target}/ab_.ed")).unwrap())
//println!("{}", String::from_utf8_lossy(&output.stdout)); .output()
//println!("{}", String::from_utf8_lossy(&output.stderr)); .unwrap();
let alef = fs::read("target/alef_").unwrap(); assert!(output.status.success(), "{output:?}");
assert_eq!(alef, bet); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = std::fs::read(format!("{target}/alef_")).unwrap();
assert_eq!(alef, bet);
}
} }
} }
} }
@@ -336,9 +342,8 @@ mod tests {
for &d in &[0, 1, 2] { for &d in &[0, 1, 2] {
for &e in &[0, 1, 2] { for &e in &[0, 1, 2] {
for &f in &[0, 1, 2] { for &f in &[0, 1, 2] {
use std::fs::{self, File}; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::process::Command;
let mut alef = Vec::new(); let mut alef = Vec::new();
let mut bet = Vec::new(); let mut bet = Vec::new();
alef.write_all(if a == 0 { b"a\n" } else { b"f\n" }) alef.write_all(if a == 0 { b"a\n" } else { b"f\n" })
@@ -374,26 +379,30 @@ mod tests {
// This test diff is intentionally reversed. // This test diff is intentionally reversed.
// We want it to turn the alef into bet. // We want it to turn the alef into bet.
let diff = diff_w(&alef, &bet, &format!("{target}/alefr")).unwrap(); let diff = diff_w(&alef, &bet, &format!("{target}/alefr")).unwrap();
File::create("target/abr.ed") File::create(format!("{target}/abr.ed"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alefr")).unwrap(); let mut fa = File::create(format!("{target}/alefr")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/betr")).unwrap(); let mut fb = File::create(format!("{target}/betr")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("ed") #[cfg(not(windows))] // there's no ed on windows
.arg(&format!("{target}/alefr")) {
.stdin(File::open("target/abr.ed").unwrap()) use std::process::Command;
.output() let output = Command::new("ed")
.unwrap(); .arg(format!("{target}/alefr"))
assert!(output.status.success(), "{output:?}"); .stdin(File::open(format!("{target}/abr.ed")).unwrap())
//println!("{}", String::from_utf8_lossy(&output.stdout)); .output()
//println!("{}", String::from_utf8_lossy(&output.stderr)); .unwrap();
let alef = fs::read(&format!("{target}/alefr")).unwrap(); assert!(output.status.success(), "{output:?}");
assert_eq!(alef, bet); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = std::fs::read(format!("{target}/alefr")).unwrap();
assert_eq!(alef, bet);
}
} }
} }
} }
+1
View File
@@ -1,5 +1,6 @@
pub mod context_diff; pub mod context_diff;
pub mod ed_diff; pub mod ed_diff;
pub mod macros;
pub mod normal_diff; pub mod normal_diff;
pub mod params; pub mod params;
pub mod unified_diff; pub mod unified_diff;
+25
View File
@@ -0,0 +1,25 @@
// asserts equality of the actual diff and expected diff
// considering datetime varitations
//
// It replaces the modification time in the actual diff
// with placeholder "TIMESTAMP" and then asserts the equality
//
// For eg.
// let brief = "*** fruits_old.txt\t2024-03-24 23:43:05.189597645 +0530\n
// --- fruits_new.txt\t2024-03-24 23:35:08.922581904 +0530\n";
//
// replaced = "*** fruits_old.txt\tTIMESTAMP\n
// --- fruits_new.txt\tTIMESTAMP\n";
#[macro_export]
macro_rules! assert_diff_eq {
($actual:expr, $expected:expr) => {{
use regex::Regex;
use std::str;
let diff = str::from_utf8(&$actual).unwrap();
let re = Regex::new(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+ [+-]\d{4}").unwrap();
let actual = re.replacen(diff, 2, "TIMESTAMP");
assert_eq!(actual, $expected);
}};
}
+45 -9
View File
@@ -4,19 +4,37 @@
// files that was distributed with this source code. // files that was distributed with this source code.
use crate::params::{parse_params, Format}; use crate::params::{parse_params, Format};
use regex::Regex;
use std::env; use std::env;
use std::ffi::OsString;
use std::fs; use std::fs;
use std::io::{self, Write}; use std::io::{self, Read, Write};
use std::process::{exit, ExitCode}; use std::process::{exit, ExitCode};
mod context_diff; mod context_diff;
mod ed_diff; mod ed_diff;
mod macros;
mod normal_diff; mod normal_diff;
mod params; mod params;
mod unified_diff; mod unified_diff;
mod utils; mod utils;
fn report_failure_to_read_input_file(
executable: &OsString,
filepath: &OsString,
error: &std::io::Error,
) {
// std::io::Error's display trait outputs "{detail} (os error {code})"
// but we want only the {detail} (error string) part
let error_code_re = Regex::new(r"\ \(os\ error\ \d+\)$").unwrap();
eprintln!(
"{}: {}: {}",
executable.to_string_lossy(),
filepath.to_string_lossy(),
error_code_re.replace(error.to_string().as_str(), ""),
);
}
// Exit codes are documented at // Exit codes are documented at
// https://www.gnu.org/software/diffutils/manual/html_node/Invoking-diff.html. // https://www.gnu.org/software/diffutils/manual/html_node/Invoking-diff.html.
// An exit status of 0 means no differences were found, // An exit status of 0 means no differences were found,
@@ -38,25 +56,43 @@ fn main() -> ExitCode {
); );
} }
}; };
if same_file::is_same_file(&params.from, &params.to).unwrap_or(false) { if params.from == "-" && params.to == "-"
|| same_file::is_same_file(&params.from, &params.to).unwrap_or(false)
{
maybe_report_identical_files(); maybe_report_identical_files();
return ExitCode::SUCCESS; return ExitCode::SUCCESS;
} }
// read files // read files
let from_content = match fs::read(&params.from) { fn read_file_contents(filepath: &OsString) -> io::Result<Vec<u8>> {
if filepath == "-" {
let mut content = Vec::new();
io::stdin().read_to_end(&mut content).and(Ok(content))
} else {
fs::read(filepath)
}
}
let mut io_error = false;
let from_content = match read_file_contents(&params.from) {
Ok(from_content) => from_content, Ok(from_content) => from_content,
Err(e) => { Err(e) => {
eprintln!("Failed to read from-file: {e}"); report_failure_to_read_input_file(&params.executable, &params.from, &e);
return ExitCode::from(2); io_error = true;
vec![]
} }
}; };
let to_content = match fs::read(&params.to) { let to_content = match read_file_contents(&params.to) {
Ok(to_content) => to_content, Ok(to_content) => to_content,
Err(e) => { Err(e) => {
eprintln!("Failed to read to-file: {e}"); report_failure_to_read_input_file(&params.executable, &params.to, &e);
return ExitCode::from(2); io_error = true;
vec![]
} }
}; };
if io_error {
return ExitCode::from(2);
}
// run diff // run diff
let result: Vec<u8> = match params.format { let result: Vec<u8> = match params.format {
Format::Normal => normal_diff::diff(&from_content, &to_content, &params), Format::Normal => normal_diff::diff(&from_content, &to_content, &params),
+24 -24
View File
@@ -275,26 +275,26 @@ mod tests {
// This test diff is intentionally reversed. // This test diff is intentionally reversed.
// We want it to turn the alef into bet. // We want it to turn the alef into bet.
let diff = diff(&alef, &bet, &Params::default()); let diff = diff(&alef, &bet, &Params::default());
File::create(&format!("{target}/ab.diff")) File::create(format!("{target}/ab.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alef")).unwrap(); let mut fa = File::create(format!("{target}/alef")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/bet")).unwrap(); let mut fb = File::create(format!("{target}/bet")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.arg(&format!("{target}/alef")) .arg(format!("{target}/alef"))
.stdin(File::open(&format!("{target}/ab.diff")).unwrap()) .stdin(File::open(format!("{target}/ab.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alef")).unwrap(); let alef = fs::read(format!("{target}/alef")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -367,27 +367,27 @@ mod tests {
// This test diff is intentionally reversed. // This test diff is intentionally reversed.
// We want it to turn the alef into bet. // We want it to turn the alef into bet.
let diff = diff(&alef, &bet, &Params::default()); let diff = diff(&alef, &bet, &Params::default());
File::create(&format!("{target}/abn.diff")) File::create(format!("{target}/abn.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alefn")).unwrap(); let mut fa = File::create(format!("{target}/alefn")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/betn")).unwrap(); let mut fb = File::create(format!("{target}/betn")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.arg("--normal") .arg("--normal")
.arg(&format!("{target}/alefn")) .arg(format!("{target}/alefn"))
.stdin(File::open(&format!("{target}/abn.diff")).unwrap()) .stdin(File::open(format!("{target}/abn.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alefn")).unwrap(); let alef = fs::read(format!("{target}/alefn")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -441,26 +441,26 @@ mod tests {
// This test diff is intentionally reversed. // This test diff is intentionally reversed.
// We want it to turn the alef into bet. // We want it to turn the alef into bet.
let diff = diff(&alef, &bet, &Params::default()); let diff = diff(&alef, &bet, &Params::default());
File::create(&format!("{target}/ab_.diff")) File::create(format!("{target}/ab_.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alef_")).unwrap(); let mut fa = File::create(format!("{target}/alef_")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/bet_")).unwrap(); let mut fb = File::create(format!("{target}/bet_")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.arg(&format!("{target}/alef_")) .arg(format!("{target}/alef_"))
.stdin(File::open(&format!("{target}/ab_.diff")).unwrap()) .stdin(File::open(format!("{target}/ab_.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alef_")).unwrap(); let alef = fs::read(format!("{target}/alef_")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -519,26 +519,26 @@ mod tests {
// This test diff is intentionally reversed. // This test diff is intentionally reversed.
// We want it to turn the alef into bet. // We want it to turn the alef into bet.
let diff = diff(&alef, &bet, &Params::default()); let diff = diff(&alef, &bet, &Params::default());
File::create(&format!("{target}/abr.diff")) File::create(format!("{target}/abr.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alefr")).unwrap(); let mut fa = File::create(format!("{target}/alefr")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/betr")).unwrap(); let mut fb = File::create(format!("{target}/betr")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.arg(&format!("{target}/alefr")) .arg(format!("{target}/alefr"))
.stdin(File::open(&format!("{target}/abr.diff")).unwrap()) .stdin(File::open(format!("{target}/abr.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alefr")).unwrap(); let alef = fs::read(format!("{target}/alefr")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
+383 -84
View File
File diff suppressed because it is too large Load Diff
+41 -32
View File
@@ -8,6 +8,7 @@ use std::io::Write;
use crate::params::Params; use crate::params::Params;
use crate::utils::do_write_line; use crate::utils::do_write_line;
use crate::utils::get_modification_time;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum DiffLine { pub enum DiffLine {
@@ -238,10 +239,14 @@ fn make_diff(
#[must_use] #[must_use]
pub fn diff(expected: &[u8], actual: &[u8], params: &Params) -> Vec<u8> { pub fn diff(expected: &[u8], actual: &[u8], params: &Params) -> Vec<u8> {
let from_modified_time = get_modification_time(&params.from.to_string_lossy());
let to_modified_time = get_modification_time(&params.to.to_string_lossy());
let mut output = format!( let mut output = format!(
"--- {0}\t\n+++ {1}\t\n", "--- {0}\t{1}\n+++ {2}\t{3}\n",
params.from.to_string_lossy(), params.from.to_string_lossy(),
params.to.to_string_lossy() from_modified_time,
params.to.to_string_lossy(),
to_modified_time
) )
.into_bytes(); .into_bytes();
let diff_results = make_diff(expected, actual, params.context_count, params.brief); let diff_results = make_diff(expected, actual, params.context_count, params.brief);
@@ -461,13 +466,13 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
File::create(&format!("{target}/ab.diff")) File::create(format!("{target}/ab.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alef")).unwrap(); let mut fa = File::create(format!("{target}/alef")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/bet")).unwrap(); let mut fb = File::create(format!("{target}/bet")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
@@ -489,13 +494,13 @@ mod tests {
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.stdin(File::open(&format!("{target}/ab.diff")).unwrap()) .stdin(File::open(format!("{target}/ab.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
println!("{}", String::from_utf8_lossy(&output.stdout)); println!("{}", String::from_utf8_lossy(&output.stdout));
println!("{}", String::from_utf8_lossy(&output.stderr)); println!("{}", String::from_utf8_lossy(&output.stderr));
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
let alef = fs::read(&format!("{target}/alef")).unwrap(); let alef = fs::read(format!("{target}/alef")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -577,25 +582,25 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
File::create(&format!("{target}/abn.diff")) File::create(format!("{target}/abn.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alefn")).unwrap(); let mut fa = File::create(format!("{target}/alefn")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/betn")).unwrap(); let mut fb = File::create(format!("{target}/betn")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.stdin(File::open(&format!("{target}/abn.diff")).unwrap()) .stdin(File::open(format!("{target}/abn.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alefn")).unwrap(); let alef = fs::read(format!("{target}/alefn")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -673,25 +678,25 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
File::create(&format!("{target}/ab_.diff")) File::create(format!("{target}/ab_.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alef_")).unwrap(); let mut fa = File::create(format!("{target}/alef_")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/bet_")).unwrap(); let mut fb = File::create(format!("{target}/bet_")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.stdin(File::open(&format!("{target}/ab_.diff")).unwrap()) .stdin(File::open(format!("{target}/ab_.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alef_")).unwrap(); let alef = fs::read(format!("{target}/alef_")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -754,25 +759,25 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
File::create(&format!("{target}/abx.diff")) File::create(format!("{target}/abx.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alefx")).unwrap(); let mut fa = File::create(format!("{target}/alefx")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/betx")).unwrap(); let mut fb = File::create(format!("{target}/betx")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.stdin(File::open(&format!("{target}/abx.diff")).unwrap()) .stdin(File::open(format!("{target}/abx.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alefx")).unwrap(); let alef = fs::read(format!("{target}/alefx")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -840,25 +845,25 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
File::create(&format!("{target}/abr.diff")) File::create(format!("{target}/abr.diff"))
.unwrap() .unwrap()
.write_all(&diff) .write_all(&diff)
.unwrap(); .unwrap();
let mut fa = File::create(&format!("{target}/alefr")).unwrap(); let mut fa = File::create(format!("{target}/alefr")).unwrap();
fa.write_all(&alef[..]).unwrap(); fa.write_all(&alef[..]).unwrap();
let mut fb = File::create(&format!("{target}/betr")).unwrap(); let mut fb = File::create(format!("{target}/betr")).unwrap();
fb.write_all(&bet[..]).unwrap(); fb.write_all(&bet[..]).unwrap();
let _ = fa; let _ = fa;
let _ = fb; let _ = fb;
let output = Command::new("patch") let output = Command::new("patch")
.arg("-p0") .arg("-p0")
.stdin(File::open(&format!("{target}/abr.diff")).unwrap()) .stdin(File::open(format!("{target}/abr.diff")).unwrap())
.output() .output()
.unwrap(); .unwrap();
assert!(output.status.success(), "{output:?}"); assert!(output.status.success(), "{output:?}");
//println!("{}", String::from_utf8_lossy(&output.stdout)); //println!("{}", String::from_utf8_lossy(&output.stdout));
//println!("{}", String::from_utf8_lossy(&output.stderr)); //println!("{}", String::from_utf8_lossy(&output.stderr));
let alef = fs::read(&format!("{target}/alefr")).unwrap(); let alef = fs::read(format!("{target}/alefr")).unwrap();
assert_eq!(alef, bet); assert_eq!(alef, bet);
} }
} }
@@ -870,6 +875,8 @@ mod tests {
#[test] #[test]
fn test_stop_early() { fn test_stop_early() {
use crate::assert_diff_eq;
let from_filename = "foo"; let from_filename = "foo";
let from = ["a", "b", "c", ""].join("\n"); let from = ["a", "b", "c", ""].join("\n");
let to_filename = "bar"; let to_filename = "bar";
@@ -884,9 +891,10 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
let expected_full = [ let expected_full = [
"--- foo\t", "--- foo\tTIMESTAMP",
"+++ bar\t", "+++ bar\tTIMESTAMP",
"@@ -1,3 +1,3 @@", "@@ -1,3 +1,3 @@",
" a", " a",
"-b", "-b",
@@ -895,7 +903,7 @@ mod tests {
"", "",
] ]
.join("\n"); .join("\n");
assert_eq!(diff_full, expected_full.as_bytes()); assert_diff_eq!(diff_full, expected_full);
let diff_brief = diff( let diff_brief = diff(
from.as_bytes(), from.as_bytes(),
@@ -907,8 +915,9 @@ mod tests {
..Default::default() ..Default::default()
}, },
); );
let expected_brief = ["--- foo\t", "+++ bar\t", ""].join("\n");
assert_eq!(diff_brief, expected_brief.as_bytes()); let expected_brief = ["--- foo\tTIMESTAMP", "+++ bar\tTIMESTAMP", ""].join("\n");
assert_diff_eq!(diff_brief, expected_brief);
let nodiff_full = diff( let nodiff_full = diff(
from.as_bytes(), from.as_bytes(),
+61
View File
@@ -52,6 +52,25 @@ pub fn do_write_line(
} }
} }
/// Retrieves the modification time of the input file specified by file path
/// If an error occurs, it returns the current system time
pub fn get_modification_time(file_path: &str) -> String {
use chrono::{DateTime, Local};
use std::fs;
use std::time::SystemTime;
let modification_time: SystemTime = fs::metadata(file_path)
.and_then(|m| m.modified())
.unwrap_or(SystemTime::now());
let modification_time: DateTime<Local> = modification_time.into();
let modification_time: String = modification_time
.format("%Y-%m-%d %H:%M:%S%.9f %z")
.to_string();
modification_time
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -115,4 +134,46 @@ mod tests {
assert_line_written("foo bar\tbaz", true, 8, "foo bar baz"); assert_line_written("foo bar\tbaz", true, 8, "foo bar baz");
} }
} }
mod modification_time {
use super::*;
#[test]
fn set_time() {
use chrono::{DateTime, Local};
use std::time::SystemTime;
use tempfile::NamedTempFile;
let temp = NamedTempFile::new().unwrap();
// set file modification time equal to current time
let current = SystemTime::now();
let _ = temp.as_file().set_modified(current);
// format current time
let current: DateTime<Local> = current.into();
let current: String = current.format("%Y-%m-%d %H:%M:%S%.9f %z").to_string();
// verify
assert_eq!(
current,
get_modification_time(&temp.path().to_string_lossy())
);
}
#[test]
fn invalid_file() {
use chrono::{DateTime, Local};
use std::time::SystemTime;
let invalid_file = "target/utils/invalid-file";
// store current time before calling `get_modification_time`
// Because the file is invalid, it will return SystemTime::now()
// which will be greater than previously saved time
let current_time: DateTime<Local> = SystemTime::now().into();
let m_time: DateTime<Local> = get_modification_time(invalid_file).parse().unwrap();
assert!(m_time > current_time);
}
}
} }
+125 -29
View File
@@ -4,9 +4,11 @@
// files that was distributed with this source code. // files that was distributed with this source code.
use assert_cmd::cmd::Command; use assert_cmd::cmd::Command;
use diffutilslib::assert_diff_eq;
use predicates::prelude::*; use predicates::prelude::*;
use std::fs::File;
use std::io::Write; use std::io::Write;
use tempfile::NamedTempFile; use tempfile::{tempdir, NamedTempFile};
// Integration tests for the diffutils command // Integration tests for the diffutils command
@@ -17,30 +19,53 @@ fn unknown_param() -> Result<(), Box<dyn std::error::Error>> {
cmd.assert() cmd.assert()
.code(predicate::eq(2)) .code(predicate::eq(2))
.failure() .failure()
.stderr(predicate::str::starts_with("Usage: ")); .stderr(predicate::str::starts_with("Unknown option: \"--foobar\""));
Ok(()) Ok(())
} }
#[test] #[test]
fn cannot_read_from_file() -> Result<(), Box<dyn std::error::Error>> { fn cannot_read_files() -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = Command::cargo_bin("diffutils")?;
cmd.arg("foo.txt").arg("bar.txt");
cmd.assert()
.code(predicate::eq(2))
.failure()
.stderr(predicate::str::starts_with("Failed to read from-file"));
Ok(())
}
#[test]
fn cannot_read_to_file() -> Result<(), Box<dyn std::error::Error>> {
let file = NamedTempFile::new()?; let file = NamedTempFile::new()?;
let nofile = NamedTempFile::new()?;
let nopath = nofile.into_temp_path();
std::fs::remove_file(&nopath)?;
#[cfg(not(windows))]
let error_message = "No such file or directory";
#[cfg(windows)]
let error_message = "The system cannot find the file specified.";
let mut cmd = Command::cargo_bin("diffutils")?; let mut cmd = Command::cargo_bin("diffutils")?;
cmd.arg(file.path()).arg("bar.txt"); cmd.arg(&nopath).arg(file.path());
cmd.assert() cmd.assert()
.code(predicate::eq(2)) .code(predicate::eq(2))
.failure() .failure()
.stderr(predicate::str::starts_with("Failed to read to-file")); .stderr(predicate::str::ends_with(format!(
": {}: {error_message}\n",
&nopath.as_os_str().to_string_lossy()
)));
let mut cmd = Command::cargo_bin("diffutils")?;
cmd.arg(file.path()).arg(&nopath);
cmd.assert()
.code(predicate::eq(2))
.failure()
.stderr(predicate::str::ends_with(format!(
": {}: {error_message}\n",
&nopath.as_os_str().to_string_lossy()
)));
let mut cmd = Command::cargo_bin("diffutils")?;
cmd.arg(&nopath).arg(&nopath);
cmd.assert().code(predicate::eq(2)).failure().stderr(
predicate::str::contains(format!(
": {}: {error_message}\n",
&nopath.as_os_str().to_string_lossy()
))
.count(2),
);
Ok(()) Ok(())
} }
@@ -173,33 +198,104 @@ fn read_from_stdin() -> Result<(), Box<dyn std::error::Error>> {
.arg(file1.path()) .arg(file1.path())
.arg("-") .arg("-")
.write_stdin("bar\n"); .write_stdin("bar\n");
cmd.assert() cmd.assert().code(predicate::eq(1)).failure();
.code(predicate::eq(1))
.failure() let output = cmd.output().unwrap().stdout;
.stdout(predicate::eq(format!( assert_diff_eq!(
"--- {}\t\n+++ /dev/stdin\t\n@@ -1 +1 @@\n-foo\n+bar\n", output,
format!(
"--- {}\tTIMESTAMP\n+++ -\tTIMESTAMP\n@@ -1 +1 @@\n-foo\n+bar\n",
file1.path().to_string_lossy() file1.path().to_string_lossy()
))); )
);
let mut cmd = Command::cargo_bin("diffutils")?; let mut cmd = Command::cargo_bin("diffutils")?;
cmd.arg("-u") cmd.arg("-u")
.arg("-") .arg("-")
.arg(file2.path()) .arg(file2.path())
.write_stdin("foo\n"); .write_stdin("foo\n");
cmd.assert() cmd.assert().code(predicate::eq(1)).failure();
.code(predicate::eq(1))
.failure() let output = cmd.output().unwrap().stdout;
.stdout(predicate::eq(format!( assert_diff_eq!(
"--- /dev/stdin\t\n+++ {}\t\n@@ -1 +1 @@\n-foo\n+bar\n", output,
format!(
"--- -\tTIMESTAMP\n+++ {}\tTIMESTAMP\n@@ -1 +1 @@\n-foo\n+bar\n",
file2.path().to_string_lossy() file2.path().to_string_lossy()
))); )
);
let mut cmd = Command::cargo_bin("diffutils")?; let mut cmd = Command::cargo_bin("diffutils")?;
cmd.arg("-u").arg("-").arg("-").write_stdin("foo\n"); cmd.arg("-u").arg("-").arg("-");
cmd.assert() cmd.assert()
.code(predicate::eq(0)) .code(predicate::eq(0))
.success() .success()
.stdout(predicate::str::is_empty()); .stdout(predicate::str::is_empty());
#[cfg(unix)]
{
let mut cmd = Command::cargo_bin("diffutils")?;
cmd.arg("-u")
.arg(file1.path())
.arg("/dev/stdin")
.write_stdin("bar\n");
cmd.assert().code(predicate::eq(1)).failure();
let output = cmd.output().unwrap().stdout;
assert_diff_eq!(
output,
format!(
"--- {}\tTIMESTAMP\n+++ /dev/stdin\tTIMESTAMP\n@@ -1 +1 @@\n-foo\n+bar\n",
file1.path().to_string_lossy()
)
);
}
Ok(())
}
#[test]
fn compare_file_to_directory() -> Result<(), Box<dyn std::error::Error>> {
let tmp_dir = tempdir()?;
let directory = tmp_dir.path().join("d");
let _ = std::fs::create_dir(&directory);
let a_path = tmp_dir.path().join("a");
let mut a = File::create(&a_path).unwrap();
a.write_all(b"a\n").unwrap();
let da_path = directory.join("a");
let mut da = File::create(&da_path).unwrap();
da.write_all(b"da\n").unwrap();
let mut cmd = Command::cargo_bin("diffutils")?;
cmd.arg("-u").arg(&directory).arg(&a_path);
cmd.assert().code(predicate::eq(1)).failure();
let output = cmd.output().unwrap().stdout;
assert_diff_eq!(
output,
format!(
"--- {}\tTIMESTAMP\n+++ {}\tTIMESTAMP\n@@ -1 +1 @@\n-da\n+a\n",
da_path.display(),
a_path.display()
)
);
let mut cmd = Command::cargo_bin("diffutils")?;
cmd.arg("-u").arg(&a_path).arg(&directory);
cmd.assert().code(predicate::eq(1)).failure();
let output = cmd.output().unwrap().stdout;
assert_diff_eq!(
output,
format!(
"--- {}\tTIMESTAMP\n+++ {}\tTIMESTAMP\n@@ -1 +1 @@\n-a\n+da\n",
a_path.display(),
da_path.display()
)
);
Ok(()) Ok(())
} }
+1 -1
View File
@@ -19,7 +19,7 @@
# By default it expects a release build of the diffutils binary, but a # By default it expects a release build of the diffutils binary, but a
# different build profile can be specified as an argument # different build profile can be specified as an argument
# (e.g. 'dev' or 'test'). # (e.g. 'dev' or 'test').
# Unless overriden by the $TESTS environment variable, all tests in the test # Unless overridden by the $TESTS environment variable, all tests in the test
# suite will be run. Tests targeting a command that is not yet implemented # suite will be run. Tests targeting a command that is not yet implemented
# (e.g. cmp, diff3 or sdiff) are skipped. # (e.g. cmp, diff3 or sdiff) are skipped.