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.
@@ -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,7 @@
1
+ nibble_installer.py
2
+ setup.py
3
+ nibble_cli.egg-info/PKG-INFO
4
+ nibble_cli.egg-info/SOURCES.txt
5
+ nibble_cli.egg-info/dependency_links.txt
6
+ nibble_cli.egg-info/entry_points.txt
7
+ nibble_cli.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ nibble = nibble_installer:main
@@ -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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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
+ )