From e74944165ab2b0cdd7a516ad4703e0a921ab3ad9 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Thu, 20 Feb 2014 03:41:58 -0500 Subject: [PATCH 1/6] Starting work on the new package structure. --- gitup/__init__.py | 16 ++++ gitup.py => gitup/script.py | 196 +++++++++++++++++++++----------------------- setup.py | 58 ++++++------- 3 files changed, 138 insertions(+), 132 deletions(-) create mode 100644 gitup/__init__.py rename gitup.py => gitup/script.py (55%) diff --git a/gitup/__init__.py b/gitup/__init__.py new file mode 100644 index 0000000..2d8d6d9 --- /dev/null +++ b/gitup/__init__.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2011-2014 Ben Kurtovic +# See the LICENSE file for details. + +""" +gitup: the git repository updater +""" + +__author__ = "Ben Kurtovic" +__copyright__ = "Copyright (C) 2011-2014 Ben Kurtovic" +__license__ = "MIT License" +__version__ = "0.2.dev" +__email__ = "ben.kurtovic@gmail.com" + +from . import script diff --git a/gitup.py b/gitup/script.py similarity index 55% rename from gitup.py rename to gitup/script.py index cf6c524..31e4a64 100644 --- a/gitup.py +++ b/gitup/script.py @@ -1,9 +1,9 @@ -#! /usr/bin/python -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- +# +# Copyright (C) 2011-2014 Ben Kurtovic +# See the LICENSE file for details. -""" -gitup: the git repository updater -""" +from __future__ import print_function import argparse import ConfigParser as configparser @@ -12,24 +12,20 @@ import re import shlex import subprocess -__author__ = "Ben Kurtovic" -__copyright__ = "Copyright (c) 2011-2014 Ben Kurtovic" -__license__ = "MIT License" -__version__ = "0.2.dev" -__email__ = "ben.kurtovic@gmail.com" +from . import __version__, __email__ config_filename = os.path.join(os.path.expanduser("~"), ".gitup") -# Text formatting functions -bold = lambda t: style_text(t, "bold") -red = lambda t: style_text(t, "red") -green = lambda t: style_text(t, "green") -yellow = lambda t: style_text(t, "yellow") -blue = lambda t: style_text(t, "blue") +# Text formatting functions: +bold = lambda t: _style_text(t, "bold") +red = lambda t: _style_text(t, "red") +green = lambda t: _style_text(t, "green") +yellow = lambda t: _style_text(t, "yellow") +blue = lambda t: _style_text(t, "blue") -def style_text(text, effect): +def _style_text(text, effect): """Give a text string a certain effect, such as boldness, or a color.""" - ansi = { # ANSI escape codes to make terminal output fancy + ansi = { # ANSI escape codes to make terminal output fancy "reset": "\x1b[0m", "bold": "\x1b[1m", "red": "\x1b[1m\x1b[31m", @@ -38,34 +34,34 @@ def style_text(text, effect): "blue": "\x1b[1m\x1b[34m", } - try: # pad text with effect, unless effect does not exist - return "{}{}{}".format(ansi[effect], text, ansi['reset']) + try: # Pad text with effect, unless effect does not exist + return ansi[effect] + text + ansi["reset"] except KeyError: return text def out(indent, msg): """Print a message at a given indentation level.""" - width = 4 # amount to indent at each level + width = 4 # Amount to indent at each level if indent == 0: spacing = "\n" else: spacing = " " * width * indent - msg = re.sub("\s+", " ", msg) # collapse multiple spaces into one - print spacing + msg + msg = re.sub(r"\s+", " ", msg) # Collapse multiple spaces into one + print(spacing + msg) def exec_shell(command): """Execute a shell command and get the output.""" command = shlex.split(command) result = subprocess.check_output(command, stderr=subprocess.STDOUT) if result: - result = result[:-1] # strip newline if command returned anything + result = result[:-1] # Strip newline if command returned anything return result def directory_is_git_repo(directory_path): """Check if a directory is a git repository.""" if os.path.isdir(directory_path): git_subfolder = os.path.join(directory_path, ".git") - if os.path.isdir(git_subfolder): # check for path/to/repository/.git + if os.path.isdir(git_subfolder): # Check for path/to/repository/.git return True return False @@ -73,60 +69,62 @@ def update_repository(repo_path, repo_name): """Update a single git repository by pulling from the remote.""" out(1, bold(repo_name) + ":") - os.chdir(repo_path) # cd into our folder so git commands target the correct - # repo + # cd into our folder so git commands target the correct repo: + os.chdir(repo_path) try: - dry_fetch = exec_shell("git fetch --dry-run") # check if there is - # anything to pull, but - # don't do it yet + # Check if there is anything to pull, but don't do it yet: + dry_fetch = exec_shell("git fetch --dry-run") except subprocess.CalledProcessError: - out(2, red("Error: ") + "cannot fetch; do you have a remote " + - "repository configured correctly?") + out(2, red("Error: ") + "cannot fetch; do you have a remote " \ + "repository configured correctly?") return try: last_commit = exec_shell("git log -n 1 --pretty=\"%ar\"") except subprocess.CalledProcessError: - last_commit = "never" # couldn't get a log, so no commits + last_commit = "never" # Couldn't get a log, so no commits - if not dry_fetch: # no new changes to pull - out(2, blue("No new changes.") + " Last commit was {}.".format( - last_commit)) + if not dry_fetch: # No new changes to pull + out(2, blue("No new changes.") + + " Last commit was {0}.".format(last_commit)) - else: # stuff has happened! + else: # Stuff has happened! out(2, "There are new changes upstream...") status = exec_shell("git status") if status.endswith("nothing to commit, working directory clean"): out(2, green("Pulling new changes...")) result = exec_shell("git pull") - out(2, "The following changes have been made since {}:".format( + out(2, "The following changes have been made since {0}:".format( last_commit)) - print result + print(result) else: - out(2, red("Warning: ") + "you have uncommitted changes in this " + - "repository!") + out(2, red("Warning: ") + + "you have uncommitted changes in this repository!") out(2, "Ignoring.") def update_directory(dir_path, dir_name, is_bookmark=False): - """First, make sure the specified object is actually a directory, then + """Update a particular directory. + + First, make sure the specified object is actually a directory, then determine whether the directory is a git repo on its own or a directory of git repositories. If the former, update the single repository; if the - latter, update all repositories contained within.""" + latter, update all repositories contained within. + """ if is_bookmark: - dir_type = "bookmark" # where did we get this directory from? + dir_type = "bookmark" # Where did we get this directory from? else: dir_type = "directory" - dir_long_name = "{} '{}'".format(dir_type, bold(dir_path)) + dir_long_name = "{0} '{1}'".format(dir_type, bold(dir_path)) try: - os.listdir(dir_path) # test if we can access this directory + os.listdir(dir_path) # Test if we can access this directory except OSError: - out(0, red("Error: ") + "cannot enter {}; does it exist?".format( - dir_long_name)) + out(0, red("Error: ") + + "cannot enter {0}; does it exist?".format(dir_long_name)) return if not os.path.isdir(dir_path): @@ -143,11 +141,11 @@ def update_directory(dir_path, dir_name, is_bookmark=False): else: repositories = [] - dir_contents = os.listdir(dir_path) # get potential repos in directory + dir_contents = os.listdir(dir_path) # Get potential repos in directory for item in dir_contents: repo_path = os.path.join(dir_path, item) repo_name = os.path.join(dir_name, item) - if directory_is_git_repo(repo_path): # filter out non-repositories + if directory_is_git_repo(repo_path): # Filter out non-repositories repositories.append((repo_path, repo_name)) num_of_repos = len(repositories) @@ -155,17 +153,17 @@ def update_directory(dir_path, dir_name, is_bookmark=False): out(0, dir_long_name.capitalize() + " contains 1 git repository:") else: out(0, dir_long_name.capitalize() + - " contains {} git repositories:".format(num_of_repos)) + " contains {0} git repositories:".format(num_of_repos)) - repositories.sort() # go alphabetically instead of randomly + repositories.sort() # Go alphabetically instead of randomly for repo_path, repo_name in repositories: update_repository(repo_path, repo_name) def update_directories(paths): """Update a list of directories supplied by command arguments.""" for path in paths: - path = os.path.abspath(path) # convert relative to absolute path - path_name = os.path.split(path)[1] # directory name; "x" in /path/to/x/ + path = os.path.abspath(path) # Convert relative to absolute path + path_name = os.path.split(path)[1] # Dir name ("x" in /path/to/x/) update_directory(path, path_name, is_bookmark=False) def update_bookmarks(): @@ -179,21 +177,19 @@ def update_bookmarks(): for bookmark_path, bookmark_name in bookmarks: update_directory(bookmark_path, bookmark_name, is_bookmark=True) else: - out(0, "You don't have any bookmarks configured! Get help with " + - "'gitup -h'.") + out(0, "You don't have any bookmarks configured! " \ + "Get help with 'gitup -h'.") def load_config_file(): - """Read the file storing our config options from config_filename and return - the resulting SafeConfigParser() object.""" + """Read the config file and return a SafeConfigParser() object.""" config = configparser.SafeConfigParser() - config.optionxform = str # don't lowercase option names, because we are - # storing paths there + # Don't lowercase option names, because we are storing paths there: + config.optionxform = str config.read(config_filename) return config def save_config_file(config): - """Save our config changes to the config file specified by - config_filename.""" + """Save config changes to the config file specified by config_filename.""" with open(config_filename, "wb") as config_file: config.write(config_file) @@ -206,9 +202,9 @@ def add_bookmarks(paths): out(0, yellow("Added bookmarks:")) for path in paths: - path = os.path.abspath(path) # convert relative to absolute path + path = os.path.abspath(path) # Convert relative to absolute path if config.has_option("bookmarks", path): - out(1, "'{}' is already bookmarked.".format(path)) + out(1, "'{0}' is already bookmarked.".format(path)) else: path_name = os.path.split(path)[1] config.set("bookmarks", path, path_name) @@ -223,12 +219,12 @@ def delete_bookmarks(paths): if config.has_section("bookmarks"): out(0, yellow("Deleted bookmarks:")) for path in paths: - path = os.path.abspath(path) # convert relative to absolute path + path = os.path.abspath(path) # Convert relative to absolute path config_was_changed = config.remove_option("bookmarks", path) if config_was_changed: out(1, bold(path)) else: - out(1, "'{}' is not bookmarked.".format(path)) + out(1, "'{0}' is not bookmarked.".format(path)) save_config_file(config) else: @@ -251,61 +247,59 @@ def list_bookmarks(): def main(): """Parse arguments and then call the appropriate function(s).""" - parser = argparse.ArgumentParser(description="""Easily pull to multiple git - repositories at once.""", epilog="""Both relative and absolute - paths are accepted by all arguments. Questions? Comments? Email the - author at {}.""".format(__email__), add_help=False) + parser = argparse.ArgumentParser( + description="""Easily pull to multiple git repositories at once.""", + epilog=""" + Both relative and absolute paths are accepted by all arguments. + Questions? Comments? Email the author at {0}.""".format(__email__), + add_help=False) group_u = parser.add_argument_group("updating repositories") group_b = parser.add_argument_group("bookmarking") group_m = parser.add_argument_group("miscellaneous") - group_u.add_argument('directories_to_update', nargs="*", metavar="path", - help="""update all repositories in this directory (or the directory - itself, if it is a repo)""") - - group_u.add_argument('-u', '--update', action="store_true", help="""update - all bookmarks (default behavior when called without arguments)""") - - group_b.add_argument('-a', '--add', dest="bookmarks_to_add", nargs="+", - metavar="path", help="add directory(s) as bookmarks") - - group_b.add_argument('-d', '--delete', dest="bookmarks_to_del", nargs="+", - metavar="path", - help="delete bookmark(s) (leaves actual directories alone)") - - group_b.add_argument('-l', '--list', dest="list_bookmarks", - action="store_true", help="list current bookmarks") - - group_m.add_argument('-h', '--help', action="help", - help="show this help message and exit") - - group_m.add_argument('-v', '--version', action="version", - version="gitup version "+__version__) + group_u.add_argument( + 'directories_to_update', nargs="*", metavar="path", + help="""update all repositories in this directory (or the directory + itself, if it is a repo)""") + group_u.add_argument( + '-u', '--update', action="store_true", help="""update all bookmarks + (default behavior when called without arguments)""") + group_b.add_argument( + '-a', '--add', dest="bookmarks_to_add", nargs="+", metavar="path", + help="add directory(s) as bookmarks") + group_b.add_argument( + '-d', '--delete', dest="bookmarks_to_del", nargs="+", metavar="path", + help="delete bookmark(s) (leaves actual directories alone)") + group_b.add_argument( + '-l', '--list', dest="list_bookmarks", action="store_true", + help="list current bookmarks") + group_m.add_argument( + '-h', '--help', action="help", help="show this help message and exit") + group_m.add_argument( + '-v', '--version', action="version", + version="gitup version " + __version__) args = parser.parse_args() - - print bold("gitup") + ": the git-repo-updater" + print(bold("gitup") + ": the git-repo-updater") if args.bookmarks_to_add: add_bookmarks(args.bookmarks_to_add) - if args.bookmarks_to_del: delete_bookmarks(args.bookmarks_to_del) - if args.list_bookmarks: list_bookmarks() - if args.directories_to_update: update_directories(args.directories_to_update) - if args.update: update_bookmarks() - if not any(vars(args).values()): # if they did not tell us to do anything, - update_bookmarks() # automatically update bookmarks + # If they did not tell us to do anything, automatically update bookmarks: + if not any(vars(args).values()): + update_bookmarks() -if __name__ == "__main__": +def run(): + """Thin wrapper for main() that catches KeyboardInterrupts.""" try: main() except KeyboardInterrupt: diff --git a/setup.py b/setup.py index c571036..3d7b348 100644 --- a/setup.py +++ b/setup.py @@ -1,35 +1,35 @@ -from setuptools import setup -import os +# -*- coding: utf-8 -*- +# +# Copyright (C) 2011-2014 Ben Kurtovic +# See the LICENSE file for details. + import sys +from setuptools import setup, find_packages + if sys.hexversion < 0x02070000: exit("Please upgrade to Python 2.7 or greater: .") -remove_py_extension = True # install script as "gitup" instead of "gitup.py" - -if os.path.exists("gitup"): - remove_py_extension = False -else: - os.rename("gitup.py", "gitup") +from gitup import __version__ -desc = "Easily pull to multiple git repositories at once." +with open('README.md') as fp: + long_desc = fp.read() -with open('README.md') as file: - long_desc = file.read() - -try: - setup( - name = "gitup", - version = "0.1", - scripts = ['gitup'], - author = "Ben Kurtovic", - author_email = "ben.kurtovic@gmail.com", - description = desc, - long_description = long_desc, - license = "MIT License", - keywords = "git repository pull update", - url = "http://github.com/earwig/git-repo-updater", - classifiers = ["Environment :: Console", +setup( + name = "gitup", + packages = find_packages(), + entry_points = {"console_scripts": ["gitup = gitup.script:run"]}, + install_requires = ["GitPython >= 0.3.2.RC1"], + version = __version__, + author = "Ben Kurtovic", + author_email = "ben.kurtovic@gmail.com", + description = "Easily pull to multiple git repositories at once.", + long_description = long_desc, + license = "MIT License", + keywords = "git repository pull update", + url = "http://github.com/earwig/git-repo-updater", + classifiers = [ + "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", @@ -38,9 +38,5 @@ try: "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Topic :: Software Development :: Version Control" - ] - ) - -finally: - if remove_py_extension: - os.rename("gitup", "gitup.py") # restore file location + ] +) From e9e2adec63656f1170e9a5af3c38154e60bea052 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 24 Feb 2014 14:15:37 -0500 Subject: [PATCH 2/6] Update gitignore, README. --- .gitignore | 10 +++++++--- README.md | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 25aacff..cc17441 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ -build/ -dist/ -*.egg-info/ +*.pyc +*.egg +*.egg-info +.DS_Store +__pycache__ +build +dist diff --git a/README.md b/README.md index 1c88284..3709582 100644 --- a/README.md +++ b/README.md @@ -80,5 +80,5 @@ For a list of all command arguments and abbreviations: gitup --help -Finally, all paths can be either absolute (e.g. /path/to/repo) or relative -(e.g. ../my/repo). +Finally, all paths can be either absolute (e.g. `/path/to/repo`) or relative +(e.g. `../my/repo`). From 910b53aeba521f7b4fef41b0bd40f6a621a45942 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 24 Feb 2014 14:43:28 -0500 Subject: [PATCH 3/6] Split code into multiple files. --- gitup/__init__.py | 2 +- gitup/config.py | 82 ++++++++++++++++++ gitup/output.py | 41 +++++++++ gitup/script.py | 244 ++---------------------------------------------------- gitup/update.py | 138 ++++++++++++++++++++++++++++++ 5 files changed, 268 insertions(+), 239 deletions(-) create mode 100644 gitup/config.py create mode 100644 gitup/output.py create mode 100644 gitup/update.py diff --git a/gitup/__init__.py b/gitup/__init__.py index 2d8d6d9..9bebff1 100644 --- a/gitup/__init__.py +++ b/gitup/__init__.py @@ -13,4 +13,4 @@ __license__ = "MIT License" __version__ = "0.2.dev" __email__ = "ben.kurtovic@gmail.com" -from . import script +from . import script, update diff --git a/gitup/config.py b/gitup/config.py new file mode 100644 index 0000000..72c1cbf --- /dev/null +++ b/gitup/config.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2011-2014 Ben Kurtovic +# See the LICENSE file for details. + +import ConfigParser as configparser +import os + +from .output import out, bold, yellow + +__all__ = ["get_bookmarks", "add_bookmarks", "delete_bookmarks", + "list_bookmarks"] + +_config_filename = os.path.join(os.path.expanduser("~"), ".gitup") + +def _load_config_file(): + """Read the config file and return a SafeConfigParser() object.""" + config = configparser.SafeConfigParser() + # Don't lowercase option names, because we are storing paths there: + config.optionxform = str + config.read(_config_filename) + return config + +def _save_config_file(config): + """Save config changes to the config file specified by _config_filename.""" + with open(_config_filename, "wb") as config_file: + config.write(config_file) + +def get_bookmarks(): + """Get a list of all bookmarks, or an empty list if there are none.""" + config = _load_config_file() + try: + return config.items("bookmarks") + except configparser.NoSectionError: + return [] + +def add_bookmarks(paths): + """Add a list of paths as bookmarks to the config file.""" + config = _load_config_file() + if not config.has_section("bookmarks"): + config.add_section("bookmarks") + + out(0, yellow("Added bookmarks:")) + + for path in paths: + path = os.path.abspath(path) # Convert relative to absolute path + if config.has_option("bookmarks", path): + out(1, "'{0}' is already bookmarked.".format(path)) + else: + path_name = os.path.split(path)[1] + config.set("bookmarks", path, path_name) + out(1, bold(path)) + + _save_config_file(config) + +def delete_bookmarks(paths): + """Remove a list of paths from the bookmark config file.""" + config = _load_config_file() + + if config.has_section("bookmarks"): + out(0, yellow("Deleted bookmarks:")) + for path in paths: + path = os.path.abspath(path) # Convert relative to absolute path + config_was_changed = config.remove_option("bookmarks", path) + if config_was_changed: + out(1, bold(path)) + else: + out(1, "'{0}' is not bookmarked.".format(path)) + _save_config_file(config) + + else: + out(0, "There are no bookmarks to delete!") + +def list_bookmarks(): + """Print all of our current bookmarks.""" + bookmarks = get_bookmarks() + if bookmarks: + out(0, yellow("Current bookmarks:")) + for bookmark_path, bookmark_name in bookmarks: + out(1, bookmark_path) + else: + out(0, "You have no bookmarks to display.") diff --git a/gitup/output.py b/gitup/output.py new file mode 100644 index 0000000..a92d86c --- /dev/null +++ b/gitup/output.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2011-2014 Ben Kurtovic +# See the LICENSE file for details. + +import re + +__all__ = ["out", "bold", "red", "green", "yellow", "blue"] + +# Text formatting functions: +bold = lambda t: _style_text(t, "bold") +red = lambda t: _style_text(t, "red") +green = lambda t: _style_text(t, "green") +yellow = lambda t: _style_text(t, "yellow") +blue = lambda t: _style_text(t, "blue") + +def _style_text(text, effect): + """Give a text string a certain effect, such as boldness, or a color.""" + ansi = { # ANSI escape codes to make terminal output fancy + "reset": "\x1b[0m", + "bold": "\x1b[1m", + "red": "\x1b[1m\x1b[31m", + "green": "\x1b[1m\x1b[32m", + "yellow": "\x1b[1m\x1b[33m", + "blue": "\x1b[1m\x1b[34m", + } + + try: # Pad text with effect, unless effect does not exist + return ansi[effect] + text + ansi["reset"] + except KeyError: + return text + +def out(indent, msg): + """Print a message at a given indentation level.""" + width = 4 # Amount to indent at each level + if indent == 0: + spacing = "\n" + else: + spacing = " " * width * indent + msg = re.sub(r"\s+", " ", msg) # Collapse multiple spaces into one + print(spacing + msg) diff --git a/gitup/script.py b/gitup/script.py index 31e4a64..ea616cd 100644 --- a/gitup/script.py +++ b/gitup/script.py @@ -6,244 +6,12 @@ from __future__ import print_function import argparse -import ConfigParser as configparser -import os -import re -import shlex -import subprocess from . import __version__, __email__ - -config_filename = os.path.join(os.path.expanduser("~"), ".gitup") - -# Text formatting functions: -bold = lambda t: _style_text(t, "bold") -red = lambda t: _style_text(t, "red") -green = lambda t: _style_text(t, "green") -yellow = lambda t: _style_text(t, "yellow") -blue = lambda t: _style_text(t, "blue") - -def _style_text(text, effect): - """Give a text string a certain effect, such as boldness, or a color.""" - ansi = { # ANSI escape codes to make terminal output fancy - "reset": "\x1b[0m", - "bold": "\x1b[1m", - "red": "\x1b[1m\x1b[31m", - "green": "\x1b[1m\x1b[32m", - "yellow": "\x1b[1m\x1b[33m", - "blue": "\x1b[1m\x1b[34m", - } - - try: # Pad text with effect, unless effect does not exist - return ansi[effect] + text + ansi["reset"] - except KeyError: - return text - -def out(indent, msg): - """Print a message at a given indentation level.""" - width = 4 # Amount to indent at each level - if indent == 0: - spacing = "\n" - else: - spacing = " " * width * indent - msg = re.sub(r"\s+", " ", msg) # Collapse multiple spaces into one - print(spacing + msg) - -def exec_shell(command): - """Execute a shell command and get the output.""" - command = shlex.split(command) - result = subprocess.check_output(command, stderr=subprocess.STDOUT) - if result: - result = result[:-1] # Strip newline if command returned anything - return result - -def directory_is_git_repo(directory_path): - """Check if a directory is a git repository.""" - if os.path.isdir(directory_path): - git_subfolder = os.path.join(directory_path, ".git") - if os.path.isdir(git_subfolder): # Check for path/to/repository/.git - return True - return False - -def update_repository(repo_path, repo_name): - """Update a single git repository by pulling from the remote.""" - out(1, bold(repo_name) + ":") - - # cd into our folder so git commands target the correct repo: - os.chdir(repo_path) - - try: - # Check if there is anything to pull, but don't do it yet: - dry_fetch = exec_shell("git fetch --dry-run") - except subprocess.CalledProcessError: - out(2, red("Error: ") + "cannot fetch; do you have a remote " \ - "repository configured correctly?") - return - - try: - last_commit = exec_shell("git log -n 1 --pretty=\"%ar\"") - except subprocess.CalledProcessError: - last_commit = "never" # Couldn't get a log, so no commits - - if not dry_fetch: # No new changes to pull - out(2, blue("No new changes.") + - " Last commit was {0}.".format(last_commit)) - - else: # Stuff has happened! - out(2, "There are new changes upstream...") - status = exec_shell("git status") - - if status.endswith("nothing to commit, working directory clean"): - out(2, green("Pulling new changes...")) - result = exec_shell("git pull") - out(2, "The following changes have been made since {0}:".format( - last_commit)) - print(result) - - else: - out(2, red("Warning: ") + - "you have uncommitted changes in this repository!") - out(2, "Ignoring.") - -def update_directory(dir_path, dir_name, is_bookmark=False): - """Update a particular directory. - - First, make sure the specified object is actually a directory, then - determine whether the directory is a git repo on its own or a directory - of git repositories. If the former, update the single repository; if the - latter, update all repositories contained within. - """ - if is_bookmark: - dir_type = "bookmark" # Where did we get this directory from? - else: - dir_type = "directory" - - dir_long_name = "{0} '{1}'".format(dir_type, bold(dir_path)) - - try: - os.listdir(dir_path) # Test if we can access this directory - except OSError: - out(0, red("Error: ") + - "cannot enter {0}; does it exist?".format(dir_long_name)) - return - - if not os.path.isdir(dir_path): - if os.path.exists(dir_path): - out(0, red("Error: ") + dir_long_name + " is not a directory!") - else: - out(0, red("Error: ") + dir_long_name + " does not exist!") - return - - if directory_is_git_repo(dir_path): - out(0, dir_long_name.capitalize() + " is a git repository:") - update_repository(dir_path, dir_name) - - else: - repositories = [] - - dir_contents = os.listdir(dir_path) # Get potential repos in directory - for item in dir_contents: - repo_path = os.path.join(dir_path, item) - repo_name = os.path.join(dir_name, item) - if directory_is_git_repo(repo_path): # Filter out non-repositories - repositories.append((repo_path, repo_name)) - - num_of_repos = len(repositories) - if num_of_repos == 1: - out(0, dir_long_name.capitalize() + " contains 1 git repository:") - else: - out(0, dir_long_name.capitalize() + - " contains {0} git repositories:".format(num_of_repos)) - - repositories.sort() # Go alphabetically instead of randomly - for repo_path, repo_name in repositories: - update_repository(repo_path, repo_name) - -def update_directories(paths): - """Update a list of directories supplied by command arguments.""" - for path in paths: - path = os.path.abspath(path) # Convert relative to absolute path - path_name = os.path.split(path)[1] # Dir name ("x" in /path/to/x/) - update_directory(path, path_name, is_bookmark=False) - -def update_bookmarks(): - """Loop through and update all bookmarks.""" - try: - bookmarks = load_config_file().items("bookmarks") - except configparser.NoSectionError: - bookmarks = [] - - if bookmarks: - for bookmark_path, bookmark_name in bookmarks: - update_directory(bookmark_path, bookmark_name, is_bookmark=True) - else: - out(0, "You don't have any bookmarks configured! " \ - "Get help with 'gitup -h'.") - -def load_config_file(): - """Read the config file and return a SafeConfigParser() object.""" - config = configparser.SafeConfigParser() - # Don't lowercase option names, because we are storing paths there: - config.optionxform = str - config.read(config_filename) - return config - -def save_config_file(config): - """Save config changes to the config file specified by config_filename.""" - with open(config_filename, "wb") as config_file: - config.write(config_file) - -def add_bookmarks(paths): - """Add a list of paths as bookmarks to the config file.""" - config = load_config_file() - if not config.has_section("bookmarks"): - config.add_section("bookmarks") - - out(0, yellow("Added bookmarks:")) - - for path in paths: - path = os.path.abspath(path) # Convert relative to absolute path - if config.has_option("bookmarks", path): - out(1, "'{0}' is already bookmarked.".format(path)) - else: - path_name = os.path.split(path)[1] - config.set("bookmarks", path, path_name) - out(1, bold(path)) - - save_config_file(config) - -def delete_bookmarks(paths): - """Remove a list of paths from the bookmark config file.""" - config = load_config_file() - - if config.has_section("bookmarks"): - out(0, yellow("Deleted bookmarks:")) - for path in paths: - path = os.path.abspath(path) # Convert relative to absolute path - config_was_changed = config.remove_option("bookmarks", path) - if config_was_changed: - out(1, bold(path)) - else: - out(1, "'{0}' is not bookmarked.".format(path)) - save_config_file(config) - - else: - out(0, "There are no bookmarks to delete!") - -def list_bookmarks(): - """Print all of our current bookmarks.""" - config = load_config_file() - try: - bookmarks = config.items("bookmarks") - except configparser.NoSectionError: - bookmarks = [] - - if bookmarks: - out(0, yellow("Current bookmarks:")) - for bookmark_path, bookmark_name in bookmarks: - out(1, bookmark_path) - else: - out(0, "You have no bookmarks to display.") +from .config import (get_bookmarks, add_bookmarks, delete_bookmarks, + list_bookmarks) +from .output import out, bold +from .update import update_bookmarks, update_directories def main(): """Parse arguments and then call the appropriate function(s).""" @@ -292,11 +60,11 @@ def main(): if args.directories_to_update: update_directories(args.directories_to_update) if args.update: - update_bookmarks() + update_bookmarks(get_bookmarks()) # If they did not tell us to do anything, automatically update bookmarks: if not any(vars(args).values()): - update_bookmarks() + update_bookmarks(get_bookmarks()) def run(): """Thin wrapper for main() that catches KeyboardInterrupts.""" diff --git a/gitup/update.py b/gitup/update.py new file mode 100644 index 0000000..0245159 --- /dev/null +++ b/gitup/update.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2011-2014 Ben Kurtovic +# See the LICENSE file for details. + +import os +import shlex +import subprocess + +from .output import out, bold, red, green, blue + +__all__ = ["update_bookmarks", "update_directories"] + +def _exec_shell(command): + """Execute a shell command and get the output.""" + command = shlex.split(command) + result = subprocess.check_output(command, stderr=subprocess.STDOUT) + if result: + result = result[:-1] # Strip newline if command returned anything + return result + +def _directory_is_git_repo(directory_path): + """Check if a directory is a git repository.""" + if os.path.isdir(directory_path): + git_subfolder = os.path.join(directory_path, ".git") + if os.path.isdir(git_subfolder): # Check for path/to/repository/.git + return True + return False + +def _update_repository(repo_path, repo_name): + """Update a single git repository by pulling from the remote.""" + out(1, bold(repo_name) + ":") + + # cd into our folder so git commands target the correct repo: + os.chdir(repo_path) + + try: + # Check if there is anything to pull, but don't do it yet: + dry_fetch = _exec_shell("git fetch --dry-run") + except subprocess.CalledProcessError: + out(2, red("Error: ") + "cannot fetch; do you have a remote " \ + "repository configured correctly?") + return + + try: + last_commit = _exec_shell("git log -n 1 --pretty=\"%ar\"") + except subprocess.CalledProcessError: + last_commit = "never" # Couldn't get a log, so no commits + + if not dry_fetch: # No new changes to pull + out(2, blue("No new changes.") + + " Last commit was {0}.".format(last_commit)) + + else: # Stuff has happened! + out(2, "There are new changes upstream...") + status = _exec_shell("git status") + + if status.endswith("nothing to commit, working directory clean"): + out(2, green("Pulling new changes...")) + result = _exec_shell("git pull") + out(2, "The following changes have been made since {0}:".format( + last_commit)) + print(result) + + else: + out(2, red("Warning: ") + + "you have uncommitted changes in this repository!") + out(2, "Ignoring.") + +def _update_directory(dir_path, dir_name, is_bookmark=False): + """Update a particular directory. + + First, make sure the specified object is actually a directory, then + determine whether the directory is a git repo on its own or a directory + of git repositories. If the former, update the single repository; if the + latter, update all repositories contained within. + """ + if is_bookmark: + dir_type = "bookmark" # Where did we get this directory from? + else: + dir_type = "directory" + + dir_long_name = "{0} '{1}'".format(dir_type, bold(dir_path)) + + try: + os.listdir(dir_path) # Test if we can access this directory + except OSError: + out(0, red("Error: ") + + "cannot enter {0}; does it exist?".format(dir_long_name)) + return + + if not os.path.isdir(dir_path): + if os.path.exists(dir_path): + out(0, red("Error: ") + dir_long_name + " is not a directory!") + else: + out(0, red("Error: ") + dir_long_name + " does not exist!") + return + + if _directory_is_git_repo(dir_path): + out(0, dir_long_name.capitalize() + " is a git repository:") + _update_repository(dir_path, dir_name) + + else: + repositories = [] + + dir_contents = os.listdir(dir_path) # Get potential repos in directory + for item in dir_contents: + repo_path = os.path.join(dir_path, item) + repo_name = os.path.join(dir_name, item) + if _directory_is_git_repo(repo_path): # Filter out non-repositories + repositories.append((repo_path, repo_name)) + + num_of_repos = len(repositories) + if num_of_repos == 1: + out(0, dir_long_name.capitalize() + " contains 1 git repository:") + else: + out(0, dir_long_name.capitalize() + + " contains {0} git repositories:".format(num_of_repos)) + + repositories.sort() # Go alphabetically instead of randomly + for repo_path, repo_name in repositories: + _update_repository(repo_path, repo_name) + +def update_bookmarks(bookmarks): + """Loop through and update all bookmarks.""" + if bookmarks: + for bookmark_path, bookmark_name in bookmarks: + _update_directory(bookmark_path, bookmark_name, is_bookmark=True) + else: + out(0, "You don't have any bookmarks configured! " \ + "Get help with 'gitup -h'.") + +def update_directories(paths): + """Update a list of directories supplied by command arguments.""" + for path in paths: + path = os.path.abspath(path) # Convert relative to absolute path + path_name = os.path.split(path)[1] # Dir name ("x" in /path/to/x/) + _update_directory(path, path_name, is_bookmark=False) From beac864d29a4b883e73c6e0bb0eae7a98886924a Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 2 Mar 2014 00:53:34 -0500 Subject: [PATCH 4/6] Clean up output.py. --- gitup/output.py | 26 +++++--------------------- gitup/update.py | 2 +- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/gitup/output.py b/gitup/output.py index a92d86c..7b160ea 100644 --- a/gitup/output.py +++ b/gitup/output.py @@ -8,27 +8,11 @@ import re __all__ = ["out", "bold", "red", "green", "yellow", "blue"] # Text formatting functions: -bold = lambda t: _style_text(t, "bold") -red = lambda t: _style_text(t, "red") -green = lambda t: _style_text(t, "green") -yellow = lambda t: _style_text(t, "yellow") -blue = lambda t: _style_text(t, "blue") - -def _style_text(text, effect): - """Give a text string a certain effect, such as boldness, or a color.""" - ansi = { # ANSI escape codes to make terminal output fancy - "reset": "\x1b[0m", - "bold": "\x1b[1m", - "red": "\x1b[1m\x1b[31m", - "green": "\x1b[1m\x1b[32m", - "yellow": "\x1b[1m\x1b[33m", - "blue": "\x1b[1m\x1b[34m", - } - - try: # Pad text with effect, unless effect does not exist - return ansi[effect] + text + ansi["reset"] - except KeyError: - return text +bold = lambda t: "\x1b[1m" + t + "\x1b[0m" +red = lambda t: "\x1b[1m\x1b[31m" + t + "\x1b[0m" +green = lambda t: "\x1b[1m\x1b[32m" + t + "\x1b[0m" +yellow = lambda t: "\x1b[1m\x1b[33m" + t + "\x1b[0m" +blue = lambda t: "\x1b[1m\x1b[34m" + t + "\x1b[0m" def out(indent, msg): """Print a message at a given indentation level.""" diff --git a/gitup/update.py b/gitup/update.py index 0245159..480a2e9 100644 --- a/gitup/update.py +++ b/gitup/update.py @@ -107,7 +107,7 @@ def _update_directory(dir_path, dir_name, is_bookmark=False): for item in dir_contents: repo_path = os.path.join(dir_path, item) repo_name = os.path.join(dir_name, item) - if _directory_is_git_repo(repo_path): # Filter out non-repositories + if _directory_is_git_repo(repo_path): # Filter out non-repos repositories.append((repo_path, repo_name)) num_of_repos = len(repositories) From 25127f4e944edc6fd012899bbd0a7be6cc6d05d3 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 23 Mar 2014 04:43:36 -0400 Subject: [PATCH 5/6] Finish conversion from output.py to colorama. --- LICENSE | 2 +- gitup/__init__.py | 2 +- gitup/config.py | 64 ++++++++++++++++++++++++++++++--------------- gitup/output.py | 25 ------------------ gitup/script.py | 10 ++++--- gitup/update.py | 78 ++++++++++++++++++++++++++++++++----------------------- setup.py | 2 +- 7 files changed, 98 insertions(+), 85 deletions(-) delete mode 100644 gitup/output.py diff --git a/LICENSE b/LICENSE index 7b13d64..b755367 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2014 Ben Kurtovic +Copyright (C) 2011-2014 Ben Kurtovic Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/gitup/__init__.py b/gitup/__init__.py index 9bebff1..7482a7c 100644 --- a/gitup/__init__.py +++ b/gitup/__init__.py @@ -13,4 +13,4 @@ __license__ = "MIT License" __version__ = "0.2.dev" __email__ = "ben.kurtovic@gmail.com" -from . import script, update +from . import config, script, update diff --git a/gitup/config.py b/gitup/config.py index 72c1cbf..5571cfe 100644 --- a/gitup/config.py +++ b/gitup/config.py @@ -3,27 +3,34 @@ # Copyright (C) 2011-2014 Ben Kurtovic # See the LICENSE file for details. +from __future__ import print_function + import ConfigParser as configparser import os -from .output import out, bold, yellow +from colorama import Fore, Style __all__ = ["get_bookmarks", "add_bookmarks", "delete_bookmarks", "list_bookmarks"] -_config_filename = os.path.join(os.path.expanduser("~"), ".gitup") +CONFIG_FILENAME = os.path.join(os.path.expanduser("~"), ".gitup") + +YELLOW = Fore.YELLOW + Style.BRIGHT +RED = Fore.RED + Style.BRIGHT + +INDENT1 = " " * 3 def _load_config_file(): """Read the config file and return a SafeConfigParser() object.""" config = configparser.SafeConfigParser() # Don't lowercase option names, because we are storing paths there: config.optionxform = str - config.read(_config_filename) + config.read(CONFIG_FILENAME) return config def _save_config_file(config): - """Save config changes to the config file specified by _config_filename.""" - with open(_config_filename, "wb") as config_file: + """Save config changes to the config file specified by CONFIG_FILENAME.""" + with open(CONFIG_FILENAME, "wb") as config_file: config.write(config_file) def get_bookmarks(): @@ -40,43 +47,58 @@ def add_bookmarks(paths): if not config.has_section("bookmarks"): config.add_section("bookmarks") - out(0, yellow("Added bookmarks:")) - + added, exists = [], [] for path in paths: - path = os.path.abspath(path) # Convert relative to absolute path + path = os.path.abspath(path) if config.has_option("bookmarks", path): - out(1, "'{0}' is already bookmarked.".format(path)) + exists.append(path) else: path_name = os.path.split(path)[1] config.set("bookmarks", path, path_name) - out(1, bold(path)) - + added.append(path) _save_config_file(config) + if added: + print(YELLOW + "Added bookmarks:") + for path in added: + print(INDENT1, path) + if exists: + print(RED + "Already bookmarked:") + for path in exists: + print(INDENT1, path) + def delete_bookmarks(paths): """Remove a list of paths from the bookmark config file.""" config = _load_config_file() + deleted, notmarked = [], [] if config.has_section("bookmarks"): - out(0, yellow("Deleted bookmarks:")) for path in paths: - path = os.path.abspath(path) # Convert relative to absolute path + path = os.path.abspath(path) config_was_changed = config.remove_option("bookmarks", path) if config_was_changed: - out(1, bold(path)) + deleted.append(path) else: - out(1, "'{0}' is not bookmarked.".format(path)) + notmarked.append(path) _save_config_file(config) - else: - out(0, "There are no bookmarks to delete!") + notmarked = [os.path.abspath(path) for path in paths] + + if deleted: + print(YELLOW + "Deleted bookmarks:") + for path in deleted: + print(INDENT1, path) + if notmarked: + print(RED + "Not bookmarked:") + for path in notmarked: + print(INDENT1, path) def list_bookmarks(): """Print all of our current bookmarks.""" bookmarks = get_bookmarks() if bookmarks: - out(0, yellow("Current bookmarks:")) - for bookmark_path, bookmark_name in bookmarks: - out(1, bookmark_path) + print(YELLOW + "Current bookmarks:") + for bookmark_path, _ in bookmarks: + print(INDENT1, bookmark_path) else: - out(0, "You have no bookmarks to display.") + print("You have no bookmarks to display.") diff --git a/gitup/output.py b/gitup/output.py deleted file mode 100644 index 7b160ea..0000000 --- a/gitup/output.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2011-2014 Ben Kurtovic -# See the LICENSE file for details. - -import re - -__all__ = ["out", "bold", "red", "green", "yellow", "blue"] - -# Text formatting functions: -bold = lambda t: "\x1b[1m" + t + "\x1b[0m" -red = lambda t: "\x1b[1m\x1b[31m" + t + "\x1b[0m" -green = lambda t: "\x1b[1m\x1b[32m" + t + "\x1b[0m" -yellow = lambda t: "\x1b[1m\x1b[33m" + t + "\x1b[0m" -blue = lambda t: "\x1b[1m\x1b[34m" + t + "\x1b[0m" - -def out(indent, msg): - """Print a message at a given indentation level.""" - width = 4 # Amount to indent at each level - if indent == 0: - spacing = "\n" - else: - spacing = " " * width * indent - msg = re.sub(r"\s+", " ", msg) # Collapse multiple spaces into one - print(spacing + msg) diff --git a/gitup/script.py b/gitup/script.py index ea616cd..8105d8a 100644 --- a/gitup/script.py +++ b/gitup/script.py @@ -7,10 +7,11 @@ from __future__ import print_function import argparse +from colorama import init as color_init, Style + from . import __version__, __email__ from .config import (get_bookmarks, add_bookmarks, delete_bookmarks, list_bookmarks) -from .output import out, bold from .update import update_bookmarks, update_directories def main(): @@ -48,8 +49,11 @@ def main(): '-v', '--version', action="version", version="gitup version " + __version__) + color_init(autoreset=True) args = parser.parse_args() - print(bold("gitup") + ": the git-repo-updater") + + print(Style.BRIGHT + "gitup" + Style.RESET_ALL + ": the git-repo-updater") + print() if args.bookmarks_to_add: add_bookmarks(args.bookmarks_to_add) @@ -71,4 +75,4 @@ def run(): try: main() except KeyboardInterrupt: - out(0, "Stopped by user.") + print("Stopped by user.") diff --git a/gitup/update.py b/gitup/update.py index 480a2e9..de2d01b 100644 --- a/gitup/update.py +++ b/gitup/update.py @@ -3,21 +3,24 @@ # Copyright (C) 2011-2014 Ben Kurtovic # See the LICENSE file for details. +from __future__ import print_function + import os import shlex import subprocess -from .output import out, bold, red, green, blue +from colorama import Fore, Style __all__ = ["update_bookmarks", "update_directories"] -def _exec_shell(command): - """Execute a shell command and get the output.""" - command = shlex.split(command) - result = subprocess.check_output(command, stderr=subprocess.STDOUT) - if result: - result = result[:-1] # Strip newline if command returned anything - return result +BOLD = Style.BRIGHT +RED = Fore.RED + BOLD +GREEN = Fore.GREEN + BOLD +BLUE = Fore.BLUE + BOLD +RESET = Style.RESET_ALL + +INDENT1 = " " * 3 +INDENT2 = " " * 7 def _directory_is_git_repo(directory_path): """Check if a directory is a git repository.""" @@ -29,17 +32,25 @@ def _directory_is_git_repo(directory_path): def _update_repository(repo_path, repo_name): """Update a single git repository by pulling from the remote.""" - out(1, bold(repo_name) + ":") + def _exec_shell(command): + """Execute a shell command and get the output.""" + command = shlex.split(command) + result = subprocess.check_output(command, stderr=subprocess.STDOUT) + if result: + result = result[:-1] # Strip newline if command returned anything + return result + + print(INDENT1, BOLD + repo_name + ":") # cd into our folder so git commands target the correct repo: - os.chdir(repo_path) + os.chdir(repo_path) # TODO: remove this when using gitpython try: # Check if there is anything to pull, but don't do it yet: dry_fetch = _exec_shell("git fetch --dry-run") except subprocess.CalledProcessError: - out(2, red("Error: ") + "cannot fetch; do you have a remote " \ - "repository configured correctly?") + print(INDENT2, RED + "Error:" + RESET, "cannot fetch;", + "do you have a remote repository configured correctly?") return try: @@ -48,24 +59,27 @@ def _update_repository(repo_path, repo_name): last_commit = "never" # Couldn't get a log, so no commits if not dry_fetch: # No new changes to pull - out(2, blue("No new changes.") + - " Last commit was {0}.".format(last_commit)) + print(INDENT2, BLUE + "No new changes." + RESET, + "Last commit was {0}.".format(last_commit)) else: # Stuff has happened! - out(2, "There are new changes upstream...") + print(INDENT2, "There are new changes upstream...") status = _exec_shell("git status") if status.endswith("nothing to commit, working directory clean"): - out(2, green("Pulling new changes...")) + print(INDENT2, GREEN + "Pulling new changes...") result = _exec_shell("git pull") - out(2, "The following changes have been made since {0}:".format( - last_commit)) + if last_commit == "never": + print(INDENT2, "The following changes have been made:") + else: + print(INDENT2, "The following changes have been made since", + last_commit + ":") print(result) else: - out(2, red("Warning: ") + - "you have uncommitted changes in this repository!") - out(2, "Ignoring.") + print(INDENT2, RED + "Warning:" + RESET, + "you have uncommitted changes in this repository!") + print(INDENT2, "Ignoring.") def _update_directory(dir_path, dir_name, is_bookmark=False): """Update a particular directory. @@ -79,25 +93,24 @@ def _update_directory(dir_path, dir_name, is_bookmark=False): dir_type = "bookmark" # Where did we get this directory from? else: dir_type = "directory" - - dir_long_name = "{0} '{1}'".format(dir_type, bold(dir_path)) + dir_long_name = dir_type + ' "' + BOLD + dir_path + RESET + '"' try: os.listdir(dir_path) # Test if we can access this directory except OSError: - out(0, red("Error: ") + - "cannot enter {0}; does it exist?".format(dir_long_name)) + print(RED + "Error:" + RESET, + "cannot enter {0}; does it exist?".format(dir_long_name)) return if not os.path.isdir(dir_path): if os.path.exists(dir_path): - out(0, red("Error: ") + dir_long_name + " is not a directory!") + print(RED + "Error:" + RESET, dir_long_name, "is not a directory!") else: - out(0, red("Error: ") + dir_long_name + " does not exist!") + print(RED + "Error:" + RESET, dir_long_name, "does not exist!") return if _directory_is_git_repo(dir_path): - out(0, dir_long_name.capitalize() + " is a git repository:") + print(dir_long_name.capitalize(), "is a git repository:") _update_repository(dir_path, dir_name) else: @@ -112,10 +125,10 @@ def _update_directory(dir_path, dir_name, is_bookmark=False): num_of_repos = len(repositories) if num_of_repos == 1: - out(0, dir_long_name.capitalize() + " contains 1 git repository:") + print(dir_long_name.capitalize(), "contains 1 git repository:") else: - out(0, dir_long_name.capitalize() + - " contains {0} git repositories:".format(num_of_repos)) + print(dir_long_name.capitalize(), + "contains {0} git repositories:".format(num_of_repos)) repositories.sort() # Go alphabetically instead of randomly for repo_path, repo_name in repositories: @@ -127,8 +140,7 @@ def update_bookmarks(bookmarks): for bookmark_path, bookmark_name in bookmarks: _update_directory(bookmark_path, bookmark_name, is_bookmark=True) else: - out(0, "You don't have any bookmarks configured! " \ - "Get help with 'gitup -h'.") + print("You don't have any bookmarks configured! Get help with 'gitup -h'.") def update_directories(paths): """Update a list of directories supplied by command arguments.""" diff --git a/setup.py b/setup.py index 3d7b348..4a907ad 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ setup( name = "gitup", packages = find_packages(), entry_points = {"console_scripts": ["gitup = gitup.script:run"]}, - install_requires = ["GitPython >= 0.3.2.RC1"], + install_requires = ["GitPython >= 0.3.2.RC1", "colorama >= 0.2.7"], version = __version__, author = "Ben Kurtovic", author_email = "ben.kurtovic@gmail.com", From 30d01fd200d30a709099eaf17e7391e8c53e66b0 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 23 Mar 2014 04:45:19 -0400 Subject: [PATCH 6/6] Remove relative imports from __init__ so __version__ can be read without deps. --- gitup/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/gitup/__init__.py b/gitup/__init__.py index 7482a7c..f82076a 100644 --- a/gitup/__init__.py +++ b/gitup/__init__.py @@ -12,5 +12,3 @@ __copyright__ = "Copyright (C) 2011-2014 Ben Kurtovic" __license__ = "MIT License" __version__ = "0.2.dev" __email__ = "ben.kurtovic@gmail.com" - -from . import config, script, update