Skip to content
Closed
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
162 changes: 121 additions & 41 deletions .github/scripts/update_availprofiles.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,140 @@
import os
import json
import logging
from copy import deepcopy

avail_profiles_path = 'AvailProfiles.json'
airports_dir = 'Airports'
avail_profiles_path = "AvailProfiles.json"
airports_dir = "Airports"

logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)


def get_actual_files(profile_path):
"""Get list of .ini and .py files in the profile directory"""
actual_files = []
if os.path.exists(profile_path):
for file_name in os.listdir(profile_path):
if file_name.endswith(".ini") or file_name.endswith(".py"):
actual_files.append(file_name)
return sorted(actual_files) # Sort for consistent ordering


def profiles_are_equal(profile1, profile2):
"""Compare two profiles to see if they have the same content"""
# Compare all fields except FileNames first
fields_to_compare = ["ProfileICAO", "Scenery", "Creator", "Version"]
for field in fields_to_compare:
if profile1.get(field) != profile2.get(field):
return False

# Compare FileNames (order doesn't matter)
files1 = sorted(profile1.get("FileNames", []))
files2 = sorted(profile2.get("FileNames", []))
return files1 == files2

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def get_airports():
# Load existing data
if os.path.exists(avail_profiles_path):
with open(avail_profiles_path) as f:
with open(avail_profiles_path, "r") as f:
data = json.load(f)
else:
data = []

# Create a mapping of existing profiles by folder name for quick lookup
existing_profiles = {profile["Folder"]: profile for profile in data}
updated_profiles = []

# Track which profiles we've seen (to remove obsolete ones later)
found_profiles = set()

# Track if any changes were made
changes_made = False

# Process each airport directory
for root, dirs, _ in os.walk(airports_dir):
for dir_name in dirs:
profile_path = os.path.join(root, dir_name)
profile_json_path = os.path.join(profile_path, "profile.json")

# Skip if no profile.json exists
if not os.path.exists(profile_json_path):
logging.warning(f"No profile.json found in {profile_path}, skipping")
continue

logging.info(f"Processing {dir_name}")
found_profiles.add(dir_name)

try:
# Read profile.json
with open(profile_json_path, "r") as profile_file:
profile_data = json.load(profile_file)

# Get actual files in directory
actual_files = get_actual_files(profile_path)

# Create new profile data
new_profile = {
"Folder": dir_name,
"ProfileICAO": profile_data["ProfileICAO"],
"Scenery": profile_data["Scenery"],
"Creator": profile_data["Creator"],
"Version": str(profile_data["Version"]),
"FileNames": actual_files,
}

# Check if this profile exists and compare
if dir_name in existing_profiles:
existing_profile = existing_profiles[dir_name]
if not profiles_are_equal(existing_profile, new_profile):
# Log what changed
changes = []
for field in ["ProfileICAO", "Scenery", "Creator", "Version"]:
if existing_profile.get(field) != new_profile.get(field):
changes.append(
f"{field}: '{existing_profile.get(field)}' -> '{new_profile.get(field)}'"
)

old_files = sorted(existing_profile.get("FileNames", []))
new_files = sorted(new_profile.get("FileNames", []))
if old_files != new_files:
changes.append(f"FileNames: {old_files} -> {new_files}")

logging.info(
f"Updating existing profile for {dir_name}: {'; '.join(changes)}"
)
# Update the existing profile in place to preserve position
for i, profile in enumerate(data):
if profile["Folder"] == dir_name:
data[i] = new_profile
changes_made = True
break
else:
logging.info(f"No changes needed for {dir_name}")
else:
logging.info(f"Adding new profile for {dir_name}")
data.append(new_profile)
changes_made = True

except (json.JSONDecodeError, KeyError) as e:
logging.error(f"Error processing {profile_json_path}: {e}")
continue

# Remove profiles that no longer exist in the filesystem
original_length = len(data)
data = [profile for profile in data if profile["Folder"] in found_profiles]
if len(data) != original_length:
logging.info(f"Removed {original_length - len(data)} obsolete profiles")
changes_made = True

# Only write the file if changes were made
if changes_made:
logging.info("Writing updated AvailProfiles.json")
with open(avail_profiles_path, "w") as f:
json.dump(data, f, indent=4)
else:
logging.info("No changes needed, file not modified")


if dir_name in existing_profiles:
profile = existing_profiles[dir_name]
logging.info(f"Updating existing profile for {dir_name}")
else:
profile = {"Folder": dir_name}
logging.info(f"Creating new profile for {dir_name}")

with open(profile_path + '/profile.json', 'r') as profile_file:
profile_data = json.load(profile_file)
profile["ProfileICAO"] = profile_data["ProfileICAO"]
profile["Scenery"] = profile_data["Scenery"]
profile["Creator"] = profile_data["Creator"]
profile["Version"] = str(profile_data["Version"])
profile["FileNames"] = profile.get("FileNames", [])

# Check for missing files in profile_path
for file_name in profile["FileNames"]:
file_path = os.path.join(profile_path, file_name)
if not os.path.exists(file_path):
logging.warning(f"File {file_name} does not exist in {profile_path}. Removing it.")
profile["FileNames"].remove(file_name)

# Add missing files to profile
for file_name in os.listdir(profile_path):
if file_name.endswith('.ini') or file_name.endswith('.py'):
if file_name not in profile["FileNames"]:
logging.warning(f"File {file_name} does not exist in {avail_profiles_path}. Adding it.")
profile["FileNames"].append(file_name)

updated_profiles.append(profile)

# Write the updated profiles
with open(avail_profiles_path, 'w') as f:
json.dump(updated_profiles, f, indent=4)

get_airports()
get_airports()
21 changes: 15 additions & 6 deletions .github/workflows/json-validator.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
name: JSON Validator
description: Validate JSON files in the Airports folder and comment on PRs with the diff

on:
push:
pull_request:
branches:
- main
pull_request:
paths:
- 'Airports/**/*.json' # Trigger only for JSON files in the Airports folder
- '**/*.json' # Trigger for any JSON files in the repository
workflow_dispatch:

permissions:
contents: read
pull-requests: write # enable write permissions for pull request comments

jobs:
json-yaml-validate:
json-validate:
runs-on: ubuntu-latest
name: Validate JSON Files
steps:
# Checkout the repo
- uses: actions/checkout@v4
Expand All @@ -36,4 +36,13 @@ jobs:
with:
comment: "true" # enable comment mode
base_dir: ./ # Base directory for validation
files: ${{ steps.git-diff-action.outputs.json-diff-path }} # Validate only changed files
files: ${{ steps.git-diff-action.outputs.json-diff-path }} # Validate only changed files

# Explicit success message when no JSON files changed
- name: No JSON files to validate
if: ${{ steps.git-diff-action.outputs.json-diff-path == '' }}
run: echo "✅ No JSON files were modified in this PR"

# Final validation status
- name: JSON Validation Complete
run: echo "✅ All JSON files are valid"
37 changes: 23 additions & 14 deletions .github/workflows/update_availprofiles.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
name: Update AvailProfiles

on:
push:
pull_request:
branches:
- main
paths:
- 'Airports/**'

permissions:
contents: write
Expand All @@ -16,6 +18,9 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4.2.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }}

- name: Set up Python
uses: actions/setup-python@v5.3.0
Expand All @@ -28,16 +33,20 @@ jobs:
- name: Update AvailProfiles.json
run: python .github/scripts/update_availprofiles.py

- name: Create pull request
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: Update AvailProfiles.json
title: Update Available Profiles
body: |
This PR updates the AvailProfiles.json file.
branch: availprofiles
base: main
reviewers: hinshee
assignees: hinshee
labels: auto-update
- name: Check for changes
id: changes
run: |
if git diff --quiet AvailProfiles.json; then
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "changed=true" >> $GITHUB_OUTPUT
fi

- name: Commit changes
if: steps.changes.outputs.changed == 'true'
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add AvailProfiles.json
git commit -m "Auto-update AvailProfiles.json"
git push
12 changes: 12 additions & 0 deletions Airports/EGBB (Pyreegue)/Information.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!--- Licensed Under: CC BY-NC 4.0 --->

Pyreegue EGBB 🐐
Available from these retailers: [Contrail.shop](https://contrail.shop/products/pyreegue-egbb-birmingham-airport-msfs-2020-2024?_pos=1&_sid=b06674ea9&_ss=r)
## Features:
- Custom Vehicle Positioning on all stands
- Walk-in gates
- Accurate Custom Pushbacks
- Accurate Ground Handling Agents
- Fixed Jetway Floor Heights

Special thanks to Krake802 and several community members that reached out to help support. ❤️
Loading
Loading