CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
Ardupilot

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

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