diff --git a/base/utils/R/write_job_sh.R b/base/utils/R/write_job_sh.R new file mode 100644 index 00000000000..0111d09191f --- /dev/null +++ b/base/utils/R/write_job_sh.R @@ -0,0 +1,21 @@ +#' Write a job.sh script for a PEcAn model run +#' +#' This helper function writes the job.sh shell script used to execute +#' a model run. It centralizes duplicated logic previously found in +#' individual write.config.* functions across model packages. +#' +#' @param rundir character. Path to the run directory +#' @param run.id character. The run ID +#' @param jobsh character vector. Lines of the job.sh script content +#' @param chmod logical. Whether to make job.sh executable. Default TRUE +#' +#' @return invisible path to the written job.sh file +#' @export +write_job_sh <- function(rundir, run.id, jobsh, chmod = TRUE) { + job_path <- file.path(rundir, run.id, "job.sh") + writeLines(jobsh, con = job_path) + if (chmod) { + Sys.chmod(job_path) + } + invisible(job_path) +} \ No newline at end of file diff --git a/base/utils/tests/testthat/test.write_job_sh.R b/base/utils/tests/testthat/test.write_job_sh.R new file mode 100644 index 00000000000..d979089e499 --- /dev/null +++ b/base/utils/tests/testthat/test.write_job_sh.R @@ -0,0 +1,45 @@ +test_that("write_job_sh creates job.sh file", { + # Create a temporary directory for testing + tmpdir <- tempfile() + dir.create(tmpdir) + run.id <- "test_run_001" + dir.create(file.path(tmpdir, run.id)) + + # Define simple job script content + jobsh <- c( + "#!/bin/bash", + "echo 'running model'" + ) + + # Call the helper function + result <- write_job_sh(tmpdir, run.id, jobsh) + + # Test 1 - file exists + expect_true(file.exists(file.path(tmpdir, run.id, "job.sh"))) + + # Test 2 - file content is correct + written <- readLines(file.path(tmpdir, run.id, "job.sh")) + expect_equal(written, jobsh) + + # Test 3 - function returns the path invisibly + expect_equal(result, file.path(tmpdir, run.id, "job.sh")) + + # Cleanup + unlink(tmpdir, recursive = TRUE) +}) + +test_that("write_job_sh chmod parameter works", { + tmpdir <- tempfile() + dir.create(tmpdir) + run.id <- "test_run_002" + dir.create(file.path(tmpdir, run.id)) + + jobsh <- c("#!/bin/bash", "./model") + + # Test with chmod = FALSE + write_job_sh(tmpdir, run.id, jobsh, chmod = FALSE) + expect_true(file.exists(file.path(tmpdir, run.id, "job.sh"))) + + # Cleanup + unlink(tmpdir, recursive = TRUE) +}) \ No newline at end of file diff --git a/models/ed/R/write.configs.ed.R b/models/ed/R/write.configs.ed.R index a0da36fb94d..aa832fecdb1 100644 --- a/models/ed/R/write.configs.ed.R +++ b/models/ed/R/write.configs.ed.R @@ -122,8 +122,7 @@ write.config.ED2 <- function(trait.values, settings, run.id, defaults = settings jobsh <- write.config.jobsh.ED2(settings = settings, run.id = run.id) - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) ## Write ED2 config.xml file xml <- write.config.xml.ED2(defaults = defaults, settings = settings, trait.values = trait.values) diff --git a/models/ed/R/write_restart.ED2.R b/models/ed/R/write_restart.ED2.R index 3a3611ad607..3492a8d8b3b 100644 --- a/models/ed/R/write_restart.ED2.R +++ b/models/ed/R/write_restart.ED2.R @@ -268,7 +268,7 @@ write_restart.ED2 <- function(outdir, runid, start.time, stop.time, mod2cf_string <- gsub(begin_from, begin_to, mod2cf_string) # e.g. change from (...'1961/01/01', '1963/01/01'...) to (...'1962/01/01', '1963/01/01'...) jobsh[mod2cf_line] <- mod2cf_string - writeLines(jobsh, file.path(rundir, runid, "job.sh")) + PEcAn.utils::write_job_sh(rundir, runid, jobsh) PEcAn.logger::logger.info("Finished --", runid) diff --git a/models/fates/R/write.configs.FATES.R b/models/fates/R/write.configs.FATES.R index 871b324fa45..f7634b8183d 100644 --- a/models/fates/R/write.configs.FATES.R +++ b/models/fates/R/write.configs.FATES.R @@ -189,8 +189,7 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){ # jobsh <- gsub('@SITE_MET@', settings$run$inputs$met$path, jobsh) ## FOR FIRST STEP, CAN USE DEFAULT - writeLines(jobsh, con=file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) # # ## Write PARAMETER file diff --git a/models/gday/R/write.config.GDAY.R b/models/gday/R/write.config.GDAY.R index cd7267327c0..f1cac9f3773 100644 --- a/models/gday/R/write.config.GDAY.R +++ b/models/gday/R/write.config.GDAY.R @@ -95,6 +95,5 @@ write.config.GDAY <- function(defaults, trait.values, settings, run.id) { jobsh <- gsub("@BINARY@", settings$model$binary, jobsh) - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) } # write.config.GDAY diff --git a/models/jules/R/write.config.JULES.R b/models/jules/R/write.config.JULES.R index 5add178de66..6200267f8d5 100644 --- a/models/jules/R/write.config.JULES.R +++ b/models/jules/R/write.config.JULES.R @@ -64,8 +64,7 @@ write.config.JULES <- function(defaults, trait.values, settings, run.id) { jobsh <- gsub("@RUNDIR@", rundir, jobsh) jobsh <- gsub("@RUNID@", run.id, jobsh) jobsh <- gsub("@BINARY@", settings$model$binary, jobsh) - writeLines(jobsh, con = file.path(local.rundir, "job.sh")) - Sys.chmod(file.path(local.rundir, "job.sh")) + PEcAn.utils::write_job_sh(local.rundir, run.id, jobsh) #----------------------------------------------------------------------- ### Copy templated NAMELIST files to local rundir diff --git a/models/ldndc/R/write.config.LDNDC.R b/models/ldndc/R/write.config.LDNDC.R index 6f13bd29ae2..5285268c1f0 100644 --- a/models/ldndc/R/write.config.LDNDC.R +++ b/models/ldndc/R/write.config.LDNDC.R @@ -133,8 +133,7 @@ write.config.LDNDC <- function(defaults, trait.values, settings, run.id) { jobsh <- gsub("@DELETE.RAW@", settings$model$delete.raw, jobsh) # Write job.sh file to rundir - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(rundir, "job.sh")) # Permissions + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) diff --git a/models/linkages/R/write.config.LINKAGES.R b/models/linkages/R/write.config.LINKAGES.R index 43c300a33ca..0b710ac601b 100644 --- a/models/linkages/R/write.config.LINKAGES.R +++ b/models/linkages/R/write.config.LINKAGES.R @@ -295,6 +295,5 @@ write.config.LINKAGES <- function(defaults = NULL, trait.values, settings, run.i pft_names <- unlist(sapply(settings$pfts, `[[`, "name")) pft_names <- paste0("pft_names = c('", paste(pft_names, collapse = "','"), "')") jobsh <- gsub("@PFT_NAMES@", pft_names, jobsh) - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) } # write.config.LINKAGES diff --git a/models/lpjguess/R/write.config.LPJGUESS.R b/models/lpjguess/R/write.config.LPJGUESS.R index 9786deeafcd..be8cb2f8a6c 100644 --- a/models/lpjguess/R/write.config.LPJGUESS.R +++ b/models/lpjguess/R/write.config.LPJGUESS.R @@ -71,8 +71,7 @@ write.config.LPJGUESS <- function(defaults, trait.values, settings, run.id, rest jobsh <- gsub("@BINARY@", settings$model$binary, jobsh) jobsh <- gsub("@INSFILE@", settings$model$insfile, jobsh) - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) } # write.config.LPJGUESS # ==================================================================================================# diff --git a/models/maat/R/write.config.MAAT.R b/models/maat/R/write.config.MAAT.R index 825cefe061f..b632329862f 100644 --- a/models/maat/R/write.config.MAAT.R +++ b/models/maat/R/write.config.MAAT.R @@ -243,8 +243,7 @@ write.config.MAAT <- function(defaults = NULL, trait.values, settings, run.id) { } #End if/else # Write the job.sh script - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) } # write.config.MAAT ##-------------------------------------------------------------------------------------------------# diff --git a/models/maespa/R/write.config.MAESPA.R b/models/maespa/R/write.config.MAESPA.R index 6adfd849eea..aca82158939 100755 --- a/models/maespa/R/write.config.MAESPA.R +++ b/models/maespa/R/write.config.MAESPA.R @@ -144,6 +144,5 @@ write.config.MAESPA <- function(defaults, trait.values, settings, run.id) { jobsh <- gsub("@BINARY@", settings$model$binary, jobsh) - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) } # write.config.MAESPA diff --git a/models/peprmt/R/write.configs.peprmt.R b/models/peprmt/R/write.configs.peprmt.R index b6f0a8ff2d6..519bbdf7f04 100644 --- a/models/peprmt/R/write.configs.peprmt.R +++ b/models/peprmt/R/write.configs.peprmt.R @@ -105,6 +105,5 @@ write.config.PEPRMT <- function(defaults, trait.values, settings, run.id) { dplyr::filter(.data$site == settings$run$site$id) utils::write.csv(run_data, file.path(rundir, "run_data.csv"), row.names = FALSE) - writeLines(jobsh, con = file.path(rundir, "job.sh")) - Sys.chmod(file.path(rundir, "job.sh")) + PEcAn.utils::write_job_sh(rundir, run.id, jobsh) } # write.config.PEPRMT diff --git a/models/preles/R/write.config.PRELES.R b/models/preles/R/write.config.PRELES.R index 42e8433c241..8a009be52a7 100644 --- a/models/preles/R/write.config.PRELES.R +++ b/models/preles/R/write.config.PRELES.R @@ -34,6 +34,5 @@ write.config.PRELES <- function(defaults, trait.values, settings, run.id) { "'",settings$run$end.date,"') ", '" | R --vanilla' ) - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) } # write.config.PRELES diff --git a/models/rothc/R/write.config.RothC.R b/models/rothc/R/write.config.RothC.R index 452396cfad4..cf3a0b22c52 100644 --- a/models/rothc/R/write.config.RothC.R +++ b/models/rothc/R/write.config.RothC.R @@ -75,8 +75,7 @@ write.config.RothC <- function(defaults, trait.values, settings, run.id) { jobsh <- gsub("@BINARY@", settings$model$binary, jobsh) - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) #----------------------------------------------------------------------- ### Edit a templated config file for runs diff --git a/models/sibcasa/R/write.config.SIBCASA.R b/models/sibcasa/R/write.config.SIBCASA.R index 1b390c4dee7..f8bf2f6495e 100644 --- a/models/sibcasa/R/write.config.SIBCASA.R +++ b/models/sibcasa/R/write.config.SIBCASA.R @@ -1,4 +1,5 @@ + #-------------------------------------------------------------------------------------------------# #' Writes a SIBCASA config file. #' @@ -60,8 +61,7 @@ write.config.SIBCASA <- function(defaults, trait.values, settings, run.id) { jobsh <- gsub("@BINARY@", settings$model$binary, jobsh) - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) #----------------------------------------------------------------------- ### Edit a templated config file for runs diff --git a/models/sipnet/R/write.configs.SIPNET.R b/models/sipnet/R/write.configs.SIPNET.R index 70993936d40..794850e6894 100755 --- a/models/sipnet/R/write.configs.SIPNET.R +++ b/models/sipnet/R/write.configs.SIPNET.R @@ -224,8 +224,7 @@ write.config.SIPNET <- function(defaults, trait.values, settings, run.id, inputs } jobsh <- gsub("@DELETE.RAW@", settings$model$delete.raw, jobsh) - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) ### Copy event file diff --git a/models/stics/R/write.config.STICS.R b/models/stics/R/write.config.STICS.R index a25063193cb..4f13a8fccd9 100644 --- a/models/stics/R/write.config.STICS.R +++ b/models/stics/R/write.config.STICS.R @@ -919,8 +919,7 @@ write.config.STICS <- function(defaults, trait.values, settings, run.id) { jobsh <- gsub("@MODFILE@", paste0("mod_s", basename(usmdirs[1]), ".sti"), jobsh) jobsh <- gsub("@STICSEXE@", stics_exe, jobsh) - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) } # write.config.STICS diff --git a/models/template/R/write.config.MODEL.R b/models/template/R/write.config.MODEL.R index 32aac0ab9fe..ce787b36921 100644 --- a/models/template/R/write.config.MODEL.R +++ b/models/template/R/write.config.MODEL.R @@ -69,8 +69,7 @@ write.config.MODEL <- function(defaults, trait.values, settings, run.id) { jobsh <- gsub("@BINARY@", settings$model$binary, jobsh) - writeLines(jobsh, con = file.path(settings$rundir, run.id, "job.sh")) - Sys.chmod(file.path(settings$rundir, run.id, "job.sh")) + PEcAn.utils::write_job_sh(settings$rundir, run.id, jobsh) #----------------------------------------------------------------------- ### Edit a templated config file for runs