dark-matter-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dark_matter_cli-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +59 -0
- dark_matter_cli-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- dark_matter_cli-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +29 -0
- dark_matter_cli-0.1.0/.github/renovate.json +60 -0
- dark_matter_cli-0.1.0/.github/workflows/ci.yml +65 -0
- dark_matter_cli-0.1.0/.github/workflows/release.yml +40 -0
- dark_matter_cli-0.1.0/.gitignore +16 -0
- dark_matter_cli-0.1.0/.pre-commit-config.yaml +108 -0
- dark_matter_cli-0.1.0/.python-version +1 -0
- dark_matter_cli-0.1.0/CODE_OF_CONDUCT.md +33 -0
- dark_matter_cli-0.1.0/LICENSE +21 -0
- dark_matter_cli-0.1.0/PKG-INFO +200 -0
- dark_matter_cli-0.1.0/README.md +156 -0
- dark_matter_cli-0.1.0/justfile +92 -0
- dark_matter_cli-0.1.0/pyproject.toml +174 -0
- dark_matter_cli-0.1.0/src/dark_matter_cli/__init__.py +35 -0
- dark_matter_cli-0.1.0/src/dark_matter_cli/cli.py +295 -0
- dark_matter_cli-0.1.0/src/dark_matter_cli/core.py +304 -0
- dark_matter_cli-0.1.0/src/dark_matter_cli/display.py +131 -0
- dark_matter_cli-0.1.0/src/dark_matter_cli/homebrew.py +320 -0
- dark_matter_cli-0.1.0/src/dark_matter_cli/logger.py +21 -0
- dark_matter_cli-0.1.0/src/dark_matter_cli/py.typed +0 -0
- dark_matter_cli-0.1.0/tests/conftest.py +26 -0
- dark_matter_cli-0.1.0/tests/test_cli.py +123 -0
- dark_matter_cli-0.1.0/tests/test_core.py +146 -0
- dark_matter_cli-0.1.0/tests/test_display.py +56 -0
- dark_matter_cli-0.1.0/tests/test_homebrew.py +110 -0
- dark_matter_cli-0.1.0/uv.lock +788 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: 🐛 Bug Report
|
|
2
|
+
description: Report anomalous pipeline behavior or incorrect bloat mass calculations.
|
|
3
|
+
title: "[BUG]: <brief description>"
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for helping map the unseen mass. Please provide as much telemetry as possible so we can accurately reproduce the anomaly in the local DAG.
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: description
|
|
12
|
+
attributes:
|
|
13
|
+
label: Anomaly Description
|
|
14
|
+
description: A clear and concise description of the pipeline failure or mathematical error.
|
|
15
|
+
placeholder: When computing the transitive in-degree map, dark-matter encounters a KeyError...
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: reproduction
|
|
20
|
+
attributes:
|
|
21
|
+
label: Reproduction Vector
|
|
22
|
+
description: The exact CLI invocation or state required to reproduce the behavior.
|
|
23
|
+
placeholder: |
|
|
24
|
+
1. Have package `X` installed via Homebrew
|
|
25
|
+
2. Execute `dark-matter --sort recursive --standard`
|
|
26
|
+
3. Observe pipeline termination
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
- type: textarea
|
|
30
|
+
id: expected
|
|
31
|
+
attributes:
|
|
32
|
+
label: Expected Behavior
|
|
33
|
+
description: What did you mathematically or programmatically expect the pipeline to output?
|
|
34
|
+
validations:
|
|
35
|
+
required: true
|
|
36
|
+
- type: textarea
|
|
37
|
+
id: logs
|
|
38
|
+
attributes:
|
|
39
|
+
label: Traceback / Output Logs
|
|
40
|
+
description: Paste any relevant stderr tracebacks or verbose CLI output.
|
|
41
|
+
render: python
|
|
42
|
+
- type: input
|
|
43
|
+
id: version
|
|
44
|
+
attributes:
|
|
45
|
+
label: Dark Matter Version
|
|
46
|
+
description: Output of `dark-matter --version`
|
|
47
|
+
placeholder: "0.1.0"
|
|
48
|
+
validations:
|
|
49
|
+
required: true
|
|
50
|
+
- type: dropdown
|
|
51
|
+
id: os
|
|
52
|
+
attributes:
|
|
53
|
+
label: Operating System / Architecture
|
|
54
|
+
options:
|
|
55
|
+
- macOS (Apple Silicon / ARM64)
|
|
56
|
+
- macOS (Intel / x86_64)
|
|
57
|
+
- Linux (POSIX)
|
|
58
|
+
validations:
|
|
59
|
+
required: true
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: 🚀 Feature Request
|
|
2
|
+
description: Propose a new metric, attribution model, or pipeline enhancement.
|
|
3
|
+
title: "[FEAT]: <brief description>"
|
|
4
|
+
labels: ["enhancement"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Have an idea to improve the resolution of the cosmological storage mapping? Detail the theoretical model or structural enhancement below.
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: problem
|
|
12
|
+
attributes:
|
|
13
|
+
label: The Problem
|
|
14
|
+
description: Is this request addressing a specific limitation or graph-ignorance in the current pipeline?
|
|
15
|
+
placeholder: The current fractional model does not account for...
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: solution
|
|
20
|
+
attributes:
|
|
21
|
+
label: Proposed Solution
|
|
22
|
+
description: Detail the programmatic implementation or mathematical algorithm you'd like to see added.
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
- type: textarea
|
|
26
|
+
id: alternatives
|
|
27
|
+
attributes:
|
|
28
|
+
label: Alternatives Considered
|
|
29
|
+
description: Are there other algorithms, heuristics, or external tooling that could achieve a similar result?
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
3
|
+
"extends": [
|
|
4
|
+
"config:best-practices",
|
|
5
|
+
":semanticCommits",
|
|
6
|
+
":prHourlyLimit2"
|
|
7
|
+
],
|
|
8
|
+
"ignorePaths": [
|
|
9
|
+
"docs/**",
|
|
10
|
+
"scripts/**",
|
|
11
|
+
"src/**",
|
|
12
|
+
"tests/**"
|
|
13
|
+
],
|
|
14
|
+
"schedule": [
|
|
15
|
+
"before 4am on monday"
|
|
16
|
+
],
|
|
17
|
+
"internalChecksFilter": "strict",
|
|
18
|
+
"rebaseWhen": "conflicted",
|
|
19
|
+
"labels": [
|
|
20
|
+
"dependencies",
|
|
21
|
+
"chore"
|
|
22
|
+
],
|
|
23
|
+
"vulnerabilityAlerts": {
|
|
24
|
+
"schedule": [
|
|
25
|
+
"at any time"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"packageRules": [
|
|
29
|
+
{
|
|
30
|
+
"description": "Require a package to be 2 weeks old before updating, but exclude vulnerability remediation from this wait.",
|
|
31
|
+
"matchUpdateTypes": [
|
|
32
|
+
"major",
|
|
33
|
+
"minor",
|
|
34
|
+
"patch",
|
|
35
|
+
"pin",
|
|
36
|
+
"digest"
|
|
37
|
+
],
|
|
38
|
+
"minimumReleaseAge": "2 weeks"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"description": "Group all python dev-dependencies (ruff, mypy, pytest) into one PR and automerge them.",
|
|
42
|
+
"matchFileNames": [
|
|
43
|
+
"pyproject.toml"
|
|
44
|
+
],
|
|
45
|
+
"matchDepTypes": [
|
|
46
|
+
"dependency-groups"
|
|
47
|
+
],
|
|
48
|
+
"groupName": "python-dev-tools",
|
|
49
|
+
"automerge": true
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"description": "Group GitHub Actions updates and automerge them.",
|
|
53
|
+
"matchManagers": [
|
|
54
|
+
"github-actions"
|
|
55
|
+
],
|
|
56
|
+
"groupName": "github-actions",
|
|
57
|
+
"automerge": true
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ "main" ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ "main" ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
name: Lint & Type Check
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
|
16
|
+
|
|
17
|
+
- name: Install uv
|
|
18
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
19
|
+
with:
|
|
20
|
+
enable-cache: true
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: uv sync --only-group ci --locked
|
|
25
|
+
|
|
26
|
+
- name: Run Ruff Linter
|
|
27
|
+
run: uv run ruff check --output-format=github .
|
|
28
|
+
|
|
29
|
+
- name: Run Ruff Formatter
|
|
30
|
+
run: uv run ruff format --check --output-format=github .
|
|
31
|
+
|
|
32
|
+
- name: Lint Markdown with rumdl
|
|
33
|
+
run: uv run rumdl check --output-format github .
|
|
34
|
+
|
|
35
|
+
- name: Check Markdown formatting with rumdl
|
|
36
|
+
run: uv run rumdl fmt --check --output-format github .
|
|
37
|
+
|
|
38
|
+
- name: Type check with Mypy
|
|
39
|
+
run: uv run mypy .
|
|
40
|
+
|
|
41
|
+
test:
|
|
42
|
+
name: Test on ${{ matrix.os }} / Python ${{ matrix.python-version }}
|
|
43
|
+
runs-on: ${{ matrix.os }}
|
|
44
|
+
strategy:
|
|
45
|
+
fail-fast: false
|
|
46
|
+
matrix:
|
|
47
|
+
os: [ubuntu-latest, macos-latest]
|
|
48
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
49
|
+
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
|
52
|
+
|
|
53
|
+
- name: Install uv
|
|
54
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
55
|
+
with:
|
|
56
|
+
enable-cache: true
|
|
57
|
+
python-version: ${{ matrix.python-version }}
|
|
58
|
+
|
|
59
|
+
- name: Install dependencies
|
|
60
|
+
run: |
|
|
61
|
+
uv sync --only-group ci --locked
|
|
62
|
+
uv pip install pytest-github-actions-annotate-failures
|
|
63
|
+
|
|
64
|
+
- name: Run tests
|
|
65
|
+
run: uv run pytest
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build-n-publish:
|
|
10
|
+
name: Build and publish to PyPI
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment: release
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
id-token: write
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
|
19
|
+
|
|
20
|
+
- name: Install uv
|
|
21
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.14"
|
|
24
|
+
|
|
25
|
+
- name: Build distribution
|
|
26
|
+
run: uv build
|
|
27
|
+
|
|
28
|
+
- name: Publish to PyPI
|
|
29
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
30
|
+
|
|
31
|
+
sync-homebrew:
|
|
32
|
+
name: Delegate Homebrew Update
|
|
33
|
+
needs: build-n-publish
|
|
34
|
+
uses: JacksonFergusonDev/ci-cd-tooling/.github/workflows/update-homebrew.yml@9300b4398eaedd7f3b369614433b38680e42ef02 # main
|
|
35
|
+
with:
|
|
36
|
+
tag: ${{ github.ref_name }}
|
|
37
|
+
package_name: "protostar"
|
|
38
|
+
formula_path: "Formula/protostar.rb"
|
|
39
|
+
secrets:
|
|
40
|
+
TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
default_install_hook_types:
|
|
2
|
+
- pre-commit
|
|
3
|
+
- commit-msg
|
|
4
|
+
- pre-push
|
|
5
|
+
|
|
6
|
+
default_stages:
|
|
7
|
+
- pre-commit
|
|
8
|
+
|
|
9
|
+
fail_fast: true
|
|
10
|
+
|
|
11
|
+
repos:
|
|
12
|
+
# Generic hooks (configured to IGNORE Python)
|
|
13
|
+
- repo: builtin
|
|
14
|
+
hooks:
|
|
15
|
+
- id: check-added-large-files
|
|
16
|
+
- id: check-merge-conflict
|
|
17
|
+
- id: check-case-conflict
|
|
18
|
+
- id: check-symlinks
|
|
19
|
+
- id: check-executables-have-shebangs
|
|
20
|
+
- id: trailing-whitespace
|
|
21
|
+
exclude: \.py$
|
|
22
|
+
- id: end-of-file-fixer
|
|
23
|
+
exclude: \.py$|\.gitkeep$
|
|
24
|
+
- id: check-yaml
|
|
25
|
+
- id: check-json
|
|
26
|
+
- id: check-toml
|
|
27
|
+
|
|
28
|
+
# Local Python + Markdown Toolchain (Managed via uv.lock)
|
|
29
|
+
- repo: local
|
|
30
|
+
hooks:
|
|
31
|
+
- id: uv-lock-check
|
|
32
|
+
name: uv lock check
|
|
33
|
+
entry: uv lock --check
|
|
34
|
+
language: system
|
|
35
|
+
pass_filenames: false
|
|
36
|
+
files: ^(pyproject\.toml|uv\.lock)$
|
|
37
|
+
|
|
38
|
+
- id: ruff-check
|
|
39
|
+
name: ruff check
|
|
40
|
+
entry: uv run ruff check --fix
|
|
41
|
+
language: system
|
|
42
|
+
types: [python]
|
|
43
|
+
exclude: ^docs/
|
|
44
|
+
require_serial: true
|
|
45
|
+
|
|
46
|
+
- id: ruff-format
|
|
47
|
+
name: ruff format
|
|
48
|
+
entry: uv run ruff format
|
|
49
|
+
language: system
|
|
50
|
+
types: [python]
|
|
51
|
+
exclude: ^docs/
|
|
52
|
+
require_serial: true
|
|
53
|
+
|
|
54
|
+
- id: mypy
|
|
55
|
+
name: mypy
|
|
56
|
+
entry: uv run mypy
|
|
57
|
+
language: system
|
|
58
|
+
types: [python]
|
|
59
|
+
exclude: ^docs/
|
|
60
|
+
require_serial: true
|
|
61
|
+
|
|
62
|
+
- id: rumdl-check
|
|
63
|
+
name: rumdl check
|
|
64
|
+
entry: uv run rumdl check --fix
|
|
65
|
+
language: system
|
|
66
|
+
types: [markdown]
|
|
67
|
+
require_serial: true
|
|
68
|
+
|
|
69
|
+
- id: rumdl-fmt
|
|
70
|
+
name: rumdl fmt
|
|
71
|
+
entry: uv run rumdl fmt
|
|
72
|
+
language: system
|
|
73
|
+
types: [markdown]
|
|
74
|
+
require_serial: true
|
|
75
|
+
|
|
76
|
+
- id: pytest-unit
|
|
77
|
+
name: pytest unit tests
|
|
78
|
+
entry: uv run pytest
|
|
79
|
+
language: system
|
|
80
|
+
pass_filenames: false
|
|
81
|
+
stages: [pre-push]
|
|
82
|
+
|
|
83
|
+
# Check for accidental commits of secrets
|
|
84
|
+
- repo: https://github.com/gitleaks/gitleaks
|
|
85
|
+
rev: v8.30.1
|
|
86
|
+
hooks:
|
|
87
|
+
- id: gitleaks
|
|
88
|
+
|
|
89
|
+
# Commit message validation
|
|
90
|
+
- repo: https://github.com/Goldziher/gitfluff
|
|
91
|
+
rev: v0.8.0
|
|
92
|
+
hooks:
|
|
93
|
+
- id: gitfluff-lint
|
|
94
|
+
args: [--write]
|
|
95
|
+
stages: [commit-msg]
|
|
96
|
+
|
|
97
|
+
# Renovate config validation
|
|
98
|
+
- repo: https://github.com/renovatebot/pre-commit-hooks
|
|
99
|
+
rev: 44.24.3
|
|
100
|
+
hooks:
|
|
101
|
+
- id: renovate-config-validator
|
|
102
|
+
files: '.github/renovate.json'
|
|
103
|
+
|
|
104
|
+
# GitHub Actions workflow validation
|
|
105
|
+
- repo: https://github.com/rhysd/actionlint
|
|
106
|
+
rev: v1.7.12
|
|
107
|
+
hooks:
|
|
108
|
+
- id: actionlint
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
9
|
+
nationality, personal appearance, race, caste, religion, or sexual identity
|
|
10
|
+
and orientation.
|
|
11
|
+
|
|
12
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
13
|
+
diverse, inclusive, and healthy community.
|
|
14
|
+
|
|
15
|
+
## Our Standards
|
|
16
|
+
|
|
17
|
+
Examples of behavior that contributes to a positive environment for our
|
|
18
|
+
community include:
|
|
19
|
+
|
|
20
|
+
- Demonstrating empathy and kindness toward other people
|
|
21
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
22
|
+
- Giving and gracefully accepting constructive feedback
|
|
23
|
+
- Accepting responsibility and apologizing to those affected by our mistakes,
|
|
24
|
+
and learning from the experience
|
|
25
|
+
- Focusing on what is best not just for us as individuals, but for the
|
|
26
|
+
overall community
|
|
27
|
+
|
|
28
|
+
## Enforcement
|
|
29
|
+
|
|
30
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
31
|
+
reported by contacting the project maintainer at **<jackson.ferguson0@gmail.com>**.
|
|
32
|
+
All complaints will be reviewed and
|
|
33
|
+
investigated promptly and fairly.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jackson Ferguson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: dark-matter-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A dependency-graph-aware storage profiler for Homebrew.
|
|
5
|
+
Project-URL: Repository, https://github.com/jacksonfergusondev/dark-matter
|
|
6
|
+
Project-URL: Issues, https://github.com/jacksonfergusondev/dark-matter/issues
|
|
7
|
+
Project-URL: PyPI, https://pypi.org/project/dark-matter-cli/
|
|
8
|
+
Author-email: Jackson Ferguson <jackson.ferguson0@gmail.com>
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 Jackson Ferguson
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
32
|
+
Classifier: Operating System :: MacOS
|
|
33
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
34
|
+
Classifier: Programming Language :: Python :: 3
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
38
|
+
Requires-Python: >=3.12
|
|
39
|
+
Requires-Dist: pandas>=3.0.3
|
|
40
|
+
Requires-Dist: requests>=2.34.0
|
|
41
|
+
Requires-Dist: rich>=15.0.0
|
|
42
|
+
Requires-Dist: typer>=0.25.1
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
<!-- rumdl-disable-file first-line-heading -->
|
|
46
|
+
<div align="center">
|
|
47
|
+
|
|
48
|
+
# Dark Matter
|
|
49
|
+
|
|
50
|
+
**A dependency-graph-aware storage profiler for Homebrew.**
|
|
51
|
+
|
|
52
|
+
[](https://github.com/JacksonFergusonDev/dark-matter/actions/workflows/ci.yml)
|
|
53
|
+
[](https://www.python.org/downloads/)
|
|
54
|
+
[](https://github.com/astral-sh/ruff)
|
|
55
|
+
[](https://mypy-lang.org/)
|
|
56
|
+
[](https://github.com/j178/prek)
|
|
57
|
+
[](LICENSE)
|
|
58
|
+
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
## Why
|
|
62
|
+
|
|
63
|
+
Homebrew flattens every dependency into a single `Cellar` directory. Tools like `du` or `ncdu` can tell you a formula takes up 500 MB, but they have no concept of *why* — whether that mass belongs to the formula itself or to a shared runtime pulled in by five other packages you installed for unrelated reasons.
|
|
64
|
+
|
|
65
|
+
Dark Matter reconstructs the dependency graph Homebrew already knows about and uses it to answer a more useful question: for each package you explicitly installed, how much disk space does it actually cost you, once shared dependencies are fairly split across everything that depends on them?
|
|
66
|
+
|
|
67
|
+
## How it works
|
|
68
|
+
|
|
69
|
+
Dark Matter parses Homebrew's own JSON metadata (via `brew info --json=v2` or its local API cache), rebuilds the dependency DAG, and walks it to compute two figures per package:
|
|
70
|
+
|
|
71
|
+
- **Core size** — the package's own on-disk footprint (or, in theoretical mode, its compressed bottle archive).
|
|
72
|
+
- **Weighted recursive size** — the core size plus a *fair share* of every transitive dependency, where each shared dependency's cost is divided evenly across all the packages that depend on it.
|
|
73
|
+
|
|
74
|
+
The ratio between the two — the **Bloat Ratio** — is the headline number. A low ratio means a package is mostly self-contained; a high ratio means most of its footprint belongs to shared infrastructure it happens to require.
|
|
75
|
+
|
|
76
|
+
## Features
|
|
77
|
+
|
|
78
|
+
- **Comprehensive analysis suite**
|
|
79
|
+
- `analyze` — measures what's actually on disk, using `brew info --json=v2 --installed` and direct filesystem traversal (`os.scandir`) for exact byte counts.
|
|
80
|
+
- `leaderboard` — a theoretical mode that ranks Homebrew's *entire* formula and cask catalog from the local API cache, without requiring anything to be installed.
|
|
81
|
+
- `inspect` & `compare` — targeted O(1) theoretical resolution for individual or grouped packages without resolving the entire ecosystem payload.
|
|
82
|
+
- `explain` — breaks down a target package's bloat by attributing fractional byte costs to each of its transitive dependencies.
|
|
83
|
+
- `export` — streams the underlying DataFrames to CSV or JSON for integration into external data pipelines.
|
|
84
|
+
- **Fractional Attribution Model** — shared dependencies (`openssl`, `python`, etc.) are divided proportionally across all parent packages instead of being double-counted, giving an honest per-package cost.
|
|
85
|
+
- **Daemon-free** — no background indexing, no persistent database. Every run is a fresh, on-demand computation.
|
|
86
|
+
- **Typed and tested** — fully type-annotated (strict `mypy`), linted with `ruff`, and covered by a `pytest` suite exercising the DAG traversal, fractional math, and network resolution logic. CI runs the full suite on macOS and Ubuntu across Python 3.12 and 3.14.
|
|
87
|
+
|
|
88
|
+
## A note on theoretical measurements
|
|
89
|
+
|
|
90
|
+
`leaderboard`, `inspect`, `compare`, and `explain` rely on `Content-Length` headers from `ghcr.io` blob storage, which report *compressed* archive size, not the size a package occupies once unpacked to disk. The absolute numbers they report will therefore run lower than `analyze`'s physical measurements.
|
|
91
|
+
|
|
92
|
+
The Bloat Ratio, however, stays meaningful. Since most bottles compress with similar algorithms (gzip or zstd), the compression factor $c$ appears in both the numerator and denominator and cancels out:
|
|
93
|
+
|
|
94
|
+
$$R \approx \frac{c \cdot m_{recursive}}{c \cdot m_{core}} \approx \frac{m_{recursive}}{m_{core}}$$
|
|
95
|
+
|
|
96
|
+
So while theoretical modes shouldn't be read as precise disk-space forecasts, they are a reliable way to evaluate relative bloat without installing anything.
|
|
97
|
+
|
|
98
|
+
## Installation
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
git clone https://github.com/jacksonfergusondev/dark-matter.git
|
|
102
|
+
cd dark-matter
|
|
103
|
+
uv tool install --editable .
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Usage
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Analyze what's actually installed
|
|
110
|
+
dark-matter analyze
|
|
111
|
+
|
|
112
|
+
# Rank the entire Homebrew catalog by theoretical bloat
|
|
113
|
+
dark-matter leaderboard
|
|
114
|
+
|
|
115
|
+
# Evaluate a specific formula instantly
|
|
116
|
+
dark-matter inspect uv
|
|
117
|
+
|
|
118
|
+
# Break down the dependency bloat of a specific package
|
|
119
|
+
dark-matter explain uv
|
|
120
|
+
|
|
121
|
+
# Compare multiple packages side-by-side
|
|
122
|
+
dark-matter compare uv poetry pdm
|
|
123
|
+
|
|
124
|
+
# Export the entire graph to JSON for external analysis
|
|
125
|
+
dark-matter export --format json > homebrew_bloat.json
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
All commands accept the global `--verbose` / `-v` flag for debug logging, and `--version` to print the installed version.
|
|
129
|
+
|
|
130
|
+
### `analyze`
|
|
131
|
+
|
|
132
|
+
| Flag | Default | Description |
|
|
133
|
+
| --- | --- | --- |
|
|
134
|
+
| `--sort` / `-s` | `ratio` | Sort by `ratio`, `core`, or `recursive` |
|
|
135
|
+
| `--top` / `-n` | `20` | Number of packages to display |
|
|
136
|
+
| `--fractional` / `--standard` | `--fractional` | Toggle the Fractional Attribution Model |
|
|
137
|
+
|
|
138
|
+
### `leaderboard`
|
|
139
|
+
|
|
140
|
+
| Flag | Default | Description |
|
|
141
|
+
| --- | --- | --- |
|
|
142
|
+
| `--sort` / `-s` | `ratio` | Sort by `ratio`, `core`, or `recursive` |
|
|
143
|
+
| `--top` / `-n` | `20` | Number of packages to display |
|
|
144
|
+
| `--arch` / `-a` | `arm64_tahoe` | Target bottle architecture |
|
|
145
|
+
|
|
146
|
+
### `inspect`
|
|
147
|
+
|
|
148
|
+
| Argument/Flag | Default | Description |
|
|
149
|
+
| --- | --- | --- |
|
|
150
|
+
| `[PACKAGE]` | **Required** | The target package to analyze |
|
|
151
|
+
| `--source` / `-s` | `installed` | Data source to compute: `installed` or `catalog` |
|
|
152
|
+
| `--arch` / `-a` | `arm64_tahoe` | Target bottle architecture |
|
|
153
|
+
|
|
154
|
+
### `compare`
|
|
155
|
+
|
|
156
|
+
| Argument/Flag | Default | Description |
|
|
157
|
+
| --- | --- | --- |
|
|
158
|
+
| `[PACKAGES]...` | **Required** | A space-separated list of packages to compare |
|
|
159
|
+
| `--sort` / `-s` | `ratio` | Sort by `ratio`, `core`, or `recursive` |
|
|
160
|
+
| `--source` / `-s` | `installed` | Data source to compute: `installed` or `catalog` |
|
|
161
|
+
| `--arch` / `-a` | `arm64_tahoe` | Target bottle architecture |
|
|
162
|
+
|
|
163
|
+
### `explain`
|
|
164
|
+
|
|
165
|
+
| Argument/Flag | Default | Description |
|
|
166
|
+
| --- | --- | --- |
|
|
167
|
+
| `[PACKAGE]` | **Required** | The specific package to analyze |
|
|
168
|
+
| `--source` / `-s` | `installed` | Data source to compute: `installed` or `catalog` |
|
|
169
|
+
| `--arch` / `-a` | `arm64_tahoe` | Target bottle architecture |
|
|
170
|
+
|
|
171
|
+
### `export`
|
|
172
|
+
|
|
173
|
+
| Flag | Default | Description |
|
|
174
|
+
| --- | --- | --- |
|
|
175
|
+
| `--source` / `-s` | `installed` | Data source to compute: `installed` or `catalog` |
|
|
176
|
+
| `--format` / `-f` | `csv` | Output format: `csv` or `json` |
|
|
177
|
+
| `--arch` / `-a` | `arm64_tahoe` | Target bottle architecture (for `catalog` source) |
|
|
178
|
+
|
|
179
|
+
## Development
|
|
180
|
+
|
|
181
|
+
The project uses [`just`](https://github.com/casey/just) to wrap common tasks:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
just format # ruff format + fix
|
|
185
|
+
just lint # ruff + rumdl
|
|
186
|
+
just typecheck # mypy
|
|
187
|
+
just test # pytest
|
|
188
|
+
just test-cov # pytest with coverage report
|
|
189
|
+
just ci # the full pipeline CI runs, locally
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## 📧 Contact
|
|
193
|
+
|
|
194
|
+
[](https://github.com/JacksonFergusonDev)
|
|
195
|
+
[](https://www.linkedin.com/in/jackson--ferguson/)
|
|
196
|
+
[](mailto:jackson.ferguson0@gmail.com)
|
|
197
|
+
|
|
198
|
+
## 📄 License
|
|
199
|
+
|
|
200
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|