blob: a2786c9f172041c1545fe6b544d9e094f2d10519 [file] [log] [blame]
Simran Basibdb52712015-08-10 13:23:23 -07001# Copyright (C) 2015 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Simran Basibdb52712015-08-10 13:23:23 -070015import os
Mike Frysinger8c1e9e62021-02-16 15:01:39 -050016import multiprocessing
Dan Willemsen5ea32d12015-09-08 13:27:20 -070017import platform
18import re
David Pursehouse46496d82015-08-20 16:37:09 +090019import sys
Simran Basib9a1b732015-08-20 12:19:28 -070020import time
Simran Basibdb52712015-08-10 13:23:23 -070021
22import git_command
23import git_config
Simran Basi8ce50412015-08-28 14:25:44 -070024import wrapper
Simran Basibdb52712015-08-10 13:23:23 -070025
Xin Lif97e72e2016-06-24 12:17:14 -070026from error import ManifestParseError
27
Dan Willemsen39252ba2016-08-23 14:06:59 -070028NUM_BATCH_RETRIEVE_REVISIONID = 32
Simran Basibdb52712015-08-10 13:23:23 -070029
David Pursehouse819827a2020-02-12 15:20:19 +090030
Simran Basi8ce50412015-08-28 14:25:44 -070031def get_gitc_manifest_dir():
32 return wrapper.Wrapper().get_gitc_manifest_dir()
33
David Pursehouse819827a2020-02-12 15:20:19 +090034
Simran Basib9a1b732015-08-20 12:19:28 -070035def parse_clientdir(gitc_fs_path):
Dan Willemsen745b4ad2015-10-06 15:23:19 -070036 return wrapper.Wrapper().gitc_parse_clientdir(gitc_fs_path)
Simran Basib9a1b732015-08-20 12:19:28 -070037
David Pursehouse819827a2020-02-12 15:20:19 +090038
Mike Frysinger8c1e9e62021-02-16 15:01:39 -050039def _get_project_revision(args):
40 """Worker for _set_project_revisions to lookup one project remote."""
41 (i, url, expr) = args
42 gitcmd = git_command.GitCommand(
43 None, ['ls-remote', url, expr], capture_stdout=True, cwd='/tmp')
44 rc = gitcmd.Wait()
45 return (i, rc, gitcmd.stdout.split('\t', 1)[0])
46
47
Simran Basibdb52712015-08-10 13:23:23 -070048def _set_project_revisions(projects):
49 """Sets the revisionExpr for a list of projects.
50
51 Because of the limit of open file descriptors allowed, length of projects
52 should not be overly large. Recommend calling this function multiple times
53 with each call not exceeding NUM_BATCH_RETRIEVE_REVISIONID projects.
54
Mike Frysinger0a849b62020-12-11 03:26:42 -050055 Args:
56 projects: List of project objects to set the revionExpr for.
Simran Basibdb52712015-08-10 13:23:23 -070057 """
58 # Retrieve the commit id for each project based off of it's current
59 # revisionExpr and it is not already a commit id.
Mike Frysinger8c1e9e62021-02-16 15:01:39 -050060 with multiprocessing.Pool(NUM_BATCH_RETRIEVE_REVISIONID) as pool:
61 results_iter = pool.imap_unordered(
62 _get_project_revision,
63 ((i, project.remote.url, project.revisionExpr)
64 for i, project in enumerate(projects)
65 if not git_config.IsId(project.revisionExpr)),
66 chunksize=8)
67 for (i, rc, revisionExpr) in results_iter:
68 project = projects[i]
69 if rc:
70 print('FATAL: Failed to retrieve revisionExpr for %s' % project.name)
71 pool.terminate()
72 sys.exit(1)
73 if not revisionExpr:
74 pool.terminate()
75 raise ManifestParseError('Invalid SHA-1 revision project %s (%s)' %
76 (project.remote.url, project.revisionExpr))
77 project.revisionExpr = revisionExpr
Simran Basibdb52712015-08-10 13:23:23 -070078
David Pursehouse819827a2020-02-12 15:20:19 +090079
Dan Willemsen5ea32d12015-09-08 13:27:20 -070080def _manifest_groups(manifest):
81 """Returns the manifest group string that should be synced
82
83 This is the same logic used by Command.GetProjects(), which is used during
84 repo sync
85
Mike Frysinger0a849b62020-12-11 03:26:42 -050086 Args:
87 manifest: The XmlManifest object
Dan Willemsen5ea32d12015-09-08 13:27:20 -070088 """
89 mp = manifest.manifestProject
90 groups = mp.config.GetString('manifest.groups')
91 if not groups:
92 groups = 'default,platform-' + platform.system().lower()
93 return groups
94
David Pursehouse819827a2020-02-12 15:20:19 +090095
Dan Willemsen5ea32d12015-09-08 13:27:20 -070096def generate_gitc_manifest(gitc_manifest, manifest, paths=None):
Simran Basibdb52712015-08-10 13:23:23 -070097 """Generate a manifest for shafsd to use for this GITC client.
98
Mike Frysinger0a849b62020-12-11 03:26:42 -050099 Args:
100 gitc_manifest: Current gitc manifest, or None if there isn't one yet.
101 manifest: A GitcManifest object loaded with the current repo manifest.
102 paths: List of project paths we want to update.
Simran Basibdb52712015-08-10 13:23:23 -0700103 """
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700104
Simran Basibdb52712015-08-10 13:23:23 -0700105 print('Generating GITC Manifest by fetching revision SHAs for each '
106 'project.')
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700107 if paths is None:
Mike Frysinger31067c02019-06-13 02:13:23 -0400108 paths = list(manifest.paths.keys())
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700109
110 groups = [x for x in re.split(r'[,\s]+', _manifest_groups(manifest)) if x]
111
112 # Convert the paths to projects, and filter them to the matched groups.
113 projects = [manifest.paths[p] for p in paths]
114 projects = [p for p in projects if p.MatchesGroups(groups)]
115
116 if gitc_manifest is not None:
Mike Frysinger31067c02019-06-13 02:13:23 -0400117 for path, proj in manifest.paths.items():
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700118 if not proj.MatchesGroups(groups):
119 continue
120
121 if not proj.upstream and not git_config.IsId(proj.revisionExpr):
122 proj.upstream = proj.revisionExpr
123
David Pursehouseeeff3532020-02-12 11:24:10 +0900124 if path not in gitc_manifest.paths:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700125 # Any new projects need their first revision, even if we weren't asked
126 # for them.
127 projects.append(proj)
David Pursehouseeeff3532020-02-12 11:24:10 +0900128 elif path not in paths:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700129 # And copy revisions from the previous manifest if we're not updating
130 # them now.
131 gitc_proj = gitc_manifest.paths[path]
132 if gitc_proj.old_revision:
133 proj.revisionExpr = None
134 proj.old_revision = gitc_proj.old_revision
135 else:
136 proj.revisionExpr = gitc_proj.revisionExpr
137
Mike Frysinger8c1e9e62021-02-16 15:01:39 -0500138 _set_project_revisions(projects)
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700139
140 if gitc_manifest is not None:
Mike Frysinger31067c02019-06-13 02:13:23 -0400141 for path, proj in gitc_manifest.paths.items():
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700142 if proj.old_revision and path in paths:
143 # If we updated a project that has been started, keep the old-revision
144 # updated.
145 repo_proj = manifest.paths[path]
146 repo_proj.old_revision = repo_proj.revisionExpr
147 repo_proj.revisionExpr = None
148
149 # Convert URLs from relative to absolute.
Mike Frysinger31067c02019-06-13 02:13:23 -0400150 for _name, remote in manifest.remotes.items():
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700151 remote.fetchUrl = remote.resolvedFetchUrl
152
Simran Basibdb52712015-08-10 13:23:23 -0700153 # Save the manifest.
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700154 save_manifest(manifest)
Simran Basib9a1b732015-08-20 12:19:28 -0700155
David Pursehouse819827a2020-02-12 15:20:19 +0900156
Simran Basib9a1b732015-08-20 12:19:28 -0700157def save_manifest(manifest, client_dir=None):
158 """Save the manifest file in the client_dir.
159
Mike Frysinger0a849b62020-12-11 03:26:42 -0500160 Args:
161 manifest: Manifest object to save.
162 client_dir: Client directory to save the manifest in.
Simran Basib9a1b732015-08-20 12:19:28 -0700163 """
164 if not client_dir:
Mike Frysingerdc60e542020-12-11 04:02:19 -0500165 manifest_file = manifest.manifestFile
166 else:
167 manifest_file = os.path.join(client_dir, '.manifest')
168 with open(manifest_file, 'w') as f:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700169 manifest.Save(f, groups=_manifest_groups(manifest))
Simran Basib9a1b732015-08-20 12:19:28 -0700170 # TODO(sbasi/jorg): Come up with a solution to remove the sleep below.
171 # Give the GITC filesystem time to register the manifest changes.
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700172 time.sleep(3)