Skip to content

Commit 13239cc

Browse files
authored
Merge pull request #72 from zakv/save-git-info
Save git info
2 parents 83e10e5 + 4716ceb commit 13239cc

File tree

1 file changed

+107
-14
lines changed

1 file changed

+107
-14
lines changed

labscript/labscript.py

Lines changed: 107 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import sys
1717
import subprocess
1818
import keyword
19+
import threading
1920
from inspect import getcallargs
2021
from functools import wraps
2122

@@ -31,6 +32,8 @@
3132

3233
import labscript_utils.h5_lock, h5py
3334
import labscript_utils.properties
35+
from labscript_utils.labconfig import LabConfig
36+
from labscript_utils.filewatcher import FileWatcher
3437

3538
# This imports the default Qt library that other labscript suite code will
3639
# import as well, since it all uses qtutils. By having a Qt library already
@@ -69,7 +72,10 @@
6972
startupinfo.dwFlags |= 1 #subprocess.STARTF_USESHOWWINDOW # This variable isn't defined, but apparently it's equal to one.
7073
else:
7174
startupinfo = None
72-
75+
76+
# Extract settings from labconfig
77+
_SAVE_HG_INFO = LabConfig().getboolean('labscript', 'save_hg_info', fallback=True)
78+
_SAVE_GIT_INFO = LabConfig().getboolean('labscript', 'save_git_info', fallback=False)
7379

7480
class config(object):
7581
suppress_mild_warnings = True
@@ -2995,8 +3001,90 @@ def generate_connection_table(hdf5_file):
29953001
else:
29963002
master_pseudoclock_name = compiler.master_pseudoclock.name
29973003
dataset.attrs['master_pseudoclock'] = master_pseudoclock_name
2998-
2999-
3004+
3005+
# Create a dictionary for caching results from vcs commands. The keys will be
3006+
# the paths to files that are saved during save_labscripts(). The values will be
3007+
# a list of tuples of the form (command, info, err); see the "Returns" section
3008+
# of the _run_vcs_commands() docstring for more info. Also create a FileWatcher
3009+
# instance for tracking when vcs results need updating. The callback will
3010+
# replace the outdated cache entry with a new list of updated vcs commands and
3011+
# outputs.
3012+
_vcs_cache = {}
3013+
_vcs_cache_rlock = threading.RLock()
3014+
def _file_watcher_callback(name, info, event):
3015+
with _vcs_cache_rlock:
3016+
_vcs_cache[name] = _run_vcs_commands(name)
3017+
3018+
_file_watcher = FileWatcher(_file_watcher_callback)
3019+
3020+
def _run_vcs_commands(path):
3021+
"""Run some VCS commands on a file and return their output.
3022+
3023+
The function is used to gather up version control system information so that
3024+
it can be stored in the hdf5 files of shots. This is for convenience and
3025+
compliments the full copy of the file already included in the shot file.
3026+
3027+
Whether hg and git commands are run is controlled by the `save_hg_info`
3028+
and `save_git_info` options in the `[labscript]` section of the labconfig.
3029+
3030+
Args:
3031+
path (str): The path with file name and extension of the file on which
3032+
the commands will be run. The working directory will be set to the
3033+
directory containing the specified file.
3034+
3035+
Returns:
3036+
results (list of (tuple, str, str)): A list of tuples, each
3037+
containing information related to one vcs command of the form
3038+
(command, info, err). The first entry in that tuple is itself a
3039+
tuple of strings which was passed to subprocess.Popen() in order to
3040+
run the command. Then info is a string that contains the text
3041+
printed to stdout by that command, and err contains the text printed
3042+
to stderr by the command.
3043+
"""
3044+
# Gather together a list of commands to run.
3045+
module_directory, module_filename = os.path.split(path)
3046+
vcs_commands = []
3047+
if compiler.save_hg_info:
3048+
hg_commands = [
3049+
['log', '--limit', '1'],
3050+
['status'],
3051+
['diff'],
3052+
]
3053+
for command in hg_commands:
3054+
command = tuple(['hg'] + command + [module_filename])
3055+
vcs_commands.append((command, module_directory))
3056+
if compiler.save_git_info:
3057+
git_commands = [
3058+
['branch', '--show-current'],
3059+
['describe', '--tags', '--always', 'HEAD'],
3060+
['rev-parse', 'HEAD'],
3061+
['diff', 'HEAD', module_filename],
3062+
]
3063+
for command in git_commands:
3064+
command = tuple(['git'] + command)
3065+
vcs_commands.append((command, module_directory))
3066+
3067+
# Now go through and start running the commands.
3068+
process_list = []
3069+
for command, module_directory in vcs_commands:
3070+
process = subprocess.Popen(
3071+
command,
3072+
cwd=module_directory,
3073+
stdout=subprocess.PIPE,
3074+
stderr=subprocess.PIPE,
3075+
startupinfo=startupinfo,
3076+
)
3077+
process_list.append((command, process))
3078+
3079+
# Gather up results from the commands issued.
3080+
results = []
3081+
for command, process in process_list:
3082+
info, err = process.communicate()
3083+
info = info.decode('utf-8')
3084+
err = err.decode('utf-8')
3085+
results.append((command, info, err))
3086+
return results
3087+
30003088
def save_labscripts(hdf5_file):
30013089
"""Writes the script files for the compiled shot to the shot file.
30023090
@@ -3028,18 +3116,21 @@ def save_labscripts(hdf5_file):
30283116
# Doesn't seem to want to double count files if you just import the contents of a file within a module
30293117
continue
30303118
hdf5_file.create_dataset(save_path, data=open(path).read())
3031-
if compiler.save_hg_info:
3032-
hg_commands = [['log', '--limit', '1'], ['status'], ['diff']]
3033-
for command in hg_commands:
3034-
process = subprocess.Popen(['hg'] + command + [os.path.split(path)[1]], cwd=os.path.split(path)[0],
3035-
stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo)
3036-
info, err = process.communicate()
3037-
if info or err:
3038-
hdf5_file[save_path].attrs['hg ' + str(command[0])] = info.decode('utf-8') + '\n' + err.decode('utf-8')
3119+
with _vcs_cache_rlock:
3120+
already_cached = path in _vcs_cache
3121+
if not already_cached:
3122+
# Add file to watch list and create its entry in the cache.
3123+
_file_watcher.add_file(path)
3124+
_file_watcher_callback(path, None, None)
3125+
with _vcs_cache_rlock:
3126+
# Save the cached vcs output to the file.
3127+
for command, info, err in _vcs_cache[path]:
3128+
attribute_str = command[0] + ' ' + command[1]
3129+
hdf5_file[save_path].attrs[attribute_str] = (info + '\n' + err)
30393130
except ImportError:
30403131
pass
30413132
except WindowsError if os.name == 'nt' else None:
3042-
sys.stderr.write('Warning: Cannot save Mercurial data for imported scripts. Check that the hg command can be run from the command line.\n')
3133+
sys.stderr.write('Warning: Cannot save version control data for imported scripts. Check that the hg and/or git command can be run from the command line.\n')
30433134

30443135

30453136
def write_device_properties(hdf5_file):
@@ -3409,7 +3500,8 @@ def labscript_cleanup():
34093500
compiler.wait_delay = 0
34103501
compiler.time_markers = {}
34113502
compiler._PrimaryBLACS = None
3412-
compiler.save_hg_info = True
3503+
compiler.save_hg_info = _SAVE_HG_INFO
3504+
compiler.save_git_info = _SAVE_GIT_INFO
34133505
compiler.shot_properties = {}
34143506

34153507
class compiler(object):
@@ -3431,7 +3523,8 @@ class compiler(object):
34313523
wait_delay = 0
34323524
time_markers = {}
34333525
_PrimaryBLACS = None
3434-
save_hg_info = True
3526+
save_hg_info = _SAVE_HG_INFO
3527+
save_git_info = _SAVE_GIT_INFO
34353528
shot_properties = {}
34363529

34373530
# safety measure in case cleanup is called before init

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy