32
32
import labscript_utils .h5_lock , h5py
33
33
import labscript_utils .properties
34
34
from labscript_utils .labconfig import LabConfig
35
+ from labscript_utils .filewatcher import FileWatcher
35
36
36
37
# This imports the default Qt library that other labscript suite code will
37
38
# import as well, since it all uses qtutils. By having a Qt library already
70
71
startupinfo .dwFlags |= 1 #subprocess.STARTF_USESHOWWINDOW # This variable isn't defined, but apparently it's equal to one.
71
72
else :
72
73
startupinfo = None
73
-
74
+
75
+ # Extract settings from labconfig
76
+ _SAVE_HG_INFO = LabConfig ().getboolean ('labscript' , 'save_hg_info' , fallback = True )
77
+ _SAVE_GIT_INFO = LabConfig ().getboolean ('labscript' , 'save_git_info' , fallback = False )
74
78
75
79
class config (object ):
76
80
suppress_mild_warnings = True
@@ -2174,8 +2178,88 @@ def generate_connection_table(hdf5_file):
2174
2178
else :
2175
2179
master_pseudoclock_name = compiler .master_pseudoclock .name
2176
2180
dataset .attrs ['master_pseudoclock' ] = master_pseudoclock_name
2177
-
2178
-
2181
+
2182
+ # Create a dictionary for caching results from vcs commands. The keys will be
2183
+ # the paths to files that are saved during save_labscripts(). The values will be
2184
+ # a list of tuples of the form (command, info, err); see the "Returns" section
2185
+ # of the _run_vcs_commands() docstring for more info. Also create a FileWatcher
2186
+ # instance for tracking when vcs results need updating. The callback will
2187
+ # replace the outdated cache entry with a new list of updated vcs commands and
2188
+ # outputs.
2189
+ _vcs_cache = {}
2190
+ def _file_watcher_callback (name , info , event ):
2191
+ _vcs_cache [name ] = _run_vcs_commands (name )
2192
+
2193
+ _file_watcher = FileWatcher (_file_watcher_callback )
2194
+
2195
+ def _run_vcs_commands (path ):
2196
+ """Run some VCS commands on a file and return their output.
2197
+
2198
+ The function is used to gather up version control system information so that
2199
+ it can be stored in the hdf5 files of shots. This is for convenience and
2200
+ compliments the full copy of the file already included in the shot file.
2201
+
2202
+ Whether hg and git commands are run is controlled by the `save_hg_info`
2203
+ and `save_git_info` options in the `[labscript]` section of the labconfig.
2204
+
2205
+ Args:
2206
+ path (str): The path with file name and extension of the file on which
2207
+ the commands will be run. The working directory will be set to the
2208
+ directory containing the specified file.
2209
+
2210
+ Returns:
2211
+ results (list of (tuple, str, str)): A list of tuples, each
2212
+ containing information related to one vcs command of the form
2213
+ (command, info, err). The first entry in that tuple is itself a
2214
+ tuple of strings which was passed to subprocess.Popen() in order to
2215
+ run the command. Then info is a string that contains the text
2216
+ printed to stdout by that command, and err contains the text printed
2217
+ to stderr by the command.
2218
+ """
2219
+ # Gather together a list of commands to run.
2220
+ module_directory , module_filename = os .path .split (path )
2221
+ vcs_commands = []
2222
+ if compiler .save_hg_info :
2223
+ hg_commands = [
2224
+ ['log' , '--limit' , '1' ],
2225
+ ['status' ],
2226
+ ['diff' ],
2227
+ ]
2228
+ for command in hg_commands :
2229
+ command = tuple (['hg' ] + command + [module_filename ])
2230
+ vcs_commands .append ((command , module_directory ))
2231
+ if compiler .save_git_info :
2232
+ git_commands = [
2233
+ ['branch' , '--show-current' ],
2234
+ ['describe' , '--tags' , '--always' , 'HEAD' ],
2235
+ ['rev-parse' , 'HEAD' ],
2236
+ ['diff' , 'HEAD' , module_filename ],
2237
+ ]
2238
+ for command in git_commands :
2239
+ command = tuple (['git' ] + command )
2240
+ vcs_commands .append ((command , module_directory ))
2241
+
2242
+ # Now go through and start running the commands.
2243
+ process_list = []
2244
+ for command , module_directory in vcs_commands :
2245
+ process = subprocess .Popen (
2246
+ command ,
2247
+ cwd = module_directory ,
2248
+ stdout = subprocess .PIPE ,
2249
+ stderr = subprocess .PIPE ,
2250
+ startupinfo = startupinfo ,
2251
+ )
2252
+ process_list .append ((command , process ))
2253
+
2254
+ # Gather up results from the commands issued.
2255
+ results = []
2256
+ for command , process in process_list :
2257
+ info , err = process .communicate ()
2258
+ info = info .decode ('utf-8' )
2259
+ err = err .decode ('utf-8' )
2260
+ results .append ((command , info , err ))
2261
+ return results
2262
+
2179
2263
def save_labscripts (hdf5_file ):
2180
2264
if compiler .labscript_file is not None :
2181
2265
script_text = open (compiler .labscript_file ).read ()
@@ -2199,28 +2283,17 @@ def save_labscripts(hdf5_file):
2199
2283
# Doesn't seem to want to double count files if you just import the contents of a file within a module
2200
2284
continue
2201
2285
hdf5_file .create_dataset (save_path , data = open (path ).read ())
2202
- if compiler .save_hg_info :
2203
- hg_commands = [['log' , '--limit' , '1' ], ['status' ], ['diff' ]]
2204
- process_list = []
2205
- for command in hg_commands :
2206
- process = subprocess .Popen (['hg' ] + command + [os .path .split (path )[1 ]], cwd = os .path .split (path )[0 ],
2207
- stdout = subprocess .PIPE , stderr = subprocess .PIPE , startupinfo = startupinfo )
2208
- process_list .append (process )
2209
- for process , command in zip (process_list , hg_commands ):
2210
- info , err = process .communicate ()
2211
- if info or err :
2212
- hdf5_file [save_path ].attrs ['hg ' + str (command [0 ])] = info .decode ('utf-8' ) + '\n ' + err .decode ('utf-8' )
2213
- if compiler .save_git_info :
2214
- module_filename = os .path .split (path )[1 ]
2215
- git_commands = [['branch' , '--show-current' ], ['describe' , '--tags' , '--always' , 'HEAD' ], ['rev-parse' , 'HEAD' ], ['diff' , 'HEAD' , module_filename ]]
2216
- process_list = []
2217
- for command in git_commands :
2218
- process = subprocess .Popen (['git' ] + command , cwd = os .path .split (path )[0 ], stdout = subprocess .PIPE ,
2219
- stderr = subprocess .PIPE , startupinfo = startupinfo )
2220
- process_list .append (process )
2221
- for process , command in zip (process_list , git_commands ):
2222
- info , err = process .communicate ()
2223
- hdf5_file [save_path ].attrs ['git ' + str (command [0 ])] = info .decode ('utf-8' ) + '\n ' + err .decode ('utf-8' )
2286
+ if path not in _file_watcher .files :
2287
+ # Add file to watch list and create its entry in the cache.
2288
+ _file_watcher .add_file (path )
2289
+ _file_watcher_callback (path , None , None )
2290
+ # Get a reference to the current results list in case
2291
+ # another thread updates _vcs_cache[path] to point at a new
2292
+ # list during this loop.
2293
+ results = _vcs_cache [path ]
2294
+ for command , info , err in results :
2295
+ attribute_str = command [0 ] + ' ' + command [1 ]
2296
+ hdf5_file [save_path ].attrs [attribute_str ] = (info + '\n ' + err )
2224
2297
except ImportError :
2225
2298
pass
2226
2299
except WindowsError if os .name == 'nt' else None :
@@ -2554,8 +2627,8 @@ def labscript_cleanup():
2554
2627
compiler .wait_delay = 0
2555
2628
compiler .time_markers = {}
2556
2629
compiler ._PrimaryBLACS = None
2557
- compiler .save_hg_info = LabConfig (). getboolean ( 'labscript' , 'save_hg_info' , fallback = True )
2558
- compiler .save_git_info = LabConfig (). getboolean ( 'labscript' , 'save_git_info' , fallback = False )
2630
+ compiler .save_hg_info = _SAVE_HG_INFO
2631
+ compiler .save_git_info = _SAVE_GIT_INFO
2559
2632
compiler .shot_properties = {}
2560
2633
2561
2634
class compiler (object ):
@@ -2575,8 +2648,8 @@ class compiler(object):
2575
2648
wait_delay = 0
2576
2649
time_markers = {}
2577
2650
_PrimaryBLACS = None
2578
- save_hg_info = LabConfig (). getboolean ( 'labscript' , 'save_hg_info' , fallback = True )
2579
- save_git_info = LabConfig (). getboolean ( 'labscript' , 'save_git_info' , fallback = False )
2651
+ save_hg_info = _SAVE_HG_INFO
2652
+ save_git_info = _SAVE_GIT_INFO
2580
2653
shot_properties = {}
2581
2654
2582
2655
# safety measure in case cleanup is called before init
0 commit comments