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.
- lsdisk-0.1.1/LICENSE +21 -0
- lsdisk-0.1.1/PKG-INFO +173 -0
- lsdisk-0.1.1/README.md +163 -0
- lsdisk-0.1.1/pyproject.toml +22 -0
- lsdisk-0.1.1/setup.cfg +4 -0
- lsdisk-0.1.1/src/lsdisk/__init__.py +3 -0
- lsdisk-0.1.1/src/lsdisk/analyzers/__init__.py +0 -0
- lsdisk-0.1.1/src/lsdisk/analyzers/capacity.py +64 -0
- lsdisk-0.1.1/src/lsdisk/analyzers/filesystems.py +116 -0
- lsdisk-0.1.1/src/lsdisk/collectors/__init__.py +0 -0
- lsdisk-0.1.1/src/lsdisk/collectors/block_devices.py +123 -0
- lsdisk-0.1.1/src/lsdisk/collectors/filesystems.py +89 -0
- lsdisk-0.1.1/src/lsdisk/inventory.py +79 -0
- lsdisk-0.1.1/src/lsdisk/main.py +128 -0
- lsdisk-0.1.1/src/lsdisk/models.py +78 -0
- lsdisk-0.1.1/src/lsdisk/serialization.py +101 -0
- lsdisk-0.1.1/src/lsdisk/ui/__init__.py +0 -0
- lsdisk-0.1.1/src/lsdisk/ui/terminal.py +643 -0
- lsdisk-0.1.1/src/lsdisk.egg-info/PKG-INFO +173 -0
- lsdisk-0.1.1/src/lsdisk.egg-info/SOURCES.txt +31 -0
- lsdisk-0.1.1/src/lsdisk.egg-info/dependency_links.txt +1 -0
- lsdisk-0.1.1/src/lsdisk.egg-info/entry_points.txt +2 -0
- lsdisk-0.1.1/src/lsdisk.egg-info/requires.txt +1 -0
- lsdisk-0.1.1/src/lsdisk.egg-info/top_level.txt +1 -0
- lsdisk-0.1.1/tests/test_block_devices.py +109 -0
- lsdisk-0.1.1/tests/test_capacity.py +45 -0
- lsdisk-0.1.1/tests/test_cli.py +91 -0
- lsdisk-0.1.1/tests/test_cli_options.py +28 -0
- lsdisk-0.1.1/tests/test_filesystem_analyzer.py +105 -0
- lsdisk-0.1.1/tests/test_filesystems.py +93 -0
- lsdisk-0.1.1/tests/test_models.py +85 -0
- lsdisk-0.1.1/tests/test_serialization.py +128 -0
- 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
|
+

|
|
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
|
+

|
|
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
|
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
|