Merge lp:~cjwatson/launchpad/testfix-git-target-inline-default-repo into lp:launchpad

Proposed by Colin Watson on 2015-05-07
Status: Merged
Merged at revision: 17485
Proposed branch: lp:~cjwatson/launchpad/testfix-git-target-inline-default-repo
Merge into: lp:launchpad
Diff against target: 134 lines (+43/-6)
3 files modified
lib/lp/code/interfaces/gitrepository.py (+7/-0)
lib/lp/code/model/gitrepository.py (+15/-1)
lib/lp/registry/model/product.py (+21/-5)
To merge this branch: bzr merge lp:~cjwatson/launchpad/testfix-git-target-inline-default-repo
Reviewer Review Type Date Requested Status
William Grant code Approve on 2015-05-08
Colin Watson Approve on 2015-05-07
Review via email: mp+258528@code.launchpad.net

Commit Message

Preload default Git repositories for projects so that ProductSet:+review-licenses can have a constant query count again.

Description of the Change

Preload default Git repositories for projects so that ProductSet:+review-licenses can have a constant query count again.

To post a comment you must log in.
Colin Watson (cjwatson) :
review: Approve
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/interfaces/gitrepository.py'
2--- lib/lp/code/interfaces/gitrepository.py 2015-05-07 15:03:27 +0000
3+++ lib/lp/code/interfaces/gitrepository.py 2015-05-07 16:52:35 +0000
4@@ -724,6 +724,13 @@
5 This only exists to keep lazr.restful happy.
6 """
7
8+ def preloadDefaultRepositoriesForProjects(projects):
9+ """Get preloaded default repositories for a list of projects.
10+
11+ :return: A dict mapping project IDs to their default repositories.
12+ Projects that do not have default repositories are omitted.
13+ """
14+
15
16 class IGitRepositoryDelta(Interface):
17 """The quantitative changes made to a Git repository that was edited or
18
19=== modified file 'lib/lp/code/model/gitrepository.py'
20--- lib/lp/code/model/gitrepository.py 2015-05-07 15:03:27 +0000
21+++ lib/lp/code/model/gitrepository.py 2015-05-07 16:52:35 +0000
22@@ -122,7 +122,10 @@
23 )
24 from lp.services.features import getFeatureFlag
25 from lp.services.mail.notificationrecipientset import NotificationRecipientSet
26-from lp.services.propertycache import cachedproperty
27+from lp.services.propertycache import (
28+ cachedproperty,
29+ get_property_cache,
30+ )
31 from lp.services.webapp.authorization import available_with_permission
32
33
34@@ -283,6 +286,9 @@
35 if existing is not None:
36 raise GitDefaultConflict(existing, self.target)
37 self.target_default = value
38+ if IProduct.providedBy(self.target):
39+ get_property_cache(self.target)._default_git_repository = (
40+ self if value else None)
41
42 @property
43 def display_name(self):
44@@ -894,6 +900,14 @@
45 """See `IGitRepositorySet`."""
46 return []
47
48+ @staticmethod
49+ def preloadDefaultRepositoriesForProjects(projects):
50+ repositories = bulk.load_referencing(
51+ GitRepository, projects, ["project_id"],
52+ extra_conditions=[GitRepository.target_default == True])
53+ return {
54+ repository.project_id: repository for repository in repositories}
55+
56
57 def get_git_repository_privacy_filter(user, repository_class=GitRepository):
58 public_filter = repository_class.information_type.is_in(
59
60=== modified file 'lib/lp/registry/model/product.py'
61--- lib/lp/registry/model/product.py 2015-05-07 11:38:18 +0000
62+++ lib/lp/registry/model/product.py 2015-05-07 16:52:35 +0000
63@@ -580,9 +580,13 @@
64 """See `IPillar`."""
65 return "Project"
66
67+ @cachedproperty
68+ def _default_git_repository(self):
69+ return getUtility(IGitRepositorySet).getDefaultRepository(self)
70+
71 @property
72 def official_codehosting(self):
73- repository = getUtility(IGitRepositorySet).getDefaultRepository(self)
74+ repository = self._default_git_repository
75 return (
76 self.development_focus.branch is not None or
77 repository is not None)
78@@ -617,7 +621,7 @@
79
80 @property
81 def codehosting_usage(self):
82- repository = getUtility(IGitRepositorySet).getDefaultRepository(self)
83+ repository = self._default_git_repository
84 if self.development_focus.branch is None and repository is None:
85 return ServiceUsage.UNKNOWN
86 elif (repository is not None or
87@@ -1582,7 +1586,8 @@
88 def get_precached_products(products, need_licences=False,
89 need_projectgroups=False, need_series=False,
90 need_releases=False, role_names=None,
91- need_role_validity=False):
92+ need_role_validity=False,
93+ need_codehosting_usage=False):
94 """Load and cache product information.
95
96 :param products: the products for which to pre-cache information
97@@ -1592,10 +1597,13 @@
98 :param need_releases: whether to cache release information
99 :param role_names: the role names to cache eg bug_supervisor
100 :param need_role_validity: whether to cache validity information
101+ :param need_codehosting_usage: whether to cache codehosting usage
102+ information
103 :return: a list of products
104 """
105
106- # Circular import.
107+ # Circular imports.
108+ from lp.code.interfaces.gitrepository import IGitRepositorySet
109 from lp.registry.model.projectgroup import ProjectGroup
110
111 product_ids = set(obj.id for obj in products)
112@@ -1684,6 +1692,13 @@
113 person_ids.discard(None)
114 list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
115 person_ids, need_validity=need_role_validity))
116+ if need_codehosting_usage:
117+ repository_set = getUtility(IGitRepositorySet)
118+ repository_map = repository_set.preloadDefaultRepositoriesForProjects(
119+ products)
120+ for product_id in product_ids:
121+ caches[product_id]._default_git_repository = repository_map.get(
122+ product_id)
123 return products
124
125
126@@ -2001,7 +2016,8 @@
127 return get_precached_products(
128 products, role_names=['_owner', 'registrant'],
129 need_role_validity=True, need_licences=True,
130- need_series=True, need_releases=True)
131+ need_series=True, need_releases=True,
132+ need_codehosting_usage=True)
133
134 return DecoratedResultSet(result, pre_iter_hook=eager_load)
135