packages.sbatch-tui: correctly escape shell args

This commit is contained in:
2025-07-22 18:32:03 +08:00
parent 527e0028de
commit 53f596508e
5 changed files with 56 additions and 34 deletions

View File

@@ -17,7 +17,7 @@ namespace sbatch
public: virtual void try_load_state(YAML::Node node) noexcept = 0; public: virtual void try_load_state(YAML::Node node) noexcept = 0;
public: virtual YAML::Node save_state() const = 0; public: virtual YAML::Node save_state() const = 0;
public: virtual ftxui::Component get_interface() = 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; public: virtual ~Program() = default;
// 用于注册程序 // 用于注册程序
@@ -75,4 +75,15 @@ namespace sbatch
}; };
return ftxui::Checkbox(title, checked, checkbox_option); 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<std::string>;
}
} }

View File

@@ -121,9 +121,9 @@ int main()
else if (State.UserCommand == UserCommandType::Continue) else if (State.UserCommand == UserCommandType::Continue)
{ {
State.CurrentInterface = InterfaceType::Confirm; State.CurrentInterface = InterfaceType::Confirm;
State.SubmitCommand = Programs[State.ProgramSelected]->get_submit_command() State.SubmitCommand = Programs[State.ProgramSelected]->get_submit_command(
+ "\n--job-name='{}' --output='{}'{}"_f "--job-name=\"{}\" --output=\"{}\"{}"_f
(State.JobName, State.OutputFile, State.LowPriority ? " --nice=10000" : ""); (escape(State.JobName), escape(State.OutputFile), State.LowPriority ? " --nice=10000" : ""));
} }
else if (!State.UserCommand) return EXIT_FAILURE; else if (!State.UserCommand) return EXIT_FAILURE;
else std::unreachable(); else std::unreachable();
@@ -148,7 +148,6 @@ int main()
} }
catch (...) {} catch (...) {}
// 提交任务 // 提交任务
boost::replace_all(State.SubmitCommand, "\n", " ");
biu::exec<{.DirectStdout = true, .DirectStderr = true, .SearchPath = true}> biu::exec<{.DirectStdout = true, .DirectStderr = true, .SearchPath = true}>
({"sh", { "-c", State.SubmitCommand }}); ({"sh", { "-c", State.SubmitCommand }});
break; break;

View File

@@ -91,10 +91,10 @@ namespace sbatch
| with_title("Misc:") | 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 = [&] auto cpu_string = [&]
{ return State_.Nomultithread ? " --hint=nomultithread" : ""; }(); { return State_.Nomultithread ? "--hint=nomultithread" : ""; }();
auto gpu_string = [&] auto gpu_string = [&]
{ {
if (State_.GpuSchemeSelected == 0) return "--gpus=1"s; 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 if (State_.MemorySchemeSelected == 2) return "--mem={}G"_f(State_.Memory);
else std::unreachable(); else std::unreachable();
}(); }();
return "sbatch --partition={}\n{}{} {}\n--wrap=\"mumax3 {}\""_f return std::vector<std::string>
(State_.QueueEntries[State_.QueueSelected], gpu_string, cpu_string, mem_string, State_.InputFile); {
"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<std::string>;
} }
}; };
template void Program::register_child_<Mumax3>(); template void Program::register_child_<Mumax3>();

View File

@@ -104,13 +104,13 @@ namespace sbatch
}) | with_title("Misc:") }) | 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 = [&] auto optcell_string = [&]
{ {
if (State_.OptcellEnable) if (State_.OptcellEnable)
if (State_.OptcellSelected == 0) return "echo -e '000\\n000\\n001' > 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\n&& "s; else if (State_.OptcellSelected == 1) return "echo -e '110\\n110\\n000' > OPTCELL &&"s;
else std::unreachable(); else std::unreachable();
else return ""s; else return ""s;
}(); }();
@@ -126,24 +126,26 @@ namespace sbatch
}(); }();
auto mem_string = [&] auto mem_string = [&]
{ {
if (State_.MemorySchemeSelected == 0) return recommended.Memory ? " --mem={}G"_f(*recommended.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 == 1) return "--mem=0"s;
else if (State_.MemorySchemeSelected == 2) return " --mem={}G"_f(State_.Memory); else if (State_.MemorySchemeSelected == 2) return "--mem={}G"_f(State_.Memory);
else std::unreachable(); else std::unreachable();
}(); }();
auto srun_string = [&] auto srun_string = [&]
{ {
if (State_.CpuSchemeSelected == 0 && recommended.Cpus) 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; else return ""s;
}(); }();
return return std::vector<std::string>
"{}sbatch --partition={} --nodes=1-1\n{}{}\n" {
"--wrap=\"srun{} vasp-intel vasp-{}\""_f optcell_string,
( "sbatch"s,
optcell_string, State_.QueueEntries[State_.QueueSelected], cpu_string, mem_string, "--partition={} --nodes=1-1"_f(State_.QueueEntries[State_.QueueSelected]),
srun_string, State_.VaspEntries[State_.VaspSelected] 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<std::string>;
} }
}; };
template void Program::register_child_<VaspCpu>(); template void Program::register_child_<VaspCpu>();

View File

@@ -123,13 +123,13 @@ namespace sbatch
}) | with_title("Misc:") }) | 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 = [&] auto optcell_string = [&]
{ {
if (State_.OptcellEnable) if (State_.OptcellEnable)
if (State_.OptcellSelected == 0) return "echo -e '000\\n000\\n001' > 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\n&& "s; else if (State_.OptcellSelected == 1) return "echo -e '110\\n110\\n000' > OPTCELL && "s;
else std::unreachable(); else std::unreachable();
else return ""s; else return ""s;
}(); }();
@@ -149,16 +149,20 @@ namespace sbatch
}(); }();
auto mem_string = [&] auto mem_string = [&]
{ {
if (State_.MemorySchemeSelected == 0) return " --mem=24G"s; if (State_.MemorySchemeSelected == 0) return "--mem=24G"s;
else if (State_.MemorySchemeSelected == 1) return " --mem=0"s; else if (State_.MemorySchemeSelected == 1) return "--mem=0"s;
else if (State_.MemorySchemeSelected == 2) return " --mem={}G"_f(State_.Memory); else if (State_.MemorySchemeSelected == 2) return "--mem={}G"_f(State_.Memory);
else std::unreachable(); else std::unreachable();
}(); }();
return "{}sbatch --partition={}\n{} {}{}\n--wrap=\"srun vasp-nvidia vasp-{}\""_f return std::vector<std::string>
( {
optcell_string, State_.QueueEntries[State_.QueueSelected], gpu_string, cpu_string, mem_string, optcell_string,
State_.VaspEntries[State_.VaspSelected] "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<std::string>;
} }
}; };
template void Program::register_child_<VaspGpu>(); template void Program::register_child_<VaspGpu>();