Skip to content
Merged
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
14 changes: 5 additions & 9 deletions .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
name: "Copilot Setup Steps"

---
name: Copilot Setup Steps
# Automatically run the setup steps when they are changed to allow for easy validation, and
# allow manual testing through the repository's "Actions" tab
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml
paths: [.github/workflows/copilot-setup-steps.yml]
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml

paths: [.github/workflows/copilot-setup-steps.yml]
jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
Expand All @@ -23,6 +20,5 @@ jobs:
sudo apt-get install -y \
libgirepository1.0-dev libgstreamer1.0-dev libcairo2-dev \
gstreamer1.0-tools python3-poetry

- name: Disable ptrace restrictions
run: "echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope"
run: echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
17 changes: 17 additions & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: Format
on:
pull_request:
branches: ['**']
jobs:
format:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Format check
uses: pre-commit/action@v3.0.1
43 changes: 43 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
name: Tests
on:
pull_request:
branches: ['**']
push:
branches: [main]
jobs:
test-girest:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: latest
virtualenvs-create: true
virtualenvs-in-project: true
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
python3-gi \
gir1.2-gstreamer-1.0 \
gir1.2-gst-plugins-base-1.0 \
gstreamer1.0-tools \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
libgirepository1.0-dev \
libcairo2-dev
- name: Allow ptrace for Frida
run: echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
- name: Install Python dependencies
working-directory: ./girest
run: poetry install --no-interaction
- name: Run tests
working-directory: ./girest
run: poetry run pytest -v
47 changes: 47 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
repos:
# Python projects: girest and gstaudit-server
- repo: https://github.com/floatingpurr/sync_with_poetry
rev: 1.0.0
hooks:
- id: sync_with_poetry

# TOML formatting and linting
- repo: https://github.com/ComPWA/taplo-pre-commit
rev: v0.9.3
hooks:
- id: taplo-format
files: \.toml$
- id: taplo-lint
files: \.toml$
# Skip if offline (catalog fetch fails)
stages: [manual]

# YAML linting
- repo: https://github.com/lyz-code/yamlfix
rev: 1.17.0
hooks:
- id: yamlfix
files: \.ya?ml$

# ruff - lint and formatting for Python
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.3
hooks:
- id: ruff
args: [--fix, --show-fixes]
files: ^(girest|gstaudit-server)/.*\.py$
- id: ruff-format
files: ^(girest|gstaudit-server)/.*\.py$

# Node.js/TypeScript project: gstaudit
# Uses system hook to run npm-installed eslint
- repo: local
hooks:
- id: eslint
name: eslint (gstaudit)
entry: bash -c 'cd gstaudit && ([ -d node_modules ] || npm install) && npm
run lint -- --fix'
language: system
files: ^gstaudit/.*\.(ts|tsx|js|jsx)$
pass_filenames: false
90 changes: 44 additions & 46 deletions girest/examples/generic_constructor_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@
For this demo, we just show the generated schema and TypeScript.
"""

import sys
import os
import json
import sys

# Add parent directory to path for imports
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from girest.main import GIRest
from girest.generator import TypeScriptGenerator


def show_gvalue_example():
Expand All @@ -28,52 +26,52 @@ def show_gvalue_example():
print("EXAMPLE: Using Generic Constructor for GObject.Value")
print("=" * 80)
print()

# Generate schema
girest = GIRest('GObject', '2.0')
girest = GIRest("GObject", "2.0")
spec = girest.generate()
schema = spec.to_dict()

# Show the endpoints
print("1. Generic Constructor Endpoint")
print("-" * 80)
new_path = '/GObject/Value/new'
operation = schema['paths'][new_path]['get']
new_path = "/GObject/Value/new"
operation = schema["paths"][new_path]["get"]

print(f"Endpoint: GET {new_path}")
print(f"Operation ID: {operation['operationId']}")
print(f"Returns: pointer to allocated GValue")
print("Returns: pointer to allocated GValue")
print()
print("Example curl command:")
print(f" curl http://localhost:9000{new_path}")
print(' # Returns: {"return": "0x7f1234567890"}')
print()

print("2. Generic Destructor Endpoint")
print("-" * 80)
free_path = '/GObject/Value/{self}/free'
operation = schema['paths'][free_path]['get']
free_path = "/GObject/Value/{self}/free"
operation = schema["paths"][free_path]["get"]

print(f"Endpoint: GET {free_path}")
print(f"Operation ID: {operation['operationId']}")
print(f"Parameter: self (pointer to free)")
print(f"Returns: 204 No Content")
print("Parameter: self (pointer to free)")
print("Returns: 204 No Content")
print()
print("Example curl command:")
print(' curl http://localhost:9000/GObject/Value/0x7f1234567890/free')
print(" curl http://localhost:9000/GObject/Value/0x7f1234567890/free")
print()

print("3. Using GValue Methods")
print("-" * 80)
# Find some GValue methods
value_methods = [p for p in schema['paths'] if '/Value/' in p and p != new_path and p != free_path]
value_methods = [p for p in schema["paths"] if "/Value/" in p and p != new_path and p != free_path]
print(f"GValue has {len(value_methods)} methods available")
print("Examples:")
for path in value_methods[:5]:
method_name = path.split('/')[-1]
method_name = path.split("/")[-1]
print(f" - {method_name}")
print()

print("4. Complete Usage Flow")
print("-" * 80)
print("""
Expand All @@ -94,7 +92,7 @@ def show_gvalue_example():
# Step 5: Free the memory
$ curl http://localhost:9000/GObject/Value/0x7f1234567890/free
""")

print("5. TypeScript Usage")
print("-" * 80)
print("""
Expand Down Expand Up @@ -127,31 +125,31 @@ def show_gst_meta_example():
print("EXAMPLE: Using Generic Constructor for Gst.Meta")
print("=" * 80)
print()

# Generate schema
girest = GIRest('Gst', '1.0')
girest = GIRest("Gst", "1.0")
spec = girest.generate()
schema = spec.to_dict()

# Show the endpoints
new_path = '/Gst/Meta/new'
operation = schema['paths'][new_path]['get']
new_path = "/Gst/Meta/new"
operation = schema["paths"][new_path]["get"]

print("1. GstMeta Allocation")
print("-" * 80)
print(f"Endpoint: GET {new_path}")
print()

# Find GstMeta methods
meta_methods = [p for p in schema['paths'] if '/Meta/' in p and '/new' not in p and '/free' not in p]
meta_methods = [p for p in schema["paths"] if "/Meta/" in p and "/new" not in p and "/free" not in p]
print(f"2. Available GstMeta Methods ({len(meta_methods)} total)")
print("-" * 80)
for path in meta_methods:
method_name = path.split('/')[-1]
operation = list(schema['paths'][path].values())[0]
method_name = path.split("/")[-1]
operation = list(schema["paths"][path].values())[0]
print(f" - {method_name:30} {operation.get('summary', '')}")
print()

print("3. TypeScript Example")
print("-" * 80)
print("""
Expand Down Expand Up @@ -186,41 +184,41 @@ def show_summary():
print("SUMMARY: All Structs with Generic Constructors")
print("=" * 80)
print()

# Collect from multiple namespaces
all_structs = []
for namespace, version in [('GObject', '2.0'), ('Gst', '1.0')]:

for namespace, version in [("GObject", "2.0"), ("Gst", "1.0")]:
girest = GIRest(namespace, version)
spec = girest.generate()
schema = spec.to_dict()
for path, operations in schema['paths'].items():

for path, operations in schema["paths"].items():
for method, operation in operations.items():
if operation.get('x-gi-generic') and operation.get('x-gi-constructor'):
op_id = operation['operationId']
struct_name = op_id.replace(f'{namespace}-', '').replace('-new', '')
if operation.get("x-gi-generic") and operation.get("x-gi-constructor"):
op_id = operation["operationId"]
struct_name = op_id.replace(f"{namespace}-", "").replace("-new", "")
all_structs.append((namespace, struct_name))

# Group by namespace
by_namespace = {}
for ns, name in all_structs:
if ns not in by_namespace:
by_namespace[ns] = []
by_namespace[ns].append(name)

for ns, structs in sorted(by_namespace.items()):
print(f"{ns} Namespace ({len(structs)} structs):")
print("-" * 80)
for name in sorted(structs):
print(f" - {name}")
print()

total = sum(len(s) for s in by_namespace.values())
print(f"Total: {total} structs with generic constructors")


if __name__ == '__main__':
if __name__ == "__main__":
show_gvalue_example()
show_gst_meta_example()
show_summary()
Loading
Loading