@simon-says-build/harbormaster 0.14.1 → 0.14.2

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.
package/README.md CHANGED
@@ -155,6 +155,15 @@ env, under the caller's explicit `--fn-env`. `exec`: on top of the caller's
155
155
  ambient env, so a key exported in some shell can't leak into the suite.
156
156
  `python3 test/project_env.py`.
157
157
 
158
+ ## A function env value can name a leased port (0.14.2)
159
+
160
+ `--fn-env KEY={port:firestore}`, or the same in `harbormaster.env`, becomes
161
+ this lease's firestore port, inside a value too (`127.0.0.1:{port:auth}`). A
162
+ caller can't know its ports before the lease, and an app whose functions read
163
+ their own variable for the emulator (Tapuat's `EMULATOR_PORT_FIRESTORE ||
164
+ "8080"`) otherwise talks to whatever holds the default. An unknown service is
165
+ left as written. `python3 test/port_env.py`.
166
+
158
167
  ## A lease never reads the hosting config it doesn't start (0.14.1)
159
168
 
160
169
  A lease whose `--only` leaves hosting out boots from a config with no
package/harbormaster CHANGED
@@ -84,7 +84,7 @@ import uuid
84
84
  from datetime import datetime, timezone
85
85
  from pathlib import Path
86
86
 
87
- VERSION = "0.14.1"
87
+ VERSION = "0.14.2"
88
88
 
89
89
  # Overridable for tests / parallel installs; default is the shared user daemon.
90
90
  # The dir keeps the old "firebase-ports" name: pre-rename binaries still installed
@@ -361,6 +361,20 @@ def _service_ports(ports):
361
361
  return {s: p for s, p in ports.items() if s not in ("ui", "hub", "logging")}
362
362
 
363
363
 
364
+ # A value that names a LEASED port: `{port:firestore}` becomes this lease's
365
+ # firestore port. The caller cannot know its ports before the lease, and an
366
+ # app whose functions read their own variable for the emulator (Tapuat's
367
+ # admin.ts: `127.0.0.1:${EMULATOR_PORT_FIRESTORE || "8080"}`, unconditionally)
368
+ # otherwise talks to whatever holds the default — on simon-linux-1, nothing;
369
+ # every callable 500'd (run 20261021-131438-exploration-everyday-user). An
370
+ # unknown service is left as written, so a typo shows in the app's own error.
371
+ _PORT_REF = re.compile(r"\{port:([a-z_]+)\}")
372
+
373
+ def _with_ports(env, ports):
374
+ return {k: _PORT_REF.sub(lambda m: str(ports[m.group(1)]) if m.group(1) in ports else m.group(0), v)
375
+ for k, v in env.items()}
376
+
377
+
364
378
  def _write_injected_config(cwd, ports, only=None):
365
379
  """Set ports on the emulators the portless firebase.json DECLARES (+ hub/logging).
366
380
  Never adds emulators the project doesn't use. Returns the temp config basename.
@@ -814,9 +828,9 @@ class Broker:
814
828
  # daemon's env — the functions emulator runtime inherits it, which is
815
829
  # the only way a CALLER can set per-suite env (e.g. LLM_CACHE_DIR)
816
830
  # when the daemon, not the caller, spawns the emulator.
817
- spawn_env = {**os.environ, **project_env(cwd), "TMPDIR": str(suite_tmp)}
831
+ spawn_env = {**os.environ, **_with_ports(project_env(cwd), all_ports), "TMPDIR": str(suite_tmp)}
818
832
  if extra_env:
819
- spawn_env.update({str(k): str(v) for k, v in dict(extra_env).items()})
833
+ spawn_env.update(_with_ports({str(k): str(v) for k, v in dict(extra_env).items()}, all_ports))
820
834
  with open(log, "w") as lf:
821
835
  proc = subprocess.Popen(cmd, cwd=cwd, stdout=lf, stderr=subprocess.STDOUT, start_new_session=True, env=spawn_env)
822
836
  if on_spawn:
@@ -1860,7 +1874,7 @@ def main():
1860
1874
  # The project's env beats the caller's AMBIENT env here: a key
1861
1875
  # exported in some shell for a one-off script is exactly what
1862
1876
  # harbormaster.env exists to keep out of the suite (project_env).
1863
- rc = subprocess.call(run, cwd=cwd, env={**os.environ, **project_env(cwd)})
1877
+ rc = subprocess.call(run, cwd=cwd, env={**os.environ, **_with_ports(project_env(cwd), _block_ports(base))})
1864
1878
  finally:
1865
1879
  try:
1866
1880
  _call("POST", "/release", {"leaseId": lid})
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simon-says-build/harbormaster",
3
- "version": "0.14.1",
3
+ "version": "0.14.2",
4
4
  "description": "A localhost daemon that leases each caller its own port block — isolated Firebase emulator sandboxes, Metro/Expo ports, private iOS simulators — reaped when the caller exits. No port collisions, no shared instances, no pkill.",
5
5
  "bin": {
6
6
  "harbormaster": "harbormaster",