Skip to content

Commit b3ff011

Browse files
committed
Merge pull request #101 from MarcCote/keep_launch_command
Save the command line in a file to keep an history
2 parents 6cd35aa + 014b1ec commit b3ff011

File tree

3 files changed

+82
-14
lines changed

3 files changed

+82
-14
lines changed

scripts/smart_dispatch.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
# -*- coding: utf-8 -*-
33

44
import os
5+
import sys
56
import argparse
67
import time as t
78
import numpy as np
9+
from os.path import join as pjoin
810
from subprocess import check_output
911
from textwrap import dedent
1012

@@ -53,7 +55,11 @@ def main():
5355
else:
5456
raise ValueError("Unknown subcommand!")
5557

56-
command_manager = CommandManager(os.path.join(path_job_commands, "commands.txt"))
58+
# Keep a log of the command line in the job folder.
59+
command_line = " ".join(sys.argv)
60+
smartdispatch.log_command_line(path_job, command_line)
61+
62+
command_manager = CommandManager(pjoin(path_job_commands, "commands.txt"))
5763

5864
# If resume mode, reset running jobs
5965
if args.mode == "launch":
@@ -82,7 +88,7 @@ def main():
8288

8389
# If no pool size is specified the number of commands is taken
8490
if args.pool is None:
85-
args.pool = command_manager.get_nb_commands_to_run()
91+
args.pool = command_manager.get_nb_commands_to_run(command_line)
8692

8793
# Generating all the worker commands
8894
COMMAND_STRING = 'cd "{cwd}"; smart_worker.py "{commands_file}" "{log_folder}" '\
@@ -111,7 +117,7 @@ def main():
111117
qsub_output = check_output('{launcher} {pbs_filename}'.format(launcher=LAUNCHER if args.launcher is None else args.launcher, pbs_filename=pbs_filename), shell=True)
112118
jobs_id += [qsub_output.strip()]
113119

114-
with utils.open_with_lock(os.path.join(path_job, "jobs_id.txt"), 'a') as jobs_id_file:
120+
with utils.open_with_lock(pjoin(path_job, "jobs_id.txt"), 'a') as jobs_id_file:
115121
jobs_id_file.writelines(t.strftime("## %Y-%m-%d %H:%M:%S ##\n"))
116122
jobs_id_file.writelines("\n".join(jobs_id) + "\n")
117123
print "\nJobs id:\n{jobs_id}".format(jobs_id=" ".join(jobs_id))
@@ -157,10 +163,10 @@ def parse_arguments():
157163

158164

159165
def _gen_job_paths(jobname):
160-
path_smartdispatch_logs = os.path.join(os.getcwd(), LOGS_FOLDERNAME)
161-
path_job = os.path.join(path_smartdispatch_logs, jobname)
162-
path_job_logs = os.path.join(path_job, 'logs')
163-
path_job_commands = os.path.join(path_job, 'commands')
166+
path_smartdispatch_logs = pjoin(os.getcwd(), LOGS_FOLDERNAME)
167+
path_job = pjoin(path_smartdispatch_logs, jobname)
168+
path_job_logs = pjoin(path_job, 'logs')
169+
path_job_commands = pjoin(path_job, 'commands')
164170

165171
return path_job, path_job_logs, path_job_commands
166172

@@ -173,10 +179,10 @@ def get_job_folders(jobname):
173179

174180
if not os.path.exists(path_job_logs):
175181
os.makedirs(path_job_logs)
176-
if not os.path.exists(os.path.join(path_job_logs, "worker")):
177-
os.makedirs(os.path.join(path_job_logs, "worker"))
178-
if not os.path.exists(os.path.join(path_job_logs, "job")):
179-
os.makedirs(os.path.join(path_job_logs, "job"))
182+
if not os.path.exists(pjoin(path_job_logs, "worker")):
183+
os.makedirs(pjoin(path_job_logs, "worker"))
184+
if not os.path.exists(pjoin(path_job_logs, "job")):
185+
os.makedirs(pjoin(path_job_logs, "job"))
180186

181187
return path_job, path_job_logs, path_job_commands
182188

@@ -190,8 +196,8 @@ def create_job_folders(jobname):
190196

191197
if not os.path.exists(path_job_logs):
192198
os.makedirs(path_job_logs)
193-
os.makedirs(os.path.join(path_job_logs, "worker"))
194-
os.makedirs(os.path.join(path_job_logs, "job"))
199+
os.makedirs(pjoin(path_job_logs, "worker"))
200+
os.makedirs(pjoin(path_job_logs, "job"))
195201

196202
return path_job, path_job_logs, path_job_commands
197203

smartdispatch/smartdispatch.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55
import itertools
66
import time as t
7+
from os.path import join as pjoin
78

89
import smartdispatch
910
from smartdispatch import utils
@@ -119,3 +120,23 @@ def get_available_queues(cluster_name=utils.detect_cluster()):
119120

120121
queues_infos = utils.load_dict_from_json_file(config_filepath)
121122
return queues_infos
123+
124+
125+
def log_command_line(path_job, command_line):
126+
""" Logs a command line in a job folder.
127+
128+
The command line is append to a file named 'command_line.log' that resides
129+
in the given job folder. The current date and time is also added along
130+
each command line logged.
131+
132+
Notes
133+
-----
134+
Commands save in log file might differ from sys.argv since we want to make sure
135+
we can paste the command line as-is in the terminal. This means that the quotes
136+
symbole " and the square brackets will be escaped.
137+
"""
138+
with utils.open_with_lock(pjoin(path_job, "command_line.log"), 'a') as command_line_log:
139+
command_line_log.write(t.strftime("## %Y-%m-%d %H:%M:%S ##\n"))
140+
command_line = command_line.replace('"', r'\"') # Make sure we can paste the command line as-is
141+
command_line = re.sub(r'(\[)([^\[\]]*\\ [^\[\]]*)(\])', r'"\1\2\3"', command_line) # Make sure we can paste the command line as-is
142+
command_line_log.write(command_line + "\n\n")

smartdispatch/tests/test_smartdispatch.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1-
import smartdispatch
1+
import os
2+
import re
3+
import shutil
4+
import time as t
5+
from os.path import join as pjoin
26
from StringIO import StringIO
37

8+
import tempfile
49
from nose.tools import assert_true, assert_equal
510
from numpy.testing import assert_array_equal
11+
12+
import smartdispatch
613
from smartdispatch import utils
714

815

@@ -137,3 +144,37 @@ def test_get_available_queues():
137144

138145
queues_infos = smartdispatch.get_available_queues(cluster_name="mammouth")
139146
assert_true(len(queues_infos) > 0)
147+
148+
149+
def test_log_command_line():
150+
temp_dir = tempfile.mkdtemp()
151+
command_line_log_file = pjoin(temp_dir, "command_line.log")
152+
153+
command_1 = "echo 1 2 3"
154+
smartdispatch.log_command_line(temp_dir, command_1)
155+
assert_true(os.path.isfile(command_line_log_file))
156+
157+
lines = open(command_line_log_file).read().strip().split("\n")
158+
assert_equal(len(lines), 2) # Datetime, the command line.
159+
assert_true(t.strftime("## %Y-%m-%d %H:%M:") in lines[0]) # Don't check second.
160+
assert_equal(lines[1], command_1)
161+
162+
command_2 = "echo \"bob\"" # With quotes.
163+
smartdispatch.log_command_line(temp_dir, command_2)
164+
assert_true(os.path.isfile(command_line_log_file))
165+
166+
lines = open(command_line_log_file).read().strip().split("\n")
167+
assert_equal(len(lines), 5)
168+
assert_true(t.strftime("## %Y-%m-%d %H:%M:") in lines[3]) # Don't check second.
169+
assert_equal(lines[4], command_2.replace('"', r'\"'))
170+
171+
command_3 = "echo [asd]" # With square brackets.
172+
smartdispatch.log_command_line(temp_dir, command_3)
173+
assert_true(os.path.isfile(command_line_log_file))
174+
175+
lines = open(command_line_log_file).read().strip().split("\n")
176+
assert_equal(len(lines), 8)
177+
assert_true(t.strftime("## %Y-%m-%d %H:%M:") in lines[6]) # Don't check second.
178+
assert_equal(lines[7], re.sub(r'(\[)([^\[\]]*\\ [^\[\]]*)(\])', r'"\1\2\3"', command_3))
179+
180+
shutil.rmtree(temp_dir)

0 commit comments

Comments
 (0)