Add _ prefix to logger

This commit is contained in:
Sleepy Monax 2023-11-10 11:31:44 +01:00
parent 548a35ffa1
commit 6822bb2352
6 changed files with 155 additions and 102 deletions

View file

@ -7,7 +7,7 @@ from cutekit.ninja import Writer
from cutekit.context import ComponentInstance, Context, contextFor from cutekit.context import ComponentInstance, Context, contextFor
from cutekit import shell, rules from cutekit import shell, rules
logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
def gen(out: TextIO, context: Context): def gen(out: TextIO, context: Context):

View file

@ -12,7 +12,7 @@ from cutekit.context import contextFor
Callback = Callable[[Args], None] Callback = Callable[[Args], None]
logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class Cmd: class Cmd:
@ -247,11 +247,11 @@ def initCmd(args: Args):
template = args.consumeArg() template = args.consumeArg()
name = args.consumeArg() name = args.consumeArg()
logger.info("Fetching registry...") _logger.info("Fetching registry...")
r = requests.get(f"https://raw.githubusercontent.com/{repo}/main/registry.json") r = requests.get(f"https://raw.githubusercontent.com/{repo}/main/registry.json")
if r.status_code != 200: if r.status_code != 200:
logger.error("Failed to fetch registry") _logger.error("Failed to fetch registry")
exit(1) exit(1)
registry = r.json() registry = r.json()
@ -272,7 +272,7 @@ def initCmd(args: Args):
raise LookupError(f"Couldn't find a template named {template}") raise LookupError(f"Couldn't find a template named {template}")
if not name: if not name:
logger.info(f"No name was provided, defaulting to {template}") _logger.info(f"No name was provided, defaulting to {template}")
name = template name = template
if os.path.exists(name): if os.path.exists(name):

View file

@ -4,10 +4,18 @@ from pathlib import Path
import os import os
import logging import logging
from cutekit.model import ProjectManifest, TargetManifest, ComponentManifest, Props, Type, Tool, Tools from cutekit.model import (
ProjectManifest,
TargetManifest,
ComponentManifest,
Props,
Type,
Tool,
Tools,
)
from cutekit import const, shell, jexpr, utils, rules, mixins, project from cutekit import const, shell, jexpr, utils, rules, mixins, project
logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class IContext(Protocol): class IContext(Protocol):
@ -27,13 +35,14 @@ class ComponentInstance:
context: IContext context: IContext
def __init__( def __init__(
self, self,
enabled: bool, enabled: bool,
disableReason: str, disableReason: str,
manifest: ComponentManifest, manifest: ComponentManifest,
sources: list[str], sources: list[str],
res: list[str], res: list[str],
resolved: list[str]): resolved: list[str],
):
self.enabled = enabled self.enabled = enabled
self.disableReason = disableReason self.disableReason = disableReason
self.manifest = manifest self.manifest = manifest
@ -55,23 +64,34 @@ class ComponentInstance:
def objsfiles(self) -> list[tuple[str, str]]: def objsfiles(self) -> list[tuple[str, str]]:
def toOFile(s: str) -> str: def toOFile(s: str) -> str:
return os.path.join(self.objdir(), s.replace(os.path.join(self.manifest.dirname(), ''), '') + ".o") return os.path.join(
self.objdir(),
s.replace(os.path.join(self.manifest.dirname(), ""), "") + ".o",
)
return list(map(lambda s: (s, toOFile(s)), self.sources)) return list(map(lambda s: (s, toOFile(s)), self.sources))
def resfiles(self) -> list[tuple[str, str, str]]: def resfiles(self) -> list[tuple[str, str, str]]:
def toAssetFile(s: str) -> str: def toAssetFile(s: str) -> str:
return os.path.join(self.resdir(), s.replace(os.path.join(self.manifest.dirname(), 'res/'), '')) return os.path.join(
self.resdir(),
s.replace(os.path.join(self.manifest.dirname(), "res/"), ""),
)
def toAssetId(s: str) -> str: def toAssetId(s: str) -> str:
return s.replace(os.path.join(self.manifest.dirname(), 'res/'), '') return s.replace(os.path.join(self.manifest.dirname(), "res/"), "")
return list(map(lambda s: (s, toAssetFile(s), toAssetId(s)), self.res)) return list(map(lambda s: (s, toAssetFile(s), toAssetId(s)), self.res))
def outfile(self) -> str: def outfile(self) -> str:
if self.isLib(): if self.isLib():
return os.path.join(self.context.builddir(), self.manifest.id, f"lib/{self.manifest.id}.a") return os.path.join(
self.context.builddir(), self.manifest.id, f"lib/{self.manifest.id}.a"
)
else: else:
return os.path.join(self.context.builddir(), self.manifest.id, f"bin/{self.manifest.id}.out") return os.path.join(
self.context.builddir(), self.manifest.id, f"bin/{self.manifest.id}.out"
)
def cinclude(self) -> str: def cinclude(self) -> str:
if "cpp-root-include" in self.manifest.props: if "cpp-root-include" in self.manifest.props:
@ -90,7 +110,9 @@ class Context(IContext):
def enabledInstances(self) -> Iterable[ComponentInstance]: def enabledInstances(self) -> Iterable[ComponentInstance]:
return filter(lambda x: x.enabled, self.instances) return filter(lambda x: x.enabled, self.instances)
def __init__(self, target: TargetManifest, instances: list[ComponentInstance], tools: Tools): def __init__(
self, target: TargetManifest, instances: list[ComponentInstance], tools: Tools
):
self.target = target self.target = target
self.instances = instances self.instances = instances
self.tools = tools self.tools = tools
@ -102,15 +124,20 @@ class Context(IContext):
return result[0] return result[0]
def cincls(self) -> list[str]: def cincls(self) -> list[str]:
includes = list(filter(lambda x: x != "", map( includes = list(
lambda x: x.cinclude(), self.enabledInstances()))) filter(
lambda x: x != "", map(lambda x: x.cinclude(), self.enabledInstances())
)
)
return utils.uniq(includes) return utils.uniq(includes)
def cdefs(self) -> list[str]: def cdefs(self) -> list[str]:
return self.target.cdefs() return self.target.cdefs()
def hashid(self) -> str: def hashid(self) -> str:
return utils.hash((self.target.props, [self.tools[t].toJson() for t in self.tools]))[0:8] return utils.hash(
(self.target.props, [self.tools[t].toJson() for t in self.tools])
)[0:8]
def builddir(self) -> str: def builddir(self) -> str:
return os.path.join(const.BUILD_DIR, f"{self.target.id}-{self.hashid()[:8]}") return os.path.join(const.BUILD_DIR, f"{self.target.id}-{self.hashid()[:8]}")
@ -123,8 +150,10 @@ def loadAllTargets() -> list[TargetManifest]:
pj = loadProject(projectRoot) pj = loadProject(projectRoot)
paths = list( paths = list(
map(lambda e: os.path.join(const.EXTERN_DIR, map(
e, const.TARGETS_DIR), pj.extern.keys()) lambda e: os.path.join(const.EXTERN_DIR, e, const.TARGETS_DIR),
pj.extern.keys(),
)
) + [const.TARGETS_DIR] ) + [const.TARGETS_DIR]
ret = [] ret = []
@ -151,47 +180,50 @@ def loadAllComponents() -> list[ComponentManifest]:
files = shell.find(const.SRC_DIR, ["manifest.json"]) files = shell.find(const.SRC_DIR, ["manifest.json"])
files += shell.find(const.EXTERN_DIR, ["manifest.json"]) files += shell.find(const.EXTERN_DIR, ["manifest.json"])
return list( return list(map(lambda path: ComponentManifest(jexpr.evalRead(path), path), files))
map(
lambda path: ComponentManifest(jexpr.evalRead(path), path),
files))
def filterDisabled(components: list[ComponentManifest], target: TargetManifest) -> tuple[list[ComponentManifest], list[ComponentManifest]]: def filterDisabled(
return list(filter(lambda c: c.isEnabled(target)[0], components)), \ components: list[ComponentManifest], target: TargetManifest
list(filter(lambda c: not c.isEnabled(target)[0], components)) ) -> tuple[list[ComponentManifest], list[ComponentManifest]]:
return list(filter(lambda c: c.isEnabled(target)[0], components)), list(
filter(lambda c: not c.isEnabled(target)[0], components)
)
def providerFor(what: str, components: list[ComponentManifest]) -> tuple[Optional[str], str]: def providerFor(
result: list[ComponentManifest] = list( what: str, components: list[ComponentManifest]
filter(lambda c: c.id == what, components)) ) -> tuple[Optional[str], str]:
result: list[ComponentManifest] = list(filter(lambda c: c.id == what, components))
if len(result) == 0: if len(result) == 0:
# Try to find a provider # Try to find a provider
result = list(filter(lambda x: (what in x.provides), components)) result = list(filter(lambda x: (what in x.provides), components))
if len(result) == 0: if len(result) == 0:
logger.error(f"No provider for '{what}'") _logger.error(f"No provider for '{what}'")
return (None, f"No provider for '{what}'") return (None, f"No provider for '{what}'")
if len(result) > 1: if len(result) > 1:
ids = list(map(lambda x: x.id, result)) ids = list(map(lambda x: x.id, result))
logger.error(f"Multiple providers for '{what}': {result}") _logger.error(f"Multiple providers for '{what}': {result}")
return (None, f"Multiple providers for '{what}': {','.join(ids)}") return (None, f"Multiple providers for '{what}': {','.join(ids)}")
return (result[0].id, "") return (result[0].id, "")
def resolveDeps(componentSpec: str, components: list[ComponentManifest], target: TargetManifest) -> tuple[bool, str, list[str]]: def resolveDeps(
componentSpec: str, components: list[ComponentManifest], target: TargetManifest
) -> tuple[bool, str, list[str]]:
mapping = dict(map(lambda c: (c.id, c), components)) mapping = dict(map(lambda c: (c.id, c), components))
def resolveInner(what: str, stack: list[str] = []) -> tuple[bool, str, list[str]]: def resolveInner(what: str, stack: list[str] = []) -> tuple[bool, str, list[str]]:
result: list[str] = [] result: list[str] = []
what = target.route(what) what = target.route(what)
resolved, unresolvedReason = providerFor(what, components) resolved, unresolvedReason = providerFor(what, components)
if resolved is None: if resolved is None:
return False, unresolvedReason, [] return False, unresolvedReason, []
if resolved in stack: if resolved in stack:
raise RuntimeError(f"Dependency loop: {stack} -> {resolved}") raise RuntimeError(f"Dependency loop: {stack} -> {resolved}")
@ -199,12 +231,12 @@ def resolveDeps(componentSpec: str, components: list[ComponentManifest], target:
stack.append(resolved) stack.append(resolved)
for req in mapping[resolved].requires: for req in mapping[resolved].requires:
keep, unresolvedReason, reqs = resolveInner(req, stack) keep, unresolvedReason, reqs = resolveInner(req, stack)
if not keep: if not keep:
stack.pop() stack.pop()
logger.error(f"Dependency '{req}' not met for '{resolved}'") _logger.error(f"Dependency '{req}' not met for '{resolved}'")
return False, unresolvedReason, [] return False, unresolvedReason, []
result.extend(reqs) result.extend(reqs)
@ -218,29 +250,33 @@ def resolveDeps(componentSpec: str, components: list[ComponentManifest], target:
return enabled, unresolvedReason, resolved return enabled, unresolvedReason, resolved
def instanciate(componentSpec: str, components: list[ComponentManifest], target: TargetManifest) -> Optional[ComponentInstance]: def instanciate(
componentSpec: str, components: list[ComponentManifest], target: TargetManifest
) -> Optional[ComponentInstance]:
manifest = next(filter(lambda c: c.id == componentSpec, components)) manifest = next(filter(lambda c: c.id == componentSpec, components))
wildcards = set( wildcards = set(chain(*map(lambda rule: rule.fileIn, rules.rules.values())))
chain(*map(lambda rule: rule.fileIn, rules.rules.values()))) sources = shell.find(manifest.subdirs, list(wildcards), recusive=False)
sources = shell.find(
manifest.subdirs, list(wildcards), recusive=False)
res = shell.find(os.path.join(manifest.dirname(), "res")) res = shell.find(os.path.join(manifest.dirname(), "res"))
enabled, unresolvedReason, resolved = resolveDeps( enabled, unresolvedReason, resolved = resolveDeps(componentSpec, components, target)
componentSpec, components, target)
return ComponentInstance(enabled, unresolvedReason, manifest, sources, res, resolved[1:]) return ComponentInstance(
enabled, unresolvedReason, manifest, sources, res, resolved[1:]
)
def instanciateDisabled(component: ComponentManifest, target: TargetManifest) -> ComponentInstance: def instanciateDisabled(
component: ComponentManifest, target: TargetManifest
) -> ComponentInstance:
return ComponentInstance( return ComponentInstance(
enabled=False, enabled=False,
disableReason=component.isEnabled(target)[1], disableReason=component.isEnabled(target)[1],
manifest=component, manifest=component,
sources=[], sources=[],
res=[], res=[],
resolved=[]) resolved=[],
)
context: dict[str, Context] = {} context: dict[str, Context] = {}
@ -250,7 +286,7 @@ def contextFor(targetSpec: str, props: Props = {}) -> Context:
if targetSpec in context: if targetSpec in context:
return context[targetSpec] return context[targetSpec]
logger.info(f"Loading context for '{targetSpec}'") _logger.info(f"Loading context for '{targetSpec}'")
targetEls = targetSpec.split(":") targetEls = targetSpec.split(":")
@ -269,10 +305,8 @@ def contextFor(targetSpec: str, props: Props = {}) -> Context:
tool = target.tools[toolSpec] tool = target.tools[toolSpec]
tools[toolSpec] = Tool( tools[toolSpec] = Tool(
strict=False, strict=False, cmd=tool.cmd, args=tool.args, files=tool.files
cmd=tool.cmd, )
args=tool.args,
files=tool.files)
tools[toolSpec].args += rules.rules[toolSpec].args tools[toolSpec].args += rules.rules[toolSpec].args
@ -286,10 +320,18 @@ def contextFor(targetSpec: str, props: Props = {}) -> Context:
tools[toolSpec].args += tool.args tools[toolSpec].args += tool.args
instances: list[ComponentInstance] = list( instances: list[ComponentInstance] = list(
map(lambda c: instanciateDisabled(c, target), disabled)) map(lambda c: instanciateDisabled(c, target), disabled)
)
instances += cast(list[ComponentInstance], list(filter(lambda e: e is not None, map(lambda c: instanciate( instances += cast(
c.id, components, target), components)))) list[ComponentInstance],
list(
filter(
lambda e: e is not None,
map(lambda c: instanciate(c.id, components, target), components),
)
),
)
context[targetSpec] = Context( context[targetSpec] = Context(
target, target,

View file

@ -6,7 +6,7 @@ import logging
from cutekit.jexpr import Json from cutekit.jexpr import Json
logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
Props = dict[str, Any] Props = dict[str, Any]
@ -267,12 +267,12 @@ class ComponentManifest(Manifest):
def isEnabled(self, target: TargetManifest) -> tuple[bool, str]: def isEnabled(self, target: TargetManifest) -> tuple[bool, str]:
for k, v in self.enableIf.items(): for k, v in self.enableIf.items():
if k not in target.props: if k not in target.props:
logger.info(f"Component {self.id} disabled by missing {k} in target") _logger.info(f"Component {self.id} disabled by missing {k} in target")
return False, f"Missing props '{k}' in target" return False, f"Missing props '{k}' in target"
if target.props[k] not in v: if target.props[k] not in v:
vStrs = [f"'{str(x)}'" for x in v] vStrs = [f"'{str(x)}'" for x in v]
logger.info( _logger.info(
f"Component {self.id} disabled by {k}={target.props[k]} not in {v}" f"Component {self.id} disabled by {k}={target.props[k]} not in {v}"
) )
return ( return (

View file

@ -5,14 +5,15 @@ from cutekit import shell, project, const, context
import importlib.util as importlib import importlib.util as importlib
logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
def load(path: str): def load(path: str):
logger.info(f"Loading plugin {path}") _logger.info(f"Loading plugin {path}")
spec = importlib.spec_from_file_location("plugin", path) spec = importlib.spec_from_file_location("plugin", path)
if not spec or not spec.loader: if not spec or not spec.loader:
logger.error(f"Failed to load plugin {path}") _logger.error(f"Failed to load plugin {path}")
return None return None
module = importlib.module_from_spec(spec) module = importlib.module_from_spec(spec)
@ -20,16 +21,18 @@ def load(path: str):
def loadAll(): def loadAll():
logger.info("Loading plugins...") _logger.info("Loading plugins...")
projectRoot = project.root() projectRoot = project.root()
if projectRoot is None: if projectRoot is None:
logger.info("Not in project, skipping plugin loading") _logger.info("Not in project, skipping plugin loading")
return return
pj = context.loadProject(projectRoot) pj = context.loadProject(projectRoot)
paths = list(map(lambda e: os.path.join(const.EXTERN_DIR, e), pj.extern.keys())) + ["."] paths = list(map(lambda e: os.path.join(const.EXTERN_DIR, e), pj.extern.keys())) + [
"."
]
for dirname in paths: for dirname in paths:
pluginDir = os.path.join(projectRoot, dirname, const.META_DIR, "plugins") pluginDir = os.path.join(projectRoot, dirname, const.META_DIR, "plugins")
@ -39,6 +42,5 @@ def loadAll():
plugin = load(os.path.join(pluginDir, files)) plugin = load(os.path.join(pluginDir, files))
if plugin: if plugin:
logger.info(f"Loaded plugin {plugin.name}") _logger.info(f"Loaded plugin {plugin.name}")
plugin.init() plugin.init()

View file

@ -15,11 +15,13 @@ import tempfile
from typing import Optional from typing import Optional
from cutekit import const from cutekit import const
logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class Uname: class Uname:
def __init__(self, sysname: str, nodename: str, release: str, version: str, machine: str): def __init__(
self, sysname: str, nodename: str, release: str, version: str, machine: str
):
self.sysname = sysname self.sysname = sysname
self.nodename = nodename self.nodename = nodename
self.release = release self.release = release
@ -47,8 +49,10 @@ def sha256sum(path: str) -> str:
return hashlib.sha256(f.read()).hexdigest() return hashlib.sha256(f.read()).hexdigest()
def find(path: str | list[str], wildcards: list[str] = [], recusive: bool = True) -> list[str]: def find(
logger.info(f"Looking for files in {path} matching {wildcards}") path: str | list[str], wildcards: list[str] = [], recusive: bool = True
) -> list[str]:
_logger.info(f"Looking for files in {path} matching {wildcards}")
result: list[str] = [] result: list[str] = []
@ -84,7 +88,7 @@ def find(path: str | list[str], wildcards: list[str] = [], recusive: bool = True
def mkdir(path: str) -> str: def mkdir(path: str) -> str:
logger.info(f"Creating directory {path}") _logger.info(f"Creating directory {path}")
try: try:
os.makedirs(path) os.makedirs(path)
@ -95,7 +99,7 @@ def mkdir(path: str) -> str:
def rmrf(path: str) -> bool: def rmrf(path: str) -> bool:
logger.info(f"Removing directory {path}") _logger.info(f"Removing directory {path}")
if not os.path.exists(path): if not os.path.exists(path):
return False return False
@ -108,18 +112,18 @@ def wget(url: str, path: Optional[str] = None) -> str:
if path is None: if path is None:
path = os.path.join( path = os.path.join(
const.CACHE_DIR, const.CACHE_DIR, hashlib.sha256(url.encode("utf-8")).hexdigest()
hashlib.sha256(url.encode('utf-8')).hexdigest()) )
if os.path.exists(path): if os.path.exists(path):
return path return path
logger.info(f"Downloading {url} to {path}") _logger.info(f"Downloading {url} to {path}")
r = requests.get(url, stream=True) r = requests.get(url, stream=True)
r.raise_for_status() r.raise_for_status()
mkdir(os.path.dirname(path)) mkdir(os.path.dirname(path))
with open(path, 'wb') as f: with open(path, "wb") as f:
for chunk in r.iter_content(chunk_size=8192): for chunk in r.iter_content(chunk_size=8192):
if chunk: if chunk:
f.write(chunk) f.write(chunk)
@ -128,17 +132,20 @@ def wget(url: str, path: Optional[str] = None) -> str:
def exec(*args: str, quiet: bool = False) -> bool: def exec(*args: str, quiet: bool = False) -> bool:
logger.info(f"Executing {args}") _logger.info(f"Executing {args}")
try: try:
proc = subprocess.run( proc = subprocess.run(
args, stdout=sys.stdout if not quiet else subprocess.PIPE, stderr=sys.stderr if not quiet else subprocess.PIPE) args,
stdout=sys.stdout if not quiet else subprocess.PIPE,
stderr=sys.stderr if not quiet else subprocess.PIPE,
)
if proc.stdout: if proc.stdout:
logger.info(proc.stdout.decode('utf-8')) _logger.info(proc.stdout.decode("utf-8"))
if proc.stderr: if proc.stderr:
logger.error(proc.stderr.decode('utf-8')) _logger.error(proc.stderr.decode("utf-8"))
except FileNotFoundError: except FileNotFoundError:
raise RuntimeError(f"{args[0]}: Command not found") raise RuntimeError(f"{args[0]}: Command not found")
@ -150,14 +157,13 @@ def exec(*args: str, quiet: bool = False) -> bool:
raise RuntimeError(f"{args[0]}: Segmentation fault") raise RuntimeError(f"{args[0]}: Segmentation fault")
if proc.returncode != 0: if proc.returncode != 0:
raise RuntimeError( raise RuntimeError(f"{args[0]}: Process exited with code {proc.returncode}")
f"{args[0]}: Process exited with code {proc.returncode}")
return True return True
def popen(*args: str) -> str: def popen(*args: str) -> str:
logger.info(f"Executing {args}") _logger.info(f"Executing {args}")
try: try:
proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=sys.stderr) proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=sys.stderr)
@ -168,14 +174,13 @@ def popen(*args: str) -> str:
raise RuntimeError(f"{args[0]}: Segmentation fault") raise RuntimeError(f"{args[0]}: Segmentation fault")
if proc.returncode != 0: if proc.returncode != 0:
raise RuntimeError( raise RuntimeError(f"{args[0]}: Process exited with code {proc.returncode}")
f"{args[0]}: Process exited with code {proc.returncode}")
return proc.stdout.decode('utf-8') return proc.stdout.decode("utf-8")
def readdir(path: str) -> list[str]: def readdir(path: str) -> list[str]:
logger.info(f"Reading directory {path}") _logger.info(f"Reading directory {path}")
try: try:
return os.listdir(path) return os.listdir(path)
@ -184,19 +189,19 @@ def readdir(path: str) -> list[str]:
def cp(src: str, dst: str): def cp(src: str, dst: str):
logger.info(f"Copying {src} to {dst}") _logger.info(f"Copying {src} to {dst}")
shutil.copy(src, dst) shutil.copy(src, dst)
def mv(src: str, dst: str): def mv(src: str, dst: str):
logger.info(f"Moving {src} to {dst}") _logger.info(f"Moving {src} to {dst}")
shutil.move(src, dst) shutil.move(src, dst)
def cpTree(src: str, dst: str): def cpTree(src: str, dst: str):
logger.info(f"Copying {src} to {dst}") _logger.info(f"Copying {src} to {dst}")
shutil.copytree(src, dst, dirs_exist_ok=True) shutil.copytree(src, dst, dirs_exist_ok=True)
@ -204,10 +209,14 @@ def cpTree(src: str, dst: str):
def cloneDir(url: str, path: str, dest: str) -> str: def cloneDir(url: str, path: str, dest: str) -> str:
with tempfile.TemporaryDirectory() as tmp: with tempfile.TemporaryDirectory() as tmp:
mkdir(tmp) mkdir(tmp)
exec(*["git", "clone", "-n", "--depth=1", exec(
"--filter=tree:0", url, tmp, "-q"], quiet=True) *["git", "clone", "-n", "--depth=1", "--filter=tree:0", url, tmp, "-q"],
exec(*["git", "-C", tmp, "sparse-checkout", quiet=True,
"set", "--no-cone", path, "-q"], quiet=True) )
exec(
*["git", "-C", tmp, "sparse-checkout", "set", "--no-cone", path, "-q"],
quiet=True,
)
exec(*["git", "-C", tmp, "checkout", "-q", "--no-progress"], quiet=True) exec(*["git", "-C", tmp, "checkout", "-q", "--no-progress"], quiet=True)
mv(os.path.join(tmp, path), dest) mv(os.path.join(tmp, path), dest)
@ -232,7 +241,7 @@ def latest(cmd: str) -> str:
if cmd in LATEST_CACHE: if cmd in LATEST_CACHE:
return LATEST_CACHE[cmd] return LATEST_CACHE[cmd]
logger.info(f"Finding latest version of {cmd}") _logger.info(f"Finding latest version of {cmd}")
regex: re.Pattern[str] regex: re.Pattern[str]
@ -254,7 +263,7 @@ def latest(cmd: str) -> str:
versions.sort() versions.sort()
chosen = versions[-1] chosen = versions[-1]
logger.info(f"Chosen {chosen} as latest version of {cmd}") _logger.info(f"Chosen {chosen} as latest version of {cmd}")
LATEST_CACHE[cmd] = chosen LATEST_CACHE[cmd] = chosen