summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gitc_utils.py69
-rw-r--r--manifest_xml.py3
-rw-r--r--project.py7
-rw-r--r--subcmds/gitc_init.py63
-rw-r--r--subcmds/sync.py29
5 files changed, 116 insertions, 55 deletions
diff --git a/gitc_utils.py b/gitc_utils.py
new file mode 100644
index 00000000..bf79bd28
--- /dev/null
+++ b/gitc_utils.py
@@ -0,0 +1,69 @@
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
19
20import git_command
21import git_config
22
23
24# TODO (sbasi) - Remove this constant and fetch manifest dir from /gitc/.config
25GITC_MANIFEST_DIR = '/usr/local/google/gitc/'
26GITC_FS_ROOT_DIR = '/gitc/manifest-rw/'
27NUM_BATCH_RETRIEVE_REVISIONID = 300
28
29def _set_project_revisions(projects):
30 """Sets the revisionExpr for a list of projects.
31
32 Because of the limit of open file descriptors allowed, length of projects
33 should not be overly large. Recommend calling this function multiple times
34 with each call not exceeding NUM_BATCH_RETRIEVE_REVISIONID projects.
35
36 @param projects: List of project objects to set the revionExpr for.
37 """
38 # Retrieve the commit id for each project based off of it's current
39 # revisionExpr and it is not already a commit id.
40 project_gitcmds = [(
41 project, git_command.GitCommand(None,
42 ['ls-remote',
43 project.remote.url,
44 project.revisionExpr],
45 capture_stdout=True, cwd='/tmp'))
46 for project in projects if not git_config.IsId(project.revisionExpr)]
47 for proj, gitcmd in project_gitcmds:
48 if gitcmd.Wait():
49 print('FATAL: Failed to retrieve revisionExpr for %s' % project)
50 sys.exit(1)
51 proj.revisionExpr = gitcmd.stdout.split('\t')[0]
52
53def generate_gitc_manifest(client_dir, manifest):
54 """Generate a manifest for shafsd to use for this GITC client.
55
56 @param client_dir: GITC client directory to install the .manifest file in.
57 @param manifest: XmlManifest object representing the repo manifest.
58 """
59 print('Generating GITC Manifest by fetching revision SHAs for each '
60 'project.')
61 project_gitcmd_dict = {}
62 index = 0
63 while index < len(manifest.projects):
64 _set_project_revisions(
65 manifest.projects[index:(index+NUM_BATCH_RETRIEVE_REVISIONID)])
66 index += NUM_BATCH_RETRIEVE_REVISIONID
67 # Save the manifest.
68 with open(os.path.join(client_dir, '.manifest'), 'w') as f:
69 manifest.Save(f)
diff --git a/manifest_xml.py b/manifest_xml.py
index 7e719600..6dc01a47 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -303,6 +303,9 @@ class XmlManifest(object):
303 if p.sync_s: 303 if p.sync_s:
304 e.setAttribute('sync-s', 'true') 304 e.setAttribute('sync-s', 'true')
305 305
306 if p.clone_depth:
307 e.setAttribute('clone-depth', str(p.clone_depth))
308
306 if p.subprojects: 309 if p.subprojects:
307 subprojects = set(subp.name for subp in p.subprojects) 310 subprojects = set(subp.name for subp in p.subprojects)
308 output_projects(p, e, list(sorted(subprojects))) 311 output_projects(p, e, list(sorted(subprojects)))
diff --git a/project.py b/project.py
index c32c1f52..24cac8bd 100644
--- a/project.py
+++ b/project.py
@@ -2147,8 +2147,8 @@ class Project(object):
2147 try: 2147 try:
2148 self._CheckDirReference(self.objdir, self.gitdir, share_refs=False) 2148 self._CheckDirReference(self.objdir, self.gitdir, share_refs=False)
2149 except GitError as e: 2149 except GitError as e:
2150 print("Retrying clone after deleting %s" % force_sync, file=sys.stderr)
2151 if force_sync: 2150 if force_sync:
2151 print("Retrying clone after deleting %s" % self.gitdir, file=sys.stderr)
2152 try: 2152 try:
2153 shutil.rmtree(os.path.realpath(self.gitdir)) 2153 shutil.rmtree(os.path.realpath(self.gitdir))
2154 if self.worktree and os.path.exists( 2154 if self.worktree and os.path.exists(
@@ -2285,7 +2285,10 @@ class Project(object):
2285 # Fail if the links are pointing to the wrong place 2285 # Fail if the links are pointing to the wrong place
2286 if src != dst: 2286 if src != dst:
2287 raise GitError('--force-sync not enabled; cannot overwrite a local ' 2287 raise GitError('--force-sync not enabled; cannot overwrite a local '
2288 'work tree') 2288 'work tree. If you\'re comfortable with the '
2289 'possibility of losing the work tree\'s git metadata,'
2290 ' use `repo sync --force-sync {0}` to '
2291 'proceed.'.format(self.relpath))
2289 2292
2290 def _ReferenceGitDir(self, gitdir, dotgit, share_refs, copy_all): 2293 def _ReferenceGitDir(self, gitdir, dotgit, share_refs, copy_all):
2291 """Update |dotgit| to reference |gitdir|, using symlinks where possible. 2294 """Update |dotgit| to reference |gitdir|, using symlinks where possible.
diff --git a/subcmds/gitc_init.py b/subcmds/gitc_init.py
index 9b9cefda..03d8cc30 100644
--- a/subcmds/gitc_init.py
+++ b/subcmds/gitc_init.py
@@ -18,15 +18,10 @@ import os
18import shutil 18import shutil
19import sys 19import sys
20 20
21import git_command 21import gitc_utils
22from subcmds import init 22from subcmds import init
23 23
24 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): 25class GitcInit(init.Init):
31 common = True 26 common = True
32 helpSummary = "Initialize a GITC Client." 27 helpSummary = "Initialize a GITC Client."
@@ -65,59 +60,21 @@ use for this GITC client.
65 if not opt.gitc_client: 60 if not opt.gitc_client:
66 print('fatal: gitc client (-c) is required', file=sys.stderr) 61 print('fatal: gitc client (-c) is required', file=sys.stderr)
67 sys.exit(1) 62 sys.exit(1)
68 self.client_dir = os.path.join(GITC_MANIFEST_DIR, opt.gitc_client) 63 self.client_dir = os.path.join(gitc_utils.GITC_MANIFEST_DIR,
69 if not os.path.exists(GITC_MANIFEST_DIR): 64 opt.gitc_client)
70 os.makedirs(GITC_MANIFEST_DIR) 65 if not os.path.exists(gitc_utils.GITC_MANIFEST_DIR):
66 os.makedirs(gitc_utils.GITC_MANIFEST_DIR)
71 if not os.path.exists(self.client_dir): 67 if not os.path.exists(self.client_dir):
72 os.mkdir(self.client_dir) 68 os.mkdir(self.client_dir)
73 super(GitcInit, self).Execute(opt, args) 69 super(GitcInit, self).Execute(opt, args)
70 # Make the destination manifest file a symlink to repo's so both repo and
71 # GITC refer to the same manifest.
74 if opt.manifest_file: 72 if opt.manifest_file:
75 if not os.path.exists(opt.manifest_file): 73 if not os.path.exists(opt.manifest_file):
76 print('fatal: Specified manifest file %s does not exist.' % 74 print('fatal: Specified manifest file %s does not exist.' %
77 opt.manifest_file) 75 opt.manifest_file)
78 sys.exit(1) 76 sys.exit(1)
79 shutil.copyfile(opt.manifest_file, 77 self.manifest.Override(opt.manifest_file)
80 os.path.join(self.client_dir, '.manifest')) 78 gitc_utils.generate_gitc_manifest(self.client_dir, self.manifest)
81 else:
82 self._GenerateGITCManifest()
83 print('Please run `cd %s` to view your GITC client.' % 79 print('Please run `cd %s` to view your GITC client.' %
84 os.path.join(GITC_FS_ROOT_DIR, opt.gitc_client)) 80 os.path.join(gitc_utils.GITC_FS_ROOT_DIR, opt.gitc_client)) \ No newline at end of file
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)
diff --git a/subcmds/sync.py b/subcmds/sync.py
index ed8622c1..0fc493c4 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -67,6 +67,7 @@ except ImportError:
67from git_command import GIT, git_require 67from git_command import GIT, git_require
68from git_config import GetSchemeFromUrl, GetUrlCookieFile 68from git_config import GetSchemeFromUrl, GetUrlCookieFile
69from git_refs import R_HEADS, HEAD 69from git_refs import R_HEADS, HEAD
70import gitc_utils
70from project import Project 71from project import Project
71from project import RemoteSpec 72from project import RemoteSpec
72from command import Command, MirrorSafeCommand 73from command import Command, MirrorSafeCommand
@@ -193,6 +194,9 @@ later is required to fix a server side protocol bug.
193 help="overwrite an existing git directory if it needs to " 194 help="overwrite an existing git directory if it needs to "
194 "point to a different object directory. WARNING: this " 195 "point to a different object directory. WARNING: this "
195 "may cause loss of data") 196 "may cause loss of data")
197 p.add_option('--force-gitc',
198 dest='force_gitc', action='store_true',
199 help="actually sync sources in the gitc client directory.")
196 p.add_option('-l', '--local-only', 200 p.add_option('-l', '--local-only',
197 dest='local_only', action='store_true', 201 dest='local_only', action='store_true',
198 help="only update working tree, don't fetch") 202 help="only update working tree, don't fetch")
@@ -535,6 +539,25 @@ later is required to fix a server side protocol bug.
535 print('error: both -u and -p must be given', file=sys.stderr) 539 print('error: both -u and -p must be given', file=sys.stderr)
536 sys.exit(1) 540 sys.exit(1)
537 541
542 cwd = os.getcwd()
543 if cwd.startswith(gitc_utils.GITC_MANIFEST_DIR) and not opt.force_gitc:
544 print('WARNING this will pull all the sources like a normal repo sync.\n'
545 '\nIf you want to update your GITC Client View please rerun this '
546 'command in \n%s%s.\nOr if you actually want to pull the sources, '
547 'rerun with --force-gitc.' %
548 (gitc_utils.GITC_FS_ROOT_DIR,
549 cwd.split(gitc_utils.GITC_MANIFEST_DIR)[1]))
550 sys.exit(1)
551
552 self._gitc_sync = False
553 if cwd.startswith(gitc_utils.GITC_FS_ROOT_DIR):
554 self._gitc_sync = True
555 self._client_name = cwd.split(gitc_utils.GITC_FS_ROOT_DIR)[1].split(
556 '/')[0]
557 self._client_dir = os.path.join(gitc_utils.GITC_MANIFEST_DIR,
558 self._client_name)
559 print('Updating GITC client: %s' % self._client_name)
560
538 if opt.manifest_name: 561 if opt.manifest_name:
539 self.manifest.Override(opt.manifest_name) 562 self.manifest.Override(opt.manifest_name)
540 563
@@ -655,6 +678,12 @@ later is required to fix a server side protocol bug.
655 if opt.repo_upgraded: 678 if opt.repo_upgraded:
656 _PostRepoUpgrade(self.manifest, quiet=opt.quiet) 679 _PostRepoUpgrade(self.manifest, quiet=opt.quiet)
657 680
681 if self._gitc_sync:
682 gitc_utils.generate_gitc_manifest(self._client_dir, self.manifest)
683 print('GITC client successfully synced.')
684 return
685
686
658 if not opt.local_only: 687 if not opt.local_only:
659 mp.Sync_NetworkHalf(quiet=opt.quiet, 688 mp.Sync_NetworkHalf(quiet=opt.quiet,
660 current_branch_only=opt.current_branch_only, 689 current_branch_only=opt.current_branch_only,