rubyrubygemsforkspawnnanoc

Replacing fork() with spawn() in nanoc live


I've got an issue with Ruby. Specifically, the spawn() and fork() methods.

I'm developing a website using Nanoc on Windows, and upon trying to implement the nanoc-live gem, I get the message that fork() is unimplemented on this machine.

Upon researching what I could about this, the only thing I really came back with, was to replace it with spawn(). However, I don't know Ruby. And the nanoc-live documentation is down. I have asked on what support forums they have with no luck.

I don't ask how to do this lightly because I like figuring out issues but this has me stumped, and I'm hardly a Ruby dev. How would I replace the below method call so it uses spawn()? Or, if someone has a different solution in their back pocket, that would also be great.

Ruby version 3.2.2
Nanoc version 4.12.15
Windows 10

This is the offending method

      def run_parent
        # create initial child
        pipe_read, pipe_write = IO.pipe
        fork { run_child(pipe_write, pipe_read) { |s| yield(s) } }  Here is the method call
        pipe_read.close

        changes = gen_lib_changes
        puts 'Listening for lib/ changes…'
        changes.each do |_e|
          # stop child
          pipe_write.write('q')
          pipe_write.close
          Process.wait

          # create new child
          pipe_read, pipe_write = IO.pipe
          fork { run_child(pipe_write, pipe_read) { |s| yield(s) } }
          pipe_read.close
        end
      rescue Interrupt
      end

And this is the run_child method called by fork()

def run_child(pipe_write, pipe_read)
        pipe_write.close

        site = Nanoc::Core::SiteLoader.new.new_from_cwd
        changes_enum = gen_changes_for_child(site)
        yield(site)

        quit = Object.new
        parent_enum = Enumerator.new do |y|
          pipe_read.read
          y << quit
        end

        puts 'Listening for site changes…'
        SlowEnumeratorTools.merge([parent_enum, changes_enum]).each do |e|
          break if quit.equal?(e)

          $stderr.print 'Reloading site… '
          $stderr.flush
          site_loader = Nanoc::Core::SiteLoader.new
          site = Nanoc::Core::Site.new(
            config: Nanoc::Core::ConfigLoader.new.new_from_cwd,
            data_source: site_loader.gen_data_source_for_config(site.config),
            code_snippets: site.code_snippets,
          )
          $stderr.puts 'done'

          yield(site)
        end

        exit 0
      rescue Interrupt
        exit 0
      end

Thanks In Advance.


Solution

  • You can use spawn like this to achieve what you want. However, as the answer details, process spawning like this in Windows is not optimal. You should consider threads.

    spawn() docs if you didn't have them already