pkgcraft/
repo.rs

1use std::cmp::Ordering;
2use std::ffi::{c_char, c_int};
3use std::ptr;
4
5use pkgcraft::dep::{Cpv, Version};
6use pkgcraft::pkg::Pkg;
7use pkgcraft::repo::{PkgRepository, Repo, RepoFormat, Repository};
8use pkgcraft::restrict::Restrict;
9use pkgcraft::traits::Contains;
10use pkgcraft::utils::hash;
11
12use crate::macros::*;
13use crate::panic::ffi_catch_panic;
14use crate::types::{RepoIter, RepoIterCpv, RepoIterRestrict};
15use crate::utils::{boxed, str_to_raw};
16
17pub mod ebuild;
18pub mod ebuild_temp;
19pub mod fake;
20pub mod set;
21
22/// Load a repo from a given path.
23///
24/// Returns NULL on error.
25///
26/// # Safety
27/// The path argument should be a valid path on the system.
28#[no_mangle]
29pub unsafe extern "C" fn pkgcraft_repo_from_path(
30    id: *const c_char,
31    priority: c_int,
32    path: *const c_char,
33    finalize: bool,
34) -> *mut Repo {
35    ffi_catch_panic! {
36        let path = try_str_from_ptr!(path);
37        let id = if id.is_null() {
38            path
39        } else {
40            try_str_from_ptr!(id)
41        };
42
43        let repo = unwrap_or_panic!(Repo::from_path(id, path, priority, finalize));
44        Box::into_raw(Box::new(repo))
45    }
46}
47
48/// Try to load a certain repo type from a given path.
49///
50/// Returns NULL on error.
51///
52/// # Safety
53/// The path argument should be a valid path on the system.
54#[no_mangle]
55pub unsafe extern "C" fn pkgcraft_repo_from_format(
56    format: RepoFormat,
57    id: *const c_char,
58    priority: c_int,
59    path: *const c_char,
60    finalize: bool,
61) -> *mut Repo {
62    ffi_catch_panic! {
63        let path = try_str_from_ptr!(path);
64        let id = if id.is_null() {
65            path
66        } else {
67            try_str_from_ptr!(id)
68        };
69
70        let repo = unwrap_or_panic!(format.load_from_path(id, path, priority, finalize));
71        Box::into_raw(Box::new(repo))
72    }
73}
74
75/// Return a repos's format.
76///
77/// # Safety
78/// The argument must be a non-null Repo pointer.
79#[no_mangle]
80pub unsafe extern "C" fn pkgcraft_repo_format(r: *mut Repo) -> RepoFormat {
81    let repo = try_ref_from_ptr!(r);
82    repo.format()
83}
84
85/// Return a repo's id.
86///
87/// # Safety
88/// The argument must be a non-null Repo pointer.
89#[no_mangle]
90pub unsafe extern "C" fn pkgcraft_repo_id(r: *mut Repo) -> *mut c_char {
91    let repo = try_ref_from_ptr!(r);
92    try_ptr_from_str!(repo.id())
93}
94
95/// Return a repo's path.
96///
97/// # Safety
98/// The argument must be a non-null Repo pointer.
99#[no_mangle]
100pub unsafe extern "C" fn pkgcraft_repo_path(r: *mut Repo) -> *mut c_char {
101    let repo = try_ref_from_ptr!(r);
102    try_ptr_from_str!(repo.path().as_str())
103}
104
105/// Return a repo's length.
106///
107/// # Safety
108/// The argument must be a non-null Repo pointer.
109#[no_mangle]
110pub unsafe extern "C" fn pkgcraft_repo_len(r: *mut Repo) -> usize {
111    let repo = try_ref_from_ptr!(r);
112    repo.len()
113}
114
115/// Determine if a repo is empty.
116///
117/// # Safety
118/// The argument must be a non-null Repo pointer.
119#[no_mangle]
120pub unsafe extern "C" fn pkgcraft_repo_is_empty(r: *mut Repo) -> bool {
121    let repo = try_ref_from_ptr!(r);
122    repo.is_empty()
123}
124
125/// Return a repo's categories.
126///
127/// # Safety
128/// The argument must be a non-null Repo pointer.
129#[no_mangle]
130pub unsafe extern "C" fn pkgcraft_repo_categories(
131    r: *mut Repo,
132    len: *mut usize,
133) -> *mut *mut c_char {
134    let repo = try_ref_from_ptr!(r);
135    iter_to_array!(repo.categories().iter(), len, str_to_raw)
136}
137
138/// Return a repo's packages for a category.
139///
140/// # Safety
141/// The arguments must be a non-null Repo pointer and category.
142#[no_mangle]
143pub unsafe extern "C" fn pkgcraft_repo_packages(
144    r: *mut Repo,
145    cat: *const c_char,
146    len: *mut usize,
147) -> *mut *mut c_char {
148    let repo = try_ref_from_ptr!(r);
149    let cat = try_str_from_ptr!(cat);
150    iter_to_array!(repo.packages(cat).iter(), len, str_to_raw)
151}
152
153/// Return a repo's versions for a package.
154///
155/// # Safety
156/// The arguments must be a non-null Repo pointer, category, and package.
157#[no_mangle]
158pub unsafe extern "C" fn pkgcraft_repo_versions(
159    r: *mut Repo,
160    cat: *const c_char,
161    pkg: *const c_char,
162    len: *mut usize,
163) -> *mut *mut Version {
164    let repo = try_ref_from_ptr!(r);
165    let cat = try_str_from_ptr!(cat);
166    let pkg = try_str_from_ptr!(pkg);
167    iter_to_array!(repo.versions(cat, pkg).into_iter(), len, boxed)
168}
169
170/// Compare two repos returning -1, 0, or 1 if the first repo is less than, equal to, or greater
171/// than the second repo, respectively.
172///
173/// # Safety
174/// The arguments must be non-null Repo pointers.
175#[no_mangle]
176pub unsafe extern "C" fn pkgcraft_repo_cmp(r1: *mut Repo, r2: *mut Repo) -> c_int {
177    let repo1 = try_ref_from_ptr!(r1);
178    let repo2 = try_ref_from_ptr!(r2);
179
180    match repo1.cmp(repo2) {
181        Ordering::Less => -1,
182        Ordering::Equal => 0,
183        Ordering::Greater => 1,
184    }
185}
186
187/// Return the hash value for a repo.
188///
189/// # Safety
190/// The argument must be a non-null Repo pointer.
191#[no_mangle]
192pub unsafe extern "C" fn pkgcraft_repo_hash(r: *mut Repo) -> u64 {
193    let repo = try_ref_from_ptr!(r);
194    hash(repo)
195}
196
197/// Determine if a path is in a repo.
198///
199/// # Safety
200/// The argument must be a non-null Repo pointer.
201#[no_mangle]
202pub unsafe extern "C" fn pkgcraft_repo_contains_path(r: *mut Repo, path: *const c_char) -> bool {
203    let repo = try_ref_from_ptr!(r);
204    let path = try_str_from_ptr!(path);
205    repo.contains(path)
206}
207
208/// Free a repo.
209///
210/// # Safety
211/// The argument must be a Repo pointer or NULL.
212#[no_mangle]
213pub unsafe extern "C" fn pkgcraft_repo_free(r: *mut Repo) {
214    if !r.is_null() {
215        unsafe { drop(Box::from_raw(r)) };
216    }
217}
218
219/// Return a Cpv iterator for a repo.
220///
221/// # Safety
222/// The argument must be a non-null Repo pointer.
223#[no_mangle]
224pub unsafe extern "C" fn pkgcraft_repo_iter_cpv<'a>(r: *mut Repo) -> *mut RepoIterCpv<'a> {
225    let repo = try_ref_from_ptr!(r);
226    Box::into_raw(Box::new(repo.iter_cpv()))
227}
228
229/// Return the next Cpv from a repo Cpv iterator.
230///
231/// Returns NULL when the iterator is empty.
232///
233/// # Safety
234/// The argument must be a non-null RepoIterCpv pointer.
235#[no_mangle]
236pub unsafe extern "C" fn pkgcraft_repo_iter_cpv_next(i: *mut RepoIterCpv) -> *mut Cpv {
237    let iter = try_mut_from_ptr!(i);
238    iter.next().map(boxed).unwrap_or(ptr::null_mut())
239}
240
241/// Free a repo Cpv iterator.
242///
243/// # Safety
244/// The argument must be a non-null RepoIterCpv pointer or NULL.
245#[no_mangle]
246pub unsafe extern "C" fn pkgcraft_repo_iter_cpv_free(i: *mut RepoIterCpv) {
247    if !i.is_null() {
248        unsafe { drop(Box::from_raw(i)) };
249    }
250}
251
252/// Return a package iterator for a repo.
253///
254/// # Safety
255/// The argument must be a non-null Repo pointer.
256#[no_mangle]
257pub unsafe extern "C" fn pkgcraft_repo_iter<'a>(r: *mut Repo) -> *mut RepoIter<'a> {
258    let repo = try_ref_from_ptr!(r);
259    Box::into_raw(Box::new(repo.iter()))
260}
261
262/// Return the next package from a package iterator.
263///
264/// Returns NULL when the iterator is empty.
265///
266/// # Safety
267/// The argument must be a non-null RepoIter pointer.
268#[no_mangle]
269pub unsafe extern "C" fn pkgcraft_repo_iter_next(i: *mut RepoIter) -> *mut Pkg {
270    let iter = try_mut_from_ptr!(i);
271    iter.next().map(boxed).unwrap_or(ptr::null_mut())
272}
273
274/// Free a repo iterator.
275///
276/// # Safety
277/// The argument must be a non-null RepoIter pointer or NULL.
278#[no_mangle]
279pub unsafe extern "C" fn pkgcraft_repo_iter_free(i: *mut RepoIter) {
280    if !i.is_null() {
281        unsafe { drop(Box::from_raw(i)) };
282    }
283}
284
285/// Return a restriction package iterator for a repo.
286///
287/// # Safety
288/// The repo argument must be a non-null Repo pointer and the restrict argument must be a non-null
289/// Restrict pointer.
290#[no_mangle]
291pub unsafe extern "C" fn pkgcraft_repo_iter_restrict<'a>(
292    repo: *mut Repo,
293    restrict: *mut Restrict,
294) -> *mut RepoIterRestrict<'a> {
295    let repo = try_ref_from_ptr!(repo);
296    let restrict = try_ref_from_ptr!(restrict);
297    Box::into_raw(Box::new(repo.iter_restrict(restrict.clone())))
298}
299
300/// Return the next package from a restriction package iterator.
301///
302/// Returns NULL when the iterator is empty.
303///
304/// # Safety
305/// The argument must be a non-null RepoIterRestrict pointer.
306#[no_mangle]
307pub unsafe extern "C" fn pkgcraft_repo_iter_restrict_next(i: *mut RepoIterRestrict) -> *mut Pkg {
308    let iter = try_mut_from_ptr!(i);
309    iter.next().map(boxed).unwrap_or(ptr::null_mut())
310}
311
312/// Free a repo restriction iterator.
313///
314/// # Safety
315/// The argument must be a non-null RepoIterRestrict pointer or NULL.
316#[no_mangle]
317pub unsafe extern "C" fn pkgcraft_repo_iter_restrict_free(i: *mut RepoIterRestrict) {
318    if !i.is_null() {
319        unsafe { drop(Box::from_raw(i)) };
320    }
321}