-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathvscode-cleanup.py
123 lines (109 loc) · 3.92 KB
/
vscode-cleanup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/env python
#
# Find "vscode" process trees that are older than some age and optionally
# kill them.
#
import subprocess
import time
import signal
import sys
import os
import re
import argparse
def childPids(ppid, pidSet=set()):
"""Recursively find all children processes of the given *ppid*"""
psProc = subprocess.Popen(
['pgrep', '--parent', str(ppid)],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
(psOut, psErr) = psProc.communicate()
del psProc
for psLine in psOut.splitlines():
pid = int(psLine)
pidSet.add(pid)
childPids(pid, pidSet)
return childPids
def parseDurationString(durationStr):
"""Parse a duration string and return the number of seconds represented. Units of d/h/m/s are permissible, e.g. 5d6h10m45s."""
unitMultiplier = {
'd': 86400, 'D': 86400,
'h': 3600, 'H': 3600,
'm': 60, 'M': 60,
's': 1, 'S': 1
}
chunkRegex = re.compile(r'^\s*([0-9]+)([dhmsDHMS]?)(.*)\s*$')
seconds = 0
try:
durS = durationStr
while durS:
chunkMatch = chunkRegex.match(durS)
if chunkMatch is None:
break
dt = int(chunkMatch.group(1))
if chunkMatch.group(2):
dt *= unitMultiplier[chunkMatch.group(2)]
durS = chunkMatch.group(3)
seconds += dt
except:
raise ValueError('Invalid age string: {:s}'.format(durationStr))
return seconds
cliParser = argparse.ArgumentParser(description='find all processes that appear to be Visual Studio Code remote sessions')
cliParser.add_argument('-q', '--quiet',
dest='isNotQuiet',
default=True,
action='store_false',
help='do not output per-pid info as the program runs')
cliParser.add_argument('-k', '--kill',
dest='shouldKill',
default=False,
action='store_true',
help='in addition to printing the process ids also send SIGKILL to each')
cliParser.add_argument('-a', '--age', metavar='<N>{dhms}{<N>{dhms}..}',
dest='age',
default='5d',
help='processes older than this value will be eligible for destruction; a bare number is implied to be seconds, more complex values can use the d/h/m/s characters as units (default 5d)')
cliArgs = cliParser.parse_args()
# Figure out delta-t for age comparisons:
dt = parseDurationString(cliArgs.age)
thresholdTime = int(time.time()) - dt
# Find all processes with the text 'vscode-server' in their command line:
try:
psProc = subprocess.Popen(
['pgrep', '-f', 'vscode-server'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
(psOut, psErr) = psProc.communicate()
del psProc
except Exception as E:
sys.stderr.write('ERROR: pgrep of vscode processes failed: {:s}'.format(str(E)))
exit(1)
# The pgrep command will produce one pid per line:
pidsOfInterest = set()
for psLine in psOut.splitlines():
pid = int(psLine)
# Add this pid and all children to the set:
pidsOfInterest.add(pid)
childPids(pid, pidsOfInterest)
# Show/kill any pids older than the given temporal threshold:
exitCode = 0
for pid in pidsOfInterest:
# Get the process start time by grabbing the creation date off
# its directory in /proc:
try:
pidFInfo = os.stat('/proc/{:d}'.format(pid))
except:
continue
if pidFInfo.st_ctime < thresholdTime:
if cliArgs.shouldKill:
try:
os.kill(pid, signal.SIGKILL)
rc = 'KILLED'
except Exception as E:
rc = 'FAILED ({:s})'.format(str(E))
exitCode = 1
if cliArgs.isNotQuiet: print('{:d} {:s}'.format(pid, rc))
else:
if cliArgs.isNotQuiet: print(pid)
exit(exitCode)