Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: setup_links.py

Issue 1845943004: setup_links.py: Use junctions instead of symlinks on Windows. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. 2 # Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 # 3 #
4 # Use of this source code is governed by a BSD-style license 4 # Use of this source code is governed by a BSD-style license
5 # that can be found in the LICENSE file in the root of the source 5 # that can be found in the LICENSE file in the root of the source
6 # tree. An additional intellectual property rights grant can be found 6 # tree. An additional intellectual property rights grant can be found
7 # in the file PATENTS. All contributing project authors may 7 # in the file PATENTS. All contributing project authors may
8 # be found in the AUTHORS file in the root of the source tree. 8 # be found in the AUTHORS file in the root of the source tree.
9 9
10 """Setup links to a Chromium checkout for WebRTC. 10 """Setup links to a Chromium checkout for WebRTC.
11 11
12 WebRTC standalone shares a lot of dependencies and build tools with Chromium. 12 WebRTC standalone shares a lot of dependencies and build tools with Chromium.
13 To do this, many of the paths of a Chromium checkout is emulated by creating 13 To do this, many of the paths of a Chromium checkout is emulated by creating
14 symlinks to files and directories. This script handles the setup of symlinks to 14 symlinks to files and directories. This script handles the setup of symlinks to
15 achieve this. 15 achieve this.
16
17 It also handles cleanup of the legacy Subversion-based approach that was used
18 before Chrome switched over their master repo from Subversion to Git.
19 """ 16 """
20 17
21 18
22 import ctypes 19 import ctypes
23 import errno 20 import errno
24 import logging 21 import logging
25 import optparse 22 import optparse
26 import os 23 import os
27 import shelve 24 import shelve
28 import shutil 25 import shutil
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 'base', 86 'base',
90 'third_party/android_platform', 87 'third_party/android_platform',
91 'third_party/android_tools', 88 'third_party/android_tools',
92 'third_party/appurify-python', 89 'third_party/appurify-python',
93 'third_party/ashmem', 90 'third_party/ashmem',
94 'third_party/catapult', 91 'third_party/catapult',
95 'third_party/icu', 92 'third_party/icu',
96 'third_party/ijar', 93 'third_party/ijar',
97 'third_party/jsr-305', 94 'third_party/jsr-305',
98 'third_party/junit', 95 'third_party/junit',
99 'third_party/libevent', 96 'third_party/libevent',
tommi 2016/04/16 19:41:33 fyi - I noticed that this directory in Chromium is
kjellander_webrtc 2016/04/18 03:10:49 That seems to be the case. It must have been moved
100 'third_party/libxml', 97 'third_party/libxml',
101 'third_party/mockito', 98 'third_party/mockito',
102 'third_party/modp_b64', 99 'third_party/modp_b64',
103 'third_party/requests', 100 'third_party/requests',
104 'third_party/robolectric', 101 'third_party/robolectric',
105 'third_party/tcmalloc', 102 'third_party/tcmalloc',
106 'tools/android', 103 'tools/android',
107 'tools/grit', 104 'tools/grit',
108 'tools/telemetry', 105 'tools/telemetry',
109 ] 106 ]
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 250
254 os.symlink(source_path, os.path.abspath(self._link_path)) 251 os.symlink(source_path, os.path.abspath(self._link_path))
255 links_db[self._source_path] = self._link_path 252 links_db[self._source_path] = self._link_path
256 253
257 254
258 class LinkError(IOError): 255 class LinkError(IOError):
259 """Failed to create a link.""" 256 """Failed to create a link."""
260 pass 257 pass
261 258
262 259
263 # Handles symlink creation on the different platforms. 260 # Use junctions instead of symlinks on the Windows platform.
264 if sys.platform.startswith('win'): 261 if sys.platform.startswith('win'):
265 def symlink(source_path, link_path): 262 def symlink(source_path, link_path):
266 flag = 1 if os.path.isdir(source_path) else 0 263 if os.path.isdir(source_path):
267 if not ctypes.windll.kernel32.CreateSymbolicLinkW( 264 subprocess.check_call(['cmd.exe', '/c', 'mklink', '/J', link_path,
268 unicode(link_path), unicode(source_path), flag): 265 source_path])
269 raise OSError('Failed to create symlink to %s. Notice that only NTFS ' 266 else:
270 'version 5.0 and up has all the needed APIs for ' 267 # Don't create symlinks to files on Windows, just copy the file instead
271 'creating symlinks.' % source_path) 268 # (there's no way to create a link without administrator's privileges).
269 shutil.copy(source_path, link_path)
272 os.symlink = symlink 270 os.symlink = symlink
273 271
274 272
275 class WebRTCLinkSetup(object): 273 class WebRTCLinkSetup(object):
276 def __init__(self, links_db, force=False, dry_run=False, prompt=False): 274 def __init__(self, links_db, force=False, dry_run=False, prompt=False):
277 self._force = force 275 self._force = force
278 self._dry_run = dry_run 276 self._dry_run = dry_run
279 self._prompt = prompt 277 self._prompt = prompt
280 self._links_db = links_db 278 self._links_db = links_db
281 279
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 for action in (a for a in actions if a.dangerous): 311 for action in (a for a in actions if a.dangerous):
314 action.announce(planning=True) 312 action.announce(planning=True)
315 print 313 print
316 314
317 if not self._force: 315 if not self._force:
318 logging.error(textwrap.dedent("""\ 316 logging.error(textwrap.dedent("""\
319 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 317 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
320 A C T I O N R E Q I R E D 318 A C T I O N R E Q I R E D
321 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 319 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
322 320
323 Because chromium/src is transitioning to Git (from SVN), we needed to 321 Setting up the checkout requires creating symlinks to directories in the
324 change the way that the WebRTC standalone checkout works. Instead of 322 Chromium checkout inside chromium/src.
325 individually syncing subdirectories of Chromium in SVN, we're now 323 To avoid disrupting developers, we've chosen to not delete directories
326 syncing Chromium (and all of its DEPS, as defined by its own DEPS file), 324 forcibly, in case you have some work in progress in one of them :)
327 into the `chromium/src` directory.
328
329 As such, all Chromium directories which are currently pulled by DEPS are
330 now replaced with a symlink into the full Chromium checkout.
331
332 To avoid disrupting developers, we've chosen to not delete your
333 directories forcibly, in case you have some work in progress in one of
334 them :).
335 325
336 ACTION REQUIRED: 326 ACTION REQUIRED:
337 Before running `gclient sync|runhooks` again, you must run: 327 Before running `gclient sync|runhooks` again, you must run:
338 %s%s --force 328 %s%s --force
339 329
340 Which will replace all directories which now must be symlinks, after 330 Which will replace all directories which now must be symlinks, after
341 prompting with a summary of the work-to-be-done. 331 prompting with a summary of the work-to-be-done.
342 """), 'python ' if sys.platform.startswith('win') else '', sys.argv[0]) 332 """), 'python ' if sys.platform.startswith('win') else '', __file__)
343 sys.exit(1) 333 sys.exit(1)
344 elif self._prompt: 334 elif self._prompt:
345 if not query_yes_no('Would you like to perform the above plan?'): 335 if not query_yes_no('Would you like to perform the above plan?'):
346 sys.exit(1) 336 sys.exit(1)
347 337
348 for action in actions: 338 for action in actions:
349 action.announce(planning=False) 339 action.announce(planning=False)
350 action.doit(self._links_db) 340 action.doit(self._links_db)
351 341
352 if not on_bot and self._force: 342 if not on_bot and self._force:
(...skipping 17 matching lines...) Expand all
370 shell=True) 360 shell=True)
371 else: 361 else:
372 os.remove(link_path) 362 os.remove(link_path)
373 del self._links_db[source] 363 del self._links_db[source]
374 364
375 @staticmethod 365 @staticmethod
376 def _ActionForPath(source_path, link_path=None, check_fn=None, 366 def _ActionForPath(source_path, link_path=None, check_fn=None,
377 check_msg=None): 367 check_msg=None):
378 """Create zero or more Actions to link to a file or directory. 368 """Create zero or more Actions to link to a file or directory.
379 369
380 This will be a symlink on POSIX platforms. On Windows this requires 370 This will be a symlink on POSIX platforms. On Windows it will result in:
381 that NTFS is version 5.0 or higher (Vista or newer). 371 * a junction for directories
372 * a copied file for single files.
382 373
383 Args: 374 Args:
384 source_path: Path relative to the Chromium checkout root. 375 source_path: Path relative to the Chromium checkout root.
385 For readability, the path may contain slashes, which will 376 For readability, the path may contain slashes, which will
386 automatically be converted to the right path delimiter on Windows. 377 automatically be converted to the right path delimiter on Windows.
387 link_path: The location for the link to create. If omitted it will be the 378 link_path: The location for the link to create. If omitted it will be the
388 same path as source_path. 379 same path as source_path.
389 check_fn: A function returning true if the type of filesystem object is 380 check_fn: A function returning true if the type of filesystem object is
390 correct for the attempted call. Otherwise an error message with 381 correct for the attempted call. Otherwise an error message with
391 check_msg will be printed. 382 check_msg will be printed.
392 check_msg: String used to inform the user of an invalid attempt to create 383 check_msg: String used to inform the user of an invalid attempt to create
393 a file. 384 a file.
394 Returns: 385 Returns:
395 A list of Action objects. 386 A list of Action objects.
396 """ 387 """
397 def fix_separators(path): 388 def fix_separators(path):
398 if sys.platform.startswith('win'): 389 if sys.platform.startswith('win'):
399 return path.replace(os.altsep, os.sep) 390 return path.replace(os.altsep, os.sep)
400 else: 391 else:
401 return path 392 return path
402 393
403 assert check_fn 394 assert check_fn
404 assert check_msg 395 assert check_msg
405 link_path = link_path or source_path 396 link_path = link_path or source_path
406 link_path = fix_separators(link_path) 397 link_path = fix_separators(link_path)
407 398
408 source_path = fix_separators(source_path) 399 source_path = fix_separators(source_path)
409 source_path = os.path.join(CHROMIUM_CHECKOUT, source_path) 400 source_path = os.path.join(CHROMIUM_CHECKOUT, source_path)
410 if os.path.exists(source_path) and not check_fn: 401 if os.path.exists(source_path) and not check_fn:
411 raise LinkError('_LinkChromiumPath can only be used to link to %s: ' 402 raise LinkError('Can only to link to %s: tried to link to: %s' %
412 'Tried to link to: %s' % (check_msg, source_path)) 403 (check_msg, source_path))
413 404
414 if not os.path.exists(source_path): 405 if not os.path.exists(source_path):
415 logging.debug('Silently ignoring missing source: %s. This is to avoid ' 406 logging.debug('Silently ignoring missing source: %s. This is to avoid '
416 'errors on platform-specific dependencies.', source_path) 407 'errors on platform-specific dependencies.', source_path)
417 return [] 408 return []
418 409
419 actions = [] 410 actions = []
420 411
421 if os.path.exists(link_path) or os.path.islink(link_path): 412 if os.path.exists(link_path) or os.path.islink(link_path):
422 if os.path.islink(link_path): 413 if os.path.islink(link_path):
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 # Work from the root directory of the checkout. 476 # Work from the root directory of the checkout.
486 script_dir = os.path.dirname(os.path.abspath(__file__)) 477 script_dir = os.path.dirname(os.path.abspath(__file__))
487 os.chdir(script_dir) 478 os.chdir(script_dir)
488 479
489 if sys.platform.startswith('win'): 480 if sys.platform.startswith('win'):
490 def is_admin(): 481 def is_admin():
491 try: 482 try:
492 return os.getuid() == 0 483 return os.getuid() == 0
493 except AttributeError: 484 except AttributeError:
494 return ctypes.windll.shell32.IsUserAnAdmin() != 0 485 return ctypes.windll.shell32.IsUserAnAdmin() != 0
495 if not is_admin(): 486 if is_admin():
496 logging.error('On Windows, you now need to have administrator ' 487 logging.warning('WARNING: On Windows, you no longer need run as '
497 'privileges for the shell running %s (or ' 488 'administrator. Please run with user account privileges.')
498 '`gclient sync|runhooks`).\nPlease start another command '
499 'prompt as Administrator and try again.', sys.argv[0])
500 return 1
501 489
502 if not os.path.exists(CHROMIUM_CHECKOUT): 490 if not os.path.exists(CHROMIUM_CHECKOUT):
503 logging.error('Cannot find a Chromium checkout at %s. Did you run "gclient ' 491 logging.error('Cannot find a Chromium checkout at %s. Did you run "gclient '
504 'sync" before running this script?', CHROMIUM_CHECKOUT) 492 'sync" before running this script?', CHROMIUM_CHECKOUT)
505 return 2 493 return 2
506 494
507 links_database = _initialize_database(LINKS_DB) 495 links_database = _initialize_database(LINKS_DB)
508 try: 496 try:
509 symlink_creator = WebRTCLinkSetup(links_database, options.force, 497 symlink_creator = WebRTCLinkSetup(links_database, options.force,
510 options.dry_run, options.prompt) 498 options.dry_run, options.prompt)
511 symlink_creator.CleanupLinks() 499 symlink_creator.CleanupLinks()
512 if not options.clean_only: 500 if not options.clean_only:
513 symlink_creator.CreateLinks(on_bot) 501 symlink_creator.CreateLinks(on_bot)
514 except LinkError as e: 502 except LinkError as e:
515 print >> sys.stderr, e.message 503 print >> sys.stderr, e.message
516 return 3 504 return 3
517 finally: 505 finally:
518 links_database.close() 506 links_database.close()
519 return 0 507 return 0
520 508
521 509
522 if __name__ == '__main__': 510 if __name__ == '__main__':
523 sys.exit(main()) 511 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698