scout-essentials 1.8.8 → 1.9.0
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.
- checksums.yaml +4 -4
- data/.vimproject +26 -12
- data/README.md +83 -112
- data/VERSION +1 -1
- data/doc/Improvements.md +226 -0
- data/doc/StartHere.md +122 -0
- data/doc/developer/AnnotationSystem.md +184 -0
- data/doc/developer/Architecture.md +147 -0
- data/doc/developer/Configuration.md +238 -0
- data/doc/developer/CoreUtilities.md +265 -0
- data/doc/developer/DesignPrinciples.md +129 -0
- data/doc/developer/ErrorHandling.md +203 -0
- data/doc/developer/LockingAndConcurrency.md +157 -0
- data/doc/developer/PathResolution.md +200 -0
- data/doc/developer/PersistenceAndResources.md +119 -0
- data/doc/developer/StreamingModel.md +236 -0
- data/doc/user/AnnotatingData.md +202 -0
- data/doc/user/CachingResults.md +183 -0
- data/doc/user/CommandLineOptions.md +189 -0
- data/doc/user/Cookbook.md +211 -0
- data/doc/user/HandlingStreams.md +236 -0
- data/doc/user/LoggingAndProgress.md +158 -0
- data/doc/user/ProducingResources.md +177 -0
- data/doc/user/RemoteData.md +157 -0
- data/doc/user/RunningCommands.md +218 -0
- data/doc/user/WorkingWithFiles.md +217 -0
- data/lib/scout/cmd.rb +343 -40
- data/lib/scout/concurrent_stream.rb +14 -1
- data/lib/scout/indiferent_hash.rb +1 -1
- data/lib/scout/log/fingerprint.rb +13 -8
- data/lib/scout/log/progress/report.rb +1 -1
- data/lib/scout/log.rb +4 -1
- data/lib/scout/misc/format.rb +24 -0
- data/lib/scout/named_array.rb +1 -1
- data/lib/scout/open/stream.rb +2 -2
- data/lib/scout/open/util.rb +4 -0
- data/lib/scout/path/find.rb +3 -2
- data/lib/scout/persist.rb +14 -10
- data/research/annotations-data-analysis.md +206 -0
- data/research/behavior-probes.md +1925 -0
- data/research/commands-streaming-analysis.md +272 -0
- data/research/design-philosophy-analysis.md +383 -0
- data/research/doc-audit-findings.md +294 -0
- data/research/ecosystem-attribution.md +118 -0
- data/research/implementation-inventory-core.md +1029 -0
- data/research/implementation-inventory-open.md +417 -0
- data/research/implementation-inventory-path-persist-resource.md +774 -0
- data/research/io-paths-analysis.md +228 -0
- data/research/persistence-resources-analysis.md +244 -0
- data/research/synthesis-report.md +80 -0
- data/scout-essentials.gemspec +37 -15
- data/test/scout/test_cmd.rb +411 -0
- metadata +36 -14
- data/doc/Annotation.md +0 -352
- data/doc/CMD.md +0 -363
- data/doc/ConcurrentStream.md +0 -163
- data/doc/IndiferentHash.md +0 -240
- data/doc/Log.md +0 -235
- data/doc/NamedArray.md +0 -174
- data/doc/Open.md +0 -331
- data/doc/Path.md +0 -217
- data/doc/Persist.md +0 -214
- data/doc/Resource.md +0 -229
- data/doc/SimpleOPT.md +0 -236
- data/doc/TmpFile.md +0 -154
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 526dfca4b8e68e08295052cb58f86b37b346857f0eb80ada50406b2683921de6
|
|
4
|
+
data.tar.gz: b2babc599d88a5e429fbcc1aad07e3f7d62483c3a73c1b56492a5847f7238319
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5041b9210824ce7add63097c50f67745af42c212197c33816ddef4a11e187e09c75d3e342b4d9e56d4a5e6132717cc5cef078518540e74494d98f7deb819c28b
|
|
7
|
+
data.tar.gz: 695290651c1db53bf9bfcd93f1567126f4eaba1c494d46b0cc6c4bbb221c4fcdd924a5c29d0ca25d8173b2b67fdbac46cfc344d59e9d28f58f8d30f19b71ea16
|
data/.vimproject
CHANGED
|
@@ -6,20 +6,34 @@ scout-essentials=/$PWD filter="*.rb *.txt *.md *.conf *.yaml" {
|
|
|
6
6
|
|
|
7
7
|
review
|
|
8
8
|
document.rb
|
|
9
|
+
documentation
|
|
10
|
+
|
|
11
|
+
cmd
|
|
12
|
+
|
|
13
|
+
timeout
|
|
9
14
|
}
|
|
10
15
|
doc=doc{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
Improvements.md
|
|
17
|
+
StartHere.md
|
|
18
|
+
user=user{
|
|
19
|
+
AnnotatingData.md
|
|
20
|
+
CachingResults.md
|
|
21
|
+
CommandLineOptions.md
|
|
22
|
+
Cookbook.md
|
|
23
|
+
HandlingStreams.md
|
|
24
|
+
LoggingAndProgress.md
|
|
25
|
+
ProducingResources.md
|
|
26
|
+
RunningCommands.md
|
|
27
|
+
WorkingWithFiles.md
|
|
28
|
+
}
|
|
29
|
+
developer=developer{
|
|
30
|
+
AnnotationSystem.md
|
|
31
|
+
Architecture.md
|
|
32
|
+
DesignPrinciples.md
|
|
33
|
+
PathResolution.md
|
|
34
|
+
PersistenceAndResources.md
|
|
35
|
+
StreamingModel.md
|
|
36
|
+
}
|
|
23
37
|
}
|
|
24
38
|
lib=lib {
|
|
25
39
|
scout-essentials.rb
|
data/README.md
CHANGED
|
@@ -1,136 +1,107 @@
|
|
|
1
1
|
# scout-essentials
|
|
2
2
|
|
|
3
|
-
scout-essentials is
|
|
3
|
+
scout-essentials is a small Ruby library (gem `scout-essentials`, [VERSION](VERSION)) that provides the shared substrate the other Scout repositories are built on: path and resource resolution, persistence/caching, file and stream I/O, command execution, streaming, annotations, logging and progress reporting, configuration, CLI-option parsing, remote data access and locking.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It deliberately contains no CLI executable, no TSV handling, no workflow engine and no job scheduler. Runtime dependencies are only `term-ansicolor`, `yaml`, `rake` and `listen` ([scout-essentials.gemspec](scout-essentials.gemspec)); it depends on no other scout-family or rbbt-family gem at runtime.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Central abstractions
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
| Abstraction | What it is |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `Path` / `Resource` | `Path` is a `String` carrying annotations that resolves logical names (`data/config.yaml`) to real locations through configurable *path maps*; `Resource` modules declare claims over those paths and `produce` them on demand |
|
|
12
|
+
| `Persist` | typed on-disk caching: `Persist.persist(key, type) { ... }` with per-type serialization drivers, staleness invalidation (`:update`/`:check`), an in-memory cache and lock-protected recompute |
|
|
13
|
+
| `Open` | one interface for local, compressed (`.gz`/`.bgz`/`.zip`) and remote (`http(s)://`, `ssh:`) file and stream I/O, including atomic `sensible_write` and the `wget`/`rsync` remote cache |
|
|
14
|
+
| `CMD` | the subprocess layer: `CMD.cmd` for shell and no-shell commands, stdin piping, timeouts, stderr capture and external-tool bootstrap |
|
|
15
|
+
| `ConcurrentStream` | an `IO` extended with the producer threads/pids that feed it, plus join/abort callbacks — the lifecycle layer behind every pipe |
|
|
16
|
+
| `Annotation` / `AnnotatedObject` / `AnnotatedArray` | a mixin that attaches named metadata to ordinary Ruby objects (Strings, Arrays, Hashes) without changing their class; the mechanism `Path`, `Resource` and `NamedArray` are built on |
|
|
17
|
+
| `Log` / `Log::ProgressBar` | a severity-gated logger writing to STDERR (constants `Log::DEBUG … Log::NONE`) plus stacked progress bars rendered in the same place; colors via `term-ansicolor` |
|
|
18
|
+
| `Scout::Config` | a flat `key -> [tokens, value]` registry where, among the entries whose token matches the caller's context, the one with the lowest priority number wins |
|
|
19
|
+
| `SOPT` | a minimal option parser: options declared as a single string, a **destructive** consumer that edits `ARGV` in place, no subcommands and no coercion beyond booleans |
|
|
20
|
+
| `TmpFile` | scratch files and directories under `$HOME/tmp/scout`, with `·`-flattened names and a 150-character cap |
|
|
21
|
+
| `IndiferentHash` | a `Hash` extended so String and Symbol keys are interchangeable, plus the options-processing helpers built on it |
|
|
22
|
+
| `NamedArray` | Arrays with named positions (`NamedArray.setup(arr, [:a, :b])`), giving both positional and field-name access |
|
|
23
|
+
| `Misc` | small load-bearing helpers: the `Misc.format` family, `timespan`, digests, `insist`, filesystem and process utilities |
|
|
24
|
+
| `Lockfile` / `Open.lock` | `Open.lock(file, &block)` is the locking primitive, built on the vendored `Lockfile` at `lib/scout/open/lock/lockfile.rb`; there are three lock namespaces under `$HOME/.scout/tmp` |
|
|
10
25
|
|
|
11
|
-
-
|
|
12
|
-
- Robust file/stream I/O and remote access: `Open`
|
|
13
|
-
- File/path abstraction and package-oriented lookup: `Path`, `Resource`
|
|
14
|
-
- Atomic persistence and caching: `Persist`, `TmpFile`
|
|
15
|
-
- Logging, color output and progress reporting: `Log`
|
|
16
|
-
- Lightweight typed annotations on arbitrary objects: `Annotation`, `NamedArray`
|
|
17
|
-
- Flexible indifferent Hash and option helpers: `IndiferentHash`, `SimpleOPT` (SOPT)
|
|
26
|
+
`require 'scout-essentials'` is the only entry point (`lib/scout-essentials.rb`); it loads the modules above plus `Open::NamedStream` and the exceptions (`Aborted`, `DontClose`, `ParameterException`, …). `NamedArray` and `Hook` are not auto-loaded and must be required explicitly.
|
|
18
27
|
|
|
19
|
-
|
|
28
|
+
## Getting started
|
|
20
29
|
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Documentation
|
|
24
|
-
|
|
25
|
-
Full module-level documentation is shipped in `doc/`. The most important documents are:
|
|
26
|
-
|
|
27
|
-
- doc/Annotation.md — add typed annotations to objects and arrays; AnnotatedArray
|
|
28
|
-
- doc/CMD.md — process execution, streaming, tool discovery and helper wrappers
|
|
29
|
-
- doc/ConcurrentStream.md — concurrent stream lifecycle, joining, aborting and callbacks
|
|
30
|
-
- doc/IndiferentHash.md — string/symbol indifferent Hash helpers and options utilities
|
|
31
|
-
- doc/Log.md — logging, colors, fingerprinting and ProgressBar
|
|
32
|
-
- doc/NamedArray.md — small record-like arrays with named fields and fuzzy matching
|
|
33
|
-
- doc/Open.md — unified file/stream I/O, remote fetch (wget/ssh), atomic writes, sync
|
|
34
|
-
- doc/Path.md — Path helpers, mapping, finding and extension utilities
|
|
35
|
-
- doc/Persist.md — typed serialization, persistence/caching and `Persist.persist`
|
|
36
|
-
- doc/Resource.md — resource production, claim/produce and rake-based producers
|
|
37
|
-
- doc/SimpleOPT.md — small option parsing and usage generation (SOPT)
|
|
38
|
-
- doc/TmpFile.md — temporary file/dir helpers and stable cache path generator
|
|
39
|
-
|
|
40
|
-
Open those files for detailed API descriptions, examples and notes.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Quick start (examples)
|
|
45
|
-
|
|
46
|
-
These short snippets show typical usage patterns — the docs in `doc/` contain more detail and examples.
|
|
47
|
-
|
|
48
|
-
Annotation:
|
|
49
30
|
```ruby
|
|
50
|
-
|
|
51
|
-
extend Annotation
|
|
52
|
-
annotation :code, :note
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
s = "hello"
|
|
56
|
-
Tag.setup(s, :code) # s.code -> :code
|
|
57
|
-
s2 = "other"
|
|
58
|
-
s.annotate(s2) # copies annotations
|
|
59
|
-
```
|
|
31
|
+
require 'scout-essentials'
|
|
60
32
|
|
|
61
|
-
Open
|
|
62
|
-
|
|
63
|
-
|
|
33
|
+
Open.write('tmp/data.txt', "1\n2\n") # creates parent directories
|
|
34
|
+
Log.info "wrote 2 lines"
|
|
35
|
+
Persist.persist('count', :integer) { Open.read('tmp/data.txt').lines.count }
|
|
64
36
|
```
|
|
65
37
|
|
|
66
|
-
|
|
67
|
-
```ruby
|
|
68
|
-
value = Persist.persist("my-result", :json, dir: Path.setup("var/cache")) do
|
|
69
|
-
expensive_computation()
|
|
70
|
-
end
|
|
71
|
-
```
|
|
38
|
+
Documentation lives in the [`doc/`](doc/StartHere.md) directory — start with [doc/StartHere.md](doc/StartHere.md).
|
|
72
39
|
|
|
73
|
-
|
|
74
|
-
```ruby
|
|
75
|
-
io = CMD.cmd("tail -n 100", :in => some_file_io, :pipe => true)
|
|
76
|
-
io2 = CMD.cmd("grep foo", :in => io, :pipe => true)
|
|
77
|
-
puts io2.read
|
|
78
|
-
io2.join
|
|
79
|
-
```
|
|
40
|
+
## Relationship to the other Scout repositories
|
|
80
41
|
|
|
81
|
-
|
|
82
|
-
```ruby
|
|
83
|
-
Log::ProgressBar.with_bar(100, desc: "Working") do |bar|
|
|
84
|
-
100.times { bar.tick; work_item }
|
|
85
|
-
end
|
|
86
|
-
```
|
|
42
|
+
scout-essentials is the lowest layer of the Scout stack; everything above it is implemented in separate repositories:
|
|
87
43
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
p = Path.setup("share/data/myfile", 'mypkg')
|
|
93
|
-
p.produce
|
|
94
|
-
Open.read(p)
|
|
95
|
-
```
|
|
44
|
+
- **scout-gear** — adds TSV, `Workflow`/`Task`/`Step`, the `scout` CLI and `scout_commands/` dispatch, and the scheduler/HPC layer (SLURM/PBS/LSF, orchestrators) on top of essentials. It declares `scout-essentials` as a runtime dependency.
|
|
45
|
+
- **scout-camp** — deploys workflows to the cloud: offsite/terraform/AWS provisioning around the CLI. Its bin loads scout-gear's `bin/scout`; the scheduler logic itself lives in gear.
|
|
46
|
+
- **scout-rig** — consumes essentials' `Path`/`Resource` machinery at the code level (`require 'scout'`, `Path.add_path`); its gemspec does not declare the essentials edge.
|
|
47
|
+
- **scout-ai** — reaches essentials transitively, via scout-rig and its own `require 'scout'`; it declares no direct dependency on essentials.
|
|
96
48
|
|
|
97
|
-
|
|
49
|
+
Attribution facts worth keeping straight (verified against installed gem sources; see the attribution table in [Architecture](doc/developer/Architecture.md)):
|
|
98
50
|
|
|
99
|
-
|
|
51
|
+
| Concept | Where it actually lives |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `TSV`, `TSV::Dumper`, `Annotation.tsv`, `Workflow`/`Task`/`Step`, `.info` files, the `scout` CLI and `scout_commands/` | scout-gear |
|
|
54
|
+
| scheduler / HPC (SLURM, PBS, LSF, orchestrators) | scout-gear (scout-camp adds the cloud/offside deploy layer) |
|
|
55
|
+
| `Misc.notify` / `Misc.send_email` and the `Bgzf` block API | legacy rbbt-util **only** — scout-essentials references them without a require or gemspec edge, so they are `NoMethodError`/`NameError` in an essentials-only install |
|
|
56
|
+
| `deep_indifferent` | does not exist anywhere in the audited ecosystem |
|
|
57
|
+
| rbbt-util `require_instead` shims | rbbt-util 6.0.5 redirects ~30 requires onto scout files; the *dependency direction* at gemspec level is UNVERIFIED |
|
|
100
58
|
|
|
101
|
-
|
|
59
|
+
## Documentation
|
|
102
60
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
61
|
+
22 Markdown pages under [`doc/`](doc/StartHere.md).
|
|
62
|
+
|
|
63
|
+
Entry points:
|
|
64
|
+
|
|
65
|
+
- [Start Here](doc/StartHere.md) — installation, the single require, what loads and what does not, what is *not* in this repo
|
|
66
|
+
- [Improvements](doc/Improvements.md) — running log of known misbehaviours (bug log, not a roadmap)
|
|
67
|
+
|
|
68
|
+
User guides:
|
|
69
|
+
|
|
70
|
+
- [Annotating Data](doc/user/AnnotatingData.md) — attaching metadata to objects
|
|
71
|
+
- [Working with Files](doc/user/WorkingWithFiles.md) — `Open` I/O, compression, grepping, atomic writes, locking, `TmpFile`
|
|
72
|
+
- [Remote Data](doc/user/RemoteData.md) — HTTP(S)/FTP/SSH fetch, the URL cache, rsync helpers
|
|
73
|
+
- [Running Commands](doc/user/RunningCommands.md) — `CMD.cmd`, piping, timeouts, stderr, tool bootstrap
|
|
74
|
+
- [Handling Streams](doc/user/HandlingStreams.md) — using `ConcurrentStream` objects: join, abort, callbacks
|
|
75
|
+
- [Caching Results](doc/user/CachingResults.md) — `Persist.persist`, serialization types, invalidation, in-memory cache
|
|
76
|
+
- [Producing Resources](doc/user/ProducingResources.md) — the `claim` syntax and `produce`
|
|
77
|
+
- [Logging and Progress](doc/user/LoggingAndProgress.md) — `Log`, severity, colors, fingerprints, progress bars
|
|
78
|
+
- [Command-Line Options](doc/user/CommandLineOptions.md) — `SOPT`
|
|
79
|
+
- [Cookbook](doc/user/Cookbook.md) — short executed recipes combining the modules
|
|
80
|
+
|
|
81
|
+
Developer guides:
|
|
82
|
+
|
|
83
|
+
- [Architecture](doc/developer/Architecture.md) — module dependency graph, load order, ecosystem boundaries
|
|
84
|
+
- [Design Principles](doc/developer/DesignPrinciples.md) — composition by annotation, and the other repo-wide conventions
|
|
85
|
+
- [Annotation System](doc/developer/AnnotationSystem.md) — the internals of annotations
|
|
86
|
+
- [Path Resolution](doc/developer/PathResolution.md) — path maps, map order, `find`/`follow`, `Resource#method_missing`
|
|
87
|
+
- [Persistence and Resources](doc/developer/PersistenceAndResources.md) — the `Persist` and `Resource#produce` write contracts
|
|
88
|
+
- [Streaming Model](doc/developer/StreamingModel.md) — how `ConcurrentStream` is built and how errors travel
|
|
89
|
+
- [Configuration](doc/developer/Configuration.md) — `Scout::Config` token priorities
|
|
90
|
+
- [Error Handling](doc/developer/ErrorHandling.md) — the exception taxonomy and the control-flow signals
|
|
91
|
+
- [Locking and Concurrency](doc/developer/LockingAndConcurrency.md) — the vendored `Lockfile` and the three lock namespaces
|
|
92
|
+
- [Core Utilities](doc/developer/CoreUtilities.md) — `IndiferentHash`, `NamedArray`, `Misc`, `TmpFile` naming, `Hook`
|
|
93
|
+
|
|
94
|
+
## Development and testing
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
bundle install
|
|
98
|
+
rake test # whole suite
|
|
99
|
+
rake test TEST=test/scout/test_open.rb # one file
|
|
100
|
+
ruby -Ilib -Itest test/scout/test_misc.rb # run a file directly
|
|
107
101
|
```
|
|
108
102
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
## Related projects
|
|
114
|
-
|
|
115
|
-
scout-essentials is intentionally focused on low-level primitives. Higher-level, domain-specific functionality is implemented in companion projects maintained on the mikisvaz GitHub account (look for repositories named `scout-gear`, `scout-ai`, etc.). Those packages build on what you find here to provide workflows, tools and integrations.
|
|
116
|
-
|
|
117
|
-
GitHub: https://github.com/mikisvaz
|
|
118
|
-
Look for repositories that begin with `scout-` (e.g. `scout-gear`, `scout-ai`).
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
## Contributing
|
|
123
|
-
|
|
124
|
-
Contributions and improvements are welcome. Please follow the repository contribution guidelines (if present) or submit issues / pull requests on the project repository.
|
|
125
|
-
|
|
126
|
-
If you extend or reuse code from this package in companion packages, prefer to keep core primitives here and implement domain logic in separate modules/packages (as done by the Scout ecosystem).
|
|
127
|
-
|
|
128
|
-
---
|
|
103
|
+
The `test` task is defined in the [Rakefile](Rakefile) (`Rake::TestTask`, pattern `test/**/test_*.rb`, which matches 49 files on disk: 47 test files (one of which, `test/scout/log/test_color.rb`, is empty) plus the two `test_helper.rb` files, one of which itself defines `TestMiscHelper`). Tests are plain `Test::Unit` and mirror the `lib/scout/` layout. The gemspec is generated by juwelier from the Rakefile — regenerate it with `rake gemspec` rather than editing it.
|
|
129
104
|
|
|
130
105
|
## License
|
|
131
106
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
If you need help finding a specific API, open the corresponding file in `doc/` (listed above) or search the `lib/` tree for concrete implementations and tests in `test/` for usage examples.
|
|
107
|
+
MIT-style license, Copyright (c) 2023 Miguel Vazquez — see [LICENSE.txt](LICENSE.txt).
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.9.0
|
data/doc/Improvements.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Improvements
|
|
2
|
+
|
|
3
|
+
Actionable recommendations for improving scout-essentials code, discovered
|
|
4
|
+
during the documentation effort. Each item includes a description, impact,
|
|
5
|
+
and suggested action.
|
|
6
|
+
|
|
7
|
+
## Status legend
|
|
8
|
+
|
|
9
|
+
- 🔴 **Bug** — Incorrect behavior that should be fixed.
|
|
10
|
+
- 🟡 **Improvement** — Works, but could be better.
|
|
11
|
+
- 🟢 **Done** — Already resolved.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## High priority
|
|
16
|
+
|
|
17
|
+
### I1. 🟡 ConcurrentStream join can deadlock with multi-stage pipelines
|
|
18
|
+
|
|
19
|
+
When joining a multi-stage pipeline (producer → filter → consumer), if the
|
|
20
|
+
producer is joined before the consumer has drained the pipe buffer, the
|
|
21
|
+
join can deadlock because the pipe buffer fills and the producer blocks.
|
|
22
|
+
|
|
23
|
+
**Impact:** Pipeline hangs in production.
|
|
24
|
+
|
|
25
|
+
**Suggested action:** Document the correct join order (consumer first,
|
|
26
|
+
producer last) and consider adding automatic consumer-joins-producer
|
|
27
|
+
chaining via `autojoin`.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
### I2. 🟡 Persist persistence_path can collide for short keys
|
|
32
|
+
|
|
33
|
+
For short, filesystem-safe keys, Persist uses the key directly as the
|
|
34
|
+
filename. If two modules use the same short key, the cache files collide.
|
|
35
|
+
|
|
36
|
+
**Impact:** Subtle data corruption — one computation overwrites another's
|
|
37
|
+
cache.
|
|
38
|
+
|
|
39
|
+
**Suggested action:** Namespace cache paths by the calling module or
|
|
40
|
+
library. Consider prefixing with a digest of the caller's file path.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### I3. 🟡 TmpFile cleanup not guaranteed on signal (SIGTERM/SIGKILL)
|
|
45
|
+
|
|
46
|
+
TmpFile's `with_file` and `with_dir` use `ensure` blocks for cleanup.
|
|
47
|
+
However, SIGTERM and SIGKILL bypass `ensure`, leaving temporary files on
|
|
48
|
+
disk.
|
|
49
|
+
|
|
50
|
+
**Impact:** Temporary file accumulation over time in long-running services.
|
|
51
|
+
|
|
52
|
+
**Suggested action:** Register a PID-based temp directory and add a
|
|
53
|
+
periodic cleanup task. Consider using `at_exit` for graceful shutdown.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
### I4. 🟡 Open remote read via SSH not documented or tested
|
|
58
|
+
|
|
59
|
+
Open supports reading from SSH paths (`user@host:path`), but this path is
|
|
60
|
+
not well documented, and test coverage is limited.
|
|
61
|
+
|
|
62
|
+
**Impact:** Users may not know SSH support exists; regressions may go
|
|
63
|
+
undetected.
|
|
64
|
+
|
|
65
|
+
**Suggested action:** Document SSH support in [Working with Files](user/WorkingWithFiles.md).
|
|
66
|
+
Add tests. Add retry logic for network failures.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Medium priority
|
|
71
|
+
|
|
72
|
+
### I5. 🟡 No central registry for path maps
|
|
73
|
+
|
|
74
|
+
Path maps are configured globally via `Path.path_maps` and
|
|
75
|
+
`Path.map_order`. There is no central registry where applications can
|
|
76
|
+
register their maps in a namespace-safe way.
|
|
77
|
+
|
|
78
|
+
**Impact:** Map name collisions between applications.
|
|
79
|
+
|
|
80
|
+
**Suggested action:** Introduce namespaced map registration: e.g.,
|
|
81
|
+
`Path.add_path("myapp:data", "/opt/myapp/{PATH}")`.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
### I6. 🟡 IndiferentHash deep_indifferent not recursive by default
|
|
86
|
+
|
|
87
|
+
`IndiferentHash.setup` makes the top-level hash key-indifferent, but nested
|
|
88
|
+
hashes are not automatically converted. `deep_indifferent` must be called
|
|
89
|
+
explicitly.
|
|
90
|
+
|
|
91
|
+
**Impact:** Surprising behavior when accessing nested keys with mixed
|
|
92
|
+
string/symbol access.
|
|
93
|
+
|
|
94
|
+
**Suggested action:** Document this clearly. Consider making
|
|
95
|
+
`deep_indifferent` the default behavior or providing a clearer alternative.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
### I7. 🟡 Path#find returns self even when file doesn't exist (for located paths)
|
|
100
|
+
|
|
101
|
+
When a path is "located" (starts with `/`, `~`, or `./`), `find` returns
|
|
102
|
+
`self` even if the file doesn't exist. This differs from non-located paths
|
|
103
|
+
where `find` may return nil when no map resolves.
|
|
104
|
+
|
|
105
|
+
**Impact:** Callers may assume `find` returns nil for nonexistent files.
|
|
106
|
+
|
|
107
|
+
**Suggested action:** Document this behavior clearly. Consider adding a
|
|
108
|
+
strict mode where `find` returns nil for nonexistent files regardless of
|
|
109
|
+
location status.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### I8. 🟡 Resource production failures leave no trace
|
|
114
|
+
|
|
115
|
+
When a Resource claim's production fails (e.g., download fails), the
|
|
116
|
+
production is abandoned silently. No log message is emitted beyond the
|
|
117
|
+
exception itself.
|
|
118
|
+
|
|
119
|
+
**Impact:** Hard to debug resource production issues in production.
|
|
120
|
+
|
|
121
|
+
**Suggested action:** Add `Log.warn` or `Log.error` calls in Resource
|
|
122
|
+
production error paths.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### I9. 🟡 CMD tool registry not namespaced
|
|
127
|
+
|
|
128
|
+
CMD tool registration (`CMD.add_tool`) uses a global registry. Multiple
|
|
129
|
+
applications using scout-essentials share the same tool registry.
|
|
130
|
+
|
|
131
|
+
**Impact:** Tool name collisions.
|
|
132
|
+
|
|
133
|
+
**Suggested action:** Namespace tool registration by application or provide
|
|
134
|
+
a scoped registry.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### I10. 🟡 No user-facing guide on custom Annotation modules
|
|
139
|
+
|
|
140
|
+
While the annotation system is powerful, there was no user-facing guide on
|
|
141
|
+
how to define and use custom annotation modules for application-specific
|
|
142
|
+
metadata.
|
|
143
|
+
|
|
144
|
+
**Impact:** Users may subclass instead of annotate, missing the idiom.
|
|
145
|
+
|
|
146
|
+
**Suggested action:** The new [Annotating Data](user/AnnotatingData.md)
|
|
147
|
+
guide covers this. It should be promoted more prominently.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Low priority
|
|
152
|
+
|
|
153
|
+
### I11. 🟢 Done — Documentation reorganized into three layers
|
|
154
|
+
|
|
155
|
+
The documentation has been reorganized from a flat class-by-class structure
|
|
156
|
+
into a three-layer structure (user/developer/research).
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### I12. 🟡 Misc module is a catch-all
|
|
161
|
+
|
|
162
|
+
The `Misc` module (`lib/scout/misc/`) contains many unrelated utilities:
|
|
163
|
+
format, digest, math, system, hooks, monitor. This is a code smell.
|
|
164
|
+
|
|
165
|
+
**Impact:** Hard to find utilities; import surface too broad.
|
|
166
|
+
|
|
167
|
+
**Suggested action:** Consider splitting into separately named modules or
|
|
168
|
+
documenting the sub-namespace usage more clearly.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### I13. 🟡 No CI configuration visible
|
|
173
|
+
|
|
174
|
+
No CI configuration (`.travis.yml`, `.github/workflows/`, etc.) is visible
|
|
175
|
+
in the repository.
|
|
176
|
+
|
|
177
|
+
**Impact:** Tests may not run automatically on commit.
|
|
178
|
+
|
|
179
|
+
**Suggested action:** Add a CI configuration to run tests on commit.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### I14. 🟡 Benchmarking suite absent
|
|
184
|
+
|
|
185
|
+
There is no benchmarking suite to track performance across releases.
|
|
186
|
+
|
|
187
|
+
**Impact:** Performance regressions may go unnoticed.
|
|
188
|
+
|
|
189
|
+
**Suggested action:** Add a simple benchmark suite using `benchmark/ips`
|
|
190
|
+
for key operations (Open.read, Persist.persist, Path.find).
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
### I15. 🟡 Annotation `setup` with frozen objects creates a duplicate
|
|
195
|
+
|
|
196
|
+
When `setup` is called on a frozen object, it duplicates the object before
|
|
197
|
+
extending it. The original frozen object is not modified.
|
|
198
|
+
|
|
199
|
+
**Impact:** This is correct behavior but can surprise callers who expect
|
|
200
|
+
the same object to be returned.
|
|
201
|
+
|
|
202
|
+
**Suggested action:** Document this clearly in the Annotation documentation
|
|
203
|
+
and user guides.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
### I16. 🟡 Persist.persist can raise if cache_dir not writable
|
|
208
|
+
|
|
209
|
+
If `Persist.cache_dir` is not writable, `persist` will fail with a
|
|
210
|
+
permissions error.
|
|
211
|
+
|
|
212
|
+
**Impact:** Can break production when cache_dir is on a read-only
|
|
213
|
+
filesystem.
|
|
214
|
+
|
|
215
|
+
**Suggested action:** Document this requirement and consider falling back
|
|
216
|
+
to a temporary cache dir or raising a clearer error message.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Summary
|
|
221
|
+
|
|
222
|
+
| Category | Count |
|
|
223
|
+
|----------|-------|
|
|
224
|
+
| Bugs (🔴) | 0 |
|
|
225
|
+
| Improvements (🟡) | 15 |
|
|
226
|
+
| Done (🟢) | 1 |
|
data/doc/StartHere.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Start Here
|
|
2
|
+
|
|
3
|
+
`scout-essentials` is the lowest layer of the Scout stack: a Ruby gem of
|
|
4
|
+
small, composable modules for paths, file I/O, command execution, caching,
|
|
5
|
+
annotations, logging, progress bars and option parsing. It deliberately
|
|
6
|
+
contains **no** CLI, no TSV handling, no workflow engine and no job
|
|
7
|
+
scheduler — those live in other repos (see
|
|
8
|
+
[Architecture](developer/Architecture.md), attribution table).
|
|
9
|
+
|
|
10
|
+
## Installation and first require
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
gem 'scout-essentials' # Gemfile
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
require 'scout-essentials'
|
|
18
|
+
Path.setup('tmp/data.txt') # => annotated String
|
|
19
|
+
Open.write('tmp/data.txt', "1\n2\n")
|
|
20
|
+
Log.info "wrote 2 lines"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### What that single require actually loads
|
|
24
|
+
|
|
25
|
+
`lib/scout-essentials.rb` is the whole surface — in this order:
|
|
26
|
+
|
|
27
|
+
| require | gives you |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `scout/exceptions` | `Aborted`, `DontClose`, `DontPersist`, `ParameterException`, … |
|
|
30
|
+
| `scout/indiferent_hash` | `IndiferentHash` |
|
|
31
|
+
| `scout/tmpfile` | `TmpFile` (also pulls `scout/open`) |
|
|
32
|
+
| `scout/log` | `Log`, `Log::ProgressBar` |
|
|
33
|
+
| `scout/path` | `Path`, `Resource`-adjacent path helpers |
|
|
34
|
+
| `scout/simple_opt` | `SOPT` |
|
|
35
|
+
| `scout/resource` | `Resource`, `Scout::Resource` |
|
|
36
|
+
| `scout/resource/scout` | scout resource defaults (`pkgdir`, `subdir`) |
|
|
37
|
+
| `scout/persist` | `Persist` |
|
|
38
|
+
| `scout/config` | `Scout::Config` |
|
|
39
|
+
|
|
40
|
+
Transitive pulls: `scout/open` (hence `Open`, `CMD`, `NamedStream`),
|
|
41
|
+
`scout/annotation` (hence `Annotation`), `scout/misc` (via
|
|
42
|
+
`scout/tmpfile`/`scout/open`). Notably **not** loaded by the umbrella
|
|
43
|
+
require (verified by probe `tmp/rewrite_C/probe_01_requires.rb`):
|
|
44
|
+
|
|
45
|
+
- `NamedArray` — `require 'scout/named_array'`
|
|
46
|
+
- `Hook` (a **top-level** `module Hook`, *not* `Misc::Hook`) —
|
|
47
|
+
`require 'scout/misc/hook'`
|
|
48
|
+
|
|
49
|
+
`Scout::Config` is loaded but you must use the namespaced name.
|
|
50
|
+
|
|
51
|
+
## What is *not* in this repository
|
|
52
|
+
|
|
53
|
+
| Not here | Where it lives |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| `bin/` CLI, `scout` executable, `scout_commands/` | scout-gear |
|
|
56
|
+
| TSV, `TSV` parsing, `Annotation.tsv` | scout-gear |
|
|
57
|
+
| `Workflow`, `Step`, job dependencies | scout-gear / scout-rig |
|
|
58
|
+
| scheduler, HPC/DRMAA/LSF/SLURM orchestration | scout-workflows |
|
|
59
|
+
| `notify`, `send_email` | rbbt-util |
|
|
60
|
+
| Bgzf (`Open.bgunzip` is here, the Bgzf block API is not) | scout-gear |
|
|
61
|
+
| `deep_indifferent` | nowhere — it does not exist |
|
|
62
|
+
|
|
63
|
+
See the [attribution table in Architecture](developer/Architecture.md) for
|
|
64
|
+
the full map.
|
|
65
|
+
|
|
66
|
+
## Bug log
|
|
67
|
+
|
|
68
|
+
[Improvements.md](Improvements.md) is the running log of known
|
|
69
|
+
misbehaviours that were documented during the audit
|
|
70
|
+
(`TmpFile.with_file` leaking on exception, `Persist` lock races, …). It is
|
|
71
|
+
**not** a roadmap; it records what the code actually does versus what you
|
|
72
|
+
might expect.
|
|
73
|
+
|
|
74
|
+
## Development and testing
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
bundle install
|
|
78
|
+
rake test # runs the whole suite (49 test files)
|
|
79
|
+
rake test TEST=test/scout/test_open.rb
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The `test` task is defined at `Rakefile:26-28`; the suite lives under
|
|
83
|
+
`test/scout/**` and mirrors the module layout (`test_path.rb`,
|
|
84
|
+
`test_open.rb`, `test_persist.rb`, `test_annotation.rb`, …). Tests are
|
|
85
|
+
plain `Test::Unit` and can be run directly:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
ruby -Ilib -Itest test/scout/test_misc.rb
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Where to go next
|
|
92
|
+
|
|
93
|
+
**User guides** — how to *use* the library:
|
|
94
|
+
|
|
95
|
+
- [Annotating Data](user/AnnotatingData.md)
|
|
96
|
+
- [Working with Files](user/WorkingWithFiles.md)
|
|
97
|
+
- [Remote Data](user/RemoteData.md)
|
|
98
|
+
- [Running Commands](user/RunningCommands.md)
|
|
99
|
+
- [Handling Streams](user/HandlingStreams.md)
|
|
100
|
+
- [Caching Results](user/CachingResults.md)
|
|
101
|
+
- [Producing Resources](user/ProducingResources.md)
|
|
102
|
+
- [Logging and Progress](user/LoggingAndProgress.md)
|
|
103
|
+
- [Command-Line Options](user/CommandLineOptions.md)
|
|
104
|
+
- [Cookbook](user/Cookbook.md)
|
|
105
|
+
|
|
106
|
+
**Developer guides** — how the library *works*:
|
|
107
|
+
|
|
108
|
+
- [Architecture](developer/Architecture.md)
|
|
109
|
+
- [Design Principles](developer/DesignPrinciples.md)
|
|
110
|
+
- [Annotation System](developer/AnnotationSystem.md)
|
|
111
|
+
- [Path Resolution](developer/PathResolution.md)
|
|
112
|
+
- [Persistence and Resources](developer/PersistenceAndResources.md)
|
|
113
|
+
- [Streaming Model](developer/StreamingModel.md)
|
|
114
|
+
- [Configuration](developer/Configuration.md)
|
|
115
|
+
- [Error Handling](developer/ErrorHandling.md)
|
|
116
|
+
- [Locking and Concurrency](developer/LockingAndConcurrency.md)
|
|
117
|
+
- [Core Utilities](developer/CoreUtilities.md)
|
|
118
|
+
|
|
119
|
+
**Research artifacts** (`../research/`) are non-normative supporting
|
|
120
|
+
material: `research/doc_audit/*` holds the per-claim audit ledgers,
|
|
121
|
+
`research/behavior-probes.md` the probe transcripts, and
|
|
122
|
+
`research/implementation-inventory-*.md` the file:line inventories.
|