Skip to content

Commit aff8410

Browse files
git subrepo pull (merge) --force shared/vendored
subrepo: subdir: "shared/vendored" merged: "c29898f" upstream: origin: "https://github.com/nextstrain/shared" branch: "main" commit: "c29898f" git-subrepo: version: "0.4.9" origin: "https://github.com/ingydotnet/git-subrepo" commit: "5e0f401"
1 parent 4d05760 commit aff8410

5 files changed

Lines changed: 92 additions & 13 deletions

File tree

shared/vendored/.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ jobs:
1111
shellcheck:
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/checkout@v5
14+
- uses: actions/checkout@v6
1515
- uses: nextstrain/.github/actions/shellcheck@master

shared/vendored/.github/workflows/pre-commit.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
pre-commit:
88
runs-on: ubuntu-latest
99
steps:
10-
- uses: actions/checkout@v5
10+
- uses: actions/checkout@v6
1111
- uses: actions/setup-python@v6
1212
with:
1313
python-version: "3.12"

shared/vendored/.gitrepo

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
[subrepo]
77
remote = https://github.com/nextstrain/shared
88
branch = main
9-
commit = 43e5a6fe06c95f605cc573a7e6ad2d4a023db7b9
10-
parent = b6b1000536050c6ebcbde0c79902c16b0b76a11a
9+
commit = c29898f7c32c3f85d65db235d23a78e776f89120
10+
parent = 4d057604f9c65bae794c7bfe3f2d2514f7deee32
1111
method = merge
12-
cmdver = 0.4.6
12+
cmdver = 0.4.9

shared/vendored/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Then add the latest shared scripts to the pathogen repo by running:
2222
git subrepo clone https://github.com/nextstrain/shared shared/vendored
2323
```
2424

25-
Any future updates of sahred scripts can be pulled in with:
25+
Any future updates of shared scripts can be pulled in with:
2626

2727
```
2828
git subrepo pull shared/vendored
@@ -90,7 +90,7 @@ Scripts for supporting workflow automation that don’t really belong in any of
9090
- [notify-on-diff](scripts/notify-on-diff) - Send Slack message with diff of a local file and an S3 object
9191
- [notify-on-job-fail](scripts/notify-on-job-fail) - Send Slack message with details about failed workflow job on GitHub Actions and/or AWS Batch
9292
- [notify-on-job-start](scripts/notify-on-job-start) - Send Slack message with details about workflow job on GitHub Actions and/or AWS Batch
93-
- [notify-on-record-change](scripts/notify-on-recod-change) - Send Slack message with details about line count changes for a file compared to an S3 object's metadata `recordcount`.
93+
- [notify-on-record-change](scripts/notify-on-record-change) - Send Slack message with details about line count changes for a file compared to an S3 object's metadata `recordcount`.
9494
If the S3 object's metadata does not have `recordcount`, then will attempt to download S3 object to count lines locally, which only supports `xz` compressed S3 objects.
9595
- [notify-slack](scripts/notify-slack) - Send message or file to Slack
9696
- [s3-object-exists](scripts/s3-object-exists) - Used to prevent 404 errors during S3 file comparisons in the notify-* scripts
@@ -114,7 +114,7 @@ Potential Nextstrain CLI scripts
114114
- [upload-to-s3](scripts/upload-to-s3) - Upload file to AWS S3 bucket with compression based on file extension in S3 URL.
115115
Skips upload if the local file's hash is identical to the S3 object's metadata `sha256sum`.
116116
Adds the following user defined metadata to uploaded S3 object:
117-
- `sha256sum` - hash of the file generated by [sha256sum](sha256sum)
117+
- `sha256sum` - hash of the file generated by [sha256sum](scripts/sha256sum)
118118
- `recordcount` - the line count of the file
119119
- [download-from-s3](scripts/download-from-s3) - Download file from AWS S3 bucket with decompression based on file extension in S3 URL.
120120
Skips download if the local file already exists and has a hash identical to the S3 object's metadata `sha256sum`.
@@ -123,7 +123,7 @@ Potential Nextstrain CLI scripts
123123

124124
Snakemake workflow functions that are shared across many pathogen workflows that don’t really belong in any of our existing tools.
125125

126-
- [config.smk](snakemake/config.smk) - Shared functions for parsing workflow configs.
126+
- [config.smk](snakemake/config.smk) - Shared functions for handling workflow configs.
127127
- [remote_files.smk](snakemake/remote_files.smk) - Exposes the `path_or_url` function which will use Snakemake's storage plugins to download/upload files to remote providers as needed.
128128

129129

shared/vendored/snakemake/config.smk

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,59 @@
11
"""
2-
Shared functions to be used within a Snakemake workflow for parsing
2+
Shared functions to be used within a Snakemake workflow for handling
33
workflow configs.
44
"""
5-
import os.path
5+
import os
6+
import sys
7+
import yaml
68
from collections.abc import Callable
7-
from snakemake.io import Wildcards
89
from typing import Optional
910
from textwrap import dedent, indent
1011

1112

13+
# Set search paths for Augur
14+
if "AUGUR_SEARCH_PATHS" in os.environ:
15+
print(dedent(f"""\
16+
Using existing search paths in AUGUR_SEARCH_PATHS:
17+
18+
{os.environ["AUGUR_SEARCH_PATHS"]!r}
19+
"""), file=sys.stderr)
20+
else:
21+
# Note that this differs from the search paths used in
22+
# resolve_config_path().
23+
# This is the preferred default moving forwards, and the plan is to
24+
# eventually update resolve_config_path() to use AUGUR_SEARCH_PATHS.
25+
search_paths = [
26+
# User analysis directory
27+
Path.cwd(),
28+
29+
# Workflow defaults folder
30+
Path(workflow.basedir) / "defaults",
31+
32+
# Workflow root (contains Snakefile)
33+
Path(workflow.basedir),
34+
]
35+
36+
# This should work for majority of workflows, but we could consider doing a
37+
# more thorough search for the nextstrain-pathogen.yaml. This would likely
38+
# replicate how CLI searches for the root.¹
39+
# ¹ <https://github.com/nextstrain/cli/blob/d5e184c5/nextstrain/cli/command/build.py#L413-L420>
40+
repo_root = Path(workflow.basedir) / ".."
41+
if (repo_root / "nextstrain-pathogen.yaml").is_file():
42+
search_paths.extend([
43+
# Pathogen repo root
44+
repo_root,
45+
])
46+
47+
search_paths = [path.resolve() for path in search_paths if path.is_dir()]
48+
49+
os.environ["AUGUR_SEARCH_PATHS"] = ":".join(map(str, search_paths))
50+
51+
1252
class InvalidConfigError(Exception):
1353
pass
1454

1555

16-
def resolve_config_path(path: str, defaults_dir: Optional[str] = None) -> Callable[[Wildcards], str]:
56+
def resolve_config_path(path: str, defaults_dir: Optional[str] = None) -> Callable:
1757
"""
1858
Resolve a relative *path* given in a configuration value. Will always try to
1959
resolve *path* after expanding wildcards with Snakemake's `expand` functionality.
@@ -75,3 +115,42 @@ def resolve_config_path(path: str, defaults_dir: Optional[str] = None) -> Callab
75115
"""), " " * 4))
76116

77117
return _resolve_config_path
118+
119+
120+
def write_config(path, section=None):
121+
"""
122+
Write Snakemake's 'config' variable, or a section of it, to a file.
123+
124+
*section* is an optional list of keys to navigate to a specific section of
125+
config. If provided, only that section will be written.
126+
"""
127+
global config
128+
129+
os.makedirs(os.path.dirname(path), exist_ok=True)
130+
131+
data = config
132+
section_str = "config"
133+
134+
if section:
135+
# Navigate to the specified section
136+
for key in section:
137+
# Error if key doesn't exist
138+
if key not in data:
139+
raise Exception(f"ERROR: Key {key!r} not found in {section_str!r}.")
140+
141+
data = data[key]
142+
section_str += f".{key}"
143+
144+
# Error if value is not a mapping
145+
if not isinstance(data, dict):
146+
raise Exception(f"ERROR: {section_str!r} is not a mapping of key/value pairs.")
147+
148+
with open(path, 'w') as f:
149+
yaml.dump(data, f, sort_keys=False, Dumper=NoAliasDumper)
150+
151+
print(f"Saved {section_str!r} to {path!r}.", file=sys.stderr)
152+
153+
154+
class NoAliasDumper(yaml.SafeDumper):
155+
def ignore_aliases(self, data):
156+
return True

0 commit comments

Comments
 (0)