Source code for src.tools.commandline

"""A collection of tools for interacting with the command line.

Notes
-----
The contents of this module have not been tested in Windows.
"""
import subprocess
import sys
import os
from src.tools import path_tools as pt
from src.tools import general

__all__ = ['Environment']
        
if sys.platform.startswith('win'):
    WIN = True
    COMMAND_LINE = ['cmd', '/k']
    PATH_SEP = ';'
    CMD_RM = 'del'
    CMD_MV = 'move'
    CMD_CP = 'copy'
#     PATH_SET = 'set %(name)s=%(value)s'
#     PATH_EXTEND_START = 'set %(name)s=%%%(name)s%%;%(value)s'
    #PATH_READ = 'echo %(name)
else:
    WIN = False
    COMMAND_LINE = ['/bin/bash']
    PATH_SEP = ':'
    CMD_RM = 'rm'
    CMD_MV = 'mv'
    CMD_CP = 'cp'
#     PATH_SET = 'export %(name)s=%(value)s'
#     PATH_EXTEND_END = 'export %(name)s=%(value)s:$%(name)s'
    PATH_READ = 'echo $%(name)s'
    
[docs]class Environment(object): """A class representing a shell session. In its present implementation, this class can only be expected to work properly in Linux. """ def __init__(self): """Constructor.""" self._env = os.environ.copy() self._cwd = pt.unrel() self._outputs = []
[docs] def extendPath(self, name, value, start=True, forceReplace=False): """Extend a path-like environment variable. Parameters ---------- name : str The name of the environment variable to extend. In this application, it will often be "PYTHONPATH". value : str The value to append to the path. start : bool Whether to prepend the new component to the variable. If `False`, the new component will be appended. forceReplace : bool Whether to change the variable if it already has a value set. """ if name in self._env and not forceReplace: oldval = self._env[name] if start: newval = PATH_SEP.join([value, oldval]) else: newval = PATH_SEP.join([oldval, value]) else: newval = value self._env[name] = newval return newval
[docs] def setPath(self, name, value): """Set a path-like variable. Parameters ---------- name : str The name of the environment variable to extend. In this application, it will often be "PYTHONPATH". value : str The value to append to the path. """ response = self.extendPath(name, value, True, True) return response
[docs] def changeDirectory(self, directory): """Change the working directory. Parameters ---------- directory : str The new working directory as a string. """ self._cwd = directory
[docs] def removeDirectory(self, directory, recursive=True): """Remove a directory. Parameters ---------- directory : str The path of the directory to remove. recursive : bool Whether to recursively remove all sub-materials. """ opts = ' -f ' if recursive: opts = ' -Rf ' self.communicate(CMD_RM + opts + directory)
[docs] def removeDirectoryContents(self, directory, filesOnly=True, ignoreHidden=True): """Remove the contents of a directory. Parameters ---------- directory : str The path of the directory whose contents should be removed. filesOnly : bool Whether to delete only regular files (i.e. ignore subfolders). The default is `True`. ignoreHidden : bool Whether to ignore hidden files and folders. The default is `True`. """ command = 'ls -a %s' contents = self.communicate(command % directory) contentsList = general.multilineStringToList(contents) if '.' in contentsList: contentsList.remove('.') if '..' in contentsList: contentsList.remove('..') newList = [] for item in contentsList: if not ignoreHidden or not item.startswith('.'): newList.append(os.path.join(directory, item)) if filesOnly: for item in newList: itemtest = pt.unrel(item) if os.path.isdir(itemtest): self.removeDirectoryContents(item, filesOnly, ignoreHidden) elif os.path.isfile(itemtest): self.remove(item) else: print 'unknown: ' + item else: for item in newList: self.removeDirectory(directory, True)
[docs] def remove(self, fileName): """Remove a regular file. Parameters ---------- fileName : str The path of the file to delete. """ self.communicate(CMD_RM + ' ' + fileName)
[docs] def move(self, source, target, force=False): """Move a file or folder. Parameters ---------- source : str The path of the file or folder to move. target : str Where the file or folder should be moved. force : bool Whether to overwrite files without prompting or failing. The default is `False`. """ if force: command = 'mv -f %s %s' else: command = 'mv %s %s' self.communicate(command % (source, target))
[docs] def moveDirectoryContents(self, source, target, force=False): """Move the contents of a directory from one location to another. Parameters ---------- source : str The path of the folder whose contents should be moved. target : str The path of the folder into which the files should be moved. force : bool Whether to automatically overwrite file conflicts. The default is `False`. """ if source.endswith('/') or source.endswith('\\'): source += '*' else: source += os.path.sep + '*' if force: command = 'mv -f %s %s' else: command = 'mv %s %s' self.communicate(command % (source, target))
[docs] def copy(self, source, target, recursive=True): """Copy a file or folder. Parameters ---------- source : str The path of the file or folder to copy. target : str The path to which the file should be copied. recursive : bool If `source` is a folder, whether to copy all of its contents recursively. Notes ----- If `recursive` is not set and `source` is a folder with contents, the operation will fail. """ if recursive: command = 'cp -R %s %s' else: command = 'cp %s %s' self.communicate(command % (source, target))
[docs] def communicate(self, command, shell=True): """Send a command and read the response. Parameters ---------- command : str The command to execute. shell : bool Whether to run in the system shell. Returns ------- str The standard output (STDOUT) for the process. """ result = subprocess.check_output(command, cwd = self._cwd, env = self._env, stderr=subprocess.STDOUT, shell = shell) self._outputs.append(result) return result
@classmethod
[docs] def isWindows(cls): """Determine whether the operating system is Windows.""" return WIN
if __name__ == '__main__': ENV = Environment() ENV.changeDirectory('/home/thomas/Documents/Projects/Transport/') print ENV.removeDirectoryContents('doc/htmlhelp') #print e.communicate('svn log')