Skip to content

Commit a958401

Browse files
authored
fix(programs): multiple fixes/improvements (#282)
* no version management, just installation * smarter default executable location detection in distribution archives * add more programs to bootstrap file
1 parent 2674176 commit a958401

6 files changed

Lines changed: 379 additions & 437 deletions

File tree

autotest/test_programs.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -256,18 +256,14 @@ def test_default_manager_exists(self):
256256
def test_convenience_wrappers(self):
257257
"""Test that convenience functions wrap the default manager."""
258258
from modflow_devtools.programs import (
259-
get_executable,
260259
install_program,
261260
list_installed,
262-
select_version,
263261
uninstall_program,
264262
)
265263

266264
# All functions should exist and be callable
267265
assert callable(install_program)
268-
assert callable(select_version)
269266
assert callable(uninstall_program)
270-
assert callable(get_executable)
271267
assert callable(list_installed)
272268

273269
def test_program_manager_list_installed_empty(self):
@@ -301,10 +297,6 @@ def test_program_manager_error_handling(self):
301297
with pytest.raises(ProgramInstallationError, match="not found"):
302298
manager.install("nonexistent-program-xyz")
303299

304-
# Test get_executable for non-installed program
305-
with pytest.raises(ProgramInstallationError, match="not installed"):
306-
manager.get_executable("nonexistent-program-xyz")
307-
308300
def test_installation_metadata_integration(self):
309301
"""Test InstallationMetadata integration with ProgramManager."""
310302
from datetime import datetime, timezone
@@ -333,7 +325,6 @@ def test_installation_metadata_integration(self):
333325
"hash": "",
334326
},
335327
executables=["test-program"],
336-
active=True,
337328
)
338329
metadata.add_installation(installation)
339330

@@ -344,7 +335,6 @@ def test_installation_metadata_integration(self):
344335
assert len(installations) == 1
345336
assert installations[0].version == "1.0.0"
346337
assert installations[0].platform == "linux"
347-
assert installations[0].active is True
348338

349339
# Clean up
350340
cache.clear()

docs/md/dev/programs.md

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,17 +232,61 @@ hash = "sha256:..."
232232
The `exe` field can be specified at three levels, checked in this order:
233233

234234
1. **Distribution-level** (`[[programs.{name}.dists]]` entry with `exe` field)
235+
- **Supports any custom path** within the archive
235236
- Use when different platforms have different archive structures
236237
- Most specific - overrides program-level and default
237238
- Example: `exe = "mf6.7.0_win64/bin/mf6.exe"`
239+
- Example: `exe = "custom/nested/path/to/program"`
238240

239241
2. **Program-level** (`[programs.{name}]` section with `exe` field)
242+
- **Supports any custom path** shared across all platforms
240243
- Use when all platforms share the same relative path structure
241244
- Example: `exe = "bin/mfnwt"`
245+
- Example: `exe = "special/location/program"`
242246

243247
3. **Default** (neither specified)
244-
- Falls back to `bin/{program}`
245-
- Example: For `mf6`, defaults to `bin/mf6`
248+
- **Automatically detects** executable location when installing
249+
- Tries common patterns in order:
250+
- **Nested with bin/**: `{archive_name}/bin/{program}`
251+
- **Nested without bin/**: `{archive_name}/{program}`
252+
- **Flat with bin/**: `bin/{program}`
253+
- **Flat without bin/**: `{program}`
254+
- Example: For `mf6`, automatically finds binary whether in `mf6.7.0_linux/bin/mf6`, `bin/mf6`, or other common layouts
255+
- Only used when no explicit `exe` field is provided
256+
257+
**Archive structure patterns**:
258+
259+
The API supports four common archive layouts:
260+
261+
1. **Nested with bin/** (e.g., MODFLOW 6):
262+
```
263+
mf6.7.0_linux.zip
264+
└── mf6.7.0_linux/
265+
└── bin/
266+
└── mf6
267+
```
268+
269+
2. **Nested without bin/**:
270+
```
271+
program.1.0_linux.zip
272+
└── program.1.0_linux/
273+
└── program
274+
```
275+
276+
3. **Flat with bin/**:
277+
```
278+
program.zip
279+
└── bin/
280+
└── program
281+
```
282+
283+
4. **Flat without bin/**:
284+
```
285+
program.zip
286+
└── program
287+
```
288+
289+
The `make_registry` tool automatically detects which pattern each archive uses and only stores non-default exe paths in the registry.
246290

247291
**Windows .exe extension handling**:
248292
- The `.exe` extension is automatically added on Windows platforms if not present
@@ -628,6 +672,12 @@ python -m modflow_devtools.programs.make_registry \
628672
- Optionally computes SHA256 hashes from local files with `--compute-hashes`
629673
- Creates asset entries from local file names
630674
- Auto-detects platform from file names (linux, mac, win64, etc.)
675+
- **Automatic pattern detection**:
676+
- Inspects archives to detect executable locations
677+
- Recognizes nested and flat archive patterns
678+
- Automatically optimizes exe paths (only stores non-default paths)
679+
- Detects when all distributions use the same relative path
680+
- Caches downloaded assets to avoid redundant downloads when multiple programs share the same archive
631681
632682
**Example CI integration** (GitHub Actions):
633683
```yaml
@@ -662,9 +712,15 @@ python -m modflow_devtools.programs.make_registry \
662712
663713
**How it works:**
664714
- Fetches release assets from GitHub API using repo and version (tag)
665-
- Downloads assets if `--compute-hashes` is specified
715+
- Downloads assets to detect exe paths and enable pattern optimization
716+
- Optionally computes SHA256 hashes with `--compute-hashes`
666717
- Useful for testing or regenerating a registry for an existing release
667718
- No `--dists` argument needed - pulls from GitHub directly
719+
- **Automatic pattern detection** (same as Mode 1):
720+
- Inspects archives to find executables
721+
- Detects nested/flat patterns automatically
722+
- Only stores non-default exe paths in registry
723+
- Caches downloads when processing multiple programs from same release
668724
669725
**Additional options:**
670726
```bash

0 commit comments

Comments
 (0)