# Licensed to the Apache Software Foundation (ASF) under one# or more contributor license agreements. See the NOTICE file# distributed with this work for additional information# regarding copyright ownership. The ASF licenses this file# to you under the Apache License, Version 2.0 (the# "License"); you may not use this file except in compliance# with the License. You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing,# software distributed under the License is distributed on an# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY# KIND, either express or implied. See the License for the# specific language governing permissions and limitations# under the License."""Common system utilities"""importatexitimportcontextlibimportdatetimeimportosimportpathlibimporttempfileimportthreadingimportshutiltry:importfcntlexceptImportError:fcntl=None
[文档]classDirectoryCreatedPastAtExit(Exception):"""Raised when a TempDirectory is created after the atexit hook runs."""
[文档]classTempDirectory(object):"""Helper object to manage temp directory during testing. Automatically removes the directory when it went out of scope. """# When True, all TempDirectory are *NOT* deleted and instead live inside a predicable directory# tree._KEEP_FOR_DEBUG=False# In debug mode, each tempdir is named after the sequence_NUM_TEMPDIR_CREATED=0_NUM_TEMPDIR_CREATED_LOCK=threading.Lock()@classmethoddef_increment_num_tempdir_created(cls):withcls._NUM_TEMPDIR_CREATED_LOCK:to_return=cls._NUM_TEMPDIR_CREATEDcls._NUM_TEMPDIR_CREATED+=1returnto_return_DEBUG_PARENT_DIR=None@classmethoddef_get_debug_parent_dir(cls):ifcls._DEBUG_PARENT_DIRisNone:all_parents=f"{tempfile.gettempdir()}/tvm-debug-mode-tempdirs"ifnotos.path.isdir(all_parents):os.makedirs(all_parents)cls._DEBUG_PARENT_DIR=tempfile.mkdtemp(prefix=datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S___"),dir=all_parents)returncls._DEBUG_PARENT_DIRTEMPDIRS=set()@classmethoddefremove_tempdirs(cls):temp_dirs=getattr(cls,"TEMPDIRS",None)iftemp_dirsisNone:returnforpathintemp_dirs:shutil.rmtree(path,ignore_errors=True)cls.TEMPDIRS=None
[文档]@classmethod@contextlib.contextmanagerdefset_keep_for_debug(cls,set_to=True):"""Keep temporary directories past program exit for debugging."""old_keep_for_debug=cls._KEEP_FOR_DEBUGtry:cls._KEEP_FOR_DEBUG=set_toyieldfinally:cls._KEEP_FOR_DEBUG=old_keep_for_debug
[文档]defremove(self):"""Remove the tmp dir"""ifself.temp_dir:ifnotself._created_with_keep_for_debug:shutil.rmtree(self.temp_dir,ignore_errors=True)self.TEMPDIRS.remove(self.temp_dir)self.temp_dir=None
@propertydefpath(self):returnpathlib.Path(self.temp_dir)def__truediv__(self,other):ifnotisinstance(other,(str,pathlib.Path)):raiseTypeError(f"TempDirectory / operator: must supply str or pathlib.Path; got {repr(other)}")returnself.path/otherdef__del__(self):temp_dirs=getattr(self,"TEMPDIRS",None)iftemp_dirsisNone:# Do nothing if the atexit hook has already run.returnself.remove()
[文档]defrelpath(self,name):"""Relative path in temp dir Parameters ---------- name : str The name of the file. Returns ------- path : str The concatenated path. """returnos.path.join(self.temp_dir,name)
[文档]deflistdir(self):"""List contents in the dir. Returns ------- names : list The content of directory """returnos.listdir(self.temp_dir)
atexit.register(TempDirectory.remove_tempdirs)
[文档]deftempdir(custom_path=None,keep_for_debug=None):"""Create temp dir which deletes the contents when exit. Parameters ---------- custom_path : str, optional Manually specify the exact temp dir path keep_for_debug : bool Keep temp directory for debugging purposes Returns ------- temp : TempDirectory The temp directory object """returnTempDirectory(custom_path=custom_path,keep_for_debug=keep_for_debug)
[文档]classFileLock(object):"""File lock object Parameters ---------- path : str The path to the lock """def__init__(self,path):self.lock_file=open(path,"w")iffcntl:fcntl.lockf(self.lock_file,fcntl.LOCK_EX)
[文档]defrelease(self):"""Release the lock"""ifself.lock_file:iffcntl:fcntl.lockf(self.lock_file,fcntl.LOCK_UN)self.lock_file.close()self.lock_file=None
[文档]deffilelock(path):"""Create a file lock which locks on path Parameters ---------- path : str The path to the lock Returns ------- lock : File lock object """returnFileLock(path)
[文档]defis_source_path(path):"""Check if path is source code path. Parameters ---------- path : str A possible path Returns ------- valid : bool Whether path is a possible source path """ifos.path.exists(path):returnTrueifpath.find("\n")!=-1:returnFalsespath=path.rsplit(".",1)returnlen(spath)==2andspath[1].strip()==spath[1]
[文档]defwhich(exec_name):"""Try to find full path of exec_name Parameters ---------- exec_name : str The executable name Returns ------- path : str The full path of executable if found, otherwise returns None """base_list=["","/bin"]+os.environ.get("PATH","").split(os.pathsep)forpathinbase_list:full_path=os.path.join(path,exec_name)ifos.path.isfile(full_path)andos.access(full_path,os.X_OK):returnfull_pathreturnNone