Codebase list python-git / 70c0097
Imported Upstream version 0.1.4.1 SVN-Git Migration 8 years ago
37 changed file(s) with 2052 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
0 Michael Trier <mtrier _at_ gmail.com>
1 Alan Briolat
2 Florian Apolloner <florian _at_ apolloner.eu>
3 David Aguilar <davvid _at_ gmail.com>
0 =======
1 CHANGES
2 =======
3
4 0.1.5
5 =====
6
7 * removed ``method_missing`` stuff and replaced with a ``__getattr__``
8 override in ``Git``.
9
10 0.1.4
11 =====
12
13 * renamed ``git_python`` to ``git``. Be sure to delete all pyc files before
14 testing.
15
16 Commit
17 ------
18 * Fixed problem with commit stats not working under all conditions.
19
20 Git
21 ---
22 * Renamed module to cmd.
23
24 * Removed shell escaping completely.
25
26 * Added support for ``stderr``, ``stdin``, and ``with_status``.
27
28 * ``git_dir`` is now optional in the constructor for ``git.Git``. Git now
29 falls back to ``os.getcwd()`` when git_dir is not specified.
30
31 * add a ``with_exceptions`` keyword argument to git commands.
32 ``GitCommandError`` is raised when the exit status is non-zero.
33
34 * add support for a ``GIT_PYTHON_TRACE`` environment variable.
35 ``GIT_PYTHON_TRACE`` allows us to debug GitPython's usage of git through
36 the use of an environment variable.
37
38 Tree
39 ----
40 * Fixed up problem where ``name`` doesn't exist on root of tree.
41
42 Repo
43 ----
44 * Corrected problem with creating bare repo. Added ``Repo.create`` alias.
45
46 0.1.2
47 =====
48
49 Tree
50 ----
51 * Corrected problem with ``Tree.__div__`` not working with zero length files.
52 Removed ``__len__`` override and replaced with size instead. Also made size
53 cach properly. This is a breaking change.
54
55 0.1.1
56 =====
57 Fixed up some urls because I'm a moron
58
59 0.1.0
60 =====
61 initial release
0 Copyright (c) 2008, Michael Trier and contributors
1 All rights reserved.
2
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions
5 are met:
6
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 * Neither the name of the GitPython project nor the names of
15 its contributors may be used to endorse or promote products derived
16 from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
0 include doc/*.txt
1 include VERSION
2 include LICENSE
3 include CHANGES
4 include AUTHORS
0 Metadata-Version: 1.0
1 Name: GitPython
2 Version: 0.1.4.1
3 Summary: Python Git Library
4 Home-page: http://gitorious.org/projects/git-python/
5 Author: Michael Trier
6 Author-email: mtrier@gmail.com
7 License: BSD License
8 Description: GitPython is a python library used to interact with Git repositories.
9
10 GitPython provides object model access to your git repository. Once you have
11 created a repository object, you can traverse it to find parent commit(s),
12 trees, blobs, etc.
13
14 GitPython is a port of the grit library in Ruby created by
15 Tom Preston-Werner and Chris Wanstrath.
16
17 Platform: UNKNOWN
18 Classifier: Development Status :: 3 - Alpha
19 Classifier: Intended Audience :: Developers
20 Classifier: License :: OSI Approved :: BSD License
21 Classifier: Programming Language :: Python
22 Classifier: Topic :: Software Development :: Libraries :: Python Modules
0 ==========
1 GitPython
2 ==========
3
4 GitPython is a python library used to interact with Git repositories.
5
6 GitPython is a port of the grit_ library in Ruby created by
7 Tom Preston-Werner and Chris Wanstrath.
8
9 .. _grit: http://grit.rubyforge.org
10
11 REQUIREMENTS
12 ============
13
14 * Git_ tested with 1.5.3.7
15 * `Python Nose`_ - used for running the tests
16 * `Mock by Michael Foord`_ used for tests
17
18 .. _Git: http://git.or.cz/
19 .. _Python Nose: http://code.google.com/p/python-nose/
20 .. _Mock by Michael Foord: http://www.voidspace.org.uk/python/mock.html
21
22 INSTALL
23 =======
24
25 python setup.py install
26
27 SOURCE
28 ======
29
30 GitPython's git repo is available on Gitorious, which can be browsed at:
31
32 http://gitorious.org/projects/git-python/
33
34 and cloned from:
35
36 git://gitorious.org/git-python/mainline.git
37
38 LICENSE
39 =======
40
41 New BSD License. See the LICENSE file.
0 0.1.4.1
Binary diff not shown
0 ========
1 TUTORIAL
2 ========
3
4 GitPython provides object model access to your git repository. Once you have
5 created a repository object, you can traverse it to find parent commit(s),
6 trees, blobs, etc.
7
8 Initialize a Repo object
9 ************************
10
11 The first step is to create a ``Repo`` object to represent your repository.
12
13 >>> from git import *
14 >>> repo = Repo("/Users/mtrier/Development/git-python")
15
16 In the above example, the directory ``/Users/mtrier/Development/git-python``
17 is my working repository and contains the ``.git`` directory. You can also
18 initialize GitPython with a bare repository.
19
20 >>> repo = Repo.create("/var/git/git-python.git")
21
22 Getting a list of commits
23 *************************
24
25 From the ``Repo`` object, you can get a list of ``Commit``
26 objects.
27
28 >>> repo.commits()
29 [<GitPython.Commit "207c0c4418115df0d30820ab1a9acd2ea4bf4431">,
30 <GitPython.Commit "a91c45eee0b41bf3cdaad3418ca3850664c4a4b4">,
31 <GitPython.Commit "e17c7e11aed9e94d2159e549a99b966912ce1091">,
32 <GitPython.Commit "bd795df2d0e07d10e0298670005c0e9d9a5ed867">]
33
34 Called without arguments, ``Repo.commits`` returns a list of up to ten commits
35 reachable by the master branch (starting at the latest commit). You can ask
36 for commits beginning at a different branch, commit, tag, etc.
37
38 >>> repo.commits('mybranch')
39 >>> repo.commits('40d3057d09a7a4d61059bca9dca5ae698de58cbe')
40 >>> repo.commits('v0.1')
41
42 You can specify the maximum number of commits to return.
43
44 >>> repo.commits('master', 100)
45
46 If you need paging, you can specify a number of commits to skip.
47
48 >>> repo.commits('master', 10, 20)
49
50 The above will return commits 21-30 from the commit list.
51
52 The Commit object
53 *****************
54
55 Commit objects contain information about a specific commit.
56
57 >>> head = repo.commits()[0]
58
59 >>> head.id
60 '207c0c4418115df0d30820ab1a9acd2ea4bf4431'
61
62 >>> head.parents
63 [<GitPython.Commit "a91c45eee0b41bf3cdaad3418ca3850664c4a4b4">]
64
65 >>> head.tree
66 <GitPython.Tree "563413aedbeda425d8d9dcbb744247d0c3e8a0ac">
67
68 >>> head.author
69 <GitPython.Actor "Michael Trier <mtrier@gmail.com>">
70
71 >>> head.authored_date
72 (2008, 5, 7, 5, 0, 56, 2, 128, 0)
73
74 >>> head.committer
75 <GitPython.Actor "Michael Trier <mtrier@gmail.com>">
76
77 >>> head.committed_date
78 (2008, 5, 7, 5, 0, 56, 2, 128, 0)
79
80 >>> head.message
81 'cleaned up a lot of test information. Fixed escaping so it works with
82 subprocess.'
83
84 Note: date time is represented in a `struct_time`_ format. Conversion to
85 human readable form can be accomplished with the various time module methods.
86
87 >>> import time
88 >>> time.asctime(head.committed_date)
89 'Wed May 7 05:56:02 2008'
90
91 >>> time.strftime("%a, %d %b %Y %H:%M", head.committed_date)
92 'Wed, 7 May 2008 05:56'
93
94 .. _struct_time: http://docs.python.org/lib/module-time.html
95
96 You can traverse a commit's ancestry by chaining calls to ``parents``.
97
98 >>> repo.commits()[0].parents[0].parents[0].parents[0]
99
100 The above corresponds to ``master^^^`` or ``master~3`` in git parlance.
101
102 The Tree object
103 ***************
104
105 A tree records pointers to the contents of a directory. Let's say you want
106 the root tree of the latest commit on the master branch.
107
108 >>> tree = repo.commits()[0].tree
109 <GitPython.Tree "a006b5b1a8115185a228b7514cdcd46fed90dc92">
110
111 >>> tree.id
112 'a006b5b1a8115185a228b7514cdcd46fed90dc92'
113
114 Once you have a tree, you can get the contents.
115
116 >>> contents = tree.contents
117 [<GitPython.Blob "6a91a439ea968bf2f5ce8bb1cd8ddf5bf2cad6c7">,
118 <GitPython.Blob "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391">,
119 <GitPython.Tree "eaa0090ec96b054e425603480519e7cf587adfc3">,
120 <GitPython.Blob "980e72ae16b5378009ba5dfd6772b59fe7ccd2df">]
121
122 This tree contains three ``Blob`` objects and one ``Tree`` object. The trees
123 are subdirectories and the blobs are files. Trees below the root have
124 additional attributes.
125
126 >>> contents = tree.contents[-2]
127 <GitPython.Tree "e5445b9db4a9f08d5b4de4e29e61dffda2f386ba">
128
129 >>> contents.name
130 'test'
131
132 >>> contents.mode
133 '040000'
134
135 There is a convenience method that allows you to get a named sub-object
136 from a tree.
137
138 >>> tree/"lib"
139 <GitPython.Tree "c1c7214dde86f76bc3e18806ac1f47c38b2b7a30">
140
141 You can also get a tree directly from the repository if you know its name.
142
143 >>> repo.tree()
144 <GitPython.Tree "master">
145
146 >>> repo.tree("c1c7214dde86f76bc3e18806ac1f47c38b2b7a30")
147 <GitPython.Tree "c1c7214dde86f76bc3e18806ac1f47c38b2b7a30">
148
149 The Blob object
150 ***************
151
152 A blob represents a file. Trees often contain blobs.
153
154 >>> blob = tree.contents[-1]
155 <GitPython.Blob "b19574431a073333ea09346eafd64e7b1908ef49">
156
157 A blob has certain attributes.
158
159 >>> blob.name
160 'urls.py'
161
162 >>> blob.mode
163 '100644'
164
165 >>> blob.mime_type
166 'text/x-python'
167
168 >>> blob.size
169 415
170
171 You can get the data of a blob as a string.
172
173 >>> blob.data
174 "from django.conf.urls.defaults import *\nfrom django.conf..."
175
176 You can also get a blob directly from the repo if you know its name.
177
178 >>> repo.blob("b19574431a073333ea09346eafd64e7b1908ef49")
179 <GitPython.Blob "b19574431a073333ea09346eafd64e7b1908ef49">
180
181 What Else?
182 **********
183
184 There is more stuff in there, like the ability to tar or gzip repos, stats,
185 log, blame, and probably a few other things. Additionally calls to the git
186 instance are handled through a ``__getattr__`` construct, which makes
187 available any git commands directly, with a nice conversion of Python dicts
188 to command line parameters.
189
190 Check the unit tests, they're pretty exhaustive.
0 Metadata-Version: 1.0
1 Name: GitPython
2 Version: 0.1.4.1
3 Summary: Python Git Library
4 Home-page: http://gitorious.org/projects/git-python/
5 Author: Michael Trier
6 Author-email: mtrier@gmail.com
7 License: BSD License
8 Description: GitPython is a python library used to interact with Git repositories.
9
10 GitPython provides object model access to your git repository. Once you have
11 created a repository object, you can traverse it to find parent commit(s),
12 trees, blobs, etc.
13
14 GitPython is a port of the grit library in Ruby created by
15 Tom Preston-Werner and Chris Wanstrath.
16
17 Platform: UNKNOWN
18 Classifier: Development Status :: 3 - Alpha
19 Classifier: Intended Audience :: Developers
20 Classifier: License :: OSI Approved :: BSD License
21 Classifier: Programming Language :: Python
22 Classifier: Topic :: Software Development :: Libraries :: Python Modules
0 AUTHORS
1 CHANGES
2 LICENSE
3 MANIFEST.in
4 README
5 VERSION
6 setup.py
7 doc/tutorial.txt
8 lib/GitPython.egg-info/PKG-INFO
9 lib/GitPython.egg-info/SOURCES.txt
10 lib/GitPython.egg-info/dependency_links.txt
11 lib/GitPython.egg-info/top_level.txt
12 lib/git/__init__.py
13 lib/git/actor.py
14 lib/git/blob.py
15 lib/git/cmd.py
16 lib/git/commit.py
17 lib/git/diff.py
18 lib/git/errors.py
19 lib/git/head.py
20 lib/git/lazy.py
21 lib/git/repo.py
22 lib/git/stats.py
23 lib/git/tag.py
24 lib/git/tree.py
25 lib/git/utils.py
Binary diff not shown
Binary diff not shown
0 # __init__.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 import os
7 import inspect
8
9 __version__ = '0.1.4.1'
10
11 from git.actor import Actor
12 from git.blob import Blob
13 from git.commit import Commit
14 from git.diff import Diff
15 from git.errors import InvalidGitRepositoryError, NoSuchPathError, GitCommandError
16 from git.cmd import Git
17 from git.head import Head
18 from git.repo import Repo
19 from git.stats import Stats
20 from git.tag import Tag
21 from git.tree import Tree
22 from git.utils import dashify
23 from git.utils import touch
24
25 __all__ = [ name for name, obj in locals().items()
26 if not (name.startswith('_') or inspect.ismodule(obj)) ]
0 # actor.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 import re
7
8 class Actor(object):
9 def __init__(self, name, email):
10 self.name = name
11 self.email = email
12
13 def __str__(self):
14 return self.name
15
16 def __repr__(self):
17 return '<GitPython.Actor "%s <%s>">' % (self.name, self.email)
18
19 @classmethod
20 def from_string(cls, string):
21 """
22 Create an Actor from a string.
23
24 ``str``
25 is the string, which is expected to be in regular git format
26
27 Format
28 John Doe <jdoe@example.com>
29
30 Returns
31 Actor
32 """
33 if re.search(r'<.+>', string):
34 m = re.search(r'(.*) <(.+?)>', string)
35 name, email = m.groups()
36 return Actor(name, email)
37 else:
38 return Actor(string, None)
0 # blob.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 import mimetypes
7 import os
8 import re
9 import time
10 from actor import Actor
11 from commit import Commit
12
13 class Blob(object):
14 DEFAULT_MIME_TYPE = "text/plain"
15
16 def __init__(self, repo, **kwargs):
17 """
18 Create an unbaked Blob containing just the specified attributes
19
20 ``repo``
21 is the Repo
22
23 ``atts``
24 is a dict of instance variable data
25
26 Returns
27 GitPython.Blob
28 """
29 self.id = None
30 self.mode = None
31 self.name = None
32 self._size = None
33 self.data_stored = None
34
35 self.repo = repo
36 for k, v in kwargs.items():
37 setattr(self, k, v)
38
39 @property
40 def size(self):
41 """
42 The size of this blob in bytes
43
44 Returns
45 int
46 """
47 if self._size is None:
48 self._size = int(self.repo.git.cat_file(self.id, **{'s': True}).rstrip())
49 return self._size
50
51 @property
52 def data(self):
53 """
54 The binary contents of this blob.
55
56 Returns
57 str
58 """
59 self.data_stored = self.data_stored or self.repo.git.cat_file(self.id, **{'p': True})
60 return self.data_stored
61
62 @property
63 def mime_type(self):
64 """
65 The mime type of this file (based on the filename)
66
67 Returns
68 str
69 """
70 guesses = None
71 if self.name:
72 guesses = mimetypes.guess_type(self.name)
73 return guesses and guesses[0] or self.DEFAULT_MIME_TYPE
74
75 @property
76 def basename(self):
77 return os.path.basename(self.name)
78
79 @classmethod
80 def blame(cls, repo, commit, file):
81 """
82 The blame information for the given file at the given commit
83
84 Returns
85 list: [GitPython.Commit, list: [<line>]]
86 """
87 data = repo.git.blame(commit, '--', file, **{'p': True})
88 commits = {}
89 blames = []
90 info = None
91
92 for line in data.splitlines():
93 parts = re.split(r'\s+', line, 1)
94 if re.search(r'^[0-9A-Fa-f]{40}$', parts[0]):
95 if re.search(r'^([0-9A-Fa-f]{40}) (\d+) (\d+) (\d+)$', line):
96 m = re.search(r'^([0-9A-Fa-f]{40}) (\d+) (\d+) (\d+)$', line)
97 id, origin_line, final_line, group_lines = m.groups()
98 info = {'id': id}
99 blames.append([None, []])
100 elif re.search(r'^([0-9A-Fa-f]{40}) (\d+) (\d+)$', line):
101 m = re.search(r'^([0-9A-Fa-f]{40}) (\d+) (\d+)$', line)
102 id, origin_line, final_line = m.groups()
103 info = {'id': id}
104 elif re.search(r'^(author|committer)', parts[0]):
105 if re.search(r'^(.+)-mail$', parts[0]):
106 m = re.search(r'^(.+)-mail$', parts[0])
107 info["%s_email" % m.groups()[0]] = parts[-1]
108 elif re.search(r'^(.+)-time$', parts[0]):
109 m = re.search(r'^(.+)-time$', parts[0])
110 info["%s_date" % m.groups()[0]] = time.gmtime(int(parts[-1]))
111 elif re.search(r'^(author|committer)$', parts[0]):
112 m = re.search(r'^(author|committer)$', parts[0])
113 info[m.groups()[0]] = parts[-1]
114 elif re.search(r'^filename', parts[0]):
115 info['filename'] = parts[-1]
116 elif re.search(r'^summary', parts[0]):
117 info['summary'] = parts[-1]
118 elif parts[0] == '':
119 if info:
120 c = commits.has_key(info['id']) and commits[info['id']]
121 if not c:
122 c = Commit(repo, **{'id': info['id'],
123 'author': Actor.from_string(info['author'] + ' ' + info['author_email']),
124 'authored_date': info['author_date'],
125 'committer': Actor.from_string(info['committer'] + ' ' + info['committer_email']),
126 'committed_date': info['committer_date'],
127 'message': info['summary']})
128 commits[info['id']] = c
129
130 m = re.search(r'^\t(.*)$', line)
131 text, = m.groups()
132 blames[-1][0] = c
133 blames[-1][1] += text
134 info = None
135
136 return blames
137
138 def __repr__(self):
139 return '<GitPython.Blob "%s">' % self.id
0 # cmd.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 import os
7 import subprocess
8 import re
9 from utils import *
10 from errors import GitCommandError
11
12 # Enables debugging of GitPython's git commands
13 GIT_PYTHON_TRACE = os.environ.get("GIT_PYTHON_TRACE", False)
14
15 execute_kwargs = ('istream', 'with_keep_cwd', 'with_extended_output',
16 'with_exceptions', 'with_raw_output')
17
18 class Git(object):
19 """
20 The Git class manages communication with the Git binary
21 """
22 def __init__(self, git_dir):
23 super(Git, self).__init__()
24 self.git_dir = git_dir
25
26 def __getattr__(self, name):
27 if name[:1] == '_':
28 raise AttributeError(name)
29 return lambda *args, **kwargs: self._call_process(name, *args, **kwargs)
30
31 @property
32 def get_dir(self):
33 return self.git_dir
34
35 def execute(self, command,
36 istream=None,
37 with_keep_cwd=False,
38 with_extended_output=False,
39 with_exceptions=True,
40 with_raw_output=False,
41 ):
42 """
43 Handles executing the command on the shell and consumes and returns
44 the returned information (stdout)
45
46 ``command``
47 The command argument list to execute
48
49 ``istream``
50 Standard input filehandle passed to subprocess.Popen.
51
52 ``with_keep_cwd``
53 Whether to use the current working directory from os.getcwd().
54 GitPython uses get_work_tree() as its working directory by
55 default and get_git_dir() for bare repositories.
56
57 ``with_extended_output``
58 Whether to return a (status, stdout, stderr) tuple.
59
60 ``with_exceptions``
61 Whether to raise an exception when git returns a non-zero status.
62
63 ``with_raw_output``
64 Whether to avoid stripping off trailing whitespace.
65
66 Returns
67 str(output) # extended_output = False (Default)
68 tuple(int(status), str(output)) # extended_output = True
69 """
70
71 if GIT_PYTHON_TRACE and not GIT_PYTHON_TRACE == 'full':
72 print ' '.join(command)
73
74 # Allow the user to have the command executed in their working dir.
75 if with_keep_cwd or self.git_dir is None:
76 cwd = os.getcwd()
77 else:
78 cwd=self.git_dir
79
80 # Start the process
81 proc = subprocess.Popen(command,
82 cwd=cwd,
83 stdin=istream,
84 stderr=subprocess.PIPE,
85 stdout=subprocess.PIPE
86 )
87
88 # Wait for the process to return
89 try:
90 stdout_value = proc.stdout.read()
91 stderr_value = proc.stderr.read()
92 status = proc.wait()
93 finally:
94 proc.stdout.close()
95 proc.stderr.close()
96
97 # Strip off trailing whitespace by default
98 if not with_raw_output:
99 stdout_value = stdout_value.rstrip()
100 stderr_value = stderr_value.rstrip()
101
102 if with_exceptions and status != 0:
103 raise GitCommandError(command, status, stderr_value)
104
105 if GIT_PYTHON_TRACE == 'full':
106 if stderr_value:
107 print "%s -> %d: '%s' !! '%s'" % (command, status, stdout_value, stderr_value)
108 elif stdout_value:
109 print "%s -> %d: '%s'" % (command, status, stdout_value)
110 else:
111 print "%s -> %d" % (command, status)
112
113 # Allow access to the command's status code
114 if with_extended_output:
115 return (status, stdout_value, stderr_value)
116 else:
117 return stdout_value
118
119 def transform_kwargs(self, **kwargs):
120 """
121 Transforms Python style kwargs into git command line options.
122 """
123 args = []
124 for k, v in kwargs.items():
125 if len(k) == 1:
126 if v is True:
127 args.append("-%s" % k)
128 elif type(v) is not bool:
129 args.append("-%s%s" % (k, v))
130 else:
131 if v is True:
132 args.append("--%s" % dashify(k))
133 elif type(v) is not bool:
134 args.append("--%s=%s" % (dashify(k), v))
135 return args
136
137 def _call_process(self, method, *args, **kwargs):
138 """
139 Run the given git command with the specified arguments and return
140 the result as a String
141
142 ``method``
143 is the command
144
145 ``args``
146 is the list of arguments
147
148 ``kwargs``
149 is a dict of keyword arguments.
150 This function accepts the same optional keyword arguments
151 as execute().
152
153 Examples
154 git.rev_list('master', max_count=10, header=True)
155
156 Returns
157 Same as execute()
158 """
159
160 # Handle optional arguments prior to calling transform_kwargs
161 # otherwise these'll end up in args, which is bad.
162 _kwargs = {}
163 for kwarg in execute_kwargs:
164 try:
165 _kwargs[kwarg] = kwargs.pop(kwarg)
166 except KeyError:
167 pass
168
169 # Prepare the argument list
170 opt_args = self.transform_kwargs(**kwargs)
171 ext_args = map(str, args)
172 args = opt_args + ext_args
173
174 call = ["git", dashify(method)]
175 call.extend(args)
176
177 return self.execute(call, **_kwargs)
0 # commit.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 import re
7 import time
8
9 from actor import Actor
10 from lazy import LazyMixin
11 import tree
12 import diff
13 import stats
14
15 class Commit(LazyMixin):
16 def __init__(self, repo, **kwargs):
17 """
18 Instantiate a new Commit
19
20 ``id``
21 is the id of the commit
22
23 ``parents``
24 is a list of commit ids (will be converted into Commit instances)
25
26 ``tree``
27 is the correspdonding tree id (will be converted into a Tree object)
28
29 ``author``
30 is the author string
31
32 ``authored_date``
33 is the authored DateTime
34
35 ``committer``
36 is the committer string
37
38 ``committed_date``
39 is the committed DateTime
40
41 ``message``
42 is the first line of the commit message
43
44 Returns
45 GitPython.Commit
46 """
47 LazyMixin.__init__(self)
48
49 self.repo = repo
50 self.id = None
51 self.tree = None
52 self.author = None
53 self.authored_date = None
54 self.committer = None
55 self.committed_date = None
56 self.message = None
57 self.parents = None
58
59 for k, v in kwargs.items():
60 setattr(self, k, v)
61
62 if self.id:
63 if 'parents' in kwargs:
64 self.parents = map(lambda p: Commit(repo, **{'id': p}), kwargs['parents'])
65 if 'tree' in kwargs:
66 self.tree = tree.Tree(repo, **{'id': kwargs['tree']})
67
68 def __bake__(self):
69 temp = Commit.find_all(self.repo, self.id, **{'max_count': 1})[0]
70 self.parents = temp.parents
71 self.tree = temp.tree
72 self.author = temp.author
73 self.authored_date = temp.authored_date
74 self.committer = temp.committer
75 self.committed_date = temp.committed_date
76 self.message = temp.message
77
78 @property
79 def id_abbrev(self):
80 return self.id[0:7]
81
82 @classmethod
83 def count(cls, repo, ref):
84 """
85 Count the number of commits reachable from this ref
86
87 ``repo``
88 is the Repo
89
90 ``ref``
91 is the ref from which to begin (SHA1 or name)
92
93 Returns
94 int
95 """
96 return len(repo.git.rev_list(ref).strip().splitlines())
97
98 @classmethod
99 def find_all(cls, repo, ref, **kwargs):
100 """
101 Find all commits matching the given criteria.
102 ``repo``
103 is the Repo
104
105 ``ref``
106 is the ref from which to begin (SHA1 or name)
107
108 ``options``
109 is a Hash of optional arguments to git where
110 ``max_count`` is the maximum number of commits to fetch
111 ``skip`` is the number of commits to skip
112
113 Returns
114 GitPython.Commit[]
115 """
116 options = {'pretty': 'raw'}
117 options.update(kwargs)
118
119 output = repo.git.rev_list(ref, **options)
120 return cls.list_from_string(repo, output)
121
122 @classmethod
123 def list_from_string(cls, repo, text):
124 """
125 Parse out commit information into a list of Commit objects
126
127 ``repo``
128 is the Repo
129
130 ``text``
131 is the text output from the git command (raw format)
132
133 Returns
134 GitPython.Commit[]
135 """
136 lines = [l for l in text.splitlines() if l.strip()]
137
138 commits = []
139
140 while lines:
141 id = lines.pop(0).split()[-1]
142 tree = lines.pop(0).split()[-1]
143
144 parents = []
145 while lines and re.search(r'^parent', lines[0]):
146 parents.append(lines.pop(0).split()[-1])
147 author, authored_date = cls.actor(lines.pop(0))
148 committer, committed_date = cls.actor(lines.pop(0))
149
150 messages = []
151 while lines and re.search(r'^ {4}', lines[0]):
152 messages.append(lines.pop(0).strip())
153
154 message = messages and messages[0] or ''
155
156 commits.append(Commit(repo, id=id, parents=parents, tree=tree, author=author, authored_date=authored_date,
157 committer=committer, committed_date=committed_date, message=message))
158
159 return commits
160
161 @classmethod
162 def diff(cls, repo, a, b = None, paths = None):
163 """
164 Show diffs between two trees:
165
166 ``repo``
167 is the Repo
168
169 ``a``
170 is a named commit
171
172 ``b``
173 is an optional named commit. Passing a list assumes you
174 wish to omit the second named commit and limit the diff to the
175 given paths.
176
177 ``paths``
178 is a list of paths to limit the diff.
179
180 Returns
181 GitPython.Diff[]
182 """
183 paths = paths or []
184
185 if isinstance(b, list):
186 paths = b
187 b = None
188
189 if paths:
190 paths.insert(0, "--")
191
192 if b:
193 paths.insert(0, b)
194 paths.insert(0, a)
195 text = repo.git.diff(*paths, **{'full_index': True})
196 return diff.Diff.list_from_string(repo, text)
197
198 @property
199 def diffs(self):
200 if not self.parents:
201 d = self.repo.git.show(self.id, **{'full_index': True, 'pretty': 'raw'})
202 if re.search(r'diff --git a', d):
203 if not re.search(r'^diff --git a', d):
204 p = re.compile(r'.+?(diff --git a)', re.MULTILINE | re.DOTALL)
205 d = p.sub(r'diff --git a', d, 1)
206 else:
207 d = ''
208 return diff.Diff.list_from_string(self.repo, d)
209 else:
210 return self.diff(self.repo, self.parents[0].id, self.id)
211
212 @property
213 def stats(self):
214 if not self.parents:
215 text = self.repo.git.diff(self.id, **{'numstat': True})
216 text2 = ""
217 for line in text.splitlines():
218 (insertions, deletions, filename) = line.split("\t")
219 text2 += "%s\t%s\t%s\n" % (deletions, insertions, filename)
220 text = text2
221 else:
222 text = self.repo.git.diff(self.parents[0].id, self.id, **{'numstat': True})
223 return stats.Stats.list_from_string(self.repo, text)
224
225 def __str__(self):
226 """ Convert commit to string which is SHA1 """
227 return self.id
228
229 def __repr__(self):
230 return '<GitPython.Commit "%s">' % self.id
231
232 @classmethod
233 def actor(cls, line):
234 """
235 Parse out the actor (author or committer) info
236
237 Returns
238 [str (actor name and email), time (acted at time)]
239 """
240 m = re.search(r'^.+? (.*) (\d+) .*$', line)
241 actor, epoch = m.groups()
242 return [Actor.from_string(actor), time.gmtime(int(epoch))]
0 # diff.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 import re
7 import commit
8
9 class Diff(object):
10 """
11 A Diff contains diff information between two commits.
12 """
13
14 def __init__(self, repo, a_path, b_path, a_commit, b_commit, a_mode, b_mode, new_file, deleted_file, diff):
15 self.repo = repo
16 self.a_path = a_path
17 self.b_path = b_path
18
19 if not a_commit or re.search(r'^0{40}$', a_commit):
20 self.a_commit = None
21 else:
22 self.a_commit = commit.Commit(repo, **{'id': a_commit})
23 if not b_commit or re.search(r'^0{40}$', b_commit):
24 self.b_commit = None
25 else:
26 self.b_commit = commit.Commit(repo, **{'id': b_commit})
27
28 self.a_mode = a_mode
29 self.b_mode = b_mode
30 self.new_file = new_file
31 self.deleted_file = deleted_file
32 self.diff = diff
33
34 @classmethod
35 def list_from_string(cls, repo, text):
36 lines = text.splitlines()
37 a_mode = None
38 b_mode = None
39 diffs = []
40 while lines:
41 m = re.search(r'^diff --git a/(\S+) b/(\S+)$', lines.pop(0))
42 if m:
43 a_path, b_path = m.groups()
44 if re.search(r'^old mode', lines[0]):
45 m = re.search(r'^old mode (\d+)', lines.pop(0))
46 if m:
47 a_mode, = m.groups()
48 m = re.search(r'^new mode (\d+)', lines.pop(0))
49 if m:
50 b_mode, = m.groups()
51 if re.search(r'^diff --git', lines[0]):
52 diffs.append(Diff(repo, a_path, b_path, None, None, a_mode, b_mode, False, False, None))
53 continue
54
55 new_file = False
56 deleted_file = False
57
58 if re.search(r'^new file', lines[0]):
59 m = re.search(r'^new file mode (.+)', lines.pop(0))
60 if m:
61 b_mode, = m.groups()
62 a_mode = None
63 new_file = True
64 elif re.search(r'^deleted file', lines[0]):
65 m = re.search(r'^deleted file mode (.+)$', lines.pop(0))
66 if m:
67 a_mode, = m.groups()
68 b_mode = None
69 deleted_file = True
70
71 m = re.search(r'^index ([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+) ?(.+)?$', lines.pop(0))
72 if m:
73 a_commit, b_commit, b_mode = m.groups()
74 if b_mode:
75 b_mode = b_mode.strip()
76
77 diff_lines = []
78 while lines and not re.search(r'^diff', lines[0]):
79 diff_lines.append(lines.pop(0))
80
81 diff = "\n".join(diff_lines)
82 diffs.append(Diff(repo, a_path, b_path, a_commit, b_commit, a_mode, b_mode, new_file, deleted_file, diff))
83
84 return diffs
0 # errors.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 class InvalidGitRepositoryError(Exception):
7 pass
8
9 class NoSuchPathError(Exception):
10 pass
11
12 class GitCommandError(Exception):
13 def __init__(self, command, status, stderr=None):
14 self.stderr = stderr
15 self.status = status
16 self.command = command
17
18 def __str__(self):
19 return repr("%s returned exit status %d" %
20 (str(self.command), self.status))
21
0 # head.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 import commit
7
8 class Head(object):
9 """
10 A Head is a named reference to a Commit. Every Head instance contains a name
11 and a Commit object.
12
13 Examples::
14
15 >>> repo = Repo("/path/to/repo")
16 >>> head = repo.heads[0]
17
18 >>> head.name
19 'master'
20
21 >>> head.commit
22 <GitPython.Commit "1c09f116cbc2cb4100fb6935bb162daa4723f455">
23
24 >>> head.commit.id
25 '1c09f116cbc2cb4100fb6935bb162daa4723f455'
26 """
27
28 def __init__(self, name, commit):
29 """
30 Instantiate a new Head
31
32 `name`
33 is the name of the head
34
35 `commit`
36 is the Commit that the head points to
37
38 Returns
39 GitPython.Head
40 """
41 self.name = name
42 self.commit = commit
43
44 @classmethod
45 def find_all(cls, repo, **kwargs):
46 """
47 Find all Heads
48
49 `repo`
50 is the Repo
51
52 `kwargs`
53 is a dict of options
54
55 Returns
56 GitPython.Head[]
57 """
58
59 options = {'sort': "committerdate",
60 'format': "%(refname)%00%(objectname)"}
61 options.update(kwargs)
62
63 output = repo.git.for_each_ref("refs/heads", **options)
64 return cls.list_from_string(repo, output)
65
66 @classmethod
67 def list_from_string(cls, repo, text):
68 """
69 Parse out head information into an array of baked head objects
70
71 ``repo``
72 is the Repo
73 ``text``
74 is the text output from the git command
75
76 Returns
77 GitPython.Head[]
78 """
79 heads = []
80
81 for line in text.splitlines():
82 heads.append(cls.from_string(repo, line))
83
84 return heads
85
86 @classmethod
87 def from_string(cls, repo, line):
88 """
89 Create a new Head instance from the given string.
90
91 ``repo``
92 is the Repo
93
94 ``line``
95 is the formatted head information
96
97 Format
98 name: [a-zA-Z_/]+
99 <null byte>
100 id: [0-9A-Fa-f]{40}
101
102 Returns
103 GitPython.Head
104 """
105 print line
106 full_name, ids = line.split("\x00")
107 name = full_name.split("/")[-1]
108 c = commit.Commit(repo, **{'id': ids})
109 return Head(name, c)
110
111 def __repr__(self):
112 return '<GitPython.Head "%s">' % self.name
0 # lazy.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 class LazyMixin(object):
7 lazy_properties = []
8
9 def __init__(self):
10 self.__baked__ = False
11
12 def __getattribute__(self, attr):
13 val = object.__getattribute__(self, attr)
14 if val is not None:
15 return val
16 else:
17 self.__prebake__()
18 return object.__getattribute__(self, attr)
19
20 def __bake__(self):
21 """ This method should be overridden in the derived class. """
22 raise NotImplementedError(" '__bake__' method has not been implemented.")
23
24 def __prebake__(self):
25 if self.__baked__:
26 return
27 self.__bake__()
28 self.__baked__ = True
29
30 def __bake_it__(self):
31 self.__baked__ = True
0 # repo.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 import os
7 import re
8 from errors import InvalidGitRepositoryError, NoSuchPathError
9 from utils import touch, is_git_dir
10 from cmd import Git
11 from head import Head
12 from blob import Blob
13 from tag import Tag
14 from commit import Commit
15 from tree import Tree
16
17 class Repo(object):
18 DAEMON_EXPORT_FILE = 'git-daemon-export-ok'
19
20 def __init__(self, path=None):
21 """
22 Create a new Repo instance
23
24 ``path``
25 is the path to either the root git directory or the bare git repo
26
27 Examples::
28
29 repo = Repo("/Users/mtrier/Development/git-python")
30 repo = Repo("/Users/mtrier/Development/git-python.git")
31
32 Returns
33 ``GitPython.Repo``
34 """
35
36 epath = os.path.abspath(os.path.expanduser(path or os.getcwd()))
37
38 if not os.path.exists(epath):
39 raise NoSuchPathError(epath)
40
41 self.path = None
42 curpath = epath
43 while curpath:
44 if is_git_dir(curpath):
45 self.bare = True
46 self.path, self.wd = curpath
47 break
48 gitpath = os.path.join(curpath, '.git')
49 if is_git_dir(gitpath):
50 self.bare = False
51 self.path = gitpath
52 self.wd = curpath
53 break
54 curpath, dummy = os.path.split(curpath)
55 if not dummy:
56 break
57
58 if self.path is None:
59 raise InvalidGitRepositoryError(epath)
60
61 self.git = Git(self.wd)
62
63 @property
64 def description(self):
65 """
66 The project's description. Taken verbatim from GIT_REPO/description
67
68 Returns
69 str
70 """
71 try:
72 f = open(os.path.join(self.path, 'description'))
73 result = f.read()
74 return result.rstrip()
75 finally:
76 f.close()
77
78 @property
79 def heads(self):
80 """
81 A list of ``Head`` objects representing the branch heads in
82 this repo
83
84 Returns
85 ``GitPython.Head[]``
86 """
87 return Head.find_all(self)
88
89 # alias heads
90 branches = heads
91
92 @property
93 def tags(self):
94 """
95 A list of ``Tag`` objects that are available in this repo
96
97 Returns
98 ``GitPython.Tag[]``
99 """
100 return Tag.find_all(self)
101
102 def commits(self, start = 'master', max_count = 10, skip = 0):
103 """
104 A list of Commit objects representing the history of a given ref/commit
105
106 ``start``
107 is the branch/commit name (default 'master')
108
109 ``max_count``
110 is the maximum number of commits to return (default 10)
111
112 ``skip``
113 is the number of commits to skip (default 0)
114
115 Returns
116 ``GitPython.Commit[]``
117 """
118 options = {'max_count': max_count,
119 'skip': skip}
120
121 return Commit.find_all(self, start, **options)
122
123 def commits_between(self, frm, to):
124 """
125 The Commits objects that are reachable via ``to`` but not via ``frm``
126 Commits are returned in chronological order.
127
128 ``from``
129 is the branch/commit name of the younger item
130
131 ``to``
132 is the branch/commit name of the older item
133
134 Returns
135 ``GitPython.Commit[]``
136 """
137 return Commit.find_all(self, "%s..%s" % (frm, to)).reverse()
138
139 def commits_since(self, start = 'master', since = '1970-01-01'):
140 """
141 The Commits objects that are newer than the specified date.
142 Commits are returned in chronological order.
143
144 ``start``
145 is the branch/commit name (default 'master')
146
147 ``since``
148 is a string represeting a date/time
149
150 Returns
151 ``GitPython.Commit[]``
152 """
153 options = {'since': since}
154
155 return Commit.find_all(self, start, **options)
156
157 def commit_count(self, start = 'master'):
158 """
159 The number of commits reachable by the given branch/commit
160
161 ``start``
162 is the branch/commit name (default 'master')
163
164 Returns
165 int
166 """
167 return Commit.count(self, start)
168
169 def commit(self, id):
170 """
171 The Commit object for the specified id
172
173 ``id``
174 is the SHA1 identifier of the commit
175
176 Returns
177 GitPython.Commit
178 """
179 options = {'max_count': 1}
180
181 commits = Commit.find_all(self, id, **options)
182
183 if not commits:
184 raise ValueError, 'Invalid identifier %s' % id
185 return commits[0]
186
187 def commit_deltas_from(self, other_repo, ref = 'master', other_ref = 'master'):
188 """
189 Returns a list of commits that is in ``other_repo`` but not in self
190
191 Returns
192 ``GitPython.Commit[]``
193 """
194 repo_refs = self.git.rev_list(ref).strip().splitlines()
195 other_repo_refs = other_repo.git.rev_list(other_ref).strip().splitlines()
196
197 diff_refs = list(set(other_repo_refs) - set(repo_refs))
198 return map(lambda ref: Commit.find_all(other_repo, ref, **{'max_count': 1}[0]), diff_refs)
199
200 def tree(self, treeish = 'master', paths = []):
201 """
202 The Tree object for the given treeish reference
203
204 ``treeish``
205 is the reference (default 'master')
206 ``paths``
207 is an optional Array of directory paths to restrict the tree (default [])
208
209 Examples::
210
211 repo.tree('master', ['lib/'])
212
213
214 Returns
215 ``GitPython.Tree``
216 """
217 return Tree.construct(self, treeish, paths)
218
219 def blob(self, id):
220 """
221 The Blob object for the given id
222
223 ``id``
224 is the SHA1 id of the blob
225
226 Returns
227 ``GitPython.Blob``
228 """
229 return Blob(self, **{'id': id})
230
231 def log(self, commit = 'master', path = None, **kwargs):
232 """
233 The commit log for a treeish
234
235 Returns
236 ``GitPython.Commit[]``
237 """
238 options = {'pretty': 'raw'}
239 options.update(kwargs)
240 if path:
241 arg = [commit, '--', path]
242 else:
243 arg = [commit]
244 commits = self.git.log(*arg, **options)
245 return Commit.list_from_string(self, commits)
246
247 def diff(self, a, b, *paths):
248 """
249 The diff from commit ``a`` to commit ``b``, optionally restricted to the given file(s)
250
251 ``a``
252 is the base commit
253 ``b``
254 is the other commit
255
256 ``paths``
257 is an optional list of file paths on which to restrict the diff
258 """
259 return self.git.diff(a, b, '--', *paths)
260
261 def commit_diff(self, commit):
262 """
263 The commit diff for the given commit
264 ``commit`` is the commit name/id
265
266 Returns
267 ``GitPython.Diff[]``
268 """
269 return Commit.diff(self, commit)
270
271 @classmethod
272 def init_bare(self, path, mkdir=True, **kwargs):
273 """
274 Initialize a bare git repository at the given path
275
276 ``path``
277 is the full path to the repo (traditionally ends with /<name>.git)
278
279 ``mkdir``
280 if specified will create the repository directory if it doesn't
281 already exists. Creates the directory with a mode=0755.
282
283 ``kwargs``
284 is any additional options to the git init command
285
286 Examples::
287
288 GitPython.Repo.init_bare('/var/git/myrepo.git')
289
290 Returns
291 ``GitPython.Repo`` (the newly created repo)
292 """
293
294 if mkdir and not os.path.exists(path):
295 os.makedirs(path, 0755)
296
297 git = Git(path)
298 output = git.init(**kwargs)
299 return Repo(path)
300 create = init_bare
301
302 def fork_bare(self, path, **kwargs):
303 """
304 Fork a bare git repository from this repo
305
306 ``path``
307 is the full path of the new repo (traditionally ends with /<name>.git)
308
309 ``options``
310 is any additional options to the git clone command
311
312 Returns
313 ``GitPython.Repo`` (the newly forked repo)
314 """
315 options = {'bare': True}
316 options.update(kwargs)
317 self.git.clone(self.path, path, **options)
318 return Repo(path)
319
320 def archive_tar(self, treeish = 'master', prefix = None):
321 """
322 Archive the given treeish
323
324 ``treeish``
325 is the treeish name/id (default 'master')
326
327 ``prefix``
328 is the optional prefix
329
330 Examples::
331
332 >>> repo.archive_tar
333 <String containing tar archive>
334
335 >>> repo.archive_tar('a87ff14')
336 <String containing tar archive for commit a87ff14>
337
338 >>> repo.archive_tar('master', 'myproject/')
339 <String containing tar archive and prefixed with 'myproject/'>
340
341 Returns
342 str (containing tar archive)
343 """
344 options = {}
345 if prefix:
346 options['prefix'] = prefix
347 return self.git.archive(treeish, **options)
348
349 def archive_tar_gz(self, treeish = 'master', prefix = None):
350 """
351 Archive and gzip the given treeish
352
353 ``treeish``
354 is the treeish name/id (default 'master')
355
356 ``prefix``
357 is the optional prefix
358
359 Examples::
360
361 >>> repo.archive_tar_gz
362 <String containing tar.gz archive>
363
364 >>> repo.archive_tar_gz('a87ff14')
365 <String containing tar.gz archive for commit a87ff14>
366
367 >>> repo.archive_tar_gz('master', 'myproject/')
368 <String containing tar.gz archive and prefixed with 'myproject/'>
369
370 Returns
371 str (containing tar.gz archive)
372 """
373 kwargs = {}
374 if prefix:
375 kwargs['prefix'] = prefix
376 self.git.archive(treeish, "| gzip", **kwargs)
377
378 def enable_daemon_serve(self):
379 """
380 Enable git-daemon serving of this repository by writing the
381 git-daemon-export-ok file to its git directory
382
383 Returns
384 None
385 """
386 touch(os.path.join(self.path, DAEMON_EXPORT_FILE))
387
388 def disable_daemon_serve(self):
389 """
390 Disable git-daemon serving of this repository by ensuring there is no
391 git-daemon-export-ok file in its git directory
392
393 Returns
394 None
395 """
396 return os.remove(os.path.join(self.path, DAEMON_EXPORT_FILE))
397
398 def _get_alternates(self):
399 """
400 The list of alternates for this repo
401
402 Returns
403 list[str] (pathnames of alternates)
404 """
405 alternates_path = os.path.join(self.path, *['objects', 'info', 'alternates'])
406
407 if os.path.exists(alternates_path):
408 try:
409 f = open(alternates_path)
410 alts = f.read()
411 finally:
412 f.close()
413 return alts.strip().splitlines()
414 else:
415 return []
416
417 def _set_alternates(self, alts):
418 """
419 Sets the alternates
420
421 ``alts``
422 is the Array of String paths representing the alternates
423
424 Returns
425 None
426 """
427 for alt in alts:
428 if not os.path.exists(alt):
429 raise NoSuchPathError("Could not set alternates. Alternate path %s must exist" % alt)
430
431 if not alts:
432 os.remove(os.path.join(self.path, *['objects', 'info', 'alternates']))
433 else:
434 try:
435 f = open(os.path.join(self.path, *['objects', 'info', 'alternates']), 'w')
436 f.write("\n".join(alts))
437 finally:
438 f.close()
439
440 alternates = property(_get_alternates, _set_alternates)
441
442 def __repr__(self):
443 return '<GitPython.Repo "%s">' % self.path
0 # stats.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 class Stats(object):
7 def __init__(self, repo, total, files):
8 self.repo = repo
9 self.total = total
10 self.files = files
11
12 @classmethod
13 def list_from_string(cls, repo, text):
14 hsh = {'total': {'insertions': 0, 'deletions': 0, 'lines': 0, 'files': 0}, 'files': {}}
15 for line in text.splitlines():
16 (raw_insertions, raw_deletions, filename) = line.split("\t")
17 insertions = raw_insertions != '-' and int(raw_insertions) or 0
18 deletions = raw_deletions != '-' and int(raw_deletions) or 0
19 hsh['total']['insertions'] += insertions
20 hsh['total']['deletions'] += deletions
21 hsh['total']['lines'] += insertions + deletions
22 hsh['total']['files'] += 1
23 hsh['files'][filename.strip()] = {'insertions': insertions,
24 'deletions': deletions,
25 'lines': insertions + deletions}
26 return Stats(repo, hsh['total'], hsh['files'])
0 # tag.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 from commit import Commit
7
8 class Tag(object):
9 def __init__(self, name, commit):
10 """
11 Instantiate a new Tag
12
13 ``name``
14 is the name of the head
15
16 ``commit``
17 is the Commit that the head points to
18
19 Returns
20 ``GitPython.Tag``
21 """
22 self.name = name
23 self.commit = commit
24
25 @classmethod
26 def find_all(cls, repo, **kwargs):
27 """
28 Find all Tags
29
30 ``repo``
31 is the Repo
32
33 ``kwargs``
34 is a dict of options
35
36 Returns
37 ``GitPython.Tag[]``
38 """
39 options = {'sort': "committerdate",
40 'format': "%(refname)%00%(objectname)"}
41 options.update(**kwargs)
42
43 output = repo.git.for_each_ref("refs/tags", **options)
44 return cls.list_from_string(repo, output)
45
46 @classmethod
47 def list_from_string(cls, repo, text):
48 """
49 Parse out tag information into an array of baked Tag objects
50
51 ``repo``
52 is the Repo
53
54 ``text``
55 is the text output from the git command
56
57 Returns
58 ``GitPython.Tag[]``
59 """
60 tags = []
61 for line in text.splitlines():
62 tags.append(cls.from_string(repo, line))
63 return tags
64
65 @classmethod
66 def from_string(cls, repo, line):
67 """
68 Create a new Tag instance from the given string.
69
70 ``repo``
71 is the Repo
72
73 ``line``
74 is the formatted tag information
75
76 Format
77 name: [a-zA-Z_/]+
78 <null byte>
79 id: [0-9A-Fa-f]{40}
80
81 Returns
82 ``GitPython.Tag``
83 """
84 full_name, ids = line.split("\x00")
85 name = full_name.split("/")[-1]
86 commit = Commit(repo, **{'id': ids})
87 return Tag(name, commit)
88
89 def __repr__(self):
90 return '<GitPython.Tag "%s">' % self.name
0 # tree.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 import os
7 from lazy import LazyMixin
8 import blob
9
10 class Tree(LazyMixin):
11 def __init__(self, repo, **kwargs):
12 LazyMixin.__init__(self)
13 self.repo = repo
14 self.id = None
15 self.mode = None
16 self.name = None
17 self.contents = None
18
19 for k, v in kwargs.items():
20 setattr(self, k, v)
21
22 def __bake__(self):
23 temp = Tree.construct(self.repo, self.id)
24 self.contents = temp.contents
25
26 @classmethod
27 def construct(cls, repo, treeish, paths = []):
28 output = repo.git.ls_tree(treeish, *paths)
29 return Tree(repo, **{'id': treeish}).construct_initialize(repo, treeish, output)
30
31 def construct_initialize(self, repo, id, text):
32 self.repo = repo
33 self.id = id
34 self.contents = []
35 self.__baked__ = False
36
37 for line in text.splitlines():
38 self.contents.append(self.content_from_string(self.repo, line))
39
40 self.contents = [c for c in self.contents if c is not None]
41
42 self.__bake_it__()
43 return self
44
45 def content_from_string(self, repo, text):
46 """
47 Parse a content item and create the appropriate object
48
49 ``repo``
50 is the Repo
51
52 ``text``
53 is the single line containing the items data in `git ls-tree` format
54
55 Returns
56 ``GitPython.Blob`` or ``GitPython.Tree``
57 """
58 try:
59 mode, typ, id, name = text.expandtabs(1).split(" ", 4)
60 except:
61 return None
62
63 if typ == "tree":
64 return Tree(repo, **{'id': id, 'mode': mode, 'name': name})
65 elif typ == "blob":
66 return blob.Blob(repo, **{'id': id, 'mode': mode, 'name': name})
67 elif typ == "commit":
68 return None
69 else:
70 raise(TypeError, "Invalid type: %s" % typ)
71
72 def __div__(self, file):
73 """
74 Find the named object in this tree's contents
75
76 Examples::
77
78 >>> Repo('/path/to/python-git').tree/'lib'
79 <GitPython.Tree "6cc23ee138be09ff8c28b07162720018b244e95e">
80 >>> Repo('/path/to/python-git').tree/'README.txt'
81 <GitPython.Blob "8b1e02c0fb554eed2ce2ef737a68bb369d7527df">
82
83 Returns
84 ``GitPython.Blob`` or ``GitPython.Tree`` or ``None`` if not found
85 """
86 contents = [c for c in self.contents if c.name == file]
87 return contents and contents[0] or None
88
89 @property
90 def basename(self):
91 os.path.basename(self.name)
92
93 def __repr__(self):
94 return '<GitPython.Tree "%s">' % self.id
0 # utils.py
1 # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors
2 #
3 # This module is part of GitPython and is released under
4 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
5
6 import os
7
8 def dashify(string):
9 return string.replace('_', '-')
10
11 def touch(filename):
12 os.utime(filename)
13
14 def is_git_dir(d):
15 """ This is taken from the git setup.c:is_git_directory
16 function."""
17
18 if os.path.isdir(d) and \
19 os.path.isdir(os.path.join(d, 'objects')) and \
20 os.path.isdir(os.path.join(d, 'refs')):
21 headref = os.path.join(d, 'HEAD')
22 return os.path.isfile(headref) or \
23 (os.path.islink(headref) and
24 os.readlink(headref).startswith('refs'))
25 return False
0 [egg_info]
1 tag_build =
2 tag_date = 0
3 tag_svn_revision = 0
4
0 from ez_setup import use_setuptools
1 use_setuptools()
2 from setuptools import setup, find_packages
3 from distutils.command.build_py import build_py as _build_py
4 from setuptools.command.sdist import sdist as _sdist
5 import os
6 from os import path
7
8 v = open(path.join(path.dirname(__file__), 'VERSION'))
9 VERSION = v.readline().strip()
10 v.close()
11
12 class build_py(_build_py):
13 def run(self):
14 init = path.join(self.build_lib, 'git', '__init__.py')
15 if path.exists(init):
16 os.unlink(init)
17 _build_py.run(self)
18 _stamp_version(init)
19 self.byte_compile([init])
20
21 class sdist(_sdist):
22 def make_release_tree (self, base_dir, files):
23 _sdist.make_release_tree(self, base_dir, files)
24 orig = path.join('lib', 'git', '__init__.py')
25 assert path.exists(orig)
26 dest = path.join(base_dir, orig)
27 if hasattr(os, 'link') and path.exists(dest):
28 os.unlink(dest)
29 self.copy_file(orig, dest)
30 _stamp_version(dest)
31
32 def _stamp_version(filename):
33 found, out = False, []
34 f = open(filename, 'r')
35 for line in f:
36 if '__version__ =' in line:
37 line = line.replace("'git'", "'%s'" % VERSION)
38 found = True
39 out.append(line)
40 f.close()
41
42 if found:
43 f = open(filename, 'w')
44 f.writelines(out)
45 f.close()
46
47
48 setup(name = "GitPython",
49 cmdclass={'build_py': build_py, 'sdist': sdist},
50 version = VERSION,
51 description = "Python Git Library",
52 author = "Michael Trier",
53 author_email = "mtrier@gmail.com",
54 url = "http://gitorious.org/projects/git-python/",
55 packages = find_packages('lib'),
56 package_dir = {'':'lib'},
57 license = "BSD License",
58 long_description = """\
59 GitPython is a python library used to interact with Git repositories.
60
61 GitPython provides object model access to your git repository. Once you have
62 created a repository object, you can traverse it to find parent commit(s),
63 trees, blobs, etc.
64
65 GitPython is a port of the grit library in Ruby created by
66 Tom Preston-Werner and Chris Wanstrath.
67 """,
68 classifiers = [
69 "Development Status :: 3 - Alpha",
70 "Intended Audience :: Developers",
71 "License :: OSI Approved :: BSD License",
72 "Programming Language :: Python",
73 "Topic :: Software Development :: Libraries :: Python Modules",
74 ]
75 )