Various fixes
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / trains / ParUtilities.C
1 /**
2  * @file   ParUtilities.C
3  * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
4  * @date   Tue Oct 16 17:51:10 2012
5  * 
6  * @brief  PAR file utilities 
7  * 
8  * @ingroup pwglf_forward_trains_util
9  * 
10  */
11 #ifndef PARHELPER_C
12 #define PARHELPER_C
13 #ifndef __CINT__
14 # include <TString.h>
15 # include <TProof.h>
16 # include <TSystem.h>
17 # include <TError.h>
18 # include <TFile.h>
19 # include <TSystem.h>
20 # include <TROOT.h>
21 # include <fstream>
22 # include <cstdlib>
23 #else
24 class TString;
25 #endif
26
27 // ===================================================================
28 /**
29  * Helper to set-up and load PARs
30  *
31  * @ingroup pwglf_forward_trains_util
32  */
33 struct ParUtilities
34 {
35   /** 
36    * Find PAR file (either in current or parent directory or directly 
37    * in $ALICE_ROOT), and link it here
38    * 
39    * @param what PAR file name (sans .par)
40    * 
41    * @return true on success
42    */
43   static Bool_t Find(const TString& what)
44   {
45     if (what.IsNull()) return false;
46     
47     TString parFile(what);
48     if (!parFile.EndsWith(".par")) parFile.Append(".par");
49     if (gSystem->AccessPathName(parFile.Data())) { 
50       // If not found
51       TString src;
52       if (gSystem->AccessPathName(Form("../%s.par", parFile.Data())) == 0) 
53         src.Form("../%s", parFile.Data());
54       else {
55         // If not found 
56         TString aliParFile = 
57           gSystem->ExpandPathName(Form("$(ALICE_ROOT)/%s", parFile.Data()));
58         if (gSystem->AccessPathName(aliParFile.Data()) == 0) 
59           src = aliParFile;
60       }
61       if (src.IsNull()) {
62           Error("ParUtilities::Find", 
63                 "PAR file %s not found in current or parent "
64                 "directory nor in $(ALICE_ROOT)", parFile.Data());
65           return false;
66       }
67       // Copy to current directory 
68       // TFile::Copy(aliParFile, parFile);
69       if (gSystem->Exec(Form("ln -s %s %s", src.Data(), parFile.Data())) != 0){
70         Error("ParUtilities::Find", "Failed to symlink %s to %s", 
71               src.Data(), parFile.Data());
72         return false;
73       }
74     }
75     return true;
76   }
77   /** 
78    * Unpack and load a PAR file previously found with Find.
79    * 
80    * @param name PAR file name 
81    * @deprecated Use Find  and Build instead
82    * @return true on success
83    */
84   static Bool_t Load(const TString& name) 
85   {
86     if (name.IsNull()) return true;
87     if (!gProof) { 
88       Error("ParUtilities::Load", "No connection to a Proof cluster");
89       return false;
90     }
91
92     // Load par library 
93     TString fn(name);
94     Info("ParUtilities::LoadLibrary", "Uploading %s", name.Data());
95     
96     // First check in current directory
97     Int_t ret = gProof->UploadPackage(fn, TProof::kRemoveOld);
98     
99     if (ret < 0)  {
100       // IF not found there, then check parent directory 
101       fn.Prepend("../");
102       gSystem->ExpandPathName(fn);
103       ret = gProof->UploadPackage(fn);
104     }
105
106     if (ret < 0) {      
107       // If not found in current or parent directory, try the 
108       // the ALICE_ROOT directory 
109       fn  = Form("$ALICE_ROOT/%s.par", name.Data());
110       gSystem->ExpandPathName(fn);
111       ret = gProof->UploadPackage(fn);
112     }
113     
114     if (ret < 0) {
115       // IF not found, bark 
116       Error("ParUtilities::Load", 
117             "Could not find module %s.par in current or parent directory "
118             "nor in $ALICE_ROOT", name.Data());
119       return false;
120     }
121     
122     ret = gProof->EnablePackage(name);
123     Info("ParUtilities::Load", "Enabled package %s (from %s)", 
124          name.Data(), fn.Data());
125     
126     return true;
127   }
128   /** 
129    * Unpack, build, and load a PAR file. 
130    * 
131    * @param what Which PAR file 
132    * 
133    * @return 
134    */
135   static Bool_t Build(const TString& what)
136   {
137     if (what.IsNull()) return false;
138     
139     TString parFile(what);
140     if (!parFile.EndsWith(".par")) parFile.Append(".par");
141
142     // Extract archive 
143     gSystem->Exec(Form("tar xzf %s", parFile.Data()));
144     
145     // Change directory into par archive
146     TString cwd = gSystem->WorkingDirectory();
147     
148     TString dir(what);
149     if (dir.EndsWith(".par")) dir.ReplaceAll(".par", "");
150     if (!gSystem->ChangeDirectory(dir)) { 
151       Error("ParUtilities::Setup", "Failed to change directory to %s", 
152             dir.Data());
153       return false;
154     }
155     
156     // Test the build 
157     if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
158       Info("ParUtilities::Setup", "Building in PAR archive %s", parFile.Data());
159       if (gSystem->Exec("PROOF-INF/BUILD.sh")) { 
160         Error("ParUtilities::Setup", "Failed to build in PAR directory %s", 
161               dir.Data());
162         gSystem->ChangeDirectory(cwd.Data());
163         return false;
164       }
165     }
166     
167     // Check for setup script
168     if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
169       // Info("ParUtilities::SetupPAR", "Setting up for PAR %s", what);
170       gROOT->Macro("PROOF-INF/SETUP.C");
171     }
172     if (!gSystem->ChangeDirectory(cwd.Data())) return false;
173
174     return true;
175   }
176   //__________________________________________________________________
177   /** 
178    * @{ 
179    * @name PAR generation from script 
180    */
181   /** 
182    * Service function to make a PAR out of a script.  
183    * 
184    * The script should contain can contain a sub-class of AliAnalysisTask. 
185    * The script will be compiled on the slaves before loading the 
186    * AliAnalysisManager.  Parts to (not) be compiled can be protected like 
187    * 
188    * @code 
189    * #ifdef BUILD_PAR
190    * // This will _only_ be compiled in the servers 
191    * #endif
192    * #ifndef BUILD_PAR
193    * // This will not be compiled in the servers 
194    * #endif
195    * @endcode
196    * 
197    * @param mode   Execution mode (Grid, PROOF, Local)
198    * @param script Script to upload and compile in the PAR
199    * @param deps   Dependency pars 
200    * 
201    * @return true on success. 
202    */
203   static Bool_t MakeScriptPAR(Bool_t isLocal, 
204                               const TString& script, 
205                               const TString& deps)
206   {
207     // --- In local mode, just AcLic and load ------------------------
208     if (isLocal) { 
209       if (gROOT->LoadMacro(Form("%s++g", script.Data())) < 0)
210         return false;
211       return true;
212     }
213
214     // --- Get the base name -----------------------------------------
215     Info("ParUtilities::MakeScriptPAR", "Making par file for %s", 
216          script.Data());
217     TString base(gSystem->BaseName(script));
218     Int_t   idx = base.Last('.');
219     if (idx != kNPOS) base.Remove(idx);
220
221     // --- Check name of script file ---------------------------------
222     TString scr(script);
223     TString ext;
224     if      (script.EndsWith(".C"))   ext = "C"; 
225     else if (script.EndsWith(".cxx")) ext = "cxx";
226     else                              { ext = "C"; scr.Append(".C"); }
227     
228     // --- Check if we can access the file ---------------------------
229     TString path = TString::Format(".:%s", TROOT::GetMacroPath());
230     char*   loc  = gSystem->Which(path, scr);
231     if (!loc) {
232       Error("ParUtilities::MakeScriptPAR", 
233             "Script %s not found in %s", scr.Data(), path.Data());
234       return false;
235     }
236     TString full(loc);
237
238     // --- Create our temporary directory ----------------------------
239     TString tmpdir(gSystem->TempDirectory());
240     int     ltempl = tmpdir.Length() + 1 + 5 + 6 + 1;
241     char*   templ  = new char[ltempl];
242     snprintf(templ, ltempl, "%s/trainXXXXXX", tmpdir.Data());
243     if (!mkdtemp(templ)) {
244       Error("ParUtilities::MakeScriptPAR", 
245             "Failed to generate temporary directory from template %s", 
246             templ);
247       return false;
248     }
249
250     Bool_t retVal = false;
251     try {
252       // --- Make directories for package ------------------------------
253       TString dir = TString::Format("%s/%s", templ, base.Data());
254       // Set-up directories 
255       if (gSystem->MakeDirectory(dir) < 0) 
256         throw TString::Format("Could not make directory '%s'", base.Data());
257       if (gSystem->MakeDirectory(Form("%s/PROOF-INF", dir.Data()))) 
258         throw TString::Format("Could not make directory %s/PROOF-INF", 
259                               base.Data());
260       
261       // --- Copy the script to the setup directory --------------------
262       TString dest = TString::Format("%s/%s.%s", dir.Data(),
263                                      base.Data(), ext.Data());
264       Int_t ret = gSystem->CopyFile(full, dest, true);
265       switch (ret) { 
266       case -1: throw TString::Format("Couldn't open %s for copy", scr.Data());
267       case -2: throw TString::Format("File %s exists", dest.Data());
268       case -3: throw TString::Format("Error while copying %s", scr.Data());
269       }
270       
271       // --- Make scripts, etc. ----------------------------------------
272       TObjArray* depList = deps.Tokenize(", ");
273       if (!MakeBuildScript(dir, base)) 
274         throw TString::Format("Failed to make build script");
275       if (!MakeUtilityScript(dir)) 
276         throw TString::Format("Failed to make utility script");
277       if (!MakeBuildMacro(dir, base, ext, depList)) 
278         throw TString::Format("Failed to make build macro");
279       if (!MakeSetupMacro(dir, base, ext, depList)) 
280         throw TString::Format("Failed to setup macro");
281
282       // --- Pack up the archive ---------------------------------------
283       ret = gSystem->Exec(Form("(cd %s && tar -czf %s.par %s)", 
284                                templ, base.Data(),base.Data()));
285       if (ret != 0) 
286         throw TString::Format("Failed to create PAR file %s.PAR from %s", 
287                               base.Data(), dir.Data());
288
289       // --- Move PAR file to here -------------------------------------
290       ret = gSystem->Exec(Form("mv -f %s/%s.par %s.par", templ, base.Data(), 
291                                base.Data()));
292       if (ret != 0) 
293         throw TString::Format("Failed to rename %s/%s.par to %s.par: %s", 
294                               templ, base.Data(), base.Data(), 
295                               gSystem->GetError());
296       retVal = true;
297     }
298     catch (TString& e) {
299       Error("ParUtilities::MakeScriptPAR", e.Data());
300       retVal = false;
301     }
302     
303     // --- Remove temporary directory --------------------------------
304     gSystem->Exec(Form("rm -rf %s", templ));
305
306     return retVal;
307   }
308   /** 
309    * Write a build script
310    * 
311    * @param dir Directory to put it in
312    * 
313    * @return true on success
314    */
315   static Bool_t MakeBuildScript(const TString& dir, 
316                                 const TString& base)
317   {
318     // Make our build file 
319     std::ofstream out(Form("%s/PROOF-INF/BUILD.sh", dir.Data()));
320     if (!out) {
321       Error("ParUtilities::MakeBuildScript", "Failed to open out shell script");
322       return false;
323     }
324     out << "#!/bin/sh\n"
325         << "if test x$ALICE_ROOT != x ; then\n"
326         << "  if test x$ALICE_TARGET = x ; then\n"
327         << "    export ALICE_TARGET=`$ROOTSYS/bin/root-config --arch`\n"
328         << "  fi\n"
329         << "  export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:"
330         << "${ALICE_ROOT}/lib/tgt_${ALICE_TARGET}\n"
331         << "fi\n"
332         << "echo BUILD.sh@`hostname`: Building " << base << "\n"
333         << "root.exe -l -out -q PROOF-INF/BUILD.C 2>&1 | tee " 
334         << base << ".log\n"
335         << "echo BUILD.sh@`hostname`: done: $?\n"
336         << std::endl;
337     out.close();
338     if (gSystem->Chmod(Form("%s/PROOF-INF/BUILD.sh", dir.Data()), 0755) != 0) {
339       Error("ParUtilities::MakeBuildScript", 
340             "Failed to set exectuable flags on %s/PROOF-INF/BUILD.sh", 
341             dir.Data());
342       return false;
343     }
344     return true;
345   }
346   /** 
347    * Write a build macro 
348    * 
349    * @param dir   Directory to put macro in
350    * @param deps  Dependencies
351    * @param base  Base name of script to compile
352    * 
353    * @return true on success
354    */
355   static Bool_t MakeBuildMacro(const TString& dir, 
356                                const TString& base, 
357                                const TString& ext,
358                                const TCollection* deps)  {
359     std::ofstream out(Form("%s/PROOF-INF/BUILD.C", dir.Data()));
360     if (!out) {
361       Error("ParUtilities::MakeBuildMacro", "Failed to open build script");
362       return false;
363     }
364     out << "void BUILD() {\n"
365         << "  gSystem->AddIncludePath(\"-DBUILD_PAR=1\");\n"
366         << "  gROOT->LoadMacro(\"PROOF-INF/UTIL.C\");\n"
367         << "  LoadROOTLibs();\n"
368         << "  AddAliROOT();\n";
369     if (deps) {
370       TIter       next(deps);
371       TObject*    dep = 0;
372       while ((dep = next())) {
373         out << "  AddDep(\"" << dep->GetName() << "\");\t"
374             << "  LoadDep(\"" << dep->GetName() << "\");\n";
375       }
376     }
377     out << "  // gDebug = 5;\n"
378         << "  int ret = gROOT->LoadMacro(\"" 
379         << base << "." << ext << "++g\");\n"
380         << "  if (ret != 0) Fatal(\"BUILD\",\"Failed to build\");\n"
381         << "  // else Info(\"BUILD\", \"Made " << base << "\");\n"
382         << "}\n"
383         << std::endl;
384     out.close();
385
386     return true;
387   }
388   /** 
389    * Make a utility macro 
390    * 
391    * @param dir Directory to put the macro in
392    * 
393    * @return true on success
394    */
395   static Bool_t MakeUtilityScript(const TString& dir)
396   {
397     std::ofstream out(Form("%s/PROOF-INF/UTIL.C", dir.Data()));
398     if (!out) {
399       Error("ParUtilities::MakeUtilityScript", "Failed to open utility script");
400       return false;
401     }
402     out << "void LoadROOTLibs() {\n"
403         << "  gSystem->Load(\"libVMC\");\n"
404         << "  gSystem->Load(\"libNet\");\n"
405         << "  gSystem->Load(\"libTree\");\n"
406         << "  gSystem->Load(\"libPhysics\");\n"
407         << "  gSystem->Load(\"libMinuit\");\n"
408         << "}\n\n"
409         << "void AddAliROOT() {\n"
410         << "  TString val(gSystem->Getenv(\"ALICE_ROOT\"));\n"
411         << "  if (val.IsNull())\n"
412         << "    Warning(\"Add\",\"ALICE_ROOT not defined\");\n"
413         << "  else\n"
414         << "    gSystem->AddIncludePath(Form(\"-I%s/include\",val.Data()));\n"
415         << "}\n\n"
416         << "void AddDep(const char* env) {\n"
417         << "  TString val(gSystem->Getenv(Form(\"%s_INCLUDE\",env)));\n"
418         << "  if (val.IsNull())\n"
419         << "    Warning(\"Add\",\"%s_INCLUDE not defined\", env);\n"
420         << "  else {\n"
421         << "    gSystem->AddIncludePath(Form(\"-I../%s\",val.Data()));\n"
422         << "  }\n"
423         << "}\n\n"
424         << "void LoadDep(const char* name) {\n"
425         << "  gSystem->AddDynamicPath(Form(\"../%s\",name));\n"
426         << "  char* full = gSystem->DynamicPathName(name,true);\n"
427         << "  if (!full) \n"
428         << "   full = gSystem->DynamicPathName(Form(\"lib%s\",name),true);\n"
429         << "  if (!full) \n"
430         << "   full = gSystem->DynamicPathName(Form(\"lib%s.so\",name),true);\n"
431         << "  if (!full) {\n"
432         << "    Warning(\"LoadDep\",\"Module %s not found\", name);\n"
433         << "    return;\n"
434         << "  }\n"
435         << "  gSystem->Load(full);\n"
436         << "}\n"
437         << std::endl;
438     out.close();
439     return true;
440   }
441   /** 
442    * Make a setup script 
443    * 
444    * @param dir   Directory to put it in 
445    * @param base  Base name of target script 
446    * @param ext   Extension of target script 
447    * @param deps  Dependencies 
448    * 
449    * @return true on success
450    */
451   static Bool_t MakeSetupMacro(const TString& dir, 
452                                const TString& base, 
453                                const TString& ext,
454                                const TCollection* deps)
455   {
456     // Make our set-up script 
457     std::ofstream out(Form("%s/PROOF-INF/SETUP.C", dir.Data()));
458     if (!out) {
459       Error("ParUtilities::MakeSetupMacro", "Failed to open setup script");
460       return false;
461     }
462     out << "void SETUP() {\n"
463         << "  gROOT->LoadMacro(\"PROOF-INF/UTIL.C\");\n"
464         << "  LoadROOTLibs();\n"
465         << "  // Info(\"SETUP\",\"Loading libraries\");\n";
466     if (deps) {
467       TIter next(deps);
468       TObject* dep = 0;
469       while ((dep = next())) 
470         out << "  LoadDep(\"" << dep->GetName() << "\");\n";
471     }
472     out << "  // gDebug = 5;\n"
473         << "  // Info(\"SETUP\",\"Loading " << base <<"_"<< ext << ".so\");\n"
474         << "  gSystem->Load(\"" << base << "_" << ext << ".so\");\n"
475         << "  // gDebug = 0;\n"
476         << "  gROOT->ProcessLine(\".include " << base << "\");\n"
477         << "  gSystem->Setenv(\"" << base << "_INCLUDE\",\"" 
478         << base << "\");\n"
479         << "  // Info(\"SETUP\", \"Done\");\n"
480         << "}\n"
481         << std::endl;
482     out.close();
483     return true;
484   }
485   /* @} */
486 };
487 #endif
488 // 
489 // EOF
490 //