Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Runner out of __init__ #816

Merged
merged 1 commit into from
Jun 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 1 addition & 87 deletions lib/ansiblelint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,11 @@

from collections import defaultdict
import logging
import os

from ansiblelint.rules import AnsibleLintRule # noqa F401: exposing public API
import ansiblelint.utils
import ansiblelint.skip_utils
from ansiblelint.errors import MatchError
from ansiblelint.rules.LoadingFailureRule import LoadingFailureRule
from typing import List, Set
from typing import List


_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -100,86 +97,3 @@ def listtags(self):
for tag in sorted(tags):
results.append("{0} {1}".format(tag, tags[tag]))
return "\n".join(results)


class Runner(object):

def __init__(self, rules, playbook, tags, skip_list, exclude_paths,
verbosity=0, checked_files=None):
"""Initialize a Runner instance."""
self.rules = rules
self.playbooks = set()
# assume role if directory
if os.path.isdir(playbook):
self.playbooks.add((os.path.join(playbook, ''), 'role'))
self.playbook_dir = playbook
else:
self.playbooks.add((playbook, 'playbook'))
self.playbook_dir = os.path.dirname(playbook)
self.tags = tags
self.skip_list = skip_list
self._update_exclude_paths(exclude_paths)
self.verbosity = verbosity
if checked_files is None:
checked_files = set()
self.checked_files = checked_files

def _update_exclude_paths(self, exclude_paths):
if exclude_paths:
# These will be (potentially) relative paths
paths = ansiblelint.utils.expand_paths_vars(exclude_paths)
# Since ansiblelint.utils.find_children returns absolute paths,
# and the list of files we create in `Runner.run` can contain both
# relative and absolute paths, we need to cover both bases.
self.exclude_paths = paths + [os.path.abspath(p) for p in paths]
else:
self.exclude_paths = []

def is_excluded(self, file_path):
# Any will short-circuit as soon as something returns True, but will
# be poor performance for the case where the path under question is
# not excluded.
return any(file_path.startswith(path) for path in self.exclude_paths)

def run(self) -> List:
files = list()
for playbook in self.playbooks:
if self.is_excluded(playbook[0]) or playbook[1] == 'role':
continue
files.append({'path': ansiblelint.utils.normpath(playbook[0]),
'type': playbook[1],
# add an absolute path here, so rules are able to validate if
# referenced files exist
'absolute_directory': os.path.dirname(playbook[0])})
visited: Set = set()
matches = list()

while (visited != self.playbooks):
for arg in self.playbooks - visited:
try:
for child in ansiblelint.utils.find_children(arg, self.playbook_dir):
if self.is_excluded(child['path']):
continue
self.playbooks.add((child['path'], child['type']))
files.append(child)
except MatchError as e:
e.rule = LoadingFailureRule
matches.append(e.get_match())
visited.add(arg)

# remove duplicates from files list
files = [value for n, value in enumerate(files) if value not in files[:n]]

# remove files that have already been checked
files = [x for x in files if x['path'] not in self.checked_files]
for file in files:
_logger.debug(
"Examining %s of type %s",
ansiblelint.utils.normpath(file['path']),
file['type'])
matches.extend(self.rules.run(file, tags=set(self.tags),
skip_list=self.skip_list))
# update list of checked files
self.checked_files.update([x['path'] for x in files])

return matches
3 changes: 2 additions & 1 deletion lib/ansiblelint/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
import sys

import ansiblelint.formatters as formatters
from ansiblelint import cli, RulesCollection, Runner
from ansiblelint import cli, RulesCollection
from ansiblelint.constants import DEFAULT_RULESDIR
from ansiblelint.runner import Runner
from ansiblelint.utils import get_playbooks_and_roles
from ansiblelint.utils import normpath, initialize_logger
from ansiblelint.generate_docs import rules_as_rst
Expand Down
98 changes: 98 additions & 0 deletions lib/ansiblelint/runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""Runner implementation."""
import logging
import os
from typing import List, Set

import ansiblelint.utils
import ansiblelint.skip_utils
from .errors import MatchError
from .rules.LoadingFailureRule import LoadingFailureRule


_logger = logging.getLogger(__name__)


class Runner(object):
"""Runner class performs the linting process."""

def __init__(self, rules, playbook, tags, skip_list, exclude_paths,
verbosity=0, checked_files=None):
"""Initialize a Runner instance."""
self.rules = rules
self.playbooks = set()
# assume role if directory
if os.path.isdir(playbook):
self.playbooks.add((os.path.join(playbook, ''), 'role'))
self.playbook_dir = playbook
else:
self.playbooks.add((playbook, 'playbook'))
self.playbook_dir = os.path.dirname(playbook)
self.tags = tags
self.skip_list = skip_list
self._update_exclude_paths(exclude_paths)
self.verbosity = verbosity
if checked_files is None:
checked_files = set()
self.checked_files = checked_files

def _update_exclude_paths(self, exclude_paths):
if exclude_paths:
# These will be (potentially) relative paths
paths = ansiblelint.utils.expand_paths_vars(exclude_paths)
# Since ansiblelint.utils.find_children returns absolute paths,
# and the list of files we create in `Runner.run` can contain both
# relative and absolute paths, we need to cover both bases.
self.exclude_paths = paths + [os.path.abspath(p) for p in paths]
else:
self.exclude_paths = []

def is_excluded(self, file_path):
"""Verify if a file path should be excluded."""
# Any will short-circuit as soon as something returns True, but will
# be poor performance for the case where the path under question is
# not excluded.
return any(file_path.startswith(path) for path in self.exclude_paths)

def run(self) -> List:
"""Execute the linting process."""
files = list()
for playbook in self.playbooks:
if self.is_excluded(playbook[0]) or playbook[1] == 'role':
continue
files.append({'path': ansiblelint.utils.normpath(playbook[0]),
'type': playbook[1],
# add an absolute path here, so rules are able to validate if
# referenced files exist
'absolute_directory': os.path.dirname(playbook[0])})
visited: Set = set()
matches = list()

while (visited != self.playbooks):
for arg in self.playbooks - visited:
try:
for child in ansiblelint.utils.find_children(arg, self.playbook_dir):
if self.is_excluded(child['path']):
continue
self.playbooks.add((child['path'], child['type']))
files.append(child)
except MatchError as e:
e.rule = LoadingFailureRule
matches.append(e.get_match())
visited.add(arg)

# remove duplicates from files list
files = [value for n, value in enumerate(files) if value not in files[:n]]

# remove files that have already been checked
files = [x for x in files if x['path'] not in self.checked_files]
for file in files:
_logger.debug(
"Examining %s of type %s",
ansiblelint.utils.normpath(file['path']),
file['type'])
matches.extend(self.rules.run(file, tags=set(self.tags),
skip_list=self.skip_list))
# update list of checked files
self.checked_files.update([x['path'] for x in files])

return matches
3 changes: 2 additions & 1 deletion test/TestAlwaysRunRule.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
from ansiblelint import RulesCollection, Runner
from ansiblelint import RulesCollection
from ansiblelint.runner import Runner
from ansiblelint.rules.AlwaysRunRule import AlwaysRunRule


Expand Down
3 changes: 2 additions & 1 deletion test/TestBecomeUserWithoutBecome.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
from ansiblelint import RulesCollection, Runner
from ansiblelint import RulesCollection
from ansiblelint.runner import Runner
from ansiblelint.rules.BecomeUserWithoutBecomeRule import BecomeUserWithoutBecomeRule


Expand Down
3 changes: 2 additions & 1 deletion test/TestCommandHasChangesCheck.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
from ansiblelint import Runner, RulesCollection
from ansiblelint import RulesCollection
from ansiblelint.runner import Runner
from ansiblelint.rules.CommandHasChangesCheckRule import CommandHasChangesCheckRule


Expand Down
2 changes: 1 addition & 1 deletion test/TestDependenciesInMeta.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from ansiblelint import Runner
from ansiblelint.runner import Runner


@pytest.mark.parametrize(
Expand Down
2 changes: 1 addition & 1 deletion test/TestImportIncludeRole.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from ansiblelint import Runner
from ansiblelint.runner import Runner


ROLE_TASKS_MAIN = '''
Expand Down
2 changes: 1 addition & 1 deletion test/TestImportWithMalformed.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest

from ansiblelint import Runner
from ansiblelint.runner import Runner


PlayFile = namedtuple('PlayFile', ['name', 'content'])
Expand Down
2 changes: 1 addition & 1 deletion test/TestIncludeMissingFileRule.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest

from ansiblelint import Runner
from ansiblelint.runner import Runner


PlayFile = namedtuple('PlayFile', ['name', 'content'])
Expand Down
3 changes: 2 additions & 1 deletion test/TestNoFormattingInWhenRule.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
from ansiblelint import RulesCollection, Runner
from ansiblelint import RulesCollection
from ansiblelint.runner import Runner
from ansiblelint.rules.NoFormattingInWhenRule import NoFormattingInWhenRule


Expand Down
3 changes: 2 additions & 1 deletion test/TestPackageIsNotLatest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
from ansiblelint import Runner, RulesCollection
from ansiblelint import RulesCollection
from ansiblelint.runner import Runner
from ansiblelint.rules.PackageIsNotLatestRule import PackageIsNotLatestRule


Expand Down
2 changes: 1 addition & 1 deletion test/TestPretaskIncludePlaybook.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from ansiblelint import Runner
from ansiblelint.runner import Runner


@pytest.mark.parametrize('stage', ('pre', 'post'))
Expand Down
3 changes: 2 additions & 1 deletion test/TestRoleHandlers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
from ansiblelint import Runner, RulesCollection
from ansiblelint import RulesCollection
from ansiblelint.runner import Runner
from ansiblelint.rules.UseHandlerRatherThanWhenChangedRule import (
UseHandlerRatherThanWhenChangedRule)

Expand Down
3 changes: 2 additions & 1 deletion test/TestRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

import pytest

from ansiblelint import formatters, Runner
from ansiblelint import formatters
from ansiblelint.runner import Runner
from ansiblelint.cli import abspath


Expand Down
2 changes: 1 addition & 1 deletion test/TestSkipImportPlaybook.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from ansiblelint import Runner
from ansiblelint.runner import Runner

IMPORTED_PLAYBOOK = '''
- hosts: all
Expand Down
3 changes: 2 additions & 1 deletion test/TestTaskHasName.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
from ansiblelint import Runner, RulesCollection
from ansiblelint import RulesCollection
from ansiblelint.runner import Runner
from ansiblelint.rules.TaskHasNameRule import TaskHasNameRule


Expand Down
2 changes: 1 addition & 1 deletion test/TestTaskIncludes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from ansiblelint import Runner
from ansiblelint.runner import Runner


@pytest.mark.parametrize(
Expand Down
3 changes: 2 additions & 1 deletion test/TestUseCommandInsteadOfShell.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
from ansiblelint import Runner, RulesCollection
from ansiblelint import RulesCollection
from ansiblelint.runner import Runner
from ansiblelint.rules.UseCommandInsteadOfShellRule import UseCommandInsteadOfShellRule


Expand Down
3 changes: 2 additions & 1 deletion test/TestUsingBareVariablesIsDeprecated.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
from ansiblelint import Runner, RulesCollection
from ansiblelint import RulesCollection
from ansiblelint.runner import Runner
from ansiblelint.rules.UsingBareVariablesIsDeprecatedRule import UsingBareVariablesIsDeprecatedRule


Expand Down
3 changes: 2 additions & 1 deletion test/TestWithSkipTagId.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
from ansiblelint import RulesCollection, Runner
from ansiblelint import RulesCollection
from ansiblelint.runner import Runner
from ansiblelint.rules.TrailingWhitespaceRule import TrailingWhitespaceRule


Expand Down
2 changes: 1 addition & 1 deletion test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import shutil
import os

from ansiblelint import Runner
from ansiblelint.runner import Runner


class RunFromText(object):
Expand Down