Skip to content

Commit

Permalink
Use omegaconf to configure the utility
Browse files Browse the repository at this point in the history
  • Loading branch information
insolor committed Jul 19, 2024
1 parent cb7eb96 commit 0e27f66
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 10 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,6 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/

offsets_*.toml
.config.yaml
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,11 @@
3. Run search:

```shell
poetry run search "C:/path/to/Dwarf Fortress/Dwarf Fortress.exe"
poetry run search path="C:/path/to/Dwarf Fortress/Dwarf Fortress.exe"
```

Alternatively, you can add a yaml config in the root of the project instead of using the CLI options:

```yaml
path: "C:/path/to/Dwarf Fortress/Dwarf Fortress.exe"
```
108 changes: 107 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ python = "^3.10"
more-itertools = "^10.3.0"
typer = "^0.12.3"
peclasses = {version = "^0.4.0", source = "dfint"}
loguru = "^0.7.2"
omegaconf = "^2.3.0"

[tool.poetry.group.dev.dependencies]
ruff = "^0.5.0"
pytest = "^8.2.2"
hypothesis = "^6.104.2"

[tool.poetry.scripts]
search = "search_offsets.search:app"
search = "search_offsets.search:main"

[[tool.poetry.source]]
name = "dfint"
Expand Down Expand Up @@ -51,6 +53,7 @@ ignore = [
"D105", # Missing docstring in magic method
"D200", # One-line docstring should fit on one line
"D212", # Multi-line docstring summary should start at the first line
"D401", # First line should be in imperative mood
]
unfixable = []

Expand Down
32 changes: 32 additions & 0 deletions search_offsets/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import functools
from collections.abc import Callable

from loguru import logger
from omegaconf import DictConfig, OmegaConf


def with_config(config_class: type, config_file: str) -> Callable[[Callable[[DictConfig], None]], Callable[[], None]]:
"""
A decorator to load the config file and merge it with the CLI options.
"""

def decorator(func: Callable[[DictConfig], None]) -> Callable[[], None]:
@functools.wraps(func)
def wrapper() -> None:
config = OmegaConf.structured(config_class)

config.merge_with(OmegaConf.from_cli())
try:
config.merge_with(OmegaConf.load(config_file))
except FileNotFoundError:
logger.info(f"Config {config_file} not found, using CLI options only")

missing = ", ".join(OmegaConf.missing_keys(config))
if missing:
logger.error(f"Missing configuration keys: {missing}")
return
func(config)

return wrapper

return decorator
18 changes: 11 additions & 7 deletions search_offsets/search.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from collections import defaultdict
from collections.abc import Iterable, Mapping
from dataclasses import dataclass
from pathlib import Path

import typer
from omegaconf import DictConfig
from peclasses.portable_executable import PortableExecutable, SectionTable

from search_offsets.config import with_config
from search_offsets.patterns import (
Pattern,
check_pattern,
Expand Down Expand Up @@ -50,24 +52,26 @@ def print_found(section_table: SectionTable, pattern_names: Iterable[str], found
print(f"{name} = 0x{rva:X}")


app = typer.Typer()
@dataclass
class _Config:
path: Path


@app.command()
def main(path: Path) -> None:
@with_config(_Config, ".config.yaml")
def main(config: DictConfig) -> None:
"""
Process the given portable executable file, print its checksum(time stamp) and offsets of the found patterns.
"""
patterns: list[Pattern] = load_patterns()

with path.open("rb") as exe:
with config.path.open("rb") as exe:
pe = PortableExecutable(exe)
print(f"checksum = 0x{pe.file_header.timedate_stamp:X}")
section_table = pe.section_table

found = search(path, patterns)
found = search(config.path, patterns)
print_found(section_table, map(str, patterns), found)


if __name__ == "__main__":
app()
main()

0 comments on commit 0e27f66

Please sign in to comment.