0

I've just come across dizzee, an Emacs package for managing subprocesses; it lets you create functions that stop, start or restart shell commands. For example:

(dz-defservice foo "script.sh" :cd ("/path/to/foo"))

This macro, dz-defservice, will create the functions foo-start, foo-stop and foo-restart that will run/kill "somecommand.sh" in the directory "/path/to/foo", and collect its output in a buffer.

This is perfect for a project I'm working on, where I want to run a bunch of commands in separate directories all at once. The commands all have the same name, but do different things depending on the directory they're in.

One way of doing this would be to write separate entries for each service like so:

(dz-defservice foo "script.sh" :cd ("/path/to/foo"))
(dz-defservice bar "script.sh" :cd ("/path/to/bar"))
(dz-defservice baz "script.sh" :cd ("/path/to/baz"))

But of course, this seems perfect for a list (particularly as I'll be adding more components in the future). So what I want to do is have a list be input to dz-defservice, which in turn seems like it's perfect for dolist:

(setq my--project-components '(foo bar baz))

(dolist (i my--project-components)
  (dz-defservice i "shell.sh" :cd (format "/path/to/%s" i)))

That was my first attempt; it only ended up redefining the functions i-start, i-stop and i-restart over and over again. Next I tried using quotes in dolist, since it's a macro too:

(dolist (i my--project-components)
  `(dz-defservice ,i "shell.sh" :cd (format "/root/%s/" element)))

but that gives me this error:

Compiler-macro error for cl--block-wrapper: (wrong-type-argument symbolp (\, i))

I'm obviously misunderstanding something here, so can anyone tell me how to use a list to create these different service entries?

  • 1
    Typo in your dolist: you have element when I think you mean i. Not sure if that's the problem, but you can check. – Dan Jan 9 '15 at 15:37
  • Doh! Fixed; thanks for catching that, but it wasn't the problem. – Saint Aardvark the Carpeted Jan 9 '15 at 15:40
  • 1
    You might also check out How to map a function over several values?. Don't have the dizzee package, but it seems like you could use something as simple as (mapc (lambda (x) (dz-defservice x "shell.sh" :cd (format "/path/to/%s" x))) '(puppies kitties turtles))). – Dan Jan 9 '15 at 15:41
  • 1
    Also: you could try (eval i) at your first invocation of i since you want its value there, not the symbol itself. – Dan Jan 9 '15 at 15:44
  • 1
    I sense (although not 100% sure) a problem with dz-defservice macro: it probably doesn't use gensym and instead of expanding i to its value, it takes the symbol i. It's probably better to tell the author of the library to fix the problem, but if you are lazy, you could "fix" it by writing a macro, which creates several separate forms which call dz-defservice with different service names. – wvxvw Jan 9 '15 at 16:37
1

I don't have dz-defservice and am too lazy to install it, but this should answer your other question wrt creating multiple forms that have distinct symbols in them:

(defmacro dz-defservices (names scripts directories)
  `(progn
     ,@(cl-loop for name in names
                for script in scripts
                for directory in directories
                collect `(dz-defservice ,name ,script :cd ,directory))))

(macroexpand
 '(dz-defservices (foo bar baz)
                  ("foo.sh" "bar.sh" "baz.sh")
                  ("some/dir/foo" "some/dir/bar" "some/dir/baz")))
(progn (dz-defservice foo "foo.sh" :cd "some/dir/foo")
       (dz-defservice bar "bar.sh" :cd "some/dir/bar")
       (dz-defservice baz "baz.sh" :cd "some/dir/baz"))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.