Skip to content
Snippets Groups Projects
Commit 866374c7 authored by Natanael Copa's avatar Natanael Copa Committed by Timo Teräs
Browse files

python: add initial python binding

So far we only implement:

- version_validate
- version_compare
- version_match

fixes: #11062
parent 0c318879
No related branches found
No related tags found
No related merge requests found
...@@ -14,6 +14,7 @@ apk_libdir = get_option('libdir') ...@@ -14,6 +14,7 @@ apk_libdir = get_option('libdir')
lua_bin = find_program('lua' + get_option('lua_version'), required: get_option('help')) lua_bin = find_program('lua' + get_option('lua_version'), required: get_option('help'))
lua_dep = dependency('lua' + get_option('lua_version'), required: get_option('lua')) lua_dep = dependency('lua' + get_option('lua_version'), required: get_option('lua'))
python_dep = dependency('python3', required: get_option('python'))
scdoc_dep = dependency('scdoc', version: '>=1.10', required: get_option('docs')) scdoc_dep = dependency('scdoc', version: '>=1.10', required: get_option('docs'))
zlib_dep = dependency('zlib') zlib_dep = dependency('zlib')
libzstd_dep = dependency('libzstd', required: get_option('zstd')) libzstd_dep = dependency('libzstd', required: get_option('zstd'))
...@@ -45,4 +46,7 @@ subdir('src') ...@@ -45,4 +46,7 @@ subdir('src')
if(lua_dep.found()) if(lua_dep.found())
subdir('lua') subdir('lua')
endif endif
if(python_dep.found())
subdir('python')
endif
subdir('test') subdir('test')
...@@ -6,6 +6,7 @@ option('docs', description: 'Build manpages with scdoc', type: 'feature', value: ...@@ -6,6 +6,7 @@ option('docs', description: 'Build manpages with scdoc', type: 'feature', value:
option('help', description: 'Build help into apk binaries, needs lua', type: 'feature', value: 'auto') option('help', description: 'Build help into apk binaries, needs lua', type: 'feature', value: 'auto')
option('lua', description: 'Build luaapk (lua bindings)', type: 'feature', value: 'auto') option('lua', description: 'Build luaapk (lua bindings)', type: 'feature', value: 'auto')
option('lua_version', description: 'Lua version to build against', type: 'string', value: '5.3') option('lua_version', description: 'Lua version to build against', type: 'string', value: '5.3')
option('python', description: 'Build python binding', type: 'feature', value: 'auto')
option('tests', description: 'Build tests', type: 'feature', value: 'auto') option('tests', description: 'Build tests', type: 'feature', value: 'auto')
option('url_backend', description: 'URL backend', type: 'combo', choices: ['libfetch', 'wget'], value: 'libfetch') option('url_backend', description: 'URL backend', type: 'combo', choices: ['libfetch', 'wget'], value: 'libfetch')
option('uvol_db_target', description: 'Default target for uvol database layer', type: 'string') option('uvol_db_target', description: 'Default target for uvol database layer', type: 'string')
......
/*
* Copyright (C) 2025 apk-tools authors
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "apk_blob.h"
#include "apk_version.h"
static apk_blob_t python_str_to_blob(PyObject *py_str) {
const char *str;
Py_ssize_t len;
str = PyUnicode_AsUTF8AndSize(py_str, &len);
apk_blob_t blob = APK_BLOB_PTR_LEN((char *) str, len);
return blob;
}
/* version_validate(verstr) -> bool */
static PyObject *version_validate(PyObject *self, PyObject *args) {
PyObject *py_verstr;
if (!PyArg_ParseTuple(args, "U", &py_verstr)) {
return NULL;
}
apk_blob_t ver = python_str_to_blob(py_verstr);
int result = apk_version_validate(ver);
return PyBool_FromLong(result);
}
/* version_compare(verstr1, verstr2) -> int */
static PyObject *version_compare(PyObject *self, PyObject *args) {
PyObject *py_verstr1, *py_verstr2;
if (!PyArg_ParseTuple(args, "UU", &py_verstr1, &py_verstr2)) {
return NULL;
}
apk_blob_t ver1 = python_str_to_blob(py_verstr1);
apk_blob_t ver2 = python_str_to_blob(py_verstr2);
return PyLong_FromLong(apk_version_compare(ver1, ver2));
}
/* version_match(verstr1, op, verstr2) -> bool */
static PyObject *version_match(PyObject *self, PyObject *args) {
PyObject *py_verstr1, *py_verstr2;
int op;
if (!PyArg_ParseTuple(args, "UiU", &py_verstr1, &op, &py_verstr2)) {
return NULL;
}
apk_blob_t ver1 = python_str_to_blob(py_verstr1);
apk_blob_t ver2 = python_str_to_blob(py_verstr2);
int result = apk_version_match(ver1, op, ver2);
return PyBool_FromLong(result);
}
static PyMethodDef ApkMethods[] = {
{"version_validate", version_validate, METH_VARARGS, "Validate a version string."},
{"version_compare", version_compare, METH_VARARGS, "Compare two version strings. Returns an integer"},
{"version_match", version_match, METH_VARARGS, "Match two version strings with a specified operation."},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef apkmodule = {
PyModuleDef_HEAD_INIT,
"apk", // Module name
"Python bindings for libapk version functions.",
-1,
ApkMethods
};
PyMODINIT_FUNC PyInit_apk(void) {
PyObject *module = PyModule_Create(&apkmodule);
if (!module) {
return NULL;
}
PyModule_AddIntConstant(module, "VERSION_UNKNOWN", APK_VERSION_UNKNOWN);
PyModule_AddIntConstant(module, "VERSION_EQUAL", APK_VERSION_EQUAL);
PyModule_AddIntConstant(module, "VERSION_LESS", APK_VERSION_LESS);
PyModule_AddIntConstant(module, "VERSION_GREATER", APK_VERSION_GREATER);
PyModule_AddIntConstant(module, "VERSION_FUZZY", APK_VERSION_FUZZY);
PyModule_AddIntConstant(module, "VERSION_CONFLICT", APK_VERSION_CONFLICT);
return module;
}
py_mod = import('python')
py_inst = py_mod.find_installation('python3')
py_ext = shared_module(
'apk',
sources: files('apk_module.c'),
dependencies: [
libapk_dep,
python_dep,
apk_deps,
libportability_dep.partial_dependency(includes: true),
],
install: true,
gnu_symbol_visibility: 'hidden',
name_prefix: '',
name_suffix: py_inst.get_variable('EXT_SUFFIX').strip('.'),
c_args: apk_cargs,
install_dir: py_inst.get_install_dir(),
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment