Repro cmd and run cmd change

This commit is contained in:
Dmitry Petrov
2017-03-15 20:02:14 -07:00
parent 4f6f2bfc89
commit 9e47af4602
11 changed files with 446 additions and 136 deletions
+8 -8
View File
@@ -38,7 +38,7 @@ class CmdDataImport(CmdBase):
lock = fasteners.InterProcessLock(self.git.lock_file)
gotten = lock.acquire(timeout=5)
if not gotten:
Logger.info('Cannot perform the command since NLX is busy and locked. Please retry the command later.')
Logger.printing('Cannot perform the command since NLX is busy and locked. Please retry the command later.')
return 1
try:
@@ -79,22 +79,22 @@ class CmdDataImport(CmdBase):
os.makedirs(os.path.dirname(dobj.cache_file_relative), exist_ok=True)
if CmdDataImport.is_url(input):
Logger.verbose('Downloading file {} ...'.format(input))
Logger.debug('Downloading file {} ...'.format(input))
self.download_file(input, dobj.cache_file_relative)
Logger.verbose('Input file "{}" was downloaded to cache "{}"'.format(
Logger.debug('Input file "{}" was downloaded to cache "{}"'.format(
input, dobj.cache_file_relative))
else:
copyfile(input, dobj.cache_file_relative)
Logger.verbose('Input file "{}" was copied to cache "{}"'.format(
Logger.debug('Input file "{}" was copied to cache "{}"'.format(
input, dobj.cache_file_relative))
dobj.create_symlink()
Logger.verbose('Symlink from data file "{}" to the cache file "{}" was created'.
format(dobj.data_file_relative, dobj.cache_file_relative))
Logger.debug('Symlink from data file "{}" to the cache file "{}" was created'.
format(dobj.data_file_relative, dobj.cache_file_relative))
state_file = StateFile(dobj.state_file_relative, self.git)
state_file.save()
Logger.verbose('State file "{}" was created'.format(dobj.state_file_relative))
Logger.debug('State file "{}" was created'.format(dobj.state_file_relative))
pass
URL_REGEX = re.compile(
@@ -124,7 +124,7 @@ class CmdDataImport(CmdBase):
last_reported += chunk_size
if last_reported >= report_bucket:
last_reported = 0
Logger.verbose('Downloaded {}'.format(sizeof_fmt(downloaded)))
Logger.debug('Downloaded {}'.format(sizeof_fmt(downloaded)))
f.write(chunk)
return
+2 -2
View File
@@ -30,7 +30,7 @@ class CmdDataRemove(CmdBase):
lock = fasteners.InterProcessLock(self.git.lock_file)
gotten = lock.acquire(timeout=5)
if not gotten:
Logger.info('Cannot perform the command since NLX is busy and locked. Please retry the command later.')
Logger.printing('Cannot perform the command since NLX is busy and locked. Please retry the command later.')
return 1
try:
@@ -92,7 +92,7 @@ class CmdDataRemove(CmdBase):
Logger.warn('S3 remove warning: file "{}" does not exist in S3'.format(aws_file_name))
else:
key.delete()
Logger.info('File "{}" was removed from S3'.format(aws_file_name))
Logger.printing('File "{}" was removed from S3'.format(aws_file_name))
def remove_dir(self, data_dir):
for f in os.listdir(data_dir):
+11 -11
View File
@@ -23,7 +23,7 @@ def sizeof_fmt(num, suffix='B'):
def percent_cb(complete, total):
Logger.verbose('{} transferred out of {}'.format(sizeof_fmt(complete), sizeof_fmt(total)))
Logger.debug('{} transferred out of {}'.format(sizeof_fmt(complete), sizeof_fmt(total)))
def file_md5(fname):
@@ -44,7 +44,7 @@ class CmdDataSync(CmdBase):
self._bucket = conn.lookup(bucket_name)
if not self._bucket:
self._bucket = conn.create_bucket(bucket_name)
Logger.info('S3 bucket "{}" was created'.format(bucket_name))
Logger.printing('S3 bucket "{}" was created'.format(bucket_name))
pass
def define_args(self, parser):
@@ -84,30 +84,30 @@ class CmdDataSync(CmdBase):
if not key:
raise DataSyncError('File "{}" does not exist in the cloud'.format(dobj.cache_file_aws_key))
Logger.info('Downloading cache file from S3 "{}/{}"'.format(self._bucket.name,
dobj.cache_file_aws_key))
Logger.printing('Downloading cache file from S3 "{}/{}"'.format(self._bucket.name,
dobj.cache_file_aws_key))
key.get_contents_to_filename(dobj.cache_file_relative, cb=percent_cb)
Logger.info('Downloading completed')
Logger.printing('Downloading completed')
pass
def sync_to_cloud(self, dobj):
key = self._bucket.get_key(dobj.cache_file_aws_key)
if key:
Logger.verbose('File already uploaded to the cloud. Checksum validation...')
Logger.debug('File already uploaded to the cloud. Checksum validation...')
md5_cloud = key.etag[1:-1]
md5_local = file_md5(dobj.cache_file_relative)
if md5_cloud == md5_local:
Logger.verbose('File checksum matches. No uploading is needed.')
Logger.debug('File checksum matches. No uploading is needed.')
return
Logger.info('Checksum miss-match. Re-uploading is required.')
Logger.printing('Checksum miss-match. Re-uploading is required.')
Logger.info('Uploading cache file "{}" to S3 "{}"'.format(dobj.cache_file_relative,
dobj.cache_file_aws_key))
Logger.printing('Uploading cache file "{}" to S3 "{}"'.format(dobj.cache_file_relative,
dobj.cache_file_aws_key))
key = self._bucket.new_key(dobj.cache_file_aws_key)
key.set_contents_from_filename(dobj.cache_file_relative, cb=percent_cb)
Logger.info('Uploading completed')
Logger.printing('Uploading completed')
pass
+3 -3
View File
@@ -76,7 +76,7 @@ SecurityGroup = neatlynx-group'''
data_dir_path.mkdir()
cache_dir_path.mkdir()
state_dir_path.mkdir()
Logger.info('Directories {}, {} and {} were created'.format(
Logger.printing('Directories {}, {} and {} were created'.format(
data_dir_path.name,
cache_dir_path.name,
state_dir_path.name))
@@ -92,12 +92,12 @@ SecurityGroup = neatlynx-group'''
gitignore_file = os.path.join(self.git.git_dir, '.gitignore')
if not os.path.exists(gitignore_file):
open(gitignore_file, 'a').close()
Logger.info('File .gitignore was created')
Logger.printing('File .gitignore was created')
with open(gitignore_file, 'a') as fd:
fd.write('\n{}'.format(cache_dir_name))
fd.write('\n{}'.format(os.path.basename(self.git.lock_file)))
Logger.info('Directory {} was added to .gitignore file'.format(cache_dir_name))
Logger.printing('Directory {} was added to .gitignore file'.format(cache_dir_name))
if __name__ == '__main__':
+88 -10
View File
@@ -1,6 +1,10 @@
import os
import fasteners
from neatlynx.cmd_base import CmdBase
from neatlynx.cmd_run import CmdRun
from neatlynx.git_wrapper import GitWrapper
from neatlynx.logger import Logger
from neatlynx.exceptions import NeatLynxException
from neatlynx.data_file_obj import DataFileObj
@@ -12,29 +16,103 @@ class ReproError(NeatLynxException):
NeatLynxException.__init__(self, 'Run error: {}'.format(msg))
class CmdRepro(CmdBase):
class CmdRepro(CmdRun):
def __init__(self):
CmdBase.__init__(self)
pass
def define_args(self, parser):
self.add_string_arg(parser, 'target', 'Reproduce data file')
self.set_skip_git_actions(parser)
# self.add_string_arg(parser, 'target', 'Reproduce data file')
parser.add_argument('target', metavar='', help='Data file to reproduce', nargs='*')
pass
# Overridden methods:
@property
def declaration_input_files(self):
return []
@property
def declaration_output_files(self):
return []
def run(self):
if not self.git.is_ready_to_go():
lock = fasteners.InterProcessLock(self.git.lock_file)
gotten = lock.acquire(timeout=5)
if not gotten:
Logger.printing('Cannot perform the command since NLX is busy and locked. Please retry the command later.')
return 1
dobj = DataFileObj(self.args.target, self.git, self.config)
os.remove(self.args.target)
try:
if not self.skip_git_actions and not self.git.is_ready_to_go():
return 1
state_file = StateFile(dobj.state_file_relative, self.git)
returncode, out, err = state_file.repro()
dobjs, externally_created_files = DataFileObj.files_to_dobjs(self.args.target, self.git, self.config)
if externally_created_files:
Logger.error('Files from outside of the data directory "{}" could not be reproduced: {}'.
format(self.config.data_dir, ' '.join(externally_created_files)))
return 1
print(out)
sys.stderr.write(err)
error = False
for dobj in dobjs:
self.repro(dobj)
return returncode
# if returncode != 0:
# error = True
# Logger.error('Error: cannot reproduce file "{}"\n{}'.format(
# dobj.data_file_relative, out))
# sys.stderr.write('{}\n'.format(err))
if error and not self.skip_git_actions:
Logger.error('Errors occurred. One or more repro command was not successful.')
self.not_committed_changes_warning()
return 1
if self.skip_git_actions:
self.not_committed_changes_warning()
return 0
message = 'NLX repro: {}'.format(' '.join(self.args.target))
self.git.commit_all_changes_and_log_status(message)
finally:
lock.release()
# dobj = DataFileObj(self.args.target, self.git, self.config)
# os.remove(self.args.target)
#
# state_file = StateFile(dobj.state_file_relative, self.git)
# returncode, out, err = state_file.repro()
#
# print(out)
# sys.stderr.write(err)
#
# return returncode
return 0
def repro(self, dobj):
state = StateFile.load(dobj.state_file_relative, self.git)
argv = state.norm_argv
if not argv:
raise ReproError('Error: parameter {} is nor defined in state file "{}"'.
format(StateFile.PARAM_NORM_ARGV, dobj.state_file_relative))
if len(argv) < 2:
raise ReproError('Error: reproducible command in state file "{}" is too short'.
format(self.file))
if argv[0][-3:] != '.py':
raise ReproError('Error: reproducible command format error in state file "{}"'.
format(self.file))
argv.pop(0)
Logger.debug('Removing data file "{}"'.format(dobj.data_file_relative))
os.remove(dobj.data_file_relative)
Logger.debug("Repro cmd:\n\t{}".format(' '.join(argv)))
return self.run_command(argv)
if __name__ == '__main__':
+93 -75
View File
@@ -1,13 +1,13 @@
import os
import sys
import shutil
import fasteners
from neatlynx.data_file_obj import DataFileObj, NotInDataDirError
from neatlynx.git_wrapper import GitWrapper
from neatlynx.cmd_base import CmdBase
from neatlynx.logger import Logger
from neatlynx.exceptions import NeatLynxException
from neatlynx.data_file_obj import DataFileObj, NotInDataDirError
from neatlynx.repository_change import RepositoryChange
from neatlynx.state_file import StateFile
@@ -27,59 +27,38 @@ class CmdRun(CmdBase):
parser.add_argument('--random', help='not reproducible, output is random', action='store_true')
parser.add_argument('--stdout', help='output std output to a file')
parser.add_argument('--stderr', help='output std error to a file')
parser.add_argument('--input-file', '-i', action='append',
help='Declare input file for reproducible command')
parser.add_argument('--output-file', '-o', action='append',
help='Declare output file for reproducible command')
pass
@property
def declaration_input_files(self):
if self.args.input_file:
return self.args.input_file
return []
@property
def declaration_output_files(self):
if self.args.output_file:
return self.args.output_file
return []
def run(self):
lock = fasteners.InterProcessLock(self.git.lock_file)
gotten = lock.acquire(timeout=5)
if not gotten:
Logger.info('Cannot perform the command since NLX is busy and locked. Please retry the command later.')
Logger.printing('Cannot perform the command since NLX is busy and locked. Please retry the command later.')
return 1
try:
if not self.skip_git_actions and not self.git.is_ready_to_go():
return 1
old_files = set(self.get_changed_files())
GitWrapper.exec_cmd(self._args_unkn, self.args.stdout, self.args.stderr)
new_files = set(self.get_changed_files())
removed_files = old_files - new_files
if removed_files != set():
Logger.error('Error: existing files were removed in run command'.format(' '.join(removed_files)))
created_files = new_files - old_files
if created_files == set():
Logger.error('Error: no files were changes in run command')
if not self.run_command(self._args_unkn, self.args.stdout, self.args.stderr):
return 1
dobjs, errors = self.files_to_dobjs(created_files)
if errors:
for file in GitWrapper.abs_paths_to_relative(errors):
Logger.error('Error: file "{}" was created outside of the data directory'.format(file))
for file in created_files:
rel_path = GitWrapper.abs_paths_to_relative([file])[0]
Logger.error('Removing created file: {}'.format(rel_path))
os.remove(file)
Logger.error('Errors occurred. Please fix the errors and re-run the command.')
return 1
for dobj in dobjs:
os.makedirs(os.path.dirname(dobj.cache_file_relative), exist_ok=True)
shutil.move(dobj.data_file_relative, dobj.cache_file_relative)
dobj.create_symlink()
state_file = StateFile(dobj.state_file_relative, self.git)
state_file.save()
pass
if self.skip_git_actions:
self.not_committed_changes_warning()
return 0
@@ -91,49 +70,88 @@ class CmdRun(CmdBase):
return 0
def files_to_dobjs(self, files):
result = []
errors = []
def run_command(self, argv, stdout=None, stderr=None):
repo_change = RepositoryChange(argv, stdout, stderr, self.git, self.config)
for file in files:
if not self.skip_git_actions and not self.validate_file_states(repo_change):
self.remove_new_files(repo_change)
return False
output_files = self.git.abs_paths_to_nlx(repo_change.new_files + self.declaration_output_files)
input_files_from_args = list(set(self.get_data_files_from_args(argv)) - set(repo_change.new_files))
input_files = self.git.abs_paths_to_nlx(input_files_from_args + self.declaration_input_files)
for dobj in repo_change.dobj_for_new_files:
os.makedirs(os.path.dirname(dobj.cache_file_relative), exist_ok=True)
Logger.debug('Move output file "{}" to cache dir "{}" and create a symlink'.format(
dobj.data_file_relative, dobj.cache_file_relative))
shutil.move(dobj.data_file_relative, dobj.cache_file_relative)
dobj.create_symlink()
Logger.debug('Create state file "{}"'.format(dobj.state_file_relative))
state_file = StateFile(dobj.state_file_relative, self.git, input_files, output_files)
state_file.save()
pass
return True
@staticmethod
def remove_new_files(repo_change):
for file in repo_change.new_files:
rel_path = GitWrapper.abs_paths_to_relative([file])[0]
Logger.error('Removing created file: {}'.format(rel_path))
os.remove(file)
pass
def validate_file_states(self, files_states):
error = False
for file in GitWrapper.abs_paths_to_relative(files_states.removed_files):
Logger.error('Error: file "{}" was removed'.format(file))
error = True
for file in GitWrapper.abs_paths_to_relative(files_states.modified_files):
Logger.error('Error: file "{}" was modified'.format(file))
error = True
for file in GitWrapper.abs_paths_to_relative(files_states.unusual_state_files):
Logger.error('Error: file "{}" is in not acceptable state'.format(file))
error = True
for file in GitWrapper.abs_paths_to_relative(files_states.externally_created_files):
Logger.error('Error: file "{}" was created outside of the data directory'.format(file))
error = True
if error:
Logger.error('Errors occurred. ' + \
'Reproducible commands allow only file creation only in data directory "{}".'.
format(self.config.data_dir))
return False
if not files_states.new_files:
Logger.error('Errors occurred. No files were changed in run command.')
return False
return True
def get_data_files_from_args(self, argv):
result = []
for arg in argv:
try:
result.append(DataFileObj(file, self.git, self.config))
if os.path.isfile(arg):
DataFileObj(arg, self.git, self.config)
result.append(arg)
except NotInDataDirError:
errors.append(file)
return result, errors
def get_changed_files(self):
statuses = GitWrapper.status_files()
result = []
for status, file in statuses:
file_path = os.path.join(self.git.git_dir_abs, file)
if os.path.isfile(file_path):
result.append(file_path)
else:
files = []
self.get_all_files_from_dir(file_path, files)
for f in files:
result.append(f)
pass
return result
def get_all_files_from_dir(self, dir, result):
if not os.path.isdir(dir):
raise RunError('Changed path {} is not directory'.format(dir))
files = os.listdir(dir)
for f in files:
path = os.path.join(dir, f)
if os.path.isfile(path):
result.append(path)
else:
self.get_all_files_from_dir(path, result)
pass
if __name__ == '__main__':
import sys
try:
sys.exit(CmdRun().run())
except NeatLynxException as e:
+13
View File
@@ -106,6 +106,19 @@ class DataFileObj(object):
def state_file_relative(self):
return os.path.relpath(self.state_file_abs, self._curr_dir_abs)
@staticmethod
def files_to_dobjs(files, git, config):
result = []
externally_created_files = []
for file in files:
try:
result.append(DataFileObj(file, git, config))
except NotInDataDirError:
externally_created_files.append(file)
return result, externally_created_files
class DataFileObjExisting(DataFileObj):
def __init__(self, data_file, git, config):
+16 -5
View File
@@ -70,7 +70,7 @@ class GitWrapper(GitWrapperI):
@staticmethod
def exec_cmd_only_success(cmd, stdout_file=None, stderr_file=None, cwd=None):
code, out, err = GitWrapper.exec_cmd(cmd, stdout_file=None, stderr_file=None, cwd=None)
code, out, err = GitWrapper.exec_cmd(cmd, stdout_file=stdout_file, stderr_file=stderr_file, cwd=cwd)
if code != 0:
if err:
sys.stderr.write(err + '\n')
@@ -88,6 +88,10 @@ class GitWrapper(GitWrapperI):
return True
@property
def curr_dir_nlx(self):
return os.path.relpath(os.path.abspath(os.curdir), self.git_dir_abs)
@property
def git_dir(self):
if self._git_dir:
@@ -143,9 +147,9 @@ class GitWrapper(GitWrapperI):
def commit_all_changes_and_log_status(self, message):
statuses = self.commit_all_changes(message)
Logger.info('A new commit {} was made in the current branch. Added files:'.format(self.curr_commit))
Logger.printing('A new commit {} was made in the current branch. Added files:'.format(self.curr_commit))
for status, file in statuses:
Logger.info('\t{} {}'.format(status, file))
Logger.printing('\t{} {}'.format(status, file))
pass
@property
@@ -158,6 +162,13 @@ class GitWrapper(GitWrapperI):
result = []
for file in files:
result.append(os.path.relpath(file, cur_dir))
result.append(os.path.relpath(os.path.realpath(file), cur_dir))
return result
return result
def abs_paths_to_nlx(self, files):
result = []
for file in files:
result.append(os.path.relpath(os.path.abspath(file), self.git_dir_abs))
return result
+7 -6
View File
@@ -3,17 +3,18 @@ import sys
class Logger(object):
@staticmethod
def info(msg):
print('{}'.format(msg))
def printing(msg):
print(u'{}'.format(msg))
@staticmethod
def warn(msg):
print('{}'.format(msg))
print(u'Warning. {}'.format(msg))
@staticmethod
def error(msg):
sys.stderr.write('{}\n'.format(msg))
#sys.stderr.write('Error. {}\n'.format(msg))
print(u'Error. {}'.format(msg))
@staticmethod
def verbose(msg):
print('{}'.format(msg))
def debug(msg):
print(u'Debug. {}'.format(msg))
+115
View File
@@ -0,0 +1,115 @@
import os
from neatlynx.data_file_obj import DataFileObj, NotInDataDirError
from neatlynx.exceptions import NeatLynxException
from neatlynx.git_wrapper import GitWrapper
class RepositoryChangeError(NeatLynxException):
def __init__(self, msg):
NeatLynxException.__init__(self, 'Repository change error: {}'.format(msg))
class FileModificationState(object):
STATUS_UNTRACKED = '?'
STATUS_DELETE = 'D'
STATUS_MODIFIED = 'M'
def __init__(self, state, file):
self.state = state
self.file = file
def _check_status(self, status):
return self.state.find(status) >= 0
@property
def is_removed(self):
return self._check_status(self.STATUS_DELETE)
@property
def is_modified(self):
return self._check_status(self.STATUS_MODIFIED)
@property
def is_new(self):
return self._check_status(self.STATUS_UNTRACKED)
@property
def is_unusual(self):
return self.is_new or self.is_modified or self.is_removed
class RepositoryChange(object):
"""Pre-condition: git repository has no changes"""
def __init__(self, args, stdout, stderr, git, config):
self.git = git
self.config = config
GitWrapper.exec_cmd_only_success(args, stdout, stderr)
self._file_states = self._get_file_states()
self._new_dobj, self._externally_created_files = DataFileObj.files_to_dobjs(
self.new_files, self.git, self.config)
@staticmethod
def exec_cmd(args, stdout, stderr, git):
return RepositoryChange(args, stdout, stderr, git)
@staticmethod
def get_filenames(mod_state_list):
return list(map(lambda x: x.file, mod_state_list))
@property
def removed_files(self):
return self.get_filenames(filter(lambda x: x.is_removed, self._file_states))
@property
def modified_files(self):
return self.get_filenames(filter(lambda x: x.is_modified, self._file_states))
@property
def new_files(self):
return self.get_filenames(filter(lambda x: x.is_new, self._file_states))
@property
def unusual_state_files(self):
return self.get_filenames(filter(lambda x: not x.is_unusual, self._file_states))
def _get_file_states(self):
statuses = GitWrapper.status_files()
result = []
for status, file in statuses:
file_path = os.path.join(self.git.git_dir_abs, file)
if os.path.isfile(file_path):
result.append(FileModificationState(status, file_path))
else:
files = []
self.get_all_files_from_dir(file_path, files)
state = self.STATUS_UNKNOWN + self.STATUS_UNKNOWN
for f in files:
result.append(FileModificationState(state, f))
return result
def get_all_files_from_dir(self, dir, result):
if not os.path.isdir(dir):
raise RepositoryChangeError('Changed path {} is not directory'.format(dir))
files = os.listdir(dir)
for f in files:
path = os.path.join(dir, f)
if os.path.isfile(path):
result.append(path)
else:
self.get_all_files_from_dir(path, result)
pass
@property
def dobj_for_new_files(self):
return self._new_dobj
@property
def externally_created_files(self):
return self._externally_created_files
+90 -16
View File
@@ -5,6 +5,7 @@ import time
from neatlynx.exceptions import NeatLynxException
from neatlynx.git_wrapper import GitWrapper
from neatlynx.logger import Logger
class StateFileError(NeatLynxException):
@@ -16,17 +17,61 @@ class StateFile(object):
MAGIC = 'NLX-State'
VERSION = '0.1'
def __init__(self, file, git):
PARAM_TYPE = 'Type'
PARAM_VERSION = 'Version'
PARAM_ARGV = 'Argv'
PARAM_NORM_ARGV = 'NormArgv'
PARAM_CWD = 'Cwd'
PARAM_CREATED_AT = 'CreatedAt'
PARAM_INPUT_FILES = 'InputFiles'
PARAM_OUTPUT_FILES = 'OutputFiles'
def __init__(self, file, git, input_files, output_files,
argv=sys.argv, norm_argv=None,
created_at=time.strftime('%Y-%m-%d %H:%M:%S %z'),
cwd=None):
self.file = file
self.git = git
self.input_files = input_files
self.output_files = output_files
self.argv = argv
if norm_argv:
self.norm_argv = norm_argv
else:
self.norm_argv = self.normalized_args()
self.created_at = created_at
if cwd:
self.cwd = cwd
else:
self.cwd = self.get_nlx_path()
pass
@staticmethod
def load(filename, git):
with open(filename, 'r') as fd:
data = json.load(fd)
return StateFile(filename,
git,
data.get('InputFiles'),
data.get('OutputFiles'),
data.get('Argv'),
data.get('NormArgv'),
data.get('CreatedAt'),
data.get('Cwd'))
def save(self):
res = {
'Type': self.MAGIC,
'Version': self.VERSION,
'Argv': sys.argv,
'NLX_cwd': self.get_nlx_path(),
'CreatedAt': time.strftime('%Y-%m-%d %H:%M:%S %z')
self.PARAM_TYPE: self.MAGIC,
self.PARAM_VERSION: self.VERSION,
self.PARAM_ARGV: self.argv,
self.PARAM_NORM_ARGV: self.norm_argv,
self.PARAM_CWD: self.cwd,
self.PARAM_CREATED_AT: self.created_at,
self.PARAM_INPUT_FILES: self.input_files,
self.PARAM_OUTPUT_FILES:self.output_files
}
file_dir = os.path.dirname(self.file)
@@ -37,6 +82,26 @@ class StateFile(object):
json.dump(res, fd, indent=2)
pass
def normalized_args(self):
result = []
if len(sys.argv) > 0:
cmd = sys.argv[0]
pos = cmd.rfind(os.sep)
if pos >= 0:
cmd = cmd[pos+1:]
result.append(cmd)
for arg in sys.argv[1:]:
if os.path.isfile(arg):
path = os.path.abspath(arg)
nlx_path = os.path.relpath(path, self.git.git_dir_abs)
result.append(nlx_path)
else:
result.append(arg)
return result
def get_nlx_path(self):
pwd = os.path.realpath(os.curdir)
if not pwd.startswith(self.git.git_dir_abs):
@@ -44,13 +109,22 @@ class StateFile(object):
return os.path.relpath(pwd, self.git.git_dir_abs)
def repro(self):
with open(self.file, 'r') as fd:
res = json.load(fd)
argv = res['Argv']
argv.insert(0, 'python')
argv.insert(2, '--ignore-git-status')
cwd = os.path.join(self.git.git_dir_abs, res['NLX_cwd'])
return GitWrapper.exec_cmd(argv, cwd=cwd)
# def repro(self):
# with open(self.file, 'r') as fd:
# res = json.load(fd)
#
# args = res['NormArgs']
# if not args:
# raise StateFileError('Error: parameter NormalizedArgs is nor defined in state file "{}"'.
# format(self.file))
# if len(args) < 2:
# raise StateFileError('Error: reproducible command in state file "{}" is too short'.
# format(self.file))
#
# if args[0][-3:] != '.py':
# raise StateFileError('Error: reproducible command format error in state file "{}"'.
# format(self.file))
# args.pop(0)
#
# Logger.info("Repro cmd:\n\t{}".format(' '.join(args)))
# return GitWrapper.exec_cmd(args, cwd=self.git.git_dir_abs)