summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@google.com>2015-08-12 23:25:20 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-08-12 23:25:20 +0000
commit5d0c3a614edc3f3d5967cfc07c7981da7013ea91 (patch)
tree8429fdb99432ff237a45a79d7ae126ad8098fa6c
parent2635c0e3b6d0fb7a48d892fe9528197eb13bc98b (diff)
parent1efc2b4a0157b5c23317e5e7a51643016133cff5 (diff)
downloadgit-repo-5d0c3a614edc3f3d5967cfc07c7981da7013ea91.tar.gz
Merge "GITC: Add gitc-init subcommand to repo."
-rwxr-xr-xrepo27
-rw-r--r--subcmds/gitc_init.py123
2 files changed, 147 insertions, 3 deletions
diff --git a/repo b/repo
index f12354a4..bf8fa3dc 100755
--- a/repo
+++ b/repo
@@ -108,6 +108,7 @@ S_repo = 'repo' # special repo repository
108S_manifests = 'manifests' # special manifest repository 108S_manifests = 'manifests' # special manifest repository
109REPO_MAIN = S_repo + '/main.py' # main script 109REPO_MAIN = S_repo + '/main.py' # main script
110MIN_PYTHON_VERSION = (2, 6) # minimum supported python version 110MIN_PYTHON_VERSION = (2, 6) # minimum supported python version
111GITC_MANIFEST_DIR = '/usr/local/google/gitc'
111 112
112 113
113import errno 114import errno
@@ -212,14 +213,25 @@ group.add_option('--config-name',
212 dest='config_name', action="store_true", default=False, 213 dest='config_name', action="store_true", default=False,
213 help='Always prompt for name/e-mail') 214 help='Always prompt for name/e-mail')
214 215
216def _GitcInitOptions(init_optparse):
217 g = init_optparse.add_option_group('GITC options')
218 g.add_option('-f', '--manifest-file',
219 dest='manifest_file',
220 help='Optional manifest file to use for this GITC client.')
221 g.add_option('-c', '--gitc-client',
222 dest='gitc_client',
223 help='The name for the new gitc_client instance.')
224
215class CloneFailure(Exception): 225class CloneFailure(Exception):
216 """Indicate the remote clone of repo itself failed. 226 """Indicate the remote clone of repo itself failed.
217 """ 227 """
218 228
219 229
220def _Init(args): 230def _Init(args, gitc_init=False):
221 """Installs repo by cloning it over the network. 231 """Installs repo by cloning it over the network.
222 """ 232 """
233 if gitc_init:
234 _GitcInitOptions(init_optparse)
223 opt, args = init_optparse.parse_args(args) 235 opt, args = init_optparse.parse_args(args)
224 if args: 236 if args:
225 init_optparse.print_usage() 237 init_optparse.print_usage()
@@ -242,6 +254,15 @@ def _Init(args):
242 raise CloneFailure() 254 raise CloneFailure()
243 255
244 try: 256 try:
257 if gitc_init:
258 client_dir = os.path.join(GITC_MANIFEST_DIR, opt.gitc_client)
259 if not os.path.exists(client_dir):
260 os.makedirs(client_dir)
261 os.chdir(client_dir)
262 if os.path.exists(repodir):
263 # This GITC Client has already initialized repo so continue.
264 return
265
245 os.mkdir(repodir) 266 os.mkdir(repodir)
246 except OSError as e: 267 except OSError as e:
247 if e.errno != errno.EEXIST: 268 if e.errno != errno.EEXIST:
@@ -732,11 +753,11 @@ def main(orig_args):
732 _Help(args) 753 _Help(args)
733 if not cmd: 754 if not cmd:
734 _NotInstalled() 755 _NotInstalled()
735 if cmd == 'init': 756 if cmd == 'init' or cmd == 'gitc-init':
736 if my_git: 757 if my_git:
737 _SetDefaultsTo(my_git) 758 _SetDefaultsTo(my_git)
738 try: 759 try:
739 _Init(args) 760 _Init(args, gitc_init=(cmd == 'gitc-init'))
740 except CloneFailure: 761 except CloneFailure:
741 shutil.rmtree(os.path.join(repodir, S_repo), ignore_errors=True) 762 shutil.rmtree(os.path.join(repodir, S_repo), ignore_errors=True)
742 sys.exit(1) 763 sys.exit(1)
diff --git a/subcmds/gitc_init.py b/subcmds/gitc_init.py
new file mode 100644
index 00000000..9b9cefda
--- /dev/null
+++ b/subcmds/gitc_init.py
@@ -0,0 +1,123 @@
1#
2# Copyright (C) 2015 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16from __future__ import print_function
17import os
18import shutil
19import sys
20
21import git_command
22from subcmds import init
23
24
25GITC_MANIFEST_DIR = '/usr/local/google/gitc'
26GITC_FS_ROOT_DIR = '/gitc/sha/rw'
27NUM_BATCH_RETRIEVE_REVISIONID = 300
28
29
30class GitcInit(init.Init):
31 common = True
32 helpSummary = "Initialize a GITC Client."
33 helpUsage = """
34%prog [options] [client name]
35"""
36 helpDescription = """
37The '%prog' command is ran to initialize a new GITC client for use
38with the GITC file system.
39
40This command will setup the client directory, initialize repo, just
41like repo init does, and then downloads the manifest collection
42and installs in in the .repo/directory of the GITC client.
43
44Once this is done, a GITC manifest is generated by pulling the HEAD
45SHA for each project and generates the properly formatted XML file
46and installs it as .manifest in the GITC client directory.
47
48The -c argument is required to specify the GITC client name.
49
50The optional -f argument can be used to specify the manifest file to
51use for this GITC client.
52"""
53
54 def _Options(self, p):
55 super(GitcInit, self)._Options(p)
56 g = p.add_option_group('GITC options')
57 g.add_option('-f', '--manifest-file',
58 dest='manifest_file',
59 help='Optional manifest file to use for this GITC client.')
60 g.add_option('-c', '--gitc-client',
61 dest='gitc_client',
62 help='The name for the new gitc_client instance.')
63
64 def Execute(self, opt, args):
65 if not opt.gitc_client:
66 print('fatal: gitc client (-c) is required', file=sys.stderr)
67 sys.exit(1)
68 self.client_dir = os.path.join(GITC_MANIFEST_DIR, opt.gitc_client)
69 if not os.path.exists(GITC_MANIFEST_DIR):
70 os.makedirs(GITC_MANIFEST_DIR)
71 if not os.path.exists(self.client_dir):
72 os.mkdir(self.client_dir)
73 super(GitcInit, self).Execute(opt, args)
74 if opt.manifest_file:
75 if not os.path.exists(opt.manifest_file):
76 print('fatal: Specified manifest file %s does not exist.' %
77 opt.manifest_file)
78 sys.exit(1)
79 shutil.copyfile(opt.manifest_file,
80 os.path.join(self.client_dir, '.manifest'))
81 else:
82 self._GenerateGITCManifest()
83 print('Please run `cd %s` to view your GITC client.' %
84 os.path.join(GITC_FS_ROOT_DIR, opt.gitc_client))
85
86 def _SetProjectRevisions(self, projects, branch):
87 """Sets the revisionExpr for a list of projects.
88
89 Because of the limit of open file descriptors allowed, length of projects
90 should not be overly large. Recommend calling this function multiple times
91 with each call not exceeding NUM_BATCH_RETRIEVE_REVISIONID projects.
92
93 @param projects: List of project objects to set the revionExpr for.
94 @param branch: The remote branch to retrieve the SHA from. If branch is
95 None, 'HEAD' is used.
96 """
97 project_gitcmds = [(
98 project, git_command.GitCommand(None,
99 ['ls-remote',
100 project.remote.url,
101 branch], capture_stdout=True))
102 for project in projects]
103 for proj, gitcmd in project_gitcmds:
104 if gitcmd.Wait():
105 print('FATAL: Failed to retrieve revisionID for %s' % project)
106 sys.exit(1)
107 proj.revisionExpr = gitcmd.stdout.split('\t')[0]
108
109 def _GenerateGITCManifest(self):
110 """Generate a manifest for shafsd to use for this GITC client."""
111 print('Generating GITC Manifest by fetching revision SHAs for each '
112 'project.')
113 manifest = self.manifest
114 project_gitcmd_dict = {}
115 index = 0
116 while index < len(manifest.projects):
117 self._SetProjectRevisions(
118 manifest.projects[index:(index+NUM_BATCH_RETRIEVE_REVISIONID)],
119 manifest.default.revisionExpr)
120 index += NUM_BATCH_RETRIEVE_REVISIONID
121 # Save the manifest.
122 with open(os.path.join(self.client_dir, '.manifest'), 'w') as f:
123 manifest.Save(f)