@@ -269,6 +269,20 @@ class ExecutorSettings(ExecutorSettingsBase):
269269 },
270270 )
271271
272+ pass_command_as_script : bool = field (
273+ default = False ,
274+ metadata = {
275+ "help" : (
276+ "Pass to sbatch and srun the command to be executed as a shell script"
277+ " (fed through stdin) instead of wrapping it in the command line "
278+ "call. Useful when a limit exists on SLURM command line length (ie. "
279+ "max_submit_line_size)."
280+ ),
281+ "env_var" : False ,
282+ "required" : False ,
283+ },
284+ )
285+
272286 def __post_init__ (self ):
273287 """Validate settings after initialization."""
274288 validate_executor_settings (self )
@@ -413,7 +427,10 @@ def warn_on_jobcontext(self, done=None):
413427 done = True
414428
415429 def additional_general_args (self ):
416- return "--executor slurm-jobstep --jobs 1"
430+ general_args = "--executor slurm-jobstep --jobs 1"
431+ if self .workflow .executor_settings .pass_command_as_script :
432+ general_args += " --slurm-jobstep-pass-command-as-script"
433+ return general_args
417434
418435 def run_job (self , job : JobExecutorInterface ):
419436 # Implement here how to run a job.
@@ -500,19 +517,31 @@ def run_job(self, job: JobExecutorInterface):
500517
501518 exec_job = self .format_job_exec (job )
502519
503- # and finally the job to execute with all the snakemake parameters
504- call += f' --wrap="{ exec_job } "'
520+ if not self .workflow .executor_settings .pass_command_as_script :
521+ # and finally wrap the job to execute with all the snakemake parameters
522+ call += f' --wrap="{ exec_job } "'
523+ subprocess_stdin = None
524+ else :
525+ # format the job to execute with all the snakemake parameters into a script
526+ sbatch_script = "\n " .join (["#!/bin/sh" , exec_job ])
527+ self .logger .debug (f"sbatch script:\n { sbatch_script } " )
528+ # feed the shell script to sbatch via stdin
529+ call += " /dev/stdin"
530+ subprocess_stdin = sbatch_script
505531
506532 self .logger .debug (f"sbatch call: { call } " )
507533 try :
508534 process = subprocess .Popen (
509535 call ,
510536 shell = True ,
511537 text = True ,
538+ stdin = subprocess .PIPE ,
512539 stdout = subprocess .PIPE ,
513540 stderr = subprocess .PIPE ,
514541 )
515- out , err = process .communicate ()
542+ out , err = process .communicate (
543+ input = subprocess_stdin # feed the sbatch shell script through stdin
544+ )
516545 if process .returncode != 0 :
517546 raise subprocess .CalledProcessError (
518547 process .returncode , call , output = err
@@ -524,6 +553,11 @@ def run_job(self, job: JobExecutorInterface):
524553 "SLURM sbatch failed. "
525554 f"The error message was '{ e .output .strip ()} '.\n "
526555 f" sbatch call:\n { call } \n "
556+ + (
557+ f" sbatch script:\n { sbatch_script } \n "
558+ if subprocess_stdin is not None
559+ else ""
560+ )
527561 ),
528562 )
529563 return
0 commit comments