source: src/Fragmentation/Automation/Jobs/SystemCommandJob.cpp@ aec098

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since aec098 was d920b9, checked in by Frederik Heber <heber@…>, 13 years ago

Abstracted FragmentJob and introduced SystemCommandJob which has its former functionality.

  • FragmentJob now has just virtual function Work(), not implemented.
  • former command and outputfile is taken over by SystemCommandJob.
  • a FragmentJob or derived class is default cstor'ed always with JobId::IllegalJob.
  • so far SystemCommandJob captures command's stdout and parses it back from file. We use mkstemps() for creating a random file and popen() to pipe stdout directly. For this we require boost::iostreams and ::filesystem.
  • SystemCommandJob has virtual method extractString() to be adaptable to the output of various system commands.
  • changes almost everywhere due to SystemCommandJob taking place of FragmentJob and FragmentJob::ptr and FragmentResult::ptr requirements.
  • added FragmentWorker::dummyInit() to enforce binding of the executable to all possible derived FragmentJob's.
  • added unit test for SystemCommandJob.
  • added FragmentJobStub that implements a no-brainer job for testing.
  • NOTE: boost::iostreams is incompatible with MemDebug due to placement new.
  • Property mode set to 100644
File size: 5.3 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * SystemCommandJob.cpp
10 *
11 * Created on: Feb 5, 2012
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include <boost/iostreams/device/file_descriptor.hpp>
21#include <boost/iostreams/stream.hpp>
22
23#include "CodePatterns/MemDebug.hpp"
24
25// include headers that implement a archive in simple text format
26// otherwise BOOST_CLASS_EXPORT_IMPLEMENT has no effect
27#include <boost/archive/text_oarchive.hpp>
28#include <boost/archive/text_iarchive.hpp>
29
30#include "SystemCommandJob.hpp"
31
32#include <cstdio>
33#include <cstdlib>
34#include <fstream>
35#include <iostream>
36#include <string>
37#include <streambuf>
38#include <boost/filesystem.hpp>
39
40
41#include "CodePatterns/Info.hpp"
42#include "CodePatterns/Log.hpp"
43#include "CodePatterns/toString.hpp"
44
45/** Constructor for class SystemCommandJob.
46 *
47 */
48SystemCommandJob::SystemCommandJob() :
49 FragmentJob(JobId::IllegalJob)
50{}
51
52/** Constructor for class SystemCommandJob.
53 *
54 * \param _command command to execute
55 * \param _outputfile configuration file for solver
56 * \param _JobId unique id of this job
57 */
58SystemCommandJob::SystemCommandJob(const std::string &_command, const std::string &_outputfile, const JobId_t _JobId) :
59 FragmentJob(_JobId),
60 command(_command),
61 outputfile(_outputfile)
62{}
63
64/** Destructor for class SystemCommandJob.
65 *
66 */
67SystemCommandJob::~SystemCommandJob()
68{}
69
70/** Work routine of this SystemCommandJob.
71 *
72 * This function encapsulates all the work that has to be done to generate
73 * a FragmentResult. Hence, the FragmentWorker does not need to know anything
74 * about the operation: it just receives it and executes this function.
75 *
76 * We obtain FragmentResult::exitflag from std::system's return value and
77 * FragmentResult::result from the contents of the piped output file.
78 *
79 * \return result of this job
80 */
81FragmentResult::ptr SystemCommandJob::Work()
82{
83 Info info((std::string(__FUNCTION__)+std::string(", id #")+toString(getId())).c_str());
84
85 // the following is taken from http://stackoverflow.com/questions/2746168/how-to-construct-a-c-fstream-from-a-posix-file-descriptor
86 char tmpTemplate[24];
87 strncpy(tmpTemplate, "/tmp/XXXXXX_", 14);
88 const std::string idstring(toString(getId()));
89 const size_t idlength = idstring.length();
90 ASSERT(idlength <= 8,
91 "SystemCommandJob::Work() - the id contains more than 8 digits.");
92 strcat(tmpTemplate, toString(getId()).c_str());
93 mkstemps(tmpTemplate, idlength+1);
94
95 // write outputfile to temporary file
96 LOG(2, "DEBUG: Temporary file is " << tmpTemplate << ".");
97 std::ofstream output(tmpTemplate);
98 ASSERT(output.is_open(),
99 "SystemCommandJob::Work() - the temporary file could not be opened.");
100 output << outputfile << std::endl;
101
102 // fork into subprocess and launch command
103 std::string command_args = command+std::string(" ")+tmpTemplate;
104 LOG(1, "INFO: Executing '" << command_args << "'.");
105 FILE *stdoutstream = popen(command_args.c_str(), "r");
106 FragmentResult::ptr s;
107 {
108 boost::iostreams::stream<boost::iostreams::file_descriptor_source> stdoutfile(fileno(stdoutstream), boost::iostreams::never_close_handle);
109 stdoutfile.set_auto_close(false); // https://svn.boost.org/trac/boost/ticket/3517
110 std::istreambuf_iterator<char> beginiter = (std::istreambuf_iterator<char>(stdoutfile));
111 std::string resultstring( beginiter, std::istreambuf_iterator<char>());
112 // construct result
113 LOG(2, "DEBUG: First 50 characters of output: " << resultstring.substr(0,50));
114 s = extractResult(resultstring);
115 }
116 const int exitflag = pclose(stdoutstream);
117 if (exitflag != 0)
118 ELOG(1, "Job " << getId() << " failed on executing: " << command_args);
119 s->exitflag = exitflag;
120
121 // close temporary file and remove it
122 output.close();
123 boost::filesystem::path tmpPath(tmpTemplate);
124 if (boost::filesystem::exists(boost::filesystem::status(tmpPath))) {
125 LOG(2, "DEBUG: Removing " << tmpPath.string());
126 boost::filesystem::remove(tmpPath);
127 }
128
129 // return result
130 return s;
131}
132
133/** Default function for result extraction is just copy.
134 *
135 * @param resultstring output of system command
136 * @return copy of \a resultstring
137 */
138FragmentResult::ptr SystemCommandJob::extractResult(const std::string &resultstring)
139{
140 return FragmentResult::ptr (new FragmentResult(getId(), resultstring) );
141}
142
143
144/** Comparator for class SystemCommandJob.
145 * \param other instance to compare to
146 * \return every member variable is the same, else - is not
147 */
148bool SystemCommandJob::operator==(const SystemCommandJob &other) const
149{
150 if (command != other.command) {
151 LOG(1, "INFO: command's of two SystemCommandJobs differ: " << command << " != " << other.command << ".");
152 return false;
153 }
154 if (outputfile != other.outputfile) {
155 LOG(1, "INFO: outputfile's of two SystemCommandJobs differ: " << outputfile << " != " << other.outputfile << ".");
156 return false;
157 }
158 return (dynamic_cast<const FragmentJob &>(*this) == dynamic_cast<const FragmentJob &>(other));
159}
160
161// we need to explicitly instantiate the serialization functions as
162// its is only serialized through its base class FragmentJob
163BOOST_CLASS_EXPORT_IMPLEMENT(SystemCommandJob)
Note: See TracBrowser for help on using the repository browser.