func formatArgs(envs map[string]string, shellCmd string, argv []string) string {
	argsLen := 9 + len(shellCmd)
	for _, arg := range argv {
		argsLen += 9 + len(arg)
	}
	envStrs := make([]string, 0, len(envs))
	for k, v := range envs {
		s := make([]byte, 0, len(k)+5+len(v))
		s = append(s, k...)
		s = append(s, '=')
		s = appendShellSafeQuote(s, v)
		argsLen += len(s) + 5
		envStrs = append(envStrs, string(s))
	}
	sort.Strings(envStrs)
	argsStr := make([]byte, 0, argsLen)
	for _, s := range envStrs {
		argsStr = append(argsStr, s...)
		argsStr = append(argsStr, " \\\n  "...)
	}
	argsStr = appendShellSafeQuote(argsStr, shellCmd)
	for _, arg := range argv {
		argsStr = append(argsStr, " \\\n  "...)
		argsStr = appendShellSafeQuote(argsStr, arg)
	}
	return string(argsStr)
}
Format a shell command line to set environment variables and run the command.

Handles quoting things as required.
package core
import (
	"bytes"
	"context"
	"math"
	"os"
	"os/exec"
	"path"
	"runtime/trace"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
	"github.com/martian-lang/martian/martian/util"
)
type RemoteJobManager struct {
	jobMode              string
	jobResourcesMappings map[string]string
	config               jobManagerConfig
	memGBPerCore         int
	maxJobs              int
	jobFreqMillis        int
	jobSem               *MaxJobsSemaphore
	limiter              *time.Ticker
	debug                bool
	queueMutex           sync.Mutex
}
func NewRemoteJobManager(jobMode string, memGBPerCore int, maxJobs int, jobFreqMillis int,
	jobResources string, config *JobManagerJson, debug bool) *RemoteJobManager {
	self := &RemoteJobManager{}
	self.jobMode = jobMode
	self.memGBPerCore = memGBPerCore
	self.maxJobs = maxJobs
	self.jobFreqMillis = jobFreqMillis
	self.debug = debug
	self.config = verifyJobManager(jobMode, config, memGBPerCore)
	self.jobResourcesMappings = map[string]string{}
	for _, mapping := range strings.Split(jobResources, ";") {
		if len(mapping) > 0 {
			parts := strings.Split(mapping, ":")
			if len(parts) == 2 {
				self.jobResourcesMappings[parts[0]] = parts[1]
				util.LogInfo("jobmngr", "Mapping %s to %s", parts[0], parts[1])
			} else {
				util.LogInfo("jobmngr", "Could not parse mapping: %s", mapping)
			}
		}
	}
	if self.maxJobs > 0 {
		self.jobSem = NewMaxJobsSemaphore(self.maxJobs)
	}
	if self.jobFreqMillis > 0 {
		self.limiter = time.NewTicker(time.Millisecond * time.Duration(self.jobFreqMillis))
	} else {
		self.limiter = time.NewTicker(time.Millisecond * 1)
	}
	return self
}
func (self *RemoteJobManager) refreshResources(bool) error {
	if self.jobSem != nil {
		self.jobSem.FindDone()
	}
	return nil
}
func (self *RemoteJobManager) GetMaxCores() int {
	return 0
}
func (self *RemoteJobManager) GetMaxMemGB() int {
	return 0
}
func (self *RemoteJobManager) GetSettings() *JobManagerSettings {
	return self.config.jobSettings
}
func (self *RemoteJobManager) GetSystemReqs(resRequest *JobResources) JobResources {
	res := *resRequest
	if res.Threads == 0 {
		res.Threads = float64(self.config.jobSettings.ThreadsPerJob)
	} else if res.Threads < 0 {
		res.Threads = -res.Threads
	}
	if res.MemGB < 0 {
		res.MemGB = -res.MemGB
	}
	if res.MemGB == 0 {
		res.MemGB = float64(self.config.jobSettings.MemGBPerJob)
	}
	if res.VMemGB < 1 {
		res.VMemGB = res.MemGB + float64(self.config.jobSettings.ExtraVmemGB)
	}
	if self.memGBPerCore > 0 {
		if threadsForMemory := res.MemGB /
			float64(self.memGBPerCore); threadsForMemory > res.Threads {
			res.Threads = threadsForMemory
		}
	}
	if !self.config.threadingEnabled {
		res.Threads = 1
	} else {
		res.Threads = math.Ceil(res.Threads)
	}
	return res
}
func (self *RemoteJobManager) execJob(shellCmd string, argv []string,
	envs map[string]string, metadata *Metadata, resRequest *JobResources,
	fqname string, shellName string, localpreflight bool) {
	ctx, task := trace.NewTask(context.Background(), "queueRemote")
	if self.maxJobs <= 0 {
		defer task.End()
		self.sendJob(shellCmd, argv, envs,
			metadata, resRequest,
			fqname, shellName, ctx)
		return
	}
	go func() {
		defer task.End()
		if self.debug {
			util.LogInfo("jobmngr", "Waiting for job: %s", fqname)
		}
		if success := self.jobSem.Acquire(metadata); !success {
			return
		}
		if self.debug {
			util.LogInfo("jobmngr", "Job sent: %s", fqname)
		}
		self.sendJob(shellCmd, argv, envs,
			metadata, resRequest,
			fqname, shellName, ctx)
	}()
}
func (self *RemoteJobManager) endJob(metadata *Metadata) {
	if self.jobSem != nil {
		self.jobSem.Release(metadata)
	}
}
func (self *RemoteJobManager) jobScript(
	shellCmd string, argv []string, envs map[string]string,
	metadata *Metadata,
	resRequest *JobResources,
	fqname, shellName string) string {
	res := self.GetSystemReqs(resRequest)
	vmemGBPerThread := int(math.Ceil(res.VMemGB / res.Threads))
	if self.memGBPerCore > vmemGBPerThread {
		vmemGBPerThread = self.memGBPerCore
	}
	memGBPerThread := vmemGBPerThread
	if self.config.alwaysVmem && res.VMemGB > res.MemGB {
		res.MemGB = res.VMemGB
	} else {
		memGBPerThread = int(math.Ceil(res.MemGB / res.Threads))
		if self.memGBPerCore > memGBPerThread {
			memGBPerThread = self.memGBPerCore
		}
	}
	mappedJobResourcesOpt := ""
	if len(res.Special) > 0 {
		if resources, ok := self.jobResourcesMappings[res.Special]; ok {
			mappedJobResourcesOpt = strings.Replace(
				self.config.jobResourcesOpt,
				"__RESOURCES__", resources, 1)
		}
	}
	threads := int(math.Ceil(res.Threads))
	argsStr := formatArgs(threadEnvs(self, threads, envs), shellCmd, argv)
	const prefix = "__MRO_"
	const suffix = "__"
	params := [...][2]string{
		{prefix + "JOB_NAME" + suffix,
			fqname + "." + shellName},
		{prefix + "THREADS" + suffix,
			strconv.Itoa(threads)},
		{prefix + "STDOUT" + suffix,
			shellSafeQuote(metadata.MetadataFilePath("stdout"))},
		{prefix + "STDERR" + suffix,
			shellSafeQuote(metadata.MetadataFilePath("stderr"))},
		{prefix + "JOB_WORKDIR" + suffix,
			shellSafeQuote(metadata.curFilesPath)},
		{prefix + "CMD" + suffix,
			argsStr},
		{prefix + "MEM_GB" + suffix,
			strconv.Itoa(int(math.Ceil(res.MemGB)))},
		{prefix + "MEM_MB" + suffix,
			strconv.Itoa(int(math.Ceil(res.MemGB * 1024)))},
		{prefix + "MEM_KB" + suffix,
			strconv.Itoa(int(math.Ceil(res.MemGB * 1024 * 1024)))},
		{prefix + "MEM_B" + suffix,
			strconv.Itoa(int(math.Ceil(res.MemGB * 1024 * 1024 * 1024)))},
		{prefix + "MEM_GB_PER_THREAD" + suffix,
			strconv.Itoa(memGBPerThread)},
		{prefix + "MEM_MB_PER_THREAD" + suffix,
			strconv.Itoa(memGBPerThread * 1024)},
		{prefix + "MEM_KB_PER_THREAD" + suffix,
			strconv.Itoa(memGBPerThread * 1024 * 1024)},
		{prefix + "MEM_B_PER_THREAD" + suffix,
			strconv.Itoa(memGBPerThread * 1024 * 1024 * 1024)},
		{prefix + "VMEM_GB" + suffix,
			strconv.Itoa(int(math.Ceil(res.VMemGB)))},
		{prefix + "VMEM_MB" + suffix,
			strconv.Itoa(int(math.Ceil(res.VMemGB * 1024)))},
		{prefix + "VMEM_KB" + suffix,
			strconv.Itoa(int(math.Ceil(res.VMemGB * 1024 * 1024)))},
		{prefix + "VMEM_B" + suffix,
			strconv.Itoa(int(math.Ceil(res.VMemGB * 1024 * 1024 * 1024)))},
		{prefix + "VMEM_GB_PER_THREAD" + suffix,
			strconv.Itoa(vmemGBPerThread)},
		{prefix + "VMEM_MB_PER_THREAD" + suffix,
			strconv.Itoa(vmemGBPerThread * 1024)},
		{prefix + "VMEM_KB_PER_THREAD" + suffix,
			strconv.Itoa(vmemGBPerThread * 1024 * 1024)},
		{prefix + "VMEM_B_PER_THREAD" + suffix,
			strconv.Itoa(vmemGBPerThread * 1024 * 1024 * 1024)},
		{prefix + "ACCOUNT" + suffix,
			os.Getenv("MRO_ACCOUNT")},
		{prefix + "RESOURCES" + suffix,
			mappedJobResourcesOpt},
	}
	template := self.config.jobTemplate
	args := make([]string, 0, 2*len(params))
	for _, vals := range params {
		rkey, val := vals[0], vals[1]
		if len(val) > 0 {
			args = append(args, rkey, val)
		} else if strings.Contains(template, rkey) {
			for _, line := range strings.Split(template, "\n") {
				if strings.Contains(line, rkey) {
					args = append(args, line, "")
				}
			}
		}
	}
	r := strings.NewReplacer(args...)
	return r.Replace(template)
}