<commit_before>#!/usr/bin/env python

# Copyright 2020 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Environment setup script for Pigweed.

This script installs everything and writes out a file for the user's shell
to source.

For now, this is valid Python 2 and Python 3. Once we switch to running this
with PyOxidizer it can be upgraded to recent Python 3.
"""

from __future__ import print_function

import argparse
import contextlib
import glob
import os
import shutil
import subprocess
import sys

# TODO(mohrr) remove import-error disabling, not sure why pylint has issues
# with it.
import cipd.update  # pylint: disable=import-error
import cipd.wrapper  # pylint: disable=import-error
import host_build.init  # pylint: disable=import-error
import cargo.init  # pylint: disable=import-error
import virtualenv.init  # pylint: disable=import-error


class UnexpectedAction(ValueError):
    pass


# TODO(mohrr) use attrs.
class _Action(object):  # pylint: disable=useless-object-inheritance
    # pylint: disable=redefined-builtin,too-few-public-methods
    def __init__(self, type, name, value, *args, **kwargs):
        pathsep = kwargs.pop('pathsep', os.pathsep)
        super(_Action, self).__init__(*args, **kwargs)
        assert type in ('set', 'prepend', 'append')
        self.type = type
        self.name = name
        self.value = value
        self.pathsep = pathsep


# TODO(mohrr) remove disable=useless-object-inheritance once in Python 3.
# pylint: disable=useless-object-inheritance
class Environment(object):
    """Stores the environment changes necessary for Pigweed.

    These changes can be accessed by writing them to a file for bash-like
    shells to source or by using this as a context manager.
    """
    def __init__(self, *args, **kwargs):
        pathsep = kwargs.pop('pathsep', os.pathsep)
        super(Environment, self).__init__(*args, **kwargs)
        self._actions = []
        self._pathsep = pathsep

    def set(self, name, value):
        self._actions.append(_Action('set', name, value))

    def clear(self, name):
        self._actions.append(_Action('set', name, None))

    def append(self, name, value):
        self._actions.append(_Action('append', name, value))

    def prepend(self, name, value):
        self._actions.append(_Action('prepend', name, value))

    def _action_str(self, action):
        if action.type == 'set':
            if action.value is None:
                fmt = 'unset {name}\n'
            else:
                fmt = '{name}="{value}"\nexport {name}\n'
        elif action.type == 'append':
            fmt = '{name}="${name}{sep}{value}"\nexport {name}\n'
        elif action.type == 'prepend':
            fmt = '{name}="{value}{sep}${name}"\nexport {name}\n'
        else:
            raise UnexpectedAction(action.name)

        return fmt.format(
            name=action.name,
            value=action.value,
            sep=self._pathsep,
        )

    def write(self, outs):
        for action in self._actions:
            outs.write(self._action_str(action))
        outs.write('# This should detect bash and zsh, which have a hash \n'
                   '# command that must be called to get it to forget past \n'
                   '# commands. Without forgetting past commands the $PATH \n'
                   '# changes we made may not be respected.\n')
        outs.write('if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then\n')
        outs.write('    hash -r\n')
        outs.write('fi\n')

    @contextlib.contextmanager
    def __call__(self):
        """Set environment as if this was written to a file and sourced."""

        orig_env = os.environ.copy()
        try:
            for action in self._actions:
                if action.type == 'set':
                    if action.value is None:
                        if action.name in os.environ:<commit_msg>Add windows mode to env_setup.py<commit_after>#!/usr/bin/env python

# Copyright 2020 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Environment setup script for Pigweed.

This script installs everything and writes out a file for the user's shell
to source.

For now, this is valid Python 2 and Python 3. Once we switch to running this
with PyOxidizer it can be upgraded to recent Python 3.
"""

from __future__ import print_function

import argparse
import contextlib
import glob
import os
import shutil
import subprocess
import sys

# TODO(mohrr) remove import-error disabling, not sure why pylint has issues
# with it.
import cipd.update  # pylint: disable=import-error
import cipd.wrapper  # pylint: disable=import-error
import host_build.init  # pylint: disable=import-error
import cargo.init  # pylint: disable=import-error
import virtualenv.init  # pylint: disable=import-error


class UnexpectedAction(ValueError):
    pass


# TODO(mohrr) use attrs.
class _Action(object):  # pylint: disable=useless-object-inheritance
    # pylint: disable=redefined-builtin,too-few-public-methods
    def __init__(self, type, name, value, *args, **kwargs):
        pathsep = kwargs.pop('pathsep', os.pathsep)
        super(_Action, self).__init__(*args, **kwargs)
        assert type in ('set', 'prepend', 'append')
        self.type = type
        self.name = name
        self.value = value
        self.pathsep = pathsep


# TODO(mohrr) remove disable=useless-object-inheritance once in Python 3.
# pylint: disable=useless-object-inheritance
class Environment(object):
    """Stores the environment changes necessary for Pigweed.

    These changes can be accessed by writing them to a file for bash-like
    shells to source or by using this as a context manager.
    """
    def __init__(self, *args, **kwargs):
        pathsep = kwargs.pop('pathsep', os.pathsep)
        windows = kwargs.pop('windows', os.name == 'nt')
        super(Environment, self).__init__(*args, **kwargs)
        self._actions = []
        self._pathsep = pathsep
        self._windows = windows

    def set(self, name, value):
        self._actions.append(_Action('set', name, value))

    def clear(self, name):
        self._actions.append(_Action('set', name, None))

    def append(self, name, value):
        self._actions.append(_Action('append', name, value))

    def prepend(self, name, value):
        self._actions.append(_Action('prepend', name, value))

    def _action_str(self, action):
        # TODO(mohrr) find a cleaner way to do this.
        if action.type == 'set':
            if action.value is None:
                if self._windows:
                    fmt = 'set {name}=\n'
                else:
                    fmt = 'unset {name}\n'
            else:
                if self._windows:
                    fmt = 'set {name}={value}\n'
                else:
                    fmt = '{name}="{value}"\nexport {name}\n'

        elif action.type == 'append':
            if self._windows:
                fmt = 'set {name}=%{name}%{sep}{value}\n'
            else:
                fmt = '{name}=${name}{sep}{value}\nexport {name}\n'

        elif action.type == 'prepend':
            if self._windows:
                fmt = 'set {name}={value}{sep}%{name}%\n'
            else:
                fmt = '{name}="{value}{sep}${name}"\nexport {name}\n'

        else:
            raise UnexpectedAction(action.name)

        return fmt.format(
            name=action.name,
            value=action.value,
            sep=self._pathsep,
        )

    def write(self, outs):
        if self._windows:
            outs.write('@echo off\n')

        for action in self._actions:
            outs.write(self._action_str(action))

        if not self._windows:
            outs.write(
                '# This should detect bash and zsh, which have a hash \n'
                '# command that must be called to get it to forget past \n'
                '# commands. Without forgetting past commands the $PATH \n'
                '# changes we made may not be respected.\n'
                'if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then\n'
                '    hash -r\n'
                'fi\n')

    @contextlib.contextmanager
    def __call__(self):
        """Set environment as if this was written to a file and sourced."""

        orig_env = os.environ.copy()
        try:
            for action in self._actions:
                if action.type == 'set':
                    if action.value is None:
                        if action.name in os.environ:
{'fraction_non_alphanumeric': 0.1089317726457872, 'fraction_numerical': 0.002530844669408415, 'mean_word_length': 2.444969124591355, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, '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': '4786000', 'n_tokens_mistral': 2754, 'n_tokens_neox': 2634, 'n_words': 907}