Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add windows support #237

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,76 @@ jobs:
just ext docker-stop
just ext docker-rm

build-and-test-extension-windows-pg14:
runs-on: windows-latest

steps:
- uses: actions/checkout@v4
- uses: taiki-e/install-action@just

- name: Install PostgreSQL
uses: ikalnytskyi/action-setup-postgres@v7
with:
postgres-version: 16

- name: Configure Passwordless Authentication
shell: bash
run: |
# This is the PGDATA dir used on the previous step.
PGDATA="$RUNNER_TEMP/pgdata"
# Add trust authentication to pg_hba.conf the extension tests
# required this, otherwise they will fail.
echo "host all all 127.0.0.1/32 trust" > "$PGDATA/pg_hba.conf"
echo "host all all ::1/128 trust" >> "$PGDATA/pg_hba.conf"

# Restart PostgreSQL to apply changes
pg_ctl -D "$PGDATA" restart

- name: Install pgvector
shell: cmd
env:
PGROOT: "C:/Program Files/PostgreSQL/16"
run: |
git clone --branch v0.8.0 https://github.com/pgvector/pgvector.git
cd pgvector
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" && ^
nmake /NOLOGO /F Makefile.win && ^
nmake /NOLOGO /F Makefile.win install

- name: Create pip cache directory
run: |
New-Item -Path "C:\Users\runneradmin\AppData\Local\pip\cache" -ItemType Directory -Force

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
cache: "pip" # caching pip dependencies

- name: Install test dependencies
shell: cmd
run: |
pip3 install -r projects/extension/requirements-test.txt

- name: Build and install extension
shell: cmd
env:
PGAI_EXT_SKIP_BUILD_CHECKS: "true"
run: |
just ext build-install

- name: Run test server
shell: cmd
env:
PYTHONUTF8: 1
run: |
start /b python3 -m fastapi dev projects/extension/tests/vectorizer/server.py

- name: Run test
shell: cmd
run: |
just ext test

build-and-test-pgai:
runs-on: ubuntu-latest

Expand Down
115 changes: 68 additions & 47 deletions projects/extension/build.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/usr/bin/env python3
import hashlib
import re
import os
import platform
import re
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path


HELP = """Available targets:
- help displays this message and exits
- build-install runs build followed by install
Expand Down Expand Up @@ -326,9 +326,10 @@ def build_feature_flags() -> str:


def build_sql() -> None:
check_versions()
check_incremental_sql_files(incremental_sql_files())
check_idempotent_sql_files(idempotent_sql_files())
if not os.environ.get("PGAI_EXT_SKIP_BUILD_CHECKS", "").lower() == "true":
check_versions()
check_incremental_sql_files(incremental_sql_files())
check_idempotent_sql_files(idempotent_sql_files())
build_control_file()
hr = "".rjust(80, "-") # "horizontal rule"
osf = output_sql_file()
Expand Down Expand Up @@ -376,34 +377,51 @@ def clean_sql() -> None:


def postgres_bin_dir() -> Path:
bin_dir = os.getenv("PG_BIN")
if bin_dir:
return Path(bin_dir).resolve()
else:
bin_dir = Path(f"/usr/lib/postgresql/{pg_major()}/bin")
bin_dir_env = os.getenv("PG_BIN")
if bin_dir_env:
bin_dir = Path(bin_dir_env)
if bin_dir.is_dir():
return bin_dir.resolve()
else:
p = shutil.which("pg_config")
if not p:
fatal("pg_config not found")
return Path(p).parent.resolve()
dir = bin_dir.resolve()
print(f"pg bin dir: using PG_BIN environment variable {dir}")
return dir

bin_dir = Path(f"/usr/lib/postgresql/{pg_major()}/bin")
if platform.system() == "Windows":
program_files = os.environ.get("ProgramFiles", r"C:\Program Files")
bin_dir = Path(f"{program_files}\\PostgreSQL\\{pg_major()}\\bin")
if bin_dir.is_dir():
dir = bin_dir.resolve()
print(f"pg bin dir: using default postgres bin directory {dir}")
return dir
else:
p = shutil.which("pg_config")
if p is None:
fatal("pg_config not found")
dir = Path(p).parent.resolve()
print(f"pg bin dir: parent directory of pg_config {dir}")
return dir


def pg_config() -> Path:
return postgres_bin_dir() / "pg_config"
cmd = "pg_config"
if platform.system() == "Windows":
cmd = "pg_config.exe"
return postgres_bin_dir() / cmd


def extension_install_dir() -> Path:
proc = subprocess.run(
f"{pg_config()} --sharedir",
check=True,
shell=True,
env=os.environ,
text=True,
capture_output=True,
)
return Path(str(proc.stdout).strip()).resolve() / "extension"
try:
proc = subprocess.run(
[pg_config(), "--sharedir"],
check=True,
env=os.environ,
text=True,
capture_output=True,
)
return Path(str(proc.stdout).strip()).resolve() / "extension"
except subprocess.CalledProcessError as e:
print(f"Error running pg_config: {e.stderr}", file=sys.stderr)
raise e


def install_sql() -> None:
Expand Down Expand Up @@ -438,9 +456,12 @@ def python_install_dir() -> Path:
# don't do it. i'm warning you
# seriously.
# you'll wreck old versions. look at build_idempotent_sql_file()
return Path(
"/usr/local/lib/pgai"
).resolve() # CONTROLS WHERE THE PYTHON LIB AND DEPS ARE INSTALLED
if platform.system() == "Windows":
program_files = Path(os.environ.get("ProgramFiles", r"C:\Program Files"))
return (program_files / "pgai" / "lib").resolve()
else:
# Use the existing Unix-like directory structure
return Path("/usr/local/lib/pgai").resolve()


def install_old_py_deps() -> None:
Expand Down Expand Up @@ -469,25 +490,25 @@ def install_prior_py() -> None:
fatal(f"'{os.sep}' in version {version}. this is not supported")
version_target_dir = python_install_dir().joinpath(version)
if version_target_dir.exists():
print(f"Version {version} already installed in {version_target_dir}")
continue
tmp_dir = Path(tempfile.gettempdir()).joinpath("pgai", version)
tmp_dir.mkdir(parents=True, exist_ok=True)
branch = git_tag(version)
subprocess.run(
f"git clone https://github.com/timescale/pgai.git --branch {branch} {tmp_dir}",
shell=True,
check=True,
env=os.environ,
)
tmp_src_dir = tmp_dir.joinpath("projects", "extension").resolve()
subprocess.run(
f'pip3 install -v --compile -t "{version_target_dir}" "{tmp_src_dir}"',
check=True,
shell=True,
env=os.environ,
cwd=str(tmp_src_dir),
)
shutil.rmtree(tmp_dir)

with tempfile.TemporaryDirectory() as tmp_dir:
branch = git_tag(version)
subprocess.run(
f"git clone https://github.com/timescale/pgai.git --branch {branch} {tmp_dir}",
shell=True,
check=True,
env=os.environ,
)
tmp_src_dir = Path(tmp_dir).joinpath("projects", "extension").resolve()
subprocess.run(
f'pip3 install -v --compile -t "{version_target_dir}" "{tmp_src_dir}"',
check=True,
shell=True,
env=os.environ,
cwd=str(tmp_src_dir),
)


def build_init_py() -> None:
Expand Down
2 changes: 1 addition & 1 deletion projects/extension/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ PG_BIN := "/usr/lib/postgresql/" + PG_MAJOR + "/bin"

# Show list of recipes
default:
@just --list
@just --list

ci: docker-build docker-run
#!/usr/bin/env bash
Expand Down
2 changes: 2 additions & 0 deletions projects/extension/tests/vectorizer/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def db_url(user: str) -> str:
return f"postgres://{user}@127.0.0.1:5432/test"
6 changes: 2 additions & 4 deletions projects/extension/tests/vectorizer/test_chunking.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
import psycopg
import pytest

from .db import db_url

# skip tests in this module if disabled
enable_vectorizer_tests = os.getenv("ENABLE_VECTORIZER_TESTS")
if enable_vectorizer_tests == "0":
pytest.skip(allow_module_level=True)


def db_url(user: str) -> str:
return f"postgres://{user}@127.0.0.1:5432/test"


def test_chunking_character_text_splitter():
tests = [
(
Expand Down
5 changes: 1 addition & 4 deletions projects/extension/tests/vectorizer/test_embedding.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@

import psycopg
import pytest
from .db import db_url

# skip tests in this module if disabled
enable_vectorizer_tests = os.getenv("ENABLE_VECTORIZER_TESTS")
if enable_vectorizer_tests == "0":
pytest.skip(allow_module_level=True)


def db_url(user: str) -> str:
return f"postgres://{user}@127.0.0.1:5432/test"


def test_embedding_openai():
tests = [
(
Expand Down
6 changes: 2 additions & 4 deletions projects/extension/tests/vectorizer/test_formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
import psycopg
import pytest

from .db import db_url

# skip tests in this module if disabled
enable_vectorizer_tests = os.getenv("ENABLE_VECTORIZER_TESTS")
if enable_vectorizer_tests == "0":
pytest.skip(allow_module_level=True)


def db_url(user: str) -> str:
return f"postgres://{user}@127.0.0.1:5432/test"


def test_formatting_python_template():
tests = [
(
Expand Down
6 changes: 2 additions & 4 deletions projects/extension/tests/vectorizer/test_grants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
import psycopg
import pytest

from .db import db_url

# skip tests in this module if disabled
enable_vectorizer_tests = os.getenv("ENABLE_VECTORIZER_TESTS")
if enable_vectorizer_tests == "0":
pytest.skip(allow_module_level=True)


def db_url(user: str) -> str:
return f"postgres://{user}@127.0.0.1:5432/test"


def test_grant_to():
tests = [
(
Expand Down
7 changes: 3 additions & 4 deletions projects/extension/tests/vectorizer/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
import psycopg
import pytest


from .db import db_url

# skip tests in this module if disabled
enable_vectorizer_tests = os.getenv("ENABLE_VECTORIZER_TESTS")
if enable_vectorizer_tests == "0":
pytest.skip(allow_module_level=True)


def db_url(user: str) -> str:
return f"postgres://{user}@127.0.0.1:5432/test"


def test_indexing_none():
tests = [
(
Expand Down
6 changes: 2 additions & 4 deletions projects/extension/tests/vectorizer/test_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
import psycopg
import pytest

from .db import db_url

# skip tests in this module if disabled
enable_vectorizer_tests = os.getenv("ENABLE_VECTORIZER_TESTS")
if enable_vectorizer_tests == "0":
pytest.skip(allow_module_level=True)


def db_url(user: str) -> str:
return f"postgres://{user}@127.0.0.1:5432/test"


def test_processing_default():
tests = [
(
Expand Down
6 changes: 2 additions & 4 deletions projects/extension/tests/vectorizer/test_scheduling.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
import psycopg
import pytest

from .db import db_url

# skip tests in this module if disabled
enable_vectorizer_tests = os.getenv("ENABLE_VECTORIZER_TESTS")
if enable_vectorizer_tests == "0":
pytest.skip(allow_module_level=True)


def db_url(user: str) -> str:
return f"postgres://{user}@127.0.0.1:5432/test"


def test_scheduling_none():
tests = [
(
Expand Down
Loading
Loading