Example #1
0
def resolve_program(executable):
    """
    Expand the name of a program into an absolute pathname.

    :param executable: The name of a program (a string).
    :returns: The absolute pathname of the program (a string).
    :raises: :exc:`.MissingProgramError` when the program doesn't exist.

    An example:

    >>> extract_program('dropbox start')
    'dropbox'
    >>> resolve_program(extract_program('dropbox start'))
    '/usr/bin/dropbox'
    """
    # Check if the executable name contains no directory components.
    if os.path.basename(executable) == executable:
        # Transform the executable name into an absolute pathname.
        matching_programs = which(executable)
        logger.debug("Programs matching executable name: %s", matching_programs)
        if not matching_programs:
            raise MissingProgramError("Program not found on $PATH! (%s)" % executable)
        executable = matching_programs[0]
    else:
        # Make sure the executable exists and is in fact executable.
        logger.debug("Validating executable name: %s", executable)
        if not os.access(executable, os.X_OK):
            raise MissingProgramError("Program not found! (%s)" % executable)
    return executable
Example #2
0
def have_agent_program():
    """
    Check whether the ``gpg-agent`` program is installed.

    :returns: :data:`True` when the ``gpg-agent`` program is available on the
               ``$PATH``, :data:`False` otherwise.
    """
    return bool(which('gpg-agent'))
Example #3
0
 def test_process_from_path(self):
     """Test the :func:`proc.core.Process.from_path()` constructor."""
     process = Process.from_path('/proc/self')
     # The following tests verify properties based on information available
     # from the Python standard library.
     assert process.pid == os.getpid(), "Unexpected process ID!"
     assert process.ppid == os.getppid(), "Unexpected parent process ID!"
     assert process.pgrp == os.getpgrp(), "Unexpected process group ID!"
     assert process.user_ids.real == os.getuid(), "Unexpected real user ID!"
     assert process.group_ids.real == os.getgid(
     ), "Unexpected real group ID!"
     assert process.cwd == os.getcwd(), "Unexpected working directory!"
     # The following assertion may fail at some point, but I chose it above
     # using uid_to_name(os.getuid()) because the latter isn't testing
     # anything useful at all ...
     assert process.user == getpass.getuser(
     ), "Unexpected username based on real user ID!"
     # We really can't make much assumptions about the name of the real
     # group ID so we'll just check whether it's available.
     assert process.group, "Expected process to have real group ID with group name!"
     # The following tests are based on common sense, here's hoping they
     # don't bite me in the ass later on :-).
     assert process.state == 'R', "Unexpected process state!"
     assert process.runtime < 600, "Test process running for >= 10 minutes?!"
     assert process.rss > parse_size(
         '10 MB'), "Resident set size (RSS) less than 10 MB?!"
     assert process.vsize > process.rss, "Virtual memory usage less than its resident set size (RSS)?!"
     assert executable(process.cmdline[0]) or which(process.cmdline[0]), \
         "First token in process command line isn't executable?!"
     assert executable(
         process.exe
     ), "Process executable pathname (based on /proc/[pid]/stat) invalid?!"
     assert executable(
         process.exe_path
     ), "Process executable pathname (fall back option) invalid?!"
     if not (os.environ.get('TRAVIS') and process.exe_name == 'pypy'):
         # https://travis-ci.org/xolox/python-proc/jobs/395176218
         assert which(
             process.exe_name
         ), "Process executable base name (fall back option) not available on $PATH?!"
     assert process.is_alive, "The current process is not running?! :-P"
     # Python's standard library doesn't seem to expose process session IDs
     # so all I can test reliably is that the session ID is an integer...
     assert isinstance(process.session,
                       int), "Process session ID not available!"
def generate_screenshots():
    """Generate screenshots from shell scripts."""
    this_script = os.path.abspath(__file__)
    this_directory = os.path.dirname(this_script)
    repository = os.path.join(this_directory, os.pardir)
    examples_directory = os.path.join(repository, 'docs', 'examples')
    images_directory = os.path.join(repository, 'docs', 'images')
    for shell_script in sorted(glob.glob(os.path.join(examples_directory, '*.sh'))):
        basename, extension = os.path.splitext(os.path.basename(shell_script))
        image_file = os.path.join(images_directory, '%s.png' % basename)
        logger.info("Generating %s by running %s ..",
                    format_path(image_file),
                    format_path(shell_script))
        command_line = [sys.executable, __file__, shell_script]
        random_title = random_string(25)
        # Generate the urxvt command line.
        urxvt_command = [
            'urxvt',
            # Enforce a default geometry.
            '-geometry', '98x30',
            # Set the text and background color.
            '-fg', TEXT_COLOR,
            '-bg', BACKGROUND_COLOR,
            # Set the font name and pixel size.
            '-fn', 'xft:%s:pixelsize=%i' % (FONT_NAME, FONT_SIZE),
            # Set the window title.
            '-title', random_title,
            # Hide scrollbars.
            '+sb',
        ]
        if which('qtile-run'):
            # I've been using tiling window managers for years now, at the
            # moment 'qtile' is my window manager of choice. It requires the
            # following special handling to enable the 'urxvt' window to float,
            # which in turn enables it to respect the '--geometry' option.
            urxvt_command.insert(0, 'qtile-run')
            urxvt_command.insert(1, '-f')
        # Apply the Ubuntu color scheme to urxvt.
        for index, css_color in enumerate(EIGHT_COLOR_PALETTE):
            urxvt_command.extend(('--color%i' % index, css_color))
        # Add the command that should run inside the terminal.
        urxvt_command.extend(('-e', 'sh', '-c', 'setterm -cursor off; %s' % quote(command_line)))
        # Launch urxvt.
        execute(*urxvt_command, asynchronous=True)
        # Make sure we close the urxvt window.
        try:
            # Wait for urxvt to start up. If I were to improve this I could
            # instead wait for the creation of a file by interpret_script().
            time.sleep(10)
            # Take a screen shot of the window using ImageMagick.
            execute('import', '-window', random_title, image_file)
            # Auto-trim the screen shot, then give it a 5px border.
            execute('convert', image_file, '-trim',
                    '-bordercolor', BACKGROUND_COLOR,
                    '-border', '5', image_file)
        finally:
            execute('wmctrl', '-c', random_title)
Example #5
0
 def test_with_gpg_agent(self):
     """Test that ``with-gpg-agent`` works."""
     if not which('gpg-agent'):
         return self.skipTest("The gpg-agent program is not installed!")
     # Test that `with-gpg-agent -h' / `with-gpg-agent --help' works.
     self.assertRaises(SystemExit, with_gpg_agent, ['-h'])
     self.assertRaises(SystemExit, with_gpg_agent, ['--help'])
     # Test that invalid command line options raise an error.
     self.assertRaises(SystemExit, with_gpg_agent, ['--whatever'])
     # Test that command line options for verbosity control are accepted
     # and that the with-gpg-agent program runs successfully.
     with_gpg_agent(['-v', '--verbose', '-q', '--quiet', 'true'])
def find_program_file():
    """Find the absolute pathname of the `crypto-drive-manager` executable."""
    value = sys.argv[0]
    msg = "Failed to determine absolute pathname of program!"
    if not os.path.isabs(value):
        candidates = which(value)
        if not candidates:
            raise Exception(msg)
        value = candidates[0]
    if not os.access(value, os.X_OK):
        raise Exception(msg)
    return value
def setUpModule():
    """Create a fake ``notify-send`` program that will keep silent."""
    # Create a temporary directory where we can create a fake notify-send
    # program that is guaranteed to exist and will run successfully, but
    # without actually bothering the user with interactive notifications.
    directory = tempfile.mkdtemp(prefix='rsync-system-backup-',
                                 suffix='-fake-path')
    TEMPORARY_DIRECTORIES.append(directory)
    fake_program = os.path.join(directory, 'notify-send')
    candidates = which('true')
    os.symlink(candidates[0], fake_program)
    # Add the directory to the $PATH.
    path = get_search_path()
    path.insert(0, directory)
    os.environ['PATH'] = os.pathsep.join(path)
Example #8
0
def run_additions():
    """
    Allow local additions to the behavior of ``cron-graceful``.

    If a command with the name of :data:`ADDITIONS_SCRIPT_NAME` exists in the
    ``$PATH`` it will be executed directly after the cron daemon is paused by
    :func:`cron_graceful()`. This allows you to inject custom logic into the
    graceful shutdown process. If the command fails a warning will be logged
    but the ``cron-graceful`` program will continue.
    """
    matching_programs = which(ADDITIONS_SCRIPT_NAME)
    if matching_programs:
        logger.info("Running command %s ..", matching_programs[0])
        try:
            execute(matching_programs[0], shell=False)
        except ExternalCommandFailed as e:
            logger.warning("Command failed with exit status %i!", e.returncode)
Example #9
0
 def test_exe_name_fallback(self):
     """Test the fall back method of :attr:`proc.core.Process.exe_name`."""
     if os.getuid() == 0:
         # Given root privileges all /proc/[pid]/exe symbolic links can be
         # successfully resolved so we can't test the fall back method.
         return self.skipTest(
             "Fall back method of Process.exe_name is useless with root privileges!"
         )
     candidates = [
         p for p in find_processes() if p.exe_name and not p.exe_path
     ]
     logger.debug("Candidates for Process.exe_name fall back test:\n %s",
                  pformat(candidates))
     if not candidates:
         return self.skipTest(
             "No processes available on which Process.exe_name fall back can be tested!"
         )
     assert any(which(p.exe_name) for p in candidates), \
         "Fall back method of Process.exe_name reported executable base name not available on $PATH?!"
Example #10
0
    def exe_name(self):
        """
        The base name of the executable (a string).

        It can be tricky to reliably determine the name of the executable of an
        arbitrary process and this property tries to make it easier. Its value
        is based on the first of the following methods that works:

        1. If :attr:`exe_path` is available then the base name of this
           pathname is returned.

           - Pro: When the :attr:`exe_path` property is available it is
             fairly reliable.
           - Con: The :attr:`exe_path` property can be unavailable (refer to
             its documentation for details).

        2. If the first string in :attr:`cmdline` contains a name that is
           available on the executable search path (``$PATH``) then this name
           is returned.

           - Pro: As long as :attr:`cmdline` contains the name of an
             executable available on the ``$PATH`` this method works.
           - Con: This method can fail because a process has changed its own
             command line (after it was started).

        3. If both of the methods above fail :attr:`comm` is returned.

           - Pro: The :attr:`comm` field is always available.
           - Con: The :attr:`comm` field may be truncated.
        """
        if self.exe_path:
            return os.path.basename(self.exe_path)
        if self.cmdline:
            name = self.cmdline[0]
            if os.path.basename(name) == name and which(name):
                return name
        return self.comm
Example #11
0
def main():
    """Command line interface for the ``executor`` program."""
    # Enable logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    command_timeout = 0
    exclusive = False
    fudge_factor = 0
    lock_name = None
    lock_timeout = 0
    # Parse the command line options.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'eT:l:t:f:vqh', [
            'exclusive', 'lock-timeout=', 'lock-file=', 'timeout=',
            'fudge-factor=', 'verbose', 'quiet', 'help',
        ])
        for option, value in options:
            if option in ('-e', '--exclusive'):
                exclusive = True
            elif option in ('-T', '--lock-timeout'):
                lock_timeout = parse_timespan(value)
            elif option in ('-l', '--lock-file'):
                lock_name = value
            elif option in ('-t', '--timeout'):
                command_timeout = parse_timespan(value)
            elif option in ('-f', '--fudge-factor'):
                fudge_factor = parse_timespan(value)
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                sys.exit(0)
            else:
                assert False, "Unhandled option!"
        # Make sure the operator provided a program to execute.
        if not arguments:
            usage(__doc__)
            sys.exit(0)
        # Make sure the program actually exists.
        program_name = arguments[0]
        if not os.path.isfile(program_name):
            # Only search the $PATH if the given program name
            # doesn't already include one or more path segments.
            if program_name == os.path.basename(program_name):
                matching_programs = which(program_name)
                if matching_programs:
                    program_name = matching_programs[0]
        # The subprocess.Popen() call later on doesn't search the $PATH so we
        # make sure to give it the absolute pathname to the program.
        arguments[0] = program_name
    except Exception as e:
        warning("Failed to parse command line arguments: %s", e)
        sys.exit(1)
    # Apply the requested fudge factor.
    apply_fudge_factor(fudge_factor)
    # Run the requested command.
    try:
        if exclusive:
            # Select a default lock file name?
            if not lock_name:
                lock_name = os.path.basename(arguments[0])
                logger.debug("Using base name of command as lock file name (%s).", lock_name)
            lock_file = get_lock_path(lock_name)
            lock = InterProcessLock(path=lock_file, logger=logger)
            logger.debug("Trying to acquire exclusive lock: %s", lock_file)
            if lock.acquire(blocking=(lock_timeout > 0), max_delay=lock_timeout):
                logger.info("Successfully acquired exclusive lock: %s", lock_file)
                run_command(arguments, timeout=command_timeout)
            else:
                logger.error("Failed to acquire exclusive lock: %s", lock_file)
                sys.exit(1)
        else:
            run_command(arguments, timeout=command_timeout)
    except ExternalCommandFailed as e:
        logger.error("%s", e.error_message)
        sys.exit(e.command.returncode)
Example #12
0
def main():
    """Command line interface for the ``executor`` program."""
    # Enable logging to the terminal and system log.
    coloredlogs.install(syslog=True)
    # Command line option defaults.
    command_timeout = 0
    exclusive = False
    fudge_factor = 0
    lock_name = None
    lock_timeout = 0
    # Parse the command line options.
    try:
        options, arguments = getopt.getopt(sys.argv[1:], 'eT:l:t:f:vqh', [
            'exclusive', 'lock-timeout=', 'lock-file=', 'timeout=',
            'fudge-factor=', 'verbose', 'quiet', 'help',
        ])
        for option, value in options:
            if option in ('-e', '--exclusive'):
                exclusive = True
            elif option in ('-T', '--lock-timeout'):
                lock_timeout = parse_timespan(value)
            elif option in ('-l', '--lock-file'):
                lock_name = value
            elif option in ('-t', '--timeout'):
                command_timeout = parse_timespan(value)
            elif option in ('-f', '--fudge-factor'):
                fudge_factor = parse_timespan(value)
            elif option in ('-v', '--verbose'):
                coloredlogs.increase_verbosity()
            elif option in ('-q', '--quiet'):
                coloredlogs.decrease_verbosity()
            elif option in ('-h', '--help'):
                usage(__doc__)
                sys.exit(0)
            else:
                assert False, "Unhandled option!"
        # Make sure the operator provided a program to execute.
        if not arguments:
            usage(__doc__)
            sys.exit(0)
        # Make sure the program actually exists.
        program_name = arguments[0]
        if not os.path.isfile(program_name):
            # Only search the $PATH if the given program name
            # doesn't already include one or more path segments.
            if program_name == os.path.basename(program_name):
                matching_programs = which(program_name)
                if matching_programs:
                    program_name = matching_programs[0]
        # The subprocess.Popen() call later on doesn't search the $PATH so we
        # make sure to give it the absolute pathname to the program.
        arguments[0] = program_name
    except Exception as e:
        warning("Failed to parse command line arguments: %s", e)
        sys.exit(1)
    # Apply the requested fudge factor.
    apply_fudge_factor(fudge_factor)
    # Run the requested command.
    try:
        if exclusive:
            # Select a default lock file name?
            if not lock_name:
                lock_name = os.path.basename(arguments[0])
                logger.debug("Using base name of command as lock file name (%s).", lock_name)
            lock_file = get_lock_path(lock_name)
            lock = InterProcessLock(path=lock_file, logger=logger)
            logger.debug("Trying to acquire exclusive lock: %s", lock_file)
            if lock.acquire(blocking=(lock_timeout > 0), max_delay=lock_timeout):
                logger.info("Successfully acquired exclusive lock: %s", lock_file)
                run_command(arguments, timeout=command_timeout)
            else:
                logger.error("Failed to acquire exclusive lock: %s", lock_file)
                sys.exit(1)
        else:
            run_command(arguments, timeout=command_timeout)
    except ExternalCommandFailed as e:
        logger.error("%s", e.error_message)
        sys.exit(e.command.returncode)
Example #13
0
 def sshd_path(self):
     """The absolute pathname of :data:`SSHD_PROGRAM_NAME` (a string)."""
     executables = which(SSHD_PROGRAM_NAME)
     return executables[0] if executables else SSHD_PROGRAM_NAME
Example #14
0
# Author: Peter Odding <*****@*****.**>
# Last Change: November 11, 2015
# URL: https://github.com/paylogic/pip-accel

"""Introspection of the AppVeyor CI environment ..."""

# Standard library modules.
import os

# External dependencies.
from humanfriendly import concatenate

# Test dependencies.
from executor import ExternalCommandFailed, execute, get_search_path, which

print("FakeS3 executables:\n%r" % which('fakes3'))

for program in which('fakes3'):
    with open(program) as handle:
        contents = handle.read()
        delimiter = "-" * 40
        vertical_whitespace = "\n\n"
        padding = vertical_whitespace + delimiter + vertical_whitespace
        print(padding + ("%s:" % program) + padding + contents + padding)

for program in ['fakes3', 'fakes3.bat'] + which('fakes3'):
    try:
        execute(program, '--help')
    except ExternalCommandFailed:
        print("%s doesn't work?!" % program)
Example #15
0
#
# Author: Peter Odding <*****@*****.**>
# Last Change: November 11, 2015
# URL: https://github.com/paylogic/pip-accel
"""Introspection of the AppVeyor CI environment ..."""

# Standard library modules.
import os

# External dependencies.
from humanfriendly import concatenate

# Test dependencies.
from executor import ExternalCommandFailed, execute, get_search_path, which

print("FakeS3 executables:\n%r" % which('fakes3'))

for program in which('fakes3'):
    with open(program) as handle:
        contents = handle.read()
        delimiter = "-" * 40
        vertical_whitespace = "\n\n"
        padding = vertical_whitespace + delimiter + vertical_whitespace
        print(padding + ("%s:" % program) + padding + contents + padding)

for program in ['fakes3', 'fakes3.bat'] + which('fakes3'):
    try:
        execute(program, '--help')
    except ExternalCommandFailed:
        print("%s doesn't work?!" % program)
Example #16
0
 def test_get_gpg_variables(self):
     """Test that searching for gpg-agents works."""
     if not which('gpg-agent'):
         return self.skipTest("The gpg-agent program is not installed!")
     variables = get_gpg_variables()
     assert variables['GPG_AGENT_INFO']
Example #17
0
 def sshd_path(self):
     """The absolute pathname of :data:`SSHD_PROGRAM_NAME` (a string)."""
     executables = which(SSHD_PROGRAM_NAME)
     return executables[0] if executables else SSHD_PROGRAM_NAME
Example #18
0
 def test_program_searching(self):
     self.assertTrue(which('python'))
     self.assertFalse(which('a-program-name-that-no-one-would-ever-use'))