1 """Tests for distutils.command.sdist.""" 2 import os 3 import unittest 4 import shutil 5 import zipfile 6 import tarfile 7 8 # zlib is not used here, but if it's not available 9 # the tests that use zipfile may fail 10 try: 11 import zlib 12 except ImportError: 13 zlib = None 14 15 try: 16 import grp 17 import pwd 18 UID_GID_SUPPORT = True 19 except ImportError: 20 UID_GID_SUPPORT = False 21 22 from os.path import join 23 import sys 24 import tempfile 25 import warnings 26 27 from test.test_support import captured_stdout, check_warnings, run_unittest 28 29 from distutils.command.sdist import sdist, show_formats 30 from distutils.core import Distribution 31 from distutils.tests.test_config import PyPIRCCommandTestCase 32 from distutils.errors import DistutilsExecError, DistutilsOptionError 33 from distutils.spawn import find_executable 34 from distutils.tests import support 35 from distutils.log import WARN 36 from distutils.archive_util import ARCHIVE_FORMATS 37 38 SETUP_PY = """ 39 from distutils.core import setup 40 import somecode 41 42 setup(name='fake') 43 """ 44 45 MANIFEST = """\ 46 # file GENERATED by distutils, do NOT edit 47 README 48 inroot.txt 49 setup.py 50 data%(sep)sdata.dt 51 scripts%(sep)sscript.py 52 some%(sep)sfile.txt 53 some%(sep)sother_file.txt 54 somecode%(sep)s__init__.py 55 somecode%(sep)sdoc.dat 56 somecode%(sep)sdoc.txt 57 """ 58 59 class SDistTestCase(PyPIRCCommandTestCase): 60 61 def setUp(self): 62 # PyPIRCCommandTestCase creates a temp dir already 63 # and put it in self.tmp_dir 64 super(SDistTestCase, self).setUp() 65 # setting up an environment 66 self.old_path = os.getcwd() 67 os.mkdir(join(self.tmp_dir, 'somecode')) 68 os.mkdir(join(self.tmp_dir, 'dist')) 69 # a package, and a README 70 self.write_file((self.tmp_dir, 'README'), 'xxx') 71 self.write_file((self.tmp_dir, 'somecode', '__init__.py'), '#') 72 self.write_file((self.tmp_dir, 'setup.py'), SETUP_PY) 73 os.chdir(self.tmp_dir) 74 75 def tearDown(self): 76 # back to normal 77 os.chdir(self.old_path) 78 super(SDistTestCase, self).tearDown() 79 80 def get_cmd(self, metadata=None): 81 """Returns a cmd""" 82 if metadata is None: 83 metadata = {'name': 'fake', 'version': '1.0', 84 'url': 'xxx', 'author': 'xxx', 85 'author_email': 'xxx'} 86 dist = Distribution(metadata) 87 dist.script_name = 'setup.py' 88 dist.packages = ['somecode'] 89 dist.include_package_data = True 90 cmd = sdist(dist) 91 cmd.dist_dir = 'dist' 92 def _warn(*args): 93 pass 94 cmd.warn = _warn 95 return dist, cmd 96 97 @unittest.skipUnless(zlib, "requires zlib") 98 def test_prune_file_list(self): 99 # this test creates a package with some vcs dirs in it 100 # and launch sdist to make sure they get pruned 101 # on all systems 102 103 # creating VCS directories with some files in them 104 os.mkdir(join(self.tmp_dir, 'somecode', '.svn')) 105 self.write_file((self.tmp_dir, 'somecode', '.svn', 'ok.py'), 'xxx') 106 107 os.mkdir(join(self.tmp_dir, 'somecode', '.hg')) 108 self.write_file((self.tmp_dir, 'somecode', '.hg', 109 'ok'), 'xxx') 110 111 os.mkdir(join(self.tmp_dir, 'somecode', '.git')) 112 self.write_file((self.tmp_dir, 'somecode', '.git', 113 'ok'), 'xxx') 114 115 # now building a sdist 116 dist, cmd = self.get_cmd() 117 118 # zip is available universally 119 # (tar might not be installed under win32) 120 cmd.formats = ['zip'] 121 122 cmd.ensure_finalized() 123 cmd.run() 124 125 # now let's check what we have 126 dist_folder = join(self.tmp_dir, 'dist') 127 files = os.listdir(dist_folder) 128 self.assertEqual(files, ['fake-1.0.zip']) 129 130 zip_file = zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip')) 131 try: 132 content = zip_file.namelist() 133 finally: 134 zip_file.close() 135 136 # making sure everything has been pruned correctly 137 self.assertEqual(len(content), 4) 138 139 @unittest.skipUnless(zlib, "requires zlib") 140 def test_make_distribution(self): 141 142 # check if tar and gzip are installed 143 if (find_executable('tar') is None or 144 find_executable('gzip') is None): 145 return 146 147 # now building a sdist 148 dist, cmd = self.get_cmd() 149 150 # creating a gztar then a tar 151 cmd.formats = ['gztar', 'tar'] 152 cmd.ensure_finalized() 153 cmd.run() 154 155 # making sure we have two files 156 dist_folder = join(self.tmp_dir, 'dist') 157 result = os.listdir(dist_folder) 158 result.sort() 159 self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz'] ) 160 161 os.remove(join(dist_folder, 'fake-1.0.tar')) 162 os.remove(join(dist_folder, 'fake-1.0.tar.gz')) 163 164 # now trying a tar then a gztar 165 cmd.formats = ['tar', 'gztar'] 166 167 cmd.ensure_finalized() 168 cmd.run() 169 170 result = os.listdir(dist_folder) 171 result.sort() 172 self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz']) 173 174 @unittest.skipUnless(zlib, "requires zlib") 175 def test_add_defaults(self): 176 177 # http://bugs.python.org/issue2279 178 179 # add_default should also include 180 # data_files and package_data 181 dist, cmd = self.get_cmd() 182 183 # filling data_files by pointing files 184 # in package_data 185 dist.package_data = {'': ['*.cfg', '*.dat'], 186 'somecode': ['*.txt']} 187 self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#') 188 self.write_file((self.tmp_dir, 'somecode', 'doc.dat'), '#') 189 190 # adding some data in data_files 191 data_dir = join(self.tmp_dir, 'data') 192 os.mkdir(data_dir) 193 self.write_file((data_dir, 'data.dt'), '#') 194 some_dir = join(self.tmp_dir, 'some') 195 os.mkdir(some_dir) 196 self.write_file((self.tmp_dir, 'inroot.txt'), '#') 197 self.write_file((some_dir, 'file.txt'), '#') 198 self.write_file((some_dir, 'other_file.txt'), '#') 199 200 dist.data_files = [('data', ['data/data.dt', 201 'inroot.txt', 202 'notexisting']), 203 'some/file.txt', 204 'some/other_file.txt'] 205 206 # adding a script 207 script_dir = join(self.tmp_dir, 'scripts') 208 os.mkdir(script_dir) 209 self.write_file((script_dir, 'script.py'), '#') 210 dist.scripts = [join('scripts', 'script.py')] 211 212 cmd.formats = ['zip'] 213 cmd.use_defaults = True 214 215 cmd.ensure_finalized() 216 cmd.run() 217 218 # now let's check what we have 219 dist_folder = join(self.tmp_dir, 'dist') 220 files = os.listdir(dist_folder) 221 self.assertEqual(files, ['fake-1.0.zip']) 222 223 zip_file = zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip')) 224 try: 225 content = zip_file.namelist() 226 finally: 227 zip_file.close() 228 229 # making sure everything was added 230 self.assertEqual(len(content), 11) 231 232 # checking the MANIFEST 233 f = open(join(self.tmp_dir, 'MANIFEST')) 234 try: 235 manifest = f.read() 236 self.assertEqual(manifest, MANIFEST % {'sep': os.sep}) 237 finally: 238 f.close() 239 240 @unittest.skipUnless(zlib, "requires zlib") 241 def test_metadata_check_option(self): 242 # testing the `medata-check` option 243 dist, cmd = self.get_cmd(metadata={}) 244 245 # this should raise some warnings ! 246 # with the `check` subcommand 247 cmd.ensure_finalized() 248 cmd.run() 249 warnings = self.get_logs(WARN) 250 self.assertEqual(len(warnings), 2) 251 252 # trying with a complete set of metadata 253 self.clear_logs() 254 dist, cmd = self.get_cmd() 255 cmd.ensure_finalized() 256 cmd.metadata_check = 0 257 cmd.run() 258 warnings = self.get_logs(WARN) 259 self.assertEqual(len(warnings), 0) 260 261 def test_check_metadata_deprecated(self): 262 # makes sure make_metadata is deprecated 263 dist, cmd = self.get_cmd() 264 with check_warnings() as w: 265 warnings.simplefilter("always") 266 cmd.check_metadata() 267 self.assertEqual(len(w.warnings), 1) 268 269 def test_show_formats(self): 270 with captured_stdout() as stdout: 271 show_formats() 272 273 # the output should be a header line + one line per format 274 num_formats = len(ARCHIVE_FORMATS.keys()) 275 output = [line for line in stdout.getvalue().split('\n') 276 if line.strip().startswith('--formats=')] 277 self.assertEqual(len(output), num_formats) 278 279 def test_finalize_options(self): 280 281 dist, cmd = self.get_cmd() 282 cmd.finalize_options() 283 284 # default options set by finalize 285 self.assertEqual(cmd.manifest, 'MANIFEST') 286 self.assertEqual(cmd.template, 'MANIFEST.in') 287 self.assertEqual(cmd.dist_dir, 'dist') 288 289 # formats has to be a string splitable on (' ', ',') or 290 # a stringlist 291 cmd.formats = 1 292 self.assertRaises(DistutilsOptionError, cmd.finalize_options) 293 cmd.formats = ['zip'] 294 cmd.finalize_options() 295 296 # formats has to be known 297 cmd.formats = 'supazipa' 298 self.assertRaises(DistutilsOptionError, cmd.finalize_options) 299 300 @unittest.skipUnless(zlib, "requires zlib") 301 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") 302 def test_make_distribution_owner_group(self): 303 304 # check if tar and gzip are installed 305 if (find_executable('tar') is None or 306 find_executable('gzip') is None): 307 return 308 309 # now building a sdist 310 dist, cmd = self.get_cmd() 311 312 # creating a gztar and specifying the owner+group 313 cmd.formats = ['gztar'] 314 cmd.owner = pwd.getpwuid(0)[0] 315 cmd.group = grp.getgrgid(0)[0] 316 cmd.ensure_finalized() 317 cmd.run() 318 319 # making sure we have the good rights 320 archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz') 321 archive = tarfile.open(archive_name) 322 try: 323 for member in archive.getmembers(): 324 self.assertEqual(member.uid, 0) 325 self.assertEqual(member.gid, 0) 326 finally: 327 archive.close() 328 329 # building a sdist again 330 dist, cmd = self.get_cmd() 331 332 # creating a gztar 333 cmd.formats = ['gztar'] 334 cmd.ensure_finalized() 335 cmd.run() 336 337 # making sure we have the good rights 338 archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz') 339 archive = tarfile.open(archive_name) 340 341 # note that we are not testing the group ownership here 342 # because, depending on the platforms and the container 343 # rights (see #7408) 344 try: 345 for member in archive.getmembers(): 346 self.assertEqual(member.uid, os.getuid()) 347 finally: 348 archive.close() 349 350 @unittest.skipUnless(zlib, "requires zlib") 351 def test_get_file_list(self): 352 # make sure MANIFEST is recalculated 353 dist, cmd = self.get_cmd() 354 355 # filling data_files by pointing files in package_data 356 dist.package_data = {'somecode': ['*.txt']} 357 self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#') 358 cmd.ensure_finalized() 359 cmd.run() 360 361 f = open(cmd.manifest) 362 try: 363 manifest = [line.strip() for line in f.read().split('\n') 364 if line.strip() != ''] 365 finally: 366 f.close() 367 368 self.assertEqual(len(manifest), 5) 369 370 # adding a file 371 self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#') 372 373 # make sure build_py is reinitialized, like a fresh run 374 build_py = dist.get_command_obj('build_py') 375 build_py.finalized = False 376 build_py.ensure_finalized() 377 378 cmd.run() 379 380 f = open(cmd.manifest) 381 try: 382 manifest2 = [line.strip() for line in f.read().split('\n') 383 if line.strip() != ''] 384 finally: 385 f.close() 386 387 # do we have the new file in MANIFEST ? 388 self.assertEqual(len(manifest2), 6) 389 self.assertIn('doc2.txt', manifest2[-1]) 390 391 @unittest.skipUnless(zlib, "requires zlib") 392 def test_manifest_marker(self): 393 # check that autogenerated MANIFESTs have a marker 394 dist, cmd = self.get_cmd() 395 cmd.ensure_finalized() 396 cmd.run() 397 398 f = open(cmd.manifest) 399 try: 400 manifest = [line.strip() for line in f.read().split('\n') 401 if line.strip() != ''] 402 finally: 403 f.close() 404 405 self.assertEqual(manifest[0], 406 '# file GENERATED by distutils, do NOT edit') 407 408 @unittest.skipUnless(zlib, "requires zlib") 409 def test_manual_manifest(self): 410 # check that a MANIFEST without a marker is left alone 411 dist, cmd = self.get_cmd() 412 cmd.ensure_finalized() 413 self.write_file((self.tmp_dir, cmd.manifest), 'README.manual') 414 cmd.run() 415 416 f = open(cmd.manifest) 417 try: 418 manifest = [line.strip() for line in f.read().split('\n') 419 if line.strip() != ''] 420 finally: 421 f.close() 422 423 self.assertEqual(manifest, ['README.manual']) 424 425 def test_suite(): 426 return unittest.makeSuite(SDistTestCase) 427 428 if __name__ == "__main__": 429 run_unittest(test_suite()) 430