10 Commits
0.2.0 ... 0.2.2

Author SHA1 Message Date
Sreedev Kodichath
028b868ea9 version 0.2.2 (#59)
* replaced fxhash with gxhash
2024-07-04 23:23:01 -04:00
Sreedev Kodichath
a56d194ee3 Merge pull request #56 from sreedevk/feature/add-json-output
Version 0.2.1
2023-11-14 18:38:50 -05:00
sreedev
080cd791dc removed early return 2023-11-14 18:37:48 -05:00
sreedev
b16236763c updated readme + version number 2023-11-14 18:36:27 -05:00
sreedev
3e407f69c8 added json output for further processing using other tools 2023-11-14 18:33:40 -05:00
Sreedev Kodichath
7d386c9420 Merge pull request #54 from sreedevk/distribution-improvements
Improve Distribution Methods & Create Compiled Binaries for More Platforms
2023-08-10 19:54:29 -04:00
sreedev
0dc681d4e7 added release yml 2023-08-10 19:51:57 -04:00
sreedev
442cb4b519 added cargo dist options 2023-08-10 13:05:29 -04:00
sreedev
8463e72f2d removed debug information from distrbution & release profiles to reduce binary size 2023-08-10 12:59:07 -04:00
sreedev
05c95bb67a added roadmap to readme 2023-08-02 09:41:15 -04:00
10 changed files with 420 additions and 477 deletions

2
.cargo/config.toml Normal file
View File

@@ -0,0 +1,2 @@
[build]
rustflags = ["-C", "target-feature=+aes,+sse2"]

View File

@@ -1,12 +1,12 @@
# CI that: # CI that:
# #
# * checks for a Git Tag that looks like a release ("v1.2.0") # * checks for a Git Tag that looks like a release
# * creates a Github Release™ # * creates a Github Release™ and fills in its text
# * builds binaries/packages with cargo-dist # * builds artifacts with cargo-dist (executable-zips, installers)
# * uploads those packages to the Github Release™ # * uploads those artifacts to the Github Release™
# #
# Note that the Github Release™ will be created before the packages, # Note that the Github Release™ will be created before the artifacts,
# so there will be a few minutes where the release has no packages # so there will be a few minutes where the release has no artifacts
# and then they will slowly trickle in, possibly failing. To make # and then they will slowly trickle in, possibly failing. To make
# this more pleasant we mark the release as a "draft" until all # this more pleasant we mark the release as a "draft" until all
# artifacts have been successfully uploaded. This allows you to # artifacts have been successfully uploaded. This allows you to
@@ -17,114 +17,116 @@ name: Release
permissions: permissions:
contents: write contents: write
# This task will run whenever you push a git tag that looks like # This task will run whenever you push a git tag that looks like a version
# a version number. We just look for `v` followed by at least one number # like "v1", "v1.2.0", "v0.1.0-prerelease01", "my-app-v1.0.0", etc.
# and then whatever. so `v1`, `v1.0.0`, and `v1.0.0-prerelease` all work. # The version will be roughly parsed as ({PACKAGE_NAME}-)?v{VERSION}, where
# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION
# must be a Cargo-style SemVer Version.
# #
# If there's a prerelease-style suffix to the version then the Github Release™ # If PACKAGE_NAME is specified, then we will create a Github Release™ for that
# will be marked as a prerelease (handled by taiki-e/create-gh-release-action). # package (erroring out if it doesn't have the given version or isn't cargo-dist-able).
# #
# Note that when generating links to uploaded artifacts, cargo-dist will currently # If PACKAGE_NAME isn't specified, then we will create a Github Release™ for all
# assume that your git tag is always v{VERSION} where VERSION is the version in # (cargo-dist-able) packages in the workspace with that version (this is mode is
# the published package's Cargo.toml (this is the default behaviour of cargo-release). # intended for workspaces with only one dist-able package, or with all dist-able
# In the future this may be made more robust/configurable. # packages versioned/released in lockstep).
#
# If you push multiple tags at once, separate instances of this workflow will
# spin up, creating an independent Github Release™ for each one.
#
# If there's a prerelease-style suffix to the version then the Github Release™
# will be marked as a prerelease.
on: on:
push: push:
tags: tags:
- v[0-9]+.* - '*-?v[0-9]+*'
env:
ALL_CARGO_DIST_TARGET_ARGS: --target=x86_64-unknown-linux-gnu --target=x86_64-apple-darwin --target=x86_64-pc-windows-msvc
ALL_CARGO_DIST_INSTALLER_ARGS:
jobs: jobs:
# Create the Github Release™ so the packages have something to be uploaded to # Create the Github Release™ so the packages have something to be uploaded to
create-release: create-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
tag: ${{ steps.create-gh-release.outputs.computed-prefix }}${{ steps.create-gh-release.outputs.version }} has-releases: ${{ steps.create-release.outputs.has-releases }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- id: create-gh-release - name: Install Rust
uses: taiki-e/create-gh-release-action@v1 run: rustup update 1.71.0 --no-self-update && rustup default 1.71.0
with: - name: Install cargo-dist
draft: true run: curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.7/cargo-dist-installer.sh | sh
# (required) GitHub token for creating GitHub Releases. - id: create-release
token: ${{ secrets.GITHUB_TOKEN }} run: |
cargo dist plan --tag=${{ github.ref_name }} --output-format=json > dist-manifest.json
echo "dist plan ran successfully"
cat dist-manifest.json
# Create the Github Release™ based on what cargo-dist thinks it should be
ANNOUNCEMENT_TITLE=$(jq --raw-output ".announcement_title" dist-manifest.json)
IS_PRERELEASE=$(jq --raw-output ".announcement_is_prerelease" dist-manifest.json)
jq --raw-output ".announcement_github_body" dist-manifest.json > new_dist_announcement.md
gh release create ${{ github.ref_name }} --draft --prerelease="$IS_PRERELEASE" --title="$ANNOUNCEMENT_TITLE" --notes-file=new_dist_announcement.md
echo "created announcement!"
# Upload the manifest to the Github Release™
gh release upload ${{ github.ref_name }} dist-manifest.json
echo "uploaded manifest!"
# Disable all the upload-artifacts tasks if we have no actual releases
HAS_RELEASES=$(jq --raw-output ".releases != null" dist-manifest.json)
echo "has-releases=$HAS_RELEASES" >> "$GITHUB_OUTPUT"
# Build and packages all the things # Build and packages all the things
upload-artifacts: upload-artifacts:
# Let the initial task tell us to not run (currently very blunt)
needs: create-release needs: create-release
if: ${{ needs.create-release.outputs.has-releases == 'true' }}
strategy: strategy:
matrix: matrix:
# For these target platforms # For these target platforms
include: include:
- target: x86_64-unknown-linux-gnu - os: macos-11
os: ubuntu-20.04 dist-args: --artifacts=local --target=aarch64-apple-darwin --target=x86_64-apple-darwin
install-dist: curl --proto '=https' --tlsv1.2 -L -sSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.2/installer.sh | sh install-dist: curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.7/cargo-dist-installer.sh | sh
- target: x86_64-apple-darwin - os: ubuntu-20.04
os: macos-11 dist-args: --artifacts=local --target=x86_64-unknown-linux-gnu
install-dist: curl --proto '=https' --tlsv1.2 -L -sSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.2/installer.sh | sh install-dist: curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.7/cargo-dist-installer.sh | sh
- target: x86_64-pc-windows-msvc - os: windows-2019
os: windows-2019 dist-args: --artifacts=local --target=x86_64-pc-windows-msvc
install-dist: irm 'https://github.com/axodotdev/cargo-dist/releases/download/v0.0.2/installer.ps1' | iex install-dist: irm https://github.com/axodotdev/cargo-dist/releases/download/v0.0.7/cargo-dist-installer.ps1 | iex
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install Rust - name: Install Rust
run: rustup update stable && rustup default stable run: rustup update 1.71.0 --no-self-update && rustup default 1.71.0
- name: Install cargo-dist - name: Install cargo-dist
run: ${{ matrix.install-dist }} run: ${{ matrix.install-dist }}
- name: Run cargo-dist - name: Run cargo-dist
# This logic is a bit janky because it's trying to be a polyglot between # This logic is a bit janky because it's trying to be a polyglot between
# powershell and bash since this will run on windows, macos, and linux! # powershell and bash since this will run on windows, macos, and linux!
# The two platforms don't agree on how to talk about env vars but they # The two platforms don't agree on how to talk about env vars but they
# do agree on 'cat' and '$()' so we use that to marshal values between commmands. # do agree on 'cat' and '$()' so we use that to marshal values between commands.
run: | run: |
# Actually do builds and make zips and whatnot # Actually do builds and make zips and whatnot
cargo dist --target=${{ matrix.target }} --output-format=json > dist-manifest.json cargo dist build --tag=${{ github.ref_name }} --output-format=json ${{ matrix.dist-args }} > dist-manifest.json
echo "dist ran successfully" echo "dist ran successfully"
cat dist-manifest.json cat dist-manifest.json
# Parse out what we just built and upload it to the Github Release™
cat dist-manifest.json | jq --raw-output ".releases[].artifacts[].path" > uploads.txt # Parse out what we just built and upload it to the Github Release™
jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json > uploads.txt
echo "uploading..." echo "uploading..."
cat uploads.txt cat uploads.txt
gh release upload ${{ needs.create-release.outputs.tag }} $(cat uploads.txt) gh release upload ${{ github.ref_name }} $(cat uploads.txt)
echo "uploaded!" echo "uploaded!"
# Compute and upload the manifest for everything # Mark the Github Release™ as a non-draft now that everything has succeeded!
upload-manifest:
needs: create-release
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v3
- name: Install Rust
run: rustup update stable && rustup default stable
- name: Install cargo-dist
run: curl --proto '=https' --tlsv1.2 -L -sSf https://github.com/axodotdev/cargo-dist/releases/download/v0.0.2/installer.sh | sh
- name: Run cargo-dist manifest
run: |
# Generate a manifest describing everything
cargo dist manifest --no-local-paths --output-format=json $ALL_CARGO_DIST_TARGET_ARGS $ALL_CARGO_DIST_INSTALLER_ARGS > dist-manifest.json
echo "dist manifest ran successfully"
cat dist-manifest.json
# Upload the manifest to the Github Release™
gh release upload ${{ needs.create-release.outputs.tag }} dist-manifest.json
echo "uploaded manifest!"
# Edit the Github Release™ title/body to match what cargo-dist thinks it should be
CHANGELOG_TITLE=$(cat dist-manifest.json | jq --raw-output ".releases[].changelog_title")
cat dist-manifest.json | jq --raw-output ".releases[].changelog_body" > new_dist_changelog.md
gh release edit ${{ needs.create-release.outputs.tag }} --title="$CHANGELOG_TITLE" --notes-file=new_dist_changelog.md
echo "updated release notes!"
# Mark the Github Release™ as a non-draft now that everything has succeeded!
publish-release: publish-release:
needs: [create-release, upload-artifacts, upload-manifest] # Only run after all the other tasks, but it's ok if upload-artifacts was skipped
needs: [create-release, upload-artifacts]
if: ${{ always() && needs.create-release.result == 'success' && (needs.upload-artifacts.result == 'skipped' || needs.upload-artifacts.result == 'success') }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -132,5 +134,4 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: mark release as non-draft - name: mark release as non-draft
run: | run: |
gh release edit ${{ needs.create-release.outputs.tag }} --draft=false gh release edit ${{ github.ref_name }} --draft=false

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/target /target
/Cargo.lock /Cargo.lock
/result-bin

691
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,9 @@
[package] [package]
name = "deduplicator" name = "deduplicator"
version = "0.2.0" version = "0.2.2"
edition = "2021" edition = "2021"
description = "find,filter,delete Duplicates" description = "find,filter,delete Duplicates"
repository = "https://github.com/sreedevk/deduplicator"
license = "MIT" license = "MIT"
authors = [ authors = [
"Sreedev Kodichath <sreedevpadmakumar@gmail.com>", "Sreedev Kodichath <sreedevpadmakumar@gmail.com>",
@@ -19,18 +20,28 @@ chrono = "0.4.23"
clap = { version = "4.0.32", features = ["derive"] } clap = { version = "4.0.32", features = ["derive"] }
colored = "2.0.0" colored = "2.0.0"
dashmap = { version = "5.4.0", features = ["rayon"] } dashmap = { version = "5.4.0", features = ["rayon"] }
fxhash = "0.2.1"
globwalk = "0.8.1" globwalk = "0.8.1"
gxhash = "3.4.1"
indicatif = { version = "0.17.2", features = ["rayon"] } indicatif = { version = "0.17.2", features = ["rayon"] }
itertools = "0.10.5" itertools = "0.10.5"
memmap2 = "0.5.8" memmap2 = "0.5.8"
pathdiff = "0.2.1" pathdiff = "0.2.1"
prettytable-rs = "0.10.0" prettytable-rs = "0.10.0"
rayon = "1.6.1" rayon = "1.6.1"
serde = { version = "1.0.192", features = ["derive"] }
serde_json = "1.0.108"
unicode-segmentation = "1.10.0" unicode-segmentation = "1.10.0"
[profile.release]
strip = true
# generated by 'cargo dist init' # generated by 'cargo dist init'
[profile.dist] [profile.dist]
inherits = "release" inherits = "release"
debug = true lto = "thin"
split-debuginfo = "packed"
[workspace.metadata.dist]
rust-toolchain-version = "1.78.0"
ci = ["github"]
targets = ["x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "aarch64-apple-darwin"]
cargo-dist-version = "0.0.7"

View File

@@ -21,6 +21,7 @@ Options:
-f, --follow-links Follow links while scanning directories -f, --follow-links Follow links while scanning directories
-h, --help Print help information -h, --help Print help information
-V, --version Print version information -V, --version Print version information
--json
``` ```
### Examples ### Examples
@@ -121,3 +122,8 @@ Memory: 31731MiB (~32GiB)
## Screenshots ## Screenshots
![](https://user-images.githubusercontent.com/36154121/213618143-e5182e39-731e-4817-87dd-1a6a0f38a449.gif) ![](https://user-images.githubusercontent.com/36154121/213618143-e5182e39-731e-4817-87dd-1a6a0f38a449.gif)
## Roadmap
- Tree format output for duplicate file listing
- GUI
- Packages for different operating system repositories (currently only installable via cargo)

View File

@@ -1,22 +1,25 @@
use anyhow::Result; use anyhow::Result;
use gxhash::GxHasher;
use memmap2::Mmap; use memmap2::Mmap;
use serde::Serialize;
use std::fs; use std::fs;
use std::hash::Hasher; use std::hash::Hasher;
use std::{fs::Metadata, path::PathBuf}; use std::{fs::Metadata, path::PathBuf};
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize)]
pub struct FileInfo { pub struct FileInfo {
pub path: PathBuf, pub path: PathBuf,
pub filemeta: Metadata,
pub hash: Option<String>, pub hash: Option<String>,
pub size: u64, pub size: u64,
#[serde(skip)]
pub filemeta: Metadata,
} }
impl FileInfo { impl FileInfo {
pub fn hash(&self) -> Result<Self> { pub fn hash(&self) -> Result<Self> {
let file = fs::File::open(self.path.clone())?; let file = fs::File::open(self.path.clone())?;
let mapper = unsafe { Mmap::map(&file)? }; let mapper = unsafe { Mmap::map(&file)? };
let mut primhasher = fxhash::FxHasher::default(); let mut primhasher = GxHasher::default();
mapper mapper
.chunks(1_000_000) .chunks(1_000_000)

View File

@@ -121,8 +121,13 @@ impl Formatter {
return Ok(()); return Ok(());
} }
let output_table = Self::generate_table(raw, app_args)?; if app_args.json {
output_table.printstd(); let output_json = serde_json::to_string_pretty(&raw)?;
println!("{}", output_json);
} else {
let output_table = Self::generate_table(raw, app_args)?;
output_table.printstd();
}
Ok(()) Ok(())
} }

View File

@@ -19,8 +19,12 @@ fn main() -> Result<()> {
let results = processor.sizewise()?.hashwise()?; let results = processor.sizewise()?.hashwise()?;
match app_args.interactive { match app_args.interactive {
false => { Formatter::print(results.files, &app_args)?; } false => {
true => { interactive::init(results.files, &app_args)?; } Formatter::print(results.files, &app_args)?;
}
true => {
interactive::init(results.files, &app_args)?;
}
} }
Ok(()) Ok(())

View File

@@ -27,6 +27,9 @@ pub struct Params {
/// Follow links while scanning directories /// Follow links while scanning directories
#[arg(long, short)] #[arg(long, short)]
pub follow_links: bool, pub follow_links: bool,
/// print json output
#[arg(long)]
pub json: bool,
} }
impl Params { impl Params {