Skip to content

Commit e85cdf4

Browse files
committed
dep: add initial Cpn object support for pkgcraft changes
1 parent 1256b7d commit e85cdf4

13 files changed

Lines changed: 351 additions & 86 deletions

File tree

src/pkgcraft/C.pxd

Lines changed: 74 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ cdef extern from "pkgcraft.h":
113113
cdef struct Config:
114114
pass
115115

116+
# Opaque wrapper for pkgcraft::dep::cpv::Cpn<String> objects.
117+
cdef struct Cpn:
118+
pass
119+
116120
# Opaque wrapper for pkgcraft::dep::cpv::Cpv<String> objects.
117121
cdef struct Cpv:
118122
pass
@@ -333,6 +337,71 @@ cdef extern from "pkgcraft.h":
333337
# The config argument must be a non-null Config pointer.
334338
RepoSet *pkgcraft_config_repos_set(Config *c, const RepoFormat *format)
335339

340+
# Get the category of a Cpn object.
341+
#
342+
# # Safety
343+
# The argument must be a non-null Cpn pointer.
344+
char *pkgcraft_cpn_category(Cpn *c)
345+
346+
# Compare two Cpns returning -1, 0, or 1 if the first is less than, equal to, or
347+
# greater than the second, respectively.
348+
#
349+
# # Safety
350+
# The arguments must be non-null Cpn pointers.
351+
int pkgcraft_cpn_cmp(Cpn *c1, Cpn *c2)
352+
353+
# Free a Cpn.
354+
#
355+
# # Safety
356+
# The argument must be a Cpn pointer or NULL.
357+
void pkgcraft_cpn_free(Cpn *c)
358+
359+
# Return the hash value for a Cpn object.
360+
#
361+
# # Safety
362+
# The argument must be a non-null Cpn pointer.
363+
uint64_t pkgcraft_cpn_hash(Cpn *c)
364+
365+
# Parse a string into a Cpn object.
366+
#
367+
# Returns NULL on error.
368+
#
369+
# # Safety
370+
# The argument should be a UTF-8 string.
371+
Cpn *pkgcraft_cpn_new(const char *s)
372+
373+
# Get the package name of a Cpn object.
374+
#
375+
# # Safety
376+
# The argument must be a non-null Cpn pointer.
377+
char *pkgcraft_cpn_package(Cpn *c)
378+
379+
# Determine if a string is a valid package Cpn.
380+
#
381+
# Returns NULL on error.
382+
#
383+
# # Safety
384+
# The argument should point to a UTF-8 string.
385+
const char *pkgcraft_cpn_parse(const char *s)
386+
387+
# Return the restriction for a Cpn object.
388+
#
389+
# # Safety
390+
# The argument must be a non-null Cpn pointer.
391+
Restrict *pkgcraft_cpn_restrict(Cpn *c)
392+
393+
# Determine if a restriction matches a Cpn object.
394+
#
395+
# # Safety
396+
# The arguments must be valid Restrict and Cpn pointers.
397+
bool pkgcraft_cpn_restrict_matches(Cpn *c, Restrict *r)
398+
399+
# Return the string for a Cpn object.
400+
#
401+
# # Safety
402+
# The argument must be a non-null Cpn pointer.
403+
char *pkgcraft_cpn_str(Cpn *c)
404+
336405
# Get the category of a Cpv object.
337406
#
338407
# # Safety
@@ -346,11 +415,11 @@ cdef extern from "pkgcraft.h":
346415
# The arguments must be non-null Cpv pointers.
347416
int pkgcraft_cpv_cmp(Cpv *c1, Cpv *c2)
348417

349-
# Get the category and package of a Cpv object.
418+
# Get the Cpn of a Cpv object.
350419
#
351420
# # Safety
352421
# The argument must be a non-null Cpv pointer.
353-
char *pkgcraft_cpv_cpn(Cpv *c)
422+
Cpn *pkgcraft_cpv_cpn(Cpv *c)
354423

355424
# Free a Cpv.
356425
#
@@ -376,7 +445,7 @@ cdef extern from "pkgcraft.h":
376445
# The arguments must be non-null Cpv and Dep pointers.
377446
bool pkgcraft_cpv_intersects_dep(Cpv *c, Dep *d)
378447

379-
# Parse a CPV string into a Cpv object.
448+
# Parse a string into a Cpv object.
380449
#
381450
# Returns NULL on error.
382451
#
@@ -496,12 +565,11 @@ cdef extern from "pkgcraft.h":
496565
# The arguments must be non-null Dep pointers.
497566
int pkgcraft_dep_cmp(Dep *d1, Dep *d2)
498567

499-
# Get the category and package of a package dependency.
500-
# For example, the package dependency "=cat/pkg-1-r2" returns "cat/pkg".
568+
# Get the Cpn of a package dependency.
501569
#
502570
# # Safety
503571
# The argument must be a non-null Dep pointer.
504-
char *pkgcraft_dep_cpn(Dep *d)
572+
Cpn *pkgcraft_dep_cpn(Dep *d)
505573

506574
# Get the category, package, and version of a package dependency.
507575
# For example, the package dependency "=cat/pkg-1-r2" returns "cat/pkg-1-r2".
@@ -554,14 +622,6 @@ cdef extern from "pkgcraft.h":
554622
Dep *pkgcraft_dep_new(const char *s,
555623
const Eapi *eapi)
556624

557-
# Parse a string into an unversioned package dependency.
558-
#
559-
# Returns NULL on error.
560-
#
561-
# # Safety
562-
# The argument must be a UTF-8 string.
563-
Dep *pkgcraft_dep_new_cpn(const char *s)
564-
565625
# Get the package and revision of a package dependency.
566626
# For example, the package dependency "=cat/pkg-1-r2" returns "pkg-1".
567627
#

src/pkgcraft/dep/__init__.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .base cimport *
2+
from .cpn cimport *
23
from .cpv cimport *
34
from .pkg cimport *
45
from .use cimport *

src/pkgcraft/dep/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .base import *
2+
from .cpn import *
23
from .cpv import *
34
from .pkg import *
45
from .use import *

src/pkgcraft/dep/cpn.pxd

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from .. cimport C
2+
3+
4+
cdef class Cpn:
5+
cdef C.Cpn *ptr
6+
# cached fields
7+
cdef str _category
8+
cdef str _package
9+
cdef int _hash
10+
11+
@staticmethod
12+
cdef Cpn from_ptr(C.Cpn *)

src/pkgcraft/dep/cpn.pyx

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
cimport cython
2+
3+
from .. cimport C
4+
from .._misc cimport cstring_to_str
5+
from ..restrict cimport Restrict
6+
7+
from ..error import InvalidCpn
8+
9+
10+
@cython.final
11+
cdef class Cpn:
12+
"""Unversioned package."""
13+
14+
def __init__(self, s: str):
15+
"""Create a new Cpn object.
16+
17+
Valid:
18+
19+
>>> from pkgcraft.dep import Cpn
20+
>>> cpn = Cpn('cat/pkg')
21+
>>> cpn.category
22+
'cat'
23+
>>> cpn.package
24+
'pkg'
25+
26+
Invalid:
27+
28+
>>> Cpn('>cat/pkg-1')
29+
Traceback (most recent call last):
30+
...
31+
pkgcraft.error.InvalidCpn: parsing failure: invalid cpn: >cat/pkg-1
32+
...
33+
"""
34+
self.ptr = C.pkgcraft_cpn_new(s.encode())
35+
if self.ptr is NULL:
36+
raise InvalidCpn
37+
38+
@staticmethod
39+
def parse(s: str, raised=False):
40+
"""Determine if a string is a valid package Cpn.
41+
42+
This avoids any allocations, only returning the validity status.
43+
44+
Args:
45+
s: the string to parse
46+
raised: if True, raise an exception when invalid
47+
48+
Returns:
49+
bool: True if the given string represents a valid Cpn, otherwise False.
50+
51+
Raises:
52+
InvalidCpn: on failure if the raised parameter is set to True
53+
54+
>>> from pkgcraft.dep import Cpn
55+
>>> Cpn.parse('cat/pkg')
56+
True
57+
"""
58+
valid = C.pkgcraft_cpn_parse(s.encode()) is not NULL
59+
if not valid and raised:
60+
raise InvalidCpn
61+
return valid
62+
63+
@staticmethod
64+
cdef Cpn from_ptr(C.Cpn *ptr):
65+
"""Create a Cpn from a pointer."""
66+
inst = <Cpn>Cpn.__new__(Cpn)
67+
inst.ptr = <C.Cpn *>ptr
68+
return inst
69+
70+
@property
71+
def category(self):
72+
"""Get the category of a Cpn.
73+
74+
Returns:
75+
str: the category name
76+
77+
>>> from pkgcraft.dep import Cpn
78+
>>> cpn = Cpn('cat/pkg')
79+
>>> cpn.category
80+
'cat'
81+
"""
82+
if self._category is None:
83+
self._category = cstring_to_str(C.pkgcraft_cpn_category(self.ptr))
84+
return self._category
85+
86+
@property
87+
def package(self):
88+
"""Get the package name of a Cpn.
89+
90+
Returns:
91+
str: the package name
92+
93+
>>> from pkgcraft.dep import Cpn
94+
>>> cpn = Cpn('cat/pkg')
95+
>>> cpn.package
96+
'pkg'
97+
"""
98+
if self._package is None:
99+
self._package = cstring_to_str(C.pkgcraft_cpn_package(self.ptr))
100+
return self._package
101+
102+
def matches(self, r: Restrict):
103+
"""Determine if a restriction matches a Cpn.
104+
105+
Args:
106+
r: restriction object to match against
107+
108+
Returns:
109+
bool: True if matching, otherwise False.
110+
"""
111+
return C.pkgcraft_cpn_restrict_matches(self.ptr, r.ptr)
112+
113+
def __lt__(self, other):
114+
if isinstance(other, Cpn):
115+
return C.pkgcraft_cpn_cmp(self.ptr, (<Cpn>other).ptr) == -1
116+
return NotImplemented
117+
118+
def __le__(self, other):
119+
if isinstance(other, Cpn):
120+
return C.pkgcraft_cpn_cmp(self.ptr, (<Cpn>other).ptr) <= 0
121+
return NotImplemented
122+
123+
def __eq__(self, other):
124+
if isinstance(other, Cpn):
125+
return C.pkgcraft_cpn_cmp(self.ptr, (<Cpn>other).ptr) == 0
126+
return NotImplemented
127+
128+
def __ne__(self, other):
129+
if isinstance(other, Cpn):
130+
return C.pkgcraft_cpn_cmp(self.ptr, (<Cpn>other).ptr) != 0
131+
return NotImplemented
132+
133+
def __ge__(self, other):
134+
if isinstance(other, Cpn):
135+
return C.pkgcraft_cpn_cmp(self.ptr, (<Cpn>other).ptr) >= 0
136+
return NotImplemented
137+
138+
def __gt__(self, other):
139+
if isinstance(other, Cpn):
140+
return C.pkgcraft_cpn_cmp(self.ptr, (<Cpn>other).ptr) == 1
141+
return NotImplemented
142+
143+
def __str__(self):
144+
return cstring_to_str(C.pkgcraft_cpn_str(self.ptr))
145+
146+
def __repr__(self):
147+
addr = <size_t>&self.ptr
148+
name = self.__class__.__name__
149+
return f"<{name} '{self}' at 0x{addr:0x}>"
150+
151+
def __hash__(self):
152+
if not self._hash:
153+
self._hash = C.pkgcraft_cpn_hash(self.ptr)
154+
return self._hash
155+
156+
def __reduce__(self):
157+
"""Support pickling Cpn objects."""
158+
return self.__class__, (str(self),)
159+
160+
def __dealloc__(self):
161+
C.pkgcraft_cpn_free(self.ptr)

src/pkgcraft/dep/cpv.pyx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ cimport cython
33
from .. cimport C
44
from .._misc cimport cstring_to_str
55
from ..restrict cimport Restrict
6-
from . cimport Dep
6+
from .cpn cimport Cpn
7+
from .pkg cimport Dep
78
from .version cimport Version
89

910
from ..error import InvalidCpv, PkgcraftError
@@ -263,14 +264,14 @@ cdef class Cpv:
263264

264265
@property
265266
def cpn(self):
266-
"""Get the category and package of a Cpv.
267+
"""Get the Cpn of a Cpv.
267268
268269
>>> from pkgcraft.dep import Cpv
269270
>>> cpv = Cpv('cat/pkg-1-r2')
270-
>>> cpv.cpn
271+
>>> str(cpv.cpn)
271272
'cat/pkg'
272273
"""
273-
return cstring_to_str(C.pkgcraft_cpv_cpn(self.ptr))
274+
return Cpn.from_ptr(C.pkgcraft_cpv_cpn(self.ptr))
274275

275276
def matches(self, r: Restrict):
276277
"""Determine if a restriction matches a Cpv.

src/pkgcraft/dep/pkg.pxd

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,3 @@ cdef class Dep:
2222

2323
@staticmethod
2424
cdef Dep from_ptr(C.Dep *)
25-
26-
27-
cdef class Cpn(Dep):
28-
pass

0 commit comments

Comments
 (0)