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.
- {flashpod-0.2.2 → flashpod-0.2.3}/PKG-INFO +1 -1
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/ipod_flash.py +45 -11
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/platform/macos.py +16 -20
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/platform/windows.py +22 -20
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/PKG-INFO +1 -1
- {flashpod-0.2.2 → flashpod-0.2.3}/pyproject.toml +1 -1
- {flashpod-0.2.2 → flashpod-0.2.3}/LICENSE +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/README.md +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/__init__.py +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/__main__.py +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/cli.py +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/contrib/99-flashpod-firewire-ipod.rules +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/fat32.py +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/fatfs.py +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/firmware/firmware.json +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/itunesdb.py +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/platform/__init__.py +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/platform/base.py +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/platform/linux.py +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod/resources.py +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/SOURCES.txt +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/dependency_links.txt +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/entry_points.txt +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/requires.txt +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/flashpod.egg-info/top_level.txt +0 -0
- {flashpod-0.2.2 → flashpod-0.2.3}/setup.cfg +0 -0
|
@@ -397,10 +397,44 @@ def device_mountpoints(dev):
|
|
|
397
397
|
# ----------------------------------------------------------------------------
|
|
398
398
|
# Interactive selection + confirmation
|
|
399
399
|
# ----------------------------------------------------------------------------
|
|
400
|
-
def
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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):
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flashpod"
|
|
7
|
-
version = "0.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
|
|
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
|