Make file writing atomic

This should render the need to use wrappers obsolete as all
file writing operations are now atomic, assuring that we either
write the entire file or fail.

That is important as we do not want to end-up serving partial files
with the web-server.

Change-Id: I696e2474b557e6b5fea707a198f32cea721cc150
This commit is contained in:
Sorin Sbarnea 2020-11-06 16:16:13 +00:00 committed by zbr
parent 43e7ee9699
commit 5104f277b8
3 changed files with 27 additions and 16 deletions

View File

@ -18,7 +18,6 @@ import argparse
from datetime import datetime
import json
import os
import sys
from launchpadlib import launchpad
import pyelasticsearch
@ -43,6 +42,7 @@ import elastic_recheck.elasticRecheck as er
from elastic_recheck import log as logging
import elastic_recheck.query_builder as qb
import elastic_recheck.results as er_results
from elastic_recheck.utils import atomic_write
STEP = 3600000
@ -237,15 +237,9 @@ def main():
key=lambda bug: -(bug['fails24'] * 100000 + bug['fails']))
jsondata['buglist'] = buglist
if args.output:
out = open(args.output, 'w')
else:
out = sys.stdout
try:
out.write(json.dumps(jsondata))
finally:
out.close()
atomic_write(
args.output,
json.dumps(jsondata))
if __name__ == "__main__":

View File

@ -30,6 +30,7 @@ import elastic_recheck.config as er_config
import elastic_recheck.elasticRecheck as er
import elastic_recheck.query_builder as qb
import elastic_recheck.results as er_results
from elastic_recheck.utils import atomic_write
LOG = logging.getLogger('eruncategorized')
@ -370,14 +371,14 @@ def main():
'ALL_FAILS_QUERY might be broken.', group)
continue
data = collect_metrics(classifier, fails, config=config)
LOG.info(
"Using templates from %s for %s group",
opts.templatedir, group)
engine = setup_template_engine(opts.templatedir, group=group)
html = classifying_rate(fails, data, engine, classifier, config.ls_url)
if opts.output:
out_dir = opts.output
else:
out_dir = os.getcwd()
with open(os.path.join(out_dir, group + '.html'), "w") as f:
f.write(html)
atomic_write(
os.path.join(opts.output or os.getcwd(), group + '.html'),
html)
if __name__ == "__main__":

16
elastic_recheck/utils.py Normal file
View File

@ -0,0 +1,16 @@
import os
import sys
from typing import Optional
def atomic_write(filename: Optional[str], data: str) -> None:
"""Atomically writes a file.
If filename is not mentioned, it will write to sys.stdout
"""
if filename:
with open(f"{filename}.tmp", "w") as f:
f.write(data)
os.replace(f"{filename}.tmp", filename)
else:
sys.stdout.write(data)