From 7d63e57fdaa5e54684fa366dd9d6e9149100f569 Mon Sep 17 00:00:00 2001 From: Pawel Szostek <pawel.szostek@gmail.com> Date: Thu, 19 May 2011 18:11:41 +0200 Subject: [PATCH] Fixed recursive fetching. --- synthesis/configparser.py | 55 +++++++---- synthesis/fetch.py | 181 +++++++++++++++++++++++++++++------- synthesis/helper_classes.py | 6 +- synthesis/module.py | 52 ++--------- synthesis/srcfile.py | 3 + 5 files changed, 196 insertions(+), 101 deletions(-) diff --git a/synthesis/configparser.py b/synthesis/configparser.py index 4c094022..dd426a08 100644 --- a/synthesis/configparser.py +++ b/synthesis/configparser.py @@ -124,44 +124,62 @@ class ConfigParser(object): if not isinstance(description, basestring): raise ValueError("Description should be a string!") self.description = description - self.options = {} + self.options = [] self.arbitrary_code = "" + def __setitem__(self, name, value): + if name in self.__names(): + filter(lambda x: x.name == name, self.options)[0] = value + else: + self.options.append(value) + + def __getitem__(self, name): + if name in self.__names(): + return filter(lambda x: x != None and x.name == name, self.options)[0] + else: + raise RuntimeException("No such option as " + str(name)) + def help(self): p.rawprint("Variables available in a manifest:") - for key in self.options: - opt = self.options[key] - line = ' {0:10}; {1:15}; {2:40}{3}{4:10}' + for opt in self.options: + if opt == None: + p.rawprint("") + continue + + line = ' {0:15}; {1:29}; {2:45}{3}{4:10}' try: tmp_def = opt.default if tmp_def == "": tmp_def = '""' - line = line.format(key, str(opt.types), opt.help,', default=', tmp_def) + line = line.format(opt.name, str(opt.types), opt.help,', default=', tmp_def) except AttributeError: #no default value line = line.format(key, str(opt.types), opt.help, "","") p.rawprint(line) def add_option(self, name, **others): - if name in self.options: + if name in self.__names(): raise ValueError("Option already added: " + name) - self.options[name] = ConfigParser.Option(name, **others) + self.options.append(ConfigParser.Option(name, **others)) def add_type(self, name, type): - if name not in self.options: + if name not in self.__names(): raise RuntimeError("Can't add type to a non-existing option") - self.options[name].add_type(type_obj=type) + self[name].add_type(type) + + def add_delimiter(self): + self.options.append(None) def add_allowed_key(self, name, key): if not isinstance(key, basestring): raise ValueError("Allowed key must be a string") try: - self.options[name].allowed_keys.append(key) + self[name].allowed_keys.append(key) except AttributeError: - if type(dict()) not in self.options[name].types: + if type(dict()) not in self[name].types: raise RuntimeError("Allowing a key makes sense for dictionaries only") - self.options[name].allowed_keys = [key] + self[name].allowed_keys = [key] - self.options[name].allowed_keys.append(key) + self[name].allowed_keys.append(key) def add_config_file(self, config_file): try: @@ -178,6 +196,9 @@ class ConfigParser(object): def add_arbitrary_code(self, code): self.arbitrary_code += code + '\n' + def __names(self): + return [o.name for o in self.options if o != None] + def parse(self): options = {} ret = {} @@ -212,24 +233,24 @@ class ConfigParser(object): for opt_name, val in list(options.items()): #check delivered options if opt_name.startswith('__'): continue - if opt_name not in self.options: + if opt_name not in self.__names(): if opt_name in arbitrary_options: continue else: raise NameError("Unrecognized option: " + opt_name) - opt = self.options[opt_name] + opt = self[opt_name] if type(val) not in opt.types: raise RuntimeError("Given option: "+str(type(val))+" doesn't match specified types:"+str(opt.types)) ret[opt_name] = val if type(val) == type(dict()): try: for key in val: - if key not in self.options[opt_name].allowed_keys: + if key not in self[opt_name].allowed_keys: raise RuntimeError("Encountered unallowed key: " +key+ " for options '"+opt_name+"'") except AttributeError: #no allowed_keys member - don't perform any check pass - for name, opt in self.options.items(): #set values for not listed items with defaults + for opt in self.options: #set values for not listed items with defaults try: if opt.name not in ret: ret[opt.name] = opt.default diff --git a/synthesis/fetch.py b/synthesis/fetch.py index b27368bf..b493fefd 100644 --- a/synthesis/fetch.py +++ b/synthesis/fetch.py @@ -6,45 +6,31 @@ import global_mod import path class ModuleFetcher: - def __init__(self): pass def fetch_single_module(self, module): - involved_modules = [] + new_modules = [] p.vprint("Fetching manifest: " + str(module.manifest)) - if(module.source == "local"): + if module.source == "local": p.vprint("ModPath: " + module.path); - module.parse_manifest() - - if module.root_module != None: - root_module = module.root_module - p.vprint("Encountered root manifest: " + str(root_module)) - new_modules = self.fetch_recursively(root_module) - involved_modules.extend(new_modules) - - for module in module.svn: + if module.source == "svn": p.vprint("[svn] Fetching to " + module.fetchto) self.__fetch_from_svn(module) - module.source = "local" - module.isparsed = False - p.vprint("[svn] Local path " + module.path) - involved_modules.append(module) - - for module in module.git: + if module.source == "git": p.vprint("[git] Fetching to " + module.fetchto) self.__fetch_from_git(module) - module.source = "local" - module.isparsed = False - module.manifest = module.search_for_manifest(); - p.vprint("[git] Local path " + module.path); - involved_modules.append(module) - for module in module.local: - involved_modules.append(module) + module.parse_manifest() - return involved_modules + if module.root_module != None: + p.vprint("Encountered root manifest: " + str(root_module)) + new_modules.append(module.root_module) + + new_modules.extend(module.svn) + new_modules.extend(module.git) + return new_modules def __fetch_from_svn(self, module): fetchto = module.fetchto @@ -135,11 +121,128 @@ class ModuleFetcher: return ret class ModulePool(list): + class ModuleFetcher: + def __init__(self): + pass + + def fetch_single_module(self, module): + new_modules = [] + p.vprint("Fetching manifest: " + str(module.manifest)) + + if module.source == "local": + print "local module in fetching" + p.vprint("ModPath: " + module.path); + if module.source == "svn": + p.vprint("[svn] Fetching to " + module.fetchto) + self.__fetch_from_svn(module) + module.manifest = module.search_for_manifest() + if module.source == "git": + p.vprint("[git] Fetching to " + module.fetchto) + self.__fetch_from_git(module) + module.manifest = module.search_for_manifest() + + module.parse_manifest() + + if module.root_module != None: + p.vprint("Encountered root manifest: " + str(root_module)) + new_modules.append(module.root_module) + + new_modules.extend(module.svn) + new_modules.extend(module.git) + return new_modules + + def __fetch_from_svn(self, module): + fetchto = module.fetchto + if not os.path.exists(fetchto): + os.mkdir(fetchto) + + cur_dir = os.getcwd() + os.chdir(fetchto) + url, rev = __parse_repo_url(module.url) + + basename = path.url_basename(url) + + cmd = "svn checkout {0} " + basename + if rev: + cmd = cmd.format(url + '@' + rev) + else: + cmd = cmd.format(url) + + rval = True + + p.vprint(cmd) + if os.system(cmd) != 0: + rval = False + os.chdir(cur_dir) + + module.isfetched = True + module.revision = rev + module.path = os.path.join(fetchto, basename) + return rval + + def __fetch_from_git(self, module): + fetchto = module.fetchto + if not os.path.exists(fetchto): + os.mkdir(fetchto) + + cur_dir = os.getcwd() + os.chdir(fetchto) + url, rev = self.__parse_repo_url(module.url) + + basename = path.url_basename(url) + + if basename.endswith(".git"): + basename = basename[:-4] #remove trailing .git + + if not os.path.exists(os.path.join(fetchto, basename)): + update_only = False + else: + update_only = True + + if update_only: + cmd = "git --git-dir="+basename+"/.git pull" + else: + cmd = "git clone " + url + + rval = True + + p.vprint(cmd) + if os.system(cmd) != 0: + rval = False + + if rev and rval: + os.chdir(basename) + cmd = "git checkout " + revision + p.vprint(cmd) + if os.system(cmd) != 0: + rval = False + + os.chdir(cur_dir) + module.isfetched = True + module.revision = rev + module.path = os.path.join(fetchto, basename) + return rval + #end class ModuleFetcher + def __parse_repo_url(self, url) : + """ + Check if link to a repo seems to be correct. Filter revision number + """ + import re + url_pat = re.compile("[ \t]*([^ \t]+)[ \t]*(@[ \t]*(.+))?[ \t]*") + url_match = re.match(url_pat, url) + + if url_match == None: + p.echo("Not a correct repo url: {0}. Skipping".format(url)) + if url_match.group(3) != None: #there is a revision given + ret = (url_match.group(1), url_match.group(3)) + else: + ret = (url_match.group(1), None) + return ret def __init__(self, top_module): self.top_module = top_module self.modules = [] - self.add(module=top_module) - + self.add(new_module=top_module) + def __iter__(self): return self.modules.__iter__() @@ -155,15 +258,19 @@ class ModulePool(list): def __str__(self): return str([str(m) for m in self.modules]) - def add(self, module): - from module import Module - if not isinstance(module, Module): - raise RuntimeError("Expecting a Module instance") + def __contains(self, module): for mod in self.modules: if mod.url == module.url: return False - self.modules.append(module) - for m in module.git + module.svn + module.local: + return True + + def add(self, new_module): + from module import Module + if not isinstance(new_module, Module): + raise RuntimeError("Expecting a Module instance") + if self.__contains(new_module): + return + for m in new_module.isfetched: self.add(m) return True @@ -173,10 +280,12 @@ class ModulePool(list): while len(fetch_queue) > 0: cur_mod = fetch_queue.pop() + self.add(cur_mod) + print "<<<<<<" + cur_mod.url new_modules = fetcher.fetch_single_module(cur_mod) + for mod in new_modules: - ret = self.add(mod) - if ret == True: + if self.__contains(mod): fetch_queue.append(mod) else: pass diff --git a/synthesis/helper_classes.py b/synthesis/helper_classes.py index 62391742..cd471615 100644 --- a/synthesis/helper_classes.py +++ b/synthesis/helper_classes.py @@ -31,19 +31,20 @@ class ManifestParser(ConfigParser): self.add_option('root_module', default=None, help="Path to root module for currently parsed", type='') self.add_option('name', default=None, help="Name of the folder at remote synthesis machine", type='') - + self.add_delimiter() self.add_option('syn_device', default=None, help = "Target FPGA device", type = ''); self.add_option('syn_grade', default=None, help = "Speed grade of target FPGA", type = ''); self.add_option('syn_package', default=None, help = "Package variant of target FPGA", type = ''); self.add_option('syn_top', default=None, help = "Top level module for synthesis", type = ''); self.add_option('syn_project', default=None, help = "Vendor flow project file", type = ''); - + self.add_delimiter() self.add_option('vsim_opt', default="", help="Additional options for vsim", type='') self.add_option('vcom_opt', default="", help="Additional options for vcom", type='') self.add_option('vlog_opt', default="", help="Additional options for vlog", type='') self.add_option('vmap_opt', default="", help="Additional options for vmap", type='') + self.add_delimiter() self.add_option('modules', default={}, help="List of local modules", type={}) self.add_option('target', default=None, help="Target architecture for synthesis", type='') @@ -51,6 +52,7 @@ class ManifestParser(ConfigParser): self.add_allowed_key('modules', key="git") self.add_allowed_key('modules', key="local") + #self.add_delimiter() self.add_option('library', default="work", help="Destination library for module's VHDL files", type="") self.add_option('files', default=[], help="List of files from the current module", type='') diff --git a/synthesis/module.py b/synthesis/module.py index 4d74b4d8..6ab5e439 100644 --- a/synthesis/module.py +++ b/synthesis/module.py @@ -148,10 +148,14 @@ class Module(object): return sth def parse_manifest(self): + print ">>>>>Parsing manifest " + self.url if self.isparsed == True: return if self.isfetched == False: return + if self.manifest == None: + self.manifest = self.__search_for_manifest() + print "MMM"+str(self.manifest) manifest_parser = ManifestParser() if(self.parent != None): @@ -259,6 +263,7 @@ class Module(object): else: self.svn = [] + print self.svn if "git" in opt_map["modules"]: opt_map["modules"]["git"] = self.__make_list(opt_map["modules"]["git"]) git = [] @@ -343,49 +348,4 @@ class Module(object): for m in modules: f_set.add(m.fileset); - return f_set -#obsolete - def generate_deps_for_vhdl_in_modules(self): - all_files = self.extract_files_from_all_modules(extensions="vhd") - p.vprint("All vhdl files:") - for file in all_files: - p.vprint(str(file) + ':' + file.library) - for file in all_files: - file.search_for_package() - file.search_for_use() - - package_file_dict = {} - for file in all_files: - packages = file.package #look for package definitions - if len(packages) != 0: #if there are some packages in the file - for package in packages: - if package in package_file_dict: - p.echo("There might be a problem... Compilation unit " + package + - " has several instances:\n\t" + str(file) + "\n\t" + str(package_file_dict[package])) - package_file_dict[package.lower()] = [package_file_dict[package.lower()], file]#/////////////////////////////////////////////////// - package_file_dict[package.lower()] = file #map found package to scanned file - file_purename = os.path.splitext(file.name)[0] - if file_purename in package_file_dict and package_file_dict[file_purename.lower()] != file: - p.echo("There might be a problem... Compilation unit " + file_purename + - " has several instances:\n\t" + str(file) + "\n\t" + str(package_file_dict[file_purename])) - package_file_dict[file_purename.lower()] = file - - p.vpprint(package_file_dict) - - file_file_dict = {} - for file in all_files: - for unit in file.use: - if unit[1].lower() in package_file_dict: - if unit[0].lower() == package_file_dict[unit[1].lower()].library: - if file in file_file_dict: - file_file_dict[file].append(package_file_dict[unit[1].lower()]) - else: - file_file_dict[file] = [package_file_dict[unit[1].lower()]] - else: - p.echo("Cannot resolve dependency: " + str(file) + " depends on " - +"compilation unit " + str(unit) + ", which cannot be found") - for file in all_files: - if file not in file_file_dict: - file_file_dict[file] = [] - p.vpprint(file_file_dict) - return file_file_dict + return f_set \ No newline at end of file diff --git a/synthesis/srcfile.py b/synthesis/srcfile.py index 4eb1c365..a23d6bd9 100644 --- a/synthesis/srcfile.py +++ b/synthesis/srcfile.py @@ -178,6 +178,8 @@ class SourceFileSet(list): raise RuntimeError("Expected object, not a string") elif isinstance(files, list): self.files.extend(files) + elif files == None: + p.vprint("Got None as a file.\n Ommiting") else: #single file, not a list self.files.append(files) #if(isinstance(files, SourceFileSet)): @@ -210,6 +212,7 @@ class SourceFileFactory: extension = tmp[len(tmp)-1] p.vprint("SFF> " + path); + nf = None if extension == 'vhd' or extension == 'vhdl': nf = VHDLFile(path, library) elif extension == 'v' or extension == 'sv': -- GitLab