diff --git a/package_control/distinfo.py b/package_control/distinfo.py index b0861878..d9bacb76 100644 --- a/package_control/distinfo.py +++ b/package_control/distinfo.py @@ -222,6 +222,28 @@ def generate_installer(self): return "Package Control\n" + def add_installer_to_record(self): + R""" + Add INSTALLER entry to .dist-info/RECORD file. + + Note: hash has been pre-compiled using... + + ```py + digest = hashlib.sha256("Package Control\n".encode("utf-8")).digest() + sha = base64.urlsafe_b64encode(digest).rstrip(b"=").decode("utf-8") + ``` + """ + installer = self.dir_name + "/INSTALLER," + record = self.abs_path("RECORD") + + # make sure not to add duplicate entries + with open(record, "r", encoding="utf-8") as fobj: + items = [item for item in fobj.readlines() if not item.startswith(installer)] + items.append(installer + "sha256=Hg_Q6w_I4zpFfb6C24LQdd4oTAMHJZDk9gtuV2yOgkw,16\n") + + with open(record, "w", encoding="utf-8", newline="\n") as fobj: + fobj.writelines(sorted(items)) + def generate_record(self, package_dirs, package_files): """ Generates the .dist-info/RECORD file contents diff --git a/package_control/package_cleanup.py b/package_control/package_cleanup.py index 05003213..581a678b 100644 --- a/package_control/package_cleanup.py +++ b/package_control/package_cleanup.py @@ -97,6 +97,7 @@ def run(self): removed_packages = None self.remove_legacy_libraries() + self.autofix_missing_installer() # Check metadata to verify packages were not improperly installed self.migrate_incompatible_packages(found_packages) @@ -446,6 +447,47 @@ def install_missing_packages(self, found_packages): with ActivityIndicator('Installing missing packages...') as progress: self.run_install_tasks(tasks, progress, unattended=True, package_kind='missing') + def autofix_missing_installer(self): + """ + Add missing INSTALLER file to available unmodified libraries + + Libraries without INSTALLER are treated unmanaged + and thus are not upgraded or removed automatically. + + Package Control prior to v4.0.7 didn't add INSTALLER for + installed whl files. This option lets users fix it, manually. + """ + + available_libraries = self.manager.list_available_libraries() + for lib in self.manager.list_libraries(): + installer = lib.dist_info.read_installer() + if installer: + continue + + available_library = available_libraries.get(lib.dist_name) + if not available_library: + continue + + if not any( + lib.python_version in available_release['python_versions'] + for available_release in available_library['releases'] + ): + continue + + if not lib.dist_info.verify_files(): + console_write( + 'Library "%s" for Python %s was modified, skipping!', + (lib.name, lib.python_version) + ) + continue + + lib.dist_info.write_installer() + lib.dist_info.add_installer_to_record() + console_write( + 'Library "%s" for Python %s fixed!', + (lib.name, lib.python_version) + ) + def remove_legacy_libraries(self): """ Rename .dist-info directory diff --git a/package_control/package_manager.py b/package_control/package_manager.py index 8c3c44e0..e52f8235 100644 --- a/package_control/package_manager.py +++ b/package_control/package_manager.py @@ -1275,6 +1275,9 @@ def install_library(self, lib): ) return False + temp_did.write_installer() + temp_did.add_installer_to_record() + try: temp_did.verify_python_version(lib.python_version) except EnvironmentError as e: