Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: CI

on:
push:
branches: [master, main]
pull_request:

jobs:
test:
name: ${{ matrix.os }} / stable
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]

steps:
- uses: actions/checkout@v4

- name: Install Rust (stable)
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy

- uses: Swatinem/rust-cache@v2

- name: cargo fmt
run: cargo fmt --all -- --check

- name: cargo clippy
run: cargo clippy --release --all-targets -- -D warnings

- name: cargo build
run: cargo build --release

- name: cargo test
run: cargo test --release
80 changes: 80 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: Release

on:
push:
tags: ['v*']

permissions:
contents: write

jobs:
build:
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
ext: ''
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
ext: ''
cross: true
- os: macos-latest
target: x86_64-apple-darwin
ext: ''
- os: macos-latest
target: aarch64-apple-darwin
ext: ''
- os: windows-latest
target: x86_64-pc-windows-msvc
ext: '.exe'

steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}

- uses: Swatinem/rust-cache@v2

- name: Install cross-toolchain (Linux aarch64)
if: matrix.cross == true
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> "$GITHUB_ENV"

- name: Build release
run: cargo build --release --target ${{ matrix.target }}

- name: Stage artifact
shell: bash
env:
TARGET: ${{ matrix.target }}
EXT: ${{ matrix.ext }}
REF_NAME: ${{ github.ref_name }}
run: |
mkdir -p dist
BIN="target/${TARGET}/release/wipedicks${EXT}"
OUT="wipedicks-${REF_NAME}-${TARGET}"
mkdir -p "dist/${OUT}"
cp "${BIN}" "dist/${OUT}/"
cp readme.md "dist/${OUT}/"
cd dist
if [[ "${EXT}" == ".exe" ]]; then
7z a "${OUT}.zip" "${OUT}"
else
tar czf "${OUT}.tar.gz" "${OUT}"
fi

- name: Upload to release
uses: softprops/action-gh-release@v2
with:
files: |
dist/*.tar.gz
dist/*.zip
139 changes: 139 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Contributing (Sword Fighters Wanted)

![Sword Fighting](https://media.giphy.com/media/l1ugaivowDSqyE3KM/giphy.gif)

Want to cross streams? Pull requests are welcome. Before you start whittling, read this end to end β€” the project has a load-bearing tone and a strict tooling bar, and most rejected PRs would have been merges if the contributor had skimmed the rules first.

## The vibe (three rules)

1. **Truth wraps in jokes, not the other way around.** Every comment, doc-string, error message, and `--help` line is a dick joke as the wrapper around the technical payload. If the joke obscures the truth, the joke loses. If the truth has no joke, that's also fine β€” comments earn their place by being load-bearing.

2. **Default to no comments.** Rust's identifiers and types do most of the documenting. Only comment when the *why* is non-obvious (a hidden invariant, a workaround, a perf detail, a platform quirk). Then dress that *why* in the project voice.

3. **The joke is about dicks and sex acts. Not about people.** Anything that punches down β€” slurs, bigotry, harassment of named individuals β€” gets rejected on sight regardless of how clever the wrapper is. `--gay` (rainbow mode) and `--rape` (override safe-word) are project-internal *action-shape* names, not pejoratives aimed at anyone. If you can't tell the difference, this isn't the project for you.

## Voice cheat-sheet

Examples pulled verbatim from the codebase. Read these before you write your own.

### Good β€” `--help` doc string (lives in `src/cli.rs`)

```rust
/// Take it slow, big boy. One penis per write(2). Useful for sanity
/// comparison or terminals with a kink for tiny syscalls. ~5000x more
/// syscalls than the buffered path.
#[arg(short = 's', long)]
pub slow: bool,
```

The joke (basic missionary / one-penis-per-write) sits *on top of* the technical claim (one `write(2)` per generated dick, useful for syscall-count comparison, ~5000Γ— ratio against the buffered path). The reader gets both.

### Good β€” module header (lives in `src/safety.rs`)

```rust
//! Cock-block department. Stops you from face-fucking your /etc/ when your
//! hand slipped, your /boot/ when you meant /tmp/, or the swap file your
//! kernel is currently using to remember things.
```

Names the module's job, then lists the actual hazards it catches.

### Good β€” invariant comment (lives in `src/wipe.rs`)

```rust
// Refill ONCE per round. Within a round we rewrite the same dicks for
// every chunk: the content is non-cryptographic ASCII art, so reusing
// the buffer is invisible. Across rounds we get fresh variety.
buf.fill();
```

A load-bearing perf note. Tells future-you (or future-contributor-you) why this isn't an accidental optimization to undo.

### Bad β€” sterile rewrite

```rust
/// Disables buffered writing for compatibility purposes.
pub slow: bool,
```

Accurate, but kills the voice. PRs that "professionalize" existing copy get closed.

### Bad β€” joke with no payload

```rust
// nut nut nut
buf.fill();
```

This is the joke without the why. Either explain the perf reason or delete the comment.

### Bad β€” punching at people

```rust
// only <slur> would name a variable this badly
```

Hard no, regardless of how true it feels in the moment.

## Code style + tooling

Reproduce locally before pushing. CI on `ubuntu-latest`, `macos-latest`, and `windows-latest` runs all four:

```bash
cargo fmt --all -- --check # exit 0
cargo clippy --release --all-targets -- -D warnings # exit 0, no warnings
cargo build --release # exit 0
cargo test --release # all tests pass
```

- **Rust 2021, snake_case, no `unsafe`.** If you genuinely need `unsafe`, justify it in the PR description.
- **Errors via `anyhow`.** Bubble to `main` and print with `{:#}` so the context chain shows up.
- **Per-platform code uses `#[cfg(target_os = "...")]`.** The fallback branch always compiles cleanly β€” silence dead-code warnings on non-supported platforms via `#[cfg_attr(not(target_os = "linux"), allow(dead_code))]` on the enum, not blanket `#[allow(dead_code)]`.
- **New deps need a one-line justification in the PR description.** We prefer leaning on existing crates (`indicatif`, `wide`, `console`, `anyhow`, `clap`, `ctrlc`, `rand`) over pulling in new ones for marginal wins.
- **Public items** (`pub fn` / `pub struct` / `pub enum`) get a doc-string in the project voice. **Private items** don't, unless the *why* is non-obvious.

## Module layout (so your PR lands in the right file)

| Module | What it does |
|---|---|
| `main.rs` | Arg parse β†’ safety check β†’ drive policy β†’ bounded thread pool β†’ exit code. |
| `cli.rs` | clap derive `Args` + per-flag `--help` copy. **Touch this and you change user-visible help text.** Match the existing voice. |
| `dicks.rs` | The actual penis generator. SIMD batched fill via `wide::u8x32`, per-thread `SmallRng`. |
| `wipe.rs` | `wipe_file`, `wipe_freespace`, `verify_file`. Cleanup pass always runs. |
| `drive.rs` | SSD/NVMe detection + refusal + `--secure-erase` delegation. Linux + macOS supported; Windows is a stub. |
| `safety.rs` | Path-safety guard. System dirs, swap, mounted devices. `--rape` bypasses. |
| `cleanup.rs` | Process-wide ctrl-c cleanup registry. |
| `progress.rs` | indicatif bars + the `VERBS` table for completion messages. |

If your PR touches more than two of these, it should probably be two PRs.

## PR checklist

- [ ] One concern per PR. Refactors stay separate from feature work.
- [ ] PR description matches the project voice. Bullet points are fine; corpo-speak is not.
- [ ] CI green on Linux, macOS, Windows.
- [ ] Tests added if you introduced a public function with non-trivial behavior.
- [ ] If you added or removed a CLI flag, the README's `<details>All options</details>` block stays in sync.
- [ ] For big changes (>200 LOC or a new module): open an issue first to align on the approach. We don't want anyone burning a weekend on a PR we'd close.

## What we want

- **Pick up `help wanted` issues.**
- **Bug reports with reproduction steps.** What you ran, what happened, what you expected, what OS + Rust version.
- **New completion verbs** for the `VERBS` table in `src/progress.rs`. Submit a PR adding one or three, each with color / bold / italic / emoji choices. Keep them on-brand.
- **More `--shaft-*` / `--jizz-*` knobs** that make the generator more configurable without exploding the flag list.

## What we don't want

- **"Modernization" PRs that swap our tone for boilerplate corporate copy.** The voice is the project.
- **Heavy new dependencies.** No `tokio`, no async runtimes, no web servers, no GUI toolkits. This is a single-binary CLI.
- **New override flags layered on top of `--rape`.** One nuclear safe-word is enough.
- **Anything that breaks the SSD-refusal default.** SSD-safety is the load-bearing feature; if you have a real reason to bypass it on a specific run, `--rape` already exists.

## The actual social contract

- Be a person to other contributors. Disagreement is fine; ad hominem is not.
- Maintainer reviews when maintainer reviews. Pinging "any update?" after 7+ days is fine; pinging hourly is not.
- If your PR sits unmerged for 2+ weeks with no maintainer response, ping in the PR thread. If it sits for 4+ weeks, escalate by tagging in the issue tracker.

8====D~~~
Loading
Loading