Skip to content

Commit

Permalink
Added KML generation, Refactored scripts, Updated readme & actions (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
aziascreations committed Nov 12, 2023
1 parent e3a085f commit 38cb4ad
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 114 deletions.
25 changes: 19 additions & 6 deletions .github/workflows/geojson-release.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Make & release GeoJSON
name: Make & release KML & GeoJSON

on:
push:
Expand All @@ -23,13 +23,16 @@ jobs:
with:
python-version: '3.10'

- name: Run "make_geojson.py"
run: python make_geojson.py
- name: Installing dependencies
run: pip install -r requirements.txt

- name: Run "make_all.py"
run: python make_all.py

- name: Check output existence
uses: thebinaryfelix/check-file-existence-action@1.0.0
with:
files: 'output/airports_full_all_feet.geojson, output/airports_full_all_meter.geojson'
files: 'output/airports_full_all_feet.geojson, output/airports_full_all_meter.geojson, output/airports_full.kml'

- name: Create release
id: create_release
Expand All @@ -44,7 +47,7 @@ jobs:
draft: true
prerelease: false

- name: Upload asset `full_all_feet`
- name: Upload asset `airports_full_all_feet.geojson`
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -54,7 +57,7 @@ jobs:
asset_name: airports_full_all_feet.geojson
asset_content_type: application/geo+json

- name: Upload asset `full_all_meter`
- name: Upload asset `airports_full_all_meter.geojson`
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -63,3 +66,13 @@ jobs:
asset_path: ./output/airports_full_all_meter.geojson
asset_name: airports_full_all_meter.geojson
asset_content_type: application/geo+json

- name: Upload asset `airports_full.kml`
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./output/airports_full.kml
asset_name: airports_full.kml
asset_content_type: application/vnd.google-earth.kml+xml
110 changes: 110 additions & 0 deletions commons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import json
import os
import shutil
import sys


# Data adapted from ISO 3166-1
# Source: https://en.m.wikipedia.org/wiki/List_of_sovereign_states_and_dependent_territories_by_continent_(data_file)
COUNTRY_IN_CONTINENT = {
# Africa
"AF": ["AO", "BF", "BI", "BJ", "BW", "CD", "CF", "CG", "CI", "CM", "CV", "DJ", "DZ", "EG", "EH", "ER", "ET", "GA",
"GH", "GM", "GN", "GQ", "GW", "IO", "KE", "KM", "LR", "LS", "LY", "MA", "MG", "ML", "MR", "MU", "MW", "MZ",
"NA", "NE", "NG", "RE", "RW", "SC", "SD", "SH", "SL", "SN", "SO", "SS", "ST", "SZ", "TD", "TF", "TG", "TN",
"TZ", "UG", "YT", "ZA", "ZM", "ZW"],

# Antarctica
"AN": ["AQ", "BV", "GS", "HM"],

# Asia
"AS": ["AE", "AF", "AM", "AZ", "BD", "BH", "BN", "BT", "CC", "CN", "CX", "CY", "EG", "GE", "HK", "ID", "IL", "IN",
"IQ", "IR", "JO", "JP", "KG", "KH", "KP", "KR", "KW", "KZ", "LA", "LB", "LK", "MM", "MN", "MO", "MV", "MY",
"NP", "OM", "PH", "PK", "PS", "QA", "RU", "SA", "SG", "SY", "TH", "TJ", "TL", "TM", "TR", "TW", "UZ", "VN",
"XD", "XS", "YE"],

# Europe
"EU": ["AD", "AL", "AM", "AT", "AX", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE", "DK", "EE", "ES", "FI",
"FO", "FR", "GB", "GE", "GG", "GI", "GR", "HR", "HU", "IE", "IM", "IS", "IT", "JE", "KZ", "LI", "LT", "LU",
"LV", "MC", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT", "RO", "RS", "RU", "SE", "SI", "SJ", "SK", "SM",
"TR", "UA", "VA", "XK"],

# North America
"NA": ["AG", "AI", "AW", "BB", "BL", "BM", "BQ", "BS", "BZ", "CA", "CR", "CU", "CW", "DM", "DO", "GD", "GL", "GP",
"GT", "HN", "HT", "JM", "KN", "KY", "LC", "MF", "MQ", "MS", "MX", "NI", "PA", "PM", "PR", "SV", "SX", "TC",
"TT", "UM", "US", "VC", "VG", "VI"],

# Oceania
"OC": ["AS", "AU", "CK", "FJ", "FM", "GU", "KI", "MH", "MP", "NC", "NF", "NR", "NU", "NZ", "PF", "PG", "PN", "PW",
"SB", "TK", "TO", "TV", "UM", "VU", "WF", "WS", "XX"],

# South America
"SA": ["AR", "BO", "BR", "CL", "CO", "EC", "FK", "GF", "GY", "PE", "PY", "SR", "UY", "VE"]
}


def prepare_output(output_path: str) -> None:
# Removing old output directory
if os.path.exists(output_path):
print(f"Removing old build folder...")
if os.path.isdir(output_path):
shutil.rmtree(output_path)
else:
raise IOError(f"The output location '{output_path}'is a file !")

# Creating new output directory
print(f"Preparing '{output_path}'...")
os.mkdir(output_path)


def get_clean_data(input_file: str) -> dict:
print(f"Loading '{input_file}'...")
with open(input_file, "rb") as f:
raw_data = json.loads(f.read().decode("utf-8"))
print(f"Loaded '{len(raw_data)}' airport(s) !")

# Validating the data
print(f"Validating & fixing the data...")
was_data_valid = True
for raw_airport_key, raw_airport_data in raw_data.items():
for required_field in ["icao", "iata", "name", "city", "state", "country", "elevation", "lat", "lon", "tz"]:
if not (required_field in raw_airport_data):
print(f"ERROR: Airport '{raw_airport_key}' is missing the '{required_field}' field !")
was_data_valid = False
if type(raw_airport_data[required_field]) is str:
if len(raw_airport_data[required_field]) == 0:
raw_airport_data[required_field] = None
if raw_airport_data["icao"] is None and raw_airport_data["iata"] is None:
print(f"ERROR: Airport '{raw_airport_key}' is missing its ICAO and IATA codes !")
was_data_valid = False
if raw_airport_data["name"] is None:
print(f"ERROR: Airport '{raw_airport_key}' is missing its name !")
was_data_valid = False
if raw_airport_data["country"] is None:
print(f"ERROR: Airport '{raw_airport_key}' is missing its country code !")
was_data_valid = False
if not was_data_valid:
print_footer("Cannot continue, we have invalid data !", True)
sys.exit(1)

return raw_data


def print_header(app_name: str, space_count: int = 0) -> None:
print(" \033[36m_ \033[94m__ \033[36m_\033[39m")
print(" \033[96m_ \033[36m_// \033[94m/\\\\ \\ \033[36m\\\\_ \033[96m_\033[39m")
print(" \033[96m_// \033[36m/ / \033[94m/ /_\\ \\ \033[36m\\ \\ \033[96m\\\\_\033[39m")
print(" \033[96m/ / \033[36m/ / \033[94m/ ___\\\\ \\ \033[36m\\ \\ \033[96m\\ \\\033[39m")
print(" \033[96m/_/ \033[36m/_/ \033[94m/_/ \033[94m\\_\\ \033[36m\\_\\ \033[96m\\_\\\033[39m")
print("\033[36m-\033[94m===========================\033[36m-\033[39m")
print(f"{' '*space_count}\033[36m{app_name}\033[39m")
print("\033[36m-\033[94m===========================\033[36m-\033[39m")


def print_footer(message: str = "Goodbye :)", is_error: bool = False) -> None:
print("\033[36m-\033[94m===========================\033[36m-\033[39m")
if is_error:
print(f"\033[31m{message}\033[39m")
else:
print(message)
print("\033[36m-\033[94m===========================\033[36m-\033[39m")
print(" \033[96m\\_\\ \033[36m\\_\\ \033[36m/_/ \033[96m/_/\033[39m")
37 changes: 0 additions & 37 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,3 @@

# Number of decimal places in meter elevations
METER_DECIMAL_COUNT = 0

# Data adapted from ISO 3166-1
# Source: https://en.m.wikipedia.org/wiki/List_of_sovereign_states_and_dependent_territories_by_continent_(data_file)
COUNTRY_IN_CONTINENT = {
# Africa
"AF": ["AO", "BF", "BI", "BJ", "BW", "CD", "CF", "CG", "CI", "CM", "CV", "DJ", "DZ", "EG", "EH", "ER", "ET", "GA",
"GH", "GM", "GN", "GQ", "GW", "IO", "KE", "KM", "LR", "LS", "LY", "MA", "MG", "ML", "MR", "MU", "MW", "MZ",
"NA", "NE", "NG", "RE", "RW", "SC", "SD", "SH", "SL", "SN", "SO", "SS", "ST", "SZ", "TD", "TF", "TG", "TN",
"TZ", "UG", "YT", "ZA", "ZM", "ZW"],

# Antarctica
"AN": ["AQ", "BV", "GS", "HM"],

# Asia
"AS": ["AE", "AF", "AM", "AZ", "BD", "BH", "BN", "BT", "CC", "CN", "CX", "CY", "EG", "GE", "HK", "ID", "IL", "IN",
"IQ", "IR", "JO", "JP", "KG", "KH", "KP", "KR", "KW", "KZ", "LA", "LB", "LK", "MM", "MN", "MO", "MV", "MY",
"NP", "OM", "PH", "PK", "PS", "QA", "RU", "SA", "SG", "SY", "TH", "TJ", "TL", "TM", "TR", "TW", "UZ", "VN",
"XD", "XS", "YE"],

# Europe
"EU": ["AD", "AL", "AM", "AT", "AX", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE", "DK", "EE", "ES", "FI",
"FO", "FR", "GB", "GE", "GG", "GI", "GR", "HR", "HU", "IE", "IM", "IS", "IT", "JE", "KZ", "LI", "LT", "LU",
"LV", "MC", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT", "RO", "RS", "RU", "SE", "SI", "SJ", "SK", "SM",
"TR", "UA", "VA", "XK"],

# North America
"NA": ["AG", "AI", "AW", "BB", "BL", "BM", "BQ", "BS", "BZ", "CA", "CR", "CU", "CW", "DM", "DO", "GD", "GL", "GP",
"GT", "HN", "HT", "JM", "KN", "KY", "LC", "MF", "MQ", "MS", "MX", "NI", "PA", "PM", "PR", "SV", "SX", "TC",
"TT", "UM", "US", "VC", "VG", "VI"],

# Oceania
"OC": ["AS", "AU", "CK", "FJ", "FM", "GU", "KI", "MH", "MP", "NC", "NF", "NR", "NU", "NZ", "PF", "PG", "PN", "PW",
"SB", "TK", "TO", "TV", "UM", "VU", "WF", "WS", "XX"],

# South America
"SA": ["AR", "BO", "BR", "CL", "CO", "EC", "FK", "GF", "GY", "PE", "PY", "SR", "UY", "VE"]
}
25 changes: 25 additions & 0 deletions make_all.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import commons
import config

from make_geojson import make_geojson
from make_kml import make_kml


if __name__ == "__main__":
# > Printing the logs header
commons.print_header("Data File Maker", 7)

# Preparing the output directory
commons.prepare_output(config.OUTPUT_DIR)

# Loading the JSON raw data file.
_raw_data = commons.get_clean_data(config.INPUT_FILE)

# Running the actual logic
print("\033[36m-\033[94m===========================\033[36m-\033[39m")
make_geojson(_raw_data)
print("\033[36m-\033[94m===========================\033[36m-\033[39m")
make_kml(_raw_data)

# Printing the logs footer
commons.print_footer()
87 changes: 19 additions & 68 deletions make_geojson.py
Original file line number Diff line number Diff line change
@@ -1,78 +1,14 @@
import copy
import gc
import json
import os
import shutil
import sys

import commons
import config


def print_footer(message: str = "Goodbye :)", is_error: bool = False) -> None:
print("\033[36m-\033[94m===========================\033[36m-\033[39m")
if is_error:
print(f"\033[31m{message}\033[39m")
else:
print(message)
print("\033[36m-\033[94m===========================\033[36m-\033[39m")
print(" \033[96m\\_\\ \033[36m\\_\\ \033[36m/_/ \033[96m/_/\033[39m")


if __name__ == "__main__":
# > Printing the logs header
print(" \033[36m_ \033[94m__ \033[36m_\033[39m")
print(" \033[96m_ \033[36m_// \033[94m/\\\\ \\ \033[36m\\\\_ \033[96m_\033[39m")
print(" \033[96m_// \033[36m/ / \033[94m/ /_\\ \\ \033[36m\\ \\ \033[96m\\\\_\033[39m")
print(" \033[96m/ / \033[36m/ / \033[94m/ ___\\\\ \\ \033[36m\\ \\ \033[96m\\ \\\033[39m")
print(" \033[96m/_/ \033[36m/_/ \033[94m/_/ \033[94m\\_\\ \033[36m\\_\\ \033[96m\\_\\\033[39m")
print("\033[36m-\033[94m===========================\033[36m-\033[39m")
print(" \033[36mTraefik Logs Preprocessor\033[39m")
print("\033[36m-\033[94m===========================\033[36m-\033[39m")

# Removing old output directory
if os.path.exists(config.OUTPUT_DIR):
print(f"Removing old build folder...")
if os.path.isdir(config.OUTPUT_DIR):
shutil.rmtree(config.OUTPUT_DIR)
else:
raise IOError(f"The output location '{config.OUTPUT_DIR}'is a file !")

# Creating new output directory
print(f"Preparing '{config.OUTPUT_DIR}'...")
os.mkdir(config.OUTPUT_DIR)

# Loading the JSON raw data file.
print(f"Loading '{config.INPUT_FILE}'...")
with open(config.INPUT_FILE, "rb") as f:
raw_data = json.loads(f.read().decode("utf-8"))
print(f"Loaded '{len(raw_data)}' airport(s) !")

# Validating the data
print(f"Validating & fixing the data...")
was_data_valid = True
for raw_airport_key, raw_airport_data in raw_data.items():
for required_field in ["icao", "iata", "name", "city", "state", "country", "elevation", "lat", "lon", "tz"]:
if not (required_field in raw_airport_data):
print(f"ERROR: Airport '{raw_airport_key}' is missing the '{required_field}' field !")
was_data_valid = False
if type(raw_airport_data[required_field]) is str:
if len(raw_airport_data[required_field]) == 0:
raw_airport_data[required_field] = None
if raw_airport_data["icao"] is None and raw_airport_data["iata"] is None:
print(f"ERROR: Airport '{raw_airport_key}' is missing its ICAO and IATA codes !")
was_data_valid = False
if raw_airport_data["name"] is None:
print(f"ERROR: Airport '{raw_airport_key}' is missing its name !")
was_data_valid = False
if raw_airport_data["country"] is None:
print(f"ERROR: Airport '{raw_airport_key}' is missing its country code !")
was_data_valid = False
if not was_data_valid:
print_footer("Cannot continue, we have invalid data !", True)
sys.exit(1)

def make_geojson(raw_data: dict):
# Preparing the output data structure
print(f"Preparing the output structure...")
print("Preparing the output GeoJSON structure...")
geojson_data_feet = {
"type": "FeatureCollection",
"features": list()
Expand Down Expand Up @@ -119,5 +55,20 @@ def print_footer(message: str = "Goodbye :)", is_error: bool = False) -> None:
# geojson_data_iata_feet = copy.deepcopy(geojson_data_feet)
# geojson_data_iata_meter = copy.deepcopy(geojson_data_meters)


if __name__ == "__main__":
# > Printing the logs header
commons.print_header("GeoJSON File Maker", 5)

# Preparing the output directory
commons.prepare_output(config.OUTPUT_DIR)

# Loading the JSON raw data file.
_raw_data = commons.get_clean_data(config.INPUT_FILE)

# Running the actual logic
print("\033[36m-\033[94m===========================\033[36m-\033[39m")
make_geojson(_raw_data)

# Printing the logs footer
print_footer()
commons.print_footer()
50 changes: 50 additions & 0 deletions make_kml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import copy
import gc
import json
import os

import commons
import config

import simplekml


def make_kml(raw_data: dict):
# Preparing the output data structure
print("Preparing the output KML structure...")
kml_main = simplekml.Kml()

# Converting to KML
print(f"Converting data to KML points...")
for raw_airport_key, raw_airport_data in raw_data.items():
pnt = kml_main.newpoint(
name=f"{raw_airport_data['icao']} - {raw_airport_data['name']}",
coords=[(raw_airport_data['lon'], raw_airport_data['lat'], )],
)
pnt.name = raw_airport_key
pass

print("Saving 'airports_full.kml'...")
kml_main.save(os.path.join(config.OUTPUT_DIR, "airports_full.kml"))

# Helping the GC along
del kml_main
gc.collect()


if __name__ == "__main__":
# > Printing the logs header
commons.print_header("KML File Maker", 7)

# Preparing the output directory
commons.prepare_output(config.OUTPUT_DIR)

# Loading the JSON raw data file.
_raw_data = commons.get_clean_data(config.INPUT_FILE)

# Running the actual logic
print("\033[36m-\033[94m===========================\033[36m-\033[39m")
make_kml(_raw_data)

# Printing the logs footer
commons.print_footer()
Loading

0 comments on commit 38cb4ad

Please sign in to comment.