Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ardupilot
GitHub Repository: Ardupilot/ardupilot
Path: blob/master/Tools/ardupilotwaf/git_submodule.py
9661 views
1
# encoding: utf-8
2
3
# flake8: noqa
4
5
"""
6
Waf tool for defining ardupilot's submodules, so that they are kept up to date.
7
Submodules can be considered dynamic sources, since they are updated during the
8
build. Furthermore, they can be used to generate other dynamic sources (mavlink
9
headers generation, for example). Thus, the correct use of this tool should
10
have three build groups: first one for updating the submodules, second for
11
generating any dynamic source from them, and the last one for the build. And
12
post_mode should be set to POST_LAZY. Example::
13
14
def build(bld):
15
bld.post_mode = waflib.Build.POST_LAZY
16
17
bld.add_group('git_submodules')
18
# gtest submodule
19
bld(
20
features='git_submodule'
21
git_submodule='gtest',
22
)
23
# mavlink submodule with syntactic sugar
24
bld.git_submodule('mavlink')
25
...
26
27
# now, for the dynamic sources
28
bld.add_group('dynamic_sources')
29
...
30
31
# now, below go the task generators for normal build process
32
bld.add_group('build')
33
...
34
"""
35
36
from waflib import Context, Logs, Task, Utils, Errors
37
from waflib.Configure import conf
38
from waflib.TaskGen import before_method, feature, taskgen_method
39
40
import os.path
41
import re
42
43
class update_submodule(Task.Task):
44
color = 'BLUE'
45
run_str = '${GIT} submodule update --recursive --init -- ${SUBMODULE_PATH}'
46
47
fast_forward_diff_re = dict(
48
removed=re.compile(r'-Subproject commit ([0-9a-f]+)'),
49
added=re.compile(r'\+Subproject commit ([0-9a-f]+)')
50
)
51
52
def is_fast_forward(self, path):
53
bld = self.generator.bld
54
git = self.env.get_flat('GIT')
55
56
cmd = git, 'diff', '--submodule=short', '--', os.path.basename(path)
57
cwd = self.cwd.make_node(os.path.dirname(path))
58
out = bld.cmd_and_log(cmd, quiet=Context.BOTH, cwd=cwd)
59
60
m = self.fast_forward_diff_re['removed'].search(out)
61
n = self.fast_forward_diff_re['added'].search(out)
62
if not m or not n:
63
bld.fatal('git_submodule: failed to parse diff')
64
65
head = n.group(1)
66
wanted = m.group(1)
67
cmd = git, 'merge-base', head, wanted
68
cwd = self.cwd.make_node(path)
69
out = bld.cmd_and_log(cmd, quiet=Context.BOTH, cwd=cwd)
70
71
return out.strip() == head
72
73
def runnable_status(self):
74
e = self.env.get_flat
75
cmd = e('GIT'), 'submodule', 'status', '--recursive', '--', e('SUBMODULE_PATH')
76
out = self.generator.bld.cmd_and_log(cmd, quiet=Context.BOTH, cwd=self.cwd)
77
78
self.non_fast_forward = []
79
80
# git submodule status uses a blank prefix for submodules that are up
81
# to date
82
r = Task.SKIP_ME
83
for line in out.splitlines():
84
prefix = line[0]
85
path = line[1:].split()[1]
86
if prefix == ' ':
87
continue
88
if prefix == '-':
89
r = Task.RUN_ME
90
if prefix == '+':
91
if not self.is_fast_forward(path):
92
self.non_fast_forward.append(path)
93
else:
94
r = Task.RUN_ME
95
96
if getattr(self,'non_fast_forward',[]):
97
r = Task.SKIP_ME
98
99
return r
100
101
def uid(self):
102
if not hasattr(self, 'uid_'):
103
m = Utils.md5()
104
def u(s):
105
m.update(s.encode('utf-8'))
106
u(self.__class__.__name__)
107
u(self.env.get_flat('SUBMODULE_PATH'))
108
self.uid_ = m.digest()
109
110
return self.uid_
111
112
def __str__(self):
113
return 'Submodule update: %s' % self.submodule
114
115
def configure(cfg):
116
cfg.find_program('git')
117
118
_submodules_tasks = {}
119
120
@taskgen_method
121
def git_submodule_update(self, name):
122
if name not in _submodules_tasks:
123
module_node = self.bld.srcnode.make_node(os.path.join('modules', name))
124
125
tsk = self.create_task('update_submodule', submodule=name)
126
tsk.cwd = self.bld.srcnode
127
tsk.env.SUBMODULE_PATH = module_node.abspath()
128
129
_submodules_tasks[name] = tsk
130
131
return _submodules_tasks[name]
132
133
134
@feature('git_submodule')
135
@before_method('process_source')
136
def process_module_dependencies(self):
137
self.git_submodule = getattr(self, 'git_submodule', '')
138
if not self.git_submodule:
139
self.bld.fatal('git_submodule: empty or missing git_submodule argument')
140
self.git_submodule_update(self.git_submodule)
141
142
@conf
143
def git_submodule(bld, git_submodule, **kw):
144
kw['git_submodule'] = git_submodule
145
kw['features'] = Utils.to_list(kw.get('features', ''))
146
kw['features'].append('git_submodule')
147
148
return bld(**kw)
149
150
def _post_fun(bld):
151
Logs.info('')
152
for name, t in _submodules_tasks.items():
153
if not getattr(t,'non_fast_forward',[]):
154
continue
155
Logs.warn("Submodule %s not updated: non-fastforward" % name)
156
157
@conf
158
def git_submodule_post_fun(bld):
159
bld.add_post_fun(_post_fun)
160
161
def _git_head_hash(ctx, path, short=False, hash_abbrev=8):
162
cmd = [ctx.env.get_flat('GIT'), 'rev-parse']
163
if short:
164
cmd.append(f'--short={hash_abbrev}')
165
cmd.append('HEAD')
166
try:
167
out = ctx.cmd_and_log(cmd, quiet=Context.BOTH, cwd=path)
168
except Errors.WafError as e:
169
print(e.stdout, e.stderr)
170
raise e
171
172
return out.strip()
173
174
@conf
175
def git_submodule_head_hash(self, name, short=False, hash_abbrev=8):
176
module_node = self.srcnode.make_node(os.path.join('modules', name))
177
return _git_head_hash(self, module_node.abspath(), short=short, hash_abbrev=hash_abbrev)
178
179
@conf
180
def git_head_hash(self, short=False, hash_abbrev=8):
181
return _git_head_hash(self, self.srcnode.abspath(), short=short, hash_abbrev=hash_abbrev)
182
183