diff --git a/PyInstaller/building/api.py b/PyInstaller/building/api.py index a97f075145..d0b3863339 100644 --- a/PyInstaller/building/api.py +++ b/PyInstaller/building/api.py @@ -306,7 +306,13 @@ def assemble(self): if self.exclude_binaries: self.dependencies.append((dest_name, src_name, typecode)) else: - archive_toc.append((dest_name, src_name, self.cdict.get(typecode, False), self.xformdict[typecode])) + if typecode == 'DATA' and os.access(src_name, os.X_OK): + # DATA with executable bit set (e.g., shell script); turn into binary so that executable bit is + # restored on the extracted file. + carchive_typecode = 'b' + else: + carchive_typecode = self.xformdict[typecode] + archive_toc.append((dest_name, src_name, self.cdict.get(typecode, False), carchive_typecode)) elif typecode == 'OPTION': archive_toc.append((dest_name, '', False, 'o')) elif typecode in ('PYSOURCE', 'PYMODULE'): @@ -1142,10 +1148,13 @@ def assemble(self): ) # Use `shutil.copyfile` to copy file with default permissions. We do not attempt to preserve original # permissions nor metadata, as they might be too restrictive and cause issues either during subsequent - # re-build attempts or when trying to move the application bundle. For binaries, we manually set the - # executable bits after copying the file. + # re-build attempts or when trying to move the application bundle. For binaries (and data files with + # executable bit set), we manually set the executable bits after copying the file. shutil.copyfile(src_name, dest_path) - if typecode in ('EXTENSION', 'BINARY', 'EXECUTABLE'): + if ( + typecode in ('EXTENSION', 'BINARY', 'EXECUTABLE') + or (typecode == 'DATA' and os.access(src_name, os.X_OK)) + ): os.chmod(dest_path, 0o755) logger.info("Building COLLECT %s completed successfully.", self.tocbasename) diff --git a/PyInstaller/building/osx.py b/PyInstaller/building/osx.py index b889078769..f99d88c0f8 100644 --- a/PyInstaller/building/osx.py +++ b/PyInstaller/building/osx.py @@ -646,10 +646,13 @@ def assemble(self): ) # Use `shutil.copyfile` to copy file with default permissions. We do not attempt to preserve original # permissions nor metadata, as they might be too restrictive and cause issues either during subsequent - # re-build attempts or when trying to move the application bundle. For binaries, we manually set the - # executable bits after copying the file. + # re-build attempts or when trying to move the application bundle. For binaries (and data files with + # executable bit set), we manually set the executable bits after copying the file. shutil.copyfile(src_name, dest_path) - if typecode in ('EXTENSION', 'BINARY', 'EXECUTABLE'): + if ( + typecode in ('EXTENSION', 'BINARY', 'EXECUTABLE') + or (typecode == 'DATA' and os.access(src_name, os.X_OK)) + ): os.chmod(dest_path, 0o755) # Sign the bundle diff --git a/news/7950.bootloader.rst b/news/7950.bootloader.rst index 9166ad502f..e5e66e4719 100644 --- a/news/7950.bootloader.rst +++ b/news/7950.bootloader.rst @@ -1,5 +1,6 @@ (Linux, macOS) When extracting files from ``onefile`` archive, the executable bit is now set only on binaries (files whose TOC type code -was either ``BINARY``, ``EXECUTABLE``, or ``EXTENSION``). Therefore, -binaries are now extracted with permissions bits set to ``0700``, while -all other files have permissions bits set to ``0600``. +was either ``BINARY``, ``EXECUTABLE``, or ``EXTENSION``) or data files +that originally had the executable bit set. Therefore, binaries are now +extracted with permissions bits set to ``0700``, while all other files +have permissions bits set to ``0600``.