driverclient 0.2.29__tar.gz → 0.2.31__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.
- {driverclient-0.2.29 → driverclient-0.2.31}/PKG-INFO +1 -1
- {driverclient-0.2.29 → driverclient-0.2.31}/pyproject.toml +1 -1
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/__init__.py +1 -1
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/ops/capture.py +20 -39
- {driverclient-0.2.29 → driverclient-0.2.31}/.gitignore +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/README.md +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/__main__.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/config.json +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/config.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/core/__init__.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/core/hardware.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/core/http.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/core/hwid.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/core/proc.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/events.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/main.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/ops/__init__.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/ops/automate.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/ops/diagnose.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/ops/download.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/ops/install.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/ops/offline.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/ops/resolve.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/ops/scan.py +0 -0
- {driverclient-0.2.29 → driverclient-0.2.31}/src/driverclient/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: driverclient
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.31
|
|
4
4
|
Summary: Driver Server client with an embeddable connector for config injection at runtime.
|
|
5
5
|
Project-URL: Homepage, https://example.com/driverclient
|
|
6
6
|
Author-email: Raja Sanaullah <sanaullah@99technologies.com>
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "driverclient"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.31"
|
|
8
8
|
description = "Driver Server client with an embeddable connector for config injection at runtime."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -97,6 +97,9 @@ def _machine_meta() -> dict:
|
|
|
97
97
|
"machine_id": machine_id,
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
|
|
101
|
+
_WINDOWS_INF = Path("C:\\Windows\\INF")
|
|
102
|
+
|
|
100
103
|
_PNPUTIL_KEYS: dict[str, str] = {
|
|
101
104
|
"published name": "published_name",
|
|
102
105
|
"original name": "original_name",
|
|
@@ -346,13 +349,12 @@ def wu_update(force: bool = False) -> CaptureResult:
|
|
|
346
349
|
**skip_reasons,
|
|
347
350
|
)
|
|
348
351
|
|
|
349
|
-
baseline = _snapshot_published_names(cfg)
|
|
350
352
|
trigger = _trigger_wu()
|
|
351
353
|
if trigger is None:
|
|
352
354
|
return CaptureResult(still_missing=len(wu_hwids))
|
|
353
355
|
|
|
354
356
|
wu_start = datetime.now(timezone.utc)
|
|
355
|
-
total = _poll_and_submit_incremental(wu_start, cfg, trigger
|
|
357
|
+
total = _poll_and_submit_incremental(wu_start, cfg, trigger)
|
|
356
358
|
total.wu_triggered = True
|
|
357
359
|
total.still_missing = max(0, len(wu_hwids) - total.submitted)
|
|
358
360
|
total.reboot_required = _wu_reboot_pending()
|
|
@@ -381,13 +383,12 @@ def wu_full() -> CaptureResult:
|
|
|
381
383
|
"windows_update", "[wu-full] Triggering full Windows Update scan (no HWID filtering)…"
|
|
382
384
|
)
|
|
383
385
|
|
|
384
|
-
baseline = _snapshot_published_names(cfg)
|
|
385
386
|
trigger = _trigger_wu()
|
|
386
387
|
if trigger is None:
|
|
387
388
|
return CaptureResult()
|
|
388
389
|
|
|
389
390
|
wu_start = datetime.now(timezone.utc)
|
|
390
|
-
total = _poll_and_submit_incremental(wu_start, cfg, trigger
|
|
391
|
+
total = _poll_and_submit_incremental(wu_start, cfg, trigger)
|
|
391
392
|
total.wu_triggered = True
|
|
392
393
|
_post_wu_session(cfg, wu_start, [], total.submitted)
|
|
393
394
|
events.done(
|
|
@@ -403,22 +404,12 @@ def wu_full() -> CaptureResult:
|
|
|
403
404
|
|
|
404
405
|
# ══ Missing-HWID classification ═══════════════════════════════════════════════
|
|
405
406
|
|
|
406
|
-
_INBOX_INADEQUATE_CLASSES = {"display adapters"}
|
|
407
|
-
|
|
408
407
|
|
|
409
408
|
def classify_missing(not_found: list[str], scan_result: ScanResult) -> dict[str, list[str]]:
|
|
410
409
|
"""Bucket repo-missing HWIDs by what the machine says about their device:
|
|
411
410
|
inbox (Windows ships the driver — not applicable), oem_local (OEM driver
|
|
412
411
|
installed locally — capturable), driverless (genuinely missing — WU
|
|
413
|
-
candidate), unknown (HWID not in scan).
|
|
414
|
-
|
|
415
|
-
Display adapters are excluded from the inbox bucket: Microsoft Basic
|
|
416
|
-
Display Adapter is Windows' inbox fallback for a GPU whose real driver
|
|
417
|
-
was never bound, and it leaves the device non-accelerated — unlike other
|
|
418
|
-
inbox drivers (HID, mass storage, ...) it is not adequate coverage. Such
|
|
419
|
-
a device is treated as driverless so it still reaches WU / gets captured
|
|
420
|
-
once a real driver shows up, instead of being silently written off.
|
|
421
|
-
"""
|
|
412
|
+
candidate), unknown (HWID not in scan)."""
|
|
422
413
|
hwid_to_device: dict[str, Device] = {}
|
|
423
414
|
for scanned in scan_result.devices:
|
|
424
415
|
for h in scanned.hwids:
|
|
@@ -436,10 +427,8 @@ def classify_missing(not_found: list[str], scan_result: ScanResult) -> dict[str,
|
|
|
436
427
|
buckets["unknown"].append(hwid)
|
|
437
428
|
elif not dev.has_driver:
|
|
438
429
|
buckets["driverless"].append(hwid)
|
|
439
|
-
elif dev.is_inbox and dev.class_name.lower() not in _INBOX_INADEQUATE_CLASSES:
|
|
440
|
-
buckets["inbox"].append(hwid)
|
|
441
430
|
elif dev.is_inbox:
|
|
442
|
-
buckets["
|
|
431
|
+
buckets["inbox"].append(hwid)
|
|
443
432
|
else:
|
|
444
433
|
buckets["oem_local"].append(hwid)
|
|
445
434
|
return buckets
|
|
@@ -527,25 +516,17 @@ def _parse_enum_drivers(output: str) -> list[dict]:
|
|
|
527
516
|
return packages
|
|
528
517
|
|
|
529
518
|
|
|
530
|
-
def
|
|
531
|
-
"""
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
package stays in the store, so "not in baseline" is a robust new-package
|
|
542
|
-
signal. The previous approach compared each INF's mtime under
|
|
543
|
-
C:\\Windows\\INF against the WU start time — but that mtime can predate the
|
|
544
|
-
run (e.g. Windows already staged the file) or otherwise not bump the way
|
|
545
|
-
expected, silently dropping a genuinely new package (e.g. a discrete AMD
|
|
546
|
-
display driver landing via WU alongside an already-captured Intel one)
|
|
547
|
-
from ever being detected as new, so it was never submitted."""
|
|
548
|
-
return [p for p in _enumerate_all_packages(cfg) if p.get("published_name") not in baseline]
|
|
519
|
+
def _enumerate_packages_since(cutoff: datetime, cfg: dict) -> list[dict]:
|
|
520
|
+
"""Return packages whose C:\\Windows\\INF mtime >= cutoff."""
|
|
521
|
+
result = []
|
|
522
|
+
for pkg in _enumerate_all_packages(cfg):
|
|
523
|
+
inf_path = _WINDOWS_INF / pkg["published_name"]
|
|
524
|
+
if not inf_path.exists():
|
|
525
|
+
continue
|
|
526
|
+
mtime = datetime.fromtimestamp(inf_path.stat().st_mtime, tz=timezone.utc)
|
|
527
|
+
if mtime >= cutoff:
|
|
528
|
+
result.append(pkg)
|
|
529
|
+
return result
|
|
549
530
|
|
|
550
531
|
|
|
551
532
|
def _published_names_for_hwids(
|
|
@@ -885,7 +866,7 @@ def _drain_wu_log(trigger: "_WuTrigger | None", pos: int) -> int:
|
|
|
885
866
|
|
|
886
867
|
|
|
887
868
|
def _poll_and_submit_incremental(
|
|
888
|
-
wu_start: datetime, cfg: dict, trigger: "_WuTrigger | None"
|
|
869
|
+
wu_start: datetime, cfg: dict, trigger: "_WuTrigger | None"
|
|
889
870
|
) -> CaptureResult:
|
|
890
871
|
"""
|
|
891
872
|
Wait on Windows Update, submitting each new DriverStore package as it lands.
|
|
@@ -920,7 +901,7 @@ def _poll_and_submit_incremental(
|
|
|
920
901
|
|
|
921
902
|
while datetime.now(timezone.utc) < deadline:
|
|
922
903
|
log_pos = _drain_wu_log(trigger, log_pos) # surface WU's live phase
|
|
923
|
-
all_new =
|
|
904
|
+
all_new = _enumerate_packages_since(wu_start, cfg)
|
|
924
905
|
new_batch = [p for p in all_new if p.get("published_name", "") not in seen]
|
|
925
906
|
|
|
926
907
|
if new_batch:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|