llvm.org GIT mirror llvm / ad83aca
Revert "Add some facilities to work with a git monorepo (experimental setup)" This reverts commit r286123, accidentally commited while testing itself... git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@286124 91177308-0d34-0410-b5e6-96231b3b80d8 Mehdi Amini 2 years ago
3 changed file(s) with 0 addition(s) and 369 deletion(s). Raw diff Collapse all Expand all
9191 endforeach()
9292 endif()
9393 endif()
94
95 # Git Mono-Repo handling: automatically set the LLVM_EXTERNAL_${project}_SOURCE_DIR
96 set(LLVM_ALL_PROJECTS "clang;libcxx;libcxxabi;lldb;compiler-rt;lld;polly")
97 set(LLVM_ENABLE_PROJECTS "" CACHE STRING
98 "Semicolon-separated list of projects to build (${LLVM_ALL_PROJECTS}), or \"all\".")
99 if( LLVM_ENABLE_PROJECTS STREQUAL "all" )
100 set( LLVM_ENABLE_PROJECTS ${LLVM_ALL_PROJECTS})
101 endif()
102 foreach(proj ${LLVM_ENABLE_PROJECTS})
103 set(PROJ_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../${proj}")
104 if(NOT EXISTS "${PROJ_DIR}" OR NOT IS_DIRECTORY "${PROJ_DIR}")
105 message(FATAL_ERROR "LLVM_ENABLE_PROJECTS requests ${proj} but directory not found: ${PROJ_DIR}")
106 endif()
107 string(TOUPPER "${proj}" upper_proj)
108 set(LLVM_EXTERNAL_${upper_proj}_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../${proj}")
109 if (proj STREQUAL "clang")
110 set(LLVM_EXTERNAL_CLANG_TOOLS_EXTRA_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../clang-tools-extra")
111 endif()
112 endforeach()
11394
11495 # The following only works with the Ninja generator in CMake >= 3.0.
11596 set(LLVM_PARALLEL_COMPILE_JOBS "" CACHE STRING
678678 % git svn rebase -l
679679
680680 Please, refer to the Git-SVN manual (``man git-svn``) for more information.
681
682 For developers to work with a git monorepo
683 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
684
685 .. note::
686
687 This set-up is using unofficial mirror hosted on GitHub, use with caution.
688
689 To set up a clone of all the llvm projects using a unified repository:
690
691 .. code-block:: console
692
693 % export TOP_LEVEL_DIR=`pwd`
694 % git clone https://github.com/llvm-project/llvm-project/
695 % cd llvm-project
696 % git config branch.master.rebase true
697
698 You can configure various build directory from this clone, starting with a build
699 of LLVM alone:
700
701 .. code-block:: console
702
703 % cd $TOP_LEVEL_DIR
704 % mkdir llvm-build && cd llvm-build
705 % cmake -GNinja ../llvm-project/llvm
706
707 Or lldb:
708
709 .. code-block:: console
710
711 % cd $TOP_LEVEL_DIR
712 % mkdir lldb-build && cd lldb-build
713 % cmake -GNinja ../llvm-project/llvm -DLLVM_ENABLE_PROJECTS=lldb
714
715 Or a combination of multiple projects:
716
717 .. code-block:: console
718
719 % cd $TOP_LEVEL_DIR
720 % mkdir clang-build && cd clang-build
721 % cmake -GNinja ../llvm-project/llvm -DLLVM_ENABLE_PROJECTS="clang;libcxx;compiler-rt"
722
723 A helper script is provided in `llvm/utils/git-svn/git-llvm`. After you add it
724 to your path, you can push committed changes upstream with `git llvm push`.
725
726 .. code-block:: console
727
728 % export PATH=$PATH:$TOP_LEVEL_DIR/llvm-project/llvm/utils/git-svn/
729 % git llvm push
730
731 While this is using SVN under the hood, it does not require any interaction from
732 you with git-svn.
733 After a few minutes, `git pull` should get back the changes as they were
734 commited.
735681
736682 Local LLVM Configuration
737683 ------------------------
+0
-296
utils/git-svn/git-llvm less more
None #!/usr/bin/env python
1 #
2 # ======- git-llvm - LLVM Git Help Integration ---------*- python -*--========#
3 #
4 # The LLVM Compiler Infrastructure
5 #
6 # This file is distributed under the University of Illinois Open Source
7 # License. See LICENSE.TXT for details.
8 #
9 # ==------------------------------------------------------------------------==#
10
11 r"""
12 git-llvm integration
13 ====================
14
15 This file provides integration for git.
16
17 For further details, run:
18
19 git llvm -h
20
21 Requires Python 2.7
22 """
23
24 from __future__ import print_function
25 import argparse
26 import collections
27 import contextlib
28 import errno
29 import os
30 import re
31 import subprocess
32 import sys
33 import tempfile
34 import time
35
36
37 desc = '''
38 TODO
39 '''
40
41 # It's *almost* a straightforward mapping from the monorepo to svn...
42 GIT_TO_SVN_DIR = {
43 d: (d + '/trunk')
44 for d in [
45 'clang-tools-extra',
46 'compiler-rt',
47 'dragonegg',
48 'klee',
49 'libclc',
50 'libcxx',
51 'libcxxabi',
52 'lld',
53 'lldb',
54 'llvm',
55 'polly',
56 ]
57 }
58 GIT_TO_SVN_DIR.update({'clang': 'cfe/trunk'})
59
60 VERBOSE = False
61 QUIET = False
62
63
64 def eprint(*args, **kwargs):
65 print(*args, file=sys.stderr, **kwargs)
66
67
68 def log(*args, **kwargs):
69 if QUIET:
70 return
71 print(*args, **kwargs)
72
73
74 def log_verbose(*args, **kwargs):
75 if not VERBOSE:
76 return
77 print(*args, **kwargs)
78
79
80 def die(msg):
81 eprint(msg)
82 sys.exit(1)
83
84
85 def shell(cmd, strip=True, cwd=None, stdin=None):
86 log_verbose('Running: %s' % ' '.join(cmd))
87
88 start = time.time()
89 p = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE,
90 stderr=subprocess.PIPE, stdin=subprocess.PIPE)
91 stdout, stderr = p.communicate(input=stdin)
92 elapsed = time.time() - start
93
94 if elapsed >= .1:
95 log_verbose('Warning: command took %0.1fs' % elapsed)
96
97 if p.returncode == 0:
98 if stderr:
99 eprint('`%s` printed to stderr:' % ' '.join(args))
100 eprint(stderr.rstrip())
101 if strip:
102 stdout = stdout.rstrip('\r\n')
103 return stdout
104 eprint('`%s` returned %s' % (' '.join(args), p.returncode))
105 if stderr:
106 eprint(stderr.rstrip())
107 sys.exit(2)
108
109
110 def git(*cmd, **kwargs):
111 return shell(['git'] + list(cmd), kwargs.get('strip', True))
112
113
114 def svn(cwd, *cmd, **kwargs):
115 # TODO: Better way to do default arg when we have *cmd?
116 return shell(['svn'] + list(cmd), cwd=cwd, stdin=kwargs.get('stdin', None))
117
118
119 def get_default_rev_range():
120 # Get the branch tracked by the current branch, as set by
121 # git branch --set-upstream-to See http://serverfault.com/a/352236/38694.
122 cur_branch = git('rev-parse', '--symbolic-full-name', 'HEAD')
123 upstream_branch = git('for-each-ref', '--format=%(upstream:short)',
124 cur_branch)
125 if not upstream_branch:
126 upstream_branch = 'origin/master'
127
128 # Get the newest common ancestor between HEAD and our upstream branch.
129 upstream_rev = git('merge-base', 'HEAD', upstream_branch)
130 return '%s..' % upstream_rev
131
132
133 def get_revs_to_push(rev_range):
134 if not rev_range:
135 rev_range = get_default_rev_range()
136 # Use git show rather than some plumbing command to figure out which revs
137 # are in rev_range because it handles single revs (HEAD^) and ranges
138 # (foo..bar) like we want.
139 revs = git('show', '--reverse', '--quiet',
140 '--pretty=%h', rev_range).split('\n')
141 # filter empty entries
142 revs = [r for r in revs if r != '']
143 if not revs:
144 die('Nothing to push: No revs in range %s.' % rev_range)
145 return revs
146
147
148 def clean_and_update_svn(svn_repo):
149 svn(svn_repo, 'revert', '-R', '.')
150
151 # Unfortunately it appears there's no svn equivalent for git clean, so we
152 # have to do it ourselves.
153 for line in svn(svn_repo, 'status').split('\n'):
154 if not line.startswith('?'):
155 continue
156 sp = line.split(' ', 1)
157 if len(sp) != 2:
158 raise RuntimeError('Unexpected svn status line: %s' % line)
159 os.remove(os.path.join(svn_repo, sp[1].strip()))
160 svn(svn_repo, 'update')
161
162
163 def svn_init(svn_root):
164 if not os.path.exists(svn_root):
165 print('Creating svn staging directory: (%s)' % (svn_root))
166 os.makedirs(svn_root)
167 print('This is a one-time initialization, please be patient for a few '
168 ' minutes...')
169 svn(svn_root, 'checkout', '--depth=immediates',
170 'https://llvm.org/svn/llvm-project/', '.')
171 svn_dirs = list(GIT_TO_SVN_DIR.values())
172 svn(svn_root, 'update', *svn_dirs)
173 print('svn staging area ready in \'%s\'' % (svn_root))
174 if not os.path.isdir(svn_root):
175 die('Can\'t initialize svn staging dir (%s)' % (svn_root))
176
177
178 def svn_push(args):
179 '''Push changes back to SVN: this is extracted from Justin Lebar's script
180 available here: https://github.com/jlebar/llvm-repo-tools/
181 '''
182 # Get the git root
183 git_root = git('rev-parse', '--show-toplevel')
184 if not os.path.isdir(git_root):
185 die('Can\'t find git root dir')
186
187 # Push from the root of the git repo
188 os.chdir(git_root)
189
190 # We need a staging area for SVN, let's hide it in the .git directory.
191 svn_root = os.path.join(git_root, '.git', 'llvm-upstream-svn')
192 svn_init(svn_root)
193
194 rev_range = args.rev_range
195 dry_run = args.dry_run
196 revs = get_revs_to_push(rev_range)
197 log('Pushing %d commit%s:\n%s' %
198 (len(revs), 's' if len(revs) != 1
199 else '', '\n'.join(' ' + git('show', '--oneline', '--quiet', c)
200 for c in revs)))
201 for r in revs:
202 clean_and_update_svn(svn_root)
203 push(svn_root, r, dry_run)
204
205
206 def first_dirname(d):
207 while True:
208 (head, tail) = os.path.split(d)
209 if not head or head == '/':
210 return tail
211 d = head
212
213
214 def push(svn_repo, rev, dry_run):
215 files = git('diff-tree', '--no-commit-id', '--name-only', '-r',
216 rev).split('\n')
217 subrepos = {first_dirname(f) for f in files}
218 if not subrepos:
219 raise RuntimeError('Empty diff for rev %s?' % rev)
220
221 status = svn(svn_repo, 'status')
222 if status:
223 die('Can\'t push git rev %s because svn status is not empty:\n%s' %
224 (rev, status))
225
226 for sr in subrepos:
227 diff = git('show', '--binary', rev, '--', sr, strip=False)
228 svn_sr_path = os.path.join(svn_repo, GIT_TO_SVN_DIR[sr])
229 # git is the only thing that can handle its own patches...
230 log_verbose('Apply patch: %s' % diff)
231 shell(['git', 'apply', '-p2', '-'], cwd=svn_sr_path, stdin=diff)
232
233 status_lines = svn(svn_repo, 'status').split('\n')
234
235 # Check that patch didn't dump any .orig or .rej files.
236 for line in status_lines:
237 if line.endswith('.rej') or line.endswith('.orig'):
238 raise RuntimeError('patch left a .orig/.rej file in the svn repo: '
239 '%s.' % line)
240 for l in (l for l in status_lines if l.startswith('?')):
241 svn(svn_repo, 'add', l[1:].strip())
242 for l in (l for l in status_lines if l.startswith('!')):
243 svn(svn_repo, 'remove', l[1:].strip())
244
245 # Now we're ready to commit.
246 commit_msg = git('show', '--pretty=%B', '--quiet', rev)
247 if not dry_run:
248 log(svn(svn_repo, 'commit', '-m', commit_msg))
249 log('Committed %s to svn.' % rev)
250 else:
251 log('Would have committed %s to svn, if this weren\'t a dry run.'
252 % rev)
253
254
255 if __name__ == '__main__':
256 argv = sys.argv[1:]
257 p = argparse.ArgumentParser(
258 prog='git llvm', formatter_class=argparse.RawDescriptionHelpFormatter,
259 description=desc)
260 subparsers = p.add_subparsers(title='subcommands',
261 description='valid subcommands',
262 help='additional help')
263 p.add_argument('-q', '--quiet', action='count', default=0,
264 help='print less information')
265 p.add_argument('-v', '--verbose', action='count', default=0,
266 help='print more information')
267
268 parser_push = subparsers.add_parser(
269 'push', help='push changes back to the LLVM SVN repository')
270 parser_push.add_argument(
271 '-n',
272 '--dry-run',
273 dest='dry_run',
274 action='store_true',
275 help='Do everything other than commit to svn. Leaves junk in the svn '
276 'repo, so probably will not work well if you try to commit more '
277 'than one rev.')
278 parser_push.add_argument(
279 'rev_range',
280 metavar='GIT_REVS',
281 type=str,
282 nargs='?',
283 help='revs to push (default: everything not in the branch\'s '
284 'upstream, or not in origin/master if the branch lacks '
285 'an explicit upstream)')
286 parser_push.set_defaults(func=svn_push)
287 args = p.parse_args(argv)
288 VERBOSE = args.verbose
289 QUIET = args.quiet
290
291 if QUIET and VERBOSE:
292 die('Error -v and -q cannot be used together: make your mind!')
293
294 # Dispatch to the right subcommand
295 args.func(args)