diff --git a/README.md b/README.md index 9aa2938..6fc9238 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,10 @@ one), `:batch`/`:daemon` (see below), `:quick` (default t; nil drops Emacs (event loop, timers, frame machinery, real init with `:quick nil`) with no visible frame. Right for driving a new build off-screen. Promote it to visible later by evaluating a - `make-frame` form in it. + `make-frame` form in it. The child's Emacs server gets a private + name (an Emacs daemon refuses to start while another server holds + its name, so this keeps it clear of a daemon you already run); + pass a string instead of t to choose the name. - both nil — the child starts normally and opens a frame on the parent's display: trying the new build as a user, or watching a sandboxed agent's Emacs. diff --git a/parenting-parent.el b/parenting-parent.el index 65b2695..30e4590 100644 --- a/parenting-parent.el +++ b/parenting-parent.el @@ -349,10 +349,13 @@ connection closes; with DAEMON non-nil it runs with --fg-daemon instead — a full interactive Emacs with no visible frame, which you can promote later by evaluating a `make-frame' form in it; with both nil the child starts normally and shows a frame on the parent's -display. With QUICK nil, -Q is dropped so the child starts with its -normal init files. NAME names the child process. Signal -`parenting-timeout' if the child has not connected after TIMEOUT -seconds. +display. A daemon child gets its own Emacs server name, so it does +not collide with any daemon already running under the default name +\(a daemon refuses to start when its server name is taken); DAEMON +may also be a string naming that server explicitly. With QUICK +nil, -Q is dropped so the child starts with its normal init files. +NAME names the child process. Signal `parenting-timeout' if the +child has not connected after TIMEOUT seconds. The remaining keywords exist for launching the child inside a sandbox or on another machine. COMMAND-WRAPPER is either a list of @@ -421,7 +424,12 @@ host network. See `parenting--sandbox-command-wrapper'." (list emacs) (and quick '("-Q")) (and batch '("--batch")) - (and daemon '("--fg-daemon")) + (and daemon + (list (concat "--fg-daemon=" + (if (stringp daemon) + daemon + (make-temp-name + (concat name "-")))))) args (cl-mapcan (lambda (dir) (list "-L" dir)) extra-load-path) diff --git a/test/parenting-test.el b/test/parenting-test.el index 1511416..5eca0ad 100644 --- a/test/parenting-test.el +++ b/test/parenting-test.el @@ -431,6 +431,30 @@ (should (> (parenting-eval conn '(length (frame-list))) 0))) (parenting-shutdown conn)))) +(ert-deftest parenting-spawn-daemon-children-do-not-collide () + ;; Each daemon child names its own Emacs server: an Emacs daemon + ;; refuses to start when its server name is already taken, so two + ;; children under the default name (or one beside the user's own + ;; daemon) could not coexist. + (let ((a (parenting-spawn :daemon t :timeout 60))) + (unwind-protect + (let ((b (parenting-spawn :daemon t :timeout 60))) + (unwind-protect + (progn + (should (eq t (parenting-eval b '(and (daemonp) t)))) + (should-not (equal "server" (parenting-eval a 'server-name))) + (should-not (equal (parenting-eval a 'server-name) + (parenting-eval b 'server-name)))) + (parenting-shutdown b))) + (parenting-shutdown a)))) + +(ert-deftest parenting-spawn-daemon-name-is-honored () + (let ((conn (parenting-spawn :daemon "parenting-test-named" :timeout 60))) + (unwind-protect + (should (equal "parenting-test-named" + (parenting-eval conn 'server-name))) + (parenting-shutdown conn)))) + (ert-deftest parenting-spawn-rejects-batch-plus-daemon () (should-error (parenting-spawn :batch t :daemon t)))