Update mplayer submodule
[mplayer2-build.git] / script / helpers.py
blobaffb82ee46e1d0bb1bc2c0525ea25a03c26ba7b4
1 import os
2 from os import path
3 import types
4 from subprocess import Popen, PIPE, check_call
6 # Arch Linux thought it was a good idea to suddenly switch the "python"
7 # binary to point to python3...
8 version3error = """
9 This script is written for Python version 2, but for some reason
10 it's being run under incompatible version 3. If you didn't do anything
11 yourself to explicitly change the version then the reason is probably
12 that your system links plain "python" to "python3" instead of a
13 backwards-compatible version. Arch Linux reportedly did this.
14 You may be able to make things work by changing the first line of all
15 Python scripts from "#!/usr/bin/env python" to "#!/usr/bin/env python2".
16 Blame your distro for the inconvenience.
17 """
18 import sys
19 if sys.version_info > (3,):
20 raise Exception(version3error)
22 def run_command(args):
23 # interpret a string as a whitespace-separated list of executable+arguments
24 if isinstance(args, types.StringTypes):
25 args = args.split()
26 t = Popen(args, stdout=PIPE)
27 stdout = t.communicate()[0]
28 if t.returncode != 0:
29 raise OSError("Call %s failed" % str(args))
30 return stdout
32 class GitWrapper(object):
33 def __init__(self):
34 self.shallow = False
35 self.supports_nofetch = True
36 v = run_command('git --version')
37 prefix = 'git version '
38 def error():
39 sys.stderr.write('Cannot parse "git --version" output, '
40 'assuming new version')
41 if not v.startswith(prefix):
42 error()
43 return
44 v = v[len(prefix):]
45 try:
46 v = [int(n) for n in v.split('.')[:3]]
47 except:
48 error()
49 return
50 if v < [1, 6, 2]:
51 self.supports_nofetch = False
53 def submodule_clone(self, name):
54 if self.shallow:
55 # Use a depth greater than 1 for shallow clones to reduce the
56 # chance that required submodule versions are not fetched when
57 # all branch heads in the corresponding repo have moved ahead.
58 shallow_args = ['--depth', '100']
59 else:
60 shallow_args = []
61 if self.supports_nofetch:
62 nofetch_args = ['--no-fetch']
63 else:
64 nofetch_args = []
65 if path.exists(path.join(name, '.git')):
66 # If the submodule already exists just try to update it
67 check_call('git submodule sync'.split()+[name])
68 check_call('git submodule update'.split()+[name])
69 else:
70 # Do things manually instead of using "git submodule update --init",
71 # because git's sucky submodule support has no way of giving
72 # options to the "git clone" command that would be needed for
73 # shallow clones.
74 repo_addr = run_command('git config --get submodule.%s.url' % name)
75 # old git versions fail to clone over an empty directory
76 try:
77 os.rmdir(name)
78 except:
79 # Don't fail if it already doesn't exist - having other
80 # failure cases continue and fail later is OK.
81 pass
82 check_call('git clone'.split() + shallow_args + [repo_addr, name])
83 check_call('git submodule update'.split() + nofetch_args + [name])
85 def get_config(self):
86 output = run_command('git config --null --list')
87 result = {}
88 for line in output.split(chr(0)):
89 if not line:
90 continue
91 name, value = line.split('\n', 1)
92 result[name] = value
93 return result
95 def get_submodules(self):
96 output = run_command('git ls-files --stage')
97 result = []
98 for line in output.splitlines():
99 mode, sha, stage, path = line.split(None, 3)
100 if mode != '160000':
101 continue
102 result.append(path)
103 return result
105 def foreach_submodule(self, func, recurse=True):
106 for module in self.get_submodules():
107 if path.exists(path.join(module, '.git')):
108 os.chdir(module)
109 func()
110 if recurse:
111 self.foreach_submodule(func)
112 os.chdir('..')
114 def foreach_module(self, func):
115 func()
116 self.foreach_submodule(func)
119 def parse_configfile(filename):
120 if not path.exists(filename):
121 return []
122 args = []
123 f = open(filename)
124 for line in f:
125 line = line.strip()
126 if not line or line.startswith('#'):
127 continue
128 args.append(line)
129 f.close()
130 return args