<commit_before># -*- coding: utf-8 -*-
'''
Salt module to manage unix mounts and the fstab file
'''

# Import python libs
import os
import re
import logging

# Import salt libs
import salt.utils
from salt._compat import string_types
from salt.utils import which as _which
from salt.exceptions import CommandNotFoundError, CommandExecutionError

# Set up logger
log = logging.getLogger(__name__)

# Define the module's virtual name
__virtualname__ = 'mount'

def __virtual__():
    '''
    Only load on POSIX-like systems
    '''
    # Disable on Windows, a specific file module exists:
    if salt.utils.is_windows():
        return False
    return True

def _list_mounts():
    ret = {}
    for line in __salt__['cmd.run_stdout']('mount -l').split('\n'):
        comps = re.sub(r"\s+", " ", line).split()
        ret[comps[2]] = comps[0]
    return ret

def _active_mountinfo(ret):
    _list = _list_mounts()
    filename = '/proc/self/mountinfo'
    if not os.access(filename, os.R_OK):
        msg = 'File not readable {0}'
        raise CommandExecutionError(msg.format(filename))

    blkid_info = __salt__['disk.blkid']()

    with salt.utils.fopen(filename) as ifile:
        for line in ifile:
            comps = line.split()
            device = comps[2].split(':')
            device_name = comps[8]
            device_uuid = None
            if device_name:
                device_uuid = blkid_info.get(device_name, {}).get('UUID')
                device_uuid = device_uuid and device_uuid.lower()
            ret[comps[4]] = {'mountid': comps[0],
                             'parentid': comps[1],
                             'major': device[0],
                             'minor': device[1],
                             'root': comps[3],
                             'opts': comps[5].split(','),
                             'fstype': comps[7],
                             'device': device_name,
                             'alt_device': _list.get(comps[4], None),
                             'superopts': comps[9].split(','),
                             'device_uuid': device_uuid}
    return ret

def _active_mounts(ret):
    '''
    List active mounts on Linux systems
    '''
    _list = _list_mounts()
    filename = '/proc/self/mounts'
    if not os.access(filename, os.R_OK):
        msg = 'File not readable {0}'
        raise CommandExecutionError(msg.format(filename))

    with salt.utils.fopen(filename) as ifile:
        for line in ifile:
            comps = line.split()
            ret[comps[1]] = {'device': comps[0],
                             'alt_device': _list.get(comps[1], None),
                             'fstype': comps[2],
                             'opts': comps[3].split(',')}
    return ret

def _active_mounts_freebsd(ret):
    '''
    List active mounts on FreeBSD systems
    '''
    for line in __salt__['cmd.run_stdout']('mount -p').split('\n'):
        comps = re.sub(r"\s+", " ", line).split()
        ret[comps[1]] = {'device': comps[0],
                         'fstype': comps[2],
                         'opts': comps[3].split(',')}
    return ret

def _active_mounts_solaris(ret):
    '''
    List active mounts on Solaris systems
    '''
    for line in __salt__['cmd.run_stdout']('mount -v').split('\n'):
        comps = re.sub(r"\s+", " ", line).split()
        ret[comps[2]] = {'device': comps[0],
                         'fstype': comps[4],
                         'opts': comps[5].split('/')}
    return ret

def _active_mounts_openbsd(ret):
    '''
    List active mounts on OpenBSD systems
    '''
    for line in __salt__['cmd.run_stdout']('mount -v').split('\n'):
        comps = re.sub(r"\s+", " ", line).split()
        nod = __salt__['cmd.run_stdout']('ls -l {0}'.format(comps[0]))
        nod = ' '.join(nod.split()).split(" ")
        parens = re.findall(r'\((.*?)\)', line, re.DOTALL)
        ret[comps[3]] = {'device': comps[0],
                         'fstype': comps[5],
                         'opts': parens[1].split(", "),
                         'major': str(nod[4].strip(",")),
                         'minor': str(nod[5]),
                         'device_uuid': parens[0]}
    return ret

def active():
    '''
    List the active mounts.

    CLI Example:

    .. code-block:: bash

        salt '*' mount.active
    '''
    ret = {}
    if __grains__['os'] == 'FreeBSD':
        _active_mounts_freebsd(ret)
    elif __grains__['os'] == 'Solaris':
        _active_mounts_solaris(ret)
    if __grains__['os'] == 'OpenBSD':
        _active_mounts_openbsd(ret)
    else:
        try:
            _active_mountinfo(ret)
        except CommandExecutionError:
            _active_mounts(ret)
    return ret

def fstab(config='/etc/fstab'):
    '''
    List the contents of the fstab

    CLI Example:

    .. code-block:: bash

        salt '*' mount.fstab
    '''
    ret = {}
    if not os.path.isfile(config):
        return ret
    with salt.utils.fopen(config) as ifile:
        for line in ifile:
            if line.startswith('#'):
                # Commented
                continue
            if not line.strip():
                # Blank line
                continue
            comps = line.split()
            if len(comps) != 6:
                # Invalid entry
                continue
            ret[comps[1]] = {'device': comps[0],
                             'fstype': comps[2],
                             'opts': comps[3].split(','),
                             'dump': comps[4],
                             'pass': comps[5]}
    return ret

def rm_fstab(name, config='/etc/fstab'):
    '''
    Remove the mount point from the fstab

    CLI Example:

    .. code-block:: bash

        salt '*' mount.rm_fstab /mnt/foo
    '''
    contents = fstab(config)
    if name not in contents:
        return True
    # The entry is present, get rid of it
    lines = []
    try:
        with salt.utils.fopen(config, 'r') as ifile:
            for line in ifile:
                if line.startswith('#'):
                    # Commented
                    lines.append(line)
                    continue
                if not line.strip():
                    # Blank line
                    lines.append(line)
                    continue
                comps = line.split()
                if len(comps) != 6:
                    # Invalid entry
                    lines.append(line)
                    continue
                comps = line.split()
                if comps[1] == name:
                    continue
                lines.append(line)
    except (IOError, OSError) as exc:
        msg = "Couldn't read from {0}: {1}"
        raise CommandExecutionError(msg.format(config, str(exc)))

    try:
        with salt.utils.fopen(config, 'w+') as ofile:
            ofile.writelines(lines)
    except (IOError, OSError) as exc:
        msg = "Couldn't write to {0}: {1}"
        raise CommandExecutionError(msg.format(config, str(exc)))
    return True

def set_fstab(
        name,
        device,
        fstype,
        opts='defaults',
        dump=0,
        pass_num=0,
        config='/etc/fstab',
        test=False,
        **kwargs):
    '''
    Verify that this mount is represented in the fstab, change the mount
    to match the data passed, or add the mount if it is not present.

    CLI Example:

    .. code-block:: bash

        salt '*' mount.set_fstab /mnt/foo /dev/sdz1 ext4
    '''
    # Fix the opts type if it is a list
    if isinstance(opts, list):
        opts = ','.join(opts)
    lines = []
    change = False
    present = False

    if not os.path.isfile(config):
        raise CommandExecutionError('Bad config file "{0}"'.format(config))

    try:
        with salt.utils.fopen(config, 'r') as ifile:
            for line in ifile:
                if line.startswith('#'):
                    # Commented
                    lines.append(line)
                    continue
                if not line.strip():
                    # Blank line
                    lines.append(line)
                    continue
                comps = line.split()
                if len(comps) != 6:
                    # Invalid entry
                    lines.append(line)
                    continue
                if comps[0] == device:
                    # check to see if there are changes
                    # and fix them if there are any
                    present = True
                    if comps[0] != device:
                        change = True
                        comps[0] = device
                    if comps[1] != name:
                        change = True
                        comps[1] = name
                    if comps[2] != fstype:
                        change = True
                        comps[2] = fstype
                    if comps[3] != opts:
                        change = True
                        comps[3] = opts
                    if comps[4] != str(dump):
                        change = True
                        comps[4] = str(dump)
                    if comps[5] != str(pass_num):
                        change = True
                        comps[5] = str(pass_num)
                    if change:
                        log.debug(
                            'fstab entry for mount point {0} needs to be '
                            'updated'.format(name)
                        )
                        newline = (
                            '{0}\t\t{1}\t{2}\t{3}\t{4} {5}\n'.format(
                                device, name, fstype, opts, dump, pass_num
                            )
                        )
                        lines.append(newline)
                else:
                    lines.append(line)
    except (IOError, OSError) as exc:
        msg = 'Couldn\'t read from {0}: {1}'
        raise CommandExecutionError(msg.format(config, str(exc)))

    if change:
        if not salt.utils.test_mode(test=test, **kwargs):
            try:
                with salt.utils.fopen(config, 'w+') as ofile:
                    # The line was changed, commit it!
                    ofile.writelines(lines)
            except (IOError, OSError):
                msg = 'File not writable {0}'
                raise CommandExecutionError(msg.format(config))

        return 'change'

    if not change:
        if present:
            # The right entry is already here
            return 'present'
        else:
            if not salt.utils.test_mode(test=test, **kwargs):
                # The entry is new, add it to the end of the fstab
                newline = '{0}\t\t{1}\t{2}\t{3}\t{4} {5}\n'.format(device,
                                                                   name,
                                                                   fstype,
                                                                   opts,
                                                                   dump,
                                                                   pass_num)
                lines.append(newline)
                try:
                    with salt.utils.fopen(config, 'w+') as ofile:
                        # The line was changed, commit it!
                        ofile.writelines(lines)
                except (IOError, OSError):
                    raise CommandExecutionError(
                        'File not writable {0}'.format(
                            config
                        )
                    )
    return 'new'

def mount(name, device, mkmnt=False, fstype='', opts='defaults'):
    '''
    Mount a device

    CLI Example:

    .. code-block:: bash

        salt '*' mount.mount /mnt/foo /dev/sdz1 True
    '''
    if isinstance(opts, string_types):
        opts = opts.split(',')
    if not os.path.exists(name) and mkmnt:
        os.makedirs(name)
    lopts = ','.join(opts)
    args = '-o {0}'.format(lopts)
    if fstype:
        args += ' -t {0}'.format(fstype)
    cmd = 'mount {0} {1} {2} '.format(args, device, name)
    out = __salt__['cmd.run_all'](cmd)
    if out['retcode']:
        return out['stderr']
    return True

def remount(name, device, mkmnt=False, fstype='', opts='defaults'):
    '''
    Attempt to remount a device, if the device is not already mounted, mount
    is called

    CLI Example:

    .. code-block:: bash

        salt '*' mount.remount /mnt/foo /dev/sdz1 True
    '''
    if isinstance(opts, string_types):
        opts = opts.split(',')
    mnts = active()
    if name in mnts:
        # The mount point is mounted, attempt to remount it with the given data
        if 'remount' not in opts and __grains__['os'] != 'OpenBSD':
            opts.append('remount')
        lopts = ','.join(opts)
        args = '-o {0}'.format(lopts)
        if fstype:
            args += ' -t {0}'.format(fstype)
        if __grains__['os'] != 'OpenBSD':
            cmd = 'mount {0} {1} {2} '.format(args, device, name)
        else:
            cmd = 'mount -u {0} {1} {2} '.format(args, device, name)
        out = __salt__['cmd.run_all'](cmd)
        if out['retcode']:
            return out['stderr']
        return True
    # Mount a filesystem that isn't already
    return mount(name, device, mkmnt, fstype, opts)

def umount(name):
    '''
    Attempt to unmount a device by specifying the directory it is mounted on

    CLI Example:

    .. code-block:: bash

        salt '*' mount.umount /mnt/foo
    '''
    mnts = active()
    if name not in mnts:
        return "{0} does not have anything mounted".format(name)

    cmd = 'umount {0}'.format(name)
    out = __salt__['cmd.run_all'](cmd)
    if out['retcode']:
        return out['stderr']
    return True

def is_fuse_exec(cmd):
    '''
    Returns true if the command passed is a fuse mountable application.

    CLI Example:

    .. code-block:: bash

        salt '*' mount.is_fuse_exec sshfs
    '''
    cmd_path = _which(cmd)

    # No point in running ldd on a command that doesn't exist
    if not cmd_path:
        return False
    elif not _which('ldd'):
        raise CommandNotFoundError('ldd')

    out = __salt__['cmd.run']('ldd {0}'.format(cmd_path))
    return 'libfuse' in out

def swaps():
    '''
    Return a dict containing information on active swap

    CLI Example:

    .. code-block:: bash

        salt '*' mount.swaps
    '''
    ret = {}
    if __grains__['os'] != 'OpenBSD':
        with salt.utils.fopen('/proc/swaps') as fp_:
            for line in fp_:
               if line.startswith('Filename'):
                  continue
               comps = line.split()
               ret[comps[0]] = {'type': comps[1],
                                'size': comps[2],
                                'used': comps[3],
                                'priority': comps[4]}
    else:
        for line in __salt__['cmd.run_stdout']('swapctl -kl').splitlines():
            type = "file"
            if line.startswith(('Device', 'Total')):
                continue
            comps = line.split()
            if comps[0].startswith('/dev/'):
                type = "partition"
            ret[comps[0]] = {'type': type,
                             'size': comps[1],
                             'used': comps[2],
                             'priority': comps[5]}
    return ret

def swapon(name, priority=None):
    '''
    Activate a swap disk

    CLI Example:

    .. code-block:: bash

        salt '*' mount.swapon /root/swapfile
    '''
    ret = {}
    on_ = swaps()
    if name in on_:
        ret['stats'] = on_[name]
        ret['new'] = False
        return ret
    cmd = 'swapon {0}'.format(name)
    if priority:
        cmd += ' -p {0}'.format(priority)
    __salt__['cmd.run'](cmd)
    on_ = swaps()
    if name in on_:
        ret['stats'] = on_[name]
        ret['new'] = True
        return ret
    return ret

def swapoff(name):
    '''
    Deactivate a named swap mount

    CLI Example:

    .. code-block:: bash

        salt '*' mount.swapoff /root/swapfile
    '''
    on_ = swaps()
    if name in on_:
        if __grains__['os'] != 'OpenBSD':
            __salt__['cmd.run']('swapoff {0}'.format(name))
        else:
            __salt__['cmd.run']('swapctl -d {0}'.format(name))
        on_ = swaps()
        if name in on_:
            return False
        return True
    return None

def is_mounted(name):
    '''
    .. versionadded:: 2014.7.0

    Provide information if the path is mounted

    CLI Example:

    .. code-block:: bash

        salt '*' mount.is_mounted /mnt/share
    '''
    active_ = active()
    if name in active_:
        return True
    else:
        return False
<commit_msg>Fix lint for #15419<commit_after># -*- coding: utf-8 -*-
'''
Salt module to manage unix mounts and the fstab file
'''

# Import python libs
import os
import re
import logging

# Import salt libs
import salt.utils
from salt._compat import string_types
from salt.utils import which as _which
from salt.exceptions import CommandNotFoundError, CommandExecutionError

# Set up logger
log = logging.getLogger(__name__)

# Define the module's virtual name
__virtualname__ = 'mount'

def __virtual__():
    '''
    Only load on POSIX-like systems
    '''
    # Disable on Windows, a specific file module exists:
    if salt.utils.is_windows():
        return False
    return True

def _list_mounts():
    ret = {}
    for line in __salt__['cmd.run_stdout']('mount -l').split('\n'):
        comps = re.sub(r"\s+", " ", line).split()
        ret[comps[2]] = comps[0]
    return ret

def _active_mountinfo(ret):
    _list = _list_mounts()
    filename = '/proc/self/mountinfo'
    if not os.access(filename, os.R_OK):
        msg = 'File not readable {0}'
        raise CommandExecutionError(msg.format(filename))

    blkid_info = __salt__['disk.blkid']()

    with salt.utils.fopen(filename) as ifile:
        for line in ifile:
            comps = line.split()
            device = comps[2].split(':')
            device_name = comps[8]
            device_uuid = None
            if device_name:
                device_uuid = blkid_info.get(device_name, {}).get('UUID')
                device_uuid = device_uuid and device_uuid.lower()
            ret[comps[4]] = {'mountid': comps[0],
                             'parentid': comps[1],
                             'major': device[0],
                             'minor': device[1],
                             'root': comps[3],
                             'opts': comps[5].split(','),
                             'fstype': comps[7],
                             'device': device_name,
                             'alt_device': _list.get(comps[4], None),
                             'superopts': comps[9].split(','),
                             'device_uuid': device_uuid}
    return ret

def _active_mounts(ret):
    '''
    List active mounts on Linux systems
    '''
    _list = _list_mounts()
    filename = '/proc/self/mounts'
    if not os.access(filename, os.R_OK):
        msg = 'File not readable {0}'
        raise CommandExecutionError(msg.format(filename))

    with salt.utils.fopen(filename) as ifile:
        for line in ifile:
            comps = line.split()
            ret[comps[1]] = {'device': comps[0],
                             'alt_device': _list.get(comps[1], None),
                             'fstype': comps[2],
                             'opts': comps[3].split(',')}
    return ret

def _active_mounts_freebsd(ret):
    '''
    List active mounts on FreeBSD systems
    '''
    for line in __salt__['cmd.run_stdout']('mount -p').split('\n'):
        comps = re.sub(r"\s+", " ", line).split()
        ret[comps[1]] = {'device': comps[0],
                         'fstype': comps[2],
                         'opts': comps[3].split(',')}
    return ret

def _active_mounts_solaris(ret):
    '''
    List active mounts on Solaris systems
    '''
    for line in __salt__['cmd.run_stdout']('mount -v').split('\n'):
        comps = re.sub(r"\s+", " ", line).split()
        ret[comps[2]] = {'device': comps[0],
                         'fstype': comps[4],
                         'opts': comps[5].split('/')}
    return ret

def _active_mounts_openbsd(ret):
    '''
    List active mounts on OpenBSD systems
    '''
    for line in __salt__['cmd.run_stdout']('mount -v').split('\n'):
        comps = re.sub(r"\s+", " ", line).split()
        nod = __salt__['cmd.run_stdout']('ls -l {0}'.format(comps[0]))
        nod = ' '.join(nod.split()).split(" ")
        parens = re.findall(r'\((.*?)\)', line, re.DOTALL)
        ret[comps[3]] = {'device': comps[0],
                         'fstype': comps[5],
                         'opts': parens[1].split(", "),
                         'major': str(nod[4].strip(",")),
                         'minor': str(nod[5]),
                         'device_uuid': parens[0]}
    return ret

def active():
    '''
    List the active mounts.

    CLI Example:

    .. code-block:: bash

        salt '*' mount.active
    '''
    ret = {}
    if __grains__['os'] == 'FreeBSD':
        _active_mounts_freebsd(ret)
    elif __grains__['os'] == 'Solaris':
        _active_mounts_solaris(ret)
    if __grains__['os'] == 'OpenBSD':
        _active_mounts_openbsd(ret)
    else:
        try:
            _active_mountinfo(ret)
        except CommandExecutionError:
            _active_mounts(ret)
    return ret

def fstab(config='/etc/fstab'):
    '''
    List the contents of the fstab

    CLI Example:

    .. code-block:: bash

        salt '*' mount.fstab
    '''
    ret = {}
    if not os.path.isfile(config):
        return ret
    with salt.utils.fopen(config) as ifile:
        for line in ifile:
            if line.startswith('#'):
                # Commented
                continue
            if not line.strip():
                # Blank line
                continue
            comps = line.split()
            if len(comps) != 6:
                # Invalid entry
                continue
            ret[comps[1]] = {'device': comps[0],
                             'fstype': comps[2],
                             'opts': comps[3].split(','),
                             'dump': comps[4],
                             'pass': comps[5]}
    return ret

def rm_fstab(name, config='/etc/fstab'):
    '''
    Remove the mount point from the fstab

    CLI Example:

    .. code-block:: bash

        salt '*' mount.rm_fstab /mnt/foo
    '''
    contents = fstab(config)
    if name not in contents:
        return True
    # The entry is present, get rid of it
    lines = []
    try:
        with salt.utils.fopen(config, 'r') as ifile:
            for line in ifile:
                if line.startswith('#'):
                    # Commented
                    lines.append(line)
                    continue
                if not line.strip():
                    # Blank line
                    lines.append(line)
                    continue
                comps = line.split()
                if len(comps) != 6:
                    # Invalid entry
                    lines.append(line)
                    continue
                comps = line.split()
                if comps[1] == name:
                    continue
                lines.append(line)
    except (IOError, OSError) as exc:
        msg = "Couldn't read from {0}: {1}"
        raise CommandExecutionError(msg.format(config, str(exc)))

    try:
        with salt.utils.fopen(config, 'w+') as ofile:
            ofile.writelines(lines)
    except (IOError, OSError) as exc:
        msg = "Couldn't write to {0}: {1}"
        raise CommandExecutionError(msg.format(config, str(exc)))
    return True

def set_fstab(
        name,
        device,
        fstype,
        opts='defaults',
        dump=0,
        pass_num=0,
        config='/etc/fstab',
        test=False,
        **kwargs):
    '''
    Verify that this mount is represented in the fstab, change the mount
    to match the data passed, or add the mount if it is not present.

    CLI Example:

    .. code-block:: bash

        salt '*' mount.set_fstab /mnt/foo /dev/sdz1 ext4
    '''
    # Fix the opts type if it is a list
    if isinstance(opts, list):
        opts = ','.join(opts)
    lines = []
    change = False
    present = False

    if not os.path.isfile(config):
        raise CommandExecutionError('Bad config file "{0}"'.format(config))

    try:
        with salt.utils.fopen(config, 'r') as ifile:
            for line in ifile:
                if line.startswith('#'):
                    # Commented
                    lines.append(line)
                    continue
                if not line.strip():
                    # Blank line
                    lines.append(line)
                    continue
                comps = line.split()
                if len(comps) != 6:
                    # Invalid entry
                    lines.append(line)
                    continue
                if comps[0] == device:
                    # check to see if there are changes
                    # and fix them if there are any
                    present = True
                    if comps[0] != device:
                        change = True
                        comps[0] = device
                    if comps[1] != name:
                        change = True
                        comps[1] = name
                    if comps[2] != fstype:
                        change = True
                        comps[2] = fstype
                    if comps[3] != opts:
                        change = True
                        comps[3] = opts
                    if comps[4] != str(dump):
                        change = True
                        comps[4] = str(dump)
                    if comps[5] != str(pass_num):
                        change = True
                        comps[5] = str(pass_num)
                    if change:
                        log.debug(
                            'fstab entry for mount point {0} needs to be '
                            'updated'.format(name)
                        )
                        newline = (
                            '{0}\t\t{1}\t{2}\t{3}\t{4} {5}\n'.format(
                                device, name, fstype, opts, dump, pass_num
                            )
                        )
                        lines.append(newline)
                else:
                    lines.append(line)
    except (IOError, OSError) as exc:
        msg = 'Couldn\'t read from {0}: {1}'
        raise CommandExecutionError(msg.format(config, str(exc)))

    if change:
        if not salt.utils.test_mode(test=test, **kwargs):
            try:
                with salt.utils.fopen(config, 'w+') as ofile:
                    # The line was changed, commit it!
                    ofile.writelines(lines)
            except (IOError, OSError):
                msg = 'File not writable {0}'
                raise CommandExecutionError(msg.format(config))

        return 'change'

    if not change:
        if present:
            # The right entry is already here
            return 'present'
        else:
            if not salt.utils.test_mode(test=test, **kwargs):
                # The entry is new, add it to the end of the fstab
                newline = '{0}\t\t{1}\t{2}\t{3}\t{4} {5}\n'.format(device,
                                                                   name,
                                                                   fstype,
                                                                   opts,
                                                                   dump,
                                                                   pass_num)
                lines.append(newline)
                try:
                    with salt.utils.fopen(config, 'w+') as ofile:
                        # The line was changed, commit it!
                        ofile.writelines(lines)
                except (IOError, OSError):
                    raise CommandExecutionError(
                        'File not writable {0}'.format(
                            config
                        )
                    )
    return 'new'

def mount(name, device, mkmnt=False, fstype='', opts='defaults'):
    '''
    Mount a device

    CLI Example:

    .. code-block:: bash

        salt '*' mount.mount /mnt/foo /dev/sdz1 True
    '''
    if isinstance(opts, string_types):
        opts = opts.split(',')
    if not os.path.exists(name) and mkmnt:
        os.makedirs(name)
    lopts = ','.join(opts)
    args = '-o {0}'.format(lopts)
    if fstype:
        args += ' -t {0}'.format(fstype)
    cmd = 'mount {0} {1} {2} '.format(args, device, name)
    out = __salt__['cmd.run_all'](cmd)
    if out['retcode']:
        return out['stderr']
    return True

def remount(name, device, mkmnt=False, fstype='', opts='defaults'):
    '''
    Attempt to remount a device, if the device is not already mounted, mount
    is called

    CLI Example:

    .. code-block:: bash

        salt '*' mount.remount /mnt/foo /dev/sdz1 True
    '''
    if isinstance(opts, string_types):
        opts = opts.split(',')
    mnts = active()
    if name in mnts:
        # The mount point is mounted, attempt to remount it with the given data
        if 'remount' not in opts and __grains__['os'] != 'OpenBSD':
            opts.append('remount')
        lopts = ','.join(opts)
        args = '-o {0}'.format(lopts)
        if fstype:
            args += ' -t {0}'.format(fstype)
        if __grains__['os'] != 'OpenBSD':
            cmd = 'mount {0} {1} {2} '.format(args, device, name)
        else:
            cmd = 'mount -u {0} {1} {2} '.format(args, device, name)
        out = __salt__['cmd.run_all'](cmd)
        if out['retcode']:
            return out['stderr']
        return True
    # Mount a filesystem that isn't already
    return mount(name, device, mkmnt, fstype, opts)

def umount(name):
    '''
    Attempt to unmount a device by specifying the directory it is mounted on

    CLI Example:

    .. code-block:: bash

        salt '*' mount.umount /mnt/foo
    '''
    mnts = active()
    if name not in mnts:
        return "{0} does not have anything mounted".format(name)

    cmd = 'umount {0}'.format(name)
    out = __salt__['cmd.run_all'](cmd)
    if out['retcode']:
        return out['stderr']
    return True

def is_fuse_exec(cmd):
    '''
    Returns true if the command passed is a fuse mountable application.

    CLI Example:

    .. code-block:: bash

        salt '*' mount.is_fuse_exec sshfs
    '''
    cmd_path = _which(cmd)

    # No point in running ldd on a command that doesn't exist
    if not cmd_path:
        return False
    elif not _which('ldd'):
        raise CommandNotFoundError('ldd')

    out = __salt__['cmd.run']('ldd {0}'.format(cmd_path))
    return 'libfuse' in out

def swaps():
    '''
    Return a dict containing information on active swap

    CLI Example:

    .. code-block:: bash

        salt '*' mount.swaps
    '''
    ret = {}
    if __grains__['os'] != 'OpenBSD':
        with salt.utils.fopen('/proc/swaps') as fp_:
            for line in fp_:
                if line.startswith('Filename'):
                    continue
                comps = line.split()
                ret[comps[0]] = {'type': comps[1],
                                 'size': comps[2],
                                 'used': comps[3],
                                 'priority': comps[4]}
    else:
        for line in __salt__['cmd.run_stdout']('swapctl -kl').splitlines():
            type = "file"
            if line.startswith(('Device', 'Total')):
                continue
            comps = line.split()
            if comps[0].startswith('/dev/'):
                type = "partition"
            ret[comps[0]] = {'type': type,
                             'size': comps[1],
                             'used': comps[2],
                             'priority': comps[5]}
    return ret

def swapon(name, priority=None):
    '''
    Activate a swap disk

    CLI Example:

    .. code-block:: bash

        salt '*' mount.swapon /root/swapfile
    '''
    ret = {}
    on_ = swaps()
    if name in on_:
        ret['stats'] = on_[name]
        ret['new'] = False
        return ret
    cmd = 'swapon {0}'.format(name)
    if priority:
        cmd += ' -p {0}'.format(priority)
    __salt__['cmd.run'](cmd)
    on_ = swaps()
    if name in on_:
        ret['stats'] = on_[name]
        ret['new'] = True
        return ret
    return ret

def swapoff(name):
    '''
    Deactivate a named swap mount

    CLI Example:

    .. code-block:: bash

        salt '*' mount.swapoff /root/swapfile
    '''
    on_ = swaps()
    if name in on_:
        if __grains__['os'] != 'OpenBSD':
            __salt__['cmd.run']('swapoff {0}'.format(name))
        else:
            __salt__['cmd.run']('swapctl -d {0}'.format(name))
        on_ = swaps()
        if name in on_:
            return False
        return True
    return None

def is_mounted(name):
    '''
    .. versionadded:: 2014.7.0

    Provide information if the path is mounted

    CLI Example:

    .. code-block:: bash

        salt '*' mount.is_mounted /mnt/share
    '''
    active_ = active()
    if name in active_:
        return True
    else:
        return False
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
Run munin plugins/checks from salt and format the output as data.
'''
from __future__ import absolute_import

# Import python libs
import os
import stat

# Import salt libs
import salt.utils
from six import string_types

PLUGINDIR = '/etc/munin/plugins/'

def __virtual__():
    '''
    Only load the module if munin-node is installed
    '''
    if os.path.exists('/etc/munin/munin-node.conf'):
        return 'munin'
    return False

def _get_conf(fname='/etc/munin/munin-node.cfg'):
    with salt.utils.fopen(fname, 'r') as fp_:
        return fp_.read()

def run(plugins):
    '''
    Run one or more named munin plugins

    CLI Example:

    .. code-block:: bash

        salt '*' munin.run uptime
        salt '*' munin.run uptime,cpu,load,memory
    '''
    all_plugins = list_plugins()

    if isinstance(plugins, string_types):
        plugins = plugins.split(',')

    data = {}
    for plugin in plugins:
        if plugin not in all_plugins:
            continue
        data[plugin] = {}
        muninout = __salt__['cmd.run']('munin-run ' + plugin)
        for line in muninout.split('\n'):
            if 'value' in line:  # This skips multigraph lines, etc
                key, val = line.split(' ')
                key = key.split('.')[0]
                try:
                    # We only want numbers
                    if '.' in val:
                        val = float(val)
                    else:
                        val = int(val)
                    data[plugin][key] = val
                except ValueError:
                    pass
    return data

def run_all():
    '''
    Run all the munin plugins

    CLI Example:

    .. code-block:: bash

        salt '*' munin.run_all
    '''
    plugins = list_plugins()
    ret = {}
    for plugin in plugins:
        ret.update(run(plugin))
    return ret

def list_plugins():
    '''
    List all the munin plugins

    CLI Example:

    .. code-block:: bash

        salt '*' munin.list_plugins
    '''
    pluginlist = os.listdir(PLUGINDIR)
    ret = []
    for plugin in pluginlist:
        # Check if execute bit
        statf = os.path.join(PLUGINDIR, plugin)
        executebit = stat.S_IXUSR & os.stat(statf)[stat.ST_MODE]
        if executebit:
            ret.append(plugin)
    return ret
<commit_msg>Replaced module six in file /salt/modules/munin.py<commit_after># -*- coding: utf-8 -*-
'''
Run munin plugins/checks from salt and format the output as data.
'''
from __future__ import absolute_import

# Import python libs
import os
import stat

# Import salt libs
import salt.utils
from salt.utils.six import string_types

PLUGINDIR = '/etc/munin/plugins/'

def __virtual__():
    '''
    Only load the module if munin-node is installed
    '''
    if os.path.exists('/etc/munin/munin-node.conf'):
        return 'munin'
    return False

def _get_conf(fname='/etc/munin/munin-node.cfg'):
    with salt.utils.fopen(fname, 'r') as fp_:
        return fp_.read()

def run(plugins):
    '''
    Run one or more named munin plugins

    CLI Example:

    .. code-block:: bash

        salt '*' munin.run uptime
        salt '*' munin.run uptime,cpu,load,memory
    '''
    all_plugins = list_plugins()

    if isinstance(plugins, string_types):
        plugins = plugins.split(',')

    data = {}
    for plugin in plugins:
        if plugin not in all_plugins:
            continue
        data[plugin] = {}
        muninout = __salt__['cmd.run']('munin-run ' + plugin)
        for line in muninout.split('\n'):
            if 'value' in line:  # This skips multigraph lines, etc
                key, val = line.split(' ')
                key = key.split('.')[0]
                try:
                    # We only want numbers
                    if '.' in val:
                        val = float(val)
                    else:
                        val = int(val)
                    data[plugin][key] = val
                except ValueError:
                    pass
    return data

def run_all():
    '''
    Run all the munin plugins

    CLI Example:

    .. code-block:: bash

        salt '*' munin.run_all
    '''
    plugins = list_plugins()
    ret = {}
    for plugin in plugins:
        ret.update(run(plugin))
    return ret

def list_plugins():
    '''
    List all the munin plugins

    CLI Example:

    .. code-block:: bash

        salt '*' munin.list_plugins
    '''
    pluginlist = os.listdir(PLUGINDIR)
    ret = []
    for plugin in pluginlist:
        # Check if execute bit
        statf = os.path.join(PLUGINDIR, plugin)
        executebit = stat.S_IXUSR & os.stat(statf)[stat.ST_MODE]
        if executebit:
            ret.append(plugin)
    return ret
<|endoftext|>


<commit_before>#
# Copyright (c) 2004-2007 rPath, Inc.
#
# This program is distributed under the terms of the Common Public License,
# version 1.0. A copy of this license should have been distributed with this
# source file in a file called LICENSE. If it is not present, the license
# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the Common Public License for
# full details.
#

"""
Contains the functions which derive a package and commit the
resulting packages to the repository.
"""

import os
import stat

from conary import branch
from conary import checkin
from conary import conaryclient
from conary import state
from conary import updatecmd
from conary import versions
from conary.build import loadrecipe
from conary.lib import log, util

class DeriveCallback(checkin.CheckinCallback):
    def setUpdateJob(self, *args, **kw):
        # stifle update announcement for extract
        pass

def derive(repos, cfg, targetLabel, troveSpec, checkoutDir = None,
           extract = False, info = False, callback = None):
    """
        Performs all the commands necessary to create a derived recipe.
        First it shadows the package, then it creates a checkout of the shadow
        and converts the checkout to a derived recipe package.

        Finally if extract = True, it installs an version of the binary
        package into a root.

        @param repos: trovesource to search for and derive packages from
        @param cfg: configuration to use when deriving the package
        @type cfg: ConaryConfiguration object
        @param targetLabel: label to derive from
        @type targetLabel: versions.Label
        @param checkoutDir: directory to create the checkout in.  If None,
                             defaults to currentDir + packageName.
        @param extract: If True, creates a subdirectory of the checkout named
                         _ROOT_ with the contents of the binary of the derived
                         package.
        @param info: If true, only display the information about the shadow
                      that would be performed if the derive command were
                      completed.
        @param callback:
    """
    if callback is None:
        callback = DeriveCallback()
    troveName, versionSpec, flavor = conaryclient.cmdline.parseTroveSpec(
                                                                    troveSpec)
    result = repos.findTrove(cfg.buildLabel, (troveName, versionSpec, flavor),
                             cfg.flavor)
    # findTrove shouldn't return multiple items for one package anymore
    # when a flavor is specified.
    assert(len(result) == 1)
    troveToDerive, = result
    # displaying output along the screen allows there to be a record
    # of what operations were performed.  Since this command is
    # an aggregate of several commands I think that is appropriate,
    # rather than simply using a progress callback.
    log.info('Shadowing %s=%s[%s] onto %s' % (troveToDerive[0],
                                             troveToDerive[1],
                                             troveToDerive[2],
                                             targetLabel))
    if info:
        cfg.interactive = False

    error = branch.branch(repos, cfg, str(targetLabel),
                  ['%s=%s[%s]' % troveToDerive],
                  makeShadow = True, sourceOnly = True, binaryOnly = False,
                  info = info)
    if info or error:
        return
    shadowedVersion = troveToDerive[1].createShadow(targetLabel)
    shadowedVersion = shadowedVersion.getSourceVersion(False)
    troveName = troveName.split(':')[0]

    checkoutDir = checkoutDir or troveName
    checkin.checkout(repos, cfg, checkoutDir,
                     ["%s=%s" % (troveName, shadowedVersion)],
                     callback=callback)
    os.chdir(checkoutDir)
    recipeName = troveName + '.recipe'
    recipePath = os.getcwd() + '/' + troveName + '.recipe'
    shadowBranch = shadowedVersion.branch()

    log.info('Rewriting recipe file')
    loader = loadrecipe.RecipeLoader(recipePath, cfg=cfg,
                                     repos=repos,
                                     branch=shadowBranch,
                                     buildFlavor=cfg.buildFlavor)
    recipeClass = loader.getRecipe()
    derivedRecipe = """
class %(className)s(DerivedPackageRecipe):
    name = '%(name)s'
    version = '%(version)s'

    def setup(r):
        pass

""" % dict(className=recipeClass.__name__,
           name=recipeClass.name,
           version=recipeClass.version)
    open(recipeName, 'w').write(derivedRecipe)

    log.info('Removing extra files from checkout')
    conaryState = state.ConaryStateFromFile('CONARY', repos)
    sourceState = conaryState.getSourceState()

    for (pathId, path, fileId, version) in list(sourceState.iterFileList()):
        if path == recipeName:
            continue
        sourceState.removeFile(pathId)
        if util.exists(path):
            statInfo = os.lstat(path)
            try:
                if statInfo.st_mode & stat.S_IFDIR:
                    os.rmdir(path)
                else:
                    os.unlink(path)
            except OSError, e:
                log.warning("cannot remove %s: %s" % (path, e.strerror))
    conaryState.write('CONARY')

    if extract:
        extractDir = os.getcwd() + '/_ROOT_'
        log.info('extracting files from %s=%s[%s]' % (troveToDerive))
        cfg.root = os.path.abspath(extractDir)
        cfg.interactive = False
        updatecmd.doUpdate(cfg, troveSpec,
                           callback=callback, depCheck=False)
<commit_msg>don't loadrecipe to derive things anymore; we can avoid it easily enough<commit_after>#
# Copyright (c) 2004-2007 rPath, Inc.
#
# This program is distributed under the terms of the Common Public License,
# version 1.0. A copy of this license should have been distributed with this
# source file in a file called LICENSE. If it is not present, the license
# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the Common Public License for
# full details.
#

"""
Contains the functions which derive a package and commit the
resulting packages to the repository.
"""

import os
import stat

from conary import branch
from conary import checkin
from conary import conaryclient
from conary import state
from conary import updatecmd
from conary import versions
from conary.lib import log, util

class DeriveCallback(checkin.CheckinCallback):
    def setUpdateJob(self, *args, **kw):
        # stifle update announcement for extract
        pass

def derive(repos, cfg, targetLabel, troveSpec, checkoutDir = None,
           extract = False, info = False, callback = None):
    """
        Performs all the commands necessary to create a derived recipe.
        First it shadows the package, then it creates a checkout of the shadow
        and converts the checkout to a derived recipe package.

        Finally if extract = True, it installs an version of the binary
        package into a root.

        @param repos: trovesource to search for and derive packages from
        @param cfg: configuration to use when deriving the package
        @type cfg: ConaryConfiguration object
        @param targetLabel: label to derive from
        @type targetLabel: versions.Label
        @param checkoutDir: directory to create the checkout in.  If None,
                             defaults to currentDir + packageName.
        @param extract: If True, creates a subdirectory of the checkout named
                         _ROOT_ with the contents of the binary of the derived
                         package.
        @param info: If true, only display the information about the shadow
                      that would be performed if the derive command were
                      completed.
        @param callback:
    """
    if callback is None:
        callback = DeriveCallback()
    troveName, versionSpec, flavor = conaryclient.cmdline.parseTroveSpec(
                                                                    troveSpec)
    result = repos.findTrove(cfg.buildLabel, (troveName, versionSpec, flavor),
                             cfg.flavor)
    # findTrove shouldn't return multiple items for one package anymore
    # when a flavor is specified.
    troveToDerive, = result
    # displaying output along the screen allows there to be a record
    # of what operations were performed.  Since this command is
    # an aggregate of several commands I think that is appropriate,
    # rather than simply using a progress callback.
    log.info('Shadowing %s=%s[%s] onto %s' % (troveToDerive[0],
                                             troveToDerive[1],
                                             troveToDerive[2],
                                             targetLabel))
    if info:
        cfg.interactive = False

    error = branch.branch(repos, cfg, str(targetLabel),
                  ['%s=%s[%s]' % troveToDerive],
                  makeShadow = True, sourceOnly = True, binaryOnly = False,
                  info = info)
    if info or error:
        return
    shadowedVersion = troveToDerive[1].createShadow(targetLabel)
    shadowedVersion = shadowedVersion.getSourceVersion(False)
    troveName = troveName.split(':')[0]

    checkoutDir = checkoutDir or troveName
    checkin.checkout(repos, cfg, checkoutDir,
                     ["%s=%s" % (troveName, shadowedVersion)],
                     callback=callback)
    os.chdir(checkoutDir)
    recipeName = troveName + '.recipe'
    shadowBranch = shadowedVersion.branch()

    log.info('Rewriting recipe file')
    className = ''.join([ x.capitalize() for x in troveName.split('-') ])
    derivedRecipe = """
class %(className)sRecipe(DerivedPackageRecipe):
    name = '%(name)s'
    version = '%(version)s'

    def setup(r):
        pass

""" % dict(className=className,
           name=troveName,
           version=shadowedVersion.trailingRevision().getVersion())
    open(recipeName, 'w').write(derivedRecipe)

    log.info('Removing extra files from checkout')
    conaryState = state.ConaryStateFromFile('CONARY', repos)
    sourceState = conaryState.getSourceState()

    for (pathId, path, fileId, version) in list(sourceState.iterFileList()):
        if path == recipeName:
            continue
        sourceState.removeFile(pathId)
        if util.exists(path):
            statInfo = os.lstat(path)
            try:
                if statInfo.st_mode & stat.S_IFDIR:
                    os.rmdir(path)
                else:
                    os.unlink(path)
            except OSError, e:
                log.warning("cannot remove %s: %s" % (path, e.strerror))
    conaryState.write('CONARY')

    if extract:
        extractDir = os.getcwd() + '/_ROOT_'
        log.info('extracting files from %s=%s[%s]' % (troveToDerive))
        cfg.root = os.path.abspath(extractDir)
        cfg.interactive = False
        updatecmd.doUpdate(cfg, troveSpec,
                           callback=callback, depCheck=False)
<|endoftext|>


<commit_before>#
# Copyright (c) 2004-2008 rPath, Inc.
#
# This program is distributed under the terms of the Common Public License,
# version 1.0. A copy of this license should have been distributed with this
# source file in a file called LICENSE. If it is not present, the license
# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the Common Public License for
# full details.
#

"""
Contains the functions which derive a package and commit the
resulting packages to the repository.
"""

import os
import shutil

from conary import checkin
from conary import conaryclient
from conary import errors
from conary import state
from conary import updatecmd
from conary.lib import log, util
from conary.versions import Label
class DeriveCallback(checkin.CheckinCallback):
    def setUpdateJob(self, *args, **kw):
        # stifle update announcement for extract
        pass

def derive(repos, cfg, targetLabel, troveToDerive, checkoutDir = None,
           extract = False, info = False, callback = None):
    """
        Creates a derived recipe. Note that is does not actually commit
        anything to the repository.

        Finally if extract = True, it installs an version of the binary
        package into a root.

        @param repos: trovesource to search for and derive packages from
        @param cfg: configuration to use when deriving the package
        @type cfg: ConaryConfiguration object
        @param targetLabel: label to derive from
        @type targetLabel: versions.Label
        @param troveToDerive the trove to derive from
        @type (n,v,f) or a troveSpec
        @param checkoutDir: directory to create the checkout in.  If None,
                             defaults to currentDir + packageName.
        @param extract: If True, creates a subdirectory of the checkout named
                         _ROOT_ with the contents of the binary of the derived
                         package.
        @param callback:
    """

    if callback is None:
        callback = DeriveCallback()
    if isinstance(troveToDerive,tuple):
        troveName, versionSpec, flavor = troveToDerive
        versionSpec = str(versionSpec)
        #flavor = str(flavor)
        troveSpec = conaryclient.cmdline.toTroveSpec(troveName,
                                                     versionSpec,
                                                     flavor)
    else:
        troveSpec = troveToDerive
        troveName, versionSpec, flavor = conaryclient.cmdline.parseTroveSpec(
            troveSpec)

    if isinstance(targetLabel,str):
        targetLabel = Label(targetLabel)

    nvfToDerive, = repos.findTrove(cfg.buildLabel, (troveName, versionSpec,
                                                        flavor), cfg.flavor)
    troveToDerive = repos.getTrove(*nvfToDerive)

    if ":" in troveName:
        raise errors.ParseError('Cannot derive individual components: %s' %
                                troveName)

    client = conaryclient.ConaryClient(cfg,repos=repos)
    laterShadows = client._checkForLaterShadows(targetLabel, [troveToDerive])
    if laterShadows:
        msg = []
        for n, v, f, shadowedVer in laterShadows:
            msg.append('Cannot derive from earlier version. You are trying to '
                       'derive from %s=%s[%s] but %s=%s[%s] is already '
                       'shadowed on this label.'
                       % (n, shadowedVer, f, n, v, f))
            raise errors.BranchError('\n\n'.join(msg))

    # displaying output along the screen allows there to be a record
    # of what operations were performed.  Since this command is
    # an aggregate of several commands I think that is appropriate,
    # rather than simply using a progress callback.
    log.info('Shadowing %s=%s[%s] onto %s' % (nvfToDerive[0],
                                              nvfToDerive[1],
                                              nvfToDerive[2],
                                              targetLabel))

    shadowedVersion = nvfToDerive[1].createShadow(targetLabel)
    shadowedVersion = shadowedVersion.getSourceVersion(False)
    troveName = troveName.split(':')[0]

    nvfs = list(troveToDerive.iterTroveList(strongRefs=True))
    trvs = repos.getTroves(nvfs,withFiles=False)
    hasCapsule = [ x for x in trvs if x.troveInfo.capsule.type() ]
    removeText = \
"""
        # This appliance uses PHP as a command interpreter but does
        # not include a web server, so remove the file that creates
        # a dependency on the web server
        r.Remove('/etc/httpd/conf.d/php.conf')
"""
    if hasCapsule:
        derivedRecipeType = 'DerivedCapsuleRecipe'
        removeText = ''
    else:
        derivedRecipeType = 'DerivedPackageRecipe'
    shadowBranch = shadowedVersion.branch()

    checkoutDir = checkoutDir or troveName
    if os.path.exists(checkoutDir):
        raise errors.CvcError("Directory '%s' already exists" % checkoutDir)
    os.mkdir(checkoutDir)

    log.info('Writing recipe file')
    recipeName = troveName + '.recipe'
    className = util.convertPackageNameToClassName(troveName)

    derivedRecipe = """
class %(className)sRecipe(%(recipeBaseClass)s):
    name = '%(name)s'
    version = '%(version)s'

    def setup(r):
        '''
        In this recipe, you can make modifications to the package.

        Examples:

        # This appliance has high-memory-use PHP scripts
        r.Replace('memory_limit = 8M', 'memory_limit = 32M', '/etc/php.ini')
%(removeText)s
        # This appliance requires that a few binaries be replaced
        # with binaries built from a custom archive that includes
        # a Makefile that honors the DESTDIR variable for its
        # install target.
        r.addArchive('foo.tar.gz')
        r.Make()
        r.MakeInstall()

        # This appliance requires an extra configuration file
        r.Create('/etc/myconfigfile', contents='some data')
        '''
""" % dict(className=className,
           name=troveName,
           version=shadowedVersion.trailingRevision().getVersion(),
           recipeBaseClass=derivedRecipeType,
           removeText=removeText)
    open(os.sep.join((checkoutDir,recipeName)), 'w').write(derivedRecipe)

    oldBldLabel = cfg.buildLabel
    cfg.buildLabel = targetLabel
    checkin.newTrove(repos,cfg,troveName,checkoutDir)
    cfg.buildLabel = oldBldLabel
    os.chdir(checkoutDir)

    conaryState = state.ConaryStateFromFile('CONARY')
    shadowedVersion.resetTimeStamps()
    sourceState = conaryState.getSourceState()
    sourceState.changeVersion(shadowedVersion)
    sourceState.changeBranch(shadowBranch)
    conaryState.write('CONARY')

    if extract:
        extractDir = os.path.join(os.getcwd(), '_ROOT_')
        log.info('extracting files from %s=%s[%s]' % (nvfToDerive))
        cfg.root = os.path.abspath(extractDir)
        cfg.interactive = False
        updatecmd.doUpdate(cfg, troveSpec,
                           callback=callback, depCheck=False)
        secondDir = os.path.join(os.getcwd(), '_OLD_ROOT_')
        shutil.copytree(extractDir, secondDir)

<commit_msg>derive function should restore the cwd before exiting<commit_after>#
# Copyright (c) 2004-2008 rPath, Inc.
#
# This program is distributed under the terms of the Common Public License,
# version 1.0. A copy of this license should have been distributed with this
# source file in a file called LICENSE. If it is not present, the license
# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the Common Public License for
# full details.
#

"""
Contains the functions which derive a package and commit the
resulting packages to the repository.
"""

import os
import shutil

from conary import checkin
from conary import conaryclient
from conary import errors
from conary import state
from conary import updatecmd
from conary.lib import log, util
from conary.versions import Label
class DeriveCallback(checkin.CheckinCallback):
    def setUpdateJob(self, *args, **kw):
        # stifle update announcement for extract
        pass

def derive(repos, cfg, targetLabel, troveToDerive, checkoutDir = None,
           extract = False, info = False, callback = None):
    """
        Creates a derived recipe. Note that is does not actually commit
        anything to the repository.

        Finally if extract = True, it installs an version of the binary
        package into a root.

        @param repos: trovesource to search for and derive packages from
        @param cfg: configuration to use when deriving the package
        @type cfg: ConaryConfiguration object
        @param targetLabel: label to derive from
        @type targetLabel: versions.Label
        @param troveToDerive the trove to derive from
        @type (n,v,f) or a troveSpec
        @param checkoutDir: directory to create the checkout in.  If None,
                             defaults to currentDir + packageName.
        @param extract: If True, creates a subdirectory of the checkout named
                         _ROOT_ with the contents of the binary of the derived
                         package.
        @param callback:
    """

    if callback is None:
        callback = DeriveCallback()
    if isinstance(troveToDerive,tuple):
        troveName, versionSpec, flavor = troveToDerive
        versionSpec = str(versionSpec)
        #flavor = str(flavor)
        troveSpec = conaryclient.cmdline.toTroveSpec(troveName,
                                                     versionSpec,
                                                     flavor)
    else:
        troveSpec = troveToDerive
        troveName, versionSpec, flavor = conaryclient.cmdline.parseTroveSpec(
            troveSpec)

    if isinstance(targetLabel,str):
        targetLabel = Label(targetLabel)

    nvfToDerive, = repos.findTrove(cfg.buildLabel, (troveName, versionSpec,
                                                        flavor), cfg.flavor)
    troveToDerive = repos.getTrove(*nvfToDerive)

    if ":" in troveName:
        raise errors.ParseError('Cannot derive individual components: %s' %
                                troveName)

    client = conaryclient.ConaryClient(cfg,repos=repos)
    laterShadows = client._checkForLaterShadows(targetLabel, [troveToDerive])
    if laterShadows:
        msg = []
        for n, v, f, shadowedVer in laterShadows:
            msg.append('Cannot derive from earlier version. You are trying to '
                       'derive from %s=%s[%s] but %s=%s[%s] is already '
                       'shadowed on this label.'
                       % (n, shadowedVer, f, n, v, f))
            raise errors.BranchError('\n\n'.join(msg))

    # displaying output along the screen allows there to be a record
    # of what operations were performed.  Since this command is
    # an aggregate of several commands I think that is appropriate,
    # rather than simply using a progress callback.
    log.info('Shadowing %s=%s[%s] onto %s' % (nvfToDerive[0],
                                              nvfToDerive[1],
                                              nvfToDerive[2],
                                              targetLabel))

    shadowedVersion = nvfToDerive[1].createShadow(targetLabel)
    shadowedVersion = shadowedVersion.getSourceVersion(False)
    troveName = troveName.split(':')[0]

    nvfs = list(troveToDerive.iterTroveList(strongRefs=True))
    trvs = repos.getTroves(nvfs,withFiles=False)
    hasCapsule = [ x for x in trvs if x.troveInfo.capsule.type() ]
    removeText = \
"""
        # This appliance uses PHP as a command interpreter but does
        # not include a web server, so remove the file that creates
        # a dependency on the web server
        r.Remove('/etc/httpd/conf.d/php.conf')
"""
    if hasCapsule:
        derivedRecipeType = 'DerivedCapsuleRecipe'
        removeText = ''
    else:
        derivedRecipeType = 'DerivedPackageRecipe'
    shadowBranch = shadowedVersion.branch()

    checkoutDir = checkoutDir or troveName
    if os.path.exists(checkoutDir):
        raise errors.CvcError("Directory '%s' already exists" % checkoutDir)
    os.mkdir(checkoutDir)

    log.info('Writing recipe file')
    recipeName = troveName + '.recipe'
    className = util.convertPackageNameToClassName(troveName)

    derivedRecipe = """
class %(className)sRecipe(%(recipeBaseClass)s):
    name = '%(name)s'
    version = '%(version)s'

    def setup(r):
        '''
        In this recipe, you can make modifications to the package.

        Examples:

        # This appliance has high-memory-use PHP scripts
        r.Replace('memory_limit = 8M', 'memory_limit = 32M', '/etc/php.ini')
%(removeText)s
        # This appliance requires that a few binaries be replaced
        # with binaries built from a custom archive that includes
        # a Makefile that honors the DESTDIR variable for its
        # install target.
        r.addArchive('foo.tar.gz')
        r.Make()
        r.MakeInstall()

        # This appliance requires an extra configuration file
        r.Create('/etc/myconfigfile', contents='some data')
        '''
""" % dict(className=className,
           name=troveName,
           version=shadowedVersion.trailingRevision().getVersion(),
           recipeBaseClass=derivedRecipeType,
           removeText=removeText)
    open(os.sep.join((checkoutDir,recipeName)), 'w').write(derivedRecipe)

    oldBldLabel = cfg.buildLabel
    cfg.buildLabel = targetLabel
    checkin.newTrove(repos,cfg,troveName,checkoutDir)
    cfg.buildLabel = oldBldLabel
    oldcwd = os.getcwd()
    os.chdir(checkoutDir)

    conaryState = state.ConaryStateFromFile('CONARY')
    shadowedVersion.resetTimeStamps()
    sourceState = conaryState.getSourceState()
    sourceState.changeVersion(shadowedVersion)
    sourceState.changeBranch(shadowBranch)
    conaryState.write('CONARY')

    if extract:
        extractDir = os.path.join(os.getcwd(), '_ROOT_')
        log.info('extracting files from %s=%s[%s]' % (nvfToDerive))
        cfg.root = os.path.abspath(extractDir)
        cfg.interactive = False
        updatecmd.doUpdate(cfg, troveSpec,
                           callback=callback, depCheck=False)
        secondDir = os.path.join(os.getcwd(), '_OLD_ROOT_')
        shutil.copytree(extractDir, secondDir)

    os.chdir(oldcwd)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
Execute overstate functions
'''

# Import salt libs
import salt.overstate
import salt.output

def over(env='base', os_fn=None):
    '''
    Execute an overstate sequence to orchestrate the executing of states
    over a group of systems

    CLI Examples:

    .. code-block:: bash

        salt-run state.over base /path/to/myoverstate.sls
    '''
    stage_num = 0
    overstate = salt.overstate.OverState(__opts__, env, os_fn)
    for stage in overstate.stages_iter():
        if isinstance(stage, dict):
            # This is highstate data
            print('Stage execution results:')
            for key, val in stage.items():
                if '_|-' in key:
                    salt.output.display_output(
                            {'error': {key: val}},
                            'highstate',
                            opts=__opts__)
                else:
                    salt.output.display_output(
                            {key: val},
                            'highstate',
                            opts=__opts__)
        elif isinstance(stage, list):
            # This is a stage
            if stage_num == 0:
                print('Executing the following Over State:')
            else:
                print('Executed Stage:')
            salt.output.display_output(stage, 'overstatestage', opts=__opts__)
            stage_num += 1
    return overstate.over_run

def sls(mods, env='base', test=None, exclude=None):
    '''
    Execute a state run from the master, used as a powerful orchestration
    system.

    CLI Examples:

    .. code-block:: bash

        salt-run state.sls webserver
        salt-run state.sls webserver env=dev test=True
    '''
    __opts__['file_client'] = 'local'
    minion = salt.minion.MasterMinion(__opts__)
    running = minion.functions['state.sls'](mods, env, test, exclude)
    ret = {minion.opts['id']: running}
    salt.output.display_output(ret, 'highstate', opts=__opts__)
    return ret

def show_stages(env='base', os_fn=None):
    '''
    Display the stage data to be executed

    CLI Examples:

    .. code-block:: bash

        salt-run state.show_stages
        salt-run state.show_stages env=dev /root/overstate.sls
    '''
    overstate = salt.overstate.OverState(__opts__, env, os_fn)
    salt.output.display_output(
            overstate.over,
            'overstatestage',
            opts=__opts__)
    return overstate.over
<commit_msg>Deprecate `env` usage in favor of `saltenv`.<commit_after># -*- coding: utf-8 -*-
'''
Execute overstate functions
'''

# Import salt libs
import salt.overstate
import salt.output

def over(saltenv='base', os_fn=None):
    '''
    Execute an overstate sequence to orchestrate the executing of states
    over a group of systems

    CLI Examples:

    .. code-block:: bash

        salt-run state.over base /path/to/myoverstate.sls
    '''
    stage_num = 0
    overstate = salt.overstate.OverState(__opts__, saltenv, os_fn)
    for stage in overstate.stages_iter():
        if isinstance(stage, dict):
            # This is highstate data
            print('Stage execution results:')
            for key, val in stage.items():
                if '_|-' in key:
                    salt.output.display_output(
                            {'error': {key: val}},
                            'highstate',
                            opts=__opts__)
                else:
                    salt.output.display_output(
                            {key: val},
                            'highstate',
                            opts=__opts__)
        elif isinstance(stage, list):
            # This is a stage
            if stage_num == 0:
                print('Executing the following Over State:')
            else:
                print('Executed Stage:')
            salt.output.display_output(stage, 'overstatestage', opts=__opts__)
            stage_num += 1
    return overstate.over_run

def sls(mods, saltenv='base', test=None, exclude=None):
    '''
    Execute a state run from the master, used as a powerful orchestration
    system.

    CLI Examples:

    .. code-block:: bash

        salt-run state.sls webserver
        salt-run state.sls webserver saltenv=dev test=True
    '''
    __opts__['file_client'] = 'local'
    minion = salt.minion.MasterMinion(__opts__)
    running = minion.functions['state.sls'](mods, saltenv, test, exclude)
    ret = {minion.opts['id']: running}
    salt.output.display_output(ret, 'highstate', opts=__opts__)
    return ret

def show_stages(saltenv='base', os_fn=None):
    '''
    Display the stage data to be executed

    CLI Examples:

    .. code-block:: bash

        salt-run state.show_stages
        salt-run state.show_stages saltenv=dev /root/overstate.sls
    '''
    overstate = salt.overstate.OverState(__opts__, saltenv, os_fn)
    salt.output.display_output(
            overstate.over,
            'overstatestage',
            opts=__opts__)
    return overstate.over
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
Configuration management using Augeas
=====================================

.. versionadded:: 0.17.0

This state requires the ``augeas`` Python module.

.. _Augeas: http://augeas.net/

Augeas_ can be used to manage configuration files.

.. warning::

    Minimal installations of Debian and Ubuntu have been seen to have packaging
    bugs with python-augeas, causing the augeas module to fail to import. If
    the minion has the augeas module installed, and the state fails with a
    comment saying that the state is unavailable, first restart the salt-minion
    service. If the problem persists past that, the following command can be
    run from the master to determine what is causing the import to fail:

    .. code-block:: bash

        salt minion-id cmd.run 'python -c "from augeas import Augeas"'

    For affected Debian/Ubuntu hosts, installing ``libpython2.7`` has been
    known to resolve the issue.

'''

# Import python libs
import re
import os.path
import difflib

def __virtual__():
    return 'augeas' if 'augeas.execute' in __salt__ else False

def change(name, context=None, changes=None, lens=None, **kwargs):
    '''
    .. versionadded:: 2014.1.6
    This state replaces :py:func:`~salt.states.augeas.setvalue`.

    Issue changes to Augeas, optionally for a specific context, with a
    specific lens.

    name
        State name

    context
        The context to use. Set this to a file path, prefixed by ``/files``, to
        avoid redundancy, e.g.:

        .. code-block:: yaml

            redis-conf:
              augeas.change:
                - context: /files/etc/redis/redis.conf
                - changes:
                  - set bind 0.0.0.0
                  - set maxmemory 1G

    changes
        List of changes that are issued to Augeas. Available commands are
        ``set``, ``mv``/``move``, ``ins``/``insert``, and ``rm``/``remove``.

    lens
        The lens to use, needs to be suffixed with `.lns`, e.g.: `Nginx.lns`. See
        the `list of stock lenses <http://augeas.net/stock_lenses.html>`_
        shipped with Augeas.

    Usage examples:

    Set the ``bind`` parameter in ``/etc/redis/redis.conf``:

    .. code-block:: yaml

        redis-conf:
          augeas.change:
            - changes:
              - set /files/etc/redis/redis.conf/bind 0.0.0.0

    .. note::

        Use the ``context`` parameter to specify the file you want to
        manipulate. This way you don't have to include this in the changes
        every time:

        .. code-block:: yaml

            redis-conf:
              augeas.change:
                - context: /files/etc/redis/redis.conf
                - changes:
                  - set bind 0.0.0.0
                  - set databases 4
                  - set maxmemory 1G

    Augeas is aware of a lot of common configuration files and their syntax.
    It knows the difference between for example ini and yaml files, but also
    files with very specific syntax, like the hosts file. This is done with
    *lenses*, which provide mappings between the Augeas tree and the file.

    There are many `preconfigured lenses`_ that come with Augeas by default,
    and they specify the common locations for configuration files. So most
    of the time Augeas will know how to manipulate a file. In the event that
    you need to manipulate a file that Augeas doesn't know about, you can
    specify the lens to use like this:

    .. code-block:: yaml

        redis-conf:
          augeas.change:
            - lens: redis
            - context: /files/etc/redis/redis.conf
            - changes:
              - set bind 0.0.0.0

    .. note::

        Even though Augeas knows that ``/etc/redis/redis.conf`` is a Redis
        configuration file and knows how to parse it, it is recommended to
        specify the lens anyway. This is because by default, Augeas loads all
        known lenses and their associated file paths. All these files are
        parsed when Augeas is loaded, which can take some time. When specifying
        a lens, Augeas is loaded with only that lens, which speeds things up
        quite a bit.

    .. _preconfigured lenses: http://augeas.net/stock_lenses.html

    A more complex example, this adds an entry to the services file for Zabbix,
    and removes an obsolete service:

    .. code-block:: yaml

        zabbix-service:
          augeas.change:
            - lens: services
            - context: /files/etc/services
            - changes:
              - ins service-name after service-name[last()]
              - set service-name[last()] zabbix-agent
              - set service-name[. = 'zabbix-agent']/#comment "Zabbix Agent service"
              - set service-name[. = 'zabbix-agent']/port 10050
              - set service-name[. = 'zabbix-agent']/protocol tcp
              - rm service-name[. = 'im-obsolete']
            - unless: grep "zabbix-agent" /etc/services

    .. warning::

        Don't forget the ``unless`` here, otherwise a new entry will be added
        every time this state is run.

    '''
    ret = {'name': name, 'result': False, 'comment': '', 'changes': {}}

    if not changes or not isinstance(changes, list):
        ret['comment'] = '\'changes\' must be specified as a list'
        return ret

    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'Executing commands'
        if context:
            ret['comment'] += ' in file "{1}"'.format(context)
        ret['comment'] += "\n".join(changes)
        return ret

    old_file = []
    if context:
        filename = re.sub('^/files|/$', '', context)
        if os.path.isfile(filename):
            file_ = open(filename, 'r')
            old_file = file_.readlines()
            file_.close()

    result = __salt__['augeas.execute'](context=context, lens=lens, commands=changes)
    ret['result'] = result['retval']

    if ret['result'] is False:
        ret['comment'] = 'Error: {0}'.format(result['error'])
        return ret

    if old_file:
        file_ = open(filename, 'r')
        diff = ''.join(difflib.unified_diff(old_file, file_.readlines(), n=0))
        file_.close()

        if diff:
            ret['comment'] = 'Changes have been saved'
            ret['changes'] = diff
        else:
            ret['comment'] = 'No changes made'

    else:
        ret['comment'] = 'Changes have been saved'
        ret['changes'] = changes

    return ret

def setvalue(name, prefix=None, changes=None, **kwargs):
    '''
    .. deprecated:: 2014.1.6
       Use :py:func:`~salt.states.augeas.change` instead.

    Set a value for a specific augeas path
    '''
    ret = {'name': name, 'result': False, 'comment': '', 'changes': {}}

    args = []
    if not changes:
        ret['comment'] = '\'changes\' must be specified'
        return ret
    else:
        if not isinstance(changes, list):
            ret['comment'] = '\'changes\' must be formatted as a list'
            return ret
        for change_ in changes:
            if not isinstance(change_, dict) or len(change_) > 1:
                ret['comment'] = 'Invalidly-formatted change'
                return ret
            key = next(iter(change_))
            args.extend([key, change_[key]])

    if prefix is not None:
        args.insert(0, 'prefix={0}'.format(prefix))

    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'Calling setvalue with {0}'.format(args)
        return ret

    call = __salt__['augeas.setvalue'](*args)

    ret['result'] = call['retval']

    if ret['result'] is False:
        ret['comment'] = 'Error: {0}'.format(call['error'])
        return ret

    ret['comment'] = 'Success'
    for change_ in changes:
        ret['changes'].update(change_)
    return ret
<commit_msg>Fix sphinx build error<commit_after># -*- coding: utf-8 -*-
'''
Configuration management using Augeas
=====================================

.. versionadded:: 0.17.0

This state requires the ``augeas`` Python module.

.. _Augeas: http://augeas.net/

Augeas_ can be used to manage configuration files.

.. warning::

    Minimal installations of Debian and Ubuntu have been seen to have packaging
    bugs with python-augeas, causing the augeas module to fail to import. If
    the minion has the augeas module installed, and the state fails with a
    comment saying that the state is unavailable, first restart the salt-minion
    service. If the problem persists past that, the following command can be
    run from the master to determine what is causing the import to fail:

    .. code-block:: bash

        salt minion-id cmd.run 'python -c "from augeas import Augeas"'

    For affected Debian/Ubuntu hosts, installing ``libpython2.7`` has been
    known to resolve the issue.

'''

# Import python libs
import re
import os.path
import difflib

def __virtual__():
    return 'augeas' if 'augeas.execute' in __salt__ else False

def change(name, context=None, changes=None, lens=None, **kwargs):
    '''
    .. versionadded:: 2014.1.6

    This state replaces :py:func:`~salt.states.augeas.setvalue`.

    Issue changes to Augeas, optionally for a specific context, with a
    specific lens.

    name
        State name

    context
        The context to use. Set this to a file path, prefixed by ``/files``, to
        avoid redundancy, e.g.:

        .. code-block:: yaml

            redis-conf:
              augeas.change:
                - context: /files/etc/redis/redis.conf
                - changes:
                  - set bind 0.0.0.0
                  - set maxmemory 1G

    changes
        List of changes that are issued to Augeas. Available commands are
        ``set``, ``mv``/``move``, ``ins``/``insert``, and ``rm``/``remove``.

    lens
        The lens to use, needs to be suffixed with `.lns`, e.g.: `Nginx.lns`. See
        the `list of stock lenses <http://augeas.net/stock_lenses.html>`_
        shipped with Augeas.

    Usage examples:

    Set the ``bind`` parameter in ``/etc/redis/redis.conf``:

    .. code-block:: yaml

        redis-conf:
          augeas.change:
            - changes:
              - set /files/etc/redis/redis.conf/bind 0.0.0.0

    .. note::

        Use the ``context`` parameter to specify the file you want to
        manipulate. This way you don't have to include this in the changes
        every time:

        .. code-block:: yaml

            redis-conf:
              augeas.change:
                - context: /files/etc/redis/redis.conf
                - changes:
                  - set bind 0.0.0.0
                  - set databases 4
                  - set maxmemory 1G

    Augeas is aware of a lot of common configuration files and their syntax.
    It knows the difference between for example ini and yaml files, but also
    files with very specific syntax, like the hosts file. This is done with
    *lenses*, which provide mappings between the Augeas tree and the file.

    There are many `preconfigured lenses`_ that come with Augeas by default,
    and they specify the common locations for configuration files. So most
    of the time Augeas will know how to manipulate a file. In the event that
    you need to manipulate a file that Augeas doesn't know about, you can
    specify the lens to use like this:

    .. code-block:: yaml

        redis-conf:
          augeas.change:
            - lens: redis
            - context: /files/etc/redis/redis.conf
            - changes:
              - set bind 0.0.0.0

    .. note::

        Even though Augeas knows that ``/etc/redis/redis.conf`` is a Redis
        configuration file and knows how to parse it, it is recommended to
        specify the lens anyway. This is because by default, Augeas loads all
        known lenses and their associated file paths. All these files are
        parsed when Augeas is loaded, which can take some time. When specifying
        a lens, Augeas is loaded with only that lens, which speeds things up
        quite a bit.

    .. _preconfigured lenses: http://augeas.net/stock_lenses.html

    A more complex example, this adds an entry to the services file for Zabbix,
    and removes an obsolete service:

    .. code-block:: yaml

        zabbix-service:
          augeas.change:
            - lens: services
            - context: /files/etc/services
            - changes:
              - ins service-name after service-name[last()]
              - set service-name[last()] zabbix-agent
              - set service-name[. = 'zabbix-agent']/#comment "Zabbix Agent service"
              - set service-name[. = 'zabbix-agent']/port 10050
              - set service-name[. = 'zabbix-agent']/protocol tcp
              - rm service-name[. = 'im-obsolete']
            - unless: grep "zabbix-agent" /etc/services

    .. warning::

        Don't forget the ``unless`` here, otherwise a new entry will be added
        every time this state is run.

    '''
    ret = {'name': name, 'result': False, 'comment': '', 'changes': {}}

    if not changes or not isinstance(changes, list):
        ret['comment'] = '\'changes\' must be specified as a list'
        return ret

    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'Executing commands'
        if context:
            ret['comment'] += ' in file "{1}"'.format(context)
        ret['comment'] += "\n".join(changes)
        return ret

    old_file = []
    if context:
        filename = re.sub('^/files|/$', '', context)
        if os.path.isfile(filename):
            file_ = open(filename, 'r')
            old_file = file_.readlines()
            file_.close()

    result = __salt__['augeas.execute'](context=context, lens=lens, commands=changes)
    ret['result'] = result['retval']

    if ret['result'] is False:
        ret['comment'] = 'Error: {0}'.format(result['error'])
        return ret

    if old_file:
        file_ = open(filename, 'r')
        diff = ''.join(difflib.unified_diff(old_file, file_.readlines(), n=0))
        file_.close()

        if diff:
            ret['comment'] = 'Changes have been saved'
            ret['changes'] = diff
        else:
            ret['comment'] = 'No changes made'

    else:
        ret['comment'] = 'Changes have been saved'
        ret['changes'] = changes

    return ret

def setvalue(name, prefix=None, changes=None, **kwargs):
    '''
    .. deprecated:: 2014.1.6
       Use :py:func:`~salt.states.augeas.change` instead.

    Set a value for a specific augeas path
    '''
    ret = {'name': name, 'result': False, 'comment': '', 'changes': {}}

    args = []
    if not changes:
        ret['comment'] = '\'changes\' must be specified'
        return ret
    else:
        if not isinstance(changes, list):
            ret['comment'] = '\'changes\' must be formatted as a list'
            return ret
        for change_ in changes:
            if not isinstance(change_, dict) or len(change_) > 1:
                ret['comment'] = 'Invalidly-formatted change'
                return ret
            key = next(iter(change_))
            args.extend([key, change_[key]])

    if prefix is not None:
        args.insert(0, 'prefix={0}'.format(prefix))

    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'Calling setvalue with {0}'.format(args)
        return ret

    call = __salt__['augeas.setvalue'](*args)

    ret['result'] = call['retval']

    if ret['result'] is False:
        ret['comment'] = 'Error: {0}'.format(call['error'])
        return ret

    ret['comment'] = 'Success'
    for change_ in changes:
        ret['changes'].update(change_)
    return ret
<|endoftext|>


<commit_before>from __future__ import print_function, division, absolute_import

import os
import sys
from os.path import isdir, isfile, join

from conda_build import config
from conda_build import environ
from conda_build import source
from conda_build.utils import _check_call
from conda_build.scripts import BAT_PROXY

from conda.compat import iteritems

try:
    import psutil
except ImportError:
    psutil = None

assert sys.platform == 'win32'

def fix_staged_scripts():
    """
    Fixes scripts which have been installed unix-style to have a .bat
    helper
    """
    scripts_dir = join(config.build_prefix, 'Scripts')
    if not isdir(scripts_dir):
        return
    for fn in os.listdir(scripts_dir):
        # process all the extensionless files
        if not isfile(join(scripts_dir, fn)) or '.' in fn:
            continue

        with open(join(scripts_dir, fn)) as f:
            line = f.readline().lower()
            # If it's a #!python script
            if not (line.startswith('#!') and 'python' in line.lower()):
                continue
            print('Adjusting unix-style #! script %s, '
                  'and adding a .bat file for it' % fn)
            # copy it with a .py extension (skipping that first #! line)
            with open(join(scripts_dir, fn + '-script.py'), 'w') as fo:
                fo.write(f.read())
            # now create the batch file
            with open(join(scripts_dir, fn + '.bat'), 'w') as fo:
                fo.write(BAT_PROXY)

        # remove the original script
        os.remove(join(scripts_dir, fn))

def msvc_env_cmd():
    if config.PY3K:
        vcvarsall = (r'C:\Program Files (x86)\Microsoft Visual Studio 10.0'
                     r'\VC\vcvarsall.bat')
    else:
        vcvarsall = (r'C:\Program Files (x86)\Microsoft Visual Studio 9.0'
                     r'\VC\vcvarsall.bat')

    if not isfile(vcvarsall):
        print("Warning: Couldn't find Visual Studio: %r" % vcvarsall)
        return ''

    return '''\
call "%s" %s
''' % (vcvarsall, {32: 'x86', 64: 'amd64'}[config.ARCH])

def kill_processes():
    if psutil is None:
        return
    for n in psutil.get_pid_list():
        try:
            p = psutil.Process(n)
            if p.name.lower() == 'msbuild.exe':
                print('Terminating:', p.name)
                p.terminate()
        except:
            continue

def build(m):
    env = dict(os.environ)
    env.update(environ.get_dict(m))

    for name in 'BIN', 'INC', 'LIB':
        path = env['LIBRARY_' + name]
        if not isdir(path):
            os.makedirs(path)

    src_dir = source.get_dir()
    bld_bat = join(m.path, 'bld.bat')
    with open(bld_bat) as fi:
        data = fi.read()
    with open(join(src_dir, 'bld.bat'), 'w') as fo:
        fo.write(msvc_env_cmd())
        # more debuggable with echo on
        fo.write('@echo on\n')
        for kv in iteritems(env):
            fo.write('set %s=%s\n' % kv)
        fo.write("REM ===== end generated header =====\n")
        fo.write(data)

    cmd = [os.environ['COMSPEC'], '/c', 'bld.bat']
    _check_call(cmd, cwd=src_dir)
    kill_processes()
    fix_staged_scripts()
<commit_msg>fix issue #38<commit_after>from __future__ import print_function, division, absolute_import

import os
import sys
from os.path import isdir, isfile, join

from conda_build import config
from conda_build import environ
from conda_build import source
from conda_build.utils import _check_call
from conda_build.scripts import BAT_PROXY

import conda.config as cc
from conda.compat import iteritems

try:
    import psutil
except ImportError:
    psutil = None

assert sys.platform == 'win32'

def fix_staged_scripts():
    """
    Fixes scripts which have been installed unix-style to have a .bat
    helper
    """
    scripts_dir = join(config.build_prefix, 'Scripts')
    if not isdir(scripts_dir):
        return
    for fn in os.listdir(scripts_dir):
        # process all the extensionless files
        if not isfile(join(scripts_dir, fn)) or '.' in fn:
            continue

        with open(join(scripts_dir, fn)) as f:
            line = f.readline().lower()
            # If it's a #!python script
            if not (line.startswith('#!') and 'python' in line.lower()):
                continue
            print('Adjusting unix-style #! script %s, '
                  'and adding a .bat file for it' % fn)
            # copy it with a .py extension (skipping that first #! line)
            with open(join(scripts_dir, fn + '-script.py'), 'w') as fo:
                fo.write(f.read())
            # now create the batch file
            with open(join(scripts_dir, fn + '.bat'), 'w') as fo:
                fo.write(BAT_PROXY)

        # remove the original script
        os.remove(join(scripts_dir, fn))

def msvc_env_cmd():
    if config.PY3K:
        vcvarsall = (r'C:\Program Files (x86)\Microsoft Visual Studio 10.0'
                     r'\VC\vcvarsall.bat')
    else:
        vcvarsall = (r'C:\Program Files (x86)\Microsoft Visual Studio 9.0'
                     r'\VC\vcvarsall.bat')

    if not isfile(vcvarsall):
        print("Warning: Couldn't find Visual Studio: %r" % vcvarsall)
        return ''

    return '''\
call "%s" %s
''' % (vcvarsall, {32: 'x86', 64: 'amd64'}[cc.bits])

def kill_processes():
    if psutil is None:
        return
    for n in psutil.get_pid_list():
        try:
            p = psutil.Process(n)
            if p.name.lower() == 'msbuild.exe':
                print('Terminating:', p.name)
                p.terminate()
        except:
            continue

def build(m):
    env = dict(os.environ)
    env.update(environ.get_dict(m))

    for name in 'BIN', 'INC', 'LIB':
        path = env['LIBRARY_' + name]
        if not isdir(path):
            os.makedirs(path)

    src_dir = source.get_dir()
    bld_bat = join(m.path, 'bld.bat')
    with open(bld_bat) as fi:
        data = fi.read()
    with open(join(src_dir, 'bld.bat'), 'w') as fo:
        fo.write(msvc_env_cmd())
        # more debuggable with echo on
        fo.write('@echo on\n')
        for kv in iteritems(env):
            fo.write('set %s=%s\n' % kv)
        fo.write("REM ===== end generated header =====\n")
        fo.write(data)

    cmd = [os.environ['COMSPEC'], '/c', 'bld.bat']
    _check_call(cmd, cwd=src_dir)
    kill_processes()
    fix_staged_scripts()
<|endoftext|>