diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index beee7db..0000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target-dir = "target/.cargo" diff --git a/.github/install-scripts b/.github/install-scripts deleted file mode 160000 index 9d05f43..0000000 --- a/.github/install-scripts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9d05f4327d954605a2145a2b5416d195a4b5d3a6 diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml deleted file mode 100644 index 043078b..0000000 --- a/.github/workflows/main.yaml +++ /dev/null @@ -1,147 +0,0 @@ -name: Release - -concurrency: - group: ${{ github.ref }} - cancel-in-progress: true - -on: - push: - branches: - - "main" - -env: - PROJECT_NAME: procmon - JUST_VERSION: "1.59.0" - -jobs: - test: - name: ๐Ÿงช Test - runs-on: ubuntu-24.04 - steps: - - { uses: actions/checkout@v4, with: { submodules: true } } - - run: source ./.github/install-scripts/just/main.ps1 - - run: source ./.github/install-scripts/rust/main.ps1 - - run: sudo apt install -y pkg-config libfreetype6-dev libfontconfig1-dev - - run: just test - - format: - name: ๐Ÿ“ Format - runs-on: ubuntu-24.04 - steps: - - { uses: actions/checkout@v4, with: { submodules: true } } - - run: source ./.github/install-scripts/just/main.ps1 - - run: source ./.github/install-scripts/rust/main.ps1 - - run: sudo apt install -y pkg-config libfreetype6-dev libfontconfig1-dev - - run: cargo install cargo-xfmt - - run: just fmt - - lint: - name: ๐Ÿค“ Lint - runs-on: ubuntu-24.04 - steps: - - { uses: actions/checkout@v4, with: { submodules: true } } - - run: source ./.github/install-scripts/just/main.ps1 - - run: source ./.github/install-scripts/rust/main.ps1 - - run: sudo apt install -y pkg-config libfreetype6-dev libfontconfig1-dev - - run: just lint - - build: - strategy: - matrix: - config: - - name: ๐Ÿฅ Linux AMD64 - os: linux - arch: amd64 - runner: ubuntu-24.04 - run: | - rustup target add x86_64-unknown-linux-musl - - - name: ๐Ÿฅ Linux ARM64 - os: linux - arch: arm64 - runner: ubuntu-24.04-arm - run: | - rustup target add aarch64-unknown-linux-musl - - # - name: ๐ŸŽ MacOS AMD64 - # os: macos - # arch: amd64 - # runner: macos-13 - - - name: ๐ŸŽ MacOS ARM64 - os: macos - arch: arm64 - runner: macos-15 - - - name: ๐ŸŸฆ Windows AMD64 - os: windows - arch: amd64 - runner: windows-latest - - - name: ๐ŸŸฆ Windows ARM64 - os: windows - arch: arm64 - runner: windows-latest - run: | - rustup target add aarch64-pc-windows-msvc - - name: ${{ matrix.config.name }} - runs-on: ${{ matrix.config.runner }} - steps: - - { uses: actions/checkout@v4, with: { submodules: true } } - - run: . ./.github/install-scripts/just/main.ps1 - - run: . ./.github/install-scripts/rust/main.ps1 - - if: matrix.config.run - run: ${{ matrix.config.run }} - - env: - os: "${{ matrix.config.os }}" - arch: "${{ matrix.config.arch }}" - profile: "release" - run: just build - - uses: actions/upload-artifact@v4 - with: - name: ${{ env.PROJECT_NAME }}-${{ matrix.config.os }}-${{ matrix.config.arch }} - path: ${{ github.workspace }}/target/${{ matrix.config.os }}-${{ matrix.config.arch }}/**/* - if-no-files-found: error - retention-days: 1 - - publish-github-release: - name: "๐Ÿ”„ Publish Github Release" - runs-on: ubuntu-24.04 - needs: - - test - - format - - lint - - build - steps: - - uses: actions/checkout@v4 - - uses: actions/download-artifact@v4 - with: { path: artifacts } - - name: Publish` Github Release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - set -e - - LAST_TAG=$(curl -sSL https://api.github.com/repos/alshdavid/procmon/releases/latest | jq ".tag_name" | cut -d "." -f 3) - if [ "$LAST_TAG" = "" ]; then - LAST_TAG="0" - fi - declare -i var="$LAST_TAG" - var=$var+1 - TAG="0.0.$var" - - echo "Tag: ${TAG}" - - gh release create $TAG --draft --notes "Automatically built binaries" - gh release edit $TAG --title "๐Ÿš€ Latest" - - cd artifacts - - for name in *; do - cd "${{ github.workspace }}/artifacts/${name}/release" - tar -czvf ./${name}.tar.gz ./* - gh release upload $TAG ${name}.tar.gz - done - - gh release edit $TAG --draft=false diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml deleted file mode 100644 index 9914c20..0000000 --- a/.github/workflows/pull-request.yaml +++ /dev/null @@ -1,29 +0,0 @@ -name: Test and Compile - -on: - push: - branches: ['!main'] - pull_request: - branches: ['*'] - -concurrency: - group: ${{ github.ref }} - cancel-in-progress: true - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Test - run: | - cargo test - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Build - run: | - cargo build diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml new file mode 100644 index 0000000..7c20861 --- /dev/null +++ b/.github/workflows/pull_request.yaml @@ -0,0 +1,67 @@ +name: Pull Request + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +on: + pull_request: + branches: + - "main" + +jobs: + test: + name: ๐Ÿงช Test + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + - run: cargo test + + platform: + name: ๐Ÿงช Test (${{ matrix.runner }}) + strategy: + fail-fast: false + matrix: + runner: + - macos-15 + - windows-latest + runs-on: ${{ matrix.runner }} + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + - run: cargo test + + format: + name: ๐Ÿ“ Format + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + - run: cargo install cargo-xfmt + - run: cargo xfmt --check + + lint: + name: ๐Ÿค“ Lint + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + - run: cargo clippy --all-targets --workspace -- -D warnings + + build: + name: ๐Ÿ”จ Check + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + - run: cargo check diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..16960fd --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,316 @@ +name: Release + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +on: + push: + branches: + - "main" + +jobs: + version: + name: ๐ŸŒ Auto Version Increment + runs-on: ubuntu-24.04 + outputs: + VERSION: ${{ steps.generate.outputs.VERSION }} + GITHUB_REPOSITORY_NAME: ${{ steps.generate.outputs.GITHUB_REPOSITORY_NAME }} + GITHUB_REPOSITORY: ${{ steps.generate.outputs.GITHUB_REPOSITORY }} + steps: + - id: generate + run: | + set -ex + + GITHUB_URL="https://api.github.com/repos/${{ github.repository }}" + LAST_VERSION=$(curl -sSL "$GITHUB_URL/releases/latest" | jq -r '.tag_name // empty') + + if [ -z "$LAST_VERSION" ]; then + # No releases yet + NEW_VERSION="0.0.1" + else + IFS='.' read -r MAJOR MINOR PATCH <<< "$LAST_VERSION" + NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" + fi + + echo "Bumping ${LAST_VERSION:-} -> $NEW_VERSION" + + GITHUB_REPOSITORY_NAME="${GITHUB_REPOSITORY#*/}" + + echo $NEW_VERSION + echo $GITHUB_REPOSITORY + echo $GITHUB_REPOSITORY_NAME + + echo "VERSION=$NEW_VERSION" >> "$GITHUB_OUTPUT" + echo "GITHUB_REPOSITORY_NAME=$GITHUB_REPOSITORY_NAME" >> "$GITHUB_OUTPUT" + echo "GITHUB_REPOSITORY=$GITHUB_REPOSITORY" >> "$GITHUB_OUTPUT" + + test: + name: ๐Ÿงช Test + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + - run: cargo test + + format: + name: ๐Ÿ“ Format + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + - run: cargo install cargo-xfmt + - run: cargo xfmt --check + + lint: + name: ๐Ÿค“ Lint + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + - run: cargo clippy --all-targets --workspace -- -D warnings + + # Due to platform differences I have opted out of using a matrix. + # Examples; + # - Windows executables have different names + # - Linux glibc builds require containers (not used here but I use this as a template) + build_linux_amd64: + name: ๐Ÿฅ Linux AMD64 + runs-on: ubuntu-latest + needs: + - version + - format + - lint + - test + env: + VERSION: ${{needs.version.outputs.VERSION}} + GITHUB_REPOSITORY_NAME: ${{needs.version.outputs.GITHUB_REPOSITORY_NAME}} + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + with: { key: "x86_64-unknown-linux-musl" } + - run: sudo apt-get update + - run: sudo apt-get update && sudo apt-get install -y musl-tools jq + - run: rustup target add x86_64-unknown-linux-musl + - run: sed "s/0.2.0/${VERSION}/g" "Cargo.toml" > "Cargo.toml.new" && mv "Cargo.toml.new" "Cargo.toml" + - run: cargo build --target x86_64-unknown-linux-musl --release + - run: | + BIN_PATH="$(cargo build --target x86_64-unknown-linux-musl --release --message-format=json 2>/dev/null | jq -er 'select(.reason=="compiler-artifact" and .executable!=null) | .executable')"; + BIN_NAME="$(basename "${BIN_PATH}")" + BIN_DIR="$(dirname "${BIN_PATH}")" + mkdir -p "${GITHUB_WORKSPACE}/artifacts" + cd "$BIN_DIR" + tar -czf "${GITHUB_WORKSPACE}/artifacts/${BIN_NAME}-linux-amd64.tar.gz" "${BIN_NAME}" + - uses: actions/upload-artifact@v7 + with: + name: ${{ env.GITHUB_REPOSITORY_NAME }}-linux-amd64 + path: ${{ github.workspace }}/artifacts/**/* + if-no-files-found: error + retention-days: 1 + + build_linux_arm64: + name: ๐Ÿฅ Linux ARM64 + runs-on: ubuntu-26.04-arm + needs: + - version + - format + - lint + - test + env: + VERSION: ${{needs.version.outputs.VERSION}} + GITHUB_REPOSITORY_NAME: ${{needs.version.outputs.GITHUB_REPOSITORY_NAME}} + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + with: { key: "aarch64-unknown-linux-musl" } + - run: sudo apt-get update + - run: sudo apt-get update && sudo apt-get install -y musl-tools jq + - run: rustup target add aarch64-unknown-linux-musl + - run: sed "s/0.2.0/${VERSION}/g" "Cargo.toml" > "Cargo.toml.new" && mv "Cargo.toml.new" "Cargo.toml" + - run: cargo build --target aarch64-unknown-linux-musl --release + - run: | + BIN_PATH="$(cargo build --target aarch64-unknown-linux-musl --release --message-format=json 2>/dev/null | jq -er 'select(.reason=="compiler-artifact" and .executable!=null) | .executable')"; + BIN_NAME="$(basename "${BIN_PATH}")" + BIN_DIR="$(dirname "${BIN_PATH}")" + mkdir -p "${GITHUB_WORKSPACE}/artifacts" + cd "$BIN_DIR" + tar -czf "${GITHUB_WORKSPACE}/artifacts/${BIN_NAME}-linux-arm64.tar.gz" "${BIN_NAME}" + - uses: actions/upload-artifact@v7 + with: + name: ${{ env.GITHUB_REPOSITORY_NAME }}-linux-arm64 + path: ${{ github.workspace }}/artifacts/**/* + if-no-files-found: error + retention-days: 1 + + build_macos_arm64: + name: ๐ŸŽ MacOS ARM64 + runs-on: macos-latest + needs: + - version + - format + - lint + - test + env: + VERSION: ${{needs.version.outputs.VERSION}} + GITHUB_REPOSITORY_NAME: ${{needs.version.outputs.GITHUB_REPOSITORY_NAME}} + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + with: { key: "aarch64-apple-darwin" } + - run: rustup target add aarch64-apple-darwin + - run: sed "s/0.2.0/${VERSION}/g" "Cargo.toml" > "Cargo.toml.new" && mv "Cargo.toml.new" "Cargo.toml" + - run: cargo build --target aarch64-apple-darwin --release + - run: | + BIN_PATH="$(cargo build --target aarch64-apple-darwin --release --message-format=json 2>/dev/null | jq -er 'select(.reason=="compiler-artifact" and .executable!=null) | .executable')"; + BIN_NAME="$(basename "${BIN_PATH}")" + BIN_DIR="$(dirname "${BIN_PATH}")" + mkdir -p "${GITHUB_WORKSPACE}/artifacts" + cd "$BIN_DIR" + tar -czf "${GITHUB_WORKSPACE}/artifacts/${BIN_NAME}-macos-arm64.tar.gz" "${BIN_NAME}" + - uses: actions/upload-artifact@v7 + with: + name: ${{ env.GITHUB_REPOSITORY_NAME }}-macos-arm64 + path: ${{ github.workspace }}/artifacts/**/* + if-no-files-found: error + retention-days: 1 + + build_windows_amd64: + name: ๐ŸŸฆ Windows AMD64 + runs-on: windows-latest + needs: + - version + - format + - lint + - test + env: + VERSION: ${{needs.version.outputs.VERSION}} + GITHUB_REPOSITORY_NAME: ${{needs.version.outputs.GITHUB_REPOSITORY_NAME}} + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + with: { key: "x86_64-pc-windows-msvc" } + - run: rustup target add x86_64-pc-windows-msvc + - run: sed "s/0.2.0/${VERSION}/g" "Cargo.toml" > "Cargo.toml.new" && mv "Cargo.toml.new" "Cargo.toml" + - run: cargo build --target x86_64-pc-windows-msvc --release + - run: | + BIN_PATH="$(cargo build --target x86_64-pc-windows-msvc --release --message-format=json 2>/dev/null | jq -er 'select(.reason=="compiler-artifact" and .executable!=null) | .executable' | tr -d '\r')"; + BIN_PATH="$(cygpath -u "${BIN_PATH}")" + BIN_NAME="$(basename "${BIN_PATH}")" + BIN_DIR="$(dirname "${BIN_PATH}")" + ARTIFACTS_DIR="$(cygpath -u "${GITHUB_WORKSPACE}")/artifacts" + mkdir -p "${ARTIFACTS_DIR}" + cd "$BIN_DIR" + tar -czf "${ARTIFACTS_DIR}/${BIN_NAME%.exe}-windows-amd64.tar.gz" "${BIN_NAME}" + - uses: actions/upload-artifact@v7 + with: + name: ${{ env.GITHUB_REPOSITORY_NAME }}-windows-amd64 + path: ${{ github.workspace }}/artifacts/**/* + if-no-files-found: error + retention-days: 1 + + build_windows_arm64: + name: ๐ŸŸฆ Windows ARM64 + runs-on: windows-latest + needs: + - version + - format + - lint + - test + env: + VERSION: ${{needs.version.outputs.VERSION}} + GITHUB_REPOSITORY_NAME: ${{needs.version.outputs.GITHUB_REPOSITORY_NAME}} + steps: + - uses: actions/checkout@v7 + - run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - uses: Swatinem/rust-cache@v2 + with: { key: "aarch64-pc-windows-msvc" } + - run: rustup target add aarch64-pc-windows-msvc + - run: sed "s/0.2.0/${VERSION}/g" "Cargo.toml" > "Cargo.toml.new" && mv "Cargo.toml.new" "Cargo.toml" + - run: cargo build --target aarch64-pc-windows-msvc --release + - run: | + BIN_PATH="$(cargo build --target aarch64-pc-windows-msvc --release --message-format=json 2>/dev/null | jq -er 'select(.reason=="compiler-artifact" and .executable!=null) | .executable' | tr -d '\r')"; + BIN_PATH="$(cygpath -u "${BIN_PATH}")" + BIN_NAME="$(basename "${BIN_PATH}")" + BIN_DIR="$(dirname "${BIN_PATH}")" + ARTIFACTS_DIR="$(cygpath -u "${GITHUB_WORKSPACE}")/artifacts" + mkdir -p "${ARTIFACTS_DIR}" + cd "$BIN_DIR" + tar -czf "${ARTIFACTS_DIR}/${BIN_NAME%.exe}-windows-arm64.tar.gz" "${BIN_NAME}" + - uses: actions/upload-artifact@v7 + with: + name: ${{ env.GITHUB_REPOSITORY_NAME }}-windows-arm64 + path: ${{ github.workspace }}/artifacts/**/* + if-no-files-found: error + retention-days: 1 + + publish_github_release: + name: "๐Ÿฑ Publish Github Release" + runs-on: ubuntu-24.04 + permissions: + contents: write + needs: + - build_linux_amd64 + - build_linux_arm64 + - build_macos_arm64 + - build_windows_amd64 + - build_windows_arm64 + - version + steps: + - uses: actions/checkout@v7 + - uses: actions/download-artifact@v8 + with: + path: artifacts + merge-multiple: true + - name: Publish` Github Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{needs.version.outputs.VERSION}} + run: | + set -ex + + echo "Tag: ${VERSION}" + + gh release delete "$VERSION" --yes --cleanup-tag 2>/dev/null || true + gh release create "$VERSION" --draft --notes "Generating" + gh release edit "$VERSION" --title "v${VERSION}" + + cd artifacts + ls -la + + for name in *; do + echo $name + gh release upload "$VERSION" "$name" + done + + gh release edit "$VERSION" --draft=false + + changelog: + name: "๐Ÿ“ Generate Changelog" + runs-on: ubuntu-latest + needs: + - version + - publish_github_release + steps: + - uses: actions/checkout@v7 + - env: + VERSION: ${{needs.version.outputs.VERSION}} + run: | + payload="$(jq -n \ + --arg repository "$GITHUB_REPOSITORY" \ + --arg version "$VERSION" \ + '{repository: $repository, version: $version}')" + + curl -fsS -X POST "${{ secrets.SENTINEL_CHANGELOG_WEBHOOK }}" \ + -H "Content-Type: application/json" \ + -d "$payload" || true diff --git a/.github/workflows/update_dependencies.yaml b/.github/workflows/update_dependencies.yaml new file mode 100644 index 0000000..b3d2c50 --- /dev/null +++ b/.github/workflows/update_dependencies.yaml @@ -0,0 +1,32 @@ +name: Update Dependencies + +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * *' + +permissions: + contents: write + +defaults: + run: + shell: bash + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +jobs: + renew: + runs-on: ubuntu-latest + steps: + - run: | + payload="$(jq -n \ + --arg repository "$GITHUB_REPOSITORY" \ + --arg repository_url "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" \ + --arg ssh_url "git@${GITHUB_SERVER_URL#https://}:$GITHUB_REPOSITORY.git" \ + '{repository_name: $repository, repository_url: $repository_url, ssh_url: $ssh_url}')" + + curl -fsS -X POST "${{ secrets.SENTINEL_UPDATE_WEBHOOK }}" \ + -H "Content-Type: application/json" \ + -d "$payload" \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 8e9d390..0000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule ".github/install-scripts"] - path = .github/install-scripts - url = https://github.com/alshdavid/install-scripts.git - branch = main diff --git a/Cargo.toml b/Cargo.toml index de9a441..a5ebb3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,34 @@ name = "procmon" version = "0.2.0" edition = "2024" +description = "A command line utility that spawns a process and produces a csv report on its resource usage" +license = "GPL-3.0" +repository = "https://github.com/alshlabs/procplot" +readme = "README.md" +keywords = ["process", "monitor", "cli"] +categories = ["command-line-utilities"] + +[lints.rust] +elided_lifetimes_in_paths = "allow" +rust_2018_idioms = { priority = -1, level = "deny" } +unsafe_code = "forbid" + +[lints.clippy] +pedantic = { level = "deny", priority = -1 } +cargo = { level = "deny", priority = -1 } +uninlined_format_args = "allow" +module_inception = "allow" +enum_glob_use = "deny" +unwrap_used = "deny" +expect_used = "deny" +panic = "deny" +dbg_macro = "deny" +todo = "deny" +unimplemented = "deny" +implicit_clone = "deny" +clone_on_ref_ptr = "deny" +rest_pat_in_fully_bound_structs = "deny" +multiple_crate_versions = "allow" [dependencies] anyhow = "1.0.104" @@ -9,3 +37,9 @@ clap = { version = "4.6.7", features = ["derive", "env", "string"] } serde = { version = "1.0.229", features = ["serde_derive", "derive"] } sysinfo = "0.40.1" +[profile.release] +codegen-units = 1 +lto = "fat" +opt-level = 3 +strip = true +panic = "abort" diff --git a/justfile b/justfile deleted file mode 100644 index c0f81cb..0000000 --- a/justfile +++ /dev/null @@ -1,98 +0,0 @@ -set windows-shell := ["pwsh", "-NoLogo", "-NoProfileLoadTime", "-Command"] - -project_name := "procmon" -profile := env_var_or_default("profile", "debug") - -os := \ -if \ - env_var_or_default("os", "") == "Windows_NT" { "windows" } \ -else if \ - env_var_or_default("os", "") != "" { env_var("os") } \ -else \ - { os() } - -arch := \ -if \ - env_var_or_default("arch", "") != "" { env_var("arch") } \ -else if \ - arch() == "x86_64" { "amd64" } \ -else if \ - arch() == "aarch64" { "arm64" } \ -else \ - { arch() } - -target := \ -if \ - os + arch == "linuxamd64" { "x86_64-unknown-linux-musl" } \ -else if \ - os + arch == "linuxarm64" { "aarch64-unknown-linux-musl" } \ -else if \ - os + arch == "macosamd64" { "x86_64-apple-darwin" } \ -else if\ - os + arch == "macosarm64" { "aarch64-apple-darwin" } \ -else if \ - os + arch == "windowsamd64" { "x86_64-pc-windows-msvc" } \ -else if \ - os + arch == "windowsarm64" { "aarch64-pc-windows-msvc" } \ -else \ - { env_var_or_default("target", "debug") } - -profile_cargo := \ -if \ - profile != "debug" { "--profile " + profile } \ -else \ - { "" } - -target_cargo := \ -if \ - target == "debug" { "" } \ -else if \ - target == "" { "" } \ -else \ - { "--target " + target } - -out_dir := join(justfile_directory(), "target", os + "-" + arch, profile) -out_dir_link := join(justfile_directory(), "target", profile) - -[unix] -build: - @rm -rf "{{out_dir}}" - @rm -rf "{{out_dir_link}}" - @mkdir -p "{{out_dir}}" - cargo build {{profile_cargo}} {{target_cargo}} - @cp "./target/.cargo/{{target}}/{{profile}}/{{project_name}}" "{{out_dir}}" - @# ln -rs "{{out_dir}}" "{{out_dir_link}}" - -[windows] -build: - @if (Test-Path {{out_dir}}) { Remove-Item -Recurse -Force {{out_dir}} | Out-Null } - @if (Test-Path {{out_dir_link}}) { Remove-Item -Recurse -Force {{out_dir_link}} | Out-Null } - @New-Item -ItemType "directory" -Force -Path "{{out_dir}}" | Out-Null - cargo build {{profile_cargo}} {{target_cargo}} - Copy-Item ".\target\.cargo\{{target}}\{{profile}}\{{project_name}}.exe" -Destination "{{out_dir}}" | Out-Null - @# New-Item -Path "{{out_dir}}" -ItemType SymbolicLink -Value "{{out_dir_link}}" - -[unix] -run *ARGS: - just build - {{out_dir}}/{{project_name}} {{ARGS}} - -[windows] -run *ARGS: - just build - {{out_dir}}/{{project_name}}.exe {{ARGS}} - -test: - cargo test - -lint: - cargo clippy -- --deny "warnings" - -lint_fix *ARGS: - cargo clippy --fix --allow-staged -- --deny "warnings" - -fmt: - cargo xfmt --check -fmt_fix *ARGS: - cargo xfmt - diff --git a/src/args.rs b/src/args.rs index c98f7a6..a6f1cc7 100644 --- a/src/args.rs +++ b/src/args.rs @@ -8,6 +8,8 @@ use clap::ValueEnum; use serde::Serialize; #[derive(Parser, Debug, Clone)] +// The flags are user-facing CLI options, grouping them into a sub-struct would only complicate the interface. +#[allow(clippy::struct_excessive_bools)] pub struct Args { /// Command to run pub command: Vec, @@ -57,10 +59,10 @@ pub struct Args { pub no_measure_disk: bool, } -fn parse_file_path(arg: &str) -> Result { +fn parse_file_path(arg: &str) -> anyhow::Result { let mut target_path = PathBuf::from(arg); if target_path.is_relative() { - target_path = env::current_dir().unwrap().join(target_path); + target_path = env::current_dir()?.join(target_path); } Ok(target_path) } @@ -102,8 +104,9 @@ impl TimeUnits { &self, t: Duration, ) -> f64 { + #[allow(clippy::cast_precision_loss)] match self { - TimeUnits::S => t.as_millis() as f64 / 1000_f64, + TimeUnits::S => t.as_secs_f64(), TimeUnits::Ms => t.as_millis() as f64, } } diff --git a/src/main.rs b/src/main.rs index 755a3f4..6375de9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,7 +27,7 @@ fn main() -> anyhow::Result<()> { let reporter = match Reporter::new( &args.report_path, - &args.override_report, + args.override_report, Columns { cpu: !args.no_measure_cpu, memory: !args.no_measure_mem, @@ -67,7 +67,10 @@ fn main() -> anyhow::Result<()> { if !command.no_measure_cpu { let cpu = info.cpu_usage(); - row.cpu = Some(cpu.round() as u64); + // Sysinfo reports a non-negative percentage, so clamping and truncating are safe + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let cpu = cpu.round().max(0.0) as u64; + row.cpu = Some(cpu); } if !command.no_measure_mem { @@ -81,7 +84,9 @@ fn main() -> anyhow::Result<()> { row.disk_write = Some(disk.written_bytes); } - row.time = now - start_time; + row.time = now + .checked_sub(start_time) + .context("Clock moved backwards")?; reporter.write(row)?; thread::sleep(command.poll_interval); @@ -128,7 +133,9 @@ fn main() -> anyhow::Result<()> { let end_time = SystemTime::now().duration_since(UNIX_EPOCH)?; reporter.write(Row { - time: end_time - start_time, + time: end_time + .checked_sub(start_time) + .context("Clock moved backwards")?, memory: Some(0), cpu: Some(0), disk_read: Some(0), @@ -139,8 +146,10 @@ fn main() -> anyhow::Result<()> { }) }; - h1.join().unwrap()?; - h0.join().unwrap()?; + h1.join() + .map_err(|_| anyhow::anyhow!("Process thread panicked"))??; + h0.join() + .map_err(|_| anyhow::anyhow!("Monitor thread panicked"))??; Ok(()) } diff --git a/src/reporter.rs b/src/reporter.rs index c6a47e5..e13df13 100644 --- a/src/reporter.rs +++ b/src/reporter.rs @@ -31,14 +31,19 @@ pub struct Reporter { } impl Reporter { + // `columns` and `args` are owned so they can be moved into the writer thread + #[allow(clippy::needless_pass_by_value)] pub fn new( report_file: &Path, - override_report: &bool, + override_report: bool, columns: Columns, args: Args, ) -> anyhow::Result { if !override_report && std::fs::exists(report_file)? { - return Err(anyhow::anyhow!("Report {:?} already exists", report_file)); + return Err(anyhow::anyhow!( + "Report {} already exists", + report_file.display() + )); } if std::fs::exists(report_file)? { @@ -95,7 +100,7 @@ impl Reporter { { match args.mem_units { MemoryUnits::Mb => { - line.push(format!("{}", memory / 1048576_u64)); + line.push(format!("{}", memory / 1_048_576_u64)); } MemoryUnits::Kb => { line.push(format!("{}", memory / 1024_u64)); @@ -117,7 +122,7 @@ impl Reporter { let mut output = String::new(); for (i, col) in line.iter().enumerate() { - output.push_str(&col.to_string()); + output.push_str(col); if i != line.len() - 1 { output.push(','); }