Эх сурвалжийг харах

app.py: use metadata_manager module

Shiv Tyagi 1 жил өмнө
parent
commit
12686d9e86
1 өөрчлөгдсөн 57 нэмэгдсэн , 132 устгасан
  1. 57 132
      app.py

+ 57 - 132
app.py

@@ -10,14 +10,12 @@ import time
 import fcntl
 import fcntl
 import base64
 import base64
 import hashlib
 import hashlib
-import fnmatch
 from distutils.dir_util import copy_tree
 from distutils.dir_util import copy_tree
 from flask import Flask, render_template, request, send_from_directory, render_template_string, jsonify, redirect
 from flask import Flask, render_template, request, send_from_directory, render_template_string, jsonify, redirect
 from threading import Thread, Lock
 from threading import Thread, Lock
 import sys
 import sys
 import re
 import re
 import requests
 import requests
-import jsonschema
 
 
 from logging.config import dictConfig
 from logging.config import dictConfig
 
 
@@ -38,6 +36,7 @@ dictConfig({
 })
 })
 
 
 import ap_git
 import ap_git
+import metadata_manager
 
 
 # run at lower priority
 # run at lower priority
 os.nice(20)
 os.nice(20)
@@ -64,16 +63,6 @@ REMOTES = None
 
 
 # LOCKS
 # LOCKS
 queue_lock = Lock()
 queue_lock = Lock()
-remotes_lock = Lock()  # lock for accessing and updating REMOTES list
-
-def get_remotes():
-    with remotes_lock:
-        return REMOTES
-    
-def set_remotes(remotes):
-    with remotes_lock:
-        global REMOTES
-        REMOTES = remotes
 
 
 try:
 try:
     repo = ap_git.GitRepo(sourcedir)
     repo = ap_git.GitRepo(sourcedir)
@@ -84,95 +73,27 @@ except FileNotFoundError:
         recurse_submodules=True,
         recurse_submodules=True,
     )
     )
 
 
-def load_remotes():
-    # load file contianing vehicles listed to be built for each remote along with the braches/tags/commits on which the firmware can be built
-    with open(os.path.join(basedir, 'configs', 'remotes.json'), 'r')  as f, open(os.path.join(appdir, 'remotes.schema.json'), 'r') as s:
-        remotes = json.loads(f.read())
-        schema = json.loads(s.read())
-        # validate schema
-        jsonschema.validate(remotes, schema=schema)
-        setup_remotes_urls(remotes)
-        set_remotes(remotes)
-
-
-def find_version_info(vehicle_name, remote_name, commit_reference):
-    if None in (vehicle_name, remote_name, commit_reference):
-        return None
-    
-    # find the object for requested remote
-    remote = next((r for r in get_remotes() if r['name'] == remote_name), None)
-
-    if remote is None:
-        return None
-    
-    # find the object requested vehicle in remote metadata
-    vehicle = next((v for v in remote['vehicles'] if v['name'] == vehicle_name), None)
+ap_src_metadata_fetcher = metadata_manager.APSourceMetadataFetcher(
+    ap_repo_path=sourcedir
+)
+versions_fetcher = metadata_manager.VersionsFetcher(
+    remotes_json_path=os.path.join(basedir, 'configs', 'remotes.json')
+)
 
 
-    if vehicle is None:
-        return None
-    
-    # find version metadata for asked commit reference
-    release = next((r for r in vehicle['releases'] if r['commit_reference'] == commit_reference), None)
-    return release
-
-def get_boards_from_ardupilot_tree(s_dir):
-    '''return a list of boards to build'''
-    tstart = time.time()
-    import importlib.util
-    spec = importlib.util.spec_from_file_location("board_list.py",
-                                                  os.path.join(s_dir, 
-                                                  'Tools', 'scripts', 
-                                                  'board_list.py'))
-    mod = importlib.util.module_from_spec(spec)
-    spec.loader.exec_module(mod)
-    all_boards = mod.AUTOBUILD_BOARDS
-    exclude_patterns = [ 'fmuv*', 'SITL*' ]
-    boards = []
-    for b in all_boards:
-        excluded = False
-        for p in exclude_patterns:
-            if fnmatch.fnmatch(b.lower(), p.lower()):
-                excluded = True
-                break
-        if not excluded:
-            boards.append(b)
-    app.logger.info('Took %f seconds to get boards' % (time.time() - tstart))
-    boards.sort()
-    default_board = boards[0]
-    return (boards, default_board)
-
-def get_build_options_from_ardupilot_tree(s_dir):
-    '''return a list of build options'''
-    tstart = time.time()
-    import importlib.util
-    spec = importlib.util.spec_from_file_location(
-        "build_options.py",
-        os.path.join(s_dir, 'Tools', 'scripts', 'build_options.py'))
-    mod = importlib.util.module_from_spec(spec)
-    spec.loader.exec_module(mod)
-    app.logger.info('Took %f seconds to get build options' % (time.time() - tstart))
-    return mod.BUILD_OPTIONS
-
-def setup_remotes_urls(remotes):
+def load_remotes():
+    versions_fetcher.reload_remotes_json()
     added_remotes = 0
     added_remotes = 0
-    for remote in remotes:
+    for remote_info in versions_fetcher.get_all_remotes_info():
         try:
         try:
-            repo.remote_add(
-                remote=remote['name'],
-                url=remote['url'],
-            )
+            repo.remote_add(remote=remote_info.name, url=remote_info.url)
         except ap_git.DuplicateRemoteError:
         except ap_git.DuplicateRemoteError:
             app.logger.info(
             app.logger.info(
-                f"remote '{remote['name']}' already exists. "
-                f"Updating url to '{remote['url']}'."
-            )
-            repo.remote_set_url(
-                remote=remote['name'],
-                url=remote['url'],
+                f"Remote '{remote_info.name}' already exists. "
+                f"Updating url to '{remote_info.url}'."
             )
             )
+            repo.remote_set_url(remote=remote_info.name, url=remote_info.url)
         added_remotes += 1
         added_remotes += 1
-
-    app.logger.info("%d/%d remotes added to base repo" % (added_remotes, len(remotes)))
+    app.logger.info(f"{added_remotes} remotes added to base repo")
 
 
 def remove_directory_recursive(dirname):
 def remove_directory_recursive(dirname):
     '''remove a directory recursively'''
     '''remove a directory recursively'''
@@ -519,25 +440,28 @@ def generate():
         chosen_version = request.form['version']
         chosen_version = request.form['version']
         chosen_remote, chosen_commit_reference = chosen_version.split('/', 1)
         chosen_remote, chosen_commit_reference = chosen_version.split('/', 1)
         chosen_vehicle = request.form['vehicle']
         chosen_vehicle = request.form['vehicle']
-        chosen_version_info = find_version_info(vehicle_name=chosen_vehicle, remote_name=chosen_remote, commit_reference=chosen_commit_reference)
+        chosen_version_info = versions_fetcher.get_version_info(
+            vehicle=chosen_vehicle,
+            remote=chosen_remote,
+            commit_ref=chosen_commit_reference
+        )
 
 
         if chosen_version_info is None:
         if chosen_version_info is None:
             raise Exception("Commit reference invalid or not listed to be built for given vehicle for remote")
             raise Exception("Commit reference invalid or not listed to be built for given vehicle for remote")
 
 
         chosen_board = request.form['board']
         chosen_board = request.form['board']
-        with repo.get_checkout_lock():
-            repo.checkout_remote_commit_ref(
-                remote=chosen_remote,
-                commit_ref=chosen_commit_reference,
-                force=True,
-                hard_reset=True,
-                clean_working_tree=True
-            )
-            if chosen_board not in get_boards_from_ardupilot_tree(s_dir=sourcedir)[0]:
-                raise Exception("bad board")
+        boards_at_commit, _ = ap_src_metadata_fetcher.get_boards_at_commit(
+            remote=chosen_remote,
+            commit_ref=chosen_commit_reference
+        )
+        if chosen_board not in boards_at_commit:
+            raise Exception("bad board")
 
 
-            #ToDo - maybe have the if-statement to check if it's changed.
-            build_options = get_build_options_from_ardupilot_tree(s_dir=sourcedir)
+        #ToDo - maybe have the if-statement to check if it's changed.
+        build_options = ap_src_metadata_fetcher.get_build_options_at_commit(
+            remote=chosen_remote,
+            commit_ref=chosen_commit_reference
+        )
 
 
         # fetch features from user input
         # fetch features from user input
         extra_hwdef = []
         extra_hwdef = []
@@ -601,7 +525,7 @@ def generate():
                 '\nBoard: ' + chosen_board +
                 '\nBoard: ' + chosen_board +
                 '\nRemote: ' + chosen_remote +
                 '\nRemote: ' + chosen_remote +
                 '\ngit-sha: ' + git_hash_short +
                 '\ngit-sha: ' + git_hash_short +
-                '\nVersion: ' + chosen_version_info['release_type'] + '-' + chosen_version_info['version_number'] +
+                '\nVersion: ' + chosen_version_info.release_type + '-' + chosen_version_info.version_number +
                 '\nSelected Features:\n' + feature_list +
                 '\nSelected Features:\n' + feature_list +
                 '\n\nWaiting for build to start...\n\n')
                 '\n\nWaiting for build to start...\n\n')
             app.logger.info('Creating build.log')
             app.logger.info('Creating build.log')
@@ -620,7 +544,7 @@ def generate():
             task['token'] = token
             task['token'] = token
             task['remote'] = chosen_remote
             task['remote'] = chosen_remote
             task['git_hash_short'] = git_hash_short
             task['git_hash_short'] = git_hash_short
-            task['version'] = chosen_version_info['release_type'] + '-' + chosen_version_info['version_number']
+            task['version'] = chosen_version_info.release_type + '-' + chosen_version_info.version_number
             task['extra_hwdef'] = os.path.join(outdir, 'extra_hwdef.dat')
             task['extra_hwdef'] = os.path.join(outdir, 'extra_hwdef.dat')
             task['vehicle'] = chosen_vehicle.lower()
             task['vehicle'] = chosen_vehicle.lower()
             task['board'] = chosen_board
             task['board'] = chosen_board
@@ -677,7 +601,7 @@ def download_file(name):
 def boards_and_features(vehicle_name, remote_name, commit_reference):
 def boards_and_features(vehicle_name, remote_name, commit_reference):
     commit_reference = base64.urlsafe_b64decode(commit_reference).decode()
     commit_reference = base64.urlsafe_b64decode(commit_reference).decode()
 
 
-    if find_version_info(vehicle_name, remote_name, commit_reference) is None:
+    if not versions_fetcher.is_version_listed(vehicle=vehicle_name, remote=remote_name, commit_ref=commit_reference):
         return "Bad request. Commit reference not allowed to build for the vehicle.", 400
         return "Bad request. Commit reference not allowed to build for the vehicle.", 400
 
 
     app.logger.info('Board list and build options requested for %s %s %s' % (vehicle_name, remote_name, commit_reference))
     app.logger.info('Board list and build options requested for %s %s %s' % (vehicle_name, remote_name, commit_reference))
@@ -690,8 +614,16 @@ def boards_and_features(vehicle_name, remote_name, commit_reference):
             hard_reset=True,
             hard_reset=True,
             clean_working_tree=True,
             clean_working_tree=True,
         )
         )
-        (boards, default_board) = get_boards_from_ardupilot_tree(s_dir=sourcedir)
-        options = get_build_options_from_ardupilot_tree(s_dir=sourcedir)   # this is a list of Feature() objects defined in build_options.py
+        (boards, default_board) = ap_src_metadata_fetcher.get_boards_at_commit(
+            remote=remote_name,
+            commit_ref=commit_reference
+        )
+
+        options = ap_src_metadata_fetcher.get_build_options_at_commit(
+            remote=remote_name,
+            commit_ref=commit_reference
+        )   # this is a list of Feature() objects defined in build_options.py
+
     # parse the set of categories from these objects
     # parse the set of categories from these objects
     categories = parse_build_categories(options)
     categories = parse_build_categories(options)
     features = []
     features = []
@@ -722,29 +654,22 @@ def boards_and_features(vehicle_name, remote_name, commit_reference):
 @app.route("/get_versions/<string:vehicle_name>", methods=['GET'])
 @app.route("/get_versions/<string:vehicle_name>", methods=['GET'])
 def get_versions(vehicle_name):
 def get_versions(vehicle_name):
     versions = list()
     versions = list()
-    for remote in get_remotes():
-        for vehicle in remote['vehicles']:
-            if vehicle['name'] == vehicle_name:
-                for release in vehicle['releases']:
-                    if release['release_type'] == "latest":
-                        title = f'Latest ({remote["name"]})'
-                    else:
-                        title = f'{release["release_type"]} {release["version_number"]} ({remote["name"]})'
-                    id = f'{remote["name"]}/{release["commit_reference"]}'
-                    versions.append({
-                        "title" :   title,
-                        "id"    :   id,
-                    })
+    for version_info in versions_fetcher.get_versions_for_vehicle(vehicle_name=vehicle_name):
+        if version_info.release_type == "latest":
+            title = f"Latest ({version_info.remote})"
+        else:
+            title = f"{version_info.release_type} {version_info.version_number} ({version_info.remote})"
+        id = f"{version_info.remote}/{version_info.commit_ref}"
+        versions.append({
+            "title" :   title,
+            "id"    :   id,
+        })
 
 
     return jsonify(sorted(versions, key=lambda x: x['title']))
     return jsonify(sorted(versions, key=lambda x: x['title']))
 
 
 @app.route("/get_vehicles")
 @app.route("/get_vehicles")
 def get_vehicles():
 def get_vehicles():
-    vehicle_set = set()
-    for remote in get_remotes():
-        vehicle_set = vehicle_set.union(set([vehicle['name'] for vehicle in remote['vehicles']]))
-
-    return jsonify(sorted(list(vehicle_set)))
+    return jsonify(versions_fetcher.get_all_vehicles_sorted_uniq())
 
 
 @app.route("/get_defaults/<string:vehicle_name>/<string:remote_name>/<string:commit_reference>/<string:board_name>", methods = ['GET'])
 @app.route("/get_defaults/<string:vehicle_name>/<string:remote_name>/<string:commit_reference>/<string:board_name>", methods = ['GET'])
 def get_deafults(vehicle_name, remote_name, commit_reference, board_name):
 def get_deafults(vehicle_name, remote_name, commit_reference, board_name):
@@ -753,12 +678,12 @@ def get_deafults(vehicle_name, remote_name, commit_reference, board_name):
         vehicle_name = "Copter"
         vehicle_name = "Copter"
 
 
     commit_reference = base64.urlsafe_b64decode(commit_reference).decode()
     commit_reference = base64.urlsafe_b64decode(commit_reference).decode()
-    version_info = find_version_info(vehicle_name, remote_name, commit_reference)
+    version_info = versions_fetcher.get_version_info(vehicle=vehicle_name, remote=remote_name, commit_ref=commit_reference)
 
 
     if version_info is None:
     if version_info is None:
         return "Bad request. Commit reference %s is not allowed for builds for the %s for %s remote." % (commit_reference, vehicle_name, remote_name), 400
         return "Bad request. Commit reference %s is not allowed for builds for the %s for %s remote." % (commit_reference, vehicle_name, remote_name), 400
 
 
-    artifacts_dir = version_info.get("ap_build_artifacts_url", None)
+    artifacts_dir = version_info.ap_build_artifacts_url
 
 
     if artifacts_dir is None:
     if artifacts_dir is None:
         return "Couldn't find artifacts for requested release/branch/commit on ardupilot server", 404
         return "Couldn't find artifacts for requested release/branch/commit on ardupilot server", 404