""" Collection of DIRAC useful operating system related modules by default on Error they return None """ from __future__ import print_function from __future__ import absolute_import from __future__ import division import six import os import distutils.spawn # pylint: disable=no-name-in-module,import-error import DIRAC from DIRAC.Core.Utilities.Subprocess import shellCall, systemCall from DIRAC.Core.Utilities import List __RCSID__ = "c59810311 (2021-10-01 10:44:25 +0200) Chris Burr " DEBUG = 0 def uniquePath(path=None): """ Utility to squeeze the string containing a PATH-like value to leave only unique elements preserving the original order """ if not isinstance(path, six.string_types): return None try: elements = List.uniqueElements(List.fromChar(path, ":")) return ":".join(elements) except Exception: return None def getDiskSpace(path=".", exclude=None): """Get the free disk space in the partition containing the path. The disk space is reported in MBytes. Returned 0 in case of any error, e.g. path does not exist """ if not os.path.exists(path): return -1 comm = "df -P -m %s " % path if exclude: comm += "-x %s " % exclude comm += "| tail -1" resultDF = shellCall(10, comm) if resultDF["OK"] and not resultDF["Value"][0]: output = resultDF["Value"][1] if output.find(" /afs") >= 0: # AFS disk space comm = "fs lq | tail -1" resultAFS = shellCall(10, comm) if resultAFS["OK"] and not resultAFS["Value"][0]: output = resultAFS["Value"][1] fields = output.split() quota = int(fields[1]) used = int(fields[2]) space = (quota - used) / 1024 return int(space) else: return -1 else: fields = output.split() try: value = int(fields[3]) except Exception as error: print("Exception during disk space evaluation:", str(error)) value = -1 return value else: return -1 def getDirectorySize(path): """Get the total size of the given directory in MB""" comm = "du -s -m %s" % path result = shellCall(10, comm) if not result["OK"] or result["Value"][0] != 0: return 0 else: output = result["Value"][1] print(output) size = int(output.split()[0]) return size def sourceEnv(timeout, cmdTuple, inputEnv=None): """Function to source configuration files in a platform dependent way and get back the environment """ # add appropriate extension to first element of the tuple (the command) envAsDict = '&& python -c "import os,sys ; print >> sys.stderr, os.environ"' # 1.- Choose the right version of the configuration file if DIRAC.getPlatformTuple()[0] == "Windows": cmdTuple[0] += ".bat" else: cmdTuple[0] += ".sh" # 2.- Check that it exists if not os.path.exists(cmdTuple[0]): result = DIRAC.S_ERROR("Missing script: %s" % cmdTuple[0]) result["stdout"] = "" result["stderr"] = "Missing script: %s" % cmdTuple[0] return result # Source it in a platform dependent way: # On windows the execution makes the environment to be inherit # On Linux or Darwin use bash and source the file. if DIRAC.getPlatformTuple()[0] == "Windows": # this needs to be tested cmd = " ".join(cmdTuple) + envAsDict ret = shellCall(timeout, [cmd], env=inputEnv) else: cmdTuple.insert(0, "source") cmd = " ".join(cmdTuple) + envAsDict ret = systemCall(timeout, ["/bin/bash", "-c", cmd], env=inputEnv) # 3.- Now get back the result stdout = "" stderr = "" result = DIRAC.S_OK() if ret["OK"]: # The Command has not timeout, retrieve stdout and stderr stdout = ret["Value"][1] stderr = ret["Value"][2] if ret["Value"][0] == 0: # execution was OK try: result["outputEnv"] = eval(stderr.split("\n")[-2] + "\n") stderr = "\n".join(stderr.split("\n")[:-2]) except Exception: stdout = cmd + "\n" + stdout result = DIRAC.S_ERROR("Could not parse Environment dictionary from stderr") else: # execution error stdout = cmd + "\n" + stdout result = DIRAC.S_ERROR("Execution returns %s" % ret["Value"][0]) else: # Timeout stdout = cmd stderr = ret["Message"] result = DIRAC.S_ERROR(stderr) # 4.- Put stdout and stderr in result structure result["stdout"] = stdout result["stderr"] = stderr return result def which(executable): return distutils.spawn.find_executable(executable) # pylint: disable=no-member