ATLAS Offline Software
Loading...
Searching...
No Matches
ScanDir.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7
8//
9// includes
10//
11
13
22#include <TString.h>
23#include <memory>
24#include <stdexcept>
25
26//
27// method implementations
28//
29
30namespace SH
31{
32 ScanDir ::
33 ScanDir ()
35 m_minDepth (0), m_maxDepth (-1),
36 m_filePattern (RCU::glob_to_regexp ("*.root*")),
37 m_directoryPattern (RCU::glob_to_regexp ("*")),
38 m_samplePattern (RCU::glob_to_regexp ("*")),
39 m_samplePostfix (RCU::glob_to_regexp ("")),
42 {}
43
44
45
46 ScanDir& ScanDir ::
47 sampleDepth (int val_sampleDepth)
48 {
49 m_relSampleDepth = val_sampleDepth;
50 m_absSampleDepth = val_sampleDepth;
51 return *this;
52 }
53
54
55
56 ScanDir& ScanDir ::
57 absSampleDepth (int val_absSampleDepth)
58 {
60 m_absSampleDepth = val_absSampleDepth;
61 return *this;
62 }
63
64
65
66 ScanDir& ScanDir ::
67 sampleName (const std::string& val_sampleName)
68 {
69 m_sampleName = val_sampleName;
70 return *this;
71 }
72
73
74
75 ScanDir& ScanDir ::
76 minDepth (std::size_t val_minDepth)
77 {
78 m_minDepth = val_minDepth;
79 return *this;
80 }
81
82
83
84 ScanDir& ScanDir ::
85 maxDepth (std::size_t val_maxDepth)
86 {
87 m_maxDepth = val_maxDepth;
88 return *this;
89 }
90
91
92
93 ScanDir& ScanDir ::
94 filePattern (const std::string& val_filePattern)
95 {
96 m_filePattern = RCU::glob_to_regexp (val_filePattern);
97 return *this;
98 }
99
100
101
102 ScanDir& ScanDir ::
103 fileRegex (const std::string& val_fileRegex)
104 {
105 m_filePattern = val_fileRegex;
106 return *this;
107 }
108
109
110
111 ScanDir& ScanDir ::
112 directoryPattern (const std::string& val_directoryPattern)
113 {
114 m_directoryPattern = RCU::glob_to_regexp (val_directoryPattern);
115 return *this;
116 }
117
118
119
120 ScanDir& ScanDir ::
121 directoryRegex (const std::string& val_directoryRegex)
122 {
123 m_directoryPattern = val_directoryRegex;
124 return *this;
125 }
126
127
128
129 ScanDir& ScanDir ::
130 samplePattern (const std::string& val_samplePattern)
131 {
132 m_samplePattern = RCU::glob_to_regexp (val_samplePattern);
133 return *this;
134 }
135
136
137
138 ScanDir& ScanDir ::
139 samplePostfix (const std::string& val_samplePostfix)
140 {
141 m_samplePostfix = RCU::glob_to_regexp (val_samplePostfix);
142 m_samplePostfixEmpty = val_samplePostfix.empty();
143 return *this;
144 }
145
146
147
148 ScanDir& ScanDir ::
149 sampleRename (const std::string& pattern, const std::string& name)
150 {
151 m_sampleRename.push_back (std::pair<std::regex,std::string> (std::regex (RCU::glob_to_regexp (pattern)), name));
152 return *this;
153 }
154
155
156
157 ScanDir& ScanDir ::
158 extraNameComponent (int val_relSampleDepth)
159 {
160 RCU_REQUIRE (val_relSampleDepth != 0);
161 m_extraNameComponent = val_relSampleDepth;
162 return *this;
163 }
164
165
166
167 const ScanDir& ScanDir ::
168 scan (SampleHandler& sh, const std::string& dir) const
169 {
170 DiskListLocal list (dir);
171 scan (sh, list);
172 return *this;
173 }
174
175
176
177 const ScanDir& ScanDir ::
178 scanEOS (SampleHandler& sh, const std::string& eosDir) const
179 {
180 DiskListEOS list (eosDir);
181 scan (sh, list);
182 return *this;
183 }
184
185
186
187 const ScanDir& ScanDir ::
188 scan (SampleHandler& sh, DiskList& list) const
189 {
190 std::vector<std::string> hierarchy;
191 hierarchy.push_back (list.dirname());
192
193 std::map<std::string,std::shared_ptr<Sample>> samples;
194 recurse (samples, list, hierarchy);
195 for (const auto& sample : samples)
196 {
197 if (sample.second != nullptr)
198 {
199 sh.add (sample.second);
200 }
201 }
202 return *this;
203 }
204
205
206
207 void ScanDir ::
208 recurse (std::map<std::string,std::shared_ptr<Sample>>& samples,
209 DiskList& list,
210 const std::vector<std::string>& hierarchy) const
211 {
212 using namespace msgScanDir;
213
214 ANA_MSG_DEBUG ("scanning directory: " << list.dirname());
215 while (list.next())
216 {
217 std::unique_ptr<DiskList> sublist (list.openDirUnique());
218
219 if (sublist.get() != 0)
220 {
221 if (!RCU::match_expr (m_directoryPattern, list.fileName()))
222 {
223 ANA_MSG_DEBUG ("directory does not match pattern, skipping directory " << list.path());
224 } else if (hierarchy.size() > m_maxDepth)
225 {
226 ANA_MSG_DEBUG ("maxDepth exceeded, skipping directory " << list.path());
227 } else if (hierarchy.size() >= 100)
228 {
229 // rationale: a hard sanity cap so that a directory symlink
230 // loop (or a link to an ancestor) does not recurse forever
231 // when the user has not set an explicit maxDepth.
232 ANA_MSG_WARNING ("directory nesting exceeds 100 levels, not descending further (possible symlink loop): " << list.path());
233 } else
234 {
235 ANA_MSG_DEBUG ("descending into directory " << list.path());
236 std::vector<std::string> subhierarchy = hierarchy;
237 subhierarchy.push_back (list.fileName());
238 recurse (samples, *sublist, subhierarchy);
239 }
240 } else
241 {
242 if (hierarchy.size() > m_minDepth &&
243 RCU::match_expr (m_filePattern, list.fileName()))
244 {
245 ANA_MSG_DEBUG ("adding file " << list.path());
246 std::vector<std::string> subhierarchy = hierarchy;
247 subhierarchy.push_back (list.fileName());
248 addSampleFile (samples, subhierarchy, list.path());
249 } else
250 {
251 ANA_MSG_DEBUG ("skipping file " << list.path());
252 }
253 }
254 }
255 }
256
257
258
259 void ScanDir ::
260 addSampleFile (std::map<std::string,std::shared_ptr<Sample>>& samples,
261 const std::vector<std::string>& hierarchy,
262 const std::string& path) const
263 {
264 std::string sampleName;
265
266 if (!m_sampleName.empty())
267 {
269 } else
270 {
273 if (sampleName.empty())
274 return;
275
277 {
278 bool done = false;
279 for (std::size_t iter = 0, end = sampleName.size();
280 iter != end && !done; ++ iter)
281 {
282 if (RCU::match_expr (m_samplePostfix, sampleName.substr (iter)))
283 {
284 if (iter == 0)
285 throw std::runtime_error ("sample name matches entire postfix pattern: \"" + sampleName + "\"");
286 sampleName.resize (iter);
287 done = true;
288 }
289 }
290 }
291
292 if (m_extraNameComponent != 0)
293 {
294 std::string component = findPathComponent
296 if (component.empty())
297 return;
298 sampleName += "_" + component;
299 }
300
302 return;
303
304 {
305 bool done = false;
306 for (SampleRenameIter iter = m_sampleRename.begin(),
307 end = m_sampleRename.end(); !done && iter != end; ++ iter)
308 {
309 if (RCU::match_expr (iter->first, sampleName))
310 {
311 sampleName = iter->second;
312 done = true;
313 }
314 }
315 }
316 }
317
318 auto iter = samples.find (sampleName);
319 if (iter == samples.end())
320 {
321 auto sample = std::make_shared<SampleLocal> (sampleName);
322 samples[sampleName] = sample;
323 iter = samples.find (sampleName);
324 }
325 SampleLocal *sample = dynamic_cast<SampleLocal*>(iter->second.get());
326 RCU_ASSERT (sample != 0);
327 sample->add (path);
328 }
329
330
331
332 std::string ScanDir ::
333 findPathComponent (const std::vector<std::string>& hierarchy,
334 int absSampleDepth,
335 int relSampleDepth) const
336 {
337 std::string sampleName;
338
339 int myindex = absSampleDepth+1;
340 if (relSampleDepth < 0)
341 myindex = relSampleDepth + hierarchy.size();
342 // rationale: only apply the upper-bound check for a non-negative
343 // index; a negative index (e.g. absSampleDepth <= -2) is meant to
344 // climb up the hierarchy in the else branch below, and converting
345 // it to std::size_t here would wrap to SIZE_MAX and drop every
346 // file.
347 if (myindex >= 0 && std::size_t (myindex) >= hierarchy.size())
348 return sampleName;
349 if (myindex > 0)
350 {
351 sampleName = hierarchy[myindex];
352 } else
353 {
354 sampleName = hierarchy[0];
355 while (sampleName.empty() ||
356 sampleName[sampleName.size()-1] == '/' ||
357 myindex < 0)
358 {
359 while (!sampleName.empty() && sampleName[sampleName.size()-1] == '/')
360 sampleName.pop_back();
361 if (sampleName.empty())
362 return sampleName;
363 if (myindex < 0)
364 {
365 std::string::size_type split = sampleName.rfind ('/');
366 if (split == std::string::npos)
367 {
368 sampleName.clear ();
369 return sampleName;
370 }
371 sampleName.resize (split);
372 ++ myindex;
373 }
374 if (sampleName.empty())
375 return sampleName;
376 }
377 std::string::size_type split = sampleName.rfind ('/');
378 if (split != std::string::npos)
379 sampleName = sampleName.substr (split + 1);
380 }
381 return sampleName;
382 }
383}
#define RCU_ASSERT(x)
Definition Assert.h:210
#define RCU_REQUIRE(x)
Definition Assert.h:196
#define ANA_MSG_WARNING(xmsg)
Macro printing warning messages.
#define ANA_MSG_DEBUG(xmsg)
Macro printing debug messages.
a DiskList implementation for EOS
Definition DiskListEOS.h:18
a DiskList implementation for local directories
an interface for listing directory contents, locally or on a file server
Definition DiskList.h:25
A class that manages a list of Sample objects.
A Sample based on a simple file list.
Definition SampleLocal.h:30
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
void scan(TDirectory *td=0, int depth=0)
Definition listroot.cxx:440
This module defines a variety of assert style macros.
Definition Assert.cxx:23
bool match_expr(const std::regex &expr, std::string_view str)
returns: whether we can match the entire string with the regular expression guarantee: strong failure...
std::string glob_to_regexp(std::string_view glob)
returns: a string that is the regular expression equivalent of the given glob expression guarantee: s...
This module provides a lot of global definitions, forward declarations and includes that are used by ...
Definition PrunDriver.h:15
std::vector< std::pair< std::regex, std::string > >::const_iterator SampleRenameIter
the list of entries from sampleRename
Definition ScanDir.h:211
std::regex m_directoryPattern
the value set by directoryPattern, converted to a regular expression
Definition ScanDir.h:192
ScanDir & sampleName(const std::string &val_sampleName)
a single sample name into which all found files should be placed.
Definition ScanDir.cxx:67
std::string m_sampleName
the value set by sampleName
Definition ScanDir.h:174
bool m_samplePostfixEmpty
whether samplePostfix has been set to the empty string
Definition ScanDir.h:207
std::regex m_filePattern
the value set by filePattern, converted to a regular expression
Definition ScanDir.h:187
std::string findPathComponent(const std::vector< std::string > &hierarchy, int absSampleDepth, int relSampleDepth) const
find the path component at the given depth
Definition ScanDir.cxx:333
int m_relSampleDepth
if this is negative it is the depth at which we take the sample name, counting from the end
Definition ScanDir.h:164
int m_extraNameComponent
the depth set with extraNameComponent, or 0 otherwise
Definition ScanDir.h:216
std::vector< std::pair< std::regex, std::string > > m_sampleRename
Definition ScanDir.h:212
int m_absSampleDepth
if m_relSampleDepth is not negative, it is the depth at which we take the sample name,...
Definition ScanDir.h:170
ScanDir & absSampleDepth(int val_absSampleDepth)
the index of the file hierarchy at which we gather the sample name.
Definition ScanDir.cxx:57
std::size_t m_maxDepth
the value set by maxDepth
Definition ScanDir.h:182
std::regex m_samplePattern
the value set by samplePattern, converted to a regular expression
Definition ScanDir.h:197
ScanDir()
standard constructor
Definition ScanDir.cxx:33
std::size_t m_minDepth
the value set by minDepth
Definition ScanDir.h:178
std::regex m_samplePostfix
the value set by samplePostfix, converted to a regular expression
Definition ScanDir.h:202
void recurse(std::map< std::string, std::shared_ptr< Sample > > &samples, DiskList &list, const std::vector< std::string > &hierarchy) const
perform the recursive scanning of the directory tree
Definition ScanDir.cxx:208
void addSampleFile(std::map< std::string, std::shared_ptr< Sample > > &samples, const std::vector< std::string > &hierarchy, const std::string &path) const
add the given file to the sample based on the hierarchy, creating the sample if necessary
Definition ScanDir.cxx:260