src/ws/hop.bend

ezx@1.10.0.0 · 113 lines · 0 definitions

1# ws/hop: where a whole-workspace command runs (EZ-WS-2). `ez lock`, `ez
2# fetch` and `ez doctor` act on the whole workspace from any member, so run in
3# a member they run again at the root, with the same words, and end as that
4# run ends. Run at the root, or in a project of its own, they run where they
5# are. Which of the three it is, and the line that runs again, are decided
6# here; ws/run.bend only reads what the search needs and runs what this says.
7import Base
8import ezx@1.10.0.0/src/pkg/path.bend as P
9import ezx@1.10.0.0/src/ws/workspace.bend as W
10import ezx@1.10.0.0/src/ws/root.bend as R
11
12# where a command runs: where it is, again at the root's directory, or
13# nowhere, because the search for the root was refused
14type Hop is Data:
15  Here{}
16  Hop{dir: String}
17  Stop{why: String}
18
19# the root a member found, once it is known whether that is where ez runs
20def hop.within(+top: String, root: List<&2, String>, rel: List<&2, String>) -> Hop:
21  match rel:
22    case []:
23      Here{}
24    case _hd <> _tl:
25      Hop{P.join(top, W.segs.text(root))}
26
27# where a command runs, from what the search found. `top` is the top of the
28# checkout, as git printed it.
29def hop(+top: String, found: R.Found) -> Hop:
30  match found:
31    case R.Alone{}:
32      Here{}
33    case R.Within{root, rel}:
34      hop.within(top, root, rel)
35    case R.Broken{why}:
36      Stop{why}
37
38# the program as it was started, found again from another directory: a path
39# with a `/` in it taken from where ez was started, and a bare name looked up
40# on PATH as it was
41def program(+pwd: String, +prog: String) -> String:
42  Bool.pick(String, String.contains(prog, "/"), P.anchor(pwd, prog), prog)
43
44# the line that runs the same command at the root: a shell that changes to the
45# root's directory and hands every word on as it was, with no word read by the
46# shell, which takes them as its positional parameters
47def line(+dir: String, +pwd: String, +prog: String, words: List<&2, String>) -> List<&2, String>:
48  List.append(&2, String,
49    ["sh", "-c", "cd -- \"$1\" && shift && exec \"$@\"", "sh", dir, program(pwd, prog)], words)
50
51# ---------------------------------------------------------------------------
52# the library a member's own command uses
53
54# the BEND_LIB a command run in a member uses: the one the environment sets,
55# or, when it sets none, the root's `.ez/lib`, where the workspace's lock lays
56# its packages
57type Lib is Data:
58  Keep{}
59  Set{lib: String}
60
61# the root a member found, once it is known whether that is where ez runs
62def lib.within(+top: String, root: List<&2, String>, rel: List<&2, String>) -> Lib:
63  match rel:
64    case []:
65      Keep{}
66    case _hd <> _tl:
67      Set{P.join(P.join(top, W.segs.text(root)), ".ez/lib")}
68
69# the library, once it is known whether the environment sets one
70def lib.found(set: Bool, +top: String, found: R.Found) -> Lib:
71  match set:
72    case True{}:
73      Keep{}
74    case False{}:
75      match found:
76        case R.Alone{}:
77          Keep{}
78        case R.Within{root, rel}:
79          lib.within(top, root, rel)
80        case R.Broken{_why}:
81          Keep{}
82
83# the library a member's own command uses: `env` is BEND_LIB as the
84# environment has it, "" for unset
85def lib(+top: String, found: R.Found, +env: String) -> Lib:
86  lib.found(Bool.not(String.is_empty(env)), top, found)
87
88# the line that runs the same command where it is, with BEND_LIB set
89def lib.line(+lib: String, +pwd: String, +prog: String, words: List<&2, String>) -> List<&2, String>:
90  List.append(&2, String,
91    ["sh", "-c", "BEND_LIB=\"$1\"; export BEND_LIB; shift; exec \"$@\"", "sh", lib, program(pwd, prog)], words)
92
93# ---------------------------------------------------------------------------
94# the lock a member's own command reads
95
96# the root a member found, once it is known whether that is where ez runs
97def lock.within(+top: String, root: List<&2, String>, rel: List<&2, String>) -> String:
98  match rel:
99    case []:
100      "ez.lock.toml"
101    case _hd <> _tl:
102      P.join(P.join(top, W.segs.text(root)), "ez.lock.toml")
103
104# the lock a command run in a directory reads: the root's, which is the only
105# one a workspace has, or its own in a project of its own and at the root
106def lock(+top: String, found: R.Found) -> String:
107  match found:
108    case R.Alone{}:
109      "ez.lock.toml"
110    case R.Within{root, rel}:
111      lock.within(top, root, rel)
112    case R.Broken{_why}:
113      "ez.lock.toml"