vimPlugins: Automate redirect updates in update.py
Many of the plugins in vim-plugin-names are out of date and redirect to their new github repos. This commit adds a flag to automatically update these and defines a process for committing these updates into nixpkgs.
This commit is contained in:
parent
11315a3e27
commit
d4874a7ee6
|
@ -263,7 +263,7 @@ Sometimes plugins require an override that must be changed when the plugin is up
|
||||||
|
|
||||||
To add a new plugin:
|
To add a new plugin:
|
||||||
|
|
||||||
1. run `./update.py` and create a commit named "vimPlugins: Update",
|
1. run `./update.py --update-redirects` and create a commit named "vimPlugins: Update",
|
||||||
2. add the new plugin to [vim-plugin-names](/pkgs/misc/vim-plugins/vim-plugin-names) and add overrides if required to [overrides.nix](/pkgs/misc/vim-plugins/overrides.nix),
|
2. add the new plugin to [vim-plugin-names](/pkgs/misc/vim-plugins/vim-plugin-names) and add overrides if required to [overrides.nix](/pkgs/misc/vim-plugins/overrides.nix),
|
||||||
3. run `./update.py` again and create a commit named "vimPlugins.[name]: init at [version]" (where `name` and `version` can be found in [generated.nix](/pkgs/misc/vim-plugins/generated.nix)), and
|
3. run `./update.py` again and create a commit named "vimPlugins.[name]: init at [version]" (where `name` and `version` can be found in [generated.nix](/pkgs/misc/vim-plugins/generated.nix)), and
|
||||||
4. create a pull request.
|
4. create a pull request.
|
||||||
|
|
|
@ -9,13 +9,16 @@
|
||||||
# $ nix run nixpkgs.python3Packages.flake8 -c flake8 --ignore E501,E265 update.py
|
# $ nix run nixpkgs.python3Packages.flake8 -c flake8 --ignore E501,E265 update.py
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import fileinput
|
||||||
import functools
|
import functools
|
||||||
|
import http
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import urllib.error
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
@ -71,9 +74,11 @@ def retry(ExceptionToCheck: Any, tries: int = 4, delay: float = 3, backoff: floa
|
||||||
|
|
||||||
|
|
||||||
class Repo:
|
class Repo:
|
||||||
def __init__(self, owner: str, name: str) -> None:
|
def __init__(self, owner: str, name: str, alias: str) -> None:
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.alias = alias
|
||||||
|
self.redirect: Dict[str, str] = {}
|
||||||
|
|
||||||
def url(self, path: str) -> str:
|
def url(self, path: str) -> str:
|
||||||
return urljoin(f"https://github.com/{self.owner}/{self.name}/", path)
|
return urljoin(f"https://github.com/{self.owner}/{self.name}/", path)
|
||||||
|
@ -96,7 +101,9 @@ class Repo:
|
||||||
|
|
||||||
@retry(urllib.error.URLError, tries=4, delay=3, backoff=2)
|
@retry(urllib.error.URLError, tries=4, delay=3, backoff=2)
|
||||||
def latest_commit(self) -> Tuple[str, datetime]:
|
def latest_commit(self) -> Tuple[str, datetime]:
|
||||||
with urllib.request.urlopen(self.url("commits/master.atom"), timeout=10) as req:
|
commit_url = self.url("commits/master.atom")
|
||||||
|
with urllib.request.urlopen(commit_url, timeout=10) as req:
|
||||||
|
self.check_for_redirect(commit_url, req)
|
||||||
xml = req.read()
|
xml = req.read()
|
||||||
root = ET.fromstring(xml)
|
root = ET.fromstring(xml)
|
||||||
latest_entry = root.find(ATOM_ENTRY)
|
latest_entry = root.find(ATOM_ENTRY)
|
||||||
|
@ -111,6 +118,22 @@ class Repo:
|
||||||
updated = datetime.strptime(updated_tag.text, "%Y-%m-%dT%H:%M:%SZ")
|
updated = datetime.strptime(updated_tag.text, "%Y-%m-%dT%H:%M:%SZ")
|
||||||
return Path(str(url.path)).name, updated
|
return Path(str(url.path)).name, updated
|
||||||
|
|
||||||
|
def check_for_redirect(self, url: str, req: http.client.HTTPResponse):
|
||||||
|
response_url = req.geturl()
|
||||||
|
if url != response_url:
|
||||||
|
new_owner, new_name = (
|
||||||
|
urllib.parse.urlsplit(response_url).path.strip("/").split("/")[:2]
|
||||||
|
)
|
||||||
|
end_line = f" as {self.alias}\n" if self.alias else "\n"
|
||||||
|
plugin_line = "{owner}/{name}" + end_line
|
||||||
|
|
||||||
|
old_plugin = plugin_line.format(owner=self.owner, name=self.name)
|
||||||
|
new_plugin = plugin_line.format(owner=new_owner, name=new_name)
|
||||||
|
self.redirect[old_plugin] = new_plugin
|
||||||
|
|
||||||
|
if new_name != self.name:
|
||||||
|
print(f"Plugin Name Changed: {self.name} -> {new_name}")
|
||||||
|
|
||||||
def prefetch_git(self, ref: str) -> str:
|
def prefetch_git(self, ref: str) -> str:
|
||||||
data = subprocess.check_output(
|
data = subprocess.check_output(
|
||||||
["nix-prefetch-git", "--fetch-submodules", self.url(""), ref]
|
["nix-prefetch-git", "--fetch-submodules", self.url(""), ref]
|
||||||
|
@ -197,15 +220,17 @@ def get_current_plugins() -> List[Plugin]:
|
||||||
return plugins
|
return plugins
|
||||||
|
|
||||||
|
|
||||||
def prefetch_plugin(user: str, repo_name: str, alias: str, cache: "Cache") -> Plugin:
|
def prefetch_plugin(
|
||||||
repo = Repo(user, repo_name)
|
user: str, repo_name: str, alias: str, cache: "Cache"
|
||||||
|
) -> Tuple[Plugin, Dict[str, str]]:
|
||||||
|
repo = Repo(user, repo_name, alias)
|
||||||
commit, date = repo.latest_commit()
|
commit, date = repo.latest_commit()
|
||||||
has_submodules = repo.has_submodules()
|
has_submodules = repo.has_submodules()
|
||||||
cached_plugin = cache[commit]
|
cached_plugin = cache[commit]
|
||||||
if cached_plugin is not None:
|
if cached_plugin is not None:
|
||||||
cached_plugin.name = alias or repo_name
|
cached_plugin.name = alias or repo_name
|
||||||
cached_plugin.date = date
|
cached_plugin.date = date
|
||||||
return cached_plugin
|
return cached_plugin, repo.redirect
|
||||||
|
|
||||||
print(f"prefetch {user}/{repo_name}")
|
print(f"prefetch {user}/{repo_name}")
|
||||||
if has_submodules:
|
if has_submodules:
|
||||||
|
@ -213,7 +238,10 @@ def prefetch_plugin(user: str, repo_name: str, alias: str, cache: "Cache") -> Pl
|
||||||
else:
|
else:
|
||||||
sha256 = repo.prefetch_github(commit)
|
sha256 = repo.prefetch_github(commit)
|
||||||
|
|
||||||
return Plugin(alias or repo_name, commit, has_submodules, sha256, date=date)
|
return (
|
||||||
|
Plugin(alias or repo_name, commit, has_submodules, sha256, date=date),
|
||||||
|
repo.redirect,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def print_download_error(plugin: str, ex: Exception):
|
def print_download_error(plugin: str, ex: Exception):
|
||||||
|
@ -227,20 +255,22 @@ def print_download_error(plugin: str, ex: Exception):
|
||||||
|
|
||||||
|
|
||||||
def check_results(
|
def check_results(
|
||||||
results: List[Tuple[str, str, Union[Exception, Plugin]]]
|
results: List[Tuple[str, str, Union[Exception, Plugin], Dict[str, str]]]
|
||||||
) -> List[Tuple[str, str, Plugin]]:
|
) -> Tuple[List[Tuple[str, str, Plugin]], Dict[str, str]]:
|
||||||
failures: List[Tuple[str, Exception]] = []
|
failures: List[Tuple[str, Exception]] = []
|
||||||
plugins = []
|
plugins = []
|
||||||
for (owner, name, result) in results:
|
redirects: Dict[str, str] = {}
|
||||||
|
for (owner, name, result, redirect) in results:
|
||||||
if isinstance(result, Exception):
|
if isinstance(result, Exception):
|
||||||
failures.append((name, result))
|
failures.append((name, result))
|
||||||
else:
|
else:
|
||||||
plugins.append((owner, name, result))
|
plugins.append((owner, name, result))
|
||||||
|
redirects.update(redirect)
|
||||||
|
|
||||||
print(f"{len(results) - len(failures)} plugins were checked", end="")
|
print(f"{len(results) - len(failures)} plugins were checked", end="")
|
||||||
if len(failures) == 0:
|
if len(failures) == 0:
|
||||||
print()
|
print()
|
||||||
return plugins
|
return plugins, redirects
|
||||||
else:
|
else:
|
||||||
print(f", {len(failures)} plugin(s) could not be downloaded:\n")
|
print(f", {len(failures)} plugin(s) could not be downloaded:\n")
|
||||||
|
|
||||||
|
@ -328,15 +358,15 @@ class Cache:
|
||||||
|
|
||||||
def prefetch(
|
def prefetch(
|
||||||
args: Tuple[str, str, str], cache: Cache
|
args: Tuple[str, str, str], cache: Cache
|
||||||
) -> Tuple[str, str, Union[Exception, Plugin]]:
|
) -> Tuple[str, str, Union[Exception, Plugin], dict]:
|
||||||
assert len(args) == 3
|
assert len(args) == 3
|
||||||
owner, repo, alias = args
|
owner, repo, alias = args
|
||||||
try:
|
try:
|
||||||
plugin = prefetch_plugin(owner, repo, alias, cache)
|
plugin, redirect = prefetch_plugin(owner, repo, alias, cache)
|
||||||
cache[plugin.commit] = plugin
|
cache[plugin.commit] = plugin
|
||||||
return (owner, repo, plugin)
|
return (owner, repo, plugin, redirect)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return (owner, repo, e)
|
return (owner, repo, e, {})
|
||||||
|
|
||||||
|
|
||||||
header = (
|
header = (
|
||||||
|
@ -386,6 +416,31 @@ in lib.fix' (lib.extends overrides packages)
|
||||||
print(f"updated {outfile}")
|
print(f"updated {outfile}")
|
||||||
|
|
||||||
|
|
||||||
|
def update_redirects(input_file: Path, output_file: Path, redirects: dict):
|
||||||
|
with fileinput.input(input_file, inplace=True) as f:
|
||||||
|
for line in f:
|
||||||
|
print(redirects.get(line, line), end="")
|
||||||
|
print(
|
||||||
|
f"""\
|
||||||
|
Redirects have been detected and {input_file} has been updated. Please take the
|
||||||
|
following steps:
|
||||||
|
1. Go ahead and commit just the updated expressions as you intended to do:
|
||||||
|
git add {output_file}
|
||||||
|
git commit -m "vimPlugins: Update"
|
||||||
|
2. If any of the plugin names were changed, add the old names as aliases in
|
||||||
|
aliases.nix
|
||||||
|
3. Make sure the updated {input_file} is still correctly sorted:
|
||||||
|
sort -udf ./vim-plugin-names > sorted && mv sorted vim-plugin-names
|
||||||
|
4. Run this script again so these changes will be reflected in the
|
||||||
|
generated expressions (no need to use the --update-redirects flag again):
|
||||||
|
./update.py
|
||||||
|
5. Commit {input_file} along with aliases and generated expressions:
|
||||||
|
git add {output_file} {input_file} aliases.nix
|
||||||
|
git commit -m "vimPlugins: Update redirects"
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description=(
|
description=(
|
||||||
|
@ -407,6 +462,12 @@ def parse_args():
|
||||||
default=DEFAULT_OUT,
|
default=DEFAULT_OUT,
|
||||||
help="Filename to save generated nix code",
|
help="Filename to save generated nix code",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--update-redirects",
|
||||||
|
dest="update_redirects",
|
||||||
|
action="store_true",
|
||||||
|
help="Update input file if repos have been redirected.",
|
||||||
|
)
|
||||||
|
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
@ -428,10 +489,19 @@ def main() -> None:
|
||||||
finally:
|
finally:
|
||||||
cache.store()
|
cache.store()
|
||||||
|
|
||||||
plugins = check_results(results)
|
plugins, redirects = check_results(results)
|
||||||
|
|
||||||
generate_nix(plugins, args.outfile)
|
generate_nix(plugins, args.outfile)
|
||||||
|
|
||||||
|
if redirects:
|
||||||
|
if args.update_redirects:
|
||||||
|
update_redirects(args.input_file, args.outfile, redirects)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
"Outdated vim-plugin-names found. Please run with "
|
||||||
|
"--update-redirects flag."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in New Issue