about summary refs log tree commit diff stats
path: root/pkgs/by-name/up/update-vim-plugins/update_vim_plugins/plugin.py
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-05-23 13:26:22 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-05-23 13:26:22 +0200
commit204731c0a69136c9cebcb54f1afecf5145e26bbe (patch)
treefc9132e5dc74e4a8e1327cdd411839a90f9410aa /pkgs/by-name/up/update-vim-plugins/update_vim_plugins/plugin.py
parentrefactor(sys): Modularize and move to `modules/system` or `pkgs` (diff)
downloadnixos-config-204731c0a69136c9cebcb54f1afecf5145e26bbe.zip
refactor(pkgs): Categorize into `by-name` shards
This might not be the perfect way to organize a package set --
especially if the set is not nearly the size of nixpkgs -- but it is
_at_ least a way of organization.
Diffstat (limited to 'pkgs/by-name/up/update-vim-plugins/update_vim_plugins/plugin.py')
-rw-r--r--pkgs/by-name/up/update-vim-plugins/update_vim_plugins/plugin.py182
1 files changed, 182 insertions, 0 deletions
diff --git a/pkgs/by-name/up/update-vim-plugins/update_vim_plugins/plugin.py b/pkgs/by-name/up/update-vim-plugins/update_vim_plugins/plugin.py
new file mode 100644
index 00000000..8334ad53
--- /dev/null
+++ b/pkgs/by-name/up/update-vim-plugins/update_vim_plugins/plugin.py
@@ -0,0 +1,182 @@
+import logging
+import os
+import urllib
+
+import requests
+import jsonpickle
+from datetime import datetime, date
+from dateparser import parse
+
+from .nix import GitSource, License, Source, UrlSource
+from .spec import PluginSpec, RepositoryHost
+
+
+logger = logging.getLogger(__name__)
+
+
+class VimPlugin:
+    """Abstract base class for vim plugins."""
+
+    name: str
+    owner: str
+    repo: str
+    version: date
+    source: Source
+    description: str = "No description"
+    homepage: str
+    license: License
+    source_line: str
+    checked: date = datetime.now().date()
+
+    def to_nix(self):
+        """Return the nix expression for this plugin."""
+        meta = f'with lib; {{ description = "{self.description}"; homepage = "{self.homepage}"; license = with licenses; [ {self.license.value} ]; }}'
+        return f'/* Generated from: {self.source_line} */ {self.name} = buildVimPlugin {{ pname = "{self.name}";  version = "{self.version}"; src = {self.source.get_nix_expression()}; meta = {meta}; }};'
+
+    def to_json(self):
+        """Serizalize the plugin to json"""
+        return jsonpickle.encode(self)
+
+    def to_markdown(self):
+        link = f"[{self.source_line}]({self.homepage})"
+        version = f"{self.version}"
+        package_name = f"{self.name}"
+        checked = f"{self.checked}"
+
+        return f"| {link} | {version} | `{package_name}` | {checked} |"
+
+    def __lt__(self, o: object) -> bool:
+        if not isinstance(o, VimPlugin):
+            return False
+
+        return self.name.lower() < o.name.lower()
+
+    def __repr__(self):
+        """Return the representation of this plugin."""
+        return f"VimPlugin({self.name!r}, {self.version.strftime('%Y-%m-%d')})"
+
+
+def _get_github_token():
+    token = os.environ.get("GITHUB_TOKEN")
+    if token is None:
+        # NOTE: This should never use more than the free api requests <2023-12-09>
+        pass
+        # logger.warning("GITHUB_TOKEN environment variable not set")
+    return token
+
+
+class GitHubPlugin(VimPlugin):
+    def __init__(self, plugin_spec: PluginSpec) -> None:
+        """Initialize a GitHubPlugin."""
+
+        full_name = f"{plugin_spec.owner}/{plugin_spec.repo}"
+        repo_info = self._api_call(f"repos/{full_name}")
+        default_branch = plugin_spec.branch or repo_info["default_branch"]
+        api_callback = self._api_call(f"repos/{full_name}/commits/{default_branch}")
+        latest_commit = api_callback["commit"]
+        sha = api_callback["sha"]
+
+        self.name = plugin_spec.name
+        self.owner = plugin_spec.owner
+        self.version = parse(latest_commit["committer"]["date"]).date()
+        self.source = UrlSource(f"https://github.com/{full_name}/archive/{sha}.tar.gz")
+        self.description = (repo_info.get("description") or "").replace('"', '\\"')
+        self.homepage = repo_info["html_url"]
+        self.license = plugin_spec.license or License.from_spdx_id((repo_info.get("license") or {}).get("spdx_id"))
+        self.source_line = plugin_spec.line
+
+    def _api_call(self, path: str, token: str | None = _get_github_token()):
+        """Call the GitHub API."""
+        url = f"https://api.github.com/{path}"
+        headers = {"Content-Type": "application/json"}
+        if token is not None:
+            headers["Authorization"] = f"token {token}"
+        response = requests.get(url, headers=headers)
+        if response.status_code != 200:
+            raise RuntimeError(f"GitHub API call failed: {response.text}")
+        return response.json()
+
+
+class GitlabPlugin(VimPlugin):
+    def __init__(self, plugin_spec: PluginSpec) -> None:
+        """Initialize a GitlabPlugin."""
+
+        full_name = urllib.parse.quote(f"{plugin_spec.owner}/{plugin_spec.repo}", safe="")
+        repo_info = self._api_call(f"projects/{full_name}")
+        default_branch = plugin_spec.branch or repo_info["default_branch"]
+        api_callback = self._api_call(f"projects/{full_name}/repository/branches/{default_branch}")
+        latest_commit = api_callback["commit"]
+        sha = latest_commit["id"]
+
+        self.name = plugin_spec.name
+        self.owner = plugin_spec.owner
+        self.version = parse(latest_commit["created_at"]).date()
+        self.source = UrlSource(f"https://gitlab.com/api/v4/projects/{full_name}/repository/archive.tar.gz?sha={sha}")
+        self.description = (repo_info.get("description") or "").replace('"', '\\"')
+        self.homepage = repo_info["web_url"]
+        self.license = plugin_spec.license or License.from_spdx_id(repo_info.get("license", {}).get("key"))
+        self.source_line = plugin_spec.line
+
+    def _api_call(self, path: str) -> dict:
+        """Call the Gitlab API."""
+        url = f"https://gitlab.com/api/v4/{path}"
+        response = requests.get(url)
+        if response.status_code != 200:
+            raise RuntimeError(f"Gitlab API call failed: {response.text}")
+        return response.json()
+
+
+def _get_sourcehut_token():
+    token = os.environ.get("SOURCEHUT_TOKEN")
+    if token is None:
+        # NOTE: This should never use more than the free requests <2023-12-09>
+        pass
+        # logger.warning("SOURCEHUT_TOKEN environment variable not set")
+    return token
+
+
+class SourceHutPlugin(VimPlugin):
+    def __init__(self, plugin_spec: PluginSpec) -> None:
+        """Initialize a SourceHutPlugin."""
+
+        repo_info = self._api_call(f"~{plugin_spec.owner}/repos/{plugin_spec.repo}")
+        if plugin_spec.branch is None:
+            commits = self._api_call(f"~{plugin_spec.owner}/repos/{plugin_spec.repo}/log")
+        else:
+            commits = self._api_call(f"~{plugin_spec.owner}/repos/{plugin_spec.repo}/log/{plugin_spec.branch}")
+        latest_commit = commits["results"][0]
+        sha = latest_commit["id"]
+
+        self.name = plugin_spec.name
+        self.owner = plugin_spec.owner
+        self.version = parse(latest_commit["timestamp"]).date()
+        self.description = (repo_info.get("description") or "").replace('"', '\\"')
+        self.homepage = f"https://git.sr.ht/~{plugin_spec.owner}/{plugin_spec.repo}"
+        self.source = GitSource(self.homepage, sha)
+        self.license = plugin_spec.license or License.UNKNOWN  # cannot be determined via API
+        self.source_line = plugin_spec.line
+
+    def _api_call(self, path: str, token: str | None = _get_sourcehut_token()):
+        """Call the SourceHut API."""
+
+        url = f"https://git.sr.ht/api/{path}"
+        headers = {"Content-Type": "application/json"}
+        if token is not None:
+            headers["Authorization"] = f"token {token}"
+        response = requests.get(url, headers=headers)
+        if response.status_code != 200:
+            raise RuntimeError(f"SourceHut API call failed: {response.json()}")
+        return response.json()
+
+
+def plugin_from_spec(plugin_spec: PluginSpec) -> VimPlugin:
+    """Initialize a VimPlugin."""
+
+    if plugin_spec.repository_host == RepositoryHost.GITHUB:
+        return GitHubPlugin(plugin_spec)
+    elif plugin_spec.repository_host == RepositoryHost.GITLAB:
+        return GitlabPlugin(plugin_spec)
+    elif plugin_spec.repository_host == RepositoryHost.SOURCEHUT:
+        return SourceHutPlugin(plugin_spec)
+    else:
+        raise NotImplementedError(f"Unsupported source: {plugin_spec.repository_host}")