diff --git a/README.md b/README.md index 9a55dc3..43831ee 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # RemoteHPC.jl [![Build Status](https://github.com/louisponet/RemoteHPC.jl/workflows/CI/badge.svg)](https://github.com/louisponet/RemoteHPC.jl/actions?query=workflow%3ACI) [![codecov](https://codecov.io/gh/louisponet/RemoteHPC.jl/branch/master/graph/badge.svg?token=PAFMYMVJUT)](https://codecov.io/gh/louisponet/RemoteHPC.jl) +[![Package Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/RemoteHPC)](https://pkgs.genieframework.com?packages=RemoteHPC) RemoteHPC attempts to wrap all the usual interactions one might have with a remote HPC cluster in a restAPI webserver that runs on the frontend of the cluster. diff --git a/src/client.jl b/src/client.jl index 71e6477..12ef9aa 100644 --- a/src/client.jl +++ b/src/client.jl @@ -325,15 +325,17 @@ function ask_input(::Type{T}, message, default = nothing) where {T} end function configure!(storable::T, s::Server) where {T<:Storable} - tf = tempname() + tdir = tempname() + mkpath(tdir) + tf = joinpath(tdir, "storable.md") open(tf, "w") do f - write(f, "Storable configuration. Replace default fields as desired after reading the documentation below.\nSave and close editor when finished.\n\n") + write(f, "Storable configuration. Replace default fields as desired after reading the documentation below.\nSave and close editor when finished.\n```julia\n") for field in configurable_fieldnames(T) value = getfield(storable, field) ft = typeof(value) write(f, "$field::$ft = $(repr(value))\n") end - write(f, "\n\n\n") + write(f, "```\n\n\n") write(f, "########## DOCUMENTATION #########\n") write(f, string(Docs.doc(T))) write(f, "\n") @@ -341,7 +343,10 @@ function configure!(storable::T, s::Server) where {T<:Storable} end InteractiveUtils.edit(tf) tstr = filter(!isempty, readlines(tf)) - i = findfirst(x->occursin("Save and close",x), tstr) + i = findfirst(x->occursin("```julia",x), tstr) + + parsing_error = false + for (ii, f) in enumerate(configurable_fieldnames(T)) field = getfield(storable, f) ft = typeof(field) @@ -356,16 +361,19 @@ function configure!(storable::T, s::Server) where {T<:Storable} setfield!(storable, f, v) catch e - @warn "Failed parsing $(split(tstr[i+ii], "=")[end]) as $ft. Try again" - @error stacktrace(catch_backtrace()) - print("Press any key to continue...\n") - readline() - configure!(storable, s) + @warn "Failed parsing $(split(tstr[i+ii], "=")[end]) as $ft." + showerror(stdout, e, stacktrace(catch_backtrace())) + parsing_error = true end end + if parsing_error - rm(tf) - return storable + @info "There was a parsing error. Please try again by pressing any key to continue...\n" + readline() + return configure!(storable, s) + else + return storable + end end function version(s::Server) diff --git a/src/types.jl b/src/types.jl index 3a972de..6caf713 100644 --- a/src/types.jl +++ b/src/types.jl @@ -13,12 +13,22 @@ from the [`Server`](@ref) where it is stored. In a job script this will be translated as ` `. -For example: +# `configure()` Example +```julia +name::String = "exec_label" +path::String = "/path/to/exec" +flags::Dict{Any, Any} = Dict{Any, Any}("l" => 1, "-np" => 4, "trialname" => "testtrial") +modules::Vector{String} = String["intel","intel-mkl"] +parallel::Bool = false +``` + +# Example: ```julia Exec(; path="ls", flags=Dict("l" => "")) -# translates into: ls -l ``` -## Flags +translates into `ls -l` in the jobscript. + +# Flags The `flags` `Dict` is expanded into the jobscript as follows: ```julia Exec(path="foo", flags = Dict("N" => 1, @@ -28,11 +38,11 @@ Exec(path="foo", flags = Dict("N" => 1, "--t2" => 24) # translates into: foo -N1 -nk 10 --np=\$NPOOLS --t --t2=24 ``` -## Modules +# Modules The `modules` vector gets expanded into `module load` commands: `modules = ["gcc", "QuantumESPRESSO"]` will lead to `module load gcc, QuantumESPRESSO` in the jobscript. -## Parallel +# Parallel `parallel` communicates whether the executable should be ran with the parallel executable defined in the [`Environment`](@ref) that represents the execution environment. For example: @@ -144,6 +154,16 @@ and which executable to use for parallel execution (think `mpirun`, `srun`, etc) As with any [`Storable`](@ref), `name` is used simply as a label to be able to [`load`](@ref) it from the [`Server`](@ref) where it is stored. +# `configure()` Example +```julia +name::String = "default", +directives::Dict{Any, Any} = Dict{Any, Any}("time" => "24:00:00", "partition" => "standard", "account" => "s1073", "N" => 4, "ntasks-per-node" => 36, "cpus-per-taks" => 1) +exports::Dict{Any, Any} = Dict{Any, Any}("OMP_NUM_THREADS" => 1) +preamble::String = "echo hello" +postamble::String = "echo goodbye" +parallel_exec::Exec = Exec(name="srun", path="srun", flags=Dict("n" => 36)) +``` + # Example ```julia