X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=build%2Fsymlink.py;h=ad938072d59e0b91a6677e1785eb7769bb210874;hb=refs%2Fchanges%2F87%2F308787%2F2;hp=5a261dcad93e1bddc77b42312f552a12dc8c131f;hpb=f2d92c43eba8c2b1d99715af61b37d7e03463c1d;p=platform%2Fframework%2Fweb%2Fchromium-efl.git diff --git a/build/symlink.py b/build/symlink.py index 5a261dc..ad93807 100755 --- a/build/symlink.py +++ b/build/symlink.py @@ -1,27 +1,33 @@ -#!/usr/bin/env python -# Copyright (c) 2013 The Chromium Authors. All rights reserved. +#!/usr/bin/env python3 +# Copyright 2013 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -"""Make a symlink and optionally touch a file (to handle dependencies). - -Usage: - symlink.py [options] sources... target - -A sym link to source is created at target. If multiple sources are specfied, -then target is assumed to be a directory, and will contain all the links to +description = """ +Make a symlink and optionally touch a file (to handle dependencies). +""" +usage = "%prog [options] source[ source ...] linkname" +epilog = """\ +A symlink to source is created at linkname. If multiple sources are specified, +then linkname is assumed to be a directory, and will contain all the links to the sources (basenames identical to their source). + +On Windows, this will use hard links (mklink /H) to avoid requiring elevation. +This means that if the original is deleted and replaced, the link will still +have the old contents. """ import errno import optparse import os.path import shutil +import subprocess import sys def Main(argv): - parser = optparse.OptionParser() + parser = optparse.OptionParser(usage=usage, description=description, + epilog=epilog) parser.add_option('-f', '--force', action='store_true') parser.add_option('--touch') @@ -36,11 +42,24 @@ def Main(argv): if len(sources) == 1 and not os.path.isdir(target): t = target t = os.path.expanduser(t) - if os.path.realpath(t) == s: + if os.path.realpath(t) == os.path.realpath(s): continue try: - os.symlink(s, t) - except OSError, e: + # N.B. Python 2.x does not have os.symlink for Windows. + # Python 3 has os.symlink for Windows, but requires either the admin- + # granted privilege SeCreateSymbolicLinkPrivilege or, as of Windows 10 + # 1703, that Developer Mode be enabled. Hard links and junctions do not + # require any extra privileges to create. + if os.name == 'nt': + # mklink does not tolerate /-delimited path names. + t = t.replace('/', '\\') + s = s.replace('/', '\\') + # N.B. This tool only handles file hardlinks, not directory junctions. + subprocess.check_output(['cmd.exe', '/c', 'mklink', '/H', t, s], + stderr=subprocess.STDOUT) + else: + os.symlink(s, t) + except OSError as e: if e.errno == errno.EEXIST and options.force: if os.path.isdir(t): shutil.rmtree(t, ignore_errors=True) @@ -49,10 +68,23 @@ def Main(argv): os.symlink(s, t) else: raise + except subprocess.CalledProcessError as e: + # Since subprocess.check_output does not return an easily checked error + # number, in the 'force' case always assume it is 'file already exists' + # and retry. + if options.force: + if os.path.isdir(t): + shutil.rmtree(t, ignore_errors=True) + else: + os.remove(t) + subprocess.check_output(e.cmd, stderr=subprocess.STDOUT) + else: + raise if options.touch: - with open(options.touch, 'w') as f: + os.makedirs(os.path.dirname(options.touch), exist_ok=True) + with open(options.touch, 'w'): pass