<commit_before>from __future__ import unicode_literals
from __future__ import absolute_import
from docker.client import APIError
import logging
import re
import os
import sys
from .container import Container

log = logging.getLogger(__name__)


class BuildError(Exception):
    pass


class Service(object):
    def __init__(self, name, client=None, project='default', links=[], **options):
        if not re.match('^[a-zA-Z0-9]+$', name):
            raise ValueError('Invalid name: %s' % name)
        if not re.match('^[a-zA-Z0-9]+$', project):
            raise ValueError('Invalid project: %s' % project)
        if 'image' in options and 'build' in options:
            raise ValueError('Service %s has both an image and build path specified. A service can either be built to image or use an existing image, not both.' % name)

        self.name = name
        self.client = client
        self.project = project
        self.links = links or []
        self.options = options

    def containers(self, stopped=False, one_off=False):
        l = []
        for container in self.client.containers(all=stopped):
            name = get_container_name(container)
            if not name or not is_valid_name(name, one_off):
                continue
            project, name, number = parse_name(name)
            if project == self.project and name == self.name:
                l.append(Container.from_ps(self.client, container))
        return l

    def start(self, **options):
        for c in self.containers(stopped=True):
            if not c.is_running:
                self.start_container(c, **options)

    def stop(self, **options):
        for c in self.containers():
            c.stop(**options)

    def kill(self, **options):
        for c in self.containers():
            c.kill(**options)

    def remove_stopped(self, **options):
        for c in self.containers(stopped=True):
            if not c.is_running:
                c.remove(**options)

    def create_container(self, one_off=False, **override_options):
        """
        Create a container for this service. If the image doesn't exist, attempt to pull
        it.
        """
        container_options = self._get_container_options(override_options, one_off=one_off)
        try:
            return Container.create(self.client, **container_options)
        except APIError as e:
            if e.response.status_code == 404 and e.explanation and 'No such image' in str(e.explanation):
                log.info('Pulling image %s...' % container_options['image'])
                self.client.pull(container_options['image'])
                return Container.create(self.client, **container_options)
            raise

    def recreate_containers(self, **override_options):
        """
        If a container for this service doesn't exist, create one. If there are
        any, stop them and create new ones. Does not remove the old containers.
        """
        old_containers = self.containers(stopped=True)
        if len(old_containers) == 0:
            return ([], [self.create_container(**override_options)])
        else:
            new_containers = []
            for old_container in old_containers:
                if old_container.is_running:
                    old_container.stop(timeout=1)
                options = dict(override_options)
                options['volumes_from'] = old_container.id
                new_containers.append(self.create_container(**options))
            return (old_containers, new_containers)

    def start_container(self, container=None, **override_options):
        if container is None:
            container = self.create_container(**override_options)

        options = self.options.copy()
        options.update(override_options)

        port_bindings = {}<commit_msg>Refactor recreate_containers() in preparation for smart name-preserving logic<commit_after>from __future__ import unicode_literals
from __future__ import absolute_import
from docker.client import APIError
import logging
import re
import os
import sys
from .container import Container

log = logging.getLogger(__name__)


class BuildError(Exception):
    pass


class Service(object):
    def __init__(self, name, client=None, project='default', links=[], **options):
        if not re.match('^[a-zA-Z0-9]+$', name):
            raise ValueError('Invalid name: %s' % name)
        if not re.match('^[a-zA-Z0-9]+$', project):
            raise ValueError('Invalid project: %s' % project)
        if 'image' in options and 'build' in options:
            raise ValueError('Service %s has both an image and build path specified. A service can either be built to image or use an existing image, not both.' % name)

        self.name = name
        self.client = client
        self.project = project
        self.links = links or []
        self.options = options

    def containers(self, stopped=False, one_off=False):
        l = []
        for container in self.client.containers(all=stopped):
            name = get_container_name(container)
            if not name or not is_valid_name(name, one_off):
                continue
            project, name, number = parse_name(name)
            if project == self.project and name == self.name:
                l.append(Container.from_ps(self.client, container))
        return l

    def start(self, **options):
        for c in self.containers(stopped=True):
            if not c.is_running:
                self.start_container(c, **options)

    def stop(self, **options):
        for c in self.containers():
            c.stop(**options)

    def kill(self, **options):
        for c in self.containers():
            c.kill(**options)

    def remove_stopped(self, **options):
        for c in self.containers(stopped=True):
            if not c.is_running:
                c.remove(**options)

    def create_container(self, one_off=False, **override_options):
        """
        Create a container for this service. If the image doesn't exist, attempt to pull
        it.
        """
        container_options = self._get_container_options(override_options, one_off=one_off)
        try:
            return Container.create(self.client, **container_options)
        except APIError as e:
            if e.response.status_code == 404 and e.explanation and 'No such image' in str(e.explanation):
                log.info('Pulling image %s...' % container_options['image'])
                self.client.pull(container_options['image'])
                return Container.create(self.client, **container_options)
            raise

    def recreate_containers(self, **override_options):
        """
        If a container for this service doesn't exist, create one. If there are
        any, stop them and create new ones. Does not remove the old containers.
        """
        containers = self.containers(stopped=True)

        if len(containers) == 0:
            return ([], [self.create_container(**override_options)])
        else:
            old_containers = []
            new_containers = []

            for c in containers:
                (old_container, new_container) = self.recreate_container(c, **override_options)
                old_containers.append(old_container)
                new_containers.append(new_container)

            return (old_containers, new_containers)

    def recreate_container(self, container, **override_options):
        if container.is_running:
            container.stop(timeout=1)

        options = dict(override_options)
        options['volumes_from'] = container.id

        return (container, self.create_container(**options))

    def start_container(self, container=None, **override_options):
        if container is None:
            container = self.create_container(**override_options)

        options = self.options.copy()
        options.update(override_options)

        port_bindings = {}
{'fraction_non_alphanumeric': 0.10022750252780586, 'fraction_numerical': 0.002275025278058645, 'mean_word_length': 2.4034408602150537, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6046282', 'n_tokens_mistral': 2174, 'n_tokens_neox': 2079, 'n_words': 602}