test_archive_util.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. # -*- coding: utf-8 -*-
  2. """Tests for distutils.archive_util."""
  3. import unittest
  4. import os
  5. import sys
  6. import tarfile
  7. from os.path import splitdrive
  8. import warnings
  9. from distutils import archive_util
  10. from distutils.archive_util import (check_archive_formats, make_tarball,
  11. make_zipfile, make_archive,
  12. ARCHIVE_FORMATS)
  13. from distutils.spawn import find_executable, spawn
  14. from distutils.tests import support
  15. from test.support import check_warnings, run_unittest, patch, change_cwd
  16. try:
  17. import grp
  18. import pwd
  19. UID_GID_SUPPORT = True
  20. except ImportError:
  21. UID_GID_SUPPORT = False
  22. try:
  23. import zipfile
  24. ZIP_SUPPORT = True
  25. except ImportError:
  26. ZIP_SUPPORT = find_executable('zip')
  27. try:
  28. import zlib
  29. ZLIB_SUPPORT = True
  30. except ImportError:
  31. ZLIB_SUPPORT = False
  32. try:
  33. import bz2
  34. except ImportError:
  35. bz2 = None
  36. try:
  37. import lzma
  38. except ImportError:
  39. lzma = None
  40. def can_fs_encode(filename):
  41. """
  42. Return True if the filename can be saved in the file system.
  43. """
  44. if os.path.supports_unicode_filenames:
  45. return True
  46. try:
  47. filename.encode(sys.getfilesystemencoding())
  48. except UnicodeEncodeError:
  49. return False
  50. return True
  51. class ArchiveUtilTestCase(support.TempdirManager,
  52. support.LoggingSilencer,
  53. unittest.TestCase):
  54. @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
  55. def test_make_tarball(self, name='archive'):
  56. # creating something to tar
  57. tmpdir = self._create_files()
  58. self._make_tarball(tmpdir, name, '.tar.gz')
  59. # trying an uncompressed one
  60. self._make_tarball(tmpdir, name, '.tar', compress=None)
  61. @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
  62. def test_make_tarball_gzip(self):
  63. tmpdir = self._create_files()
  64. self._make_tarball(tmpdir, 'archive', '.tar.gz', compress='gzip')
  65. @unittest.skipUnless(bz2, 'Need bz2 support to run')
  66. def test_make_tarball_bzip2(self):
  67. tmpdir = self._create_files()
  68. self._make_tarball(tmpdir, 'archive', '.tar.bz2', compress='bzip2')
  69. @unittest.skipUnless(lzma, 'Need lzma support to run')
  70. def test_make_tarball_xz(self):
  71. tmpdir = self._create_files()
  72. self._make_tarball(tmpdir, 'archive', '.tar.xz', compress='xz')
  73. @unittest.skipUnless(can_fs_encode('årchiv'),
  74. 'File system cannot handle this filename')
  75. def test_make_tarball_latin1(self):
  76. """
  77. Mirror test_make_tarball, except filename contains latin characters.
  78. """
  79. self.test_make_tarball('årchiv') # note this isn't a real word
  80. @unittest.skipUnless(can_fs_encode('のアーカイブ'),
  81. 'File system cannot handle this filename')
  82. def test_make_tarball_extended(self):
  83. """
  84. Mirror test_make_tarball, except filename contains extended
  85. characters outside the latin charset.
  86. """
  87. self.test_make_tarball('のアーカイブ') # japanese for archive
  88. def _make_tarball(self, tmpdir, target_name, suffix, **kwargs):
  89. tmpdir2 = self.mkdtemp()
  90. unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
  91. "source and target should be on same drive")
  92. base_name = os.path.join(tmpdir2, target_name)
  93. # working with relative paths to avoid tar warnings
  94. with change_cwd(tmpdir):
  95. make_tarball(splitdrive(base_name)[1], 'dist', **kwargs)
  96. # check if the compressed tarball was created
  97. tarball = base_name + suffix
  98. self.assertTrue(os.path.exists(tarball))
  99. self.assertEqual(self._tarinfo(tarball), self._created_files)
  100. def _tarinfo(self, path):
  101. tar = tarfile.open(path)
  102. try:
  103. names = tar.getnames()
  104. names.sort()
  105. return names
  106. finally:
  107. tar.close()
  108. _zip_created_files = ['dist/', 'dist/file1', 'dist/file2',
  109. 'dist/sub/', 'dist/sub/file3', 'dist/sub2/']
  110. _created_files = [p.rstrip('/') for p in _zip_created_files]
  111. def _create_files(self):
  112. # creating something to tar
  113. tmpdir = self.mkdtemp()
  114. dist = os.path.join(tmpdir, 'dist')
  115. os.mkdir(dist)
  116. self.write_file([dist, 'file1'], 'xxx')
  117. self.write_file([dist, 'file2'], 'xxx')
  118. os.mkdir(os.path.join(dist, 'sub'))
  119. self.write_file([dist, 'sub', 'file3'], 'xxx')
  120. os.mkdir(os.path.join(dist, 'sub2'))
  121. return tmpdir
  122. @unittest.skipUnless(find_executable('tar') and find_executable('gzip')
  123. and ZLIB_SUPPORT,
  124. 'Need the tar, gzip and zlib command to run')
  125. def test_tarfile_vs_tar(self):
  126. tmpdir = self._create_files()
  127. tmpdir2 = self.mkdtemp()
  128. base_name = os.path.join(tmpdir2, 'archive')
  129. old_dir = os.getcwd()
  130. os.chdir(tmpdir)
  131. try:
  132. make_tarball(base_name, 'dist')
  133. finally:
  134. os.chdir(old_dir)
  135. # check if the compressed tarball was created
  136. tarball = base_name + '.tar.gz'
  137. self.assertTrue(os.path.exists(tarball))
  138. # now create another tarball using `tar`
  139. tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
  140. tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
  141. gzip_cmd = ['gzip', '-f', '-9', 'archive2.tar']
  142. old_dir = os.getcwd()
  143. os.chdir(tmpdir)
  144. try:
  145. spawn(tar_cmd)
  146. spawn(gzip_cmd)
  147. finally:
  148. os.chdir(old_dir)
  149. self.assertTrue(os.path.exists(tarball2))
  150. # let's compare both tarballs
  151. self.assertEqual(self._tarinfo(tarball), self._created_files)
  152. self.assertEqual(self._tarinfo(tarball2), self._created_files)
  153. # trying an uncompressed one
  154. base_name = os.path.join(tmpdir2, 'archive')
  155. old_dir = os.getcwd()
  156. os.chdir(tmpdir)
  157. try:
  158. make_tarball(base_name, 'dist', compress=None)
  159. finally:
  160. os.chdir(old_dir)
  161. tarball = base_name + '.tar'
  162. self.assertTrue(os.path.exists(tarball))
  163. # now for a dry_run
  164. base_name = os.path.join(tmpdir2, 'archive')
  165. old_dir = os.getcwd()
  166. os.chdir(tmpdir)
  167. try:
  168. make_tarball(base_name, 'dist', compress=None, dry_run=True)
  169. finally:
  170. os.chdir(old_dir)
  171. tarball = base_name + '.tar'
  172. self.assertTrue(os.path.exists(tarball))
  173. @unittest.skipUnless(find_executable('compress'),
  174. 'The compress program is required')
  175. def test_compress_deprecated(self):
  176. tmpdir = self._create_files()
  177. base_name = os.path.join(self.mkdtemp(), 'archive')
  178. # using compress and testing the PendingDeprecationWarning
  179. old_dir = os.getcwd()
  180. os.chdir(tmpdir)
  181. try:
  182. with check_warnings() as w:
  183. warnings.simplefilter("always")
  184. make_tarball(base_name, 'dist', compress='compress')
  185. finally:
  186. os.chdir(old_dir)
  187. tarball = base_name + '.tar.Z'
  188. self.assertTrue(os.path.exists(tarball))
  189. self.assertEqual(len(w.warnings), 1)
  190. # same test with dry_run
  191. os.remove(tarball)
  192. old_dir = os.getcwd()
  193. os.chdir(tmpdir)
  194. try:
  195. with check_warnings() as w:
  196. warnings.simplefilter("always")
  197. make_tarball(base_name, 'dist', compress='compress',
  198. dry_run=True)
  199. finally:
  200. os.chdir(old_dir)
  201. self.assertFalse(os.path.exists(tarball))
  202. self.assertEqual(len(w.warnings), 1)
  203. @unittest.skipUnless(ZIP_SUPPORT and ZLIB_SUPPORT,
  204. 'Need zip and zlib support to run')
  205. def test_make_zipfile(self):
  206. # creating something to tar
  207. tmpdir = self._create_files()
  208. base_name = os.path.join(self.mkdtemp(), 'archive')
  209. with change_cwd(tmpdir):
  210. make_zipfile(base_name, 'dist')
  211. # check if the compressed tarball was created
  212. tarball = base_name + '.zip'
  213. self.assertTrue(os.path.exists(tarball))
  214. with zipfile.ZipFile(tarball) as zf:
  215. self.assertEqual(sorted(zf.namelist()), self._zip_created_files)
  216. @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
  217. def test_make_zipfile_no_zlib(self):
  218. patch(self, archive_util.zipfile, 'zlib', None) # force zlib ImportError
  219. called = []
  220. zipfile_class = zipfile.ZipFile
  221. def fake_zipfile(*a, **kw):
  222. if kw.get('compression', None) == zipfile.ZIP_STORED:
  223. called.append((a, kw))
  224. return zipfile_class(*a, **kw)
  225. patch(self, archive_util.zipfile, 'ZipFile', fake_zipfile)
  226. # create something to tar and compress
  227. tmpdir = self._create_files()
  228. base_name = os.path.join(self.mkdtemp(), 'archive')
  229. with change_cwd(tmpdir):
  230. make_zipfile(base_name, 'dist')
  231. tarball = base_name + '.zip'
  232. self.assertEqual(called,
  233. [((tarball, "w"), {'compression': zipfile.ZIP_STORED})])
  234. self.assertTrue(os.path.exists(tarball))
  235. with zipfile.ZipFile(tarball) as zf:
  236. self.assertEqual(sorted(zf.namelist()), self._zip_created_files)
  237. def test_check_archive_formats(self):
  238. self.assertEqual(check_archive_formats(['gztar', 'xxx', 'zip']),
  239. 'xxx')
  240. self.assertIsNone(check_archive_formats(['gztar', 'bztar', 'xztar',
  241. 'ztar', 'tar', 'zip']))
  242. def test_make_archive(self):
  243. tmpdir = self.mkdtemp()
  244. base_name = os.path.join(tmpdir, 'archive')
  245. self.assertRaises(ValueError, make_archive, base_name, 'xxx')
  246. def test_make_archive_cwd(self):
  247. current_dir = os.getcwd()
  248. def _breaks(*args, **kw):
  249. raise RuntimeError()
  250. ARCHIVE_FORMATS['xxx'] = (_breaks, [], 'xxx file')
  251. try:
  252. try:
  253. make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
  254. except:
  255. pass
  256. self.assertEqual(os.getcwd(), current_dir)
  257. finally:
  258. del ARCHIVE_FORMATS['xxx']
  259. def test_make_archive_tar(self):
  260. base_dir = self._create_files()
  261. base_name = os.path.join(self.mkdtemp() , 'archive')
  262. res = make_archive(base_name, 'tar', base_dir, 'dist')
  263. self.assertTrue(os.path.exists(res))
  264. self.assertEqual(os.path.basename(res), 'archive.tar')
  265. self.assertEqual(self._tarinfo(res), self._created_files)
  266. @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
  267. def test_make_archive_gztar(self):
  268. base_dir = self._create_files()
  269. base_name = os.path.join(self.mkdtemp() , 'archive')
  270. res = make_archive(base_name, 'gztar', base_dir, 'dist')
  271. self.assertTrue(os.path.exists(res))
  272. self.assertEqual(os.path.basename(res), 'archive.tar.gz')
  273. self.assertEqual(self._tarinfo(res), self._created_files)
  274. @unittest.skipUnless(bz2, 'Need bz2 support to run')
  275. def test_make_archive_bztar(self):
  276. base_dir = self._create_files()
  277. base_name = os.path.join(self.mkdtemp() , 'archive')
  278. res = make_archive(base_name, 'bztar', base_dir, 'dist')
  279. self.assertTrue(os.path.exists(res))
  280. self.assertEqual(os.path.basename(res), 'archive.tar.bz2')
  281. self.assertEqual(self._tarinfo(res), self._created_files)
  282. @unittest.skipUnless(lzma, 'Need xz support to run')
  283. def test_make_archive_xztar(self):
  284. base_dir = self._create_files()
  285. base_name = os.path.join(self.mkdtemp() , 'archive')
  286. res = make_archive(base_name, 'xztar', base_dir, 'dist')
  287. self.assertTrue(os.path.exists(res))
  288. self.assertEqual(os.path.basename(res), 'archive.tar.xz')
  289. self.assertEqual(self._tarinfo(res), self._created_files)
  290. def test_make_archive_owner_group(self):
  291. # testing make_archive with owner and group, with various combinations
  292. # this works even if there's not gid/uid support
  293. if UID_GID_SUPPORT:
  294. group = grp.getgrgid(0)[0]
  295. owner = pwd.getpwuid(0)[0]
  296. else:
  297. group = owner = 'root'
  298. base_dir = self._create_files()
  299. root_dir = self.mkdtemp()
  300. base_name = os.path.join(self.mkdtemp() , 'archive')
  301. res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
  302. group=group)
  303. self.assertTrue(os.path.exists(res))
  304. res = make_archive(base_name, 'zip', root_dir, base_dir)
  305. self.assertTrue(os.path.exists(res))
  306. res = make_archive(base_name, 'tar', root_dir, base_dir,
  307. owner=owner, group=group)
  308. self.assertTrue(os.path.exists(res))
  309. res = make_archive(base_name, 'tar', root_dir, base_dir,
  310. owner='kjhkjhkjg', group='oihohoh')
  311. self.assertTrue(os.path.exists(res))
  312. @unittest.skipUnless(ZLIB_SUPPORT, "Requires zlib")
  313. @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
  314. def test_tarfile_root_owner(self):
  315. tmpdir = self._create_files()
  316. base_name = os.path.join(self.mkdtemp(), 'archive')
  317. old_dir = os.getcwd()
  318. os.chdir(tmpdir)
  319. group = grp.getgrgid(0)[0]
  320. owner = pwd.getpwuid(0)[0]
  321. try:
  322. archive_name = make_tarball(base_name, 'dist', compress=None,
  323. owner=owner, group=group)
  324. finally:
  325. os.chdir(old_dir)
  326. # check if the compressed tarball was created
  327. self.assertTrue(os.path.exists(archive_name))
  328. # now checks the rights
  329. archive = tarfile.open(archive_name)
  330. try:
  331. for member in archive.getmembers():
  332. self.assertEqual(member.uid, 0)
  333. self.assertEqual(member.gid, 0)
  334. finally:
  335. archive.close()
  336. def test_suite():
  337. return unittest.makeSuite(ArchiveUtilTestCase)
  338. if __name__ == "__main__":
  339. run_unittest(test_suite())