lsdisk 0.1.1__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.
Files changed (33) hide show
  1. lsdisk-0.1.1/LICENSE +21 -0
  2. lsdisk-0.1.1/PKG-INFO +173 -0
  3. lsdisk-0.1.1/README.md +163 -0
  4. lsdisk-0.1.1/pyproject.toml +22 -0
  5. lsdisk-0.1.1/setup.cfg +4 -0
  6. lsdisk-0.1.1/src/lsdisk/__init__.py +3 -0
  7. lsdisk-0.1.1/src/lsdisk/analyzers/__init__.py +0 -0
  8. lsdisk-0.1.1/src/lsdisk/analyzers/capacity.py +64 -0
  9. lsdisk-0.1.1/src/lsdisk/analyzers/filesystems.py +116 -0
  10. lsdisk-0.1.1/src/lsdisk/collectors/__init__.py +0 -0
  11. lsdisk-0.1.1/src/lsdisk/collectors/block_devices.py +123 -0
  12. lsdisk-0.1.1/src/lsdisk/collectors/filesystems.py +89 -0
  13. lsdisk-0.1.1/src/lsdisk/inventory.py +79 -0
  14. lsdisk-0.1.1/src/lsdisk/main.py +128 -0
  15. lsdisk-0.1.1/src/lsdisk/models.py +78 -0
  16. lsdisk-0.1.1/src/lsdisk/serialization.py +101 -0
  17. lsdisk-0.1.1/src/lsdisk/ui/__init__.py +0 -0
  18. lsdisk-0.1.1/src/lsdisk/ui/terminal.py +643 -0
  19. lsdisk-0.1.1/src/lsdisk.egg-info/PKG-INFO +173 -0
  20. lsdisk-0.1.1/src/lsdisk.egg-info/SOURCES.txt +31 -0
  21. lsdisk-0.1.1/src/lsdisk.egg-info/dependency_links.txt +1 -0
  22. lsdisk-0.1.1/src/lsdisk.egg-info/entry_points.txt +2 -0
  23. lsdisk-0.1.1/src/lsdisk.egg-info/requires.txt +1 -0
  24. lsdisk-0.1.1/src/lsdisk.egg-info/top_level.txt +1 -0
  25. lsdisk-0.1.1/tests/test_block_devices.py +109 -0
  26. lsdisk-0.1.1/tests/test_capacity.py +45 -0
  27. lsdisk-0.1.1/tests/test_cli.py +91 -0
  28. lsdisk-0.1.1/tests/test_cli_options.py +28 -0
  29. lsdisk-0.1.1/tests/test_filesystem_analyzer.py +105 -0
  30. lsdisk-0.1.1/tests/test_filesystems.py +93 -0
  31. lsdisk-0.1.1/tests/test_models.py +85 -0
  32. lsdisk-0.1.1/tests/test_serialization.py +128 -0
  33. lsdisk-0.1.1/tests/test_terminal.py +123 -0
lsdisk-0.1.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SammMartins
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.
lsdisk-0.1.1/PKG-INFO ADDED
@@ -0,0 +1,173 @@
1
+ Metadata-Version: 2.4
2
+ Name: lsdisk
3
+ Version: 0.1.1
4
+ Summary: Cross-distro Linux Storage Explorer
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: rich>=13.0
9
+ Dynamic: license-file
10
+
11
+ <div align="center">
12
+
13
+ <img src="img/lsdisk.png" alt="lsdisk — Linux Storage Explorer" width="760">
14
+
15
+ <p><strong>Cross-distro Linux Storage Explorer</strong></p>
16
+ <p>Understand your disks, partitions, and filesystems — clearly, safely, and from the terminal.</p>
17
+
18
+ </div>
19
+
20
+ <div align="center">
21
+
22
+ <p>
23
+ <a href="https://github.com/SammMartins/lsdisk/releases/latest"><img src="https://img.shields.io/github/v/release/SammMartins/lsdisk?color=blue" alt="Latest Release"></a>
24
+ <a href="https://github.com/SammMartins/lsdisk/blob/main/LICENSE"><img src="https://img.shields.io/github/license/SammMartins/lsdisk?color=green" alt="License"></a>
25
+ <a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.8%2B-blue?logo=python&logoColor=white" alt="Python"></a>
26
+ <a href="https://www.kernel.org/"><img src="https://img.shields.io/badge/platform-linux-lightgrey?logo=linux&logoColor=white" alt="Platform"></a>
27
+ <a href="https://github.com/SammMartins/lsdisk/stargazers"><img src="https://img.shields.io/github/stars/SammMartins/lsdisk?color=yellow" alt="GitHub Stars"></a>
28
+ </p>
29
+
30
+ </div>
31
+
32
+ ---
33
+
34
+ ## About lsdisk
35
+
36
+ **lsdisk** is a Linux storage inspection tool designed to make information about HDDs, SSDs, partitions, and filesystems easier to understand.
37
+
38
+ It brings storage topology and filesystem capacity information together in a structured terminal interface. lsdisk is read-only: it inspects storage and does not format, partition, mount, or modify filesystems.
39
+
40
+ <br>
41
+
42
+ ![lsdisk Demo](./img/lsdisk_0_1_1.gif)
43
+
44
+ <p><sub><em>Live demonstration of lsdisk v0.1.1 inspecting Linux storage devices in the terminal.</em></sub></p>
45
+
46
+ ## Features
47
+
48
+ - **Physical storage inventory** — show detected disks and their child partitions in a hierarchical view.
49
+ - **Device details** — display device names, capacity, model, physical/virtual classification, and HDD or SSD/Flash indicators when the system provides enough information.
50
+ - **Filesystem capacity** — report total, used, free, and user-available capacity for accessible mounted filesystems.
51
+ - **Mountpoint visibility** — associate filesystem information with mountpoints where the relationship can be established.
52
+ - **Filesystem grouping** — group related filesystem records to avoid repeating capacity for multiple mountpoints, including supported Btrfs subvolume cases.
53
+ - **Utilization bars** — display a compact visual usage bar and percentage in the terminal. The filled bar and percentage use utilization colors: green below 70%, yellow from 70% to below 90%, and red at 90% or above.
54
+ - **Multiple output modes** — provide a compact default view, expanded output, table output, and JSON output.
55
+ - **Graceful handling of missing data** — distinguish unavailable information from a confirmed zero value.
56
+
57
+ Capacity values depend on the information available from the running Linux system. Physical disk capacity and mounted filesystem capacity describe different layers and should not be treated as interchangeable.
58
+
59
+ ## Design principles
60
+
61
+ | Principle | What it means |
62
+ |---|---|
63
+ | **Read-only inspection** | Do not modify disks, partitions, or filesystems. |
64
+ | **Modular architecture** | Keep data collection, analysis, serialization, and presentation separated. |
65
+ | **Portability** | Avoid unnecessary dependencies on a specific Linux distribution. |
66
+ | **Transparency** | Distinguish confirmed values from estimates or unavailable data. |
67
+ | **Testability** | Validate calculations and behavior with automated tests. |
68
+
69
+ ## Technology
70
+
71
+ - **Python** — application logic.
72
+ - **Rich** — terminal presentation and colored utilization bars.
73
+ - **Python standard library** — core APIs and supporting functionality.
74
+ - **Linux interfaces**, including `/sys` and `/proc`, where appropriate.
75
+ - **`os.statvfs()`** — mounted filesystem capacity statistics.
76
+ - **`unittest`** — automated testing.
77
+
78
+ ## Requirements
79
+
80
+ - Linux
81
+ - Python 3.11 or newer
82
+ - `curl` and `tar` for the shell installer
83
+
84
+ The installer creates an isolated Python virtual environment and installs the Python dependencies. Some storage information may depend on available system interfaces, permissions, and the storage configuration.
85
+
86
+ ## Installation
87
+
88
+ The installation script downloads lsdisk, creates an isolated Python virtual environment, and installs the `lsdisk` command for the current user:
89
+
90
+ ```bash
91
+ curl -sSL https://raw.githubusercontent.com/SammMartins/lsdisk/main/install.sh | bash
92
+ ```
93
+
94
+ The installer does not require `sudo` and refuses to run as root. By default, it stores application data in `~/.local/share/lsdisk` and the executable in `~/.local/bin`. If `~/.local/bin` is not in your `PATH`, follow the instruction printed by the installer.
95
+
96
+ Run lsdisk:
97
+
98
+ ```bash
99
+ lsdisk
100
+ ```
101
+
102
+ Show available options:
103
+
104
+ ```bash
105
+ lsdisk --help
106
+ ```
107
+
108
+ To install from a different branch, set `LSDISK_BRANCH` before running the installer:
109
+
110
+ ```bash
111
+ curl -sSL https://raw.githubusercontent.com/SammMartins/lsdisk/main/install.sh | LSDISK_BRANCH=main bash
112
+ ```
113
+
114
+ ## Uninstallation
115
+
116
+ If `uninstall.sh` is available locally, run it as your regular user, without `sudo`:
117
+
118
+ ```bash
119
+ bash uninstall.sh
120
+ ```
121
+
122
+ The uninstaller removes the per-user launcher and application data directory. It does not delete the local Git repository or project source files.
123
+
124
+ ## Usage
125
+
126
+ ```bash
127
+ lsdisk
128
+ lsdisk --all
129
+ lsdisk --table-mode
130
+ lsdisk --json
131
+ lsdisk --help
132
+ ```
133
+
134
+ - `lsdisk` displays the default compact storage view.
135
+ - `lsdisk --all` displays expanded inventory details, including additional devices and mount information.
136
+ - `lsdisk --table-mode` selects table output.
137
+ - `lsdisk --json` emits machine-readable JSON without terminal UI formatting.
138
+ - `lsdisk --help` lists the options supported by the installed version.
139
+
140
+ Use the output of `lsdisk --help` as the source of truth for the options available in a specific release.
141
+
142
+ ## Development status
143
+
144
+ **lsdisk is in early development.** Features and interfaces may change as the project evolves. The current implementation focuses on block-device topology and capacity information for mounted filesystems.
145
+
146
+ ### Roadmap
147
+
148
+ - [ ] Identify filesystem types on unmounted partitions without mounting them.
149
+ - [ ] Collect filesystem labels and UUIDs more completely.
150
+ - [ ] Improve identification of partitions whose filesystem information is unavailable.
151
+ - [ ] Expand validated handling of Btrfs, LVM, RAID, LUKS, and other storage layers.
152
+
153
+ These items are planned improvements, not guarantees of the current implementation.
154
+
155
+ ## Project documentation
156
+
157
+ - [Architecture](docs/ARCHITECTURE.md)
158
+ - [Development guide](docs/DEVELOPMENT.md)
159
+ - [Changelog](CHANGELOG.md)
160
+
161
+ ## Safety scope
162
+
163
+ lsdisk is intended for **storage inspection only**. Formatting, partitioning, filesystem modification, and automatic mounting are outside the project's scope.
164
+
165
+ ## License
166
+
167
+ lsdisk is distributed under the [MIT License](LICENSE).
168
+
169
+ ---
170
+
171
+ <div align="center">
172
+ <sub>lsdisk — making Linux storage easier to explore.</sub>
173
+ </div>
lsdisk-0.1.1/README.md ADDED
@@ -0,0 +1,163 @@
1
+ <div align="center">
2
+
3
+ <img src="img/lsdisk.png" alt="lsdisk — Linux Storage Explorer" width="760">
4
+
5
+ <p><strong>Cross-distro Linux Storage Explorer</strong></p>
6
+ <p>Understand your disks, partitions, and filesystems — clearly, safely, and from the terminal.</p>
7
+
8
+ </div>
9
+
10
+ <div align="center">
11
+
12
+ <p>
13
+ <a href="https://github.com/SammMartins/lsdisk/releases/latest"><img src="https://img.shields.io/github/v/release/SammMartins/lsdisk?color=blue" alt="Latest Release"></a>
14
+ <a href="https://github.com/SammMartins/lsdisk/blob/main/LICENSE"><img src="https://img.shields.io/github/license/SammMartins/lsdisk?color=green" alt="License"></a>
15
+ <a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.8%2B-blue?logo=python&logoColor=white" alt="Python"></a>
16
+ <a href="https://www.kernel.org/"><img src="https://img.shields.io/badge/platform-linux-lightgrey?logo=linux&logoColor=white" alt="Platform"></a>
17
+ <a href="https://github.com/SammMartins/lsdisk/stargazers"><img src="https://img.shields.io/github/stars/SammMartins/lsdisk?color=yellow" alt="GitHub Stars"></a>
18
+ </p>
19
+
20
+ </div>
21
+
22
+ ---
23
+
24
+ ## About lsdisk
25
+
26
+ **lsdisk** is a Linux storage inspection tool designed to make information about HDDs, SSDs, partitions, and filesystems easier to understand.
27
+
28
+ It brings storage topology and filesystem capacity information together in a structured terminal interface. lsdisk is read-only: it inspects storage and does not format, partition, mount, or modify filesystems.
29
+
30
+ <br>
31
+
32
+ ![lsdisk Demo](./img/lsdisk_0_1_1.gif)
33
+
34
+ <p><sub><em>Live demonstration of lsdisk v0.1.1 inspecting Linux storage devices in the terminal.</em></sub></p>
35
+
36
+ ## Features
37
+
38
+ - **Physical storage inventory** — show detected disks and their child partitions in a hierarchical view.
39
+ - **Device details** — display device names, capacity, model, physical/virtual classification, and HDD or SSD/Flash indicators when the system provides enough information.
40
+ - **Filesystem capacity** — report total, used, free, and user-available capacity for accessible mounted filesystems.
41
+ - **Mountpoint visibility** — associate filesystem information with mountpoints where the relationship can be established.
42
+ - **Filesystem grouping** — group related filesystem records to avoid repeating capacity for multiple mountpoints, including supported Btrfs subvolume cases.
43
+ - **Utilization bars** — display a compact visual usage bar and percentage in the terminal. The filled bar and percentage use utilization colors: green below 70%, yellow from 70% to below 90%, and red at 90% or above.
44
+ - **Multiple output modes** — provide a compact default view, expanded output, table output, and JSON output.
45
+ - **Graceful handling of missing data** — distinguish unavailable information from a confirmed zero value.
46
+
47
+ Capacity values depend on the information available from the running Linux system. Physical disk capacity and mounted filesystem capacity describe different layers and should not be treated as interchangeable.
48
+
49
+ ## Design principles
50
+
51
+ | Principle | What it means |
52
+ |---|---|
53
+ | **Read-only inspection** | Do not modify disks, partitions, or filesystems. |
54
+ | **Modular architecture** | Keep data collection, analysis, serialization, and presentation separated. |
55
+ | **Portability** | Avoid unnecessary dependencies on a specific Linux distribution. |
56
+ | **Transparency** | Distinguish confirmed values from estimates or unavailable data. |
57
+ | **Testability** | Validate calculations and behavior with automated tests. |
58
+
59
+ ## Technology
60
+
61
+ - **Python** — application logic.
62
+ - **Rich** — terminal presentation and colored utilization bars.
63
+ - **Python standard library** — core APIs and supporting functionality.
64
+ - **Linux interfaces**, including `/sys` and `/proc`, where appropriate.
65
+ - **`os.statvfs()`** — mounted filesystem capacity statistics.
66
+ - **`unittest`** — automated testing.
67
+
68
+ ## Requirements
69
+
70
+ - Linux
71
+ - Python 3.11 or newer
72
+ - `curl` and `tar` for the shell installer
73
+
74
+ The installer creates an isolated Python virtual environment and installs the Python dependencies. Some storage information may depend on available system interfaces, permissions, and the storage configuration.
75
+
76
+ ## Installation
77
+
78
+ The installation script downloads lsdisk, creates an isolated Python virtual environment, and installs the `lsdisk` command for the current user:
79
+
80
+ ```bash
81
+ curl -sSL https://raw.githubusercontent.com/SammMartins/lsdisk/main/install.sh | bash
82
+ ```
83
+
84
+ The installer does not require `sudo` and refuses to run as root. By default, it stores application data in `~/.local/share/lsdisk` and the executable in `~/.local/bin`. If `~/.local/bin` is not in your `PATH`, follow the instruction printed by the installer.
85
+
86
+ Run lsdisk:
87
+
88
+ ```bash
89
+ lsdisk
90
+ ```
91
+
92
+ Show available options:
93
+
94
+ ```bash
95
+ lsdisk --help
96
+ ```
97
+
98
+ To install from a different branch, set `LSDISK_BRANCH` before running the installer:
99
+
100
+ ```bash
101
+ curl -sSL https://raw.githubusercontent.com/SammMartins/lsdisk/main/install.sh | LSDISK_BRANCH=main bash
102
+ ```
103
+
104
+ ## Uninstallation
105
+
106
+ If `uninstall.sh` is available locally, run it as your regular user, without `sudo`:
107
+
108
+ ```bash
109
+ bash uninstall.sh
110
+ ```
111
+
112
+ The uninstaller removes the per-user launcher and application data directory. It does not delete the local Git repository or project source files.
113
+
114
+ ## Usage
115
+
116
+ ```bash
117
+ lsdisk
118
+ lsdisk --all
119
+ lsdisk --table-mode
120
+ lsdisk --json
121
+ lsdisk --help
122
+ ```
123
+
124
+ - `lsdisk` displays the default compact storage view.
125
+ - `lsdisk --all` displays expanded inventory details, including additional devices and mount information.
126
+ - `lsdisk --table-mode` selects table output.
127
+ - `lsdisk --json` emits machine-readable JSON without terminal UI formatting.
128
+ - `lsdisk --help` lists the options supported by the installed version.
129
+
130
+ Use the output of `lsdisk --help` as the source of truth for the options available in a specific release.
131
+
132
+ ## Development status
133
+
134
+ **lsdisk is in early development.** Features and interfaces may change as the project evolves. The current implementation focuses on block-device topology and capacity information for mounted filesystems.
135
+
136
+ ### Roadmap
137
+
138
+ - [ ] Identify filesystem types on unmounted partitions without mounting them.
139
+ - [ ] Collect filesystem labels and UUIDs more completely.
140
+ - [ ] Improve identification of partitions whose filesystem information is unavailable.
141
+ - [ ] Expand validated handling of Btrfs, LVM, RAID, LUKS, and other storage layers.
142
+
143
+ These items are planned improvements, not guarantees of the current implementation.
144
+
145
+ ## Project documentation
146
+
147
+ - [Architecture](docs/ARCHITECTURE.md)
148
+ - [Development guide](docs/DEVELOPMENT.md)
149
+ - [Changelog](CHANGELOG.md)
150
+
151
+ ## Safety scope
152
+
153
+ lsdisk is intended for **storage inspection only**. Formatting, partitioning, filesystem modification, and automatic mounting are outside the project's scope.
154
+
155
+ ## License
156
+
157
+ lsdisk is distributed under the [MIT License](LICENSE).
158
+
159
+ ---
160
+
161
+ <div align="center">
162
+ <sub>lsdisk — making Linux storage easier to explore.</sub>
163
+ </div>
@@ -0,0 +1,22 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "lsdisk"
7
+ version = "0.1.1"
8
+ description = "Cross-distro Linux Storage Explorer"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ dependencies = [
12
+ "rich>=13.0",
13
+ ]
14
+
15
+ [project.scripts]
16
+ lsdisk = "lsdisk.main:main"
17
+
18
+ [tool.setuptools]
19
+ package-dir = {"" = "src"}
20
+
21
+ [tool.setuptools.packages.find]
22
+ where = ["src"]
lsdisk-0.1.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """lsdisk: Cross-distro Linux Storage Explorer."""
2
+
3
+ __version__ = "0.1.0"
File without changes
@@ -0,0 +1,64 @@
1
+ """Capacity calculations for lsdisk."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass(frozen=True)
7
+ class Capacity:
8
+ """Represent a capacity measurement in bytes."""
9
+
10
+ total_bytes: int
11
+ available_bytes: int
12
+
13
+ def __post_init__(self) -> None:
14
+ if self.total_bytes < 0:
15
+ raise ValueError("Total capacity cannot be negative.")
16
+
17
+ if self.available_bytes < 0:
18
+ raise ValueError("Available space cannot be negative.")
19
+
20
+ if self.available_bytes > self.total_bytes:
21
+ raise ValueError(
22
+ "Available space cannot exceed total capacity."
23
+ )
24
+
25
+ @property
26
+ def used_bytes(self) -> int:
27
+ """Calculate used space in bytes."""
28
+ return self.total_bytes - self.available_bytes
29
+
30
+ @property
31
+ def used_percent(self) -> float:
32
+ """Calculate the percentage used, from 0 to 100."""
33
+ if self.total_bytes == 0:
34
+ return 0.0
35
+
36
+ return self.used_bytes / self.total_bytes * 100
37
+
38
+ @property
39
+ def available_percent(self) -> float:
40
+ """Calculate the percentage available, from 0 to 100."""
41
+ if self.total_bytes == 0:
42
+ return 0.0
43
+
44
+ return self.available_bytes / self.total_bytes * 100
45
+
46
+
47
+ def format_bytes(size_bytes: int) -> str:
48
+ """Format bytes using binary units (KiB, MiB, GiB, and TiB)."""
49
+ if size_bytes < 0:
50
+ raise ValueError("Size cannot be negative.")
51
+
52
+ value = float(size_bytes)
53
+ units = ("B", "KiB", "MiB", "GiB", "TiB", "PiB")
54
+
55
+ for unit in units:
56
+ if value < 1024 or unit == units[-1]:
57
+ if unit == "B":
58
+ return f"{int(value)} B"
59
+
60
+ return f"{value:.2f} {unit}"
61
+
62
+ value /= 1024
63
+
64
+ raise AssertionError("Size unit not found.")
@@ -0,0 +1,116 @@
1
+ """Classification and grouping of mounted filesystems."""
2
+
3
+ from dataclasses import dataclass, field
4
+
5
+ from lsdisk.models import FilesystemUsage
6
+
7
+
8
+ VIRTUAL_FILESYSTEMS = {
9
+ "autofs",
10
+ "bpf",
11
+ "cgroup",
12
+ "cgroup2",
13
+ "configfs",
14
+ "debugfs",
15
+ "devpts",
16
+ "devtmpfs",
17
+ "efivarfs",
18
+ "fusectl",
19
+ "hugetlbfs",
20
+ "mqueue",
21
+ "proc",
22
+ "pstore",
23
+ "securityfs",
24
+ "sysfs",
25
+ "tmpfs",
26
+ "tracefs",
27
+ }
28
+
29
+ NETWORK_FILESYSTEMS = {
30
+ "9p",
31
+ "ceph",
32
+ "cifs",
33
+ "glusterfs",
34
+ "nfs",
35
+ "nfs4",
36
+ "smb3",
37
+ "sshfs",
38
+ }
39
+
40
+ PERSISTENT_FILESYSTEMS = {
41
+ "btrfs",
42
+ "exfat",
43
+ "ext2",
44
+ "ext3",
45
+ "ext4",
46
+ "f2fs",
47
+ "jfs",
48
+ "ntfs",
49
+ "ntfs3",
50
+ "reiserfs",
51
+ "udf",
52
+ "vfat",
53
+ "xfs",
54
+ "zfs",
55
+ }
56
+
57
+
58
+ @dataclass
59
+ class FilesystemGroup:
60
+ """Represent one filesystem with its associated mountpoints."""
61
+
62
+ representative: FilesystemUsage
63
+ mountpoints: list[str] = field(default_factory=list)
64
+
65
+ @property
66
+ def total_bytes(self) -> int:
67
+ return self.representative.total_bytes
68
+
69
+ @property
70
+ def used_bytes(self) -> int:
71
+ return self.representative.used_bytes
72
+
73
+ @property
74
+ def available_bytes(self) -> int:
75
+ return self.representative.available_bytes
76
+
77
+
78
+ def classify_filesystem(filesystem: FilesystemUsage) -> str:
79
+ """Classify a filesystem without hiding unrecognized types."""
80
+ filesystem_type = filesystem.filesystem_type.lower()
81
+
82
+ if filesystem_type in VIRTUAL_FILESYSTEMS:
83
+ return "virtual"
84
+
85
+ if filesystem_type in NETWORK_FILESYSTEMS:
86
+ return "network"
87
+
88
+ if filesystem_type in PERSISTENT_FILESYSTEMS:
89
+ return "persistent"
90
+
91
+ return "unknown"
92
+
93
+
94
+ def group_filesystems(
95
+ filesystems: list[FilesystemUsage],
96
+ ) -> list[FilesystemGroup]:
97
+ """Group mounts that share the same filesystem identity."""
98
+ groups: dict[tuple[str, str, str], FilesystemGroup] = {}
99
+
100
+ for filesystem in filesystems:
101
+ identity = (
102
+ filesystem.device_id or filesystem.source,
103
+ filesystem.filesystem_type,
104
+ filesystem.source,
105
+ )
106
+
107
+ group = groups.get(identity)
108
+
109
+ if group is None:
110
+ group = FilesystemGroup(representative=filesystem)
111
+ groups[identity] = group
112
+
113
+ if filesystem.mountpoint not in group.mountpoints:
114
+ group.mountpoints.append(filesystem.mountpoint)
115
+
116
+ return list(groups.values())
File without changes