c84192c52a
We try to model repository as collection of source and binary packages with their dependencies, and do some stuff with it. The initial version can calculate a list of unmets.
115 lines
3.8 KiB
Python
115 lines
3.8 KiB
Python
|
|
import cffi
|
|
|
|
|
|
_CDEF = """
|
|
void
|
|
parseEVR(const char* evr,
|
|
const char **e, const char **v, const char **r);
|
|
|
|
int
|
|
rpmEVRcmp(const char * const aE, const char * const aV, const char * const aR,
|
|
const char * const aDepend,
|
|
const char * const bE, const char * const bV, const char * const bR,
|
|
const char * const bDepend);
|
|
|
|
int rpmRangesOverlap(const char * AName, const char * AEVR, int AFlags,
|
|
const char * BName, const char * BEVR, int BFlags);
|
|
"""
|
|
|
|
|
|
_FFI = cffi.FFI()
|
|
_FFI.cdef(_CDEF)
|
|
_LIBRPM = _FFI.dlopen('librpm-4.0.4.so')
|
|
|
|
|
|
def _pp_str(p_str):
|
|
"""Convert FFI's char** to Python string.
|
|
|
|
Assumes that pointer points to a zero-terminated C-string.
|
|
Returns None if the pointer is NULL.
|
|
"""
|
|
if p_str and p_str[0]:
|
|
return _FFI.string(p_str[0])
|
|
return None
|
|
|
|
|
|
def parse_evr(evr):
|
|
"""Returns 3-tuple (epoch, version, release)"""
|
|
p_evr = _FFI.new('char[]', evr)
|
|
e = _FFI.new('char**')
|
|
v = _FFI.new('char**')
|
|
r = _FFI.new('char**')
|
|
_LIBRPM.parseEVR(p_evr, e, v, r)
|
|
epoch = _pp_str(e)
|
|
if epoch:
|
|
epoch = int(epoch)
|
|
return epoch, _pp_str(v), _pp_str(r)
|
|
|
|
|
|
def ranges_overlap(aname, aevr, aflags, bname, bevr, bflags):
|
|
return _LIBRPM.rpmRangesOverlap(
|
|
_FFI.new('char[]', aname), _FFI.new('char[]', aevr), aflags,
|
|
_FFI.new('char[]', bname), _FFI.new('char[]', bevr), bflags)
|
|
|
|
|
|
def _epoch_to_pchar(epoch, mode):
|
|
if mode not in ('pkg', 'deps'):
|
|
raise ValueError("Epoch mode should be one of "
|
|
"'pkg', 'deps' -- not " + mode)
|
|
if epoch is not None:
|
|
return _FFI.new('char[]', str(epoch).encode())
|
|
elif mode == 'pkg':
|
|
# for packages no epoch is the same as zero epoch
|
|
return _FFI.new('char[]', b'0')
|
|
else:
|
|
return _FFI.NULL
|
|
|
|
|
|
def evr_cmp(evr1, evr2, mode):
|
|
p_e1 = _epoch_to_pchar(evr1[0], mode)
|
|
p_v1 = _FFI.new('char[]', evr1[1]) if evr1[1] else _FFI.NULL
|
|
p_r1 = _FFI.new('char[]', evr1[2]) if evr1[2] else _FFI.NULL
|
|
|
|
p_e2 = _epoch_to_pchar(evr2[0], mode)
|
|
p_v2 = _FFI.new('char[]', evr2[1]) if evr2[1] else _FFI.NULL
|
|
p_r2 = _FFI.new('char[]', evr2[2]) if evr2[2] else _FFI.NULL
|
|
|
|
dep = _FFI.new('char[]', b'')
|
|
|
|
return _LIBRPM.rpmEVRcmp(p_e1, p_v1, p_r1, dep,
|
|
p_e2, p_v2, p_r2, dep)
|
|
|
|
|
|
def ver_cmp(ver1, ver2):
|
|
return evr_cmp((None, ver1, b'1'), (None, ver2, b'1'), 'pkg')
|
|
|
|
|
|
def _tests():
|
|
assert parse_evr(b'3:42.8.4-alt1.mipsel0') == (3, b'42.8.4', b'alt1.mipsel0')
|
|
assert parse_evr(b'0:42.8.4-alt1.mipsel0') == (0, b'42.8.4', b'alt1.mipsel0')
|
|
assert parse_evr(b'42.8.4-alt1.mipsel0') == (None, b'42.8.4', b'alt1.mipsel0')
|
|
|
|
assert parse_evr(b'1.20.0-alt1_1') == (None, b'1.20.0', b'alt1_1')
|
|
assert parse_evr(b'1:1.20.1-alt1') == (1, b'1.20.1', b'alt1')
|
|
|
|
assert evr_cmp((3, b'42.8.4', b'alt1'), (3, b'42.8.4', b'alt2'), 'pkg') < 0
|
|
assert evr_cmp((3, b'42.9.4', b'alt1'), (3, b'42.8.4', b'alt2'), 'pkg') > 0
|
|
assert evr_cmp((3, b'42.8.4', b'alt1'), (3, b'42.8.4', b'alt1'), 'pkg') == 0
|
|
assert evr_cmp((3, b'42.9.4', b'alt1'), (5, b'42.8.4', b'alt1'), 'pkg') < 0
|
|
|
|
assert evr_cmp((1, b'1.2.0', b'alt1'), (None, b'1.2.0', b'alt1_1'), 'pkg') > 0
|
|
assert evr_cmp((None, b'1.2.0', b'alt1_1'), (1, b'1.2.0', b'alt1'), 'pkg') < 0
|
|
|
|
# 'deps' mode means that first argument satisfies requirement
|
|
# specified as second argument; here, if epoch is absent on the right
|
|
# side, it's ignored
|
|
assert evr_cmp((1, b'1.2.0', b'alt1'), (None, b'1.2.0', b'alt1_1'), 'deps') < 0
|
|
assert evr_cmp((None, b'1.2.0', b'alt1_1'), (1, b'1.2.0', b'alt1'), 'deps') < 0
|
|
assert evr_cmp((1, b'1.3.0', b'alt1'), (None, b'1.2.0', b'alt1_1'), 'deps') > 0
|
|
assert evr_cmp((None, b'1.3.0', b'alt1_1'), (1, b'1.2.0', b'alt1'), 'deps') < 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
_tests()
|