Skip to content
This repository was archived by the owner on Mar 9, 2026. It is now read-only.

Commit da41068

Browse files
committed
Unified run.py file allowing execution of an excavator against a file.
Provide a central excavators module which re-exports the various named configurations. Use this to implement a CLI recognizing a --excavator argument which will call an exacavtion of the supplied filename. Rework run_example as a wrapper around this new unified CLI. Expand the README documenting both run_example and unified run entry points noting that in the absence of arguments a list of supported excavators is output. While here add smoke tests for basic validation of exports and scripts.
1 parent b19719f commit da41068

34 files changed

+396
-128
lines changed

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
test:
2+
@python3 -m unittest discover tests "*_test.py"
3+
@python3 -m unittest discover tests/autoarchaologist "*_test.py"

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,35 @@ computers, in a convenient and user-friendly way.
88
The AutoArchaeologist is a framework where plugins can be written to take
99
apart and present old data media, in a browser-friendly fashion.
1010

11+
## Getting started
12+
13+
To get a feel for how this works and ensure you've got everything set up,
14+
we've included a sample file that can be excavated as an example:
15+
16+
```sh
17+
python3 run_example.py
18+
```
19+
20+
When you're ready to for further and process you own images use `run.py`.
21+
22+
## Using run.py
23+
24+
The various utilities that allow the extraction and processing of data are
25+
designed to be composed into an Excavation that can be run against binary
26+
images of disks and other media. Some standard excavations have been put
27+
together in bundles ad exposed via a single `run` command.
28+
29+
Performing an exavation of a file is as simple as the following:
30+
31+
```sh
32+
python3 run.py --excavator <excavator> <filename>
33+
```
34+
35+
Usage information including the list of excavatos that are avalable as well as
36+
other options will be output when running without arguments: `python3 run.py`.
37+
38+
## From the DDHF
39+
1140
# First Example: Commodore CBM900 Harddisk
1241

1342
Our first historic use of the AutoArchaeologist is now online:

autoarchaeologist/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
from .base.excavation import Excavation, DuplicateArtifact
55
from .record import Record
66
from .base.namespace import NameSpace
7+
from . import excavators

autoarchaeologist/base/excavation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ def summary(self, *args, **kwargs):
389389
font-family: "Inconsolata", "Courier New", mono-space;
390390
}
391391
td,th {
392-
padding: 0 10px 0;
392+
padding: 0 10px 0;
393393
}
394394
th {
395395
border-bottom: 1px solid black;
Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
'''
55

66

7+
from ..base import excavation
78
from ..base import type_case
89
from ..generic import samesame
910
from ..generic import textfiles
@@ -12,10 +13,12 @@
1213
cpm.cpm_filename_typecase.set_slug(0x5f, '_', '_')
1314
cpm.cpm_filename_typecase.set_slug(0x3b, ';', ';')
1415

15-
def std_cpm_excavation(exc):
16+
class Cpm(excavation.Excavation):
17+
1618
''' Standard CP/M excavation '''
1719

18-
exc.type_case = type_case.DS2089Cpm()
19-
exc.add_examiner(cpm.CpmFileSystem)
20-
exc.add_examiner(textfiles.TextFile)
21-
exc.add_examiner(samesame.SameSame)
20+
def __init__(self, **kwargs):
21+
self.type_case = type_case.DS2089Cpm()
22+
self.add_examiner(cpm.CpmFileSystem)
23+
self.add_examiner(textfiles.TextFile)
24+
self.add_examiner(samesame.SameSame)

autoarchaeologist/ddhf/decorated_context.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class DDHF_Excavation(excavation.Excavation):
1919

2020
def __init__(
2121
self,
22+
Excavation,
2223
ddhf_topic=None,
2324
ddhf_topic_link=None,
2425
ddhf_bitstore_cache=None,
@@ -31,6 +32,9 @@ def __init__(
3132
self.ddhf_bitstore_cache = ddhf_bitstore_cache
3233
super().__init__(**kwargs)
3334

35+
# apply the configuration of the chosen excavation
36+
Excavation.__init__(self, **kwargs)
37+
3438
def html_prefix_banner(self, file, _this):
3539
''' Emit the banner for this excavation '''
3640
file.write('<table>\n')

autoarchaeologist/excavators.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import importlib.util
2+
import os
3+
import sys
4+
5+
# XXX: importing excavations this way is a kludge to avoid multiple rounds
6+
# of file splitting churn that would pollute diffs.. important as the
7+
# the most critical thing (for now) is avoiding changes to behaviour
8+
def _import_name(import_name):
9+
import_path = f"{import_name}.py"
10+
spec = importlib.util.spec_from_file_location(import_name, import_path)
11+
mod = importlib.util.module_from_spec(spec)
12+
spec.loader.exec_module(mod)
13+
return mod
14+
15+
from .ddhf.cpm_excavator import Cpm as cpm
16+
cbm900 = _import_name("ddhf_cbm900").Cbm900
17+
cr80 = _import_name("ddhf_cr80").Cr80Floppy
18+
cr80_wang = _import_name("ddhf_cr80_wang").Cr80Wang
19+
dask = _import_name("ddhf_dask").Dask
20+
gier = _import_name("ddhf_gier").Gier
21+
intel_isis = _import_name("ddhf_intel_isis").IntelISIS
22+
r1k = _import_name("ddhf_r1k_tapes").R1k
23+
r1k_backup = _import_name("ddhf_r1k_backup").R1kBackup
24+
r1k_dfs = _import_name("ddhf_r1k_dfs").R1kDFS
25+
rc3600 = _import_name("ddhf_rc3600").Rc3600
26+
uug = _import_name("ddhf_dkuug").DkuugEuug
27+
zilog_mcz = _import_name("ddhf_zilog_mcz").ZilogMCZ
28+
29+
# from .gier import configure_excavation as gier
30+
# from .intel_isis import configure_excavation as intel_isis
31+
# from .r1kdfs import configure_excavation as r1kdfs
32+
# from .uug import configure_excavation as uug
33+
34+
__all__ = [
35+
"cbm900",
36+
"cpm",
37+
"cr80",
38+
"cr80_wang",
39+
"dask",
40+
"gier",
41+
"intel_isis",
42+
"r1k",
43+
"r1k_backup",
44+
"r1k_dfs",
45+
"rc3600",
46+
"uug",
47+
"zilog_mcz",
48+
]
49+
50+
EXCAVATORS = {name:getattr(sys.modules[__name__], name) for name in __all__}
51+
52+
def excavator_by_name(excavator_name):
53+
if excavator_name not in EXCAVATORS:
54+
raise LookupError(f'no extractor named "{excavator_name}"')
55+
return EXCAVATORS[excavator_name]

ddhf_butler.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,22 @@
33
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44
'''
55

6-
from autoarchaeologist import ddhf
7-
from autoarchaeologist.ddhf import cpm_exc
6+
from autoarchaeologist import ddhf, Excavation
7+
from autoarchaeologist.ddhf.cpm_excavator import Cpm
88

9-
class Butler(ddhf.DDHF_Excavation):
9+
class DDHF_Butler(ddhf.DDHF_Excavation):
1010
''' All Butler artifacts '''
1111

1212
def __init__(self, **kwargs):
13-
super().__init__(**kwargs)
14-
15-
cpm_exc.std_cpm_excavation(self)
13+
super().__init__(Cpm, **kwargs)
1614

1715
self.from_bitstore(
1816
"COMPANY/BOGIKA",
1917
)
2018

2119
if __name__ == "__main__":
2220
ddhf.main(
23-
Butler,
21+
DDHF_Butler,
2422
html_subdir="butler",
2523
ddhf_topic = 'Bogika Butler',
2624
ddhf_topic_link = 'https://datamuseum.dk/wiki/BDS_Butler'

ddhf_cbm900.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
'''
55

66
from autoarchaeologist import ddhf
7+
from autoarchaeologist.base import excavation
78

89
from autoarchaeologist.unix import cbm900_partition
910
from autoarchaeologist.unix import v7_filesystem
@@ -12,7 +13,7 @@
1213
from autoarchaeologist.generic import textfiles
1314
from autoarchaeologist.generic import samesame
1415

15-
class CBM900(ddhf.DDHF_Excavation):
16+
class Cbm900(excavation.Excavation):
1617

1718
'''
1819
Two CBM900 hard-disk images, one also contains the four distribution
@@ -29,14 +30,18 @@ def __init__(self, **kwargs):
2930
self.add_examiner(textfiles.TextFile)
3031
self.add_examiner(samesame.SameSame)
3132

33+
class DDHF_Cbm900(ddhf.DDHF_Excavation):
34+
def __init__(self, **kwargs):
35+
super().__init__(Cbm900, **kwargs)
36+
3237
self.from_bitstore(
3338
"30001199",
3439
"30001972",
3540
)
3641

3742
if __name__ == "__main__":
3843
ddhf.main(
39-
CBM900,
44+
DDHF_Cbm900,
4045
html_subdir="cbm900",
4146
ddhf_topic = "Commodore CBM-900",
4247
ddhf_topic_link = 'https://datamuseum.dk/wiki/Commodore/CBM900',

ddhf_comet.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,22 @@
44
'''
55

66
from autoarchaeologist import ddhf
7-
from autoarchaeologist.ddhf import cpm_exc
7+
from autoarchaeologist.ddhf.cpm_excavator import Cpm
88

9-
class Comet(ddhf.DDHF_Excavation):
9+
class DDHF_Comet(ddhf.DDHF_Excavation):
1010

1111
''' All Comet artifacts '''
1212

1313
def __init__(self, **kwargs):
14-
super().__init__(**kwargs)
15-
16-
cpm_exc.std_cpm_excavation(self)
14+
super().__init__(Cpm, **kwargs)
1715

1816
self.from_bitstore(
1917
"COMPANY/ICL/COMET",
2018
)
2119

2220
if __name__ == "__main__":
2321
ddhf.main(
24-
Comet,
22+
DDHF_Comet,
2523
html_subdir="comet",
2624
ddhf_topic = 'ICL Comet',
2725
ddhf_topic_link = 'https://datamuseum.dk/wiki/ICL_Comet'

0 commit comments

Comments
 (0)