tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

lookup_branch_head.py (4453B)


      1 # This Source Code Form is subject to the terms of the Mozilla Public
      2 # License, v. 2.0. If a copy of the MPL was not distributed with this
      3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      4 import argparse
      5 import json
      6 import os
      7 import pathlib
      8 import sys
      9 import urllib.request
     10 
     11 # default cache file location in STATE_DIR location
     12 default_cache_path = ".moz-fast-forward/milestone.cache"
     13 
     14 
     15 def fetch_branch_head_dict():
     16    # The milestone dictionary was found by opening the Mozilla dev
     17    # tools network tab and loading page
     18    # https://chromiumdash.appspot.com/branches
     19    milestone_url = (
     20        "https://chromiumdash.appspot.com/fetch_milestones?only_branched=true"
     21    )
     22    uf = urllib.request.urlopen(milestone_url)
     23    html = uf.read()
     24    milestone_dict = json.loads(html)
     25 
     26    # There is more information in the json dictionary, but we only care
     27    # about the milestone (version) to branch "name" (webrtc_branch)
     28    # info.  For example:
     29    #  v106 -> 5249 (which translates to branch-heads/5249)
     30    #  v107 -> 5304 (which translates to branch-heads/5304)
     31    #
     32    # As returned from web query, milestones are integers and branch
     33    # "names" are strings.
     34    new_dict = {}
     35    for row in milestone_dict:
     36        new_dict[row["milestone"]] = row["webrtc_branch"]
     37 
     38    return new_dict
     39 
     40 
     41 def fetch_branch_schedule_dict():
     42    # The milestone schedule dictionary was found by opening the Mozilla
     43    # dev tools network tab and loading page
     44    # https://chromiumdash.appspot.com/schedule
     45    milestone_schedule_url = (
     46        "https://chromiumdash.appspot.com/fetch_milestone_schedule?offset=-1&n=4"
     47    )
     48    uf = urllib.request.urlopen(milestone_schedule_url)
     49    html = uf.read()
     50    schedule_dict = json.loads(html)
     51 
     52    # There is more information in the json dictionary, but we only care
     53    # about the mstone (version) to branch_point date info.  For example:
     54    # v138 -> 2025-05-26T00:00:00
     55    # v139 -> 2025-06-23T00:00:00
     56    # v140 -> 2025-08-04T00:00:00
     57    #
     58    # As returned from web query, milestones are integers and branch_point
     59    # dates are strings.
     60    new_dict = {}
     61    for row in schedule_dict["mstones"]:
     62        new_dict[row["mstone"]] = row["branch_point"]
     63 
     64    return new_dict
     65 
     66 
     67 def get_branch_date(milestone):
     68    milestone_dates = {}
     69    try:
     70        milestone_dates = fetch_branch_schedule_dict()
     71    except Exception:
     72        pass
     73 
     74    if milestone in milestone_dates:
     75        return milestone_dates[milestone]
     76    return None
     77 
     78 
     79 def read_dict_from_cache(cache_path):
     80    if cache_path is not None and os.path.exists(cache_path):
     81        with open(cache_path) as ifile:
     82            return json.loads(ifile.read(), object_hook=jsonKeys2int)
     83    return {}
     84 
     85 
     86 def write_dict_to_cache(cache_path, milestones):
     87    with open(cache_path, "w") as ofile:
     88        ofile.write(json.dumps(milestones))
     89 
     90 
     91 def get_branch_head(milestone, cache_path=default_cache_path):
     92    milestones = read_dict_from_cache(cache_path)
     93 
     94    # if the cache didn't exist or is stale, try to fetch using a web query
     95    if milestone not in milestones:
     96        try:
     97            milestones = fetch_branch_head_dict()
     98            write_dict_to_cache(cache_path, milestones)
     99        except Exception:
    100            pass
    101 
    102    if milestone in milestones:
    103        return milestones[milestone]
    104    return None
    105 
    106 
    107 # From https://stackoverflow.com/questions/1450957/pythons-json-module-converts-int-dictionary-keys-to-strings
    108 def jsonKeys2int(x):
    109    if isinstance(x, dict):
    110        return {int(k): v for k, v in x.items()}
    111    return x
    112 
    113 
    114 if __name__ == "__main__":
    115    parser = argparse.ArgumentParser(
    116        description="Get libwebrtc branch-head for given chromium milestone"
    117    )
    118    parser.add_argument(
    119        "milestone", type=int, help="integer chromium milestone (example: 106)"
    120    )
    121    parser.add_argument("-v", "--verbose", action="store_true")
    122    parser.add_argument("-c", "--cache", type=pathlib.Path, help="path to cache file")
    123    args = parser.parse_args()
    124 
    125    # if the user provided a cache path use it, otherwise use the default
    126    local_cache_path = args.cache or default_cache_path
    127 
    128    branch_head = get_branch_head(args.milestone, local_cache_path)
    129    if branch_head is None:
    130        sys.exit(f"error: chromium milestone '{args.milestone}' is not found.")
    131 
    132    if args.verbose:
    133        print(f"chromium milestone {args.milestone} uses branch-heads/{branch_head}")
    134    else:
    135        print(branch_head)