11# -*- coding: utf-8 -*-
2-
2+ import ast
33import datetime
44import getpass
55import hashlib
1717from psycopg2 import sql
1818from psycopg2 .extensions import TransactionRollbackError
1919
20- from ..common import dt2time , now , grep , local_pgadmin_cursor , dest_reg , os , list_local_dbs , pseudo_markdown , RunbotException , findall , sanitize , markdown_escape , tail
20+ from ..common import dt2time , now , grep , local_pgadmin_cursor , dest_reg , os , list_local_dbs , pseudo_markdown , RunbotException , findall , sanitize , markdown_escape , tail , transactioncache
2121from ..container import docker_stop , docker_state , Command , docker_run , docker_pull
2222from ..fields import JsonDictField
2323
@@ -61,7 +61,6 @@ def remove_readonly(func, path_str, exinfo):
6161def make_selection (array ):
6262 return [(elem , elem .replace ('_' , ' ' ).capitalize ()) if isinstance (elem , str ) else elem for elem in array ]
6363
64-
6564class BuildParameters (models .Model ):
6665 _name = 'runbot.build.params'
6766 _description = "Build parameters"
@@ -1091,25 +1090,28 @@ def _checkout(self):
10911090
10921091 return exports
10931092
1093+ def _list_available_modules (self ):
1094+ for commit in self .env .context .get ('defined_commit_ids' ) or self .params_id .commit_ids :
1095+ for (addons_path , module , manifest_file_name ) in commit ._list_available_modules ():
1096+ yield commit , addons_path , module , manifest_file_name
1097+
10941098 def _get_available_modules (self ):
10951099 all_modules = dict ()
10961100 available_modules = defaultdict (list )
10971101 # repo_modules = []
1098- for commit in self .env .context .get ('defined_commit_ids' ) or self .params_id .commit_ids :
1099- for (addons_path , module , manifest_file_name ) in commit ._get_available_modules ():
1100- if module in all_modules :
1101- self ._log (
1102- 'Building environment' ,
1103- '%s is a duplicated modules (found in "%s", already defined in %s)' % (
1104- module ,
1105- commit ._source_path (addons_path , module , manifest_file_name ),
1106- all_modules [module ]._source_path (addons_path , module , manifest_file_name )),
1107- level = 'WARNING' ,
1108- )
1109- else :
1110- available_modules [commit .repo_id ].append (module )
1111- all_modules [module ] = commit
1112- # return repo_modules, available_modules
1102+ for commit , addons_path , module , manifest_file_name in self ._list_available_modules ():
1103+ if module in all_modules :
1104+ self ._log (
1105+ 'Building environment' ,
1106+ '%s is a duplicated modules (found in "%s", already defined in %s)' % (
1107+ module ,
1108+ commit ._source_path (addons_path , module , manifest_file_name ),
1109+ all_modules [module ]._source_path (addons_path , module , manifest_file_name )),
1110+ level = 'WARNING' ,
1111+ )
1112+ else :
1113+ available_modules [commit .repo_id ].append (module )
1114+ all_modules [module ] = commit
11131115 return available_modules
11141116
11151117 def _get_modules_to_test (self , modules_patterns = '' ):
@@ -1120,6 +1122,43 @@ def _get_modules_to_test(self, modules_patterns=''):
11201122 modules_patterns = (modules_patterns or '' ).split (',' )
11211123 return trigger ._filter_modules_to_test (modules , params_patterns + modules_patterns ) # we may switch params_patterns and modules_patterns order
11221124
1125+ @transactioncache
1126+ def _dependency_graph (self ):
1127+ dependency_graph = defaultdict (set )
1128+ dependant_graph = defaultdict (set )
1129+ for commit , addons_path , module , manifest_file_name in self ._list_available_modules ():
1130+ manifest = commit ._git_show_file (os .path .join (addons_path , module , manifest_file_name ))
1131+ manifest_content = ast .literal_eval (manifest )
1132+ depends = manifest_content .get ('depends' , [])
1133+ if not depends and module != 'base' :
1134+ depends = ['base' ]
1135+ for dep in depends :
1136+ dependency_graph [module ].add (dep )
1137+ dependant_graph [dep ].add (module )
1138+ return dependency_graph , dependant_graph
1139+
1140+ def search_modules_graph (self , modules , graph , depth = None ):
1141+ def search (modules , depth = None , visited = None ):
1142+ visited = visited or set ()
1143+ modules = set (modules ) - visited
1144+ visited |= modules
1145+ dependencies = set (modules )
1146+ if depth == 0 or not modules :
1147+ return dependencies
1148+ for module in modules :
1149+ dependencies |= search (graph [module ], depth - 1 if depth is not None else None , visited )
1150+ return dependencies
1151+ return sorted (search (modules , depth ))
1152+
1153+ def _get_modules_dependencies (self , modules , depth = None ):
1154+ self .ensure_one ()
1155+ dependency_graph , _ = self ._dependency_graph ()
1156+ return self .search_modules_graph (modules , dependency_graph , depth )
1157+
1158+ def _get_dependant_modules (self , modules , depth = None ):
1159+ _ , dependant_graph = self ._dependency_graph ()
1160+ return self .search_modules_graph (modules , dependant_graph , depth )
1161+
11231162 def _local_pg_dropdb (self , dbname ):
11241163 msg = ''
11251164 try :
@@ -1249,13 +1288,17 @@ def _modified_files(self, commit_link_links=None):
12491288 modified_files [commit_link ] = files
12501289 return modified_files
12511290
1252- def _modified_modules (self , commit_link_links = None ):
1291+ def _modified_modules (self , commit_link_links = None , defaults = None ):
12531292 modified_files = self ._modified_files (commit_link_links )
12541293 modified_modules = set ()
12551294 for commit_link , files in modified_files .items ():
12561295 commit = commit_link .commit_id
12571296 for file in files :
1258- modified_modules .add (commit .repo_id ._get_module (file ))
1297+ module = commit .repo_id ._get_module (file )
1298+ if module :
1299+ modified_modules .add (module )
1300+ elif defaults :
1301+ modified_modules |= set (defaults )
12591302 return modified_modules
12601303
12611304 def _get_upgrade_path (self ):
0 commit comments