tor-browser

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

client.py (5718B)


      1 #!/usr/bin/python
      2 # This Source Code Form is subject to the terms of the Mozilla Public
      3 # License, v. 2.0. If a copy of the MPL was not distributed with this
      4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      5 
      6 HG_EXCLUSIONS = [".hg", ".hgignore", ".hgtags"]
      7 
      8 import glob
      9 import os
     10 import shutil
     11 import sys
     12 from optparse import OptionParser
     13 from subprocess import check_call
     14 
     15 topsrcdir = os.path.dirname(__file__)
     16 if topsrcdir == "":
     17    topsrcdir = "."
     18 
     19 
     20 def check_call_noisy(cmd, *args, **kwargs):
     21    print("Executing command:", cmd)
     22    check_call(cmd, *args, **kwargs)
     23 
     24 
     25 def do_hg_pull(dir, repository, hg):
     26    fulldir = os.path.join(topsrcdir, dir)
     27    # clone if the dir doesn't exist, pull if it does
     28    if not os.path.exists(fulldir):
     29        check_call_noisy([hg, "clone", repository, fulldir])
     30    else:
     31        cmd = [hg, "pull", "-u", "-R", fulldir]
     32        if repository is not None:
     33            cmd.append(repository)
     34        check_call_noisy(cmd)
     35    check_call([
     36        hg,
     37        "parent",
     38        "-R",
     39        fulldir,
     40        "--template=Updated to revision {node}.\n",
     41    ])
     42 
     43 
     44 def do_hg_replace(dir, repository, tag, exclusions, hg):
     45    """
     46    Replace the contents of dir with the contents of repository, except for
     47    files matching exclusions.
     48    """
     49    fulldir = os.path.join(topsrcdir, dir)
     50    if os.path.exists(fulldir):
     51        shutil.rmtree(fulldir)
     52 
     53    assert not os.path.exists(fulldir)
     54    check_call_noisy([hg, "clone", "-u", tag, repository, fulldir])
     55 
     56    for thing in exclusions:
     57        for excluded in glob.iglob(os.path.join(fulldir, thing)):
     58            if os.path.isdir(excluded):
     59                shutil.rmtree(excluded)
     60            else:
     61                os.remove(excluded)
     62 
     63 
     64 def toggle_trailing_blank_line(depname):
     65    """If the trailing line is empty, then we'll delete it.
     66    Otherwise we'll add a blank line."""
     67    lines = open(depname, "rb").readlines()
     68    if not lines:
     69        print("unexpected short file", file=sys.stderr)
     70        return
     71 
     72    if not lines[-1].strip():
     73        # trailing line is blank, removing it
     74        open(depname, "wb").writelines(lines[:-1])
     75    else:
     76        # adding blank line
     77        open(depname, "ab").write(b"\n")
     78 
     79 
     80 def get_trailing_blank_line_state(depname):
     81    lines = open(depname).readlines()
     82    if not lines:
     83        print("unexpected short file", file=sys.stderr)
     84        return "no blank line"
     85 
     86    if not lines[-1].strip():
     87        return "has blank line"
     88    return "no blank line"
     89 
     90 
     91 def update_nspr_or_nss(tag, depfile, destination, hgpath):
     92    destination = destination.rstrip("/")
     93    permanent_patch_dir = destination + "/patches"
     94    temporary_patch_dir = destination + ".patches"
     95    if os.path.exists(temporary_patch_dir):
     96        print("please clean up leftover directory " + temporary_patch_dir)
     97        sys.exit(2)
     98    warn_if_patch_exists(permanent_patch_dir)
     99    # protect patch directory from being removed by do_hg_replace
    100    if os.path.exists(permanent_patch_dir):
    101        shutil.move(permanent_patch_dir, temporary_patch_dir)
    102    # now update the destination
    103    print("reverting to HG version of %s to get its blank line state" % depfile)
    104    check_call_noisy([options.hg, "revert", depfile])
    105    old_state = get_trailing_blank_line_state(depfile)
    106    print("old state of %s is: %s" % (depfile, old_state))
    107    do_hg_replace(destination, hgpath, tag, HG_EXCLUSIONS, options.hg)
    108    new_state = get_trailing_blank_line_state(depfile)
    109    print("new state of %s is: %s" % (depfile, new_state))
    110    if old_state == new_state:
    111        print("toggling blank line in: ", depfile)
    112        toggle_trailing_blank_line(depfile)
    113    tag_file = destination + "/TAG-INFO"
    114    with open(tag_file, "w") as f:
    115        f.write(tag)
    116    # move patch directory back to a subdirectory
    117    if os.path.exists(temporary_patch_dir):
    118        shutil.move(temporary_patch_dir, permanent_patch_dir)
    119 
    120 
    121 def warn_if_patch_exists(path):
    122    # If the given patch directory exists and contains at least one file,
    123    # then print warning and wait for the user to acknowledge.
    124    if os.path.isdir(path) and os.listdir(path):
    125        print("========================================")
    126        print("WARNING: At least one patch file exists")
    127        print("in directory: " + path)
    128        print("You must manually re-apply all patches")
    129        print("after this script has completed!")
    130        print("========================================")
    131        input("Press Enter to continue...")
    132        return
    133 
    134 
    135 o = OptionParser(usage="client.py [options] update_nspr tagname | update_nss tagname")
    136 o.add_option(
    137    "--skip-mozilla",
    138    dest="skip_mozilla",
    139    action="store_true",
    140    default=False,
    141    help="Obsolete",
    142 )
    143 
    144 o.add_option(
    145    "--hg",
    146    dest="hg",
    147    default=os.environ.get("HG", "hg"),
    148    help="The location of the hg binary",
    149 )
    150 o.add_option(
    151    "--repo", dest="repo", help="the repo to update from (default: upstream repo)"
    152 )
    153 
    154 try:
    155    options, args = o.parse_args()
    156    action = args[0]
    157 except IndexError:
    158    o.print_help()
    159    sys.exit(2)
    160 
    161 if action in ("checkout", "co"):
    162    print("Warning: client.py checkout is obsolete.", file=sys.stderr)
    163    pass
    164 elif action in ("update_nspr"):
    165    (tag,) = args[1:]
    166    depfile = "nsprpub/config/prdepend.h"
    167    if not options.repo:
    168        options.repo = "https://hg.mozilla.org/projects/nspr"
    169    update_nspr_or_nss(tag, depfile, "nsprpub", options.repo)
    170 elif action in ("update_nss"):
    171    (tag,) = args[1:]
    172    depfile = "security/nss/coreconf/coreconf.dep"
    173    if not options.repo:
    174        options.repo = "https://hg.mozilla.org/projects/nss"
    175    update_nspr_or_nss(tag, depfile, "security/nss", options.repo)
    176 else:
    177    o.print_help()
    178    sys.exit(2)