Фикс скрипта
This commit is contained in:
parent
092bc6bdd9
commit
cd059e52d4
2 changed files with 387 additions and 0 deletions
12
Readme.md
12
Readme.md
|
|
@ -27,8 +27,20 @@ PDF-документация и 3D-модели хранятся вне этог
|
||||||
- прописывает переменные путей в `Configure Paths`;
|
- прописывает переменные путей в `Configure Paths`;
|
||||||
- добавляет подключение DB Library;
|
- добавляет подключение DB Library;
|
||||||
- подключает таблицы символов и футпринтов из этого репозитория;
|
- подключает таблицы символов и футпринтов из этого репозитория;
|
||||||
|
- проверяет и при необходимости предлагает установить PostgreSQL ODBC-драйвер
|
||||||
|
для DB Library (`psqlodbc` на Arch/CachyOS, `odbc-postgresql` на Ubuntu/Debian);
|
||||||
- создаёт резервные копии изменяемых файлов настроек KiCad.
|
- создаёт резервные копии изменяемых файлов настроек KiCad.
|
||||||
|
|
||||||
|
Для полностью неинтерактивного запуска с установкой/регистрацией ODBC-драйвера:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/setup_kicad_user_library.py \
|
||||||
|
--pdf-dir "<путь-к-папке-PDF>" \
|
||||||
|
--non-interactive \
|
||||||
|
--install-odbc-driver \
|
||||||
|
--strict-odbc-check
|
||||||
|
```
|
||||||
|
|
||||||
## Переменные KiCad
|
## Переменные KiCad
|
||||||
|
|
||||||
| Переменная | Назначение |
|
| Переменная | Назначение |
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,24 @@ import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
ENV_VARS = ("KICAD_LIB_DIR_USER", "KICAD_PDF_DIR_USER", "KICAD_3D_PARTY_USER")
|
ENV_VARS = ("KICAD_LIB_DIR_USER", "KICAD_PDF_DIR_USER", "KICAD_3D_PARTY_USER")
|
||||||
|
DATABASE_LIBRARY_FILE = "eda-core.kicad_dbl"
|
||||||
|
DEFAULT_POSTGRES_ODBC_DRIVER = "PostgreSQL Unicode"
|
||||||
|
DEFAULT_POSTGRES_ODBC_DRIVER_LIBS = (
|
||||||
|
Path("/usr/lib/psqlodbcw.so"),
|
||||||
|
Path("/usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so"),
|
||||||
|
Path("/usr/lib/aarch64-linux-gnu/odbc/psqlodbcw.so"),
|
||||||
|
Path("/usr/lib/arm-linux-gnueabihf/odbc/psqlodbcw.so"),
|
||||||
|
Path("/usr/lib/odbc/psqlodbcw.so"),
|
||||||
|
)
|
||||||
|
AUR_HELPERS = ("paru", "yay", "pikaur")
|
||||||
|
|
||||||
|
|
||||||
def repo_root() -> Path:
|
def repo_root() -> Path:
|
||||||
|
|
@ -66,6 +78,19 @@ def ask_path(name: str, prompt: str, default: str | None, required: bool = True)
|
||||||
print("Path is required.")
|
print("Path is required.")
|
||||||
|
|
||||||
|
|
||||||
|
def ask_yes_no(prompt: str, default: bool = True) -> bool:
|
||||||
|
suffix = " [Y/n]" if default else " [y/N]"
|
||||||
|
while True:
|
||||||
|
value = input(f"{prompt}{suffix}: ").strip().lower()
|
||||||
|
if not value:
|
||||||
|
return default
|
||||||
|
if value in {"y", "yes", "д", "да"}:
|
||||||
|
return True
|
||||||
|
if value in {"n", "no", "н", "нет"}:
|
||||||
|
return False
|
||||||
|
print("Please answer yes or no.")
|
||||||
|
|
||||||
|
|
||||||
def backup(path: Path) -> Path:
|
def backup(path: Path) -> Path:
|
||||||
stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||||
target = path.with_name(f"{path.name}.bak-{stamp}")
|
target = path.with_name(f"{path.name}.bak-{stamp}")
|
||||||
|
|
@ -137,6 +162,316 @@ def configure_library_tables(config_dir: Path) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def warn(message: str) -> None:
|
||||||
|
print(f"warning: {message}", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_odbc_driver(connection_string: str) -> str | None:
|
||||||
|
match = re.search(
|
||||||
|
r"(?:^|;)\s*Driver\s*=\s*(?:\{([^}]*)\}|([^;]*))",
|
||||||
|
connection_string,
|
||||||
|
flags=re.IGNORECASE,
|
||||||
|
)
|
||||||
|
if not match:
|
||||||
|
return None
|
||||||
|
return (match.group(1) or match.group(2) or "").strip() or None
|
||||||
|
|
||||||
|
|
||||||
|
def read_database_source(lib_dir: str) -> tuple[Path, dict[str, object]] | None:
|
||||||
|
dbl_path = Path(lib_dir).expanduser() / DATABASE_LIBRARY_FILE
|
||||||
|
if not dbl_path.exists():
|
||||||
|
warn(f"database library file does not exist: {dbl_path}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
data = json.loads(dbl_path.read_text(encoding="utf-8"))
|
||||||
|
source = data.get("source")
|
||||||
|
if not isinstance(source, dict):
|
||||||
|
warn(f"database library source block is missing: {dbl_path}")
|
||||||
|
return None
|
||||||
|
if source.get("type") != "odbc":
|
||||||
|
return None
|
||||||
|
|
||||||
|
return dbl_path, source
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(args: list[str]) -> subprocess.CompletedProcess[str] | None:
|
||||||
|
try:
|
||||||
|
return subprocess.run(
|
||||||
|
args,
|
||||||
|
check=False,
|
||||||
|
text=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
except FileNotFoundError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def run_interactive_command(args: list[str], env: dict[str, str] | None = None) -> bool:
|
||||||
|
print("+ " + " ".join(args))
|
||||||
|
try:
|
||||||
|
result = subprocess.run(args, check=False, env=env)
|
||||||
|
except FileNotFoundError:
|
||||||
|
warn(f"command not found: {args[0]}")
|
||||||
|
return False
|
||||||
|
return result.returncode == 0
|
||||||
|
|
||||||
|
|
||||||
|
def with_sudo(args: list[str]) -> list[str]:
|
||||||
|
if os.geteuid() == 0:
|
||||||
|
return args
|
||||||
|
if shutil.which("sudo") is None:
|
||||||
|
raise SystemExit("sudo is required for system package/ODBC registration changes")
|
||||||
|
return ["sudo", *args]
|
||||||
|
|
||||||
|
|
||||||
|
def read_os_release() -> dict[str, str]:
|
||||||
|
path = Path("/etc/os-release")
|
||||||
|
if not path.exists():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
|
||||||
|
if not line or line.startswith("#") or "=" not in line:
|
||||||
|
continue
|
||||||
|
key, value = line.split("=", 1)
|
||||||
|
data[key] = value.strip().strip('"')
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def detect_linux_family() -> str | None:
|
||||||
|
data = read_os_release()
|
||||||
|
distro_id = data.get("ID", "").lower()
|
||||||
|
id_like = set(data.get("ID_LIKE", "").lower().split())
|
||||||
|
|
||||||
|
if distro_id in {"arch", "cachyos", "manjaro", "endeavouros", "garuda"} or "arch" in id_like:
|
||||||
|
return "arch"
|
||||||
|
if distro_id in {"ubuntu", "debian", "linuxmint", "pop"} or id_like & {"debian", "ubuntu"}:
|
||||||
|
return "debian"
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def find_aur_helper() -> str | None:
|
||||||
|
for helper in AUR_HELPERS:
|
||||||
|
path = shutil.which(helper)
|
||||||
|
if path:
|
||||||
|
return path
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def query_odbc_driver(driver: str) -> tuple[bool, str]:
|
||||||
|
result = run_command(["odbcinst", "-q", "-d", "-n", driver])
|
||||||
|
if result is None:
|
||||||
|
return False, ""
|
||||||
|
return result.returncode == 0, result.stdout + result.stderr
|
||||||
|
|
||||||
|
|
||||||
|
def parse_driver_library(odbcinst_output: str) -> Path | None:
|
||||||
|
for line in odbcinst_output.splitlines():
|
||||||
|
key, sep, value = line.partition("=")
|
||||||
|
if sep and key.strip().lower() == "driver" and value.strip():
|
||||||
|
return Path(value.strip())
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def expected_driver_library(driver: str) -> Path | None:
|
||||||
|
if driver.lower() == DEFAULT_POSTGRES_ODBC_DRIVER.lower():
|
||||||
|
return locate_postgres_odbc_library() or DEFAULT_POSTGRES_ODBC_DRIVER_LIBS[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def locate_postgres_odbc_library() -> Path | None:
|
||||||
|
for path in DEFAULT_POSTGRES_ODBC_DRIVER_LIBS:
|
||||||
|
if path.exists():
|
||||||
|
return path
|
||||||
|
|
||||||
|
for base in (Path("/usr/lib"), Path("/usr/local/lib")):
|
||||||
|
if not base.exists():
|
||||||
|
continue
|
||||||
|
matches = sorted(base.glob("**/psqlodbcw.so"))
|
||||||
|
if matches:
|
||||||
|
return matches[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def print_postgres_odbc_help(driver: str, driver_lib: Path | None) -> None:
|
||||||
|
if driver.lower() != DEFAULT_POSTGRES_ODBC_DRIVER.lower():
|
||||||
|
print("ODBC driver is not ready. Register the driver in /etc/odbcinst.ini.")
|
||||||
|
return
|
||||||
|
|
||||||
|
lib_path = driver_lib or locate_postgres_odbc_library() or DEFAULT_POSTGRES_ODBC_DRIVER_LIBS[0]
|
||||||
|
print("PostgreSQL ODBC setup:")
|
||||||
|
print(" Arch/CachyOS:")
|
||||||
|
print(" paru -S psqlodbc")
|
||||||
|
print(" # or: yay -S psqlodbc")
|
||||||
|
print(" Ubuntu/Debian:")
|
||||||
|
print(" sudo apt-get install unixodbc odbc-postgresql")
|
||||||
|
print(" Ensure /etc/odbcinst.ini contains:")
|
||||||
|
print(f" [{DEFAULT_POSTGRES_ODBC_DRIVER}]")
|
||||||
|
print(f" Description={DEFAULT_POSTGRES_ODBC_DRIVER}")
|
||||||
|
print(f" Driver={lib_path}")
|
||||||
|
print(" UsageCount=1")
|
||||||
|
print(" Check registration:")
|
||||||
|
print(f" odbcinst -q -d -n '{DEFAULT_POSTGRES_ODBC_DRIVER}'")
|
||||||
|
|
||||||
|
|
||||||
|
def install_postgres_odbc_package(non_interactive: bool) -> bool:
|
||||||
|
family = detect_linux_family()
|
||||||
|
|
||||||
|
if family == "arch":
|
||||||
|
if shutil.which("pacman") is not None:
|
||||||
|
pacman_cmd = ["pacman", "-S", "--needed"]
|
||||||
|
if non_interactive:
|
||||||
|
pacman_cmd.append("--noconfirm")
|
||||||
|
pacman_cmd.append("unixodbc")
|
||||||
|
if not run_interactive_command(with_sudo(pacman_cmd)):
|
||||||
|
return False
|
||||||
|
|
||||||
|
helper = find_aur_helper()
|
||||||
|
if helper is None:
|
||||||
|
warn("psqlodbc is an AUR package on Arch/CachyOS, but no AUR helper was found")
|
||||||
|
warn("install it manually, for example: paru -S psqlodbc")
|
||||||
|
return False
|
||||||
|
|
||||||
|
helper_cmd = [helper, "-S", "--needed"]
|
||||||
|
if non_interactive:
|
||||||
|
helper_cmd.append("--noconfirm")
|
||||||
|
helper_cmd.append("psqlodbc")
|
||||||
|
return run_interactive_command(helper_cmd)
|
||||||
|
|
||||||
|
if family == "debian":
|
||||||
|
if shutil.which("apt-get") is None:
|
||||||
|
warn("apt-get was not found")
|
||||||
|
return False
|
||||||
|
env = os.environ.copy()
|
||||||
|
if non_interactive:
|
||||||
|
env["DEBIAN_FRONTEND"] = "noninteractive"
|
||||||
|
return run_interactive_command(
|
||||||
|
with_sudo(["apt-get", "install", "-y", "unixodbc", "odbc-postgresql"]),
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
|
|
||||||
|
warn("unsupported Linux distribution for automatic psqlODBC installation")
|
||||||
|
warn("supported families: Arch/CachyOS and Ubuntu/Debian")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def register_odbc_driver(driver: str, driver_lib: Path) -> bool:
|
||||||
|
if shutil.which("odbcinst") is None:
|
||||||
|
warn("odbcinst was not found after package installation")
|
||||||
|
return False
|
||||||
|
if not driver_lib.exists():
|
||||||
|
warn(f"cannot register missing driver library: {driver_lib}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
template = (
|
||||||
|
f"[{driver}]\n"
|
||||||
|
f"Description={driver}\n"
|
||||||
|
f"Driver={driver_lib}\n"
|
||||||
|
"UsageCount=1\n"
|
||||||
|
)
|
||||||
|
with tempfile.NamedTemporaryFile("w", encoding="utf-8", delete=False) as tmp:
|
||||||
|
tmp.write(template)
|
||||||
|
template_path = Path(tmp.name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return run_interactive_command(
|
||||||
|
with_sudo(["odbcinst", "-i", "-d", "-f", str(template_path)])
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
template_path.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def install_and_register_odbc_driver(driver: str, non_interactive: bool) -> bool:
|
||||||
|
if driver.lower() != DEFAULT_POSTGRES_ODBC_DRIVER.lower():
|
||||||
|
warn(f"automatic installation is only implemented for {DEFAULT_POSTGRES_ODBC_DRIVER!r}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
driver_lib = locate_postgres_odbc_library()
|
||||||
|
if driver_lib is None or shutil.which("odbcinst") is None:
|
||||||
|
print("Installing PostgreSQL ODBC driver package...")
|
||||||
|
if not install_postgres_odbc_package(non_interactive):
|
||||||
|
return False
|
||||||
|
driver_lib = locate_postgres_odbc_library()
|
||||||
|
|
||||||
|
if driver_lib is None:
|
||||||
|
warn("PostgreSQL ODBC package installed, but psqlodbcw.so was not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
registered, odbcinst_output = query_odbc_driver(driver)
|
||||||
|
registered_lib = parse_driver_library(odbcinst_output) if registered else None
|
||||||
|
if registered and registered_lib == driver_lib and driver_lib.exists():
|
||||||
|
return True
|
||||||
|
|
||||||
|
print(f"Registering ODBC driver [{driver}] -> {driver_lib}")
|
||||||
|
if not register_odbc_driver(driver, driver_lib):
|
||||||
|
return False
|
||||||
|
|
||||||
|
registered, odbcinst_output = query_odbc_driver(driver)
|
||||||
|
registered_lib = parse_driver_library(odbcinst_output) if registered else None
|
||||||
|
return bool(registered and registered_lib and registered_lib.exists())
|
||||||
|
|
||||||
|
|
||||||
|
def check_database_odbc_driver(lib_dir: str) -> bool:
|
||||||
|
source_info = read_database_source(lib_dir)
|
||||||
|
if source_info is None:
|
||||||
|
return True
|
||||||
|
|
||||||
|
dbl_path, source = source_info
|
||||||
|
dsn = str(source.get("dsn") or "").strip()
|
||||||
|
connection_string = str(source.get("connection_string") or "")
|
||||||
|
driver = extract_odbc_driver(connection_string)
|
||||||
|
|
||||||
|
print("Database library ODBC check:")
|
||||||
|
print(f" file: {dbl_path}")
|
||||||
|
|
||||||
|
if not driver:
|
||||||
|
if dsn:
|
||||||
|
warn(f"database library uses DSN '{dsn}', driver lookup is left to unixODBC")
|
||||||
|
return True
|
||||||
|
warn("database library ODBC source has no Driver=... or DSN")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f" driver: {driver}")
|
||||||
|
|
||||||
|
if shutil.which("odbcinst") is None:
|
||||||
|
warn("odbcinst was not found; KiCad cannot resolve ODBC drivers")
|
||||||
|
print_postgres_odbc_help(driver, expected_driver_library(driver))
|
||||||
|
return False
|
||||||
|
|
||||||
|
registered, odbcinst_output = query_odbc_driver(driver)
|
||||||
|
registered_lib = parse_driver_library(odbcinst_output) if registered else None
|
||||||
|
driver_lib = registered_lib or expected_driver_library(driver)
|
||||||
|
|
||||||
|
problems = []
|
||||||
|
if not registered:
|
||||||
|
problems.append(f"driver is not registered in /etc/odbcinst.ini as [{driver}]")
|
||||||
|
if driver_lib is not None and not driver_lib.exists():
|
||||||
|
problems.append(f"driver library does not exist: {driver_lib}")
|
||||||
|
if registered and registered_lib is None:
|
||||||
|
problems.append(f"registered driver [{driver}] has no Driver=... path")
|
||||||
|
|
||||||
|
if not problems:
|
||||||
|
if driver_lib is not None:
|
||||||
|
print(f" library: {driver_lib}")
|
||||||
|
print(" status: OK")
|
||||||
|
return True
|
||||||
|
|
||||||
|
for problem in problems:
|
||||||
|
warn(problem)
|
||||||
|
print_postgres_odbc_help(driver, driver_lib)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def database_odbc_driver_name(lib_dir: str) -> str | None:
|
||||||
|
source_info = read_database_source(lib_dir)
|
||||||
|
if source_info is None:
|
||||||
|
return None
|
||||||
|
_, source = source_info
|
||||||
|
connection_string = str(source.get("connection_string") or "")
|
||||||
|
return extract_odbc_driver(connection_string)
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Configure KiCad paths and library tables for KiCad User Library."
|
description="Configure KiCad paths and library tables for KiCad User Library."
|
||||||
|
|
@ -146,7 +481,25 @@ def main() -> int:
|
||||||
parser.add_argument("--pdf-dir", help="Path to PDF datasheet directory")
|
parser.add_argument("--pdf-dir", help="Path to PDF datasheet directory")
|
||||||
parser.add_argument("--3d-dir", dest="models_dir", help="Path to user 3D models directory")
|
parser.add_argument("--3d-dir", dest="models_dir", help="Path to user 3D models directory")
|
||||||
parser.add_argument("--non-interactive", action="store_true", help="Do not ask questions")
|
parser.add_argument("--non-interactive", action="store_true", help="Do not ask questions")
|
||||||
|
parser.add_argument("--skip-odbc-check", action="store_true", help="Do not check DB Library ODBC driver")
|
||||||
|
parser.add_argument(
|
||||||
|
"--install-odbc-driver",
|
||||||
|
action="store_true",
|
||||||
|
help="Install/register missing PostgreSQL ODBC driver for DB Library",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-install-odbc-driver",
|
||||||
|
action="store_true",
|
||||||
|
help="Do not offer automatic PostgreSQL ODBC driver installation",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--strict-odbc-check",
|
||||||
|
action="store_true",
|
||||||
|
help="Fail when DB Library ODBC driver is not configured",
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
if args.install_odbc_driver and args.no_install_odbc_driver:
|
||||||
|
raise SystemExit("--install-odbc-driver and --no-install-odbc-driver are mutually exclusive")
|
||||||
|
|
||||||
config_path = detect_kicad_config(args.kicad_version)
|
config_path = detect_kicad_config(args.kicad_version)
|
||||||
existing = read_existing_vars(config_path)
|
existing = read_existing_vars(config_path)
|
||||||
|
|
@ -176,6 +529,26 @@ def main() -> int:
|
||||||
if key != "KICAD_LIB_DIR_USER" and not Path(value).expanduser().exists():
|
if key != "KICAD_LIB_DIR_USER" and not Path(value).expanduser().exists():
|
||||||
print(f"warning: {key} path does not exist yet: {value}", file=sys.stderr)
|
print(f"warning: {key} path does not exist yet: {value}", file=sys.stderr)
|
||||||
|
|
||||||
|
odbc_ok = True
|
||||||
|
if not args.skip_odbc_check:
|
||||||
|
odbc_ok = check_database_odbc_driver(lib_dir)
|
||||||
|
if not odbc_ok and not args.no_install_odbc_driver:
|
||||||
|
should_install = args.install_odbc_driver
|
||||||
|
if not should_install and not args.non_interactive:
|
||||||
|
should_install = ask_yes_no("Install/register PostgreSQL ODBC driver now?", True)
|
||||||
|
|
||||||
|
if should_install:
|
||||||
|
driver = database_odbc_driver_name(lib_dir)
|
||||||
|
if driver:
|
||||||
|
odbc_ok = install_and_register_odbc_driver(driver, args.non_interactive)
|
||||||
|
if odbc_ok:
|
||||||
|
odbc_ok = check_database_odbc_driver(lib_dir)
|
||||||
|
else:
|
||||||
|
warn("could not determine DB Library ODBC driver name")
|
||||||
|
|
||||||
|
if args.strict_odbc_check and not odbc_ok:
|
||||||
|
raise SystemExit("DB Library ODBC driver is not configured")
|
||||||
|
|
||||||
backups = [backup(config_path)]
|
backups = [backup(config_path)]
|
||||||
config_dir = config_path.parent
|
config_dir = config_path.parent
|
||||||
for table_name in ("sym-lib-table", "fp-lib-table"):
|
for table_name in ("sym-lib-table", "fp-lib-table"):
|
||||||
|
|
@ -193,6 +566,8 @@ def main() -> int:
|
||||||
print("Library table entries updated:")
|
print("Library table entries updated:")
|
||||||
print(" sym-lib-table: eda-core, sym-lib-table")
|
print(" sym-lib-table: eda-core, sym-lib-table")
|
||||||
print(" fp-lib-table: fp-lib-table")
|
print(" fp-lib-table: fp-lib-table")
|
||||||
|
if not args.skip_odbc_check and not odbc_ok:
|
||||||
|
print("Database ODBC check reported warnings above.")
|
||||||
print("Backups:")
|
print("Backups:")
|
||||||
for item in backups:
|
for item in backups:
|
||||||
print(f" {item}")
|
print(f" {item}")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue