driverclient 0.2.17__tar.gz → 0.2.18__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 (23) hide show
  1. {driverclient-0.2.17 → driverclient-0.2.18}/PKG-INFO +1 -1
  2. {driverclient-0.2.17 → driverclient-0.2.18}/pyproject.toml +1 -1
  3. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/__init__.py +1 -1
  4. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/config.json +2 -1
  5. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/ops/capture.py +60 -0
  6. {driverclient-0.2.17 → driverclient-0.2.18}/.gitignore +0 -0
  7. {driverclient-0.2.17 → driverclient-0.2.18}/README.md +0 -0
  8. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/__main__.py +0 -0
  9. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/config.py +0 -0
  10. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/core/__init__.py +0 -0
  11. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/core/hardware.py +0 -0
  12. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/core/http.py +0 -0
  13. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/core/hwid.py +0 -0
  14. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/core/proc.py +0 -0
  15. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/events.py +0 -0
  16. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/main.py +0 -0
  17. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/ops/__init__.py +0 -0
  18. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/ops/automate.py +0 -0
  19. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/ops/diagnose.py +0 -0
  20. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/ops/install.py +0 -0
  21. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/ops/resolve.py +0 -0
  22. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/ops/scan.py +0 -0
  23. {driverclient-0.2.17 → driverclient-0.2.18}/src/driverclient/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: driverclient
3
- Version: 0.2.17
3
+ Version: 0.2.18
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.17"
7
+ version = "0.2.18"
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"
@@ -25,7 +25,7 @@ from driverclient.main import run as _run
25
25
 
26
26
  __all__ = ["DriverClient", "ClientEvent"]
27
27
 
28
- __version__ = "0.2.17"
28
+ __version__ = "0.2.18"
29
29
 
30
30
 
31
31
  class DriverClient:
@@ -19,8 +19,9 @@
19
19
  "usb": [".inf", ".sys", ".cat", ".dll"]
20
20
  },
21
21
 
22
- "wu_wait_minutes": 10,
22
+ "wu_wait_minutes": 30,
23
23
  "wu_poll_interval_seconds": 30,
24
+ "wu_quiescent_polls": 2,
24
25
  "wu_ignore_classes": ["hidclass", "bluetooth", "printer"],
25
26
 
26
27
  "automate_wu_fallback": true,
@@ -714,6 +714,63 @@ def _trigger_wu() -> "_WuTrigger | None":
714
714
  return None
715
715
 
716
716
 
717
+ def _emit_wu_log_line(line: str) -> None:
718
+ """Turn one raw status line from the WU PowerShell into a friendly GUI event
719
+ so the operator sees WU's real phase (searching / downloading / installing)
720
+ live, instead of only a generic 'still working' tick."""
721
+ up = line.upper()
722
+ if up.startswith("SERVICE MICROSOFT_UPDATE"):
723
+ events.ok("windows_update",
724
+ "[wu-update] Using the Microsoft Update service (drivers + Microsoft products)")
725
+ elif up.startswith("SERVICE WINDOWS_UPDATE_FALLBACK"):
726
+ detail = line.split(None, 2)[2] if len(line.split(None, 2)) > 2 else ""
727
+ events.warn("windows_update",
728
+ f"[wu-update] Microsoft Update unavailable — falling back to default "
729
+ f"Windows Update service {detail}".rstrip())
730
+ elif up == "SEARCHING":
731
+ events.progress("windows_update",
732
+ "[wu-update] Searching Windows Update for applicable updates… "
733
+ "(the first scan can take several minutes)")
734
+ elif up == "NO_UPDATES":
735
+ events.progress("windows_update", "[wu-update] Search complete — no applicable updates found")
736
+ elif up.startswith("DOWNLOADING"):
737
+ n = line.split()[-1] if line.split() else "?"
738
+ events.progress("windows_update", f"[wu-update] Downloading {n} update(s)…")
739
+ elif up == "NONE_DOWNLOADED":
740
+ events.warn("windows_update", "[wu-update] Nothing downloaded")
741
+ elif up.startswith("INSTALLING"):
742
+ n = line.split()[-1] if line.split() else "?"
743
+ events.progress("windows_update", f"[wu-update] Installing {n} update(s)…")
744
+ elif up.startswith("INSTALLED"):
745
+ events.ok("windows_update", f"[wu-update] {line}")
746
+ elif up.startswith("WU_ERROR"):
747
+ detail = line[len("WU_ERROR"):].strip()
748
+ events.warn("windows_update", f"[wu-update] Windows Update error: {detail}", error=detail)
749
+ else:
750
+ events.progress("windows_update", f"[wu-update] {line}")
751
+
752
+
753
+ def _drain_wu_log(trigger: "_WuTrigger | None", pos: int) -> int:
754
+ """Emit any new lines the WU PowerShell wrote to its log since offset `pos`,
755
+ return the new offset. Best-effort — a read failure just leaves `pos`
756
+ unchanged and never raises into the poll loop. Only the COM path writes a
757
+ log (trigger.log_path); the usoclient/wuauclt fallbacks have none."""
758
+ if trigger is None or not trigger.log_path:
759
+ return pos
760
+ try:
761
+ with open(trigger.log_path, "r", encoding="utf-8", errors="replace") as fh:
762
+ fh.seek(pos)
763
+ chunk = fh.read()
764
+ new_pos = fh.tell()
765
+ except Exception:
766
+ return pos
767
+ for line in chunk.splitlines():
768
+ line = line.strip()
769
+ if line:
770
+ _emit_wu_log_line(line)
771
+ return new_pos
772
+
773
+
717
774
  def _poll_and_submit_incremental(wu_start: datetime, cfg: dict,
718
775
  trigger: "_WuTrigger | None") -> CaptureResult:
719
776
  """
@@ -739,12 +796,14 @@ def _poll_and_submit_incremental(wu_start: datetime, cfg: dict,
739
796
  seen: set[str] = set()
740
797
  total = CaptureResult()
741
798
  empty_polls = 0
799
+ log_pos = 0
742
800
 
743
801
  events.progress("windows_update",
744
802
  f"[wu-update] Waiting on Windows Update — polling every {poll_secs}s, "
745
803
  f"stops early once WU goes idle (hard cap {wait_min} min)")
746
804
 
747
805
  while datetime.now(timezone.utc) < deadline:
806
+ log_pos = _drain_wu_log(trigger, log_pos) # surface WU's live phase
748
807
  all_new = _enumerate_packages_since(wu_start, cfg)
749
808
  new_batch = [
750
809
  p for p in all_new
@@ -789,6 +848,7 @@ def _poll_and_submit_incremental(wu_start: datetime, cfg: dict,
789
848
  events.warn("windows_update",
790
849
  f"[wu-update] Reached {wait_min} min hard cap — stopping WU wait")
791
850
 
851
+ _drain_wu_log(trigger, log_pos) # flush any final lines before cleanup
792
852
  if trigger is not None:
793
853
  trigger.terminate()
794
854
  return total
File without changes
File without changes