All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
utilities.sh
Go to the documentation of this file.
1 #!/usr/bin/env bash
2 #
3 # Common utilities for the scripts in this directory.
4 #
5 
6 # ------------------------------------------------------------------------------
7 function isFlagSet() {
8  local -r VarName="$1"
9  [[ -n "${!VarName//0}" ]]
10 } # isFlagSet()
11 
12 function isFlagUnset() {
13  local -r VarName="$1"
14  [[ -z "${!VarName//0}" ]]
15 } # isFlagUnset()
16 
17 function STDERR() { echo "$*" >&2 ; }
18 function ERROR() { STDERR "ERROR: $*" ; }
19 function FATAL() {
20  local -i Code="$1"
21  shift
22  STDERR "FATAL (${Code}): $*"
23  exit "$Code"
24 } # FATAL()
25 function LASTFATAL() {
26  local -i Code="$?"
27  [[ "$Code" == 0 ]] || FATAL "$Code" "$@"
28 } # LASTFATAL()
29 
30 
31 # ------------------------------------------------------------------------------
32 function isRelativePath() {
33  local -r Path="$1"
34  [[ "${Path:0:1}" != '/' ]]
35 } # isRelativePath()
36 
37 
38 function simplifyPath() {
39  # Replaces '.' and '..' path components by plain text substitution.
40  local Path="$(sed -E 's@/+@/@g' <<< "${1}/")" # replace double / with single ones
41 
42  # build a stack of directories, from the root on
43  local Dir OtherPath
44  local -a Stack
45  local -i nParents=0 # number of parent directories at root
46  while true ; do
47 
48  Dir="${Path%%/*}"
49  OtherPath="${Path#${Dir}/}"
50  case "$Dir" in
51  ( '.' )
52  ;;
53  ( '..' )
54  local -i lastElem=$((${#Stack[@]} - 1))
55  if [[ $lastElem -ge 0 ]] && [[ "${Stack[$lastElem]}" != '..' ]]; then
56  # if the element is empty then it's root (should be lastElem=0)
57  # and we can't escalate to the parent
58  [[ -n "${Stack[$lastElem]}" ]] && unset Stack[$lastElem]
59  else
60  let ++nParents
61  fi
62  ;;
63  ( * )
64  Stack+=( "$Dir" ) ;;
65  esac
66 
67  [[ "${Dir}/" == "$Path" ]] && break
68  Path="$OtherPath"
69  done
70 
71  # merge the elements left
72  local ReconstitutedPath
73  while [[ $nParents -gt 0 ]]; do
74  ReconstitutedPath+='../'
75  let --nParents
76  done
77  for Elem in "${Stack[@]}" ; do
78  ReconstitutedPath+="${Elem}/"
79  done
80 
81  [[ "$ReconstitutedPath" != '/' ]] && ReconstitutedPath="${ReconstitutedPath%/}"
82  echo "$ReconstitutedPath"
83 
84 } # simplifyPath()
85 
86 
87 function makeAbsolutePath() {
88  local Path="$1"
89  local RelativeTo="$2"
90 
91  if isRelativePath "$Path" ; then
92  [[ -z "$RelativeTo" ]] && RelativeTo="$(pwd)"
93  Path="${RelativeTo%/}/${Path}"
94  fi
95  simplifyPath "$Path"
96 
97 } # makeAbsolutePath()
98 
99 
100 # ------------------------------------------------------------------------------
101 function isExperiment() {
102  #
103  # Prints the name of the experiment as deduced.
104  # Returns 0 on success, 1 if deduction failed, and 2 if more than one
105  # experiments match.
106  #
107 
108  local -ar ExperimentNames=( 'MicroBooNE' 'DUNE' 'SBND' 'LArIAT' 'ArgoNeuT' 'ICARUS' )
109  local -A ExperimentHostNames ExptDirs
110  local Name
111  for Name in "${ExperimentNames[@]}" ; do
112  ExperimentHostNames[$Name]="${Name,,}"
113  ExperimentDirectories[$Name]="${Name,,}"
114  done
115  ExperimentHostNames['MicroBooNE']='uboone'
116  ExperimentDirectories['MicroBooNE']='uboone'
117 
118  local -a Experiments
119  local ExperimentCandidate ExperimentHostName
120  local HostName="$(hostname)"
121  if [[ -n "$HostName" ]]; then
122  for ExperimentCandidate in "${!ExperimentHostNames[@]}" ; do
123  [[ "$HostName" =~ ^${ExperimentHostNames[$ExperimentCandidate]} ]] || continue
124  Experiments+=( "$ExperimentCandidate" )
125  break
126  done
127  fi
128 
129  # back up to directory presence for known experiments
130  if [[ "${#Experiments[@]}" == 0 ]]; then
131  local ExperimentDir
132  for ExperimentCandidate in "${!ExperimentHostNames[@]}" ; do
133  ExperimentDir="/${ExperimentDirectories[$ExperimentCandidate]}"
134  [[ -d "$ExperimentDir" ]] && Experiments+=( "$ExperimentCandidate" )
135  done
136  fi
137 
138  # back up to directory discovery
139  if [[ "${#Experiments[@]}" == 0 ]]; then
140  local CandidateData
141  for CandidateData in /*/data ; do
142  local Candidate="$(dirname "${CandidateData#/}")"
143 
144  # is there an 'app' directory too?
145  [[ -d "/${Candidate}/app" ]] || continue
146  Experiments+=( "$Candidate" )
147  done
148  fi
149 
150  case "${#Experiments[@]}" in
151  ( 0 ) return 1 ;;
152  ( 1 ) ;;
153  ( * ) return 2 ;;
154  esac
155  echo "${Experiments[0]^^}"
156 
157 } # isExperiment()
158 
159 
160 
161 
162 function FindExperiment() {
163  #
164  # Prints the name of the experiment the directory or machine belongs to.
165  #
166  local -r ExperimentNameFile='ExperimentName'
167 
168  [[ -r "$ExperimentNameFile" ]] && cat "$ExperimentNameFile" && return
169 
170  isExperiment
171 
172 } # FindExperiment()
173 
174 
175 function FindLatestUPS() {
176  local -r ProductName="$1"
177  local -r Qualifiers="$2" # optional
178 
179  ups list -aKVERSION "$ProductName" ${Qualifiers:+-q "$Qualifiers"} | tr -d '" ' | sort -u | tail -n 1
180 
181 } # FindLatestUPS()
182 
183 
184 function PickAnyQualifiersFor() {
185  local -r ProductName="$1"
186  local -r Version="$2"
187 
188  ups list -aKQUALIFIERS "$ProductName" "$Version" | tr -d '" ' | sort -u | tail -n 1
189 
190 } # PickAnyQualifiersFor()
191 
192 
193 function UPSversion() {
194  # Product must already be set up
195  local -r Product="$1"
196 
197  local VarName
198  VarName="${Product^^}_DIR"
199  [[ -n "${!VarName}" ]]
200  declare -p "$VarName" >& /dev/null || return 2
201 
202  VarName="${Product^^}_VERSION"
203  declare -p "$VarName" >& /dev/null || return 1
204 
205  echo "${!VarName}"
206 } # UPSversion()
207 
208 
209 function NeedSetup() {
210  local Experiment="$1"
211 
212  local ExperimentCodeName="$(ExperimentCodeProduct "$Experiment" )"
213 
214  local VarName="${ExperimentCodeName}_DIR"
215  [[ -z "${!VarName}" ]]
216 
217 } # NeedSetup()
218 
219 
220 function ExperimentSetup() {
221 
222  local ExperimentName="$1"
223 
224  local -r ExperimentCodeName="$(ExperimentCodeProduct "$ExperimentName")"
225 
226  if ! NeedSetup "$ExperimentName" ; then
227  echo "${ExperimentName} software already set up (${ExperimentCodeName} $(UPSversion "$ExperimentCodeName")"
228  return 0
229  fi
230 
231  local -r experiment="${ExperimentName,,}"
232  local -a SetupScriptCandidates=(
233  "/cvmfs/${experiment}.opensciencegrid.org/products/${experiment}/setup_${experiment}.sh"
234  "/cvmfs/${experiment}.opensciencegrid.org/products/setup_${experiment}.sh"
235  )
236 
237  local SetupScript
238  for SetupScript in "${SetupScriptCandidates[@]}" "" ; do
239  [[ -r "$SetupScript" ]] && break
240  done
241 
242  [[ -r "$SetupScript" ]] || FATAL 1 "Can't find setup script for experiment '${Experiment}'."
243 
244  echo "Setting up the UPS area for ${Experiment}..."
245  source "$SetupScript"
246 
247  local -r LatestVersion=$(FindLatestUPS "$ExperimentCodeName")
248 
249  local -r Qualifiers=$(PickAnyQualifiersFor "$ExperimentCodeName" "$LatestVersion")
250 
251  echo "Setting up: ${ExperimentCodeName} ${LatestVersion}${Qualifiers:+" (${Qualifiers})"}"
252  source "$(ups setup "$ExperimentCodeName" "$LatestVersion" ${Qualifiers:+-q "$Qualifiers"})"
253 
254  source "$(ups setup git)" # failed? doesn't matter
255 
256 } # ExperimentSetup()
257 
258 
259 function DetectROOTversion() {
260 
261  root-config --version
262 
263 } # DetectROOTversion()
264 
265 
266 # ------------------------------------------------------------------------------
267 function ExperimentCodeProduct() {
268 
269  local Experiment="$1"
270 
271  # won't work for lariatsoft and dunetpc
272  echo "${Experiment,,}code"
273 
274 } # ExperimentCodeProduct()
275 
276 
277 function RedmineGITremoteURL() {
278  local -r RepoName="$1"
279  echo "http://cdcvs.fnal.gov/projects/${RepoName}"
280 } # RedmineGITremoteURL()
281 
282 
283 function GitHubRemoteURL() {
284  local -r RepoName="$1"
285  local -r GroupName="${2:-"$RepoName"}"
286 
287  echo "git@github.com:${GroupName}/${RepoName}.git"
288 } # GitHubRemoteURL()
289 
290 
291 function FindGitRepository() {
292 
293  local RepoName="$1"
294 
295  local CandidateRepoDir
296  for CandidateRepoDir in "${RepoDir:+${RepoDir%/}}/${RepoName}" ; do
297  [[ -r "${CandidateRepoDir}/.git" ]] && break
298  done
299 
300  [[ -r "$CandidateRepoDir" ]] || LASTFATAL "Could not find the local GIT repository for '${RepoName}'."
301  echo "$CandidateRepoDir"
302 
303 } # FindGitRepository()
304 
305 
306 function isInGITrepository() {
307 
308  local Path="$(makeAbsolutePath "${1:-.}")"
309 
310  while true ; do
311  [[ -d "${Path%/}/.git" ]] && return 0
312  [[ "$Path" == '/' ]] && break
313  Path="$(dirname "$Path")"
314  done
315  return 1
316 } # isInGITrepository()
317 
318 
319 function GITrepositoryPath() {
320 
321  local Path="$(makeAbsolutePath "${1:-.}")"
322 
323  while true ; do
324  if [[ -d "${Path%/}/.git" ]]; then
325  echo "${Path%/}"
326  return 0
327  fi
328  [[ "$Path" == '/' ]] && break
329  Path="$(dirname "$Path")"
330  done
331  return 1
332 } # GITrepositoryPath()
333 
334 
335 function GITrepositoryName() {
336 
337  local Path
338  Path="$(GITrepositoryPath "$1")" && basename "$Path"
339 
340 } # GITrepositoryName()
341 
342 
343 function hasGITtag() {
344 
345  local -r Tag="$1"
346  local -r Directory="$2"
347 
348  git${Directory:+ -C "$Directory"} rev-parse "$Tag" >& /dev/null
349 
350 } # hasGITtag()
351 
352 
353 function checkoutGITtagIfExists() {
354 
355  local -r Tag="$1"
356  local -r Directory="$2"
357 
358  hasGITtag "$Tag" && git${Directory:+ -C "$Directory"} checkout "$Tag"
359 
360  git${Directory:+ -C "$Directory"} rebase
361 
362 } # checkoutGITtagIfExists()
363 
364 
365 # ------------------------------------------------------------------------------
366 function FindDoxyfile() {
367  # looks for a Doxygen file in the repository directories;
368 
369  local -r ExptName="$1"
370  shift
371  local -a PriorityDirs=( "$@" )
372 
373  local -r ExptCodeName="$(ExperimentCodeProduct "$ExptName" )"
374 
375  local -a CandidateDoxyfiles
376  local GITrepoPath
377  for GITrepoPath in "${PriorityDirs[@]}" "$(GITrepositoryPath)" "$(GITrepositoryPath "$0")" ; do
378  [[ -n "$GITrepoPath" ]] || continue
379  CandidateDoxyfiles+=(
380  "${GITrepoPath}/${RepoDocSubdir}/${ExptCodeName}.doxy"
381  "${GITrepoPath}/${RepoDocSubdir}/Doxyfile.${ExptCodeName}"
382  "${GITrepoPath}/${RepoDocSubdir}/${ExptName}.doxy"
383  "${GITrepoPath}/${RepoDocSubdir}/Doxyfile.${ExptCode}"
384  "${GITrepoPath}/${RepoDocSubdir}/Doxyfile"
385  )
386  done
387 
388  CandidateDoxyfiles+=(
389  "${ExptCodeName}/docs/Doxyfile"
390  "Doxyfile.${ExptCodeName}"
391  "Doxyfile.${ExptName}"
392  "${ExptCodeName}.doxy"
393  "${ExptName}.doxy"
394  'Doxyfile'
395  )
396 
397  local Doxyfile
398  for Doxyfile in "${CandidateDoxyfiles[@]}" "" ; do
399  [[ -r "$Doxyfile" ]] || continue
400  echo "$Doxyfile"
401  return
402  done
403 
404  return 1
405 } # FindDoxyfile()
406 
407 
408 function Unquote() {
409 
410  local String="$1"
411  String="${String#\"}"
412  String="${String%\"}"
413  String="${String#\'}"
414  String="${String%\'}"
415  echo $String
416 
417 } # Unquote()
418 
419 
420 function ExtractFromMetadata() {
421  #
422  # Prints the value of metadata value Key in the specified metadata file.
423  # Metadata files are created by this same script.
424  #
425  # An error code (1) is returned if the variable is not defined.
426  #
427  # Usage: ExtractFromMetadata Key MetadataFile
428  #
429  # This works only for variables with values defined on a single line.
430  # Also, it does not do any decent parsing.
431  #
432  local -r Key="$1"
433  local -r DataFile="$2"
434 
435  [[ -r "$DataFile" ]] || return 1 # no file, no key
436 
437  # note that we are avoiding using `eval` for security reasons
438  local DefLine
439  DefLine="$(grep -E "^[[:blank:]]*${Key}[[:blank:]]*=[[:blank:]]*" "$DataFile" | sed -e 's/[[:blank:]]*=[[:blank:]]*/=/' | sed -e 's/[[:blank:]]*#.*$//g')"
440  local -i res=$?
441  [[ $res != 0 ]] && return $res
442  [[ -z "$DefLine" ]] && return 1
443 
444  local "$DefLine" || FATAL 1 "Could not assign '${Key}' with the line \`local \"${DefLine}\"\`."
445 
446  Unquote "${!Key}"
447 
448  return 0
449 } # ExtractFromMetadata()
450 
451 
452 function ExtractValueFromDoxyfile() {
453  #
454  # Prints the value assigned to VarName in the specified file.
455  # An error code (1) is returned if the variable is not defined.
456  #
457  # Usage: ExtractValueFromDoxyfile VarName DefinitionFile
458  #
459  # This works only for variables with values defined on a single line.
460  # Also, it does not do any decent parsing.
461  #
462  local -r VarName="$1"
463  local -r Doxyfile="$2"
464 
465  # since our metadata has a format compatible with Doxygen, we use the same tool
466  ExtractFromMetadata "$VarName" "$Doxyfile"
467 
468 } # ExtractValueFromDoxyfile()
469 
470 
471 # ------------------------------------------------------------------------------
472 function FindFirstVariableName() {
473  #
474  # Prints the name of the first "variable" in the input stream, introduced as
475  # "${VarName}", with VarName a valid bash variable identifier
476  #
477 
478  #
479  # this means:
480  # * do not print anything by default
481  # * look for a line with pattern ${VarName} (VarName made of letters, underscores and, except the first character, numbers
482  # * when found, execute the three commands:
483  # * match the variable name and replace the whole line with it
484  # * print the new line
485  # * quit
486  #
487  sed -n -E '/\$\{[[:alpha:]_][[:alnum:]_]*\}/{s/^.*\$\{([[:alpha:]_][[:alnum:]_]*)\}.*$/\1/;p;q}'
488 } # FindFirstVariableName()
489 
490 
491 function EscapeSedReplacementLiteralPattern() {
492  local Value="$1"
493  local Escape="$2"
494  Value="${Value//\\/\\\\}"
495  [[ "$Escape" != '\' ]] && Value="${Value//${Escape}/\\${Escape}}"
496  echo "$Value"
497 } # EscapeSedReplacementLiteralPattern()
498 
499 
500 function ReplaceEnvironmentVariables() {
501  #
502  # Using `sed`, which means a lot of potential problems...
503  #
504  local -r TemplateFile="$1"
505  local -r DestFile="$2"
506 
507  if [[ "$TemplateFile" -ef "$DestFile" ]]; then
508  FATAL 1 "ReplaceEnvironmentVariables does not support in-place changes ('${TemplateFile}' and '${DestFile}' are the same file)."
509  fi
510 
511  cp "$TemplateFile" "$DestFile"
512  LASTFATAL "ReplaceEnvironmentVariables: can't create file '${DestFile}'."
513 
514  local VarName LastVarName
515  while true ; do
516  VarName="$(FindFirstVariableName < "$DestFile")"
517  [[ $? == 0 ]] || break # done
518  [[ -z "$VarName" ]] && break # done
519 
520  # avoid infinite loops (from bugs, presumably)
521  [[ "$LastVarName" == "$VarName" ]] && FATAL 1 "Internal error: variable '${VarName}' still present in '${DestFile}' after substitution."
522  LastVarName="$VarName"
523 
524  local Value
525  Value="${!VarName}"
526  LASTFATAL "ReplaceEnvironmentVariables: error evaluating the variable '${VarName}'."
527 
528  echo "Replacing: '\${${VarName}}' => '${Value}'"
529  sed -i -E "s@\\$\\{${VarName}\\}@$(EscapeSedReplacementLiteralPattern "$Value" '@')@g" "$DestFile"
530  LASTFATAL "ReplaceEnvironmentVariables: error replacing variable '${VarName}' with value '${Value}'."
531 
532  done
533  return 0
534 } # ReplaceEnvironmentVariables()
535 
536 
537 # ------------------------------------------------------------------------------
538 # for test: bash utilities.sh testCommand args
539 if [[ "${BASH_SOURCE[0]}" == "$0" ]] && [[ $# -gt 0 ]]; then
540  echo "CMD> $*"
541  "$@"
542 else
543  true
544 fi
545 
546 # ------------------------------------------------------------------------------
process_name opflash particleana ie ie ie z
then echo FATAL
function isRelativePath()
Definition: utilities.sh:32
function LASTFATAL()
Definition: utilities.sh:25
then echo ERROR
Definition: grid_setup.sh:42
std::string Escape(const std::string &s)
process_name E
function isFlagSet()
Definition: utilities.sh:7
function STDERR()
Definition: utilities.sh:17
shift
Definition: fcl_checks.sh:26
process_name gaushit a
then local
BEGIN_PROLOG dataFFTHistosEW root
BEGIN_PROLOG vertical distance to the surface Name
then shift fi
then echo Work directory not specified exit fi echo Work directory
if &&[-z"$BASH_VERSION"] then echo Attempting to switch to bash bash shellSwitch exit fi &&["$1"= 'shellSwitch'] shift declare a IncludeDirectives for Dir in
then echo File list $list not found else cat $list while read file do echo $file sed s
Definition: file_to_url.sh:60
function simplifyPath()
Definition: utilities.sh:38
float A
Definition: dedx.py:137
esac echo uname r
function isFlagUnset()
Definition: utilities.sh:12
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true