Allow the abbreviation of StGIT commands
[stgit] / stgit / utils.py
index 9465fe0..67431ec 100644 (file)
@@ -1,6 +1,8 @@
 """Common utility functions
 """
 
+import errno, os, os.path
+
 __copyright__ = """
 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
 
@@ -18,45 +20,135 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
+def mkdir_file(filename, mode):
+    """Opens filename with the given mode, creating the directory it's
+    in if it doesn't already exist."""
+    create_dirs(os.path.dirname(filename))
+    return file(filename, mode)
+
 def read_string(filename, multiline = False):
     """Reads the first line from a file
     """
     f = file(filename, 'r')
     if multiline:
-        string = f.read()
+        result = f.read()
     else:
-        string = f.readline().strip()
+        result = f.readline().strip()
     f.close()
-    return string
+    return result
 
-def write_string(filename, string, multiline = False):
-    """Writes string to file and truncates it
+def write_string(filename, line, multiline = False):
+    """Writes 'line' to file and truncates it
     """
-    f = file(filename, 'w+')
+    f = mkdir_file(filename, 'w+')
     if multiline:
-        f.write(string)
+        f.write(line)
     else:
-        print >> f, string
+        print >> f, line
     f.close()
 
-def append_string(filename, string):
-    """Appends string to file
+def append_strings(filename, lines):
+    """Appends 'lines' sequence to file
     """
-    f = file(filename, 'a+')
-    print >> f, string
+    f = mkdir_file(filename, 'a+')
+    for line in lines:
+        print >> f, line
     f.close()
 
-def insert_string(filename, string):
-    """Inserts a string at the beginning of the file
+def append_string(filename, line):
+    """Appends 'line' to file
     """
-    f = file(filename, 'r+')
+    f = mkdir_file(filename, 'a+')
+    print >> f, line
+    f.close()
+
+def insert_string(filename, line):
+    """Inserts 'line' at the beginning of the file
+    """
+    f = mkdir_file(filename, 'r+')
     lines = f.readlines()
     f.seek(0); f.truncate()
-    print >> f, string
+    print >> f, line
     f.writelines(lines)
     f.close()
 
 def create_empty_file(name):
     """Creates an empty file
     """
-    file(name, 'w+').close()
+    mkdir_file(name, 'w+').close()
+
+def list_files_and_dirs(path):
+    """Return the sets of filenames and directory names in a
+    directory."""
+    files, dirs = [], []
+    for fd in os.listdir(path):
+        full_fd = os.path.join(path, fd)
+        if os.path.isfile(full_fd):
+            files.append(fd)
+        elif os.path.isdir(full_fd):
+            dirs.append(fd)
+    return files, dirs
+
+def walk_tree(basedir):
+    """Starting in the given directory, iterate through all its
+    subdirectories. For each subdirectory, yield the name of the
+    subdirectory (relative to the base directory), the list of
+    filenames in the subdirectory, and the list of directory names in
+    the subdirectory."""
+    subdirs = ['']
+    while subdirs:
+        subdir = subdirs.pop()
+        files, dirs = list_files_and_dirs(os.path.join(basedir, subdir))
+        for d in dirs:
+            subdirs.append(os.path.join(subdir, d))
+        yield subdir, files, dirs
+
+def strip_prefix(prefix, string):
+    """Return string, without the prefix. Blow up if string doesn't
+    start with prefix."""
+    assert string.startswith(prefix)
+    return string[len(prefix):]
+
+def strip_suffix(suffix, string):
+    """Return string, without the suffix. Blow up if string doesn't
+    end with suffix."""
+    assert string.endswith(suffix)
+    return string[:-len(suffix)]
+
+def remove_dirs(basedir, dirs):
+    """Starting at join(basedir, dirs), remove the directory if empty,
+    and try the same with its parent, until we find a nonempty
+    directory or reach basedir."""
+    path = dirs
+    while path:
+        try:
+            os.rmdir(os.path.join(basedir, path))
+        except OSError:
+            return # can't remove nonempty directory
+        path = os.path.dirname(path)
+
+def remove_file_and_dirs(basedir, file):
+    """Remove join(basedir, file), and then remove the directory it
+    was in if empty, and try the same with its parent, until we find a
+    nonempty directory or reach basedir."""
+    os.remove(os.path.join(basedir, file))
+    remove_dirs(basedir, os.path.dirname(file))
+
+def create_dirs(directory):
+    """Create the given directory, if the path doesn't already exist."""
+    if directory and not os.path.isdir(directory):
+        create_dirs(os.path.dirname(directory))
+        try:
+            os.mkdir(directory)
+        except OSError, e:
+            if e.errno != errno.EEXIST:
+                raise e
+
+def rename(basedir, file1, file2):
+    """Rename join(basedir, file1) to join(basedir, file2), not
+    leaving any empty directories behind and creating any directories
+    necessary."""
+    full_file2 = os.path.join(basedir, file2)
+    create_dirs(os.path.dirname(full_file2))
+    os.rename(os.path.join(basedir, file1), full_file2)
+    remove_dirs(basedir, os.path.dirname(file1))