diff --git a/packages/sbatch-tui/include/sbatch-tui.hpp b/packages/sbatch-tui/include/sbatch-tui.hpp index 6662aabb..9c0643b2 100644 --- a/packages/sbatch-tui/include/sbatch-tui.hpp +++ b/packages/sbatch-tui/include/sbatch-tui.hpp @@ -17,7 +17,7 @@ namespace sbatch public: virtual void try_load_state(YAML::Node node) noexcept = 0; public: virtual YAML::Node save_state() const = 0; public: virtual ftxui::Component get_interface() = 0; - public: virtual std::string get_submit_command() const = 0; + public: virtual std::string get_submit_command(std::string extra_sbatch_parameter) const = 0; public: virtual ~Program() = default; // 用于注册程序 @@ -75,4 +75,15 @@ namespace sbatch }; return ftxui::Checkbox(title, checked, checkbox_option); }; + // 转义字符 + inline std::string escape(std::string str) + { + return str | ranges::views::transform([](char c) + { + // only the following characters need to be escaped: $ ` \ " newline * @ + if (std::set{'$','`','\\','\"','\n','*','@'}.contains(c)) + return '\\' + std::string(1, c); + else return std::string(1, c); + }) | ranges::views::join("") | ranges::to; + } } diff --git a/packages/sbatch-tui/src/main.cpp b/packages/sbatch-tui/src/main.cpp index 1e360b0e..9c94295f 100644 --- a/packages/sbatch-tui/src/main.cpp +++ b/packages/sbatch-tui/src/main.cpp @@ -121,9 +121,9 @@ int main() else if (State.UserCommand == UserCommandType::Continue) { State.CurrentInterface = InterfaceType::Confirm; - State.SubmitCommand = Programs[State.ProgramSelected]->get_submit_command() - + "\n--job-name='{}' --output='{}'{}"_f - (State.JobName, State.OutputFile, State.LowPriority ? " --nice=10000" : ""); + State.SubmitCommand = Programs[State.ProgramSelected]->get_submit_command( + "--job-name=\"{}\" --output=\"{}\"{}"_f + (escape(State.JobName), escape(State.OutputFile), State.LowPriority ? " --nice=10000" : "")); } else if (!State.UserCommand) return EXIT_FAILURE; else std::unreachable(); @@ -148,7 +148,6 @@ int main() } catch (...) {} // 提交任务 - boost::replace_all(State.SubmitCommand, "\n", " "); biu::exec<{.DirectStdout = true, .DirectStderr = true, .SearchPath = true}> ({"sh", { "-c", State.SubmitCommand }}); break; diff --git a/packages/sbatch-tui/src/mumax3.cpp b/packages/sbatch-tui/src/mumax3.cpp index 271b95a2..0670efef 100644 --- a/packages/sbatch-tui/src/mumax3.cpp +++ b/packages/sbatch-tui/src/mumax3.cpp @@ -91,10 +91,10 @@ namespace sbatch | with_title("Misc:") }); } - public: virtual std::string get_submit_command() const override + public: virtual std::string get_submit_command(std::string extra_sbatch_parameter) const override { auto cpu_string = [&] - { return State_.Nomultithread ? " --hint=nomultithread" : ""; }(); + { return State_.Nomultithread ? "--hint=nomultithread" : ""; }(); auto gpu_string = [&] { if (State_.GpuSchemeSelected == 0) return "--gpus=1"s; @@ -109,8 +109,14 @@ namespace sbatch else if (State_.MemorySchemeSelected == 2) return "--mem={}G"_f(State_.Memory); else std::unreachable(); }(); - return "sbatch --partition={}\n{}{} {}\n--wrap=\"mumax3 {}\""_f - (State_.QueueEntries[State_.QueueSelected], gpu_string, cpu_string, mem_string, State_.InputFile); + return std::vector + { + "sbatch"s, + "--partition={}"_f(State_.QueueEntries[State_.QueueSelected]), + gpu_string, cpu_string, mem_string, + "--wrap=\"mumax3 \\\"{}\\\"\""_f(escape(escape(State_.InputFile))), + extra_sbatch_parameter + } | biu::toLvalue | ranges::views::join(" \\\n") | ranges::to; } }; template void Program::register_child_(); diff --git a/packages/sbatch-tui/src/vasp_cpu.cpp b/packages/sbatch-tui/src/vasp_cpu.cpp index 92604dc4..791bb203 100644 --- a/packages/sbatch-tui/src/vasp_cpu.cpp +++ b/packages/sbatch-tui/src/vasp_cpu.cpp @@ -104,13 +104,13 @@ namespace sbatch }) | with_title("Misc:") }); } - public: virtual std::string get_submit_command() const override + public: virtual std::string get_submit_command(std::string extra_sbatch_parameter) const override { auto optcell_string = [&] { if (State_.OptcellEnable) - if (State_.OptcellSelected == 0) return "echo -e '000\\n000\\n001' > OPTCELL\n&& "s; - else if (State_.OptcellSelected == 1) return "echo -e '110\\n110\\n000' > OPTCELL\n&& "s; + if (State_.OptcellSelected == 0) return "echo -e '000\\n000\\n001' > OPTCELL &&"s; + else if (State_.OptcellSelected == 1) return "echo -e '110\\n110\\n000' > OPTCELL &&"s; else std::unreachable(); else return ""s; }(); @@ -126,24 +126,26 @@ namespace sbatch }(); auto mem_string = [&] { - if (State_.MemorySchemeSelected == 0) return recommended.Memory ? " --mem={}G"_f(*recommended.Memory) : ""; - else if (State_.MemorySchemeSelected == 1) return " --mem=0"s; - else if (State_.MemorySchemeSelected == 2) return " --mem={}G"_f(State_.Memory); + if (State_.MemorySchemeSelected == 0) return recommended.Memory ? "--mem={}G"_f(*recommended.Memory) : ""; + else if (State_.MemorySchemeSelected == 1) return "--mem=0"s; + else if (State_.MemorySchemeSelected == 2) return "--mem={}G"_f(State_.Memory); else std::unreachable(); }(); auto srun_string = [&] { if (State_.CpuSchemeSelected == 0 && recommended.Cpus) - return " --ntasks={} --cpus-per-task={}"_f(recommended.Mpi, recommended.Openmp); + return "--ntasks={} --cpus-per-task={}"_f(recommended.Mpi, recommended.Openmp); else return ""s; }(); - return - "{}sbatch --partition={} --nodes=1-1\n{}{}\n" - "--wrap=\"srun{} vasp-intel vasp-{}\""_f - ( - optcell_string, State_.QueueEntries[State_.QueueSelected], cpu_string, mem_string, - srun_string, State_.VaspEntries[State_.VaspSelected] - ); + return std::vector + { + optcell_string, + "sbatch"s, + "--partition={} --nodes=1-1"_f(State_.QueueEntries[State_.QueueSelected]), + cpu_string, mem_string, + "--wrap=\"srun {} vasp-intel vasp-{}\""_f(srun_string, State_.VaspEntries[State_.VaspSelected]), + extra_sbatch_parameter + } | biu::toLvalue | ranges::views::join(" \\\n") | ranges::to; } }; template void Program::register_child_(); diff --git a/packages/sbatch-tui/src/vasp_gpu.cpp b/packages/sbatch-tui/src/vasp_gpu.cpp index a4fe1481..3d8a9345 100644 --- a/packages/sbatch-tui/src/vasp_gpu.cpp +++ b/packages/sbatch-tui/src/vasp_gpu.cpp @@ -123,13 +123,13 @@ namespace sbatch }) | with_title("Misc:") }); } - public: virtual std::string get_submit_command() const override + public: virtual std::string get_submit_command(std::string extra_sbatch_parameter) const override { auto optcell_string = [&] { if (State_.OptcellEnable) - if (State_.OptcellSelected == 0) return "echo -e '000\\n000\\n001' > OPTCELL\n&& "s; - else if (State_.OptcellSelected == 1) return "echo -e '110\\n110\\n000' > OPTCELL\n&& "s; + if (State_.OptcellSelected == 0) return "echo -e '000\\n000\\n001' > OPTCELL && "s; + else if (State_.OptcellSelected == 1) return "echo -e '110\\n110\\n000' > OPTCELL && "s; else std::unreachable(); else return ""s; }(); @@ -149,16 +149,20 @@ namespace sbatch }(); auto mem_string = [&] { - if (State_.MemorySchemeSelected == 0) return " --mem=24G"s; - else if (State_.MemorySchemeSelected == 1) return " --mem=0"s; - else if (State_.MemorySchemeSelected == 2) return " --mem={}G"_f(State_.Memory); + if (State_.MemorySchemeSelected == 0) return "--mem=24G"s; + else if (State_.MemorySchemeSelected == 1) return "--mem=0"s; + else if (State_.MemorySchemeSelected == 2) return "--mem={}G"_f(State_.Memory); else std::unreachable(); }(); - return "{}sbatch --partition={}\n{} {}{}\n--wrap=\"srun vasp-nvidia vasp-{}\""_f - ( - optcell_string, State_.QueueEntries[State_.QueueSelected], gpu_string, cpu_string, mem_string, - State_.VaspEntries[State_.VaspSelected] - ); + return std::vector + { + optcell_string, + "sbatch"s, + "--partition={} --nodes=1-1"_f(State_.QueueEntries[State_.QueueSelected]), + gpu_string, cpu_string, mem_string, + "--wrap=\"srun vasp-nvidia vasp-{}\""_f(State_.VaspEntries[State_.VaspSelected]), + extra_sbatch_parameter + } | biu::toLvalue | ranges::views::join(" \\\n") | ranges::to; } }; template void Program::register_child_();