def make_distribution(self): """Create the source distribution(s). First, we create the release tree with 'make_release_tree()'; then, we create all required archive files (according to 'self.formats') from the release tree. Finally, we clean up by blowing away the release tree (unless 'self.keep_temp' is true). The list of archive files created is stored so it can be retrieved later by 'get_archive_files()'. """ # Don't warn about missing metadata here -- should be (and is!) # done elsewhere. base_dir = self.distribution.get_fullname() base_name = os.path.join(self.dist_dir, base_dir) self.make_release_tree(base_dir, self.filelist.files) archive_files = [] # remember names of files we create # tar archive must be created last to avoid overwrite and remove if 'tar' in self.formats: self.formats.append(self.formats.pop(self.formats.index('tar'))) for fmt in self.formats: file = self.make_archive(base_name, fmt, base_dir=base_dir, owner=self.owner, group=self.group) archive_files.append(file) self.distribution.dist_files.append(('sdist', '', file)) self.archive_files = archive_files if not self.keep_temp: if self.dry_run: logger.info('removing %s', base_dir) else: rmtree(base_dir)
def test_dont_copy_file_onto_link_to_itself(self): # Temporarily disable test on Windows. if os.name == 'nt': return # bug 851123. os.mkdir(TESTFN) src = os.path.join(TESTFN, 'cheese') dst = os.path.join(TESTFN, 'shop') try: f = open(src, 'w') try: f.write('cheddar') finally: f.close() os.link(src, dst) self.assertRaises(shutil.Error, shutil.copyfile, src, dst) f = open(src, 'r') try: self.assertEqual(f.read(), 'cheddar') finally: f.close() os.remove(dst) finally: shutil.rmtree(TESTFN, ignore_errors=True)
def run(self): # remove the build/temp.<plat> directory (unless it's already # gone) if os.path.exists(self.build_temp): if self.dry_run: logger.info('removing %s', self.build_temp) else: rmtree(self.build_temp) else: logger.debug("'%s' does not exist -- can't clean it", self.build_temp) if self.all: # remove build directories for directory in (self.build_lib, self.bdist_base, self.build_scripts): if os.path.exists(directory): if self.dry_run: logger.info('removing %s', directory) else: rmtree(directory) else: logger.warning("'%s' does not exist -- can't clean it", directory) # just for the heck of it, try to remove the base build directory: # we might have emptied it right now, but if not we don't care if not self.dry_run: try: os.rmdir(self.build_base) logger.info("removing '%s'", self.build_base) except OSError: pass
def install_local_project(path): """Install a distribution from a source directory or archive. If *path* is an archive, it will be unarchived first. If the source directory contains a setup.py install using distutils1. If a setup.cfg is found, install using the install_dist command. Returns True on success, False on Failure. """ path = os.path.abspath(path) if os.path.isdir(path): logger.info('Installing from source directory: %r', path) return _run_install_from_dir(path) elif _is_archive_file(path): logger.info('Installing from archive: %r', path) _unpacked_dir = tempfile.mkdtemp() try: shutil.unpack_archive(path, _unpacked_dir) return _run_install_from_archive(_unpacked_dir) finally: shutil.rmtree(_unpacked_dir) else: logger.warning('No project to install.') return False
def test_copytree_simple(self): def read_data(path): f = open(path) data = f.read() f.close() return data src_dir = tempfile.mkdtemp() dst_dir = os.path.join(tempfile.mkdtemp(), 'destination') self._write_data(os.path.join(src_dir, 'test.txt'), '123') os.mkdir(os.path.join(src_dir, 'test_dir')) self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') try: shutil.copytree(src_dir, dst_dir) self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt'))) self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir'))) self.assertTrue( os.path.isfile(os.path.join(dst_dir, 'test_dir', 'test.txt'))) actual = read_data(os.path.join(dst_dir, 'test.txt')) self.assertEqual(actual, '123') actual = read_data(os.path.join(dst_dir, 'test_dir', 'test.txt')) self.assertEqual(actual, '456') finally: for path in ( os.path.join(src_dir, 'test.txt'), os.path.join(dst_dir, 'test.txt'), os.path.join(src_dir, 'test_dir', 'test.txt'), os.path.join(dst_dir, 'test_dir', 'test.txt'), ): if os.path.exists(path): os.remove(path) for path in (src_dir, os.path.dirname(dst_dir)): if os.path.exists(path): shutil.rmtree(path)
def tearDown(self): for d in (self.src_dir, self.dst_dir): try: if d: shutil.rmtree(d) except: pass
def tearDown(self): for handle, name in self._files: handle.close() unlink(name) os.chdir(self._olddir) shutil.rmtree(self._basetempdir) super(TempdirManager, self).tearDown()
def run(self): if not self.skip_build: self.run_command('build') install = self.reinitialize_command('install_dist', reinit_subcommands=True) install.root = self.bdist_dir install.skip_build = self.skip_build install.warn_dir = False logger.info("installing to %s", self.bdist_dir) self.run_command('install_dist') # And make an archive relative to the root of the # pseudo-installation tree. archive_basename = "%s.%s" % (self.distribution.get_fullname(), self.plat_name) # OS/2 objects to any ":" characters in a filename (such as when # a timestamp is used in a version) so change them to hyphens. if os.name == "os2": archive_basename = archive_basename.replace(":", "-") pseudoinstall_root = os.path.join(self.dist_dir, archive_basename) if not self.relative: archive_root = self.bdist_dir else: if (self.distribution.has_ext_modules() and (install.install_base != install.install_platbase)): raise PackagingPlatformError( "can't make a dumb built distribution where base and " "platbase are different (%r, %r)" % (install.install_base, install.install_platbase)) else: archive_root = os.path.join( self.bdist_dir, self._ensure_relative(install.install_base)) # Make the archive filename = self.make_archive(pseudoinstall_root, self.format, root_dir=archive_root, owner=self.owner, group=self.group) if self.distribution.has_ext_modules(): pyversion = get_python_version() else: pyversion = 'any' self.distribution.dist_files.append( ('bdist_dumb', pyversion, filename)) if not self.keep_temp: if self.dry_run: logger.info('removing %s', self.bdist_dir) else: rmtree(self.bdist_dir)
def test_move_dir(self): # Move a dir to another location on the same filesystem. dst_dir = tempfile.mktemp() try: self._check_move_dir(self.src_dir, dst_dir, dst_dir) finally: try: shutil.rmtree(dst_dir) except: pass
def run(self): if not self.skip_build: self.run_command('build') install = self.reinitialize_command('install_dist', reinit_subcommands=True) install.root = self.bdist_dir install.skip_build = self.skip_build install.warn_dir = False logger.info("installing to %s", self.bdist_dir) self.run_command('install_dist') # And make an archive relative to the root of the # pseudo-installation tree. archive_basename = "%s.%s" % (self.distribution.get_fullname(), self.plat_name) # OS/2 objects to any ":" characters in a filename (such as when # a timestamp is used in a version) so change them to hyphens. if os.name == "os2": archive_basename = archive_basename.replace(":", "-") pseudoinstall_root = os.path.join(self.dist_dir, archive_basename) if not self.relative: archive_root = self.bdist_dir else: if (self.distribution.has_ext_modules() and (install.install_base != install.install_platbase)): raise PackagingPlatformError( "can't make a dumb built distribution where base and " "platbase are different (%r, %r)" % (install.install_base, install.install_platbase)) else: archive_root = os.path.join( self.bdist_dir, self._ensure_relative(install.install_base)) # Make the archive filename = self.make_archive(pseudoinstall_root, self.format, root_dir=archive_root, owner=self.owner, group=self.group) if self.distribution.has_ext_modules(): pyversion = get_python_version() else: pyversion = 'any' self.distribution.dist_files.append(('bdist_dumb', pyversion, filename)) if not self.keep_temp: if self.dry_run: logger.info('removing %s', self.bdist_dir) else: rmtree(self.bdist_dir)
def test_rmtree_on_symlink(self): # bug 1669. os.mkdir(TESTFN) try: src = os.path.join(TESTFN, 'cheese') dst = os.path.join(TESTFN, 'shop') os.mkdir(src) os.symlink(src, dst) self.assertRaises(OSError, shutil.rmtree, dst) finally: shutil.rmtree(TESTFN, ignore_errors=True)
def test_destinsrc_false_positive(self): os.mkdir(TESTFN) try: for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]: src = os.path.join(TESTFN, src) dst = os.path.join(TESTFN, dst) self.assertFalse(shutil._destinsrc(src, dst), msg='_destinsrc() wrongly concluded that ' 'dst (%s) is in src (%s)' % (dst, src)) finally: shutil.rmtree(TESTFN, ignore_errors=True)
def rmpath(self, name, dry_run=None): if dry_run is None: dry_run = self.dry_run name = os.path.normpath(name) if not os.path.isdir(name) or name == '': return if dry_run: head = '' for part in name.split(os.sep): logger.info("removing directory %s%s", head, part) head += part + os.sep return rmtree(name)
def run(self): target = self.target if os.path.isdir(target) and not os.path.islink(target): if self.dry_run: pass # XXX else: rmtree(target) elif os.path.exists(target): self.execute(os.unlink,(self.target,),"Removing "+target) elif not os.path.isdir(self.install_dir): self.execute(os.makedirs, (self.install_dir,), "Creating "+self.install_dir) log.info("Writing %s", target) if not self.dry_run: f = open(target, 'w') self.distribution.metadata.write_file(f) f.close()
def test_copytree_named_pipe(self): os.mkdir(TESTFN) try: subdir = os.path.join(TESTFN, "subdir") os.mkdir(subdir) pipe = os.path.join(subdir, "mypipe") os.mkfifo(pipe) try: shutil.copytree(TESTFN, TESTFN2) except shutil.Error as e: errors = e.args[0] self.assertEqual(len(errors), 1) src, dst, error_msg = errors[0] self.assertEqual("`%s` is a named pipe" % pipe, error_msg) else: self.fail("shutil.Error should have been raised") finally: shutil.rmtree(TESTFN, ignore_errors=True) shutil.rmtree(TESTFN2, ignore_errors=True)
def test_copytree_simple(self): def read_data(path): f = open(path) data = f.read() f.close() return data src_dir = tempfile.mkdtemp() dst_dir = os.path.join(tempfile.mkdtemp(), 'destination') self._write_data(os.path.join(src_dir, 'test.txt'), '123') os.mkdir(os.path.join(src_dir, 'test_dir')) self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') try: shutil.copytree(src_dir, dst_dir) self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt'))) self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir'))) self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir', 'test.txt'))) actual = read_data(os.path.join(dst_dir, 'test.txt')) self.assertEqual(actual, '123') actual = read_data(os.path.join(dst_dir, 'test_dir', 'test.txt')) self.assertEqual(actual, '456') finally: for path in ( os.path.join(src_dir, 'test.txt'), os.path.join(dst_dir, 'test.txt'), os.path.join(src_dir, 'test_dir', 'test.txt'), os.path.join(dst_dir, 'test_dir', 'test.txt'), ): if os.path.exists(path): os.remove(path) for path in (src_dir, os.path.dirname(dst_dir) ): if os.path.exists(path): shutil.rmtree(path)
def test_on_error(self): self.errorState = 0 os.mkdir(TESTFN) self.childpath = os.path.join(TESTFN, 'a') f = open(self.childpath, 'w') f.close() old_dir_mode = os.stat(TESTFN).st_mode old_child_mode = os.stat(self.childpath).st_mode # Make unwritable. os.chmod(self.childpath, stat.S_IREAD) os.chmod(TESTFN, stat.S_IREAD) shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) # Test whether onerror has actually been called. self.assertEqual(self.errorState, 2, "Expected call to onerror function did not happen.") # Make writable again. os.chmod(TESTFN, old_dir_mode) os.chmod(self.childpath, old_child_mode) # Clean up. shutil.rmtree(TESTFN)
def test_dont_copy_file_onto_symlink_to_itself(self): # bug 851123. os.mkdir(TESTFN) src = os.path.join(TESTFN, 'cheese') dst = os.path.join(TESTFN, 'shop') try: f = open(src, 'w') try: f.write('cheddar') finally: f.close() # Using `src` here would mean we end up with a symlink pointing # to TESTFN/TESTFN/cheese, while it should point at # TESTFN/cheese. os.symlink('cheese', dst) self.assertRaises(shutil.Error, shutil.copyfile, src, dst) f = open(src, 'r') try: self.assertEqual(f.read(), 'cheddar') finally: f.close() os.remove(dst) finally: shutil.rmtree(TESTFN, ignore_errors=True)
def test_on_error(self): self.errorState = 0 os.mkdir(TESTFN) self.childpath = os.path.join(TESTFN, 'a') f = open(self.childpath, 'w') f.close() old_dir_mode = os.stat(TESTFN).st_mode old_child_mode = os.stat(self.childpath).st_mode # Make unwritable. os.chmod(self.childpath, stat.S_IREAD) os.chmod(TESTFN, stat.S_IREAD) shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) # Test whether onerror has actually been called. self.assertEqual( self.errorState, 2, "Expected call to onerror function did not happen.") # Make writable again. os.chmod(TESTFN, old_dir_mode) os.chmod(self.childpath, old_child_mode) # Clean up. shutil.rmtree(TESTFN)
def tearDown(self): super(TestShutil, self).tearDown() while self.tempdirs: d = self.tempdirs.pop() shutil.rmtree(d, os.name in ('nt', 'cygwin'))
def run(self): if (sys.platform != "win32" and (self.distribution.has_ext_modules() or self.distribution.has_c_libraries())): raise PackagingPlatformError \ ("distribution contains extensions and/or C libraries; " "must be compiled on a Windows 32 platform") if not self.skip_build: self.run_command('build') install = self.reinitialize_command('install', reinit_subcommands=True) install.root = self.bdist_dir install.skip_build = self.skip_build install.warn_dir = False install.plat_name = self.plat_name install_lib = self.reinitialize_command('install_lib') # we do not want to include pyc or pyo files install_lib.compile = False install_lib.optimize = 0 if self.distribution.has_ext_modules(): # If we are building an installer for a Python version other # than the one we are currently running, then we need to ensure # our build_lib reflects the other Python version rather than ours. # Note that for target_version!=sys.version, we must have skipped the # build step, so there is no issue with enforcing the build of this # version. target_version = self.target_version if not target_version: assert self.skip_build, "Should have already checked this" target_version = '%s.%s' % sys.version_info[:2] plat_specifier = ".%s-%s" % (self.plat_name, target_version) build = self.get_finalized_command('build') build.build_lib = os.path.join(build.build_base, 'lib' + plat_specifier) # Use a custom scheme for the zip-file, because we have to decide # at installation time which scheme to use. for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): value = key.upper() if key == 'headers': value = value + '/Include/$dist_name' setattr(install, 'install_' + key, value) logger.info("installing to %s", self.bdist_dir) install.ensure_finalized() # avoid warning of 'install_lib' about installing # into a directory not in sys.path sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB')) install.run() del sys.path[0] # And make an archive relative to the root of the # pseudo-installation tree. from tempfile import NamedTemporaryFile archive_basename = NamedTemporaryFile().name fullname = self.distribution.get_fullname() arcname = self.make_archive(archive_basename, "zip", root_dir=self.bdist_dir) # create an exe containing the zip-file self.create_exe(arcname, fullname, self.bitmap) if self.distribution.has_ext_modules(): pyversion = get_python_version() else: pyversion = 'any' self.distribution.dist_files.append(('bdist_wininst', pyversion, self.get_installer_filename(fullname))) # remove the zip-file again logger.debug("removing temporary file '%s'", arcname) os.remove(arcname) if not self.keep_temp: logger.info('removing %s', self.bdist_dir) if not self.dry_run: rmtree(self.bdist_dir)
def test_copytree_with_exclude(self): def read_data(path): f = open(path) data = f.read() f.close() return data # creating data join = os.path.join exists = os.path.exists src_dir = tempfile.mkdtemp() try: dst_dir = join(tempfile.mkdtemp(), 'destination') self._write_data(join(src_dir, 'test.txt'), '123') self._write_data(join(src_dir, 'test.tmp'), '123') os.mkdir(join(src_dir, 'test_dir')) self._write_data(join(src_dir, 'test_dir', 'test.txt'), '456') os.mkdir(join(src_dir, 'test_dir2')) self._write_data(join(src_dir, 'test_dir2', 'test.txt'), '456') os.mkdir(join(src_dir, 'test_dir2', 'subdir')) os.mkdir(join(src_dir, 'test_dir2', 'subdir2')) self._write_data(join(src_dir, 'test_dir2', 'subdir', 'test.txt'), '456') self._write_data(join(src_dir, 'test_dir2', 'subdir2', 'test.py'), '456') # testing glob-like patterns try: patterns = shutil.ignore_patterns('*.tmp', 'test_dir2') shutil.copytree(src_dir, dst_dir, ignore=patterns) # checking the result: some elements should not be copied self.assertTrue(exists(join(dst_dir, 'test.txt'))) self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) self.assertTrue(not exists(join(dst_dir, 'test_dir2'))) finally: if os.path.exists(dst_dir): shutil.rmtree(dst_dir) try: patterns = shutil.ignore_patterns('*.tmp', 'subdir*') shutil.copytree(src_dir, dst_dir, ignore=patterns) # checking the result: some elements should not be copied self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) self.assertTrue( not exists(join(dst_dir, 'test_dir2', 'subdir2'))) self.assertTrue( not exists(join(dst_dir, 'test_dir2', 'subdir'))) finally: if os.path.exists(dst_dir): shutil.rmtree(dst_dir) # testing callable-style try: def _filter(src, names): res = [] for name in names: path = os.path.join(src, name) if (os.path.isdir(path) and path.split()[-1] == 'subdir'): res.append(name) elif os.path.splitext(path)[-1] in ('.py'): res.append(name) return res shutil.copytree(src_dir, dst_dir, ignore=_filter) # checking the result: some elements should not be copied self.assertTrue(not exists( join(dst_dir, 'test_dir2', 'subdir2', 'test.py'))) self.assertTrue( not exists(join(dst_dir, 'test_dir2', 'subdir'))) finally: if os.path.exists(dst_dir): shutil.rmtree(dst_dir) finally: shutil.rmtree(src_dir) shutil.rmtree(os.path.dirname(dst_dir))
def _cleanup_testfn(self): path = TESTFN if os.path.isfile(path): os.remove(path) elif os.path.isdir(path): shutil.rmtree(path)
def run(self): target = self.install_dir if os.path.isdir(target) and not os.path.islink(target): if not self.dry_run: rmtree(target) elif os.path.exists(target): self.execute(os.unlink, (self.install_dir,), "removing " + target) self.execute(os.makedirs, (target,), "creating " + target) metadata_path = os.path.join(self.install_dir, 'METADATA') self.execute(self.distribution.metadata.write, (metadata_path,), "creating " + metadata_path) self.outfiles.append(metadata_path) installer_path = os.path.join(self.install_dir, 'INSTALLER') logger.info('creating %s', installer_path) if not self.dry_run: f = open(installer_path, 'w') try: f.write(self.installer) finally: f.close() self.outfiles.append(installer_path) if self.requested: requested_path = os.path.join(self.install_dir, 'REQUESTED') logger.info('creating %s', requested_path) if not self.dry_run: open(requested_path, 'wb').close() self.outfiles.append(requested_path) if not self.no_resources: install_data = self.get_finalized_command('install_data') if install_data.get_resources_out() != []: resources_path = os.path.join(self.install_dir, 'RESOURCES') logger.info('creating %s', resources_path) if not self.dry_run: f = open(resources_path, 'w') try: writer = csv.writer(f, delimiter=',', lineterminator='\n', quotechar='"') for row in install_data.get_resources_out(): writer.writerow(row) finally: f.close() self.outfiles.append(resources_path) if not self.no_record: record_path = os.path.join(self.install_dir, 'RECORD') logger.info('creating %s', record_path) if not self.dry_run: f = codecs.open(record_path, 'w', encoding='utf-8') try: writer = csv.writer(f, delimiter=',', lineterminator='\n', quotechar='"') install = self.get_finalized_command('install_dist') for fpath in install.get_outputs(): if fpath.endswith('.pyc') or fpath.endswith('.pyo'): # do not put size and md5 hash, as in PEP-376 writer.writerow((fpath, '', '')) else: size = os.path.getsize(fpath) fp = open(fpath, 'rb') try: hash = hashlib.md5() hash.update(fp.read()) finally: fp.close() md5sum = hash.hexdigest() writer.writerow((fpath, md5sum, size)) # add the RECORD file itself writer.writerow((record_path, '', '')) finally: f.close() self.outfiles.append(record_path)
def run (self): if not self.skip_build: self.run_command('build') install = self.get_reinitialized_command('install', reinit_subcommands=1) install.prefix = self.bdist_dir install.skip_build = self.skip_build install.warn_dir = 0 install_lib = self.get_reinitialized_command('install_lib') # we do not want to include pyc or pyo files install_lib.compile = 0 install_lib.optimize = 0 if self.distribution.has_ext_modules(): # If we are building an installer for a Python version other # than the one we are currently running, then we need to ensure # our build_lib reflects the other Python version rather than ours. # Note that for target_version!=sys.version, we must have skipped the # build step, so there is no issue with enforcing the build of this # version. target_version = self.target_version if not target_version: assert self.skip_build, "Should have already checked this" target_version = sys.version[0:3] plat_specifier = ".%s-%s" % (self.plat_name, target_version) build = self.get_finalized_command('build') build.build_lib = os.path.join(build.build_base, 'lib' + plat_specifier) log.info("installing to %s", self.bdist_dir) install.ensure_finalized() # avoid warning of 'install_lib' about installing # into a directory not in sys.path sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB')) install.run() del sys.path[0] self.mkpath(self.dist_dir) fullname = self.distribution.get_fullname() installer_name = self.get_installer_filename(fullname) installer_name = os.path.abspath(installer_name) if os.path.exists(installer_name): os.unlink(installer_name) metadata = self.distribution.metadata author = metadata.author if not author: author = metadata.maintainer if not author: author = "UNKNOWN" version = metadata.get_version() # ProductVersion must be strictly numeric # XXX need to deal with prerelease versions sversion = "%d.%d.%d" % StrictVersion(version).version # Prefix ProductName with Python x.y, so that # it sorts together with the other Python packages # in Add-Remove-Programs (APR) fullname = self.distribution.get_fullname() if self.target_version: product_name = "Python %s %s" % (self.target_version, fullname) else: product_name = "Python %s" % (fullname) self.db = msilib.init_database(installer_name, schema, product_name, msilib.gen_uuid(), sversion, author) msilib.add_tables(self.db, sequence) props = [('DistVersion', version)] email = metadata.author_email or metadata.maintainer_email if email: props.append(("ARPCONTACT", email)) if metadata.url: props.append(("ARPURLINFOABOUT", metadata.url)) if props: add_data(self.db, 'Property', props) self.add_find_python() self.add_files() self.add_scripts() self.add_ui() self.db.Commit() if hasattr(self.distribution, 'dist_files'): tup = 'bdist_msi', self.target_version or 'any', fullname self.distribution.dist_files.append(tup) if not self.keep_temp: log.info("removing temporary build directory %s", self.bdist_dir) if not self.dry_run: rmtree(self.bdist_dir)
def run(self): target = self.install_dir if os.path.isdir(target) and not os.path.islink(target): if not self.dry_run: rmtree(target) elif os.path.exists(target): self.execute(os.unlink, (self.install_dir, ), "removing " + target) self.execute(os.makedirs, (target, ), "creating " + target) metadata_path = os.path.join(self.install_dir, 'METADATA') self.execute(self.distribution.metadata.write, (metadata_path, ), "creating " + metadata_path) self.outfiles.append(metadata_path) installer_path = os.path.join(self.install_dir, 'INSTALLER') logger.info('creating %s', installer_path) if not self.dry_run: with open(installer_path, 'w') as f: f.write(self.installer) self.outfiles.append(installer_path) if self.requested: requested_path = os.path.join(self.install_dir, 'REQUESTED') logger.info('creating %s', requested_path) if not self.dry_run: open(requested_path, 'wb').close() self.outfiles.append(requested_path) if not self.no_resources: install_data = self.get_finalized_command('install_data') if install_data.get_resources_out() != []: resources_path = os.path.join(self.install_dir, 'RESOURCES') logger.info('creating %s', resources_path) if not self.dry_run: with open(resources_path, 'w') as f: writer = csv.writer(f, delimiter=',', lineterminator='\n', quotechar='"') for row in install_data.get_resources_out(): writer.writerow(row) self.outfiles.append(resources_path) if not self.no_record: record_path = os.path.join(self.install_dir, 'RECORD') logger.info('creating %s', record_path) if not self.dry_run: with open(record_path, 'w', encoding='utf-8') as f: writer = csv.writer(f, delimiter=',', lineterminator='\n', quotechar='"') install = self.get_finalized_command('install_dist') for fpath in install.get_outputs(): if fpath.endswith('.pyc') or fpath.endswith('.pyo'): # do not put size and md5 hash, as in PEP-376 writer.writerow((fpath, '', '')) else: size = os.path.getsize(fpath) with open(fpath, 'rb') as fp: hash = hashlib.md5() hash.update(fp.read()) md5sum = hash.hexdigest() writer.writerow((fpath, md5sum, size)) # add the RECORD file itself writer.writerow((record_path, '', '')) self.outfiles.append(record_path)
def test_copytree_with_exclude(self): def read_data(path): f = open(path) data = f.read() f.close() return data # creating data join = os.path.join exists = os.path.exists src_dir = tempfile.mkdtemp() try: dst_dir = join(tempfile.mkdtemp(), 'destination') self._write_data(join(src_dir, 'test.txt'), '123') self._write_data(join(src_dir, 'test.tmp'), '123') os.mkdir(join(src_dir, 'test_dir')) self._write_data(join(src_dir, 'test_dir', 'test.txt'), '456') os.mkdir(join(src_dir, 'test_dir2')) self._write_data(join(src_dir, 'test_dir2', 'test.txt'), '456') os.mkdir(join(src_dir, 'test_dir2', 'subdir')) os.mkdir(join(src_dir, 'test_dir2', 'subdir2')) self._write_data(join(src_dir, 'test_dir2', 'subdir', 'test.txt'), '456') self._write_data(join(src_dir, 'test_dir2', 'subdir2', 'test.py'), '456') # testing glob-like patterns try: patterns = shutil.ignore_patterns('*.tmp', 'test_dir2') shutil.copytree(src_dir, dst_dir, ignore=patterns) # checking the result: some elements should not be copied self.assertTrue(exists(join(dst_dir, 'test.txt'))) self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) self.assertTrue(not exists(join(dst_dir, 'test_dir2'))) finally: if os.path.exists(dst_dir): shutil.rmtree(dst_dir) try: patterns = shutil.ignore_patterns('*.tmp', 'subdir*') shutil.copytree(src_dir, dst_dir, ignore=patterns) # checking the result: some elements should not be copied self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2'))) self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) finally: if os.path.exists(dst_dir): shutil.rmtree(dst_dir) # testing callable-style try: def _filter(src, names): res = [] for name in names: path = os.path.join(src, name) if (os.path.isdir(path) and path.split()[-1] == 'subdir'): res.append(name) elif os.path.splitext(path)[-1] in ('.py'): res.append(name) return res shutil.copytree(src_dir, dst_dir, ignore=_filter) # checking the result: some elements should not be copied self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2', 'test.py'))) self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) finally: if os.path.exists(dst_dir): shutil.rmtree(dst_dir) finally: shutil.rmtree(src_dir) shutil.rmtree(os.path.dirname(dst_dir))
def install_from_infos(install_path=None, install=[], remove=[], conflicts=[], paths=None): """Install and remove the given distributions. The function signature is made to be compatible with the one of get_infos. The aim of this script is to povide a way to install/remove what's asked, and to rollback if needed. So, it's not possible to be in an inconsistant state, it could be either installed, either uninstalled, not half-installed. The process follow those steps: 1. Move all distributions that will be removed in a temporary location 2. Install all the distributions that will be installed in a temp. loc. 3. If the installation fails, rollback (eg. move back) those distributions, or remove what have been installed. 4. Else, move the distributions to the right locations, and remove for real the distributions thats need to be removed. :param install_path: the installation path where we want to install the distributions. :param install: list of distributions that will be installed; install_path must be provided if this list is not empty. :param remove: list of distributions that will be removed. :param conflicts: list of conflicting distributions, eg. that will be in conflict once the install and remove distribution will be processed. :param paths: list of paths (defaults to sys.path) to look for info """ # first of all, if we have conflicts, stop here. if conflicts: raise InstallationConflict(conflicts) if install and not install_path: raise ValueError("Distributions are to be installed but `install_path`" " is not provided.") # before removing the files, we will start by moving them away # then, if any error occurs, we could replace them in the good place. temp_files = {} # contains lists of {dist: (old, new)} paths temp_dir = None if remove: temp_dir = tempfile.mkdtemp() for dist in remove: files = dist.list_installed_files() paths = [path for path, md5, size in files] temp_files[dist] = _move_files(paths, temp_dir) try: if install: install_dists(install, install_path, paths) except: # if an error occurs, put back the files in the right place. for files in temp_files.values(): for old, new in files: shutil.move(new, old) if temp_dir: shutil.rmtree(temp_dir) # now re-raising raise # we can remove them for good for files in temp_files.values(): for old, new in files: os.remove(new) if temp_dir: shutil.rmtree(temp_dir)
def test_checks_upload_dir(self): self.cmd.upload_dir = self.prepare_sample_dir() shutil.rmtree(os.path.join(self.cmd.upload_dir)) self.assertRaises(PackagingOptionError, self.cmd.ensure_finalized)
def run(self): # FIXME dry-run should be used at a finer level, so that people get # useful logging output and can have an idea of what the command would # have done if not self.dry_run: target = self.distinfo_dir if os.path.isdir(target) and not os.path.islink(target): rmtree(target) elif os.path.exists(target): self.execute(os.unlink, (self.distinfo_dir,), "removing " + target) self.execute(os.makedirs, (target,), "creating " + target) metadata_path = os.path.join(self.distinfo_dir, 'METADATA') log.info('creating %s', metadata_path) self.distribution.metadata.write(metadata_path) self.outputs.append(metadata_path) installer_path = os.path.join(self.distinfo_dir, 'INSTALLER') log.info('creating %s', installer_path) f = open(installer_path, 'w') try: f.write(self.installer) finally: f.close() self.outputs.append(installer_path) if self.requested: requested_path = os.path.join(self.distinfo_dir, 'REQUESTED') log.info('creating %s', requested_path) f = open(requested_path, 'w') f.close() self.outputs.append(requested_path) if not self.no_record: record_path = os.path.join(self.distinfo_dir, 'RECORD') log.info('creating %s', record_path) f = open(record_path, 'wb') try: writer = csv.writer(f, delimiter=',', lineterminator=os.linesep, quotechar='"') install = self.get_finalized_command('install') for fpath in install.get_outputs(): if fpath.endswith('.pyc') or fpath.endswith('.pyo'): # do not put size and md5 hash, as in PEP-376 writer.writerow((fpath, '', '')) else: size = os.path.getsize(fpath) fd = open(fpath, 'r') hash = hashlib.md5() hash.update(fd.read()) md5sum = hash.hexdigest() writer.writerow((fpath, md5sum, size)) # add the RECORD file itself writer.writerow((record_path, '', '')) self.outputs.append(record_path) finally: f.close()
try: subdir = os.path.join(TESTFN, "subdir") os.mkdir(subdir) pipe = os.path.join(subdir, "mypipe") os.mkfifo(pipe) try: shutil.copytree(TESTFN, TESTFN2) except shutil.Error, e: errors = e.args[0] self.assertEqual(len(errors), 1) src, dst, error_msg = errors[0] self.assertEqual("`%s` is a named pipe" % pipe, error_msg) else: self.fail("shutil.Error should have been raised") finally: shutil.rmtree(TESTFN, ignore_errors=True) shutil.rmtree(TESTFN2, ignore_errors=True) def test_copytree_special_func(self): src_dir = self.mkdtemp() dst_dir = os.path.join(self.mkdtemp(), 'destination') self._write_data(os.path.join(src_dir, 'test.txt'), '123') os.mkdir(os.path.join(src_dir, 'test_dir')) self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') copied = [] def _copy(src, dst): copied.append((src, dst)) shutil.copytree(src_dir, dst_dir, copy_function=_copy)
def remove(project_name, paths=None, auto_confirm=True): """Removes a single project from the installation. Returns True on success """ dist = get_distribution(project_name, use_egg_info=True, paths=paths) if dist is None: raise PackagingError('Distribution %r not found' % project_name) files = dist.list_installed_files(local=True) rmdirs = [] rmfiles = [] tmp = tempfile.mkdtemp(prefix=project_name + '-uninstall') def _move_file(source, target): try: os.rename(source, target) except OSError as err: return err return None success = True error = None try: for file_, md5, size in files: if os.path.isfile(file_): dirname, filename = os.path.split(file_) tmpfile = os.path.join(tmp, filename) try: error = _move_file(file_, tmpfile) if error is not None: success = False break finally: if not os.path.isfile(file_): os.rename(tmpfile, file_) if file_ not in rmfiles: rmfiles.append(file_) if dirname not in rmdirs: rmdirs.append(dirname) finally: shutil.rmtree(tmp) if not success: logger.info('%r cannot be removed.', project_name) logger.info('Error: %s', error) return False logger.info('Removing %r: ', project_name) for file_ in rmfiles: logger.info(' %s', file_) # Taken from the pip project if auto_confirm: response = 'y' else: response = ask('Proceed (y/n)? ', ('y', 'n')) if response == 'y': file_count = 0 for file_ in rmfiles: os.remove(file_) file_count += 1 dir_count = 0 for dirname in rmdirs: if not os.path.exists(dirname): # could continue files_count = 0 for root, dir, files in os.walk(dirname): files_count += len(files) if files_count > 0: # XXX Warning continue # empty dirs with only empty dirs if os.stat(dirname).st_mode & stat.S_IWUSR: # XXX Add a callable in shutil.rmtree to count # the number of deleted elements shutil.rmtree(dirname) dir_count += 1 # removing the top path # XXX count it ? if os.path.exists(dist.path): shutil.rmtree(dist.path) logger.info('Success: removed %d files and %d dirs', file_count, dir_count) return True
def run(self): if (sys.platform != "win32" and (self.distribution.has_ext_modules() or self.distribution.has_c_libraries())): raise PackagingPlatformError \ ("distribution contains extensions and/or C libraries; " "must be compiled on a Windows 32 platform") if not self.skip_build: self.run_command('build') install = self.reinitialize_command('install', reinit_subcommands=True) install.root = self.bdist_dir install.skip_build = self.skip_build install.warn_dir = False install.plat_name = self.plat_name install_lib = self.reinitialize_command('install_lib') # we do not want to include pyc or pyo files install_lib.compile = False install_lib.optimize = 0 if self.distribution.has_ext_modules(): # If we are building an installer for a Python version other # than the one we are currently running, then we need to ensure # our build_lib reflects the other Python version rather than ours. # Note that for target_version!=sys.version, we must have skipped the # build step, so there is no issue with enforcing the build of this # version. target_version = self.target_version if not target_version: assert self.skip_build, "Should have already checked this" target_version = '%s.%s' % sys.version_info[:2] plat_specifier = ".%s-%s" % (self.plat_name, target_version) build = self.get_finalized_command('build') build.build_lib = os.path.join(build.build_base, 'lib' + plat_specifier) # Use a custom scheme for the zip-file, because we have to decide # at installation time which scheme to use. for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): value = key.upper() if key == 'headers': value = value + '/Include/$dist_name' setattr(install, 'install_' + key, value) logger.info("installing to %s", self.bdist_dir) install.ensure_finalized() # avoid warning of 'install_lib' about installing # into a directory not in sys.path sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB')) install.run() del sys.path[0] # And make an archive relative to the root of the # pseudo-installation tree. from tempfile import NamedTemporaryFile archive_basename = NamedTemporaryFile().name fullname = self.distribution.get_fullname() arcname = self.make_archive(archive_basename, "zip", root_dir=self.bdist_dir) # create an exe containing the zip-file self.create_exe(arcname, fullname, self.bitmap) if self.distribution.has_ext_modules(): pyversion = get_python_version() else: pyversion = 'any' self.distribution.dist_files.append( ('bdist_wininst', pyversion, self.get_installer_filename(fullname))) # remove the zip-file again logger.debug("removing temporary file '%s'", arcname) os.remove(arcname) if not self.keep_temp: logger.info('removing %s', self.bdist_dir) if not self.dry_run: rmtree(self.bdist_dir)
dirname, filename = os.path.split(file_) tmpfile = os.path.join(tmp, filename) try: error = _move_file(file_, tmpfile) if error is not None: success = False break finally: if not os.path.isfile(file_): os.rename(tmpfile, file_) if file_ not in rmfiles: rmfiles.append(file_) if dirname not in rmdirs: rmdirs.append(dirname) finally: shutil.rmtree(tmp) if not success: logger.info('%r cannot be removed.', project_name) logger.info('Error: %s', error) return False logger.info('Removing %r: ', project_name) for file_ in rmfiles: logger.info(' %s', file_) # Taken from the pip project if auto_confirm: response = 'y' else: