OpenDroneMap-ODM/opendm/system.py

176 wiersze
4.9 KiB
Python

import os
import errno
import json
import datetime
import sys
import subprocess
import string
import signal
2021-06-09 15:46:56 +00:00
import io
2023-01-11 18:16:04 +00:00
import shutil
2021-06-09 15:46:56 +00:00
from collections import deque
from opendm import context
from opendm import log
2021-04-05 13:50:04 +00:00
class SubprocessException(Exception):
def __init__(self, msg, errorCode):
super().__init__(msg)
self.errorCode = errorCode
2021-06-09 15:46:56 +00:00
class ExitException(Exception):
pass
def get_ccd_widths():
"""Return the CCD Width of the camera listed in the JSON defs file."""
with open(context.ccd_widths_path) as f:
sensor_data = json.loads(f.read())
return dict(zip(map(string.lower, sensor_data.keys()), sensor_data.values()))
running_subprocesses = []
cleanup_callbacks = []
def add_cleanup_callback(func):
global cleanup_callbacks
cleanup_callbacks.append(func)
def remove_cleanup_callback(func):
global cleanup_callbacks
try:
cleanup_callbacks.remove(func)
except ValueError as e:
log.ODM_EXCEPTION("Tried to remove %s from cleanup_callbacks but got: %s" % (str(func), str(e)))
def exit_gracefully():
global running_subprocesses
global cleanup_callbacks
log.ODM_WARNING("Caught TERM/INT signal, attempting to exit gracefully...")
for cb in cleanup_callbacks:
cb()
for sp in running_subprocesses:
log.ODM_WARNING("Sending TERM signal to PID %s..." % sp.pid)
2021-05-19 19:39:36 +00:00
if sys.platform == 'win32':
os.kill(sp.pid, signal.CTRL_C_EVENT)
else:
os.killpg(os.getpgid(sp.pid), signal.SIGTERM)
os._exit(1)
def sighandler(signum, frame):
exit_gracefully()
signal.signal(signal.SIGINT, sighandler)
signal.signal(signal.SIGTERM, sighandler)
2023-05-18 19:26:34 +00:00
def run(cmd, env_paths=[context.superbuild_bin_path], env_vars={}, packages_paths=context.python_packages_paths, quiet=False):
"""Run a system command"""
global running_subprocesses
2023-05-18 19:26:34 +00:00
if not quiet:
log.ODM_INFO('running %s' % cmd)
env = os.environ.copy()
2021-05-15 18:21:55 +00:00
sep = ":"
if sys.platform == 'win32':
sep = ";"
if len(env_paths) > 0:
2021-05-15 18:21:55 +00:00
env["PATH"] = env["PATH"] + sep + sep.join(env_paths)
if len(packages_paths) > 0:
2021-05-15 18:21:55 +00:00
env["PYTHONPATH"] = env.get("PYTHONPATH", "") + sep + sep.join(packages_paths)
2022-09-10 20:45:16 +00:00
if sys.platform == 'darwin':
# Propagate DYLD_LIBRARY_PATH
cmd = "export DYLD_LIBRARY_PATH=\"%s\" && %s" % (env.get("DYLD_LIBRARY_PATH", ""), cmd)
for k in env_vars:
env[k] = str(env_vars[k])
2021-06-09 15:46:56 +00:00
p = subprocess.Popen(cmd, shell=True, env=env, start_new_session=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
running_subprocesses.append(p)
2021-06-09 15:46:56 +00:00
lines = deque()
for line in io.TextIOWrapper(p.stdout):
print(line, end="")
lines.append(line.strip())
if len(lines) == 11:
lines.popleft()
retcode = p.wait()
2021-06-09 15:46:56 +00:00
2023-05-18 19:26:34 +00:00
if not quiet:
log.logger.log_json_process(cmd, retcode, list(lines))
2021-06-09 15:46:56 +00:00
running_subprocesses.remove(p)
if retcode < 0:
2021-04-05 13:50:04 +00:00
raise SubprocessException("Child was terminated by signal {}".format(-retcode), -retcode)
elif retcode > 0:
2021-04-05 13:50:04 +00:00
raise SubprocessException("Child returned {}".format(retcode), retcode)
def now():
"""Return the current time"""
return datetime.datetime.now().strftime('%a %b %d %H:%M:%S %Z %Y')
def now_raw():
return datetime.datetime.now()
def benchmark(start, benchmarking_file, process):
"""
runs a benchmark with a start datetime object
:return: the running time (delta)
"""
# Write to benchmark file
delta = (datetime.datetime.now() - start).total_seconds()
with open(benchmarking_file, 'a') as b:
b.write('%s runtime: %s seconds\n' % (process, delta))
def mkdir_p(path):
"""Make a directory including parent directories.
"""
try:
os.makedirs(path)
except os.error as exc:
if exc.errno != errno.EEXIST or not os.path.isdir(path):
raise
# Python2 shutil.which
def which(program):
path=os.getenv('PATH')
for p in path.split(os.path.pathsep):
p=os.path.join(p,program)
if os.path.exists(p) and os.access(p,os.X_OK):
return p
def link_file(src, dst):
if os.path.isdir(dst):
dst = os.path.join(dst, os.path.basename(src))
if not os.path.isfile(dst):
if sys.platform == 'win32':
os.link(src, dst)
else:
os.symlink(os.path.relpath(os.path.abspath(src), os.path.dirname(os.path.abspath(dst))), dst)
2023-01-11 18:16:04 +00:00
def move_files(src, dst):
if not os.path.isdir(dst):
raise IOError("Not a directory: %s" % dst)
for f in os.listdir(src):
if os.path.isfile(os.path.join(src, f)):
shutil.move(os.path.join(src, f), dst)
def delete_files(folder, exclude=()):
2023-01-11 18:16:04 +00:00
if not os.path.isdir(folder):
return
for f in os.listdir(folder):
if os.path.isfile(os.path.join(folder, f)):
if not exclude or not f.endswith(exclude):
os.unlink(os.path.join(folder, f))