blob: 3022f4d638d469a17ac9cfe2ecd852a032200d86 [file]
"""Landmine step for clobbering output directories when needed.
This step checks for a landmine file in continuous-tests/cq/landmines, and
clobbers all the output directories if it finds a new landmine.
For more information on using landmines, checkout out the documentation at
continous-tests/cq/landmines/README.md
"""
from __future__ import absolute_import
import logging
import os
import re
from helpers import git_utils
from slave.step import shell_step
LANDMINE_PATTERN = r'landmine\.(?P<landmine_number>\d+)'
class LandmineStep(shell_step.ShellStep):
"""Landmine step for clobbering output directories when needed."""
def __init__(self, eureka_root, **kwargs):
"""Creates a LandmineStep instance."""
shell_step.ShellStep.__init__(self,
name='landmine',
halt_on_failure=True,
**kwargs)
self._landmine_path = eureka_root / '.landmines'
def get_landmine_dir(self):
"""Return the directory where new landmine files get checked in."""
continuous_tests = self.get_project_path('continuous-tests')
return os.path.join(continuous_tests, 'cq', 'landmines')
def get_landmine(self):
"""Returns the name of landmine file with the highest number (or None)."""
landmine = None
max_landmine_number = float('-inf')
landmine_dir = self.get_landmine_dir()
if not os.path.isdir(landmine_dir):
return landmine
for filename in os.listdir(landmine_dir):
match = re.search(LANDMINE_PATTERN, filename)
if match:
logging.info('Found landmine file: %s', filename)
landmine_number = int(match.group('landmine_number'))
if landmine_number > max_landmine_number:
landmine, max_landmine_number = filename, landmine_number
logging.info('Highest landmine: %s', landmine)
return landmine
def should_clobber(self, landmine):
"""Returns True if |landmine| is new, indicating a clobber should happen."""
return not (self._landmine_path / landmine).exists()
def should_mark_landmine_used(self, landmine):
"""A landmine should only be marked used once it is committed.
If a landmine is in the patches running through CQ, then do not mark
the landmine as used, so that if a builder runs another CL between running
the landmine CL and the landmine actually landing, the landmine can run
again.
"""
all_patches = [{'project': self.patch_project}] + self.depends_on_list
changed_files = git_utils.get_changed_files_in_all_patches(
self, all_patches, self.get_project_path_lookup_table())
return all(landmine not in f for f in changed_files)
def get_commands(self):
commands = []
landmine = self.get_landmine()
if landmine and self.should_clobber(landmine):
commands.append(self.ShellCommand(['make', 'clean'], cwd=os.getcwd()))
commands.append(self.ShellCommand(
['mkdir', '-p', str(self._landmine_path)],
cwd=os.getcwd()))
if self.should_mark_landmine_used(landmine):
commands.append(self.ShellCommand(
['touch', str(self._landmine_path / landmine)],
cwd=os.getcwd()))
return commands