summaryrefslogtreecommitdiffstats
path: root/repo_trace.py
diff options
context:
space:
mode:
Diffstat (limited to 'repo_trace.py')
-rw-r--r--repo_trace.py55
1 files changed, 37 insertions, 18 deletions
diff --git a/repo_trace.py b/repo_trace.py
index d79408d9..1ba86c79 100644
--- a/repo_trace.py
+++ b/repo_trace.py
@@ -23,6 +23,7 @@ To also include trace outputs in stderr do `repo --trace_to_stderr ...`
23import sys 23import sys
24import os 24import os
25import time 25import time
26import tempfile
26from contextlib import ContextDecorator 27from contextlib import ContextDecorator
27 28
28import platform_utils 29import platform_utils
@@ -35,34 +36,40 @@ _TRACE = os.environ.get(REPO_TRACE) != '0'
35_TRACE_TO_STDERR = False 36_TRACE_TO_STDERR = False
36_TRACE_FILE = None 37_TRACE_FILE = None
37_TRACE_FILE_NAME = 'TRACE_FILE' 38_TRACE_FILE_NAME = 'TRACE_FILE'
38_MAX_SIZE = 70 # in mb 39_MAX_SIZE = 70 # in MiB
39_NEW_COMMAND_SEP = '+++++++++++++++NEW COMMAND+++++++++++++++++++' 40_NEW_COMMAND_SEP = '+++++++++++++++NEW COMMAND+++++++++++++++++++'
40 41
41 42
42def IsTraceToStderr(): 43def IsTraceToStderr():
44 """Whether traces are written to stderr."""
43 return _TRACE_TO_STDERR 45 return _TRACE_TO_STDERR
44 46
45 47
46def IsTrace(): 48def IsTrace():
49 """Whether tracing is enabled."""
47 return _TRACE 50 return _TRACE
48 51
49 52
50def SetTraceToStderr(): 53def SetTraceToStderr():
54 """Enables tracing logging to stderr."""
51 global _TRACE_TO_STDERR 55 global _TRACE_TO_STDERR
52 _TRACE_TO_STDERR = True 56 _TRACE_TO_STDERR = True
53 57
54 58
55def SetTrace(): 59def SetTrace():
60 """Enables tracing."""
56 global _TRACE 61 global _TRACE
57 _TRACE = True 62 _TRACE = True
58 63
59 64
60def _SetTraceFile(quiet): 65def _SetTraceFile(quiet):
66 """Sets the trace file location."""
61 global _TRACE_FILE 67 global _TRACE_FILE
62 _TRACE_FILE = _GetTraceFile(quiet) 68 _TRACE_FILE = _GetTraceFile(quiet)
63 69
64 70
65class Trace(ContextDecorator): 71class Trace(ContextDecorator):
72 """Used to capture and save git traces."""
66 73
67 def _time(self): 74 def _time(self):
68 """Generate nanoseconds of time in a py3.6 safe way""" 75 """Generate nanoseconds of time in a py3.6 safe way"""
@@ -128,20 +135,32 @@ def _GetTraceFile(quiet):
128 135
129 136
130def _ClearOldTraces(): 137def _ClearOldTraces():
131 """Clear the oldest commands if trace file is too big. 138 """Clear the oldest commands if trace file is too big."""
132 139 try:
133 Note: If the trace file contains output from two `repo` 140 with open(_TRACE_FILE, 'r', errors='ignore') as f:
134 commands that were running at the same time, this 141 if os.path.getsize(f.name) / (1024 * 1024) <= _MAX_SIZE:
135 will not work precisely. 142 return
136 """ 143 trace_lines = f.readlines()
137 if os.path.isfile(_TRACE_FILE): 144 except FileNotFoundError:
138 while os.path.getsize(_TRACE_FILE) / (1024 * 1024) > _MAX_SIZE: 145 return
139 temp_file = _TRACE_FILE + '.tmp' 146
140 with open(_TRACE_FILE, 'r', errors='ignore') as fin: 147 while sum(len(x) for x in trace_lines) / (1024 * 1024) > _MAX_SIZE:
141 with open(temp_file, 'w') as tf: 148 for i, line in enumerate(trace_lines):
142 trace_lines = fin.readlines() 149 if 'END:' in line and _NEW_COMMAND_SEP in line:
143 for i, l in enumerate(trace_lines): 150 trace_lines = trace_lines[i + 1:]
144 if 'END:' in l and _NEW_COMMAND_SEP in l: 151 break
145 tf.writelines(trace_lines[i + 1:]) 152 else:
146 break 153 # The last chunk is bigger than _MAX_SIZE, so just throw everything away.
147 platform_utils.rename(temp_file, _TRACE_FILE) 154 trace_lines = []
155
156 while trace_lines and trace_lines[-1] == '\n':
157 trace_lines = trace_lines[:-1]
158 # Write to a temporary file with a unique name in the same filesystem
159 # before replacing the original trace file.
160 temp_dir, temp_prefix = os.path.split(_TRACE_FILE)
161 with tempfile.NamedTemporaryFile('w',
162 dir=temp_dir,
163 prefix=temp_prefix,
164 delete=False) as f:
165 f.writelines(trace_lines)
166 platform_utils.rename(f.name, _TRACE_FILE)