Upload upstream chromium 94.0.4606.31
[platform/framework/web/chromium-efl.git] / build / symlink.py
1 #!/usr/bin/env python
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 description = """
7 Make a symlink and optionally touch a file (to handle dependencies).
8 """
9 usage = "%prog [options] source[ source ...] linkname"
10 epilog = """\
11 A symlink to source is created at linkname. If multiple sources are specified,
12 then linkname is assumed to be a directory, and will contain all the links to
13 the sources (basenames identical to their source).
14
15 On Windows, this will use hard links (mklink /H) to avoid requiring elevation.
16 This means that if the original is deleted and replaced, the link will still
17 have the old contents.
18 """
19
20 import errno
21 import optparse
22 import os.path
23 import shutil
24 import subprocess
25 import sys
26
27
28 def Main(argv):
29   parser = optparse.OptionParser(usage=usage, description=description,
30                                  epilog=epilog)
31   parser.add_option('-f', '--force', action='store_true')
32   parser.add_option('--touch')
33
34   options, args = parser.parse_args(argv[1:])
35   if len(args) < 2:
36     parser.error('at least two arguments required.')
37
38   target = args[-1]
39   sources = args[:-1]
40   for s in sources:
41     t = os.path.join(target, os.path.basename(s))
42     if len(sources) == 1 and not os.path.isdir(target):
43       t = target
44     t = os.path.expanduser(t)
45     if os.path.realpath(t) == os.path.realpath(s):
46       continue
47     try:
48       # N.B. Python 2.x does not have os.symlink for Windows.
49       #   Python 3 has os.symlink for Windows, but requires either the admin-
50       #   granted privilege SeCreateSymbolicLinkPrivilege or, as of Windows 10
51       #   1703, that Developer Mode be enabled. Hard links and junctions do not
52       #   require any extra privileges to create.
53       if os.name == 'nt':
54         # mklink does not tolerate /-delimited path names.
55         t = t.replace('/', '\\')
56         s = s.replace('/', '\\')
57         # N.B. This tool only handles file hardlinks, not directory junctions.
58         subprocess.check_output(['cmd.exe', '/c', 'mklink', '/H', t, s],
59                                 stderr=subprocess.STDOUT)
60       else:
61         os.symlink(s, t)
62     except OSError as e:
63       if e.errno == errno.EEXIST and options.force:
64         if os.path.isdir(t):
65           shutil.rmtree(t, ignore_errors=True)
66         else:
67           os.remove(t)
68         os.symlink(s, t)
69       else:
70         raise
71     except subprocess.CalledProcessError as e:
72       # Since subprocess.check_output does not return an easily checked error
73       # number, in the 'force' case always assume it is 'file already exists'
74       # and retry.
75       if options.force:
76         if os.path.isdir(t):
77           shutil.rmtree(t, ignore_errors=True)
78         else:
79           os.remove(t)
80         subprocess.check_output(e.cmd, stderr=subprocess.STDOUT)
81       else:
82         raise
83
84
85   if options.touch:
86     with open(options.touch, 'w'):
87       pass
88
89
90 if __name__ == '__main__':
91   sys.exit(Main(sys.argv))