11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project# common python utility routines for the Bionic tool scripts
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport sys, os, commands, string, commands
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project# basic debugging trace support
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project# call D_setlevel to set the verbosity level
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project# and D(), D2(), D3(), D4() to add traces
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectverbose = 0
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef panic(msg):
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sys.stderr.write( find_program_name() + ": error: " )
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sys.stderr.write( msg )
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sys.exit(1)
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef D(msg):
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    global verbose
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if verbose > 0:
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        print msg
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef D2(msg):
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    global verbose
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if verbose >= 2:
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        print msg
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef D3(msg):
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    global verbose
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if verbose >= 3:
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        print msg
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef D4(msg):
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    global verbose
331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if verbose >= 4:
341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        print msg
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef D_setlevel(level):
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    global verbose
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    verbose = level
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#  other stuff
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#
431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#
441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef find_program_name():
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return os.path.basename(sys.argv[0])
461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef find_program_dir():
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return os.path.dirname(sys.argv[0])
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef find_file_from_upwards(from_path,target_file):
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    """find a file in the current directory or its parents. if 'from_path' is None,
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       seach from the current program's directory"""
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    path = from_path
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if path == None:
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        path = os.path.realpath(sys.argv[0])
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        path = os.path.dirname(path)
571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        D("this script seems to be located in: %s" % path)
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while 1:
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        D("probing "+path)
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if path == "":
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            file = target_file
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            file = path + "/" + target_file
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if os.path.isfile(file):
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D("found %s in %s" % (target_file, path))
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return file
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if path == "":
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return None
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        path = os.path.dirname(path)
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef find_bionic_root():
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    file = find_file_from_upwards(None, "SYSCALLS.TXT")
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if file:
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return os.path.dirname(file)
791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    else:
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return None
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef find_kernel_headers():
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    """try to find the directory containing the kernel headers for this machine"""
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    status, version = commands.getstatusoutput( "uname -r" )  # get Linux kernel version
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if status != 0:
861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        D("could not execute 'uname -r' command properly")
871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return None
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    # get rid of the "-xenU" suffix that is found in Xen virtual machines
901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if len(version) > 5 and version[-5:] == "-xenU":
911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        version = version[:-5]
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    path = "/usr/src/linux-headers-" + version
941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    D("probing %s for kernel headers" % (path+"/include"))
951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ret = os.path.isdir( path )
961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ret:
971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        D("found kernel headers in: %s" % (path + "/include"))
981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return path
991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return None
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project# parser for the SYSCALLS.TXT file
1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#
1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectclass SysCallsTxtParser:
1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __init__(self):
1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.syscalls = []
1071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.lineno   = 0
1081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def E(msg):
1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        print "%d: %s" % (self.lineno, msg)
1111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def parse_line(self, line):
1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        pos_lparen = line.find('(')
1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        E          = self.E
1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if pos_lparen < 0:
1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            E("missing left parenthesis in '%s'" % line)
1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return
1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        pos_rparen = line.rfind(')')
1201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if pos_rparen < 0 or pos_rparen <= pos_lparen:
1211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            E("missing or misplaced right parenthesis in '%s'" % line)
1221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return
1231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return_type = line[:pos_lparen].strip().split()
1251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if len(return_type) < 2:
1261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            E("missing return type in '%s'" % line)
1271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return
1281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        syscall_func = return_type[-1]
1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return_type  = string.join(return_type[:-1],' ')
1311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        pos_colon = syscall_func.find(':')
1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if pos_colon < 0:
1341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            syscall_name = syscall_func
1351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
1361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if pos_colon == 0 or pos_colon+1 >= len(syscall_func):
1371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                E("misplaced colon in '%s'" % line)
1381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return
1391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            syscall_name = syscall_func[pos_colon+1:]
1401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            syscall_func = syscall_func[:pos_colon]
1411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if pos_rparen > pos_lparen+1:
1431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            syscall_params = line[pos_lparen+1:pos_rparen].split(',')
1441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            params         = string.join(syscall_params,',')
1451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
1461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            syscall_params = []
1471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            params         = "void"
1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        number = line[pos_rparen+1:].strip()
1501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if number == "stub":
1511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            syscall_id  = -1
1521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            syscall_id2 = -1
1531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
1541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            try:
1551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if number[0] == '#':
1561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    number = number[1:].strip()
1571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                numbers = string.split(number,',')
1581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                syscall_id  = int(numbers[0])
1591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                syscall_id2 = syscall_id
1601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if len(numbers) > 1:
1611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    syscall_id2 = int(numbers[1])
1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            except:
1631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                E("invalid syscall number in '%s'" % line)
1641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return
1651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        t = { "id"     : syscall_id,
1671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "id2"    : syscall_id2,
1681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "name"   : syscall_name,
1691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "func"   : syscall_func,
1701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "params" : syscall_params,
1711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "decl"   : "%-15s  %s (%s);" % (return_type, syscall_func, params) }
1721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.syscalls.append(t)
1741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def parse_file(self, file_path):
1761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        fp = open(file_path)
1771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for line in fp.xreadlines():
1781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            self.lineno += 1
1791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            line = line.strip()
1801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if not line: continue
1811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if line[0] == '#': continue
1821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            self.parse_line(line)
1831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        fp.close()
1851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectclass Output:
1881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def  __init__(self,out=sys.stdout):
1891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.out = out
1901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def write(self,msg):
1921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.out.write(msg)
1931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def writeln(self,msg):
1951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.out.write(msg)
1961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.out.write("\n")
1971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectclass StringOutput:
1991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __init__(self):
2001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.line = ""
2011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def write(self,msg):
2031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.line += msg
2041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        D2("write '%s'" % msg)
2051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def writeln(self,msg):
2071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.line += msg + '\n'
2081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        D2("write '%s\\n'"% msg)
2091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def get(self):
2111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return self.line
2121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef create_file_path(path):
2151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    dirs = []
2161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while 1:
2171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        parent = os.path.dirname(path)
2181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        #print "parent: %s <- %s" % (parent, path)
2191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if parent == "/" or parent == "":
2201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break
2211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dirs.append(parent)
2221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        path = parent
2231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    dirs.reverse()
2251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for dir in dirs:
2261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        #print "dir %s" % dir
2271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if os.path.isdir(dir):
2281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue
2291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        os.mkdir(dir)
2301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef walk_source_files(paths,callback,args,excludes=[]):
2321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    """recursively walk a list of paths and files, only keeping the source files in directories"""
2331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for path in paths:
234fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        if len(path) > 0 and path[0] == '@':
235fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner            # this is the name of another file, include it and parse it
236fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner            path = path[1:]
237fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner            if os.path.exists(path):
238fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                for line in open(path):
239fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    if len(line) > 0 and line[-1] == '\n':
240fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        line = line[:-1]
241fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    walk_source_files([line],callback,args,excludes)
242fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner            continue
2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if not os.path.isdir(path):
2441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            callback(path,args)
2451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
2461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            for root, dirs, files in os.walk(path):
2471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                #print "w-- %s (ex: %s)" % (repr((root,dirs)), repr(excludes))
2481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if len(excludes):
2491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    for d in dirs[:]:
250fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        if os.path.join(root,d) in excludes:
2511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                            dirs.remove(d)
2521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                for f in files:
2531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    r, ext = os.path.splitext(f)
2541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if ext in [ ".h", ".c", ".cpp", ".S" ]:
2551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                        callback( "%s/%s" % (root,f), args )
2561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef cleanup_dir(path):
2581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    """create a directory if needed, and ensure that it is totally empty
2591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       by removing any existing content in it"""
2601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if not os.path.exists(path):
2611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        os.mkdir(path)
2621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    else:
2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for root, dirs, files in os.walk(path, topdown=False):
2641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if root.endswith("kernel_headers/"):
2651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                # skip 'kernel_headers'
2661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                continue
2671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            for name in files:
2681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                os.remove(os.path.join(root, name))
2691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            for name in dirs:
2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                os.rmdir(os.path.join(root, name))
2711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef update_file( path, newdata ):
2731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    """update a file on disk, only if its content has changed"""
2741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if os.path.exists( path ):
2751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        try:
2761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            f = open( path, "r" )
2771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            olddata = f.read()
2781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            f.close()
2791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        except:
2801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D("update_file: cannot read existing file '%s'" % path)
2811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return 0
2821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if oldata == newdata:
2841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D2("update_file: no change to file '%s'" % path )
2851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return 0
2861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        update = 1
2881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    else:
2891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        try:
2901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            create_file_path(path)
2911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        except:
2921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D("update_file: cannot create path to '%s'" % path)
2931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return 0
2941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    f = open( path, "w" )
2961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    f.write( newdata )
2971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    f.close()
2981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 1
3001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectclass BatchFileUpdater:
3031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    """a class used to edit several files at once"""
3041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __init__(self):
3051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.old_files = set()
3061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.new_files = set()
3071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.new_data  = {}
3081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def readFile(self,path):
3101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        #path = os.path.realpath(path)
3111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if os.path.exists(path):
3121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            self.old_files.add(path)
3131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def readDir(self,path):
3151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        #path = os.path.realpath(path)
3161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for root, dirs, files in os.walk(path):
3171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            for f in files:
3181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                dst = "%s/%s" % (root,f)
3191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                self.old_files.add(dst)
3201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def editFile(self,dst,data):
3221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        """edit a destination file. if the file is not mapped from a source,
3231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           it will be added. return 0 if the file content wasn't changed,
3241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           1 if it was edited, or 2 if the file is new"""
3251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        #dst = os.path.realpath(dst)
3261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        result = 1
3271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if os.path.exists(dst):
3281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            f = open(dst, "r")
3291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            olddata = f.read()
3301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            f.close()
3311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if olddata == data:
3321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                self.old_files.remove(dst)
3331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return 0
3341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
3351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            result = 2
3361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.new_data[dst] = data
3381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.new_files.add(dst)
3391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return result
3401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def getChanges(self):
3421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        """determine changes, returns (adds, deletes, edits)"""
3431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        adds    = set()
3441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        edits   = set()
3451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        deletes = set()
3461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for dst in self.new_files:
3481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if not (dst in self.old_files):
3491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                adds.add(dst)
3501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            else:
3511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                edits.add(dst)
3521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for dst in self.old_files:
3541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if not dst in self.new_files:
3551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                deletes.add(dst)
3561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (adds, deletes, edits)
3581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def _writeFile(self,dst,data=None):
3601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if not os.path.exists(os.path.dirname(dst)):
3611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            create_file_path(dst)
3621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if data == None:
3631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            data = self.new_data[dst]
3641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        f = open(dst, "w")
3651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        f.write(self.new_data[dst])
3661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        f.close()
3671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def updateFiles(self):
3691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        adds, deletes, edits = self.getChanges()
3701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for dst in sorted(adds):
3721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            self._writeFile(dst)
3731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for dst in sorted(edits):
3751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            self._writeFile(dst)
3761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for dst in sorted(deletes):
3781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            os.remove(dst)
3791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def updateP4Files(self):
3811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        adds, deletes, edits = self.getChanges()
3821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if len(adds):
3841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            files = string.join(sorted(adds)," ")
3851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D( "%d new files will be p4 add-ed" % len(adds) )
3861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            for dst in adds:
3871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                self._writeFile(dst)
3881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D2("P4 ADDS: %s" % files)
3891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            o = commands.getoutput( "p4 add " + files )
3901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D2( o )
3911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if len(edits):
3931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            files = string.join(sorted(edits)," ")
3941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D( "%d files will be p4 edit-ed" % len(edits) )
3951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D2("P4 EDITS: %s" % files)
3961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            o = commands.getoutput( "p4 edit " + files )
3971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D2( o )
3981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            for dst in edits:
3991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                self._writeFile(dst)
4001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if len(deletes):
4021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            files = string.join(sorted(deletes)," ")
4031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D( "%d files will be p4 delete-d" % len(deletes) )
4041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D2("P4 DELETES: %s" % files)
4051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            o = commands.getoutput( "p4 delete " + files )
4061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            D2( o )
407fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
408fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner    def updateGitFiles(self):
409fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        adds, deletes, edits = self.getChanges()
410fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
411fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        if adds:
412fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner            for dst in sorted(adds):
413fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                self._writeFile(dst)
414fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner            commands.getoutput("git add " + " ".join(adds))
415fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
416fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        if deletes:
417fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner            commands.getoutput("git rm " + " ".join(deletes))
418fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
419fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        if edits:
420fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner            for dst in sorted(edits):
421fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                self._writeFile(dst)
422fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner            commands.getoutput("git add " + " ".join(edits))
423