blob: 157008ace7b4944644e8e4064747afafdaf01602 [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
"""Tool for creating symlinks from SOURCES to TARGET.
For each SOURCE in SOURCES create a link from SOURCE to TARGET. If a
SOURCE ends with .../lib, the lib suffix is ignored when determining
the name of the target link.
If a SOURCE contains ":", the left side is the path and the right side is the
name of the package symlink.
Before creating any links, the old entries of the TARGET directory will be
removed.
Usage:
python tools/make_links.py OPTIONS TARGET SOURCES...
"""
import optparse
import os
import shutil
import subprocess
import sys
import utils
# Useful messages when we find orphaned checkouts.
old_directories = {
'package_config': 'Please remove third_party/pkg/package_config.',
'analyzer_cli': 'Please remove third_party/pkg/analyzer_cli.'}
def get_options():
result = optparse.OptionParser()
result.add_option("--timestamp_file", "",
help='Create a timestamp file when done creating the links.',
default='')
return result.parse_args()
def make_link(source, target, orig_source):
if os.path.islink(target):
print 'Removing %s' % target
sys.stdout.flush()
os.unlink(target)
if os.path.isdir(target):
print 'Removing %s' % target
sys.stdout.flush()
os.rmdir(target)
if os.path.isfile(orig_source):
print 'Copying file from %s to %s' % (orig_source, target)
sys.stdout.flush()
shutil.copyfile(orig_source, target)
return 0
else:
print 'Creating link from %s to %s' % (source, target)
sys.stdout.flush()
if utils.GuessOS() == 'win32':
return subprocess.call(['mklink', '/j', target, source], shell=True)
else:
return subprocess.call(['ln', '-s', source, target])
def create_timestamp_file(options):
if options.timestamp_file != '':
dir_name = os.path.dirname(options.timestamp_file)
if not os.path.exists(dir_name):
os.mkdir(dir_name)
open(options.timestamp_file, 'w').close()
def main(argv):
(options, args) = get_options()
target = os.path.relpath(args[0])
if os.path.exists(target):
# If the packages directory already exists, delete the current links inside
# it. This is necessary, otherwise we can end up having links in there
# pointing to directories which no longer exist (on incremental builds).
for link in os.listdir(target):
full_link = os.path.join(target, link)
if os.path.isdir(full_link) and utils.IsWindows():
# It seems like python on Windows is treating pseudo symlinks to
# directories as directories.
os.rmdir(full_link)
else:
os.remove(full_link)
else:
os.makedirs(target)
linked_names = {};
for source in args[1:]:
# Assume the source directory is named ".../NAME/lib".
split = source.split(':')
name = None
if len(split) == 2: (source, name) = split
(path, lib) = os.path.split(source)
if lib != 'lib':
path = source
# Remove any additional path components preceding NAME, if one wasn't
# specified explicitly.
if not name: (_, name) = os.path.split(path)
# We have an issue with left-behind checkouts in third_party/pkg and
# third_party/pkg_tested when we move entries in DEPS. This reports them.
if name in linked_names:
print 'Duplicate directory %s is linked to both %s and %s.' % (
name, linked_names[name], path)
if name in old_directories:
print old_directories[name]
return 1
linked_names[name] = path
orig_source = source
if utils.GuessOS() == 'win32':
source = os.path.relpath(source)
else:
source = os.path.relpath(source, start=target)
exit_code = make_link(source, os.path.join(target, name), orig_source)
if exit_code != 0:
return exit_code
create_timestamp_file(options)
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))