mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
915 lines
34 KiB
C
915 lines
34 KiB
C
/*
|
|
Copyright (C) 2011 Statoil ASA, Norway.
|
|
|
|
The file 'ext_job.c' is part of ERT - Ensemble based Reservoir Tool.
|
|
|
|
ERT is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
|
for more details.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <util.h>
|
|
#include <hash.h>
|
|
#include <ext_job.h>
|
|
#include <config.h>
|
|
#include <stringlist.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <subst_list.h>
|
|
#include <parser.h>
|
|
|
|
/*
|
|
About arguments
|
|
---------------
|
|
How a job is run is defined in terms of the following variables:
|
|
|
|
o stdout_file / stdin_file / stderr_file
|
|
o arglist
|
|
o ....
|
|
|
|
These variables will then contain string values from when the job
|
|
configuration is read in, for example this little job
|
|
|
|
STDOUT my_stdout
|
|
STDERR my_stderr
|
|
ARGLIST my_job_input my_job_output
|
|
|
|
stdout & stderr are redirected to the files 'my_stdout' and
|
|
'my_stderr' respectively, and when invoked with an exec() call the
|
|
job is given the argumentlist:
|
|
|
|
my_job_input my_job_output
|
|
|
|
This implies that _every_time_ this job is invoked the argumentlist
|
|
will be identical; that is clearly quite limiting! To solve this we
|
|
have the possibility of performing string substitutions on the
|
|
strings in the job defintion prior to executing the job, this is
|
|
handled with the privat_args substitutions. The definition for a
|
|
copy-file job:
|
|
|
|
|
|
EXECUTABLE /bin/cp
|
|
ARGLIST <SRC_FILE> <TARGET_FILE>
|
|
|
|
|
|
This can then be invoked several times, with different key=value
|
|
arguments for the SRC_FILE and TARGET_FILE:
|
|
|
|
|
|
COPY_FILE(SRC_FILE = file1 , TARGET_FILE = /tmp/file1)
|
|
COPY_FILE(SRC_FILE = file2 , TARGET_FILE = /tmp/file2)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
jobList = [
|
|
{"executable" : None,
|
|
"environment" : {"LM_LICENSE_PATH" : "1700@osl001lic.hda.hydro.com:1700@osl002lic.hda.hydro.com:1700@osl003lic.hda.hydro.com",
|
|
"F_UFMTENDIAN" : "big"},
|
|
"target_file":"222",
|
|
"argList" : [],
|
|
"stdout" : "eclipse.stdout",
|
|
"stderr" : "eclipse.stdout",
|
|
"stdin" : "eclipse.stdin"}]
|
|
*/
|
|
|
|
|
|
#define EXT_JOB_TYPE_ID 763012
|
|
|
|
|
|
struct ext_job_struct {
|
|
UTIL_TYPE_ID_DECLARATION;
|
|
char * name;
|
|
char * executable;
|
|
char * target_file;
|
|
char * error_file; /* Job has failed if this is present. */
|
|
char * start_file; /* Will not start if not this file is present */
|
|
char * stdout_file;
|
|
char * stdin_file;
|
|
char * stderr_file;
|
|
char * license_path; /* If this is NULL - it will be unrestricted ... */
|
|
char * license_root_path;
|
|
char * config_file;
|
|
int max_running; /* 0 means unlimited. */
|
|
int max_running_minutes; /* The maximum number of minutes this job is allowed to run - 0: unlimited. */
|
|
subst_list_type * private_args; /* A substitution list of input arguments which is performed before the external substitutions -
|
|
these are the arguments supplied as key=value pairs in the forward model call. */
|
|
char * private_args_string;
|
|
char * argv_string;
|
|
stringlist_type * argv; /* This should *NOT* start with the executable */
|
|
hash_type * environment;
|
|
hash_type * default_mapping;
|
|
char * help_text;
|
|
|
|
bool private_job; /* Can the current user/delete this job? (private_job == true) means the user can edit it. */
|
|
bool __valid; /* Temporary variable consulted during the bootstrap - when the ext_job is completely initialized this should NOT be consulted anymore. */
|
|
};
|
|
|
|
|
|
static UTIL_SAFE_CAST_FUNCTION( ext_job , EXT_JOB_TYPE_ID)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ext_job_type * ext_job_alloc__(const char * name , const char * license_root_path , bool private_job) {
|
|
ext_job_type * ext_job = util_malloc(sizeof * ext_job );
|
|
|
|
UTIL_TYPE_ID_INIT( ext_job , EXT_JOB_TYPE_ID);
|
|
ext_job->name = util_alloc_string_copy( name );
|
|
ext_job->license_root_path = util_alloc_string_copy( license_root_path );
|
|
ext_job->executable = NULL;
|
|
ext_job->stdout_file = NULL;
|
|
ext_job->target_file = NULL;
|
|
ext_job->error_file = NULL;
|
|
ext_job->start_file = NULL;
|
|
ext_job->stdin_file = NULL;
|
|
ext_job->stderr_file = NULL;
|
|
ext_job->environment = hash_alloc();
|
|
ext_job->default_mapping = hash_alloc();
|
|
ext_job->argv = stringlist_alloc_new();
|
|
ext_job->argv_string = NULL;
|
|
ext_job->__valid = true;
|
|
ext_job->license_path = NULL;
|
|
ext_job->config_file = NULL;
|
|
ext_job->max_running = 0; /* 0 means unlimited. */
|
|
ext_job->max_running_minutes = 0; /* 0 means unlimited. */
|
|
ext_job->private_job = private_job; /* If private_job == true the job is user editable. */
|
|
ext_job->help_text = NULL;
|
|
ext_job->private_args_string = NULL;
|
|
|
|
/*
|
|
ext_job->private_args is set explicitly in the ext_job_alloc()
|
|
and ext_job_alloc_copy() functions.
|
|
*/
|
|
return ext_job;
|
|
}
|
|
|
|
|
|
const char * ext_job_get_help_text( const ext_job_type * job ) {
|
|
if (job->help_text != NULL)
|
|
return job->help_text;
|
|
else
|
|
return "No help text installed for this job.";
|
|
}
|
|
|
|
|
|
void ext_job_set_help_text( ext_job_type * job , const char * help_text) {
|
|
job->help_text = util_realloc_string_copy( job->help_text , help_text );
|
|
}
|
|
|
|
/*
|
|
Exported function - must have name != NULL. Observe that the
|
|
instance returned from this function is not really usable for
|
|
anything.
|
|
|
|
Should probably define a minium set of parameters which must be set
|
|
before the job is in a valid initialized state.
|
|
*/
|
|
|
|
ext_job_type * ext_job_alloc(const char * name , const char * license_root_path , bool private_job) {
|
|
ext_job_type * ext_job = ext_job_alloc__(name , license_root_path , private_job);
|
|
ext_job->private_args = subst_list_alloc( NULL );
|
|
return ext_job;
|
|
}
|
|
|
|
|
|
|
|
|
|
ext_job_type * ext_job_alloc_copy(const ext_job_type * src_job) {
|
|
ext_job_type * new_job = ext_job_alloc__( src_job->name , src_job->license_root_path , true /* All copies are by default private jobs. */);
|
|
|
|
new_job->config_file = util_alloc_string_copy(src_job->config_file);
|
|
new_job->executable = util_alloc_string_copy(src_job->executable);
|
|
new_job->target_file = util_alloc_string_copy(src_job->target_file);
|
|
new_job->error_file = util_alloc_string_copy(src_job->error_file);
|
|
new_job->start_file = util_alloc_string_copy(src_job->start_file);
|
|
new_job->stdout_file = util_alloc_string_copy(src_job->stdout_file);
|
|
new_job->stdin_file = util_alloc_string_copy(src_job->stdin_file);
|
|
new_job->stderr_file = util_alloc_string_copy(src_job->stderr_file);
|
|
new_job->license_path = util_alloc_string_copy(src_job->license_path);
|
|
|
|
ext_job_set_help_text( new_job , src_job->help_text );
|
|
|
|
new_job->max_running_minutes = src_job->max_running_minutes;
|
|
new_job->max_running = src_job->max_running;
|
|
new_job->private_args = subst_list_alloc_deep_copy( src_job->private_args );
|
|
|
|
/* Copying over all the keys in the environment hash table */
|
|
{
|
|
hash_iter_type * iter = hash_iter_alloc( src_job->environment );
|
|
const char * key = hash_iter_get_next_key(iter);
|
|
while (key != NULL) {
|
|
char * value = hash_get( src_job->environment , key);
|
|
hash_insert_hash_owned_ref( new_job->environment , key , util_alloc_string_copy(value) , free);
|
|
key = hash_iter_get_next_key(iter);
|
|
}
|
|
hash_iter_free(iter);
|
|
}
|
|
|
|
|
|
/* The default mapping. */
|
|
{
|
|
hash_iter_type * iter = hash_iter_alloc( src_job->default_mapping );
|
|
const char * key = hash_iter_get_next_key(iter);
|
|
while (key != NULL) {
|
|
char * value = hash_get( src_job->default_mapping , key);
|
|
hash_insert_hash_owned_ref( new_job->default_mapping , key , util_alloc_string_copy(value) , free);
|
|
key = hash_iter_get_next_key(iter);
|
|
}
|
|
hash_iter_free(iter);
|
|
}
|
|
|
|
|
|
|
|
stringlist_deep_copy( new_job->argv , src_job->argv );
|
|
|
|
return new_job;
|
|
}
|
|
|
|
|
|
|
|
|
|
void ext_job_free(ext_job_type * ext_job) {
|
|
free(ext_job->name);
|
|
util_safe_free(ext_job->executable);
|
|
util_safe_free(ext_job->stdout_file);
|
|
util_safe_free(ext_job->stdin_file);
|
|
util_safe_free(ext_job->target_file);
|
|
util_safe_free(ext_job->error_file);
|
|
util_safe_free(ext_job->stderr_file);
|
|
util_safe_free(ext_job->license_path);
|
|
util_safe_free(ext_job->license_root_path);
|
|
util_safe_free(ext_job->config_file);
|
|
util_safe_free(ext_job->argv_string);
|
|
util_safe_free(ext_job->help_text);
|
|
util_safe_free(ext_job->private_args_string);
|
|
|
|
hash_free( ext_job->default_mapping);
|
|
hash_free( ext_job->environment );
|
|
stringlist_free(ext_job->argv);
|
|
subst_list_free( ext_job->private_args );
|
|
free(ext_job);
|
|
}
|
|
|
|
void ext_job_free__(void * __ext_job) {
|
|
ext_job_free ( ext_job_safe_cast(__ext_job) );
|
|
}
|
|
|
|
|
|
static void __update_mode( const char * filename , mode_t add_mode) {
|
|
util_addmode_if_owner( filename , add_mode);
|
|
}
|
|
|
|
|
|
/**
|
|
The license_path =
|
|
|
|
root_license_path / job_name / job_name
|
|
|
|
*/
|
|
|
|
static void ext_job_init_license_control(ext_job_type * ext_job) {
|
|
if (ext_job->license_path == NULL) {
|
|
ext_job->license_path = util_alloc_sprintf("%s%c%s" , ext_job->license_root_path , UTIL_PATH_SEP_CHAR , ext_job->name );
|
|
util_make_path( ext_job->license_path );
|
|
printf("License for %s in %s \n",ext_job->name , ext_job->license_path);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ext_job_set_max_time( ext_job_type * ext_job , int max_time ) {
|
|
ext_job->max_running_minutes = max_time;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
There are many different alternatives for what the @executable
|
|
variable points to. The main classification is whether the
|
|
@executable corresponds to an existing file or not:
|
|
|
|
@executable exists: We verify that the executable is indeed
|
|
executable for the current user; if this check fails the job
|
|
is marked as invalid and later discarded.
|
|
|
|
@executable does not exist: In this case we check whether the
|
|
@executable parameter corresponds to an absolute or relative
|
|
path:
|
|
|
|
@executable is an absolute path: Discard the job.
|
|
|
|
@executable is a relative path: Try to check the PATH
|
|
variable, otherwise use the input value and hope that input
|
|
value should be interpreted as template key which will be
|
|
replaced upon execution.
|
|
*/
|
|
|
|
void ext_job_set_executable(ext_job_type * ext_job, const char * executable) {
|
|
|
|
if (!util_file_exists(executable)) {
|
|
if (util_is_abs_path( executable )) {
|
|
/* If you have given an absolute path (i.e. starting with '/' to
|
|
a non existing job we mark it as invalid - no possibility to
|
|
provide context replacement afterwards. The job will be
|
|
discarded by the calling scope.
|
|
*/
|
|
fprintf(stderr , "** The executable:%s can not be found - job:%s will not be available.\n" , executable , ext_job->name );
|
|
ext_job->__valid = false;
|
|
} else {
|
|
/* Go through the PATH variable to try to locate the executable. */
|
|
char * path_executable = util_alloc_PATH_executable( executable );
|
|
|
|
if (path_executable != NULL) {
|
|
ext_job_set_executable( ext_job , path_executable );
|
|
free( path_executable );
|
|
} else
|
|
/* We take the chance that user will supply a valid subst key for this later;
|
|
if the final executable is not an actually executable file when exporting the
|
|
job from ext_job_python_fprintf() a big warning will be written on stderr.
|
|
*/
|
|
ext_job->executable = util_realloc_string_copy(ext_job->executable , executable);
|
|
}
|
|
} else {
|
|
/*
|
|
The @executable parameter points to an existing file; we store
|
|
the full path as the executable field of the job; we also try
|
|
to update the mode of the full_path executable to make sure it
|
|
is executable.
|
|
*/
|
|
char * full_path = util_alloc_realpath( executable );
|
|
__update_mode( full_path , S_IRUSR + S_IWUSR + S_IXUSR + S_IRGRP + S_IWGRP + S_IXGRP + S_IROTH + S_IXOTH); /* u:rwx g:rwx o:rx */
|
|
ext_job->executable = util_realloc_string_copy(ext_job->executable , full_path);
|
|
free( full_path );
|
|
}
|
|
|
|
/*
|
|
If in the end we do not have execute rights to the executable :
|
|
discard the job.
|
|
*/
|
|
if (ext_job->executable != NULL) {
|
|
if (util_file_exists(executable)) {
|
|
if (!util_is_executable( ext_job->executable )) {
|
|
fprintf(stderr , "** You do not have execute rights to:%s - job will not be available.\n" , ext_job->executable);
|
|
ext_job->__valid = false; /* Mark the job as NOT successfully installed - the ext_job
|
|
instance will later be freed and discarded. */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Observe that this does NOT reread the ext_job instance from the new
|
|
config_file.
|
|
*/
|
|
|
|
|
|
/*****************************************************************/
|
|
/* Scalar set and get functions */
|
|
|
|
void ext_job_set_config_file(ext_job_type * ext_job, const char * config_file) {
|
|
ext_job->config_file = util_realloc_string_copy(ext_job->config_file , config_file);
|
|
}
|
|
|
|
const char * ext_job_get_config_file(const ext_job_type * ext_job) {
|
|
return ext_job->config_file;
|
|
}
|
|
|
|
void ext_job_set_target_file(ext_job_type * ext_job, const char * target_file) {
|
|
ext_job->target_file = util_realloc_string_copy(ext_job->target_file , target_file);
|
|
}
|
|
|
|
const char * ext_job_get_target_file(const ext_job_type * ext_job) {
|
|
return ext_job->target_file;
|
|
}
|
|
|
|
void ext_job_set_error_file(ext_job_type * ext_job, const char * error_file) {
|
|
ext_job->error_file = util_realloc_string_copy(ext_job->error_file , error_file);
|
|
}
|
|
|
|
const char * ext_job_get_error_file(const ext_job_type * ext_job) {
|
|
return ext_job->error_file;
|
|
}
|
|
|
|
const char * ext_job_get_executable(const ext_job_type * ext_job) {
|
|
return ext_job->executable;
|
|
}
|
|
|
|
void ext_job_set_start_file(ext_job_type * ext_job, const char * start_file) {
|
|
ext_job->start_file = util_realloc_string_copy(ext_job->start_file , start_file);
|
|
}
|
|
|
|
const char * ext_job_get_start_file(const ext_job_type * ext_job) {
|
|
return ext_job->start_file;
|
|
}
|
|
|
|
void ext_job_set_name(ext_job_type * ext_job, const char * name) {
|
|
ext_job->name = util_realloc_string_copy(ext_job->name , name);
|
|
}
|
|
|
|
const char * ext_job_get_name(const ext_job_type * ext_job) {
|
|
return ext_job->name;
|
|
}
|
|
void ext_job_set_stdin_file(ext_job_type * ext_job, const char * stdin_file) {
|
|
ext_job->stdin_file = util_realloc_string_copy(ext_job->stdin_file , stdin_file);
|
|
}
|
|
|
|
const char * ext_job_get_stdin_file(const ext_job_type * ext_job) {
|
|
return ext_job->stdin_file;
|
|
}
|
|
|
|
void ext_job_set_stdout_file(ext_job_type * ext_job, const char * stdout_file) {
|
|
ext_job->stdout_file = util_realloc_string_copy(ext_job->stdout_file , stdout_file);
|
|
}
|
|
|
|
const char * ext_job_get_stdout_file(const ext_job_type * ext_job) {
|
|
return ext_job->stdout_file;
|
|
}
|
|
|
|
void ext_job_set_stderr_file(ext_job_type * ext_job, const char * stderr_file) {
|
|
ext_job->stderr_file = util_realloc_string_copy(ext_job->stderr_file , stderr_file);
|
|
}
|
|
|
|
const char * ext_job_get_stderr_file(const ext_job_type * ext_job) {
|
|
return ext_job->stderr_file;
|
|
}
|
|
|
|
void ext_job_set_max_running( ext_job_type * ext_job , int max_running) {
|
|
ext_job->max_running = max_running;
|
|
if (max_running > 0)
|
|
ext_job_init_license_control( ext_job );
|
|
}
|
|
|
|
int ext_job_get_max_running( const ext_job_type * ext_job ) {
|
|
return ext_job->max_running;
|
|
}
|
|
|
|
void ext_job_set_max_running_minutes( ext_job_type * ext_job , int max_running_minutes) {
|
|
ext_job->max_running_minutes = max_running_minutes;
|
|
}
|
|
|
|
int ext_job_get_max_running_minutes( const ext_job_type * ext_job ) {
|
|
return ext_job->max_running_minutes;
|
|
}
|
|
|
|
/*****************************************************************/
|
|
|
|
void ext_job_set_private_arg(ext_job_type * ext_job, const char * key , const char * value) {
|
|
subst_list_append_copy( ext_job->private_args , key , value , NULL);
|
|
}
|
|
|
|
void ext_job_add_environment(ext_job_type *ext_job , const char * key , const char * value) {
|
|
hash_insert_hash_owned_ref( ext_job->environment , key , util_alloc_string_copy( value ) , free);
|
|
}
|
|
|
|
|
|
void ext_job_clear_environment( ext_job_type * ext_job ) {
|
|
hash_clear( ext_job->environment );
|
|
}
|
|
|
|
hash_type * ext_job_get_environment( ext_job_type * ext_job ) {
|
|
return ext_job->environment;
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
|
|
static char * __alloc_filtered_string( const char * src_string , const subst_list_type * private_args, const subst_list_type * global_args) {
|
|
char * tmp1 = subst_list_alloc_filtered_string( private_args , src_string ); /* internal filtering first */
|
|
char * tmp2;
|
|
|
|
if (global_args != NULL) {
|
|
tmp2 = subst_list_alloc_filtered_string( global_args , tmp1 ); /* Global filtering. */
|
|
free( tmp1 );
|
|
} else
|
|
tmp2 = tmp1;
|
|
|
|
return tmp2;
|
|
|
|
}
|
|
|
|
static void __fprintf_string(FILE * stream , const char * s , const subst_list_type * private_args, const subst_list_type * global_args) {
|
|
char * filtered_string = __alloc_filtered_string(s , private_args , global_args );
|
|
fprintf(stream , "\"%s\"" , filtered_string );
|
|
free( filtered_string );
|
|
}
|
|
|
|
|
|
static void __fprintf_python_string(FILE * stream , const char * id , const char * value, const subst_list_type * private_args, const subst_list_type * global_args) {
|
|
fprintf(stream , "\"%s\" : " , id);
|
|
if (value == NULL)
|
|
fprintf(stream,"None");
|
|
else
|
|
__fprintf_string(stream , value , private_args , global_args);
|
|
}
|
|
|
|
|
|
static void __fprintf_init_python_list( FILE * stream , const char * id ) {
|
|
fprintf(stream , "\"%s\" : " , id);
|
|
fprintf(stream,"[");
|
|
}
|
|
|
|
static void __fprintf_close_python_list( FILE * stream ) {
|
|
fprintf(stream,"]");
|
|
}
|
|
|
|
|
|
static void __fprintf_python_list(FILE * stream , const char * id , const stringlist_type * list , const subst_list_type * private_args, const subst_list_type * global_args ) {
|
|
int size;
|
|
int i;
|
|
__fprintf_init_python_list( stream , id );
|
|
if (list == NULL)
|
|
size = 0;
|
|
else
|
|
size = stringlist_get_size(list);
|
|
|
|
for (i = 0; i < size; i++) {
|
|
const char * value = stringlist_iget(list , i);
|
|
__fprintf_string(stream , value , private_args , global_args);
|
|
|
|
if (i < (size - 1))
|
|
fprintf(stream,",");
|
|
}
|
|
__fprintf_close_python_list( stream );
|
|
}
|
|
|
|
|
|
|
|
static void __fprintf_python_hash(FILE * stream , const char * id , hash_type * hash, const subst_list_type * private_args, const subst_list_type * global_args) {
|
|
fprintf(stream , "\"%s\" : " , id);
|
|
int hash_size = hash_get_size(hash);
|
|
if (hash_size > 0) {
|
|
int counter = 0;
|
|
fprintf(stream,"{");
|
|
hash_iter_type * iter = hash_iter_alloc(hash);
|
|
const char * key = hash_iter_get_next_key(iter);
|
|
while (key != NULL) {
|
|
const char * value = hash_get(hash , key);
|
|
|
|
fprintf(stream,"\"%s\" : " , key);
|
|
__fprintf_string(stream , value , private_args , global_args);
|
|
|
|
if (counter < (hash_size - 1))
|
|
fprintf(stream,",");
|
|
|
|
key = hash_iter_get_next_key(iter);
|
|
}
|
|
fprintf(stream,"}");
|
|
} else
|
|
fprintf(stream , "None");
|
|
}
|
|
|
|
|
|
static void __fprintf_python_int( FILE * stream , const char * key , int value) {
|
|
if (value > 0)
|
|
fprintf(stream , "\"%s\" : %d" , key , value);
|
|
else
|
|
fprintf(stream , "\"%s\" : None" , key);
|
|
}
|
|
|
|
|
|
static void __end_line(FILE * stream) {
|
|
fprintf(stream,",\n");
|
|
}
|
|
|
|
|
|
static void __indent(FILE * stream, int indent) {
|
|
int i;
|
|
for (i = 0; i < indent; i++)
|
|
fprintf(stream," ");
|
|
}
|
|
|
|
|
|
/*
|
|
This is special cased to support the default mapping.
|
|
*/
|
|
|
|
static void ext_job_fprintf_python_argList( const ext_job_type * ext_job , FILE * stream , const subst_list_type * global_args) {
|
|
__fprintf_init_python_list( stream , "argList" );
|
|
{
|
|
for (int index = 0; index < stringlist_get_size( ext_job->argv ); index++) {
|
|
const char * src_string = stringlist_iget( ext_job->argv , index );
|
|
char * filtered_string = __alloc_filtered_string(src_string , ext_job->private_args , global_args );
|
|
if (hash_has_key( ext_job->default_mapping , filtered_string ))
|
|
filtered_string = util_realloc_string_copy( filtered_string , hash_get( ext_job->default_mapping , filtered_string ));
|
|
|
|
fprintf(stream , "\"%s\"" , filtered_string );
|
|
if (index < (stringlist_get_size( ext_job->argv) - 1))
|
|
fprintf(stream , "," );
|
|
|
|
free( filtered_string );
|
|
}
|
|
}
|
|
__fprintf_close_python_list( stream );
|
|
}
|
|
|
|
|
|
|
|
void ext_job_python_fprintf(const ext_job_type * ext_job, FILE * stream, const subst_list_type * global_args) {
|
|
char * executable;
|
|
executable = subst_list_alloc_filtered_string( ext_job->private_args , ext_job->executable );
|
|
if (global_args != NULL)
|
|
subst_list_update_string( global_args , &executable );
|
|
|
|
if (util_is_executable( executable )) {
|
|
fprintf(stream," {");
|
|
__indent(stream, 0); __fprintf_python_string(stream , "name" , ext_job->name , ext_job->private_args , NULL); __end_line(stream);
|
|
__indent(stream, 2); __fprintf_python_string(stream , "executable" , ext_job->executable , ext_job->private_args, global_args); __end_line(stream);
|
|
__indent(stream, 2); __fprintf_python_string(stream , "target_file" , ext_job->target_file , ext_job->private_args, global_args); __end_line(stream);
|
|
__indent(stream, 2); __fprintf_python_string(stream , "error_file" , ext_job->error_file , ext_job->private_args, global_args); __end_line(stream);
|
|
__indent(stream, 2); __fprintf_python_string(stream , "start_file" , ext_job->start_file , ext_job->private_args, global_args); __end_line(stream);
|
|
__indent(stream, 2); __fprintf_python_string(stream , "stdout" , ext_job->stdout_file , ext_job->private_args, global_args); __end_line(stream);
|
|
__indent(stream, 2); __fprintf_python_string(stream , "stderr" , ext_job->stderr_file , ext_job->private_args, global_args); __end_line(stream);
|
|
__indent(stream, 2); __fprintf_python_string(stream , "stdin" , ext_job->stdin_file , ext_job->private_args, global_args); __end_line(stream);
|
|
__indent(stream, 2); ext_job_fprintf_python_argList(ext_job , stream , global_args); __end_line(stream);
|
|
__indent(stream, 2); __fprintf_python_hash(stream , "environment" , ext_job->environment , ext_job->private_args, global_args); __end_line(stream);
|
|
__indent(stream, 2); __fprintf_python_string(stream , "license_path" , ext_job->license_path , ext_job->private_args, global_args); __end_line(stream);
|
|
__indent(stream, 2); __fprintf_python_int( stream , "max_running_minutes" , ext_job->max_running_minutes ); __end_line(stream);
|
|
__indent(stream, 2); __fprintf_python_int( stream , "max_running" , ext_job->max_running ); __end_line(stream);
|
|
fprintf(stream,"}");
|
|
} else
|
|
fprintf(stderr," ** WARNING: The executable:%s could not be located on host computer - job will most probably fail.\n", executable);
|
|
|
|
free( executable );
|
|
}
|
|
|
|
|
|
#define PRINT_KEY_STRING( stream , key , value ) \
|
|
if (value != NULL) \
|
|
{ \
|
|
fprintf(stream , "%16s ", key); \
|
|
fprintf(stream , "%s\n" , value); \
|
|
}
|
|
|
|
|
|
#define PRINT_KEY_INT( stream , key , value ) \
|
|
if (value != 0) \
|
|
{ \
|
|
fprintf(stream , "%16s ", key); \
|
|
fprintf(stream , "%d\n" , value); \
|
|
}
|
|
|
|
|
|
/**
|
|
Observe that the job will save itself to the internalized
|
|
config_file; if you wish to save to some other place you must call
|
|
ext_job_set_config_file() first.
|
|
*/
|
|
|
|
void ext_job_save( const ext_job_type * ext_job ) {
|
|
FILE * stream = util_mkdir_fopen( ext_job->config_file , "w" );
|
|
|
|
PRINT_KEY_STRING( stream , "EXECUTABLE" , ext_job->executable);
|
|
PRINT_KEY_STRING( stream , "STDIN" , ext_job->stdin_file);
|
|
PRINT_KEY_STRING( stream , "STDERR" , ext_job->stderr_file);
|
|
PRINT_KEY_STRING( stream , "STDOUT" , ext_job->stdout_file);
|
|
PRINT_KEY_STRING( stream , "TARGET_FILE" , ext_job->target_file);
|
|
PRINT_KEY_STRING( stream , "START_FILE" , ext_job->start_file);
|
|
PRINT_KEY_STRING( stream , "ERROR_FILE" , ext_job->error_file);
|
|
PRINT_KEY_INT( stream , "MAX_RUNNING" , ext_job->max_running);
|
|
PRINT_KEY_INT( stream , "MAX_RUNNING_MINUTES" , ext_job->max_running_minutes);
|
|
|
|
if (stringlist_get_size( ext_job->argv ) > 0) {
|
|
fprintf(stream , "%16s" , "ARGLIST");
|
|
stringlist_fprintf( ext_job->argv , " " , stream );
|
|
fprintf(stream , "\n");
|
|
}
|
|
if (hash_get_size( ext_job->environment ) > 0) {
|
|
hash_iter_type * hash_iter = hash_iter_alloc( ext_job->environment );
|
|
while (!hash_iter_is_complete( hash_iter )) {
|
|
const char * key = hash_iter_get_next_key( hash_iter );
|
|
fprintf(stream, "%16s %16s %s\n" , "ENV" , key , (const char *) hash_get( ext_job->environment , key ));
|
|
}
|
|
hash_iter_free( hash_iter );
|
|
}
|
|
fclose( stream );
|
|
}
|
|
|
|
#undef PRINT_KEY_STRING
|
|
#undef PRINT_KEY_INT
|
|
|
|
|
|
|
|
void ext_job_fprintf(const ext_job_type * ext_job , FILE * stream) {
|
|
fprintf(stream , "%s", ext_job->name);
|
|
if (subst_list_get_size( ext_job->private_args ) > 0) {
|
|
fprintf(stream , "(");
|
|
subst_list_fprintf(ext_job->private_args , stream);
|
|
fprintf(stream , ")");
|
|
}
|
|
fprintf(stream , " ");
|
|
}
|
|
|
|
|
|
/**
|
|
The format variable @fmt should contain two '%s' placeholders -
|
|
one for the job name, and one for the job description file.
|
|
*/
|
|
|
|
void ext_job_fprintf_config(const ext_job_type * ext_job , const char * fmt , FILE * stream) {
|
|
fprintf(stream , fmt , ext_job->name , ext_job->config_file );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ext_job_type * ext_job_fscanf_alloc(const char * name , const char * license_root_path , bool private_job , const char * config_file) {
|
|
{
|
|
mode_t target_mode = S_IRUSR + S_IWUSR + S_IRGRP + S_IWGRP + S_IROTH; /* u+rw g+rw o+r */
|
|
__update_mode( config_file , target_mode );
|
|
}
|
|
|
|
if (util_entry_readable( config_file)) {
|
|
ext_job_type * ext_job = ext_job_alloc(name , license_root_path , private_job);
|
|
config_type * config = config_alloc( );
|
|
|
|
ext_job_set_config_file( ext_job , config_file );
|
|
{
|
|
config_schema_item_type * item;
|
|
item = config_add_schema_item(config , "MAX_RUNNING" , false , false); config_schema_item_set_argc_minmax(item , 1 , 1 , 1 , (const config_item_types [1]) {CONFIG_INT});
|
|
item = config_add_schema_item(config , "STDIN" , false , false); config_schema_item_set_argc_minmax(item , 1 , 1 , 0 , NULL);
|
|
item = config_add_schema_item(config , "STDOUT" , false , false); config_schema_item_set_argc_minmax(item , 1 , 1 , 0 , NULL);
|
|
item = config_add_schema_item(config , "STDERR" , false , false); config_schema_item_set_argc_minmax(item , 1 , 1 , 0 , NULL);
|
|
item = config_add_schema_item(config , "EXECUTABLE" , false , false); config_schema_item_set_argc_minmax(item , 1 , 1 , 0 , NULL);
|
|
item = config_add_schema_item(config , "TARGET_FILE" , false , false); config_schema_item_set_argc_minmax(item , 1 , 1 , 0 , NULL);
|
|
item = config_add_schema_item(config , "ERROR_FILE" , false , false); config_schema_item_set_argc_minmax(item , 1 , 1 , 0 , NULL);
|
|
item = config_add_schema_item(config , "START_FILE" , false , false); config_schema_item_set_argc_minmax(item , 1 , 1 , 0 , NULL);
|
|
item = config_add_schema_item(config , "ENV" , false , true ); config_schema_item_set_argc_minmax(item , 2 , 2 , 0 , NULL);
|
|
item = config_add_schema_item(config , "DEFAULT" , false , true ); config_schema_item_set_argc_minmax(item , 2 , 2 , 0 , NULL);
|
|
item = config_add_schema_item(config , "ARGLIST" , false , true ); config_schema_item_set_argc_minmax(item , 1 ,-1 , 0 , NULL);
|
|
item = config_add_schema_item(config , "MAX_RUNNING_MINUTES" , false , false); config_schema_item_set_argc_minmax(item , 1 , 1 , 1 , (const config_item_types [1]) {CONFIG_INT});
|
|
}
|
|
config_add_alias(config , "EXECUTABLE" , "PORTABLE_EXE");
|
|
config_parse(config , config_file , "--" , NULL , NULL , true , true);
|
|
{
|
|
if (config_item_set(config , "STDIN")) ext_job_set_stdin_file(ext_job , config_iget(config , "STDIN" , 0,0));
|
|
if (config_item_set(config , "STDOUT")) ext_job_set_stdout_file(ext_job , config_iget(config , "STDOUT" , 0,0));
|
|
if (config_item_set(config , "STDERR")) ext_job_set_stderr_file(ext_job , config_iget(config , "STDERR" , 0,0));
|
|
if (config_item_set(config , "ERROR_FILE")) ext_job_set_error_file(ext_job , config_iget(config , "ERROR_FILE" , 0,0));
|
|
if (config_item_set(config , "TARGET_FILE")) ext_job_set_target_file(ext_job , config_iget(config , "TARGET_FILE" , 0,0));
|
|
if (config_item_set(config , "START_FILE")) ext_job_set_start_file(ext_job , config_iget(config , "START_FILE" , 0,0));
|
|
if (config_item_set(config , "EXECUTABLE")) ext_job_set_executable(ext_job , config_iget(config , "EXECUTABLE" , 0,0));
|
|
if (config_item_set(config , "MAX_RUNNING")) ext_job_set_max_running(ext_job , config_iget_as_int(config , "MAX_RUNNING" , 0,0));
|
|
if (config_item_set(config , "MAX_RUNNING_MINUTES")) ext_job_set_max_time(ext_job , config_iget_as_int(config , "MAX_RUNNING_MINUTES" , 0,0));
|
|
|
|
|
|
|
|
if (config_item_set(config , "ARGLIST")) {
|
|
stringlist_type *argv = config_iget_stringlist_ref( config , "ARGLIST" , 0);
|
|
stringlist_deep_copy( ext_job->argv , argv );
|
|
}
|
|
|
|
|
|
/**
|
|
The code assumes that the hash tables are valid, can not be NULL:
|
|
*/
|
|
if (config_item_set(config , "ENV")) {
|
|
for (int occ_nr = 0; occ_nr < config_get_occurences( config , "ENV"); occ_nr++) {
|
|
const stringlist_type *key_value = config_iget_stringlist_ref( config , "ENV" , occ_nr);
|
|
for (int i=0; i < stringlist_get_size( key_value ); i+= 2)
|
|
hash_insert_hash_owned_ref( ext_job->environment,
|
|
stringlist_iget( key_value , i ) ,
|
|
util_alloc_string_copy( stringlist_iget( key_value , i + 1)) , free);
|
|
}
|
|
}
|
|
|
|
/* Default mappings; these are used to set values in the argList
|
|
which have not been supplied by the calling context. */
|
|
if (config_item_set(config , "DEFAULT")) {
|
|
for (int occ_nr = 0; occ_nr < config_get_occurences( config , "DEFAULT"); occ_nr++) {
|
|
const stringlist_type *key_value = config_iget_stringlist_ref( config , "DEFAULT" , occ_nr);
|
|
for (int i=0; i < stringlist_get_size( key_value ); i+= 2)
|
|
hash_insert_hash_owned_ref( ext_job->default_mapping,
|
|
stringlist_iget( key_value , i ) ,
|
|
util_alloc_string_copy( stringlist_iget( key_value , i + 1)) , free);
|
|
}
|
|
}
|
|
}
|
|
config_free(config);
|
|
|
|
if (!ext_job->__valid) {
|
|
/*
|
|
Something NOT OK (i.e. EXECUTABLE now); free the job instance and return NULL:
|
|
*/
|
|
ext_job_free( ext_job );
|
|
ext_job = NULL;
|
|
fprintf(stderr,"** Warning: job: \'%s\' not available ... \n", name );
|
|
}
|
|
|
|
return ext_job;
|
|
} else {
|
|
fprintf(stderr,"** Warning: you do not have permission to read file:\'%s\' - job:%s not available. \n", config_file , name);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
const stringlist_type * ext_job_get_arglist( const ext_job_type * ext_job ) {
|
|
return ext_job->argv;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
*/
|
|
|
|
//const char * ext_job_get_arglist_as_string( ext_job_type * ext_job ) {
|
|
// if (stringlist_get_size( ext_job->argv ) == 0)
|
|
// return NULL;
|
|
// else {
|
|
// const char * sep = " ";
|
|
// int argc = stringlist_get_size( ext_job->argv );
|
|
// int i;
|
|
// buffer_type * buffer = buffer_alloc( 512 );
|
|
// for (i = 0; i < argc; i++) {
|
|
// const char * arg = stringlist_iget( ext_job->argv , i );
|
|
// bool quote = false;
|
|
// if (strchr(arg , ' ') != NULL)
|
|
// quote = true;
|
|
//
|
|
// if (quote)
|
|
// buffer_fwrite_char( buffer , ' ' );
|
|
// buffer_fwrite_char_ptr( buffer , arg );
|
|
// if (quote)
|
|
// buffer_fwrite_char( buffer , ' ' );
|
|
//
|
|
// if (i < (argc - 1))
|
|
// buffer_fwrite_char_ptr( buffer , sep );
|
|
//
|
|
// buffer_fwrite_char( buffer , '\0');
|
|
// util_safe_free(ext_job->argv_string);
|
|
// ext_job->argv_string = buffer_alloc_data_copy( buffer );
|
|
// buffer_free( buffer );
|
|
//
|
|
// return ext_job->argv_string;
|
|
// }
|
|
//}
|
|
//
|
|
//
|
|
//void ext_job_set_arglist_from_string( ext_job_type * ext_job , const char * argv_string ) {
|
|
// parser_type * parser = parser_alloc(" " , "\"" , NULL , NULL , NULL , NULL );
|
|
// stringlist_free( ext_job->argv );
|
|
// ext_job->argv = parser_tokenize_buffer( parser , argv_string , true );
|
|
// parser_free( parser );
|
|
//}
|
|
|
|
|
|
const char * ext_job_get_private_args_as_string( ext_job_type * ext_job ) {
|
|
util_safe_free( ext_job->private_args_string );
|
|
ext_job->private_args_string = subst_list_alloc_string_representation( ext_job->private_args );
|
|
return ext_job->private_args_string;
|
|
}
|
|
|
|
|
|
/**
|
|
Set the internal arguments of the job based on an input string
|
|
@arg_string which is of the form:
|
|
|
|
key1=value1, key2=value2 , key3=value3
|
|
|
|
The internal private argument list is cleared before adding these
|
|
arguments.
|
|
*/
|
|
|
|
int ext_job_set_private_args_from_string( ext_job_type * ext_job , const char * arg_string ) {
|
|
subst_list_clear( ext_job->private_args );
|
|
return subst_list_add_from_string( ext_job->private_args , arg_string , true );
|
|
}
|
|
|
|
|
|
|
|
bool ext_job_is_shared( const ext_job_type * ext_job ) {
|
|
return !ext_job->private_job;
|
|
}
|
|
|
|
bool ext_job_is_private( const ext_job_type * ext_job ) {
|
|
return ext_job->private_job;
|
|
}
|
|
|
|
|
|
#undef ASSERT_TOKENS
|