195 lines
4.6 KiB
Python
195 lines
4.6 KiB
Python
"""Path operations."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import re
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
from reflex import constants
|
|
|
|
# Shorthand for join.
|
|
join = os.linesep.join
|
|
|
|
|
|
def rm(path: str):
|
|
"""Remove a file or directory.
|
|
|
|
Args:
|
|
path: The path to the file or directory.
|
|
"""
|
|
if os.path.isdir(path):
|
|
shutil.rmtree(path)
|
|
elif os.path.isfile(path):
|
|
os.remove(path)
|
|
|
|
|
|
def cp(src: str, dest: str, overwrite: bool = True) -> bool:
|
|
"""Copy a file or directory.
|
|
|
|
Args:
|
|
src: The path to the file or directory.
|
|
dest: The path to the destination.
|
|
overwrite: Whether to overwrite the destination.
|
|
|
|
Returns:
|
|
Whether the copy was successful.
|
|
"""
|
|
if src == dest:
|
|
return False
|
|
if not overwrite and os.path.exists(dest):
|
|
return False
|
|
if os.path.isdir(src):
|
|
rm(dest)
|
|
shutil.copytree(src, dest)
|
|
else:
|
|
shutil.copyfile(src, dest)
|
|
return True
|
|
|
|
|
|
def mv(src: str, dest: str, overwrite: bool = True) -> bool:
|
|
"""Move a file or directory.
|
|
|
|
Args:
|
|
src: The path to the file or directory.
|
|
dest: The path to the destination.
|
|
overwrite: Whether to overwrite the destination.
|
|
|
|
Returns:
|
|
Whether the move was successful.
|
|
"""
|
|
if src == dest:
|
|
return False
|
|
if not overwrite and os.path.exists(dest):
|
|
return False
|
|
rm(dest)
|
|
shutil.move(src, dest)
|
|
return True
|
|
|
|
|
|
def mkdir(path: str):
|
|
"""Create a directory.
|
|
|
|
Args:
|
|
path: The path to the directory.
|
|
"""
|
|
os.makedirs(path, exist_ok=True)
|
|
|
|
|
|
def ln(src: str, dest: str, overwrite: bool = False) -> bool:
|
|
"""Create a symbolic link.
|
|
|
|
Args:
|
|
src: The path to the file or directory.
|
|
dest: The path to the destination.
|
|
overwrite: Whether to overwrite the destination.
|
|
|
|
Returns:
|
|
Whether the link was successful.
|
|
"""
|
|
if src == dest:
|
|
return False
|
|
if not overwrite and (os.path.exists(dest) or os.path.islink(dest)):
|
|
return False
|
|
if os.path.isdir(src):
|
|
rm(dest)
|
|
os.symlink(src, dest, target_is_directory=True)
|
|
else:
|
|
os.symlink(src, dest)
|
|
return True
|
|
|
|
|
|
def which(program: str) -> str | None:
|
|
"""Find the path to an executable.
|
|
|
|
Args:
|
|
program: The name of the executable.
|
|
|
|
Returns:
|
|
The path to the executable.
|
|
"""
|
|
return shutil.which(program)
|
|
|
|
|
|
def get_node_bin_path() -> str | None:
|
|
"""Get the node binary dir path.
|
|
|
|
Returns:
|
|
The path to the node bin folder.
|
|
"""
|
|
if not os.path.exists(constants.Node.BIN_PATH):
|
|
str_path = which("node")
|
|
return str(Path(str_path).parent) if str_path else str_path
|
|
return constants.Node.BIN_PATH
|
|
|
|
|
|
def get_node_path() -> str | None:
|
|
"""Get the node binary path.
|
|
|
|
Returns:
|
|
The path to the node binary file.
|
|
"""
|
|
if not os.path.exists(constants.Node.PATH):
|
|
return which("node")
|
|
return constants.Node.PATH
|
|
|
|
|
|
def get_npm_path() -> str | None:
|
|
"""Get npm binary path.
|
|
|
|
Returns:
|
|
The path to the npm binary file.
|
|
"""
|
|
if not os.path.exists(constants.Node.PATH):
|
|
return which("npm")
|
|
return constants.Node.NPM_PATH
|
|
|
|
|
|
def update_json_file(file_path: str, update_dict: dict[str, int | str]):
|
|
"""Update the contents of a json file.
|
|
|
|
Args:
|
|
file_path: the path to the JSON file.
|
|
update_dict: object to update json.
|
|
"""
|
|
fp = Path(file_path)
|
|
|
|
# Create the file if it doesn't exist.
|
|
fp.touch(exist_ok=True)
|
|
|
|
# Create an empty json object if file is empty
|
|
fp.write_text("{}") if fp.stat().st_size == 0 else None
|
|
|
|
# Read the existing json object from the file.
|
|
json_object = {}
|
|
if fp.stat().st_size == 0:
|
|
with open(fp) as f:
|
|
json_object = json.load(f)
|
|
|
|
# Update the json object with the new data.
|
|
json_object.update(update_dict)
|
|
|
|
# Write the updated json object to the file
|
|
with open(fp, "w") as f:
|
|
json.dump(json_object, f, ensure_ascii=False)
|
|
|
|
|
|
def find_replace(directory: str, find: str, replace: str):
|
|
"""Recursively find and replace text in files in a directory.
|
|
|
|
Args:
|
|
directory: The directory to search.
|
|
find: The text to find.
|
|
replace: The text to replace.
|
|
"""
|
|
for root, _dirs, files in os.walk(directory):
|
|
for file in files:
|
|
filepath = os.path.join(root, file)
|
|
with open(filepath, "r", encoding="utf-8") as f:
|
|
text = f.read()
|
|
text = re.sub(find, replace, text)
|
|
with open(filepath, "w") as f:
|
|
f.write(text)
|