flashpod 0.2.2__tar.gz → 0.2.3__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 (26) hide show
  1. {flashpod-0.2.2 → flashpod-0.2.3}/PKG-INFO +1 -1
  2. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/ipod_flash.py +45 -11
  3. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/platform/macos.py +16 -20
  4. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/platform/windows.py +22 -20
  5. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/PKG-INFO +1 -1
  6. {flashpod-0.2.2 → flashpod-0.2.3}/pyproject.toml +1 -1
  7. {flashpod-0.2.2 → flashpod-0.2.3}/LICENSE +0 -0
  8. {flashpod-0.2.2 → flashpod-0.2.3}/README.md +0 -0
  9. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/__init__.py +0 -0
  10. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/__main__.py +0 -0
  11. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/cli.py +0 -0
  12. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/contrib/99-flashpod-firewire-ipod.rules +0 -0
  13. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/fat32.py +0 -0
  14. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/fatfs.py +0 -0
  15. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/firmware/firmware.json +0 -0
  16. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/itunesdb.py +0 -0
  17. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/platform/__init__.py +0 -0
  18. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/platform/base.py +0 -0
  19. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/platform/linux.py +0 -0
  20. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/resources.py +0 -0
  21. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/SOURCES.txt +0 -0
  22. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/dependency_links.txt +0 -0
  23. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/entry_points.txt +0 -0
  24. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/requires.txt +0 -0
  25. {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/top_level.txt +0 -0
  26. {flashpod-0.2.2 → flashpod-0.2.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flashpod
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Command-line iPod sync + card-flashing tooling for early FireWire-era iPods, pure Python
5
5
  Author: David Barnhart
6
6
  License-Expression: MIT
@@ -397,10 +397,44 @@ def device_mountpoints(dev):
397
397
  # ----------------------------------------------------------------------------
398
398
  # Interactive selection + confirmation
399
399
  # ----------------------------------------------------------------------------
400
- def choose_device():
401
- cands = list_candidates()
402
- if not cands:
403
- sys.exit(color("No removable/USB disks found. Plug in the card and retry.", C_RED))
400
+ def pick_device(scan, render, path_of, empty_msg):
401
+ """Interactive device chooser shared by every platform backend.
402
+
403
+ ``scan()`` returns the candidate list (called again on each refresh),
404
+ ``render(items)`` prints the table, ``path_of(item)`` yields the device path
405
+ to return.
406
+
407
+ The loop accepts 'r' to re-scan. Without it, a reader plugged in — or a card
408
+ inserted — after the list was drawn stays invisible until you quit and start
409
+ the whole command over, which is a long way back when you've already picked
410
+ a model and firmware.
411
+ """
412
+ items = scan()
413
+ if not items:
414
+ sys.exit(color(empty_msg, C_RED))
415
+ render(items)
416
+ while True:
417
+ try:
418
+ sel = input(color("Select device number "
419
+ "('r' to rescan, 'q' to quit): ", C_CYN)).strip().lower()
420
+ except (EOFError, KeyboardInterrupt):
421
+ print(file=sys.stderr)
422
+ sys.exit("Aborted.")
423
+ if sel in ("q", "quit", ""):
424
+ sys.exit("Aborted.")
425
+ if sel in ("r", "refresh", "rescan"):
426
+ items = scan()
427
+ if not items:
428
+ print(color(" " + empty_msg, C_YEL), file=sys.stderr)
429
+ else:
430
+ render(items)
431
+ continue
432
+ if sel.isdigit() and int(sel) < len(items):
433
+ return path_of(items[int(sel)])
434
+ print(color(" invalid selection", C_RED), file=sys.stderr)
435
+
436
+
437
+ def _render_candidates(cands):
404
438
  print(color("\nAttached removable storage:\n", C_CYN), file=sys.stderr)
405
439
  # Multi-slot readers expose one /dev/sdX per slot, all with the same
406
440
  # identity strings; number the slots so they can be told apart.
@@ -442,13 +476,13 @@ def choose_device():
442
476
  if r["warn"]:
443
477
  print(color(" " * sub + "⚠ " + r["warn"], C_YEL), file=sys.stderr)
444
478
  print(file=sys.stderr)
445
- while True:
446
- sel = input(color("Select device number (or 'q' to quit): ", C_CYN)).strip()
447
- if sel.lower() in ("q", "quit", ""):
448
- sys.exit("Aborted.")
449
- if sel.isdigit() and int(sel) < len(cands):
450
- return "/dev/" + cands[int(sel)]["name"]
451
- print(color(" invalid selection", C_RED), file=sys.stderr)
479
+
480
+
481
+ def choose_device():
482
+ return pick_device(
483
+ list_candidates, _render_candidates,
484
+ lambda d: "/dev/" + d["name"],
485
+ "No removable/USB disks found. Plug in the card and retry.")
452
486
 
453
487
  def device_label(dev):
454
488
  """Short, typeable name for a device, used in the ERASE confirmation.
@@ -73,26 +73,22 @@ class MacOSPlatform(Platform):
73
73
  def choose_device(self):
74
74
  from .. import ipod_flash
75
75
  color = ipod_flash.color
76
- disks = self._external_disks()
77
- if not disks:
78
- sys.exit(color("No external disks found. Plug in the card reader and retry.",
79
- ipod_flash.C_RED))
80
- print(color("\nAttached external disks:\n", ipod_flash.C_CYN), file=sys.stderr)
81
- for i, (d, info) in enumerate(disks):
82
- size = int(info.get("TotalSize") or info.get("Size") or 0)
83
- name = (info.get("MediaName") or info.get("IORegistryEntryName")
84
- or "").strip() or "disk"
85
- print(" [%d] /dev/%-7s %10s %s" %
86
- (i, d, ipod_flash.fmt_size(size), name), file=sys.stderr)
87
- print(file=sys.stderr)
88
- while True:
89
- sel = input(color("Select device number (or 'q' to quit): ",
90
- ipod_flash.C_CYN)).strip()
91
- if sel.lower() in ("q", "quit", ""):
92
- sys.exit("Aborted.")
93
- if sel.isdigit() and int(sel) < len(disks):
94
- return "/dev/" + disks[int(sel)][0]
95
- print(color(" invalid selection", ipod_flash.C_RED), file=sys.stderr)
76
+
77
+ def render(disks):
78
+ print(color("\nAttached external disks:\n", ipod_flash.C_CYN),
79
+ file=sys.stderr)
80
+ for i, (d, info) in enumerate(disks):
81
+ size = int(info.get("TotalSize") or info.get("Size") or 0)
82
+ name = (info.get("MediaName") or info.get("IORegistryEntryName")
83
+ or "").strip() or "disk"
84
+ print(" [%d] /dev/%-7s %10s %s" %
85
+ (i, d, ipod_flash.fmt_size(size), name), file=sys.stderr)
86
+ print(file=sys.stderr)
87
+
88
+ return ipod_flash.pick_device(
89
+ self._external_disks, render,
90
+ lambda item: "/dev/" + item[0],
91
+ "No external disks found. Plug in the card reader and retry.")
96
92
 
97
93
  def device_sectors(self, dev):
98
94
  # real file/image -> just its size
@@ -144,29 +144,31 @@ class WindowsPlatform(Platform):
144
144
  f[4].strip().lower() == "true" or f[5].strip().lower() == "true"))
145
145
  return disks
146
146
 
147
+ def _removable_disks(self):
148
+ """Removable/USB disks worth offering, falling back to every non-system
149
+ disk when nothing matches the removable bus types."""
150
+ disks = self._disks()
151
+ cands = [d for d in disks
152
+ if not d[4] and d[3] in ("USB", "SD", "MMC", "1394")]
153
+ return cands or [d for d in disks if not d[4]]
154
+
147
155
  def choose_device(self):
148
156
  from .. import ipod_flash
149
157
  color = ipod_flash.color
150
- cands = [d for d in self._disks()
151
- if not d[4] and d[3] in ("USB", "SD", "MMC", "1394")]
152
- if not cands:
153
- cands = [d for d in self._disks() if not d[4]]
154
- if not cands:
155
- sys.exit(color("No removable disks found. Plug in the card and retry.",
156
- ipod_flash.C_RED))
157
- print(color("\nAttached removable disks:\n", ipod_flash.C_CYN), file=sys.stderr)
158
- for i, (num, size, name, bus, _sys) in enumerate(cands):
159
- print(" [%d] \\\\.\\PhysicalDrive%-3d %10s %s (%s)" %
160
- (i, num, ipod_flash.fmt_size(size), name.strip(), bus), file=sys.stderr)
161
- print(file=sys.stderr)
162
- while True:
163
- sel = input(color("Select device number (or 'q' to quit): ",
164
- ipod_flash.C_CYN)).strip()
165
- if sel.lower() in ("q", "quit", ""):
166
- sys.exit("Aborted.")
167
- if sel.isdigit() and int(sel) < len(cands):
168
- return "\\\\.\\PhysicalDrive%d" % cands[int(sel)][0]
169
- print(color(" invalid selection", ipod_flash.C_RED), file=sys.stderr)
158
+
159
+ def render(cands):
160
+ print(color("\nAttached removable disks:\n", ipod_flash.C_CYN),
161
+ file=sys.stderr)
162
+ for i, (num, size, name, bus, _sys) in enumerate(cands):
163
+ print(" [%d] \\\\.\\PhysicalDrive%-3d %10s %s (%s)" %
164
+ (i, num, ipod_flash.fmt_size(size), name.strip(), bus),
165
+ file=sys.stderr)
166
+ print(file=sys.stderr)
167
+
168
+ return ipod_flash.pick_device(
169
+ self._removable_disks, render,
170
+ lambda d: "\\\\.\\PhysicalDrive%d" % d[0],
171
+ "No removable disks found. Plug in the card and retry.")
170
172
 
171
173
  def device_sectors(self, dev):
172
174
  if os.path.isfile(dev):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flashpod
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Command-line iPod sync + card-flashing tooling for early FireWire-era iPods, pure Python
5
5
  Author: David Barnhart
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "flashpod"
7
- version = "0.2.2"
7
+ version = "0.2.3"
8
8
  description = "Command-line iPod sync + card-flashing tooling for early FireWire-era iPods, pure Python"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.6"
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