Просмотр исходного кода

assign allowed vehicles to branches

This assigns which vehicles are allowed to be built on a branch so that when a user selects a vehicle in the application, he only sees the branches which should be built for that vehicle
Shiv Tyagi 3 лет назад
Родитель
Сommit
b572d7e435
2 измененных файлов с 144 добавлено и 45 удалено
  1. 85 29
      app.py
  2. 59 16
      templates/index.html

+ 85 - 29
app.py

@@ -21,36 +21,72 @@ os.nice(20)
 
 appdir = os.path.dirname(__file__)
 
-VEHICLES = [ 'Copter', 'Plane', 'Rover', 'Sub', 'AntennaTracker', 'Blimp', 'Heli']
-default_vehicle = 'Copter'
-#Note: Current implementation of BRANCHES means we can't have multiple branches with the same name even if they're in different remote repos.
-#Branch names (the git branch name not the display name) also cannot contain anything not valid in folder names.
-BRANCHES = {
-    'upstream/master' : 'Latest',
-    'upstream/Plane-4.2' : 'Plane 4.2 stable',
-    'upstream/Copter-4.2' : 'Copter 4.2 stable',
-    'upstream/Rover-4.2' : 'Rover 4.2 stable'
-}
-default_branch = 'upstream/master'
-
-def get_vehicles():
-    return VEHICLES
-
-def get_default_vehicle():
-    return default_vehicle
+class Vehicle:
+    def __init__(self, name):
+        self.name = name
+
+# create vehicle objects
+copter = Vehicle('Copter')
+plane = Vehicle('Plane')
+rover = Vehicle('Rover')
+sub = Vehicle('Sub')
+tracker = Vehicle('AntennaTracker')
+blimp = Vehicle('Blimp')
+heli = Vehicle('Heli')
+
+VEHICLES = [copter, plane, rover, sub, tracker, blimp, heli]
+default_vehicle = copter
+# Note: Current implementation of BRANCHES means we can't have multiple branches with the same name even if they're in different remote repos.
+# Branch names (the git branch name not the Label) also cannot contain anything not valid in folder names.
+# the first branch in this list is always the default branch
+BRANCHES = [
+    {
+        'full_name'         : 'upstream/master',
+        'label'             : 'Latest',
+        'allowed_vehicles'  : [copter, plane, rover, sub, tracker, blimp, heli]
+    },
+    {
+        'full_name'         : 'upstream/Plane-4.3',
+        'label'             : 'Plane 4.3 stable',
+        'allowed_vehicles'  : [plane]
+    },
+    {
+        'full_name'         : 'upstream/Copter-4.3',
+        'label'             : 'Copter 4.3 stable',
+        'allowed_vehicles'  : [copter, heli]
+    },
+    {
+        'full_name'         : 'upstream/Rover-4.3',
+        'label'             : 'Rover 4.3 stable',
+        'allowed_vehicles'  : [rover]
+    },
+]
+default_branch = BRANCHES[0]
+
+def get_vehicle_names():
+    return sorted([vehicle.name for vehicle in VEHICLES])
+
+def get_default_vehicle_name():
+    return default_vehicle.name
+
+def get_branch_names():
+    return sorted([branch['full_name'] for branch in BRANCHES])
 
 def get_branches():
-    return BRANCHES
+    return sorted(BRANCHES, key=lambda x: x['full_name'])
 
-def get_default_branch():
-    return default_branch
+def get_default_branch_name():
+    return default_branch['full_name']
 
 # LOCKS
 queue_lock = Lock()
 head_lock = Lock()  # lock git HEAD, i.e., no branch change until this lock is released
 
-def is_valid_branch(branch):
-    return get_branches().get(branch) is not None
+def is_valid_vehicle(vehicle_name):
+    return vehicle_name in get_vehicle_names()
+
+def is_valid_branch(branch_name):
+    return branch_name in get_branch_names()
 
 def run_git(cmd, cwd):
     app.logger.info("Running git: %s" % ' '.join(cmd))
@@ -68,7 +104,7 @@ def on_branch(branch):
     return git_hash_target == git_hash_current
 
 def delete_branch(branch_name, s_dir):
-    run_git(['git', 'checkout', default_branch], cwd=s_dir) # to make sure we are not already on branch to be deleted
+    run_git(['git', 'checkout', get_default_branch_name()], cwd=s_dir) # to make sure we are not already on branch to be deleted
     run_git(['git', 'branch', '-D', branch_name], cwd=s_dir)    # delete branch
 
 def checkout_branch(targetBranch, s_dir, fetch_and_reset=False, temp_branch_name=None):
@@ -423,7 +459,7 @@ except IOError:
 
 app.logger.info('Initial fetch')
 # checkout to default branch, fetch remote, update submodules
-checkout_branch(default_branch, s_dir=sourcedir, fetch_and_reset=True)
+checkout_branch(get_default_branch_name(), s_dir=sourcedir, fetch_and_reset=True)
 update_submodules(s_dir=sourcedir)
 
 app.logger.info('Python version is: %s' % sys.version)
@@ -436,7 +472,7 @@ def generate():
             raise Exception("bad branch")
 
         chosen_vehicle = request.form['vehicle']
-        if not chosen_vehicle in VEHICLES:
+        if not is_valid_vehicle(chosen_vehicle):
             raise Exception("bad vehicle")
 
         chosen_board = request.form['board']
@@ -569,10 +605,8 @@ def parse_build_categories(build_options):
 def home():
     app.logger.info('Rendering index.html')
     return render_template('index.html',
-                           get_branches=get_branches,
-                           get_vehicles=get_vehicles,
-                           get_default_branch=get_default_branch,
-                           get_default_vehicle=get_default_vehicle)
+                           get_vehicle_names=get_vehicle_names,
+                           get_default_vehicle_name=get_default_vehicle_name)
 
 @app.route("/builds/<path:name>")
 def download_file(name):
@@ -619,5 +653,27 @@ def boards_and_features(remote, branch_name):
     # return jsonified result dict
     return jsonify(result)
 
+@app.route("/get_allowed_branches/<string:vehicle_name>", methods=['GET'])
+def get_allowed_branches(vehicle_name):
+    if not is_valid_vehicle(vehicle_name):
+        app.logger.error("Bad vehicle")
+        return ("Bad Vehicle", 400)
+
+    app.logger.info("Supported branches requested for %s" % vehicle_name)
+    branches = []
+    for branch in get_branches():
+        if vehicle_name in [vehicle.name for vehicle in branch['allowed_vehicles']]:
+            branches.append({
+                'full_name': branch['full_name'],
+                'label' : branch['label']
+            })
+
+    result = {
+        'branches' : branches,
+        'default_branch' : get_default_branch_name()
+    }
+    # return jsonified result dictionary
+    return jsonify(result)
+
 if __name__ == '__main__':
     app.run()

+ 59 - 16
templates/index.html

@@ -35,21 +35,18 @@
         <h2>ArduPilot Custom Firmware Builder</h2>
 
         <form action="/generate" method="post">
-            <label for="branch">Choose a branch:
-                <select name="branch" id="branch" onchange="requestBoardsAndFeatures(this.value);">
-                    {% for branch in get_branches() %}
-                    <option value="{{branch}}" {% if branch == get_default_branch() %} selected {% endif %}>{{get_branches()[branch]}}</option>
-                    {% endfor %}
-                </select>
-            </label>
+            <div id="vehicle_list">
+                <label for="vehicle">Choose a vehicle:
+                    <select name="vehicle" id="vehicle" onchange="requestBranches(this.value);">
+                        {% for vehicle in get_vehicle_names() %}
+                        <option value="{{vehicle}}" {% if vehicle == get_default_vehicle_name() %} selected {% endif %}>{{vehicle}}</option>
+                        {% endfor %}
+                    </select>
+                </label>
+            </div>
+            <p></p>
+            <div id="branch_list"></div>
             <p></p>
-            <label for="vehicle">Choose a vehicle:
-                <select name="vehicle" id="vehicle">
-                    {% for vehicle in get_vehicles() %}
-                    <option value="{{vehicle}}" {% if vehicle == get_default_vehicle() %} selected {% endif %}>{{vehicle}}</option>
-                    {% endfor %}
-                </select>
-            </label>
             <div id="board_list"></div>
             <p></p>
             <div id="build_options"></div>
@@ -64,7 +61,7 @@
     <script>
         function init() {
             refresh_builds();
-            requestBoardsAndFeatures(document.getElementById('branch').value);
+            requestBranches(document.getElementById("vehicle").value);
         }
 
         function refresh_builds() {
@@ -103,8 +100,11 @@
                     fillBoards(boards, default_board);
                     fillBuildOptions(features);
                     document.getElementById("submit").disabled = false;
-                    document.getElementById("branch").disabled = false;
+                } else {
+                    document.getElementById('board_list').innerHTML = "Something went wrong. Please try again. (Response says: "+xhr.response+")";
+                    document.getElementById('build_options').innerHTML = "";      
                 }
+                document.getElementById("branch").disabled = false;
             }
             xhr.send();
         }
@@ -173,6 +173,49 @@
                     break;
             }
         }
+
+        function requestBranches(vehicle) {
+            var xhr = new XMLHttpRequest();
+            xhr.open('GET', '/get_allowed_branches/'+vehicle);           
+            document.getElementById("submit").disabled = true;
+            document.getElementById("vehicle").disabled = true;
+
+            xhr.onload = function () {
+                if (xhr.status == 200) {
+                    response = JSON.parse(xhr.response);
+                    branches = response['branches'];
+                    default_branch = response['default_branch'];
+                    old_branch = document.getElementById("branch");
+                    fillBranches(branches);
+                    document.getElementById("submit").disabled = false;
+                    if (old_branch == null || old_branch.value != default_branch){
+                        // branch has changed
+                        // fetch boards and features again
+                        requestBoardsAndFeatures(default_branch);
+                    }
+                } else {
+                    document.getElementById('branch_list').innerHTML = "Something went wrong. Please try again. (Response says: "+xhr.response+")";
+                }
+                document.getElementById("vehicle").disabled = false;
+            }
+            xhr.send();
+        }
+
+        function fillBranches(branches) {
+            var output = document.getElementById('branch_list');
+            output.innerHTML =  "<label for='branch'>Choose a branch: "+
+                                    "<select name='branch' id='branch' onchange='requestBoardsAndFeatures(this.value);'>"+
+                                    "</select>"+
+                                "</label>";
+            branchList = document.getElementById("branch");
+            branches.forEach(branch => {
+                opt = document.createElement('option');
+                opt.value = branch['full_name'];
+                opt.innerHTML = branch['label'];
+                opt.selected = (branch['full_name'] === default_branch);
+                branchList.appendChild(opt);
+            });
+        }
     </script>
 </div>
 </body>