Package coprs :: Package logic :: Module packages_logic
[hide private]
[frames] | no frames]

Source Code for Module coprs.logic.packages_logic

  1  import json 
  2  import re 
  3   
  4  from sqlalchemy import bindparam, Integer 
  5  from sqlalchemy.sql import true, text 
  6   
  7  from coprs import app 
  8  from coprs import db 
  9  from coprs import exceptions 
 10  from coprs import models 
 11  from coprs import helpers 
 12   
 13  from coprs.logic import users_logic 
 14  from coprs.logic import builds_logic 
 15  from copr_common.enums import StatusEnum 
 16   
 17  log = app.logger 
18 19 20 -class PackagesLogic(object):
21 22 @classmethod
23 - def get_by_id(cls, package_id):
25 26 @classmethod
27 - def get_all(cls, copr_dir_id):
30 31 @classmethod
32 - def get_all_in_copr(cls, copr_id):
33 return (models.Package.query 34 .filter(models.Package.copr_id == copr_id))
35 36 @classmethod
37 - def get_copr_packages_list(cls, copr_dir):
38 query_select = """ 39 SELECT package.name, build.pkg_version, build.submitted_on, package.webhook_rebuild, order_to_status(subquery2.min_order_for_a_build) AS status, build.source_status 40 FROM package 41 LEFT OUTER JOIN (select MAX(build.id) as max_build_id_for_a_package, package_id 42 FROM build 43 WHERE build.copr_dir_id = :copr_dir_id 44 GROUP BY package_id) as subquery1 ON subquery1.package_id = package.id 45 LEFT OUTER JOIN build ON build.id = subquery1.max_build_id_for_a_package 46 LEFT OUTER JOIN (select build_id, min(status_to_order(status)) as min_order_for_a_build 47 FROM build_chroot 48 GROUP BY build_id) as subquery2 ON subquery2.build_id = subquery1.max_build_id_for_a_package 49 WHERE package.copr_dir_id = :copr_dir_id; 50 """ 51 52 if db.engine.url.drivername == "sqlite": 53 def sqlite_status_to_order(x): 54 if x == 3: 55 return 1 56 elif x == 6: 57 return 2 58 elif x == 7: 59 return 3 60 elif x == 4: 61 return 4 62 elif x == 0: 63 return 5 64 elif x == 1: 65 return 6 66 elif x == 5: 67 return 7 68 elif x == 2: 69 return 8 70 elif x == 8: 71 return 9 72 elif x == 9: 73 return 10 74 return 1000
75 76 def sqlite_order_to_status(x): 77 if x == 1: 78 return 3 79 elif x == 2: 80 return 6 81 elif x == 3: 82 return 7 83 elif x == 4: 84 return 4 85 elif x == 5: 86 return 0 87 elif x == 6: 88 return 1 89 elif x == 7: 90 return 5 91 elif x == 8: 92 return 2 93 elif x == 9: 94 return 8 95 elif x == 10: 96 return 9 97 return 1000
98 99 conn = db.engine.connect() 100 conn.connection.create_function("status_to_order", 1, sqlite_status_to_order) 101 conn.connection.create_function("order_to_status", 1, sqlite_order_to_status) 102 statement = text(query_select) 103 statement.bindparams(bindparam("copr_dir_id", Integer)) 104 result = conn.execute(statement, {"copr_dir_id": copr_dir.id}) 105 else: 106 statement = text(query_select) 107 statement.bindparams(bindparam("copr_dir_id", Integer)) 108 result = db.engine.execute(statement, {"copr_dir_id": copr_dir.id}) 109 110 return result 111 112 @classmethod
113 - def get_list_by_copr(cls, copr_id, package_name):
114 return models.Package.query.filter(models.Package.copr_id == copr_id, 115 models.Package.name == package_name)
116 117 @classmethod
118 - def get(cls, copr_dir_id, package_name):
119 return models.Package.query.filter(models.Package.copr_dir_id == copr_dir_id, 120 models.Package.name == package_name)
121 122 @classmethod
123 - def get_by_dir(cls, copr_dir, package_name):
124 return models.Package.query.join(models.CoprDir).filter( 125 models.CoprDir.id==copr_dir.id, 126 models.Package.name==package_name 127 )
128 129 @classmethod
130 - def get_or_create(cls, copr_dir, package_name, src_pkg):
131 package = cls.get_by_dir(copr_dir, package_name).first() 132 133 if package: 134 return package 135 136 package = models.Package( 137 name=src_pkg.name, 138 copr=src_pkg.copr, 139 source_type=src_pkg.source_type, 140 source_json=src_pkg.source_json, 141 copr_dir=copr_dir) 142 143 db.session.add(package) 144 return package
145 146 @classmethod
147 - def get_for_webhook_rebuild(cls, copr_id, webhook_secret, clone_url, commits, ref_type, ref):
148 clone_url_stripped = re.sub(r'(\.git)?/*$', '', clone_url) 149 150 packages = (models.Package.query.join(models.Copr) 151 .filter(models.Copr.webhook_secret == webhook_secret) 152 .filter(models.Package.source_type == helpers.BuildSourceEnum("scm")) 153 .filter(models.Package.copr_id == copr_id) 154 .filter(models.Package.webhook_rebuild == true()) 155 .filter(models.Package.source_json.contains(clone_url_stripped))) 156 157 result = [] 158 for package in packages: 159 package_clone_url = package.source_json_dict.get('clone_url', '') 160 package_clone_url_stripped = re.sub(r'(\.git)?/*$', '', package_clone_url) 161 162 if package_clone_url_stripped != clone_url_stripped: 163 continue 164 165 if cls.commits_belong_to_package(package, commits, ref_type, ref): 166 result += [package] 167 168 return result
169 170 @classmethod
171 - def commits_belong_to_package(cls, package, commits, ref_type, ref):
172 if ref_type == "tag": 173 matches = re.search(r'(.*)-[^-]+-[^-]+$', ref) 174 if matches and package.name != matches.group(1): 175 return False 176 else: 177 return True 178 179 committish = package.source_json_dict.get("committish") or '' 180 if committish and not ref.endswith(committish): 181 return False 182 183 for commit in commits: 184 subdir = package.source_json_dict.get('subdirectory') 185 sm = helpers.SubdirMatch(subdir) 186 changed = set() 187 for ch in ['added', 'removed', 'modified']: 188 changed |= set(commit.get(ch, [])) 189 190 for file_path in changed: 191 if sm.match(file_path): 192 return True 193 194 return False
195 196 @classmethod
197 - def add(cls, user, copr_dir, package_name, source_type=helpers.BuildSourceEnum("unset"), source_json=json.dumps({})):
198 users_logic.UsersLogic.raise_if_cant_build_in_copr( 199 user, copr_dir.copr, 200 "You don't have permissions to build in this copr.") 201 202 if cls.exists(copr_dir.id, package_name).all(): 203 raise exceptions.DuplicateException( 204 "Project dir {} already has a package '{}'" 205 .format(copr_dir.full_name, package_name)) 206 207 package = models.Package( 208 name=package_name, 209 copr=copr_dir.copr, 210 copr_dir=copr_dir, 211 source_type=source_type, 212 source_json=source_json, 213 ) 214 215 db.session.add(package) 216 return package
217 218 @classmethod
219 - def exists(cls, copr_dir_id, package_name):
220 return (models.Package.query 221 .filter(models.Package.copr_dir_id == copr_dir_id) 222 .filter(models.Package.name == package_name))
223 224 225 @classmethod
226 - def delete_package(cls, user, package):
227 if not user.can_edit(package.copr): 228 raise exceptions.InsufficientRightsException( 229 "You are not allowed to delete package `{}`.".format(package.id)) 230 231 to_delete = [] 232 for build in package.builds: 233 to_delete.append(build) 234 235 builds_logic.BuildsLogic.delete_multiple_builds(user, to_delete) 236 db.session.delete(package)
237 238 239 @classmethod
240 - def reset_package(cls, user, package):
241 if not user.can_edit(package.copr): 242 raise exceptions.InsufficientRightsException( 243 "You are not allowed to reset package `{}`.".format(package.id)) 244 245 package.source_json = json.dumps({}) 246 package.source_type = helpers.BuildSourceEnum("unset") 247 248 db.session.add(package)
249 250 251 @classmethod
252 - def build_package(cls, user, copr, package, chroot_names=None, copr_dirname=None, **build_options):
253 if not package.has_source_type_set or not package.source_json: 254 raise exceptions.NoPackageSourceException('Unset default source for package {0}'.format(package.name)) 255 return builds_logic.BuildsLogic.create_new(user, copr, package.source_type, package.source_json, 256 chroot_names, copr_dirname=copr_dirname, **build_options)
257 258 259 @classmethod
260 - def batch_build(cls, user, copr, packages, chroot_names=None, **build_options):
261 new_builds = [] 262 263 batch = models.Batch() 264 db.session.add(batch) 265 266 for package in packages: 267 git_hashes = {} 268 skip_import = False 269 source_build = None 270 271 if (package.source_type == helpers.BuildSourceEnum('upload') or 272 package.source_type == helpers.BuildSourceEnum('link')): 273 source_build = package.last_build() 274 275 if not source_build or not source_build.build_chroots[0].git_hash: 276 raise exceptions.NoPackageSourceException( 277 "Could not get latest git hash for {}".format(package.name)) 278 279 for chroot_name in chroot_names: 280 git_hashes[chroot_name] = source_build.build_chroots[0].git_hash 281 skip_import = True 282 283 new_build = builds_logic.BuildsLogic.create_new( 284 user, 285 copr, 286 package.source_type, 287 package.source_json, 288 chroot_names, 289 git_hashes=git_hashes, 290 skip_import=skip_import, 291 batch=batch, 292 **build_options) 293 294 if source_build: 295 new_build.package_id = source_build.package_id 296 new_build.pkg_version = source_build.pkg_version 297 298 new_builds.append(new_build) 299 300 return new_builds
301 302 @classmethod
303 - def delete_orphaned_packages(cls):
304 pkgs_to_delete = models.Package.query\ 305 .join(models.Copr, models.Package.copr_id == models.Copr.id)\ 306 .filter(models.Copr.deleted == True) 307 308 counter = 0 309 for pkg in pkgs_to_delete: 310 cls.delete_package(pkg.copr.user, pkg) 311 counter += 1 312 if counter >= 100: 313 db.session.commit() 314 counter = 0 315 316 if counter > 0: 317 db.session.commit()
318 319 @classmethod
320 - def last_successful_build_chroots(cls, package):
321 builds = {} 322 for chroot in package.chroots: 323 for build in reversed(package.builds): 324 try: 325 build_chroot = build.chroots_dict_by_name[chroot.name] 326 except KeyError: 327 continue 328 if build_chroot.status not in [StatusEnum("succeeded"), StatusEnum("forked")]: 329 continue 330 if build not in builds: 331 builds[build] = [build_chroot] 332 else: 333 builds[build].append(build_chroot) 334 break 335 return builds
336