1# exc.py
2# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
3#
4# This module is part of GitPython and is released under
5# the BSD License: http://www.opensource.org/licenses/bsd-license.php
6""" Module containing all exceptions thrown throughout the git package, """
7
8from gitdb.exc import *     # NOQA @UnusedWildImport
9from git.compat import UnicodeMixin, safe_decode, string_types
10
11
12class GitError(Exception):
13    """ Base class for all package exceptions """
14
15
16class InvalidGitRepositoryError(GitError):
17    """ Thrown if the given repository appears to have an invalid format.  """
18
19
20class WorkTreeRepositoryUnsupported(InvalidGitRepositoryError):
21    """ Thrown to indicate we can't handle work tree repositories """
22
23
24class NoSuchPathError(GitError, OSError):
25    """ Thrown if a path could not be access by the system. """
26
27
28class CommandError(UnicodeMixin, GitError):
29    """Base class for exceptions thrown at every stage of `Popen()` execution.
30
31    :param command:
32        A non-empty list of argv comprising the command-line.
33    """
34
35    #: A unicode print-format with 2 `%s for `<cmdline>` and the rest,
36    #:  e.g.
37    #:     u"'%s' failed%s"
38    _msg = u"Cmd('%s') failed%s"
39
40    def __init__(self, command, status=None, stderr=None, stdout=None):
41        if not isinstance(command, (tuple, list)):
42            command = command.split()
43        self.command = command
44        self.status = status
45        if status:
46            if isinstance(status, Exception):
47                status = u"%s('%s')" % (type(status).__name__, safe_decode(str(status)))
48            else:
49                try:
50                    status = u'exit code(%s)' % int(status)
51                except (ValueError, TypeError):
52                    s = safe_decode(str(status))
53                    status = u"'%s'" % s if isinstance(status, string_types) else s
54
55        self._cmd = safe_decode(command[0])
56        self._cmdline = u' '.join(safe_decode(i) for i in command)
57        self._cause = status and u" due to: %s" % status or "!"
58        self.stdout = stdout and u"\n  stdout: '%s'" % safe_decode(stdout) or ''
59        self.stderr = stderr and u"\n  stderr: '%s'" % safe_decode(stderr) or ''
60
61    def __unicode__(self):
62        return (self._msg + "\n  cmdline: %s%s%s") % (
63            self._cmd, self._cause, self._cmdline, self.stdout, self.stderr)
64
65
66class GitCommandNotFound(CommandError):
67    """Thrown if we cannot find the `git` executable in the PATH or at the path given by
68    the GIT_PYTHON_GIT_EXECUTABLE environment variable"""
69    def __init__(self, command, cause):
70        super(GitCommandNotFound, self).__init__(command, cause)
71        self._msg = u"Cmd('%s') not found%s"
72
73
74class GitCommandError(CommandError):
75    """ Thrown if execution of the git command fails with non-zero status code. """
76
77    def __init__(self, command, status, stderr=None, stdout=None):
78        super(GitCommandError, self).__init__(command, status, stderr, stdout)
79
80
81class CheckoutError(GitError):
82    """Thrown if a file could not be checked out from the index as it contained
83    changes.
84
85    The .failed_files attribute contains a list of relative paths that failed
86    to be checked out as they contained changes that did not exist in the index.
87
88    The .failed_reasons attribute contains a string informing about the actual
89    cause of the issue.
90
91    The .valid_files attribute contains a list of relative paths to files that
92    were checked out successfully and hence match the version stored in the
93    index"""
94
95    def __init__(self, message, failed_files, valid_files, failed_reasons):
96        Exception.__init__(self, message)
97        self.failed_files = failed_files
98        self.failed_reasons = failed_reasons
99        self.valid_files = valid_files
100
101    def __str__(self):
102        return Exception.__str__(self) + ":%s" % self.failed_files
103
104
105class CacheError(GitError):
106
107    """Base for all errors related to the git index, which is called cache internally"""
108
109
110class UnmergedEntriesError(CacheError):
111    """Thrown if an operation cannot proceed as there are still unmerged
112    entries in the cache"""
113
114
115class HookExecutionError(CommandError):
116    """Thrown if a hook exits with a non-zero exit code. It provides access to the exit code and the string returned
117    via standard output"""
118
119    def __init__(self, command, status, stderr=None, stdout=None):
120        super(HookExecutionError, self).__init__(command, status, stderr, stdout)
121        self._msg = u"Hook('%s') failed%s"
122
123
124class RepositoryDirtyError(GitError):
125    """Thrown whenever an operation on a repository fails as it has uncommitted changes that would be overwritten"""
126
127    def __init__(self, repo, message):
128        self.repo = repo
129        self.message = message
130
131    def __str__(self):
132        return "Operation cannot be performed on %r: %s" % (self.repo, self.message)
133