Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / tools / git-sync-deps
1 #!/usr/bin/python
2 # Copyright 2014 Google Inc.
3 #
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7
8 """Parse a DEPS file and git checkout all of the dependencies.
9
10 Args:
11   An optional list of deps_os values.
12
13 Environment Variables:
14   GIT_EXECUTABLE: path to "git" binary; if unset, will look for one of
15   ['git', 'git.exe', 'git.bat'] in your default path.
16
17   GIT_SYNC_DEPS_PATH: file to get the dependency list from; if unset,
18   will use the file ../DEPS relative to this script's directory.
19
20   GIT_SYNC_DEPS_QUIET: if set to non-empty string, suppress messages.
21
22 Git Config:
23   To disable syncing of a single repository:
24       cd path/to/repository
25       git config sync-deps.disable true
26
27   To re-enable sync:
28       cd path/to/repository
29       git config --unset sync-deps.disable
30 """
31
32
33 import os
34 import subprocess
35 import sys
36 import threading
37
38
39 def git_executable():
40   """Find the git executable.
41
42   Returns:
43       A string suitable for passing to subprocess functions, or None.
44   """
45   envgit = os.environ.get('GIT_EXECUTABLE')
46   searchlist = ['git', 'git.exe', 'git.bat']
47   if envgit:
48     searchlist.insert(0, envgit)
49   with open(os.devnull, 'w') as devnull:
50     for git in searchlist:
51       try:
52         subprocess.call([git, '--version'], stdout=devnull)
53       except (OSError,):
54         continue
55       return git
56   return None
57
58
59 DEFAULT_DEPS_PATH = os.path.normpath(
60   os.path.join(os.path.dirname(__file__), os.pardir, 'DEPS'))
61
62
63 def usage(deps_file_path = None):
64   sys.stderr.write(
65     'Usage: run to grab dependencies, with optional platform support:\n')
66   sys.stderr.write('  python %s' % __file__)
67   if deps_file_path:
68     for deps_os in parse_file_to_dict(deps_file_path)['deps_os']:
69       sys.stderr.write(' [%s]' % deps_os)
70   else:
71     sys.stderr.write(' [DEPS_OS...]')
72   sys.stderr.write('\n\n')
73   sys.stderr.write(__doc__)
74
75
76 def git_repository_sync_is_disabled(git, directory):
77   try:
78     disable = subprocess.check_output(
79       [git, 'config', 'sync-deps.disable'], cwd=directory)
80     return disable.lower().strip() in ['true', '1', 'yes', 'on']
81   except subprocess.CalledProcessError:
82     return False
83
84
85 def is_git_toplevel(git, directory):
86   """Return true iff the directory is the top level of a Git repository.
87
88   Args:
89     git (string) the git executable
90
91     directory (string) the path into which the repository
92               is expected to be checked out.
93   """
94   try:
95     toplevel = subprocess.check_output(
96       [git, 'rev-parse', '--show-toplevel'], cwd=directory).strip()
97     return os.path.realpath(directory) == os.path.realpath(toplevel)
98   except subprocess.CalledProcessError:
99     return False
100
101
102 def git_checkout_to_directory(git, repo, checkoutable, directory, verbose):
103   """Checkout (and clone if needed) a Git repository.
104
105   Args:
106     git (string) the git executable
107
108     repo (string) the location of the repository, suitable
109          for passing to `git clone`.
110
111     checkoutable (string) a tag, branch, or commit, suitable for
112                  passing to `git checkout`
113
114     directory (string) the path into which the repository
115               should be checked out.
116
117     verbose (boolean)
118
119   Raises an exception if any calls to git fail.
120   """
121   if not os.path.isdir(directory):
122     subprocess.check_call(
123       [git, 'clone', '--quiet', repo, directory])
124
125   if not is_git_toplevel(git, directory):
126     # if the directory exists, but isn't a git repo, you will modify
127     # the parent repostory, which isn't what you want.
128     sys.stdout.write('%s\n  IS NOT TOP-LEVEL GIT DIRECTORY.\n' % directory)
129     return
130
131   # Check to see if this repo is disabled.  Quick return.
132   if git_repository_sync_is_disabled(git, directory):
133     sys.stdout.write('%s\n  SYNC IS DISABLED.\n' % directory)
134     return
135
136   subprocess.check_call([git, 'fetch', '--quiet'], cwd=directory)
137
138   subprocess.check_call(
139     [git, 'checkout', '--quiet', checkoutable], cwd=directory)
140
141   if verbose:
142     sys.stdout.write('%s\n  @ %s\n' % (directory, checkoutable))  # Success.
143
144
145 def parse_file_to_dict(path):
146   dictionary = {}
147   execfile(path, dictionary)
148   return dictionary
149
150
151 def git_sync_deps(deps_file_path, command_line_os_requests, verbose):
152   """Grab dependencies, with optional platform support.
153
154   Args:
155     deps_file_path (string) Path to the DEPS file.
156
157     command_line_os_requests (list of strings) Can be empty list.
158         List of strings that should each be a key in the deps_os
159         dictionary in the DEPS file.
160
161   Raises git Exceptions.
162   """
163   git = git_executable()
164   assert git
165
166   deps_file_directory = os.path.dirname(deps_file_path)
167   deps_file = parse_file_to_dict(deps_file_path)
168   dependencies = deps_file['deps'].copy()
169   os_specific_dependencies = deps_file.get('deps_os', [])
170   for os_name in command_line_os_requests:
171     # Add OS-specific dependencies
172     if os_name in os_specific_dependencies:
173       dependencies.update(os_specific_dependencies[os_name])
174   list_of_arg_lists = []
175   for directory in dependencies:
176     if '@' in dependencies[directory]:
177       repo, checkoutable = dependencies[directory].split('@', 1)
178     else:
179       repo, checkoutable = dependencies[directory], 'origin/master'
180
181     relative_directory = os.path.join(deps_file_directory, directory)
182
183     list_of_arg_lists.append(
184       (git, repo, checkoutable, relative_directory, verbose))
185
186   multithread(git_checkout_to_directory, list_of_arg_lists)
187
188   for directory in deps_file.get('recursedeps', []):
189     recursive_path = os.path.join(deps_file_directory, directory, 'DEPS')
190     git_sync_deps(recursive_path, command_line_os_requests, verbose)
191
192
193 def multithread(function, list_of_arg_lists):
194   # for args in list_of_arg_lists:
195   #   function(*args)
196   # return
197   threads = []
198   for args in list_of_arg_lists:
199     thread = threading.Thread(None, function, None, args)
200     thread.start()
201     threads.append(thread)
202   for thread in threads:
203     thread.join()
204
205
206 def main(argv):
207   deps_file_path = os.environ.get('GIT_SYNC_DEPS_PATH', DEFAULT_DEPS_PATH)
208   verbose = not bool(os.environ.get('GIT_SYNC_DEPS_QUIET', False))
209
210   if '--help' in argv or '-h' in argv:
211     usage(deps_file_path)
212     return 1
213
214   git_sync_deps(deps_file_path, argv, verbose)
215   return 0
216
217
218 if __name__ == '__main__':
219   exit(main(sys.argv[1:]))