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