1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
# vim: set sw=4 sts=4 et :
# Copyright: 2008 Gentoo Foundation
# Author(s): Nirbheek Chauhan <nirbheek.chauhan@gmail.com>
# License: GPL-2
#
# Immortal lh!
#
# XXX: This is purely yay-something-works code
# This will change radically with time
import re, subprocess, sys, os
import os.path as osp
from .. import config, daemon
class Jobuild(object):
"""A jobuild"""
def __init__(self, jobtagedir, atom):
"""
@param jobtagedir: Jobtage directory
@type jobtagdir: string
@param atom: Atom for finding the corresponding jobuild
@type atom: string
"""
self.atom = atom
self.jobtagedir = jobtagedir
self.which = self._best_jobuild(atom)
def __str__(self):
return '%s jobuild object' % self.atom
def _split_atom(self, atom):
regex = re.compile(r'^([<>]?=)?([a-zA-Z0-9_+-]+)/([a-zA-Z0-9_+-]+)(-|$)([0-9]+\.[0-9]+)?') # Fancy regex aye?
# >= bheekling / test-beagle - 1.0
# bheekling / build-brasero
parts = regex.findall(atom)
if not parts:
# FIXME: Custom exceptions
raise 'Invalid atom %s' % atom
parts = parts[0]
if parts[3] and not parts[4]:
# FIXME: Custom exceptions
raise 'Invalid atom %s' % atom
parts = (parts[0], parts[1], parts[2], parts[4],)
if (parts[0] and not parts[3]) or (parts[3] and not parts[0]):
# FIXME: Custom exceptions
raise 'Invalid atom %s' % atom
return parts
def _get_all_pv_sorted(self, data):
files = os.listdir('%(jobtage)s/%(maint)s/%(pn)s' % data)
for file in files[:]:
if not file.endswith('.jobuild'):
files.remove(file)
else:
files[files.index(file)] = '=%s/%s' % (data['maint'], osp.basename(file)[:-8],) # .jobuild is 8 characters
# =maint/pn-pv
pv = []
for atom in files:
pv.append(self._split_atom(atom)[3])
pv.sort()
return pv
def _best_jobuild(self, atom):
parts = self._split_atom(atom)
data = {'op': parts[0],
'maint': parts[1],
'pn': parts[2],
'pv': parts[3],
'jobtage': self.jobtagedir}
if data['op'] == '=':
pass # Nothing to be done
elif not data['op']:
pv = self._get_all_pv_sorted(data)
data['pv'] = pv[-1]
elif data['op'] == '>=':
pv = self._get_all_pv_sorted(data)
if pv[-1] >= data['pv']:
data['pv'] = pv[-1]
else:
raise 'No matching jobuild found for atom \"%s\"' % atom
elif data['op'] == '<=':
pv = self._get_all_pv_sorted(data)
pv.reverse()
for i in pv:
if i <= data['pv']:
data['pv'] = i
break
if i == pv[-1]: # If it's the last pv..
raise 'No matching jobuild found for atom \"%s\"' % atom
return '%(maint)s/%(pn)s/%(pn)s-%(pv)s.jobuild' % data
class Processor(object):
"""Generic Jobuild processor"""
def __init__(self, jobuild, chroot):
"""
@param jobuild: Jobuild to process. Can be changed anytime
@type jobuild: L{autotua.jobuild.Jobuild}
@param chroot: Chroot to use for processing the jobuild
@type chroot: L{autotua.chroot.WorkChroot}
"""
self.jobuild = jobuild
self.chroot = chroot
def run_phase(self, phase):
"""
Run the specified phase of the jobuild
all: Run all the phases
unpack: src_unpack()
work: do_work()
cleanup: cleanup()
"""
args = {'phase': phase,
'jobuild': self.jobuild.which,}
self._msg('RUN_PHASE "%(phase)s" "%(jobuild)s"' % args)
def get_var(self, var):
"""
Parse jobuild and get a variable
(yay-something-works function)
"""
args = {'var': var,
'jobuild': self.jobuild.which,}
return self._msg('GET_VAR "%(var)s" "%(jobuild)s"' % args)
def _msg(self, msg):
chroot = None
workdir = config.AUTOTUA_DIR
if self.chroot:
chroot = self.chroot.chrootdir
workdir = config.CHAUTOTUA_DIR
proc = daemon.Spawn(chroot, self.jobuild.jobtagedir, workdir, '\"%s\"/bin/jobuild.sh %s' % (workdir, msg))
# XXX: This waits for process to close stderr.
# Replace with a loop during daemonisation
response = proc.process.stderr.read()[:-1] # Remove trailing newline
returncode = proc.process.returncode
if returncode and returncode < 0:
# FIXME: Custom exceptions
raise 'Daemon died with exit code \'%s\'' % -returncode
return response
class Resolver(object):
"""Jobuild dependency resolver"""
def __init__(self, jobuild):
"""
@param jobuild: Jobuild to resolve dependencies of
@type jobuild: L{autotua.jobuild.Jobuild}
"""
self.jobuild = jobuild
self.processor = Processor(self.jobuild, None)
def _get_deplist(self, deplist):
retlist = deplist
index = 0
while index < len(deplist):
if not isinstance(deplist[index], list):
jobj = Jobuild(self.jobuild.jobtagedir, deplist[index])
self.processor.jobuild = jobj
deps = self.processor.get_var('DEPEND').split()
if deps:
retlist.append(self._get_deplist(deps))
index += 1
return retlist
def _flatten(self, deplist):
newlist = []
for item in deplist:
if isinstance(item, list):
newlist.extend(self._flatten(item))
else:
newlist.append(item)
return newlist
def _unique(self, deplist):
"""
Makes deplist unique and reverses order
This gives us the required merge order
"""
newlist = []
index = len(deplist)
while index >= 0:
index -= 1
if deplist[index] not in newlist:
newlist.append(deplist[index])
return newlist
def resolve(self):
"""
Resolve all the dependencies of the Jobuild and
return a list of jobs in running order
"""
deps = [self.jobuild.atom]
deps = self._get_deplist(deps)
deps = self._flatten(deps)
return self._unique(deps)
|