Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers remove-device-h.py Source File

remove-device-h.py

00001 import json
00002 import os
00003 import stat
00004 import re
00005 from collections import OrderedDict
00006 from subprocess import Popen
00007 
00008 git_processes = []
00009 
00010 class MyJSONEncoder(json.JSONEncoder):
00011     def __init__(self, *args, **kwargs):
00012         super(MyJSONEncoder, self).__init__(*args, **kwargs)
00013         self.current_indent = 0
00014         self.current_indent_str = ""
00015 
00016 
00017     def encode(self, o):
00018         #Special Processing for lists
00019         if isinstance(o, (list, tuple)):
00020             primitives_only = True
00021             for item in o:
00022                 if isinstance(item, (list, tuple, dict)):
00023                     primitives_only = False
00024                     break
00025             output = []
00026             if primitives_only:
00027                 for item in o:
00028                     output.append(json.dumps(item))
00029                 return "[" + ", ".join(output) + "]"
00030             else:
00031                 self.current_indent += self.indent
00032                 self.current_indent_str = " " * self.current_indent
00033                 for item in o:
00034                     output.append(self.current_indent_str + self.encode(item))
00035                 self.current_indent -= self.indent
00036                 self.current_indent_str = " " * self.current_indent
00037                 return "[\n" + ",\n".join(output) + "\n" + self.current_indent_str + "]"
00038         elif isinstance(o, dict):
00039             primitives_only = True
00040             for item in o.values():
00041                 if isinstance(item, (list, tuple, dict)):
00042                     primitives_only = False
00043                     break
00044             output = []
00045             if primitives_only and len(o) < 3:
00046                 for key, value in o.items():
00047                     output.append(json.dumps(key) + ": " + self.encode(value))
00048                 return "{" + ", ".join(output) + "}"
00049             else:
00050                 self.current_indent += self.indent
00051                 self.current_indent_str = " " * self.current_indent
00052                 for key, value in o.items():
00053                     output.append(self.current_indent_str + json.dumps(key) + ": " + self.encode(value))
00054                 self.current_indent -= self.indent
00055                 self.current_indent_str = " " * self.current_indent
00056                 return "{\n" + ",\n".join(output) + "\n" + self.current_indent_str + "}"
00057         else:
00058             return json.dumps(o)
00059 
00060 def load(path):
00061     with open(path, 'r') as f :
00062         return json.load(f, object_pairs_hook=OrderedDict)
00063 
00064 def dump(path, obj):
00065     with os.fdopen(os.open(path, os.O_WRONLY | os.O_CREAT, stat.S_IRUSR | stat.S_IWUSR), 'w') as f :
00066         os.chmod(path, stat.S_IRUSR | stat.S_IWUSR)
00067         f.write(MyJSONEncoder(indent=4).encode(obj))
00068         f.write(u'\n')
00069         f.truncate()
00070 
00071 def find(stem, path) :
00072     for root, directories, files in os.walk(path, followlinks=True) :
00073         [dir for dir in directories if dir[0] != '.']
00074         if (stem_match(stem,os.path.basename(os.path.normpath(root))) and
00075             "device.h" in files) :
00076             return os.path.join(root, "device.h")
00077 
00078 def find_all_devices(path, verbose=False) :
00079     for root, directories, files in os.walk(path, followlinks=True) :
00080         [dir for dir in directories if dir[0] != '.']
00081         if "device.h" in files :
00082             if verbose : print("[VERBOSE] found a device.h file in {}".format(root))
00083             yield os.path.join(root, "device.h")
00084 
00085 mbed_matcher = re.compile('mbed', re.IGNORECASE)
00086 def stem_match(stem, thing) :
00087     return (stem in thing or
00088             re.sub(mbed_matcher, '', stem) in thing)
00089 
00090 attr_matcher = re.compile('^#define\W+DEVICE_(\w+)\W+1.*$')
00091 def parse_attributes(path) :
00092     with open(path) as input :
00093         for line in input :
00094             m = re.match(attr_matcher, line)
00095             if m: yield m.group(1)
00096 
00097 remove_matcher = re.compile('^#define\W+DEVICE_(\w+)\W+[10].*$')
00098 def remove_attributes(path) :
00099     with open(path) as input :
00100         remainder = filter(lambda l: not re.match(remove_matcher, l), input)
00101     with open(path,"wb") as output :
00102         output.truncate(0)
00103         output.write("// The 'provides' section in 'target.json' is now used"+
00104                      " to create the device's hardware preprocessor switches.\n")
00105         output.write("// Check the 'provides' section of the target description"+
00106                      " in 'targets.json' for more details.\n")
00107         output.writelines(remainder)
00108 
00109 def user_select(things, message) :
00110     print(message)
00111     for thing, number in zip(things, range(len(things))):
00112         print("{} : {}".format(number, thing))
00113     selection = None
00114     while selection is None :
00115         print("please select an integer [0..{}] or specify all".format(len(things) - 1))
00116         try :
00117             i = raw_input()
00118             if i == "all" :
00119                 selection = "all"
00120             else :
00121                 selection = int(i)
00122                 if (selection > len(things) or
00123                     selection < 0) :
00124                     print("selection {} out of range".format(selection))
00125                     selection = None
00126         except (ValueError, SyntaxError) :
00127             print("selection not understood")
00128     if selection == "all" :
00129         return things
00130     else :
00131         return [things[selection]]
00132 
00133 target_matcher = re.compile("TARGET_")
00134 def strip_target(str) :
00135     return re.sub(target_matcher, "", str)
00136 
00137 def add_to_targets(targets, device_file, verbose=False, remove=False) :
00138     if verbose : print("[VERBOSE] trying target {}".format(device_file))
00139     device = strip_target(os.path.basename(os.path.normpath(os.path.dirname(device_file))))
00140     if not device :
00141         print("[WARNING] device {} did not have an associated device.h".format(device))
00142     else :
00143         possible_matches = set([key for key in targets.keys() if stem_match(device, key)])
00144         for key, value in targets.items() :
00145             for alt in value['extra_labels'] if 'extra_labels' in value else [] :
00146                 if stem_match(device, alt) : possible_matches.add(key)
00147             for alt in value['extra_labels_add'] if 'extra_labels_add' in value else [] :
00148                 if stem_match(device, alt) : possible_matches.add(key)
00149         possible_matches = list(possible_matches)
00150         for match in possible_matches :
00151             if device == match : possible_matches = [match]
00152         if not possible_matches :
00153             print("[WARNING] device {} did not have an associated entry in targets.json".format(device))
00154             return None
00155         elif len(possible_matches) > 1 :
00156             message = ("possible matches for file {}".format(device_file))
00157             target = user_select(possible_matches, message)
00158         else :
00159             target = possible_matches
00160         attrs = list(parse_attributes(device_file))
00161         if attrs :
00162             for t in target :
00163                 targets[t]["device_has"] = sorted(list(set(targets[t].setdefault("device_has",[]) + attrs)))
00164                 if verbose : print("[VERBOSE] target {} now device_has {}".format(t, attrs))
00165             if remove is True:
00166                 remove_attributes(device_file)
00167 
00168 if __name__ == '__main__' :
00169     import argparse
00170     parser = argparse.ArgumentParser(description='A helpful little script for converting' +
00171                                      ' device.h files to parts of the targets.json file')
00172     parser.add_argument('-a', '--all', action='store_true',
00173                         help='find and convert all available device.h files in the'+
00174                         ' directory tree starting at the current directory')
00175     parser.add_argument('-f', '--file', nargs='+', help='specify an individual file to '+
00176                         'convert from device.h format to a piece of targets.json')
00177     parser.add_argument('-t', '--target', nargs='+', help='specify an individual target'+
00178                         ' to convert from device.h format to a piece of targets.json')
00179     parser.add_argument('-v', '--verbose', action='store_true',
00180                         help="print out every target that is updated in the targets.json")
00181     parser.add_argument('-r', '--rm', action='store_true',
00182                         help="remove the used attributes from a device.h file")
00183     args = parser.parse_args()
00184     if not args.target and not args.file and not args.all :
00185         print("[WARNING] no action specified; auto-formatting targets.json")
00186 
00187     targets_file_name = os.path.join(os.curdir, "hal", "targets.json")
00188     try :
00189         targets = load(targets_file_name)
00190     except OSError :
00191         print("[ERROR] did not find targets.json where I expected it {}".format(targets_file_name))
00192         exit(1)
00193     except ValueError :
00194         print("[ERROR] invalid json found in {}".format(targets_file_name))
00195         exit(2)
00196 
00197     if args.target :
00198         for target in args.target :
00199             device_file = find(target, os.curdir)
00200             if device_file :
00201                 add_to_targets(targets, device_file, verbose=args.verbose, remove=args.rm)
00202             else :
00203                 print("[WARNING] could not locate a device file for target {}".format(target))
00204 
00205     if args.file :
00206         for file in args.file :
00207             add_to_targets(targets, file, verbose=args.verbose, remove=args.rm)
00208 
00209     if args.all :
00210         for file in find_all_devices(os.curdir, verbose=args.verbose) :
00211             add_to_targets(targets, file, verbose=args.verbose, remove=args.rm)
00212 
00213     dump(targets_file_name, targets)
00214 
00215     for process in git_processes :
00216         process.wait()