blob: 486bbeb0150e6de5aba9f80e4f2f957ae6da4efb [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 generate_gitc_manifest(gitc_manifest, manifest, paths=None):
Simran Basibdb52712015-08-10 13:23:23 -070081 """Generate a manifest for shafsd to use for this GITC client.
82
Mike Frysinger0a849b62020-12-11 03:26:42 -050083 Args:
84 gitc_manifest: Current gitc manifest, or None if there isn't one yet.
85 manifest: A GitcManifest object loaded with the current repo manifest.
86 paths: List of project paths we want to update.
Simran Basibdb52712015-08-10 13:23:23 -070087 """
Dan Willemsen5ea32d12015-09-08 13:27:20 -070088
Simran Basibdb52712015-08-10 13:23:23 -070089 print('Generating GITC Manifest by fetching revision SHAs for each '
90 'project.')
Dan Willemsen5ea32d12015-09-08 13:27:20 -070091 if paths is None:
Mike Frysinger31067c02019-06-13 02:13:23 -040092 paths = list(manifest.paths.keys())
Dan Willemsen5ea32d12015-09-08 13:27:20 -070093
Raman Tenneti080877e2021-03-09 15:19:06 -080094 groups = [x for x in re.split(r'[,\s]+', manifest.GetGroupsStr()) if x]
Dan Willemsen5ea32d12015-09-08 13:27:20 -070095
96 # Convert the paths to projects, and filter them to the matched groups.
97 projects = [manifest.paths[p] for p in paths]
98 projects = [p for p in projects if p.MatchesGroups(groups)]
99
100 if gitc_manifest is not None:
Mike Frysinger31067c02019-06-13 02:13:23 -0400101 for path, proj in manifest.paths.items():
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700102 if not proj.MatchesGroups(groups):
103 continue
104
105 if not proj.upstream and not git_config.IsId(proj.revisionExpr):
106 proj.upstream = proj.revisionExpr
107
David Pursehouseeeff3532020-02-12 11:24:10 +0900108 if path not in gitc_manifest.paths:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700109 # Any new projects need their first revision, even if we weren't asked
110 # for them.
111 projects.append(proj)
David Pursehouseeeff3532020-02-12 11:24:10 +0900112 elif path not in paths:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700113 # And copy revisions from the previous manifest if we're not updating
114 # them now.
115 gitc_proj = gitc_manifest.paths[path]
116 if gitc_proj.old_revision:
117 proj.revisionExpr = None
118 proj.old_revision = gitc_proj.old_revision
119 else:
120 proj.revisionExpr = gitc_proj.revisionExpr
121
Mike Frysinger8c1e9e62021-02-16 15:01:39 -0500122 _set_project_revisions(projects)
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700123
124 if gitc_manifest is not None:
Mike Frysinger31067c02019-06-13 02:13:23 -0400125 for path, proj in gitc_manifest.paths.items():
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700126 if proj.old_revision and path in paths:
127 # If we updated a project that has been started, keep the old-revision
128 # updated.
129 repo_proj = manifest.paths[path]
130 repo_proj.old_revision = repo_proj.revisionExpr
131 repo_proj.revisionExpr = None
132
133 # Convert URLs from relative to absolute.
Mike Frysinger31067c02019-06-13 02:13:23 -0400134 for _name, remote in manifest.remotes.items():
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700135 remote.fetchUrl = remote.resolvedFetchUrl
136
Simran Basibdb52712015-08-10 13:23:23 -0700137 # Save the manifest.
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700138 save_manifest(manifest)
Simran Basib9a1b732015-08-20 12:19:28 -0700139
David Pursehouse819827a2020-02-12 15:20:19 +0900140
Simran Basib9a1b732015-08-20 12:19:28 -0700141def save_manifest(manifest, client_dir=None):
142 """Save the manifest file in the client_dir.
143
Mike Frysinger0a849b62020-12-11 03:26:42 -0500144 Args:
145 manifest: Manifest object to save.
146 client_dir: Client directory to save the manifest in.
Simran Basib9a1b732015-08-20 12:19:28 -0700147 """
148 if not client_dir:
Mike Frysingerdc60e542020-12-11 04:02:19 -0500149 manifest_file = manifest.manifestFile
150 else:
151 manifest_file = os.path.join(client_dir, '.manifest')
152 with open(manifest_file, 'w') as f:
Raman Tenneti080877e2021-03-09 15:19:06 -0800153 manifest.Save(f, groups=manifest.GetGroupsStr())
Simran Basib9a1b732015-08-20 12:19:28 -0700154 # TODO(sbasi/jorg): Come up with a solution to remove the sleep below.
155 # Give the GITC filesystem time to register the manifest changes.
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700156 time.sleep(3)