author | Alberto Bertogli
<albertito@blitiri.com.ar> 2020-05-24 13:20:56 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2020-05-24 15:04:24 UTC |
parent | ad950208bf19d49e8f825007ba267ca3c43b8390 |
git-arr | +7 | -6 |
git.py | +24 | -16 |
utils.py | +22 | -20 |
diff --git a/git-arr b/git-arr index 05ac171..b109f23 100755 --- a/git-arr +++ b/git-arr @@ -9,8 +9,9 @@ import optparse import os import re import sys +from typing import Union -import bottle +import bottle # type: ignore import git import utils @@ -328,10 +329,10 @@ def is_404(e): return e.status_code == 404 -def generate(output, only=None): +def generate(output: str, only=None): """Generate static html to the output directory.""" - def write_to(path, func_or_str, args=(), mtime=None): + def write_to(path: str, func_or_str, args=(), mtime=None): path = output + "/" + path dirname = os.path.dirname(path) @@ -339,7 +340,7 @@ def generate(output, only=None): os.makedirs(dirname) if mtime: - path_mtime = 0 + path_mtime: Union[float, int] = 0 if os.path.exists(path): path_mtime = os.stat(path).st_mtime @@ -380,8 +381,8 @@ def generate(output, only=None): print(from_path, "->", to_path) os.symlink(to_path, from_path) - def write_tree(r, bn, mtime): - t = r.tree(bn) + def write_tree(r: git.Repo, bn: str, mtime): + t: git.Tree = r.tree(bn) write_to("r/%s/b/%s/t/index.html" % (r.name, bn), tree, (r, bn), mtime) diff --git a/git.py b/git.py index 3b2b5b7..846c1a6 100644 --- a/git.py +++ b/git.py @@ -14,13 +14,16 @@ import email.utils import datetime import urllib.request, urllib.parse, urllib.error from html import escape +from typing import Any, Dict, IO, Iterable, List, Optional, Tuple, Union # Path to the git binary. GIT_BIN = "git" -def run_git(repo_path, params, stdin=None, silent_stderr=False, raw=False): +def run_git( + repo_path: str, params, stdin: bytes = None, silent_stderr=False, raw=False +) -> Union[IO[str], IO[bytes]]: """Invokes git with the given parameters. This function invokes git with the given parameters, and returns a @@ -44,9 +47,12 @@ def run_git(repo_path, params, stdin=None, silent_stderr=False, raw=False): stderr=stderr, ) + assert p.stdin is not None p.stdin.write(stdin) p.stdin.close() + assert p.stdout is not None + if raw: return p.stdout @@ -58,13 +64,13 @@ def run_git(repo_path, params, stdin=None, silent_stderr=False, raw=False): class GitCommand(object): """Convenient way of invoking git.""" - def __init__(self, path, cmd, *args, **kwargs): + def __init__(self, path: str, cmd: str, *args, **kwargs): self._override = True self._path = path self._cmd = cmd - self._args = list(args) - self._kwargs = {} - self._stdin_buf = None + self._args: List[str] = list(args) + self._kwargs: Dict[str, str] = {} + self._stdin_buf: Optional[bytes] = None self._raw = False self._override = False for k, v in kwargs: @@ -77,17 +83,17 @@ class GitCommand(object): k = k.replace("_", "-") self._kwargs[k] = v - def arg(self, a): + def arg(self, a: str): """Adds an argument.""" self._args.append(a) - def raw(self, b): + def raw(self, b: bool): """Request raw rather than utf8-encoded command output.""" self._override = True self._raw = b self._override = False - def stdin(self, s): + def stdin(self, s: Union[str, bytes]): """Sets the contents we will send in stdin.""" self._override = True if isinstance(s, str): @@ -130,14 +136,14 @@ class smstr: .html -> an HTML-embeddable representation. """ - def __init__(self, raw): + def __init__(self, raw: str): if not isinstance(raw, (str, bytes)): raise TypeError( "The raw string must be instance of 'str', not %s" % type(raw) ) self.raw = raw if isinstance(raw, bytes): - self.unicode = raw.decode("utf8", errors="backslashreplace") + self.unicode: str = raw.decode("utf8", errors="backslashreplace") else: self.unicode = raw self.url = urllib.request.pathname2url(raw) @@ -177,7 +183,7 @@ class smstr: return html -def unquote(s): +def unquote(s: str): """Git can return quoted file names, unquote them. Always return a str.""" if not (s[0] == '"' and s[-1] == '"'): # Unquoted strings are always safe, no need to mess with them @@ -204,10 +210,10 @@ def unquote(s): class Repo: """A git repository.""" - def __init__(self, path, name=None, info=None): + def __init__(self, path: str, name=None, info=None): self.path = path self.name = name - self.info = info or SimpleNamespace() + self.info: Any = info or SimpleNamespace() def cmd(self, cmd): """Returns a GitCommand() on our path.""" @@ -535,11 +541,13 @@ class Diff: class Tree: """ A git tree.""" - def __init__(self, repo, ref): + def __init__(self, repo: Repo, ref: str): self.repo = repo self.ref = ref - def ls(self, path, recursive=False): + def ls( + self, path, recursive=False + ) -> Iterable[Tuple[str, smstr, Optional[int]]]: """Generates (type, name, size) for each file in path.""" cmd = self.repo.cmd("ls-tree") cmd.long = None @@ -575,7 +583,7 @@ class Tree: class Blob: """A git blob.""" - def __init__(self, raw_content): + def __init__(self, raw_content: bytes): self.raw_content = raw_content self._utf8_content = None diff --git a/utils.py b/utils.py index 0f25be1..9c2c45a 100644 --- a/utils.py +++ b/utils.py @@ -5,16 +5,16 @@ These are mostly used in templates, for presentation purposes. """ try: - import pygments - from pygments import highlight - from pygments import lexers - from pygments.formatters import HtmlFormatter + import pygments # type: ignore + from pygments import highlight # type: ignore + from pygments import lexers # type: ignore + from pygments.formatters import HtmlFormatter # type: ignore except ImportError: pygments = None try: - import markdown - import markdown.treeprocessors + import markdown # type: ignore + import markdown.treeprocessors # type: ignore except ImportError: markdown = None @@ -23,14 +23,16 @@ import mimetypes import string import os.path +import git -def shorten(s, width=60): + +def shorten(s: str, width=60): if len(s) < 60: return s return s[:57] + "..." -def can_colorize(s): +def can_colorize(s: str): """True if we can colorize the string, False otherwise.""" if pygments is None: return False @@ -54,7 +56,7 @@ def can_colorize(s): return True -def can_markdown(repo, fname): +def can_markdown(repo: git.Repo, fname: str): """True if we can process file through markdown, False otherwise.""" if markdown is None: return False @@ -75,14 +77,14 @@ def can_embed_image(repo, fname): ) -def colorize_diff(s): +def colorize_diff(s: str) -> str: lexer = lexers.DiffLexer(encoding="utf-8") formatter = HtmlFormatter(encoding="utf-8", cssclass="source_code") return highlight(s, lexer, formatter) -def colorize_blob(fname, s): +def colorize_blob(fname, s: str) -> str: try: lexer = lexers.guess_lexer_for_filename(fname, s, encoding="utf-8") except lexers.ClassNotFound: @@ -107,7 +109,7 @@ def colorize_blob(fname, s): return highlight(s, lexer, formatter) -def markdown_blob(s): +def markdown_blob(s: str) -> str: extensions = [ "markdown.extensions.fenced_code", "markdown.extensions.tables", @@ -116,7 +118,7 @@ def markdown_blob(s): return markdown.markdown(s, extensions=extensions) -def embed_image_blob(fname, image_data): +def embed_image_blob(fname: str, image_data: bytes) -> str: mimetype = mimetypes.guess_type(fname)[0] b64img = base64.b64encode(image_data).decode("ascii") return '<img style="max-width:100%;" src="data:{0};base64,{1}" />'.format( @@ -124,22 +126,22 @@ def embed_image_blob(fname, image_data): ) -def is_binary(s): +def is_binary(b: bytes): # Git considers a blob binary if NUL in first ~8KB, so do the same. - return b"\0" in s[:8192] + return b"\0" in b[:8192] -def hexdump(s): +def hexdump(s: bytes): graph = string.ascii_letters + string.digits + string.punctuation + " " - s = s.decode("latin1") + b = s.decode("latin1") offset = 0 - while s: - t = s[:16] + while b: + t = b[:16] hexvals = ["%.2x" % ord(c) for c in t] text = "".join(c if c in graph else "." for c in t) yield offset, " ".join(hexvals[:8]), " ".join(hexvals[8:]), text offset += 16 - s = s[16:] + b = b[16:] if markdown: