nibble-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.
- nibble_cli-0.1.0/PKG-INFO +23 -0
- nibble_cli-0.1.0/nibble_cli.egg-info/PKG-INFO +23 -0
- nibble_cli-0.1.0/nibble_cli.egg-info/SOURCES.txt +7 -0
- nibble_cli-0.1.0/nibble_cli.egg-info/dependency_links.txt +1 -0
- nibble_cli-0.1.0/nibble_cli.egg-info/entry_points.txt +2 -0
- nibble_cli-0.1.0/nibble_cli.egg-info/top_level.txt +1 -0
- nibble_cli-0.1.0/nibble_installer.py +152 -0
- nibble_cli-0.1.0/setup.cfg +4 -0
- nibble_cli-0.1.0/setup.py +43 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nibble-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Fast local network scanner with hardware identification and a terminal UI
|
|
5
|
+
Home-page: https://github.com/saberd/nibble
|
|
6
|
+
Author: saberd
|
|
7
|
+
Author-email: your-email@example.com
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: System Administrators
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: System :: Networking
|
|
15
|
+
Requires-Python: >=3.6
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: author-email
|
|
19
|
+
Dynamic: classifier
|
|
20
|
+
Dynamic: description-content-type
|
|
21
|
+
Dynamic: home-page
|
|
22
|
+
Dynamic: requires-python
|
|
23
|
+
Dynamic: summary
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nibble-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Fast local network scanner with hardware identification and a terminal UI
|
|
5
|
+
Home-page: https://github.com/saberd/nibble
|
|
6
|
+
Author: saberd
|
|
7
|
+
Author-email: your-email@example.com
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: System Administrators
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: System :: Networking
|
|
15
|
+
Requires-Python: >=3.6
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: author-email
|
|
19
|
+
Dynamic: classifier
|
|
20
|
+
Dynamic: description-content-type
|
|
21
|
+
Dynamic: home-page
|
|
22
|
+
Dynamic: requires-python
|
|
23
|
+
Dynamic: summary
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nibble_installer
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Nibble CLI wrapper for pip.
|
|
4
|
+
Downloads the matching GitHub Release binary and executes it.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import platform
|
|
9
|
+
import shutil
|
|
10
|
+
import subprocess
|
|
11
|
+
import sys
|
|
12
|
+
import tarfile
|
|
13
|
+
import tempfile
|
|
14
|
+
import urllib.error
|
|
15
|
+
import urllib.request
|
|
16
|
+
import zipfile
|
|
17
|
+
from importlib import metadata
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
REPO = "saberd/nibble"
|
|
21
|
+
PROJECT = "nibble"
|
|
22
|
+
DIST_NAME = "nibble-cli"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _platform_triplet():
|
|
26
|
+
system = platform.system().lower()
|
|
27
|
+
machine = platform.machine().lower()
|
|
28
|
+
|
|
29
|
+
os_map = {
|
|
30
|
+
"linux": "linux",
|
|
31
|
+
"darwin": "darwin",
|
|
32
|
+
"windows": "windows",
|
|
33
|
+
}
|
|
34
|
+
arch_map = {
|
|
35
|
+
"x86_64": "amd64",
|
|
36
|
+
"amd64": "amd64",
|
|
37
|
+
"aarch64": "arm64",
|
|
38
|
+
"arm64": "arm64",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
os_name = os_map.get(system)
|
|
42
|
+
arch = arch_map.get(machine)
|
|
43
|
+
if not os_name or not arch:
|
|
44
|
+
raise RuntimeError(f"unsupported platform: system={system}, arch={machine}")
|
|
45
|
+
return os_name, arch
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _install_dir():
|
|
49
|
+
if os.name == "nt":
|
|
50
|
+
base = Path(os.environ.get("LOCALAPPDATA", str(Path.home())))
|
|
51
|
+
else:
|
|
52
|
+
base = Path.home() / ".local" / "share"
|
|
53
|
+
path = base / PROJECT
|
|
54
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
55
|
+
return path
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _dist_version():
|
|
59
|
+
version = metadata.version(DIST_NAME)
|
|
60
|
+
return version[1:] if version.startswith("v") else version
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _binary_name():
|
|
64
|
+
return f"{PROJECT}.exe" if os.name == "nt" else PROJECT
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _download_asset(url, out_path):
|
|
68
|
+
try:
|
|
69
|
+
with urllib.request.urlopen(url) as resp, open(out_path, "wb") as f:
|
|
70
|
+
shutil.copyfileobj(resp, f)
|
|
71
|
+
return True
|
|
72
|
+
except urllib.error.HTTPError as e:
|
|
73
|
+
if e.code == 404:
|
|
74
|
+
return False
|
|
75
|
+
raise
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _extract_binary(archive_path, dest_binary):
|
|
79
|
+
bin_names = {_binary_name(), PROJECT, f"{PROJECT}.exe"}
|
|
80
|
+
|
|
81
|
+
if str(archive_path).endswith(".zip"):
|
|
82
|
+
with zipfile.ZipFile(archive_path, "r") as zf:
|
|
83
|
+
for member in zf.namelist():
|
|
84
|
+
name = Path(member).name
|
|
85
|
+
if name in bin_names:
|
|
86
|
+
with zf.open(member) as src, open(dest_binary, "wb") as dst:
|
|
87
|
+
shutil.copyfileobj(src, dst)
|
|
88
|
+
return
|
|
89
|
+
else:
|
|
90
|
+
with tarfile.open(archive_path, "r:*") as tf:
|
|
91
|
+
for member in tf.getmembers():
|
|
92
|
+
if not member.isfile():
|
|
93
|
+
continue
|
|
94
|
+
name = Path(member.name).name
|
|
95
|
+
if name in bin_names:
|
|
96
|
+
src = tf.extractfile(member)
|
|
97
|
+
if src is None:
|
|
98
|
+
continue
|
|
99
|
+
with src, open(dest_binary, "wb") as dst:
|
|
100
|
+
shutil.copyfileobj(src, dst)
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
raise RuntimeError("binary not found inside release archive")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def ensure_installed():
|
|
107
|
+
install_dir = _install_dir()
|
|
108
|
+
version = _dist_version()
|
|
109
|
+
version_dir = install_dir / version / "bin"
|
|
110
|
+
version_dir.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
binary_path = version_dir / _binary_name()
|
|
112
|
+
if binary_path.exists():
|
|
113
|
+
return binary_path
|
|
114
|
+
|
|
115
|
+
os_name, arch = _platform_triplet()
|
|
116
|
+
asset_base = f"{PROJECT}_{os_name}_{arch}"
|
|
117
|
+
candidates = [f"{asset_base}.tar.gz", f"{asset_base}.zip"]
|
|
118
|
+
|
|
119
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
120
|
+
tmpdir = Path(tmp)
|
|
121
|
+
archive_path = None
|
|
122
|
+
for asset in candidates:
|
|
123
|
+
url = f"https://github.com/{REPO}/releases/download/v{version}/{asset}"
|
|
124
|
+
local = tmpdir / asset
|
|
125
|
+
if _download_asset(url, local):
|
|
126
|
+
archive_path = local
|
|
127
|
+
break
|
|
128
|
+
if archive_path is None:
|
|
129
|
+
raise RuntimeError(
|
|
130
|
+
f"no release asset found for {os_name}/{arch} at v{version} (tried: {', '.join(candidates)})"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
_extract_binary(archive_path, binary_path)
|
|
134
|
+
|
|
135
|
+
if os.name != "nt":
|
|
136
|
+
binary_path.chmod(0o755)
|
|
137
|
+
return binary_path
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def main():
|
|
141
|
+
try:
|
|
142
|
+
binary = ensure_installed()
|
|
143
|
+
except Exception as e:
|
|
144
|
+
print(f"nibble install error: {e}", file=sys.stderr)
|
|
145
|
+
return 1
|
|
146
|
+
|
|
147
|
+
result = subprocess.run([str(binary)] + sys.argv[1:])
|
|
148
|
+
return result.returncode
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if __name__ == "__main__":
|
|
152
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
import os
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
def get_version():
|
|
6
|
+
"""Get version from git tags"""
|
|
7
|
+
try:
|
|
8
|
+
version = subprocess.check_output(
|
|
9
|
+
["git", "describe", "--tags", "--abbrev=0"],
|
|
10
|
+
cwd=os.path.dirname(__file__),
|
|
11
|
+
stderr=subprocess.DEVNULL
|
|
12
|
+
).decode().strip()
|
|
13
|
+
return version[1:] if version.startswith("v") else version
|
|
14
|
+
except:
|
|
15
|
+
return "0.1.0"
|
|
16
|
+
|
|
17
|
+
setup(
|
|
18
|
+
name="nibble-cli",
|
|
19
|
+
version=get_version(),
|
|
20
|
+
description="Fast local network scanner with hardware identification and a terminal UI",
|
|
21
|
+
long_description=open("README.md").read() if os.path.exists("README.md") else "",
|
|
22
|
+
long_description_content_type="text/markdown",
|
|
23
|
+
author="saberd",
|
|
24
|
+
author_email="your-email@example.com",
|
|
25
|
+
url="https://github.com/saberd/nibble",
|
|
26
|
+
py_modules=["nibble_installer"],
|
|
27
|
+
entry_points={
|
|
28
|
+
"console_scripts": [
|
|
29
|
+
"nibble=nibble_installer:main",
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
install_requires=[],
|
|
33
|
+
python_requires=">=3.6",
|
|
34
|
+
classifiers=[
|
|
35
|
+
"Development Status :: 4 - Beta",
|
|
36
|
+
"Environment :: Console",
|
|
37
|
+
"Intended Audience :: System Administrators",
|
|
38
|
+
"License :: OSI Approved :: MIT License",
|
|
39
|
+
"Operating System :: OS Independent",
|
|
40
|
+
"Programming Language :: Python :: 3",
|
|
41
|
+
"Topic :: System :: Networking",
|
|
42
|
+
],
|
|
43
|
+
)
|