text: import os
  from os.path import sep, join, exists
  from itertools import groupby
  from xml.etree.ElementTree import Element, tostring
  import re
  import json
  
  from tools.arm_pack_manager import Cache
  from tools.targets import TARGET_MAP
  from tools.export.exporters import Exporter, TargetNotSupportedException
  from tools.utils import split_path
  
  class fileCMSIS():
      """CMSIS file class.
  
      Encapsulates information necessary for files in cpdsc project file"""
      file_types = {'.cpp': 'sourceCpp', '.c': 'sourceC', '.s': 'sourceAsm',
                    '.obj': 'object', '.o': 'object', '.lib': 'library',
                    '.ar': 'linkerScript', '.h': 'header', '.sct': 'linkerScript'}
  
      def __init__(self, loc, name):
          #print loc
          _, ext = os.path.splitext(loc)
          self.type = self.file_types[ext.lower()]
          self.loc = loc
          self.name = name
  
  
  class DeviceCMSIS():
      """CMSIS Device class
  
      Encapsulates target information retrieved by arm-pack-manager"""
  
      CACHE = Cache(True, False)
      def __init__(self, target):
          target_info = self.check_supported(target)
          if not target_info:
              raise TargetNotSupportedException("Target not supported in CMSIS pack")
          self.url = target_info['pdsc_file']
          self.pdsc_url, self.pdsc_id, _ = split_path(self.url)
          self.pack_url, self.pack_id, _ = split_path(target_info['pack_file'])
          self.dname = target_info["_cpu_name"]
          self.core = target_info["_core"]
          self.dfpu = target_info['processor']['fpu']
          self.debug, self.dvendor = self.vendor_debug(target_info['vendor'])
          self.dendian = target_info['processor'].get('endianness','Little-endian')
          self.debug_svd = target_info.get('debug', '')
          self.compile_header = target_info['compile']['header']
          self.target_info = target_info
  
      @staticmethod
      def check_supported(target):
          t = TARGET_MAP[target]
          try:
              cpu_name = t.device_name
              target_info = DeviceCMSIS.CACHE.index[cpu_name]
          # Target does not have device name or pdsc file
          except:
              try:
                  # Try to find the core as a generic CMSIS target
                  cpu_name = DeviceCMSIS.cpu_cmsis(t.core)
                  target_info = DeviceCMSIS.CACHE.index[cpu_name]
              except:
                  return False
          target_info["_cpu_name"] = cpu_name
          target_info["_core"] = t.core
          return target_info
  
      def vendor_debug(self, vendor):
          """Reads the vendor from a PDSC <dvendor> tag.
          This tag contains some additional numeric information that is meaningless
          for our purposes, so we use a regex to filter.
  
          Positional arguments:
          Vendor - information in <dvendor> tag scraped from ArmPackManager
  
          Returns a tuple of (debugger, vendor)
          """
          reg = "([\w\s]+):?\d*?"
          m = re.search(reg, vendor)
          vendor_match = m.group(1) if m else None
          debug_map ={
              'STMicroelectronics':'ST-Link',
              'Silicon Labs':'J-LINK',
              'Nuvoton':'NULink'
          }
          return debug_map.get(vendor_match, "CMSIS-DAP"), vendor_match
  
      @staticmethod
      def cpu_cmsis(cpu):
          """
          Transforms information from targets.json to the way the generic cores are named
          in CMSIS PDSC files.
          Ex:
          Cortex-M4F => ARMCM4_FP, Cortex-M0+ => ARMCM0P
          Returns formatted CPU
          """
          cpu = cpu.replace("Cortex-","ARMC")
          cpu = cpu.replace("+","P")
          cpu = cpu.replace("F","_FP")
          return cpu
  
  
  class CMSIS(Exporter):
      NAME = 'cmsis'
      TOOLCHAIN = 'ARM'
  
      @classmethod
      def is_target_supported(cls, target_name):
          target = TARGET_MAP[target_name]
          return cls.TOOLCHAIN in target.supported_toolchains
  
      def make_key(self, src):
          """turn a source file into its group name"""
          key = src.name.split(sep)[0]
          if key == ".":
              key = os.path.basename(os.path.realpath(self.export_dir))
          return key
  
      def group_project_files(self, sources, root_element):
          """Recursively group the source files by their encompassing directory"""
  
          data = sorted(sources, key=self.make_key)
          for group, files in groupby(data, self.make_key):
              new_srcs = []
              for f in list(files):
                  spl = f.name.split(sep)
                  if len(spl) <= 2:
                      file_element = Element('file',
                                             attrib={
                                                 'category':f.type,
                                                 'name': f.loc})
                      root_element.append(file_element)
                  else:
                      f.name = os.path.join(*spl[1:])
                      new_srcs.append(f)
              if new_srcs:
                  group_element = Element('group',attrib={'name':group})
                  root_element.append(self.group_project_files(new_srcs,
                                                          group_element))
          return root_element
  
      def generate(self):
          srcs = self.resources.headers + self.resources.s_sources + \
                 self.resources.c_sources + self.resources.cpp_sources + \
                 self.resources.objects + self.libraries + \
                 [self.resources.linker_script]
          srcs = [fileCMSIS(src, src) for src in srcs if src]
          ctx = {
              'name': self.project_name,
              'project_files': tostring(self.group_project_files(srcs, Element('files'))),
              'device': DeviceCMSIS(self.target),
              'date': ''
          }
          self.gen_file('cmsis/cpdsc.tmpl', ctx, 'project.cpdsc')
  
  
      @staticmethod
      def clean(_):
          os.remove('project.cpdsc')
  