-
Notifications
You must be signed in to change notification settings - Fork 0
Enable creating "multi-watch" processes #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
637d478
3805e3b
a258d7a
c21cc8d
cb309af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| name: Checks | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: | ||
| - main | ||
|
|
||
| jobs: | ||
| checks: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| id-token: write | ||
| contents: read | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - uses: DeterminateSystems/determinate-nix-action@v3 | ||
|
|
||
| - uses: DeterminateSystems/flakehub-cache-action@v3 | ||
|
|
||
| - name: Flake checks (root) | ||
| run: | | ||
| nix flake check --all-systems | ||
|
|
||
| - name: Flake checks (example) | ||
| run: | | ||
| nix flake check --all-systems ./example |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,58 +1,138 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lib, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkProcessTree, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pkgs, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| command, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| paths ? [ "." ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extensions ? [ ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ignore ? [ ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| debounce ? null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package ? pkgs.watchexec, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| packages ? [ ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ... | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }@args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkWatchexecCmd = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name ? "watch", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| command, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| paths ? [ "." ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extensions ? [ ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ignore ? [ ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| debounce ? null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package ? pkgs.watchexec, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert lib.assertMsg (paths != [ ]) "mkWatchexecCmd: 'paths' must not be empty"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prefix = lib.escapeShellArgs ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ (lib.getExe package) ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ++ lib.concatMap (p: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--watch" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| p | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) paths | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ++ lib.optionals (extensions != [ ]) [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--exts" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (lib.concatStringsSep "," extensions) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ++ lib.concatMap (p: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--ignore" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| p | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) ignore | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ++ lib.optionals (debounce != null) [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--debounce" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (toString debounce) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ++ [ "--" ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "${prefix} ${command}"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert lib.assertMsg (paths != [ ]) "mkWatch: 'paths' must not be empty"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkWatch = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| command, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| paths ? [ "." ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extensions ? [ ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ignore ? [ ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| debounce ? null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package ? pkgs.watchexec, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| packages ? [ ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ... | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }@args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| taskModuleArgs = builtins.removeAttrs args [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "command" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "paths" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "extensions" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "ignore" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "debounce" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "package" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "packages" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| watchexecCmd = mkWatchexecCmd { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inherit | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| command | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| paths | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extensions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ignore | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| debounce | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| taskModuleArgs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raw = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| skip = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| packages = packages ++ [ package ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| command = watchexecCmd; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| taskModuleArgs = builtins.removeAttrs args [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "command" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "paths" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "extensions" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "ignore" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "debounce" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "package" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "packages" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkWatchMany = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name ? "watch-all", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| watchers, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package ? pkgs.watchexec, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| packages ? [ ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ... | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }@args: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert lib.assertMsg (watchers != [ ]) "mkWatchMany: 'watchers' must not be empty"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| taskModuleArgs = builtins.removeAttrs args [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "name" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "watchers" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "package" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "packages" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
lucperkins marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| watchexecPrefix = lib.escapeShellArgs ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ (lib.getExe package) ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ++ lib.concatMap (p: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--watch" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| p | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) paths | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ++ lib.optionals (extensions != [ ]) [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--exts" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (lib.concatStringsSep "," extensions) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ++ lib.concatMap (p: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--ignore" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| p | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) ignore | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ++ lib.optionals (debounce != null) [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--debounce" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (toString debounce) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ++ [ "--" ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| watchexecCmd = "${watchexecPrefix} ${command}"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Resolve each watcher's package and give it a stable process name. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| indexed = lib.imap0 (i: w: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inherit i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| watcher = w // { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package = w.package or package; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) watchers; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Process name: either user-supplied `name`, or `watcher-<index>`. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| processNameOf = { i, watcher }: watcher.name or "watcher-${toString i}"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| processes = lib.listToAttrs ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| map (entry: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name = processNameOf entry; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| command = mkWatchexecCmd entry.watcher; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| packages = [ entry.watcher.package ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) indexed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+108
to
+119
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reject duplicate watcher names before building If two watchers resolve to the same name here, 🔧 Proposed fix # Process name: either user-supplied `name`, or `watcher-<index>`.
processNameOf = { i, watcher }: watcher.name or "watcher-${toString i}";
- processes = lib.listToAttrs (
- map (entry: {
- name = processNameOf entry;
- value = {
- command = mkWatchexecCmd entry.watcher;
- packages = [ entry.watcher.package ];
- };
- }) indexed
- );
+ processNames = map processNameOf indexed;
+
+ processes =
+ assert lib.assertMsg
+ (lib.length processNames == lib.length (lib.unique processNames))
+ "mkWatchMany: watcher names must be unique";
+ lib.listToAttrs (
+ map (entry: {
+ name = processNameOf entry;
+ value = {
+ command = mkWatchexecCmd entry.watcher;
+ packages = [ entry.watcher.package ];
+ };
+ }) indexed
+ );📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| taskModuleArgs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raw = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| skip = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| command = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (mkProcessTree { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inherit | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| packages | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| processes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| + "/bin/${name}"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| taskModuleArgs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raw = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| skip = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| packages = packages ++ [ package ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| command = watchexecCmd; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inherit mkWatch mkWatchMany; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: DeterminateSystems/up
Length of output: 480
🏁 Script executed:
Repository: DeterminateSystems/up
Length of output: 83
🏁 Script executed:
Repository: DeterminateSystems/up
Length of output: 292
🏁 Script executed:
Repository: DeterminateSystems/up
Length of output: 412
🌐 Web query:
watchexec --debounce duration syntax milliseconds documentation💡 Result:
The syntax for the --debounce option in watchexec is -d, --debounce , where specifies the time to wait for new events before taking action (default: 50ms). It accepts: - A unit-less value in milliseconds (e.g., 100 for 100ms). This is deprecated, will warn, and become an error in the future. - A time span value (e.g., 5sec, 20ms, 1min 30s, 30min). Example: watchexec -d 100 command or watchexec --debounce 500ms command. Setting to 0 is highly discouraged. This is from the official watchexec manual.
Citations:
Add explicit
msunit to--debounceargument.Watchexec accepts unit-less debounce values as milliseconds but marks this form deprecated and will error on it in future versions. The
lib/process-tree.nixpath already uses"${toString w.debounce}ms", so this inconsistency makes themkWatchexecCmdhelper fragile and diverges from the established pattern.🔧 Proposed fix
++ lib.optionals (debounce != null) [ "--debounce" - (toString debounce) + "${toString debounce}ms" ]📝 Committable suggestion
🤖 Prompt for AI Agents