Provide a method to write a tree to an archive
Add Repository.write_archive() to write a given tree to an archive. As there are many customisation options, we only provide a method to write to an archive which is created by the user.
This commit is contained in:
		| @@ -69,3 +69,4 @@ Below there are some general attributes and methods: | ||||
| .. automethod:: pygit2.Repository.write | ||||
| .. automethod:: pygit2.Repository.reset | ||||
| .. automethod:: pygit2.Repository.state_cleanup | ||||
| .. automethod:: pygit2.Repository.write_archive | ||||
|   | ||||
| @@ -35,6 +35,7 @@ from string import hexdigits | ||||
| from _pygit2 import Repository as _Repository | ||||
| from _pygit2 import Oid, GIT_OID_HEXSZ, GIT_OID_MINPREFIXLEN | ||||
| from _pygit2 import GIT_CHECKOUT_SAFE_CREATE, GIT_DIFF_NORMAL | ||||
| from _pygit2 import GIT_FILEMODE_LINK | ||||
| from _pygit2 import Reference, Tree, Commit, Blob | ||||
|  | ||||
| from .config import Config | ||||
| @@ -43,7 +44,7 @@ from .ffi import ffi, C | ||||
| from .index import Index | ||||
| from .remote import Remote | ||||
| from .blame import Blame | ||||
| from .utils import to_bytes, to_str | ||||
| from .utils import to_bytes, to_str, is_string | ||||
|  | ||||
|  | ||||
| class Repository(_Repository): | ||||
| @@ -488,3 +489,73 @@ class Repository(_Repository): | ||||
|         check_error(err, True) | ||||
|  | ||||
|         return Index.from_c(self, cindex) | ||||
|  | ||||
|     # | ||||
|     # Utility for writing a tree into an archive | ||||
|     # | ||||
|     def write_archive(self, treeish, archive, timestamp=None): | ||||
|         """Write treeish into an archive | ||||
|  | ||||
|         If no timestamp is provided and 'treeish' is a commit, its committer | ||||
|         timestamp will be used. Otherwise the current time will be used. | ||||
|  | ||||
|         Arguments: | ||||
|  | ||||
|         treeish | ||||
|             The treeish to write. | ||||
|         archive | ||||
|             An archive from the 'tarfile' module | ||||
|         timestamp | ||||
|             Timestamp to use for the files in the archive. | ||||
|  | ||||
|         Example:: | ||||
|  | ||||
|             >>> import tarfile, pygit2 | ||||
|             >>>> with tarfile.open('foo.tar', 'w') as archive: | ||||
|             >>>>     repo = pygit2.Repsitory('.') | ||||
|             >>>>     repo.write_archive(archive, repo.head.target) | ||||
|         """ | ||||
|  | ||||
|         import tarfile, sys | ||||
|         from time import time | ||||
|         if sys.version_info[0] < 3: | ||||
|             from cStringIO import StringIO | ||||
|         else: | ||||
|             from io import BytesIO as StringIO | ||||
|  | ||||
|         # Try to get a tree form whatever we got | ||||
|         if isinstance(treeish, Tree): | ||||
|             tree = treeish | ||||
|  | ||||
|         if isinstance(treeish, Oid) or is_string(treeish): | ||||
|             treeish = self[treeish] | ||||
|  | ||||
|         # if we don't have a timestamp, try to get it from a commit | ||||
|         if not timestamp: | ||||
|             try: | ||||
|                 commit = treeish.peel(Commit) | ||||
|                 timestamp = commit.committer.time | ||||
|             except: | ||||
|                 pass | ||||
|  | ||||
|         # as a last resort, use the current timestamp | ||||
|         if not timestamp: | ||||
|             timestamp = int(time()) | ||||
|  | ||||
|         tree = treeish.peel(Tree) | ||||
|  | ||||
|         index = Index() | ||||
|         index.read_tree(tree) | ||||
|  | ||||
|         for entry in index: | ||||
|             content = self[entry.id].read_raw() | ||||
|             info = tarfile.TarInfo(entry.path) | ||||
|             info.size = len(content) | ||||
|             info.mtime = timestamp | ||||
|             info.uname = info.gname = 'root' # just because git does this | ||||
|             if entry.mode == GIT_FILEMODE_LINK: | ||||
|                 info.type = archive.SYMTYPE | ||||
|                 info.linkname = content | ||||
|                 info.mode = 0o777 # symlinks get placeholder | ||||
|  | ||||
|             archive.addfile(info, StringIO(content)) | ||||
|   | ||||
							
								
								
									
										74
									
								
								test/test_archive.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								test/test_archive.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| # -*- coding: UTF-8 -*- | ||||
| # | ||||
| # Copyright 2010-2014 The pygit2 contributors | ||||
| # | ||||
| # This file is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License, version 2, | ||||
| # as published by the Free Software Foundation. | ||||
| # | ||||
| # In addition to the permissions in the GNU General Public License, | ||||
| # the authors give you unlimited permission to link the compiled | ||||
| # version of this file into combinations with other programs, | ||||
| # and to distribute those combinations without any restriction | ||||
| # coming from the use of this file.  (The General Public License | ||||
| # restrictions do apply in other respects; for example, they cover | ||||
| # modification of the file, and distribution when not linked into | ||||
| # a combined executable.) | ||||
| # | ||||
| # This file is distributed in the hope that it will be useful, but | ||||
| # WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
| # General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; see the file COPYING.  If not, write to | ||||
| # the Free Software Foundation, 51 Franklin Street, Fifth Floor, | ||||
| # Boston, MA 02110-1301, USA. | ||||
|  | ||||
| """Tests for Blame objects.""" | ||||
|  | ||||
| from __future__ import absolute_import | ||||
| from __future__ import unicode_literals | ||||
| import unittest | ||||
| import pygit2 | ||||
| from pygit2 import Index, Oid, Tree, Object | ||||
| import tarfile | ||||
| import os | ||||
| from . import utils | ||||
| from time import time | ||||
|  | ||||
| TREE_HASH = 'fd937514cb799514d4b81bb24c5fcfeb6472b245' | ||||
| COMMIT_HASH = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98' | ||||
|  | ||||
| class ArchiveTest(utils.RepoTestCase): | ||||
|  | ||||
|     def check_writing(self, treeish, timestamp=None): | ||||
|         archive = tarfile.open('foo.tar', mode='w') | ||||
|         self.repo.write_archive(treeish, archive) | ||||
|  | ||||
|         index = Index() | ||||
|         if isinstance(treeish, Object): | ||||
|             index.read_tree(treeish.peel(Tree)) | ||||
|         else: | ||||
|             index.read_tree(self.repo[treeish].peel(Tree)) | ||||
|      | ||||
|         self.assertEqual(len(index), len(archive.getmembers())) | ||||
|  | ||||
|         if timestamp: | ||||
|             fileinfo = archive.getmembers()[0] | ||||
|             self.assertEqual(timestamp, fileinfo.mtime) | ||||
|  | ||||
|         archive.close() | ||||
|         self.assertTrue(os.path.isfile('foo.tar')) | ||||
|         os.remove('foo.tar') | ||||
|      | ||||
|     def test_write_tree(self): | ||||
|         self.check_writing(TREE_HASH) | ||||
|         self.check_writing(Oid(hex=TREE_HASH)) | ||||
|         self.check_writing(self.repo[TREE_HASH]) | ||||
|  | ||||
|     def test_write_commit(self): | ||||
|         commit_timestamp = self.repo[COMMIT_HASH].committer.time | ||||
|         self.check_writing(COMMIT_HASH, commit_timestamp) | ||||
|         self.check_writing(Oid(hex=COMMIT_HASH), commit_timestamp) | ||||
|         self.check_writing(self.repo[COMMIT_HASH], commit_timestamp) | ||||
		Reference in New Issue
	
	Block a user
	 Carlos Martín Nieto
					Carlos Martín Nieto