Skip to content

Commit d32a4c3

Browse files
committed
Add compose stack and CI
1 parent da5b62d commit d32a4c3

File tree

7 files changed

+124
-134
lines changed

7 files changed

+124
-134
lines changed

.github/workflows/ci.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
- uses: actions/setup-python@v5
13+
with:
14+
python-version: "3.12"
15+
- name: Install
16+
run: pip install -e .
17+
- name: Unit tests
18+
run: python -m unittest discover -s tests
19+
20+
docker:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v4
24+
- name: Build image
25+
run: docker build -t ofmx2pgsql .
26+
- name: Dry-run import in container
27+
run: |
28+
docker run --rm \
29+
-e PG_DSN="postgresql://dummy:dummy@localhost:5432/dummy" \
30+
-e OFMX_URL="https://snapshots.openflightmaps.org/live/2513/ofmx/lkaa/latest/ofmx_lk.zip" \
31+
-e PG_SCHEMA="ofmx" \
32+
-e APPLY_MIGRATIONS="false" \
33+
-e DRY_RUN="true" \
34+
-e VERBOSE="false" \
35+
ofmx2pgsql

Makefile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.PHONY: docker-build docker-import docker-compose-import
2+
3+
docker-build:
4+
docker build -t ofmx2pgsql .
5+
6+
docker-import:
7+
docker run --rm \
8+
-e PG_DSN="${PG_DSN}" \
9+
-e OFMX_URL="${OFMX_URL}" \
10+
-e PG_SCHEMA="${PG_SCHEMA}" \
11+
-e APPLY_MIGRATIONS="${APPLY_MIGRATIONS}" \
12+
ofmx2pgsql
13+
14+
docker-compose-import:
15+
docker compose up --build --abort-on-container-exit

PROGRESS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
- INI-based config support added for CLI defaults.
1818
- Schema selection and JSON validation output added to the CLI.
1919
- Airspace uniqueness relaxed to preserve duplicate OFMX IDs.
20+
- Docker Compose stack added with a custom PostGIS image for arm64 hosts.
2021
- Implementation work has not started (no parser, schema, or imports yet).
2122

2223
## Milestones

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Importer and schema are functional for the LK sample dataset. See `TODO.md` for
99
- `pip install -e .` installs the package and the `psycopg` dependency.
1010
- `config/ofmx2pgsql.example.ini` shows the supported config keys.
1111
- `Dockerfile` builds a container that downloads a snapshot and imports it into PostGIS.
12+
- `docker-compose.yml` provides a PostGIS + importer stack for local testing.
1213

1314
## Repository Layout
1415
- `ofmx_lk/` sample OFMX data and reference materials.
@@ -50,6 +51,15 @@ docker run --rm \\
5051
ofmx2pgsql
5152
```
5253

54+
## Docker Compose
55+
Spin up a local PostGIS instance and run a one-shot import.
56+
57+
```sh
58+
docker compose up --build --abort-on-container-exit
59+
```
60+
61+
The compose stack builds a lightweight Postgres 18 + PostGIS image from `docker/postgis.Dockerfile` to support arm64 hosts.
62+
5363
## Data Notes
5464
The sample data in `ofmx_lk/` is treated as reference input. Avoid editing these files unless intentionally updating fixtures.
5565

TODO.md

Lines changed: 29 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,31 @@
11
# ofmx2pgsql – TODO List
22

3-
Build a lightweight importer for OpenFlightMaps OFMX data into PostgreSQL/PostGIS.
4-
5-
---
6-
7-
## Phase -1 — Repository Setup
8-
9-
- [x] Add contributor guidelines (`AGENTS.md`)
10-
- [x] Add project overview (`README.md`)
11-
- [x] Add progress log (`PROGRESS.md`)
12-
- [x] Add base ignore rules (`.gitignore`)
13-
14-
---
15-
16-
## Phase 0 — Scope & Principles
17-
18-
- [ ] Define non-goals
19-
- [ ] No rendering optimizations
20-
- [ ] No tile generation
21-
- [ ] No attempt to support all OFMX edge cases initially
22-
- [ ] Decide target CRS
23-
- [ ] Use EPSG:4326 only
24-
- [ ] Decide geometry fidelity
25-
- [ ] Points and polygons only (no arcs initially)
26-
- [ ] Define vertical dimension handling
27-
- [ ] Store altitudes as attributes (`lower_ft`, `upper_ft`)
28-
- [ ] No 3D geometries in v1
29-
30-
---
31-
32-
## Phase 1 — Understand OFMX Structure
33-
34-
- [ ] Obtain OFMX XSD schema
35-
- [ ] Identify top-level entities
36-
- [ ] Airports
37-
- [ ] Runways
38-
- [ ] RunwayEnds
39-
- [ ] Airspaces
40-
- [ ] Navaids
41-
- [ ] Waypoints
42-
- [ ] Map ID relationships
43-
- [ ] Airport ↔ Runway
44-
- [ ] Runway ↔ RunwayEnd
45-
- [ ] Identify coordinate representations
46-
- [ ] Lat/Lon formats
47-
- [ ] Polygon definitions
48-
- [ ] Circles / arcs
49-
- [ ] Document mandatory vs optional fields
50-
51-
---
52-
53-
## Phase 2 — Define PostGIS Schema
54-
55-
- [x] Design core tables
56-
- [ ] airports
57-
- [ ] runways
58-
- [ ] runway_ends
59-
- [ ] airspaces
60-
- [ ] navaids
61-
- [ ] waypoints
62-
- [x] Define primary keys
63-
- [x] Store OFMX source IDs
64-
- [x] Define foreign keys
65-
- [x] Define geometry columns
66-
- [x] POINT for airports, navaids, waypoints
67-
- [x] LINESTRING for runways, POINT for runway ends
68-
- [x] MULTIPOLYGON for airspaces
69-
- [x] Add metadata fields
70-
- [ ] source
71-
- [ ] cycle
72-
- [ ] valid_from
73-
- [ ] valid_to
74-
- [x] Create spatial indexes (GIST)
75-
76-
---
77-
78-
## Phase 3 — Project Skeleton
79-
80-
- [x] Create repository `ofmx2pgsql`
81-
- [x] Choose language
82-
- [x] Python
83-
- [ ] Setup virtual environment
84-
- [x] Setup CLI framework (`argparse` or `typer`)
85-
- [x] Define project structure
86-
87-
---
88-
89-
## Phase 4 — XML Parsing Layer
90-
91-
- [x] Add parser module scaffold
92-
- [x] Implement streaming XML parser (`xml.etree.ElementTree.iterparse`)
93-
- [x] Implement entity parsers
94-
- [x] Normalize coordinates to decimal degrees
95-
- [x] Preserve OFMX IDs
96-
97-
---
98-
99-
## Phase 5 — Geometry Construction
100-
101-
- [ ] Convert coordinates to Shapely geometries
102-
- [ ] Validate geometries
103-
- [ ] Parse altitude limits
104-
105-
---
106-
107-
## Phase 6 — Database Writer
108-
109-
- [x] Implement database connection
110-
- [x] Implement bulk inserts
111-
- [x] Implement idempotent loads
112-
113-
---
114-
115-
## Phase 7 — CLI Features
116-
117-
- [x] Import command
118-
- [x] Schema selection
119-
- [x] Dry run
120-
- [x] Verbose logging
121-
- [x] Config file defaults
122-
123-
---
124-
125-
## Phase 8 — Validation & QA
126-
127-
- [x] Compare counts with source
128-
- [x] JSON validation output
129-
- [ ] Visual inspection in QGIS
130-
131-
---
132-
133-
## Phase 9 — Documentation
134-
135-
- [ ] README
136-
- [ ] Example config
3+
Focused, remaining work for the OFMX-to-PostGIS importer.
4+
5+
## Done (Milestones)
6+
- Repository bootstrapped (docs, config, tests, schema, CLI).
7+
- Parser and importer wired to LK sample data.
8+
- Import validation and dry-run workflows implemented.
9+
## Scope Decisions
10+
- Confirm non-goals (no rendering, no tile generation, limited edge-case support).
11+
- Lock CRS (EPSG:4326 only).
12+
- Confirm geometry fidelity (points, lines, polygons; arcs handled only via extension).
13+
- Decide altitude handling (attribute columns vs 3D geometries).
14+
15+
## OFMX Understanding
16+
- Obtain and pin the OFMX XSD schema version used by the dataset.
17+
- Document mandatory vs optional fields for Ahp/Rwy/Rdn/Ase/Dpn/Ndb/Vor/Dme.
18+
- Clarify coordinate formats and arc/circle handling in core XML vs extensions.
19+
20+
## Parsing & Geometry
21+
- Add geometry construction helpers (Shapely or raw WKT) for non-airspace shapes.
22+
- Validate geometries (self-intersections, ring closure, SRID consistency).
23+
- Parse altitude limits into numeric fields with normalized units.
24+
25+
## Database & Import
26+
- Populate metadata fields (`source`, `cycle`, `valid_from`, `valid_to`) during import.
27+
- Decide how to version or archive imports across cycles.
28+
29+
## Validation & QA
30+
- Visual inspection in QGIS for a sample import.
31+
- Add a lightweight regression dataset comparison (counts + spot checks).

docker-compose.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
services:
2+
db:
3+
build:
4+
context: .
5+
dockerfile: docker/postgis.Dockerfile
6+
environment:
7+
POSTGRES_USER: ofmx
8+
POSTGRES_PASSWORD: ofmx
9+
POSTGRES_DB: ofmx
10+
healthcheck:
11+
test: ["CMD-SHELL", "pg_isready -U ofmx -d ofmx"]
12+
interval: 5s
13+
timeout: 5s
14+
retries: 5
15+
16+
importer:
17+
build: .
18+
depends_on:
19+
db:
20+
condition: service_healthy
21+
environment:
22+
PG_DSN: postgresql://ofmx:ofmx@db:5432/ofmx
23+
OFMX_URL: https://snapshots.openflightmaps.org/live/2513/ofmx/lkaa/latest/ofmx_lk.zip
24+
PG_SCHEMA: ofmx
25+
APPLY_MIGRATIONS: "true"
26+
VERBOSE: "true"

docker/postgis.Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM postgres:18-alpine
2+
3+
RUN apk add --no-cache postgis \
4+
&& rm -rf /usr/local/share/postgresql/extension \
5+
&& ln -s /usr/share/postgresql18/extension /usr/local/share/postgresql/extension \
6+
&& ln -sf /usr/lib/postgresql18/postgis-3.so /usr/local/lib/postgresql/postgis-3.so \
7+
&& ln -sf /usr/lib/postgresql18/rtpostgis-3.so /usr/local/lib/postgresql/rtpostgis-3.so \
8+
&& ln -sf /usr/lib/postgresql18/postgis_sfcgal-3.so /usr/local/lib/postgresql/postgis_sfcgal-3.so

0 commit comments

Comments
 (0)