bionode / bionode-watermill

đŸ’§Bionode-Watermill: A (Not Yet Streaming) Workflow Engine
https://bionode.gitbooks.io/bionode-watermill/content/
MIT License
37 stars 11 forks source link

Inline Scripts #89

Open thejmazz opened 6 years ago

thejmazz commented 6 years ago

Due to the way we parse a string into a child process it may be the case that certain operations (e.g., a bash for/while read loop) may not run.

It would be nice to use ES6 tagged template literals to define scripts, this could look like:

const myTask = task({
  name: 'my task',
  input: '*.lowercase',
  output: '*.uppercase'
}, ({ input }) => bash`
  input="${input}"
  output="${input.replace(/\.lowercase$/, '.uppercase')}"

  cat $input | awk '{print toupper($0)}' > $output
`)

These could be written to the folder the task is being ran, which has the added benefit of being able to simply cd data/<id> to run the script.

This will involve

thejmazz commented 6 years ago

Userland implementation from 9a2e750 for quick reference:


const script = ({ dir, program }) => (strings, ...values) => {
  let content = ''
  strings.forEach((str, i) => {
    content += str + (values[i] || '')
  })

  const scriptLocation = path.resolve(dir, 'script.' + (() => {
    switch (program) {
      case 'bash': return 'sh'
      case 'python': return 'py'
    }
  })())

  fs.writeFileSync(scriptLocation, `
#!/usr/bin/env ${program}
${content.replace(/\n\ {2}/g, '\n')}
  `.trim())

  fs.chmodSync(scriptLocation, '755')

  const cp = spawn(scriptLocation)

  cp.on('error', (err) => console.log(`${scriptLocation} error:`, err))
  cp.on('close', () => console.log(`${scriptLocation} closed`))
  cp.on('exit', () => console.log(`${scriptLocation} exited`))
  cp.on('disconnect', () => console.log(`${scriptLocation} disconnected`))

  cp.stdout.on('data', (chunk) => console.log(`${scriptLocation} stdout: ${chunk}`))
  cp.stderr.on('data', (chunk) => console.log(`${scriptLocation} stderr: ${chunk}`))

  return cp
}

const myTask = task({
  name: 'my task',
  input: '*.lowercase',
  output: '*.uppercase'
}, ({ input, dir }) => script({ dir, program: 'bash' })`
  input="${input}"
  output="${input.replace(/\.lowercase$/, '.uppercase')}"

  cat $input | awk '{print toupper($0)}' > $output
`)