Discussion:
[SATYR PATCH 0/8] Python bindings for the report structure
Martin Milata
2013-08-26 14:48:59 UTC
Permalink
Please note that this patchset depends on following, as of yet unreviewed
patches:

[SATYR PATCHv3 1/7] Add sr_java_frame_append
[SATYR PATCHv3 2/7] Helper functions for json deserialization
[SATYR PATCHv3 3/7] Implement JSON deserialization for reports
[SATYR PATCHv3 4/7] Type-agnostic JSON deserialization
[SATYR PATCHv3 5/7] python: add version attribute to Kerneloops object
[SATYR PATCHv3 6/7] python: expose from_json for stacktraces
[SATYR PATCHv3 7/7] tests for json deserialization of stacktraces
[SATYR PATCHv3] python: treat UINT64_MAX as None

* * *

Martin Milata (8):
python: bindings for struct sr_operating_system
python: bindings for struct sr_rpm_package
Minor json parsing refactorization
report: function for parsing json text
Helpers for converting report type to/from string
report: use generic stacktrace type
python: factor out stacktrace object creation
python: bindings for struct sr_report

include/json.h | 2 +-
include/report.h | 14 +-
include/report_type.h | 8 +
lib/Makefile.am | 2 +-
lib/abrt.c | 34 +--
lib/core_stacktrace.c | 19 +-
lib/generic_stacktrace.c | 15 +-
lib/json.c | 10 +-
lib/report.c | 129 +++++------
python/Makefile.am | 6 +
python/py_common.c | 7 +
python/py_common.h | 4 +
python/py_core_stacktrace.c | 64 +++---
python/py_core_stacktrace.h | 3 +
python/py_java_stacktrace.c | 65 +++---
python/py_java_stacktrace.h | 3 +
python/py_koops_stacktrace.c | 59 +++--
python/py_koops_stacktrace.h | 3 +
python/py_module.c | 35 +++
python/py_operating_system.c | 167 ++++++++++++++
python/py_operating_system.h | 63 ++++++
python/py_python_stacktrace.c | 59 +++--
python/py_python_stacktrace.h | 3 +
python/py_report.c | 491 ++++++++++++++++++++++++++++++++++++++++++
python/py_report.h | 79 +++++++
python/py_rpm_package.c | 225 +++++++++++++++++++
python/py_rpm_package.h | 67 ++++++
tests/Makefile.am | 1 +
tests/json_files/ureport-1 | 107 +++++++++
tests/python/report.py | 88 ++++++++
tests/python_bindings.at | 1 +
tests/report.at | 59 +++++
tests/testsuite.at | 1 +
33 files changed, 1625 insertions(+), 268 deletions(-)
create mode 100644 python/py_operating_system.c
create mode 100644 python/py_operating_system.h
create mode 100644 python/py_report.c
create mode 100644 python/py_report.h
create mode 100644 python/py_rpm_package.c
create mode 100644 python/py_rpm_package.h
create mode 100644 tests/json_files/ureport-1
create mode 100755 tests/python/report.py
create mode 100644 tests/report.at
--
1.8.3.1
Martin Milata
2013-08-26 14:49:00 UTC
Permalink
Needed for #86.

Signed-off-by: Martin Milata <mmilata-H+wXaHxf7aLQT0dZR+***@public.gmane.org>
---
python/Makefile.am | 2 +
python/py_module.c | 10 +++
python/py_operating_system.c | 167 +++++++++++++++++++++++++++++++++++++++++++
python/py_operating_system.h | 63 ++++++++++++++++
tests/python/report.py | 23 ++++++
tests/python_bindings.at | 1 +
6 files changed, 266 insertions(+)
create mode 100644 python/py_operating_system.c
create mode 100644 python/py_operating_system.h
create mode 100755 tests/python/report.py

diff --git a/python/Makefile.am b/python/Makefile.am
index 95a81c0..fab2c13 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -44,6 +44,8 @@ _satyr_la_SOURCES = \
py_java_stacktrace.c \
py_metrics.h \
py_metrics.c \
+ py_operating_system.h \
+ py_operating_system.c \
py_common.h \
py_common.c \
py_module.c
diff --git a/python/py_module.c b/python/py_module.c
index 23c8882..763ffaf 100644
--- a/python/py_module.c
+++ b/python/py_module.c
@@ -18,6 +18,7 @@
#include "py_core_thread.h"
#include "py_core_stacktrace.h"
#include "py_metrics.h"
+#include "py_operating_system.h"

#include "distance.h"
#include "thread.h"
@@ -157,6 +158,12 @@ init_satyr()
return;
}

+ if (PyType_Ready(&sr_py_operating_system_type) < 0)
+ {
+ puts("PyType_Ready(&sr_py_operating_system_type) < 0");
+ return;
+ }
+

PyObject *module = Py_InitModule("_satyr", module_methods);
if (!module)
@@ -264,4 +271,7 @@ init_satyr()
PyModule_AddObject(module, "CoreStacktrace",
(PyObject *)&sr_py_core_stacktrace_type);

+ Py_INCREF(&sr_py_operating_system_type);
+ PyModule_AddObject(module, "OperatingSystem",
+ (PyObject *)&sr_py_operating_system_type);
}
diff --git a/python/py_operating_system.c b/python/py_operating_system.c
new file mode 100644
index 0000000..0974d7a
--- /dev/null
+++ b/python/py_operating_system.c
@@ -0,0 +1,167 @@
+/*
+ py_operating_system.c
+
+ Copyright (C) 2013 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "py_common.h"
+#include "py_operating_system.h"
+
+#include "operating_system.h"
+#include "strbuf.h"
+
+#define operating_system_doc "satyr.OperatingSystem - describes an operating system\n" \
+ "Usage:\n" \
+ "satyr.OperatingSystem() - creates an empty operating system object\n" \
+ "satyr.OperatingSystem(name, version, arch) - creates an operating system\n" \
+ "object with given properties (all arguments are strings or None)"
+
+/* See python/py_common.h and python/py_gdb_frame.c for generic getters/setters documentation. */
+#define GSOFF_PY_STRUCT sr_py_operating_system
+#define GSOFF_PY_MEMBER operating_system
+#define GSOFF_C_STRUCT sr_operating_system
+GSOFF_START
+GSOFF_MEMBER(name),
+GSOFF_MEMBER(version),
+GSOFF_MEMBER(architecture),
+GSOFF_MEMBER(cpe),
+GSOFF_MEMBER(uptime)
+GSOFF_END
+
+static PyGetSetDef
+operating_system_getset[] =
+{
+ SR_ATTRIBUTE_STRING(name, "Operating system name (string)" ),
+ SR_ATTRIBUTE_STRING(version, "Version (string)" ),
+ SR_ATTRIBUTE_STRING(architecture, "Architecture (string)" ),
+ SR_ATTRIBUTE_STRING(cpe, "Common platform enumeration identifier (string)" ),
+ SR_ATTRIBUTE_UINT64(uptime, "Machine uptime (long)" ),
+ { NULL },
+};
+
+PyTypeObject
+sr_py_operating_system_type =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "satyr.OperatingSystem", /* tp_name */
+ sizeof(struct sr_py_operating_system), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ sr_py_operating_system_free,/* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL, /* tp_hash */
+ NULL, /* tp_call */
+ sr_py_operating_system_str, /* tp_str */
+ NULL, /* tp_getattro */
+ NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ operating_system_doc, /* tp_doc */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ NULL, /* tp_methods */
+ NULL, /* tp_members */
+ operating_system_getset, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ NULL, /* tp_init */
+ NULL, /* tp_alloc */
+ sr_py_operating_system_new, /* tp_new */
+ NULL, /* tp_free */
+ NULL, /* tp_is_gc */
+ NULL, /* tp_bases */
+ NULL, /* tp_mro */
+ NULL, /* tp_cache */
+ NULL, /* tp_subclasses */
+ NULL, /* tp_weaklist */
+};
+
+/* constructor */
+PyObject *
+sr_py_operating_system_new(PyTypeObject *object, PyObject *args, PyObject *kwds)
+{
+ struct sr_py_operating_system *os =
+ PyObject_New(struct sr_py_operating_system, &sr_py_operating_system_type);
+
+ if (!os)
+ return PyErr_NoMemory();
+
+ os->operating_system = sr_operating_system_new();
+
+ const char *name = NULL, *version = NULL, *arch = NULL;
+ if (!PyArg_ParseTuple(args, "|sss", &name, &version, &arch))
+ return NULL;
+
+ if (name)
+ os->operating_system->name = sr_strdup(name);
+
+ if (version)
+ os->operating_system->version = sr_strdup(version);
+
+ if (arch)
+ os->operating_system->architecture = sr_strdup(arch);
+
+ return (PyObject*)os;
+}
+
+/* destructor */
+void
+sr_py_operating_system_free(PyObject *object)
+{
+ struct sr_py_operating_system *this = (struct sr_py_operating_system *)object;
+ sr_operating_system_free(this->operating_system);
+ PyObject_Del(object);
+}
+
+/* str */
+PyObject *
+sr_py_operating_system_str(PyObject *object)
+{
+ struct sr_py_operating_system *this = (struct sr_py_operating_system*)object;
+ struct sr_strbuf *buf = sr_strbuf_new();
+
+ sr_strbuf_append_str(buf,
+ this->operating_system->name ? this->operating_system->name : "(unknown)");
+
+ if (this->operating_system->version)
+ sr_strbuf_append_strf(buf, " %s", this->operating_system->version);
+
+ if (this->operating_system->architecture)
+ sr_strbuf_append_strf(buf, " (%s)", this->operating_system->architecture);
+
+ if (this->operating_system->cpe)
+ sr_strbuf_append_strf(buf, ", CPE: %s", this->operating_system->cpe);
+
+ char *str = sr_strbuf_free_nobuf(buf);
+ PyObject *result = Py_BuildValue("s", str);
+ free(str);
+ return result;
+}
diff --git a/python/py_operating_system.h b/python/py_operating_system.h
new file mode 100644
index 0000000..bcd8e7f
--- /dev/null
+++ b/python/py_operating_system.h
@@ -0,0 +1,63 @@
+/*
+ py_operating_system.h
+
+ Copyright (C) 2013 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef SATYR_PY_OPERATING_SYSTEM_H
+#define SATYR_PY_OPERATING_SYSTEM_H
+
+/**
+ * @file
+ * @brief Python bindings for operating system.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Python.h>
+#include <structmember.h>
+
+PyTypeObject sr_py_operating_system_type;
+
+struct sr_py_operating_system
+{
+ PyObject_HEAD
+ struct sr_operating_system *operating_system;
+};
+
+/**
+ * Constructor.
+ */
+PyObject *sr_py_operating_system_new(PyTypeObject *object,
+ PyObject *args, PyObject *kwds);
+
+/**
+ * Destructor.
+ */
+void sr_py_operating_system_free(PyObject *object);
+
+/**
+ * str
+ */
+PyObject *sr_py_operating_system_str(PyObject *self);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tests/python/report.py b/tests/python/report.py
new file mode 100755
index 0000000..7580fb5
--- /dev/null
+++ b/tests/python/report.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+import unittest
+from test_helpers import *
+
+class TestOperatingSystem(BindingsTestCase):
+ def setUp(self):
+ self.opsys = satyr.OperatingSystem('fedora', '19', 'x86_64')
+
+ def test_str(self):
+ self.assertEqual(str(self.opsys), 'fedora 19 (x86_64)')
+
+ def test_getset(self):
+ self.assertGetSetCorrect(self.opsys, 'name', 'fedora', 'debian')
+ self.assertGetSetCorrect(self.opsys, 'version', '19', 'XP')
+ self.assertGetSetCorrect(self.opsys, 'architecture', 'x86_64', 's390x')
+ self.assertGetSetCorrect(self.opsys, 'uptime', 0, 9000)
+ self.assertGetSetCorrect(self.opsys, 'cpe', None, 'cpe:/o:fedoraproject:fedora:19')
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/tests/python_bindings.at b/tests/python_bindings.at
index a7ab98d..1433864 100644
--- a/tests/python_bindings.at
+++ b/tests/python_bindings.at
@@ -12,3 +12,4 @@ AT_TEST_PYTHON([python])
AT_TEST_PYTHON([java])
AT_TEST_PYTHON([core])
AT_TEST_PYTHON([metrics])
+AT_TEST_PYTHON([report])
--
1.8.3.1
Martin Milata
2013-08-26 14:49:01 UTC
Permalink
Needed for #86.

Signed-off-by: Martin Milata <mmilata-H+wXaHxf7aLQT0dZR+***@public.gmane.org>
---
python/Makefile.am | 2 +
python/py_module.c | 15 ++++
python/py_rpm_package.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++
python/py_rpm_package.h | 67 ++++++++++++++
tests/python/report.py | 16 ++++
5 files changed, 325 insertions(+)
create mode 100644 python/py_rpm_package.c
create mode 100644 python/py_rpm_package.h

diff --git a/python/Makefile.am b/python/Makefile.am
index fab2c13..34491c1 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -42,6 +42,8 @@ _satyr_la_SOURCES = \
py_java_thread.c \
py_java_stacktrace.h \
py_java_stacktrace.c \
+ py_rpm_package.h \
+ py_rpm_package.c \
py_metrics.h \
py_metrics.c \
py_operating_system.h \
diff --git a/python/py_module.c b/python/py_module.c
index 763ffaf..e566376 100644
--- a/python/py_module.c
+++ b/python/py_module.c
@@ -17,6 +17,7 @@
#include "py_core_frame.h"
#include "py_core_thread.h"
#include "py_core_stacktrace.h"
+#include "py_rpm_package.h"
#include "py_metrics.h"
#include "py_operating_system.h"

@@ -24,6 +25,7 @@
#include "thread.h"
#include "stacktrace.h"
#include "gdb/sharedlib.h"
+#include "rpm.h"

static PyMethodDef
module_methods[]=
@@ -164,6 +166,12 @@ init_satyr()
return;
}

+ if (PyType_Ready(&sr_py_rpm_package_type) < 0)
+ {
+ puts("PyType_Ready(&sr_py_rpm_package_type) < 0");
+ return;
+ }
+

PyObject *module = Py_InitModule("_satyr", module_methods);
if (!module)
@@ -274,4 +282,11 @@ init_satyr()
Py_INCREF(&sr_py_operating_system_type);
PyModule_AddObject(module, "OperatingSystem",
(PyObject *)&sr_py_operating_system_type);
+
+ Py_INCREF(&sr_py_rpm_package_type);
+ PyModule_AddObject(module, "RpmPackage",
+ (PyObject *)&sr_py_rpm_package_type);
+
+ PyModule_AddIntConstant(module, "ROLE_UNKNOWN", SR_ROLE_UNKNOWN);
+ PyModule_AddIntConstant(module, "ROLE_AFFECTED", SR_ROLE_AFFECTED);
}
diff --git a/python/py_rpm_package.c b/python/py_rpm_package.c
new file mode 100644
index 0000000..22165d7
--- /dev/null
+++ b/python/py_rpm_package.c
@@ -0,0 +1,225 @@
+/*
+ py_rpm_package.c
+
+ Copyright (C) 2013 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "py_common.h"
+#include "py_rpm_package.h"
+
+#include "rpm.h"
+#include "strbuf.h"
+
+#define rpm_package_doc "satyr.RpmPackage - RPM package representation\n" \
+ "Usage:\n" \
+ "satyr.RpmPackage() - creates an empty RPM package object\n" \
+ "satyr.RpmPackage(name, epoch, version, release, arch) - creates RPM package\n" \
+ "object with given properties"
+
+#define rpm_role_doc "Role the package plays in the problem. Currently ROLE_UNKNOWN or ROLE_AFFECTED."
+
+/* See python/py_common.h and python/py_gdb_frame.c for generic getters/setters documentation. */
+#define GSOFF_PY_STRUCT sr_py_rpm_package
+#define GSOFF_PY_MEMBER rpm_package
+#define GSOFF_C_STRUCT sr_rpm_package
+GSOFF_START
+GSOFF_MEMBER(name),
+GSOFF_MEMBER(epoch),
+GSOFF_MEMBER(version),
+GSOFF_MEMBER(release),
+GSOFF_MEMBER(architecture),
+GSOFF_MEMBER(install_time)
+/* GSOFF_MEMBER(role) */
+GSOFF_END
+
+static PyGetSetDef
+rpm_package_getset[] =
+{
+ SR_ATTRIBUTE_STRING(name, "Package name (string)" ),
+ SR_ATTRIBUTE_UINT32(epoch, "Epoch (int)" ),
+ SR_ATTRIBUTE_STRING(version, "Version (string)" ),
+ SR_ATTRIBUTE_STRING(release, "Release (string)" ),
+ SR_ATTRIBUTE_STRING(architecture, "Architecture (string)" ),
+ SR_ATTRIBUTE_UINT64(install_time, "Time of installation (long)" ),
+ { (char*)"role", sr_py_rpm_package_get_role, sr_py_rpm_package_set_role, (char*)rpm_role_doc, NULL },
+ { NULL },
+};
+
+PyTypeObject
+sr_py_rpm_package_type =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "satyr.RpmPackage", /* tp_name */
+ sizeof(struct sr_py_rpm_package), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ sr_py_rpm_package_free, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL, /* tp_hash */
+ NULL, /* tp_call */
+ sr_py_rpm_package_str, /* tp_str */
+ NULL, /* tp_getattro */
+ NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ rpm_package_doc, /* tp_doc */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ NULL, /* tp_methods */
+ NULL, /* tp_members */
+ rpm_package_getset, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ NULL, /* tp_init */
+ NULL, /* tp_alloc */
+ sr_py_rpm_package_new, /* tp_new */
+ NULL, /* tp_free */
+ NULL, /* tp_is_gc */
+ NULL, /* tp_bases */
+ NULL, /* tp_mro */
+ NULL, /* tp_cache */
+ NULL, /* tp_subclasses */
+ NULL, /* tp_weaklist */
+};
+
+/* constructor */
+PyObject *
+sr_py_rpm_package_new(PyTypeObject *object, PyObject *args, PyObject *kwds)
+{
+ struct sr_py_rpm_package *rpm =
+ PyObject_New(struct sr_py_rpm_package, &sr_py_rpm_package_type);
+
+ if (!rpm)
+ return PyErr_NoMemory();
+
+ rpm->rpm_package = sr_rpm_package_new();
+
+ unsigned int epoch;
+ const char *name = NULL, *version = NULL, *rel = NULL, *arch = NULL;
+ if (!PyArg_ParseTuple(args, "|sIsss", &name, &epoch, &version, &rel, &arch))
+ return NULL;
+
+ if (name)
+ rpm->rpm_package->name = sr_strdup(name);
+
+ if (rel)
+ rpm->rpm_package->release = sr_strdup(rel);
+
+ if (version)
+ rpm->rpm_package->version = sr_strdup(version);
+
+ if (arch)
+ rpm->rpm_package->architecture = sr_strdup(arch);
+
+ rpm->rpm_package->epoch = (uint32_t)epoch;
+
+ return (PyObject*)rpm;
+}
+
+/* destructor */
+void
+sr_py_rpm_package_free(PyObject *object)
+{
+ struct sr_py_rpm_package *this = (struct sr_py_rpm_package *)object;
+ sr_rpm_package_free(this->rpm_package, false);
+ PyObject_Del(object);
+}
+
+/* str */
+PyObject *
+sr_py_rpm_package_str(PyObject *object)
+{
+ struct sr_py_rpm_package *this = (struct sr_py_rpm_package*)object;
+ struct sr_strbuf *buf = sr_strbuf_new();
+
+ if (this->rpm_package->name)
+ {
+ sr_strbuf_append_str(buf, this->rpm_package->name);
+
+ if (this->rpm_package->version)
+ {
+ sr_strbuf_append_str(buf, "-");
+
+ if (this->rpm_package->epoch)
+ sr_strbuf_append_strf(buf, "%u:", (unsigned)this->rpm_package->epoch);
+
+ sr_strbuf_append_str(buf, this->rpm_package->version);
+
+ if (this->rpm_package->release)
+ {
+ sr_strbuf_append_strf(buf, "-%s", this->rpm_package->release);
+
+ if (this->rpm_package->architecture)
+ sr_strbuf_append_strf(buf, ".%s", this->rpm_package->architecture);
+ }
+ }
+
+ }
+ else
+ sr_strbuf_append_str(buf, "(unknown)");
+
+ char *str = sr_strbuf_free_nobuf(buf);
+ PyObject *result = Py_BuildValue("s", str);
+ free(str);
+ return result;
+}
+
+/* getters & setters */
+
+PyObject *
+sr_py_rpm_package_get_role(PyObject *self, void *data)
+{
+ return Py_BuildValue("i", ((struct sr_py_rpm_package*)self)->rpm_package->role);
+}
+
+int
+sr_py_rpm_package_set_role(PyObject *self, PyObject *rhs, void *data)
+{
+ if (rhs == NULL)
+ {
+ PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute.");
+ return -1;
+ }
+
+ long newvalue = PyInt_AsLong(rhs);
+ if (PyErr_Occurred())
+ return -1;
+
+ if (newvalue != SR_ROLE_UNKNOWN && newvalue != SR_ROLE_AFFECTED)
+ {
+ PyErr_SetString(PyExc_ValueError, "Role must be either ROLE_UNKNOWN "
+ "or ROLE_AFFECTED.");
+ return -1;
+ }
+
+ ((struct sr_py_rpm_package *)self)->rpm_package->role = newvalue;
+ return 0;
+}
diff --git a/python/py_rpm_package.h b/python/py_rpm_package.h
new file mode 100644
index 0000000..0a00d8d
--- /dev/null
+++ b/python/py_rpm_package.h
@@ -0,0 +1,67 @@
+/*
+ py_rpm_package.h
+
+ Copyright (C) 2013 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef SATYR_PY_RPM_PACKAGE_H
+#define SATYR_PY_RPM_PACKAGE_H
+
+/**
+ * @file
+ * @brief Python bindings for RPM package.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Python.h>
+#include <structmember.h>
+
+PyTypeObject sr_py_rpm_package_type;
+
+struct sr_py_rpm_package
+{
+ PyObject_HEAD
+ struct sr_rpm_package *rpm_package;
+};
+
+/**
+ * Constructor.
+ */
+PyObject *sr_py_rpm_package_new(PyTypeObject *object,
+ PyObject *args, PyObject *kwds);
+
+/**
+ * Destructor.
+ */
+void sr_py_rpm_package_free(PyObject *object);
+
+/**
+ * str
+ */
+PyObject *sr_py_rpm_package_str(PyObject *self);
+
+/* getters & setters */
+PyObject *sr_py_rpm_package_get_role(PyObject *self, void *data);
+int sr_py_rpm_package_set_role(PyObject *self, PyObject *rhs, void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tests/python/report.py b/tests/python/report.py
index 7580fb5..da00b08 100755
--- a/tests/python/report.py
+++ b/tests/python/report.py
@@ -17,6 +17,22 @@ class TestOperatingSystem(BindingsTestCase):
self.assertGetSetCorrect(self.opsys, 'uptime', 0, 9000)
self.assertGetSetCorrect(self.opsys, 'cpe', None, 'cpe:/o:fedoraproject:fedora:19')

+class TestRpmPackage(BindingsTestCase):
+ def setUp(self):
+ self.rpm = satyr.RpmPackage('emacs-filesystem', 1, '24.3', '11.fc19', 'noarch')
+
+ def test_str(self):
+ self.assertEqual(str(self.rpm), 'emacs-filesystem-1:24.3-11.fc19.noarch')
+
+ def test_getset(self):
+ self.assertGetSetCorrect(self.rpm, 'name', 'emacs-filesystem', 'msword')
+ self.assertGetSetCorrect(self.rpm, 'epoch', 1, 0)
+ self.assertGetSetCorrect(self.rpm, 'version', '24.3', '48')
+ self.assertGetSetCorrect(self.rpm, 'release', '11.fc19', '1.asdf')
+ self.assertGetSetCorrect(self.rpm, 'architecture', 'noarch', 'armv7hl')
+ self.assertGetSetCorrect(self.rpm, 'install_time', 0, 1234565)
+ self.assertGetSetCorrect(self.rpm, 'role', satyr.ROLE_UNKNOWN, satyr.ROLE_AFFECTED)
+

if __name__ == '__main__':
unittest.main()
--
1.8.3.1
Martin Milata
2013-08-26 14:49:02 UTC
Permalink
Avoid some code repetition, fix a memory leak.

Related to #86.

Signed-off-by: Martin Milata <mmilata-H+wXaHxf7aLQT0dZR+***@public.gmane.org>
---
include/json.h | 2 +-
lib/abrt.c | 20 ++------------------
lib/core_stacktrace.c | 19 ++++++-------------
lib/generic_stacktrace.c | 15 ++++++---------
lib/json.c | 10 ++++++++--
5 files changed, 23 insertions(+), 43 deletions(-)

diff --git a/include/json.h b/include/json.h
index 99370df..af3ddb3 100644
--- a/include/json.h
+++ b/include/json.h
@@ -108,7 +108,7 @@ struct sr_json_value
};

struct sr_json_value *
-sr_json_parse(const char *json);
+sr_json_parse(const char *json, char **error_message);

struct sr_json_value *
sr_json_parse_ex(struct sr_json_settings *settings,
diff --git a/lib/abrt.c b/lib/abrt.c
index cdee0c6..e59c30d 100644
--- a/lib/abrt.c
+++ b/lib/abrt.c
@@ -373,26 +373,10 @@ sr_abrt_report_from_dir(const char *directory,
return NULL;
}

- struct sr_json_settings settings;
- memset(&settings, 0, sizeof(struct sr_json_settings));
- struct sr_location location;
- sr_location_init(&location);
- struct sr_json_value *json_root = sr_json_parse_ex(&settings,
- core_backtrace_contents,
- &location);
+ report->core_stacktrace = sr_core_stacktrace_from_json_text(
+ core_backtrace_contents, error_message);

free(core_backtrace_contents);
- if (!json_root)
- {
- *error_message = sr_location_to_string(&location);
- sr_report_free(report);
- return NULL;
- }
-
- report->core_stacktrace = sr_core_stacktrace_from_json(json_root,
- error_message);
-
- sr_json_value_free(json_root);
if (!report->core_stacktrace)
{
sr_report_free(report);
diff --git a/lib/core_stacktrace.c b/lib/core_stacktrace.c
index 0e1bca1..f7fd369 100644
--- a/lib/core_stacktrace.c
+++ b/lib/core_stacktrace.c
@@ -213,22 +213,15 @@ struct sr_core_stacktrace *
sr_core_stacktrace_from_json_text(const char *text,
char **error_message)
{
- struct sr_json_settings settings;
- memset(&settings, 0, sizeof(struct sr_json_settings));
- struct sr_location location;
- sr_location_init(&location);
- struct sr_json_value *json_root = sr_json_parse_ex(&settings,
- text,
- &location);
-
+ struct sr_json_value *json_root = sr_json_parse(text, error_message);
if (!json_root)
- {
- *error_message = sr_location_to_string(&location);
return NULL;
- }

- return sr_core_stacktrace_from_json(json_root,
- error_message);
+ struct sr_core_stacktrace *stacktrace =
+ sr_core_stacktrace_from_json(json_root, error_message);
+
+ sr_json_value_free(json_root);
+ return stacktrace;
}

char *
diff --git a/lib/generic_stacktrace.c b/lib/generic_stacktrace.c
index 70d876f..feb1dbc 100644
--- a/lib/generic_stacktrace.c
+++ b/lib/generic_stacktrace.c
@@ -108,19 +108,16 @@ sr_stacktrace_from_json(enum sr_report_type type, struct sr_json_value *root, ch
struct sr_stacktrace *
sr_stacktrace_from_json_text(enum sr_report_type type, const char *input, char **error_message)
{
- struct sr_json_settings settings;
- memset(&settings, 0, sizeof(struct sr_json_settings));
- struct sr_location location;
- sr_location_init(&location);
- struct sr_json_value *json_root = sr_json_parse_ex(&settings, input, &location);
+ struct sr_json_value *json_root = sr_json_parse(input, error_message);

if (!json_root)
- {
- *error_message = sr_location_to_string(&location);
return NULL;
- }

- return sr_stacktrace_from_json(type, json_root, error_message);
+ struct sr_stacktrace *stacktrace =
+ sr_stacktrace_from_json(type, json_root, error_message);
+
+ sr_json_value_free(json_root);
+ return stacktrace;
}

char *
diff --git a/lib/json.c b/lib/json.c
index aa60c0a..35b7e6b 100644
--- a/lib/json.c
+++ b/lib/json.c
@@ -636,13 +636,19 @@ sr_json_parse_ex(struct sr_json_settings *settings,
}

struct sr_json_value *
-sr_json_parse(const char *json)
+sr_json_parse(const char *json, char **error_message)
{
struct sr_json_settings settings;
memset(&settings, 0, sizeof(struct sr_json_settings));
struct sr_location location;
sr_location_init(&location);
- return sr_json_parse_ex(&settings, json, &location);
+ struct sr_json_value *json_root = sr_json_parse_ex(&settings, json,
+ &location);
+
+ if (!json_root)
+ *error_message = sr_location_to_string(&location);
+
+ return json_root;
}

void
--
1.8.3.1
Martin Milata
2013-08-26 14:49:03 UTC
Permalink
Needed for #86.

Signed-off-by: Martin Milata <mmilata-H+wXaHxf7aLQT0dZR+***@public.gmane.org>
---
include/report.h | 8 ++++++++
lib/report.c | 14 ++++++++++++++
2 files changed, 22 insertions(+)

diff --git a/include/report.h b/include/report.h
index 634c6e5..52d0149 100644
--- a/include/report.h
+++ b/include/report.h
@@ -28,6 +28,8 @@ extern "C" {
#include <inttypes.h>
#include <stdbool.h>

+struct sr_json_value;
+
struct sr_report
{
uint32_t report_version;
@@ -63,6 +65,12 @@ sr_report_free(struct sr_report *report);
char *
sr_report_to_json(struct sr_report *report);

+struct sr_report *
+sr_report_from_json(struct sr_json_value *root, char **error_message);
+
+struct sr_report *
+sr_report_from_json_text(const char *text, char **error_message);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/report.c b/lib/report.c
index 0b278b4..2b3ace4 100644
--- a/lib/report.c
+++ b/lib/report.c
@@ -375,3 +375,17 @@ fail:
sr_report_free(report);
return NULL;
}
+
+struct sr_report *
+sr_report_from_json_text(const char *report, char **error_message)
+{
+ struct sr_json_value *json_root = sr_json_parse(report, error_message);
+
+ if (!json_root)
+ return NULL;
+
+ struct sr_report *result = sr_report_from_json(json_root, error_message);
+
+ sr_json_value_free(json_root);
+ return result;
+}
--
1.8.3.1
Martin Milata
2013-08-26 14:49:06 UTC
Permalink
The code is repeated at least two times and we'll need it once again.
It is still essentially the same for all four stacktrace types and could
probably be rewritten in a generic way but I'd rather not do it now for
the sake of size of this patchset.

Related to #86.

Signed-off-by: Martin Milata <mmilata-H+wXaHxf7aLQT0dZR+***@public.gmane.org>
---
python/py_core_stacktrace.c | 64 ++++++++++++++++++------------------------
python/py_core_stacktrace.h | 3 ++
python/py_java_stacktrace.c | 65 ++++++++++++++++++-------------------------
python/py_java_stacktrace.h | 3 ++
python/py_koops_stacktrace.c | 59 ++++++++++++++++++---------------------
python/py_koops_stacktrace.h | 3 ++
python/py_python_stacktrace.c | 59 ++++++++++++++++++---------------------
python/py_python_stacktrace.h | 3 ++
8 files changed, 120 insertions(+), 139 deletions(-)

diff --git a/python/py_core_stacktrace.c b/python/py_core_stacktrace.c
index 976e994..936611b 100644
--- a/python/py_core_stacktrace.c
+++ b/python/py_core_stacktrace.c
@@ -111,48 +111,53 @@ PyTypeObject sr_py_core_stacktrace_type = {
NULL, /* tp_weaklist */
};

-/* constructor */
PyObject *
-sr_py_core_stacktrace_new(PyTypeObject *object,
- PyObject *args,
- PyObject *kwds)
+core_stacktrace_to_python_obj(struct sr_core_stacktrace *stacktrace)
{
- struct sr_py_core_stacktrace *bo = (struct sr_py_core_stacktrace*)
- PyObject_New(struct sr_py_core_stacktrace,
- &sr_py_core_stacktrace_type);
-
+ struct sr_py_core_stacktrace *bo = PyObject_New(struct sr_py_core_stacktrace,
+ &sr_py_core_stacktrace_type);
if (!bo)
return PyErr_NoMemory();

bo->thread_type = &sr_py_core_thread_type;
bo->frame_type = &sr_py_core_frame_type;

+ bo->stacktrace = stacktrace;
+ bo->threads = threads_to_python_list((struct sr_stacktrace *)bo->stacktrace,
+ bo->thread_type, bo->frame_type);
+ if (!bo->threads)
+ return NULL;
+
+ return (PyObject *)bo;
+}
+
+/* constructor */
+PyObject *
+sr_py_core_stacktrace_new(PyTypeObject *object,
+ PyObject *args,
+ PyObject *kwds)
+{
const char *str = NULL;
if (!PyArg_ParseTuple(args, "|s", &str))
return NULL;

+ struct sr_core_stacktrace *stacktrace;
+
if (str)
{
char *error_msg;
- bo->stacktrace = sr_core_stacktrace_from_json_text(str, &error_msg);
- if (!bo->stacktrace)
+ stacktrace = sr_core_stacktrace_from_json_text(str, &error_msg);
+ if (!stacktrace)
{
PyErr_SetString(PyExc_ValueError, error_msg);
free(error_msg);
return NULL;
}
- bo->threads = threads_to_python_list((struct sr_stacktrace *)bo->stacktrace,
- bo->thread_type, bo->frame_type);
- if (!bo->threads)
- return NULL;
}
else
- {
- bo->threads = PyList_New(0);
- bo->stacktrace = sr_core_stacktrace_new();
- }
+ stacktrace = sr_core_stacktrace_new();

- return (PyObject *)bo;
+ return core_stacktrace_to_python_obj(stacktrace);
}

/* destructor */
@@ -189,24 +194,9 @@ sr_py_core_stacktrace_dup(PyObject *self, PyObject *args)
if (threads_prepare_linked_list((struct sr_py_multi_stacktrace *)this) < 0)
return NULL;

- struct sr_py_core_stacktrace *bo = (struct sr_py_core_stacktrace*)
- PyObject_New(struct sr_py_core_stacktrace,
- &sr_py_core_stacktrace_type);
-
- if (!bo)
- return PyErr_NoMemory();
-
- bo->thread_type = &sr_py_core_thread_type;
- bo->frame_type = &sr_py_core_frame_type;
-
- bo->stacktrace = sr_core_stacktrace_dup(this->stacktrace);
- if (!bo->stacktrace)
- return NULL;
-
- bo->threads = threads_to_python_list((struct sr_stacktrace *)bo->stacktrace,
- bo->thread_type, bo->frame_type);
- if (!bo->threads)
+ struct sr_core_stacktrace *stacktrace = sr_core_stacktrace_dup(this->stacktrace);
+ if (!stacktrace)
return NULL;

- return (PyObject*)bo;
+ return core_stacktrace_to_python_obj(stacktrace);
}
diff --git a/python/py_core_stacktrace.h b/python/py_core_stacktrace.h
index 4cb00ad..f458a23 100644
--- a/python/py_core_stacktrace.h
+++ b/python/py_core_stacktrace.h
@@ -49,6 +49,9 @@ struct sr_py_core_stacktrace
PyTypeObject *frame_type;
};

+/* helpers */
+PyObject *core_stacktrace_to_python_obj(struct sr_core_stacktrace *stacktrace);
+
/* constructor */
PyObject *sr_py_core_stacktrace_new(PyTypeObject *object,
PyObject *args,
diff --git a/python/py_java_stacktrace.c b/python/py_java_stacktrace.c
index fc5bde9..c175692 100644
--- a/python/py_java_stacktrace.c
+++ b/python/py_java_stacktrace.c
@@ -76,49 +76,53 @@ PyTypeObject sr_py_java_stacktrace_type = {
NULL, /* tp_weaklist */
};

-/* constructor */
PyObject *
-sr_py_java_stacktrace_new(PyTypeObject *object,
- PyObject *args,
- PyObject *kwds)
+java_stacktrace_to_python_obj(struct sr_java_stacktrace *stacktrace)
{
- struct sr_py_java_stacktrace *bo = (struct sr_py_java_stacktrace*)
- PyObject_New(struct sr_py_java_stacktrace,
- &sr_py_java_stacktrace_type);
-
+ struct sr_py_java_stacktrace *bo = PyObject_New(struct sr_py_java_stacktrace,
+ &sr_py_java_stacktrace_type);
if (!bo)
return PyErr_NoMemory();

bo->thread_type = &sr_py_java_thread_type;
bo->frame_type = &sr_py_java_frame_type;

+ bo->stacktrace = stacktrace;
+ bo->threads = threads_to_python_list((struct sr_stacktrace *)bo->stacktrace,
+ bo->thread_type, bo->frame_type);
+ if (!bo->threads)
+ return NULL;
+
+ return (PyObject *)bo;
+}
+
+/* constructor */
+PyObject *
+sr_py_java_stacktrace_new(PyTypeObject *object,
+ PyObject *args,
+ PyObject *kwds)
+{
const char *str = NULL;
if (!PyArg_ParseTuple(args, "|s", &str))
return NULL;

+ struct sr_java_stacktrace *stacktrace;
+
if (str)
{
- /* ToDo parse */
struct sr_location location;
sr_location_init(&location);
- bo->stacktrace = sr_java_stacktrace_parse(&str, &location);
- if (!bo->stacktrace)
+ stacktrace = sr_java_stacktrace_parse(&str, &location);
+ if (!stacktrace)
{
PyErr_SetString(PyExc_ValueError, location.message);
return NULL;
}
- bo->threads = threads_to_python_list((struct sr_stacktrace *)bo->stacktrace,
- bo->thread_type, bo->frame_type);
- if (!bo->threads)
- return NULL;
}
else
- {
- bo->threads = PyList_New(0);
- bo->stacktrace = sr_java_stacktrace_new();
- }
+ stacktrace = sr_java_stacktrace_new();

- return (PyObject *)bo;
+ return java_stacktrace_to_python_obj(stacktrace);
}

/* destructor */
@@ -155,24 +159,9 @@ sr_py_java_stacktrace_dup(PyObject *self, PyObject *args)
if (threads_prepare_linked_list((struct sr_py_multi_stacktrace *)this) < 0)
return NULL;

- struct sr_py_java_stacktrace *bo = (struct sr_py_java_stacktrace*)
- PyObject_New(struct sr_py_java_stacktrace,
- &sr_py_java_stacktrace_type);
-
- if (!bo)
- return PyErr_NoMemory();
-
- bo->thread_type = &sr_py_java_thread_type;
- bo->frame_type = &sr_py_java_frame_type;
-
- bo->stacktrace = sr_java_stacktrace_dup(this->stacktrace);
- if (!bo->stacktrace)
- return NULL;
-
- bo->threads = threads_to_python_list((struct sr_stacktrace *)bo->stacktrace,
- bo->thread_type, bo->frame_type);
- if (!bo->threads)
+ struct sr_java_stacktrace *stacktrace = sr_java_stacktrace_dup(this->stacktrace);
+ if (!stacktrace)
return NULL;

- return (PyObject*)bo;
+ return java_stacktrace_to_python_obj(stacktrace);
}
diff --git a/python/py_java_stacktrace.h b/python/py_java_stacktrace.h
index 4802d57..9cbe80a 100644
--- a/python/py_java_stacktrace.h
+++ b/python/py_java_stacktrace.h
@@ -49,6 +49,9 @@ struct sr_py_java_stacktrace
PyTypeObject *frame_type;
};

+/* helpers */
+PyObject *java_stacktrace_to_python_obj(struct sr_java_stacktrace *stacktrace);
+
/* constructor */
PyObject *sr_py_java_stacktrace_new(PyTypeObject *object,
PyObject *args,
diff --git a/python/py_koops_stacktrace.c b/python/py_koops_stacktrace.c
index 80bc104..561cbc7 100644
--- a/python/py_koops_stacktrace.c
+++ b/python/py_koops_stacktrace.c
@@ -157,45 +157,52 @@ sr_py_koops_stacktrace_set_taint_flags(PyObject *self, PyObject *rhs, void *data
return -1;
}

-/* constructor */
PyObject *
-sr_py_koops_stacktrace_new(PyTypeObject *object,
- PyObject *args,
- PyObject *kwds)
+koops_stacktrace_to_python_obj(struct sr_koops_stacktrace *stacktrace)
{
- struct sr_py_koops_stacktrace *bo = (struct sr_py_koops_stacktrace*)
- PyObject_New(struct sr_py_koops_stacktrace,
- &sr_py_koops_stacktrace_type);
-
+ struct sr_py_koops_stacktrace *bo = PyObject_New(struct sr_py_koops_stacktrace,
+ &sr_py_koops_stacktrace_type);
if (!bo)
return PyErr_NoMemory();

bo->frame_type = &sr_py_koops_frame_type;

+ bo->stacktrace = stacktrace;
+ bo->frames = frames_to_python_list((struct sr_thread *)bo->stacktrace,
+ bo->frame_type);
+ if (!bo->frames)
+ return NULL;
+
+ return (PyObject *)bo;
+}
+
+/* constructor */
+PyObject *
+sr_py_koops_stacktrace_new(PyTypeObject *object,
+ PyObject *args,
+ PyObject *kwds)
+{
const char *str = NULL;
if (!PyArg_ParseTuple(args, "|s", &str))
return NULL;

+ struct sr_koops_stacktrace *stacktrace;
+
if (str)
{
struct sr_location location;
sr_location_init(&location);
- bo->stacktrace = sr_koops_stacktrace_parse(&str, &location);
- if (!bo->stacktrace)
+ stacktrace = sr_koops_stacktrace_parse(&str, &location);
+ if (!stacktrace)
{
PyErr_SetString(PyExc_ValueError, location.message);
return NULL;
}
-
- bo->frames = frames_to_python_list((struct sr_thread *)bo->stacktrace, bo->frame_type);
}
else
- {
- bo->stacktrace = sr_koops_stacktrace_new();
- bo->frames = PyList_New(0);
- }
+ stacktrace = sr_koops_stacktrace_new();

- return (PyObject *)bo;
+ return koops_stacktrace_to_python_obj(stacktrace);
}

/* destructor */
@@ -232,23 +239,11 @@ sr_py_koops_stacktrace_dup(PyObject *self, PyObject *args)
if (frames_prepare_linked_list((struct sr_py_base_thread *)this) < 0)
return NULL;

- struct sr_py_koops_stacktrace *bo = (struct sr_py_koops_stacktrace*)
- PyObject_New(struct sr_py_koops_stacktrace,
- &sr_py_koops_stacktrace_type);
-
- if (!bo)
- return PyErr_NoMemory();
-
- bo->frame_type = &sr_py_koops_frame_type;
- bo->stacktrace = sr_koops_stacktrace_dup(this->stacktrace);
- if (!bo->stacktrace)
- return NULL;
-
- bo->frames = frames_to_python_list((struct sr_thread *)bo->stacktrace, bo->frame_type);
- if (!bo->frames)
+ struct sr_koops_stacktrace *stacktrace = sr_koops_stacktrace_dup(this->stacktrace);
+ if (!stacktrace)
return NULL;

- return (PyObject*)bo;
+ return koops_stacktrace_to_python_obj(stacktrace);
}

PyObject *
diff --git a/python/py_koops_stacktrace.h b/python/py_koops_stacktrace.h
index 162ac5e..e72ab54 100644
--- a/python/py_koops_stacktrace.h
+++ b/python/py_koops_stacktrace.h
@@ -46,6 +46,9 @@ struct sr_py_koops_stacktrace
PyObject *taint_flags;
};

+/* helpers */
+PyObject *koops_stacktrace_to_python_obj(struct sr_koops_stacktrace *stacktrace);
+
/* constructor */
PyObject *sr_py_koops_stacktrace_new(PyTypeObject *object,
PyObject *args,
diff --git a/python/py_python_stacktrace.c b/python/py_python_stacktrace.c
index 1b45e64..65cba81 100644
--- a/python/py_python_stacktrace.c
+++ b/python/py_python_stacktrace.c
@@ -105,45 +105,52 @@ PyTypeObject sr_py_python_stacktrace_type = {
NULL, /* tp_weaklist */
};

-/* constructor */
PyObject *
-sr_py_python_stacktrace_new(PyTypeObject *object,
- PyObject *args,
- PyObject *kwds)
+python_stacktrace_to_python_obj(struct sr_python_stacktrace *stacktrace)
{
- struct sr_py_python_stacktrace *bo = (struct sr_py_python_stacktrace*)
- PyObject_New(struct sr_py_python_stacktrace,
- &sr_py_python_stacktrace_type);
-
+ struct sr_py_python_stacktrace *bo = PyObject_New(struct sr_py_python_stacktrace,
+ &sr_py_python_stacktrace_type);
if (!bo)
return PyErr_NoMemory();

bo->frame_type = &sr_py_python_frame_type;

+ bo->stacktrace = stacktrace;
+ bo->frames = frames_to_python_list((struct sr_thread *)bo->stacktrace,
+ bo->frame_type);
+ if (!bo->frames)
+ return NULL;
+
+ return (PyObject *)bo;
+}
+
+/* constructor */
+PyObject *
+sr_py_python_stacktrace_new(PyTypeObject *object,
+ PyObject *args,
+ PyObject *kwds)
+{
const char *str = NULL;
if (!PyArg_ParseTuple(args, "|s", &str))
return NULL;

+ struct sr_python_stacktrace *stacktrace;
+
if (str)
{
struct sr_location location;
sr_location_init(&location);
- bo->stacktrace = sr_python_stacktrace_parse(&str, &location);
- if (!bo->stacktrace)
+ stacktrace = sr_python_stacktrace_parse(&str, &location);
+ if (!stacktrace)
{
PyErr_SetString(PyExc_ValueError, location.message);
return NULL;
}
-
- bo->frames = frames_to_python_list((struct sr_thread *)bo->stacktrace, bo->frame_type);
}
else
- {
- bo->stacktrace = sr_python_stacktrace_new();
- bo->frames = PyList_New(0);
- }
+ stacktrace = sr_python_stacktrace_new();

- return (PyObject *)bo;
+ return python_stacktrace_to_python_obj(stacktrace);
}

/* destructor */
@@ -180,23 +187,11 @@ sr_py_python_stacktrace_dup(PyObject *self, PyObject *args)
if (frames_prepare_linked_list((struct sr_py_base_thread *)this) < 0)
return NULL;

- struct sr_py_python_stacktrace *bo = (struct sr_py_python_stacktrace*)
- PyObject_New(struct sr_py_python_stacktrace,
- &sr_py_python_stacktrace_type);
-
- if (!bo)
- return PyErr_NoMemory();
-
- bo->frame_type = &sr_py_python_frame_type;
- bo->stacktrace = sr_python_stacktrace_dup(this->stacktrace);
- if (!bo->stacktrace)
- return NULL;
-
- bo->frames = frames_to_python_list((struct sr_thread *)bo->stacktrace, bo->frame_type);
- if (!bo->frames)
+ struct sr_python_stacktrace *stacktrace = sr_python_stacktrace_dup(this->stacktrace);
+ if (!stacktrace)
return NULL;

- return (PyObject*)bo;
+ return python_stacktrace_to_python_obj(stacktrace);
}

/*
diff --git a/python/py_python_stacktrace.h b/python/py_python_stacktrace.h
index faa5e06..a89ad8f 100644
--- a/python/py_python_stacktrace.h
+++ b/python/py_python_stacktrace.h
@@ -45,6 +45,9 @@ struct sr_py_python_stacktrace
PyTypeObject *frame_type;
};

+/* helpers */
+PyObject *python_stacktrace_to_python_obj(struct sr_python_stacktrace *stacktrace);
+
/* constructor */
PyObject *sr_py_python_stacktrace_new(PyTypeObject *object,
PyObject *args,
--
1.8.3.1
Martin Milata
2013-08-26 14:49:05 UTC
Permalink
Makes it possible to simplify some code and the structure won't have to
be extended when adding new stacktrace type.

Related to #86.

Signed-off-by: Martin Milata <mmilata-H+wXaHxf7aLQT0dZR+***@public.gmane.org>
---
include/report.h | 6 ++---
lib/Makefile.am | 2 +-
lib/abrt.c | 16 ++++++-------
lib/report.c | 70 +++++++++-----------------------------------------------
4 files changed, 22 insertions(+), 72 deletions(-)

diff --git a/include/report.h b/include/report.h
index 52d0149..424b730 100644
--- a/include/report.h
+++ b/include/report.h
@@ -29,6 +29,7 @@ extern "C" {
#include <stdbool.h>

struct sr_json_value;
+struct sr_stacktrace;

struct sr_report
{
@@ -47,10 +48,7 @@ struct sr_report
char *component_name;
struct sr_rpm_package *rpm_packages;

- struct sr_python_stacktrace *python_stacktrace;
- struct sr_koops_stacktrace *koops_stacktrace;
- struct sr_core_stacktrace *core_stacktrace;
- struct sr_java_stacktrace *java_stacktrace;
+ struct sr_stacktrace *stacktrace;
};

struct sr_report *
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 65b0807..8cd7fce 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -51,7 +51,7 @@ libsatyr_la_SOURCES = \
utils.c

libsatyr_la_CFLAGS = -Wall -std=gnu99 -D_GNU_SOURCE -I$(top_srcdir)/include $(GLIB_CFLAGS)
-libsatyr_la_LDFLAGS = -version-info 1:0:0 -export-symbols-regex '^sr_' $(GLIB_LIBS)
+libsatyr_la_LDFLAGS = -version-info 2:0:0 -export-symbols-regex '^sr_' $(GLIB_LIBS)

if HAVE_LIBOPCODES
# Conditional link is required to avoid linking to a library without
diff --git a/lib/abrt.c b/lib/abrt.c
index e59c30d..53f84cd 100644
--- a/lib/abrt.c
+++ b/lib/abrt.c
@@ -373,11 +373,11 @@ sr_abrt_report_from_dir(const char *directory,
return NULL;
}

- report->core_stacktrace = sr_core_stacktrace_from_json_text(
+ report->stacktrace = (struct sr_stacktrace *)sr_core_stacktrace_from_json_text(
core_backtrace_contents, error_message);

free(core_backtrace_contents);
- if (!report->core_stacktrace)
+ if (!report->stacktrace)
{
sr_report_free(report);
return NULL;
@@ -399,12 +399,12 @@ sr_abrt_report_from_dir(const char *directory,
struct sr_location location;
sr_location_init(&location);
const char *contents_pointer = backtrace_contents;
- report->python_stacktrace = sr_python_stacktrace_parse(
+ report->stacktrace = (struct sr_stacktrace *)sr_python_stacktrace_parse(
&contents_pointer,
&location);

free(backtrace_contents);
- if (!report->python_stacktrace)
+ if (!report->stacktrace)
{
*error_message = sr_location_to_string(&location);
sr_report_free(report);
@@ -456,12 +456,12 @@ sr_abrt_report_from_dir(const char *directory,
struct sr_location location;
sr_location_init(&location);
const char *contents_pointer = backtrace_contents;
- report->koops_stacktrace = sr_koops_stacktrace_parse(
+ report->stacktrace = (struct sr_stacktrace *)sr_koops_stacktrace_parse(
&contents_pointer,
&location);

free(backtrace_contents);
- if (!report->koops_stacktrace)
+ if (!report->stacktrace)
{
*error_message = sr_location_to_string(&location);
sr_report_free(report);
@@ -483,12 +483,12 @@ sr_abrt_report_from_dir(const char *directory,
struct sr_location location;
sr_location_init(&location);
const char *contents_pointer = backtrace_contents;
- report->java_stacktrace = sr_java_stacktrace_parse(
+ report->stacktrace = (struct sr_stacktrace *)sr_java_stacktrace_parse(
&contents_pointer,
&location);

free(backtrace_contents);
- if (!report->java_stacktrace)
+ if (!report->stacktrace)
{
*error_message = sr_location_to_string(&location);
sr_report_free(report);
diff --git a/lib/report.c b/lib/report.c
index 92b77cf..a6ecae4 100644
--- a/lib/report.c
+++ b/lib/report.c
@@ -22,6 +22,7 @@
#include "config.h"
#include "utils.h"
#include "json.h"
+#include "stacktrace.h"
#include "koops/stacktrace.h"
#include "core/stacktrace.h"
#include "python/stacktrace.h"
@@ -64,10 +65,7 @@ sr_report_init(struct sr_report *report)
report->operating_system = NULL;
report->component_name = NULL;
report->rpm_packages = NULL;
- report->python_stacktrace = NULL;
- report->koops_stacktrace = NULL;
- report->core_stacktrace = NULL;
- report->java_stacktrace = NULL;
+ report->stacktrace = NULL;
}

void
@@ -76,10 +74,7 @@ sr_report_free(struct sr_report *report)
free(report->component_name);
sr_operating_system_free(report->operating_system);
sr_rpm_package_free(report->rpm_packages, true);
- sr_python_stacktrace_free(report->python_stacktrace);
- sr_koops_stacktrace_free(report->koops_stacktrace);
- sr_core_stacktrace_free(report->core_stacktrace);
- sr_java_stacktrace_free(report->java_stacktrace);
+ sr_stacktrace_free(report->stacktrace);
free(report);
}

@@ -128,43 +123,14 @@ problem_object_string(struct sr_report *report, const char *report_type)
}

/* Stacktrace. */
-
- /* Core stacktrace. */
- if (report->core_stacktrace)
- {
- char *stacktrace = sr_core_stacktrace_to_json(report->core_stacktrace);
- dismantle_object(stacktrace);
- sr_strbuf_append_str(strbuf, stacktrace);
- free(stacktrace);
- }
-
- /* Python stacktrace. */
- if (report->python_stacktrace)
- {
- char *stacktrace = sr_python_stacktrace_to_json(report->python_stacktrace);
- dismantle_object(stacktrace);
- sr_strbuf_append_str(strbuf, stacktrace);
- free(stacktrace);
- }
-
- /* Koops stacktrace. */
- if (report->koops_stacktrace)
+ if (report->stacktrace)
{
- char *stacktrace = sr_koops_stacktrace_to_json(report->koops_stacktrace);
+ char *stacktrace = sr_stacktrace_to_json(report->stacktrace);
dismantle_object(stacktrace);
sr_strbuf_append_str(strbuf, stacktrace);
free(stacktrace);
}

- /* Java stacktrace. */
- if (report->java_stacktrace)
- {
- char *stacktrace = sr_java_stacktrace_to_json(report->java_stacktrace);
- dismantle_object(stacktrace);
- sr_strbuf_append_strf(strbuf, stacktrace);
- free(stacktrace);
- }
-
sr_strbuf_append_str(strbuf, "}");

return sr_strbuf_free_nobuf(strbuf);
@@ -181,31 +147,22 @@ sr_report_to_json(struct sr_report *report)
report->report_version);

/* Report type. */
- const char *report_type;
+ char *report_type;
char *reason;
switch (report->report_type)
{
default:
case SR_REPORT_INVALID:
case SR_REPORT_GDB: /* gdb ureports are not supported */
- report_type = "invalid";
+ report_type = sr_strdup("invalid");
reason = sr_strdup("invalid");
break;
case SR_REPORT_CORE:
- report_type = "core";
- reason = sr_core_stacktrace_get_reason(report->core_stacktrace);
- break;
case SR_REPORT_PYTHON:
- report_type = "python";
- reason = sr_python_stacktrace_get_reason(report->python_stacktrace);
- break;
case SR_REPORT_KERNELOOPS:
- report_type = "kerneloops";
- reason = sr_koops_stacktrace_get_reason(report->koops_stacktrace);
- break;
case SR_REPORT_JAVA:
- report_type = "java";
- reason = sr_java_stacktrace_get_reason(report->java_stacktrace);
+ report_type = sr_report_type_to_string(report->report_type);
+ reason = sr_stacktrace_get_reason(report->stacktrace);
break;
}

@@ -245,6 +202,7 @@ sr_report_to_json(struct sr_report *report)
char *problem = problem_object_string(report, report_type);
char *problem_indented = sr_indent_except_first_line(problem, strlen(", \"problem\": "));
free(problem);
+ free(report_type);
sr_strbuf_append_strf(strbuf,
", \"problem\": %s\n",
problem_indented);
@@ -366,16 +324,10 @@ sr_report_from_json(struct sr_json_value *root, char **error_message)
switch (report->report_type)
{
case SR_REPORT_CORE:
- report->core_stacktrace = sr_core_stacktrace_from_json(problem, error_message);
- break;
case SR_REPORT_PYTHON:
- report->python_stacktrace = sr_python_stacktrace_from_json(problem, error_message);
- break;
case SR_REPORT_KERNELOOPS:
- report->koops_stacktrace = sr_koops_stacktrace_from_json(problem, error_message);
- break;
case SR_REPORT_JAVA:
- report->java_stacktrace = sr_java_stacktrace_from_json(problem, error_message);
+ report->stacktrace = sr_stacktrace_from_json(report->report_type, problem, error_message);
break;
default:
/* Invalid report type -> no stacktrace. */
--
1.8.3.1
Martin Milata
2013-08-26 14:49:04 UTC
Permalink
Needed for #86.

Signed-off-by: Martin Milata <mmilata-H+wXaHxf7aLQT0dZR+***@public.gmane.org>
---
include/report_type.h | 8 +++++++
lib/report.c | 45 ++++++++++++++++++++++++++-------------
tests/Makefile.am | 1 +
tests/report.at | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++
tests/testsuite.at | 1 +
5 files changed, 99 insertions(+), 15 deletions(-)
create mode 100644 tests/report.at

diff --git a/include/report_type.h b/include/report_type.h
index 8df81a2..a51620d 100644
--- a/include/report_type.h
+++ b/include/report_type.h
@@ -37,6 +37,14 @@ enum sr_report_type
SR_REPORT_NUM
};

+/* returns malloc()ed string representation of report_type */
+char *
+sr_report_type_to_string(enum sr_report_type report_type);
+
+/* inverse function */
+enum sr_report_type
+sr_report_type_from_string(const char *report_type_str);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/report.c b/lib/report.c
index 2b3ace4..92b77cf 100644
--- a/lib/report.c
+++ b/lib/report.c
@@ -33,6 +33,17 @@
#include <string.h>
#include <assert.h>

+static char *report_types[] =
+{
+ [SR_REPORT_INVALID] = "invalid",
+ [SR_REPORT_CORE] = "core",
+ [SR_REPORT_PYTHON] = "python",
+ [SR_REPORT_KERNELOOPS] = "kerneloops",
+ [SR_REPORT_JAVA] = "java",
+ [SR_REPORT_GDB] = "gdb",
+ NULL
+};
+
struct sr_report *
sr_report_new()
{
@@ -256,21 +267,25 @@ sr_report_to_json(struct sr_report *report)
return sr_strbuf_free_nobuf(strbuf);
}

-static enum sr_report_type
-report_type_from_string(const char *report_type_str)
+enum sr_report_type
+sr_report_type_from_string(const char *report_type_str)
+{
+ for (int i = SR_REPORT_INVALID; i < SR_REPORT_NUM; i++)
+ {
+ if (0 == sr_strcmp0(report_types[i], report_type_str))
+ return i;
+ }
+
+ return SR_REPORT_INVALID;
+}
+
+char *
+sr_report_type_to_string(enum sr_report_type report_type)
{
- assert(report_type_str);
-
- if (0 == strcmp("core", report_type_str))
- return SR_REPORT_CORE;
- else if (0 == strcmp("python", report_type_str))
- return SR_REPORT_PYTHON;
- else if (0 == strcmp("kerneloops", report_type_str))
- return SR_REPORT_KERNELOOPS;
- else if (0 == strcmp("java", report_type_str))
- return SR_REPORT_JAVA;
- else
- return SR_REPORT_INVALID;
+ if (report_type < SR_REPORT_INVALID || report_type >= SR_REPORT_NUM)
+ return sr_strdup("invalid");
+
+ return sr_strdup(report_types[report_type]);
}

struct sr_report *
@@ -332,7 +347,7 @@ sr_report_from_json(struct sr_json_value *root, char **error_message)
if (!success)
goto fail;

- report->report_type = report_type_from_string(report_type);
+ report->report_type = sr_report_type_from_string(report_type);

/* User. */
struct sr_json_value *user = json_element(root, "user");
diff --git a/tests/Makefile.am b/tests/Makefile.am
index cef50ce..d69f493 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -55,6 +55,7 @@ TESTSUITE_AT = \
cluster.at \
rpm.at \
abrt.at \
+ report.at \
python_bindings.at

EXTRA_DIST += $(TESTSUITE_AT)
diff --git a/tests/report.at b/tests/report.at
new file mode 100644
index 0000000..8736137
--- /dev/null
+++ b/tests/report.at
@@ -0,0 +1,59 @@
+# Checking the satyr. -*- Autotest -*-
+
+AT_BANNER([Report])
+
+## ------------------------ ##
+## sr_report_type_to_string ##
+## ------------------------ ##
+
+AT_TESTFUN([sr_report_type_to_string],
+[[
+#include <assert.h>
+#include "report_type.h"
+
+void check(enum sr_report_type type, char *str)
+{
+ assert(0 == sr_strcmp0(sr_report_type_to_string(type), str));
+}
+
+int main(void)
+{
+ check(SR_REPORT_INVALID, "invalid");
+ check(SR_REPORT_CORE, "core");
+ check(SR_REPORT_KERNELOOPS, "kerneloops");
+ check(SR_REPORT_GDB, "gdb");
+ check(SR_REPORT_NUM, "invalid");
+ check(5000, "invalid");
+ check(-42, "invalid");
+
+ return 0;
+}
+]])
+
+## -------------------------- ##
+## sr_report_type_from_string ##
+## -------------------------- ##
+
+AT_TESTFUN([sr_report_type_from_string],
+[[
+#include <assert.h>
+#include <stdio.h>
+#include "report_type.h"
+
+void check(enum sr_report_type type, char *str)
+{
+ assert(sr_report_type_from_string(str) == type);
+}
+
+int main(void)
+{
+ check(SR_REPORT_INVALID, "invalid");
+ check(SR_REPORT_CORE, "core");
+ check(SR_REPORT_PYTHON, "python");
+ check(SR_REPORT_GDB, "gdb");
+ check(SR_REPORT_INVALID, NULL);
+ check(SR_REPORT_INVALID, "visual basic");
+
+ return 0;
+}
+]])
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 39d9a94..904fe64 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -21,4 +21,5 @@ m4_include([metrics.at])
m4_include([cluster.at])
m4_include([rpm.at])
m4_include([abrt.at])
+m4_include([report.at])
m4_include([python_bindings.at])
--
1.8.3.1
Martin Milata
2013-08-26 14:49:07 UTC
Permalink
Closes #86 and closes #92.
---
python/Makefile.am | 2 +
python/py_common.c | 7 +
python/py_common.h | 4 +
python/py_module.c | 10 +
python/py_report.c | 491 +++++++++++++++++++++++++++++++++++++++++++++
python/py_report.h | 79 ++++++++
tests/json_files/ureport-1 | 107 ++++++++++
tests/python/report.py | 49 +++++
8 files changed, 749 insertions(+)
create mode 100644 python/py_report.c
create mode 100644 python/py_report.h
create mode 100644 tests/json_files/ureport-1

diff --git a/python/Makefile.am b/python/Makefile.am
index 34491c1..a2e95b8 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -48,6 +48,8 @@ _satyr_la_SOURCES = \
py_metrics.c \
py_operating_system.h \
py_operating_system.c \
+ py_report.h \
+ py_report.c \
py_common.h \
py_common.c \
py_module.c
diff --git a/python/py_common.c b/python/py_common.c
index 80b76f1..f8fdbb3 100644
--- a/python/py_common.c
+++ b/python/py_common.c
@@ -199,6 +199,13 @@ sr_py_setter_uint64(PyObject *self, PyObject *rhs, void *data)
}

int
+sr_py_setter_readonly(PyObject *self, PyObject *rhs, void *data)
+{
+ PyErr_SetString(PyExc_AttributeError, "This attribute is read-only.");
+ return -1;
+}
+
+int
normalize_cmp(int n)
{
if (n > 0)
diff --git a/python/py_common.h b/python/py_common.h
index 757df21..a54baa1 100644
--- a/python/py_common.h
+++ b/python/py_common.h
@@ -128,6 +128,10 @@ PyObject *sr_py_getter_uint64(PyObject *self, void *data);
/* NOTE: when rhs is None, the attribute is set to UINT64_MAX */
int sr_py_setter_uint64(PyObject *self, PyObject *rhs, void *data);

+/* Just throws an exception. */
+int
+sr_py_setter_readonly(PyObject *self, PyObject *rhs, void *data);
+
/*
* Satyr's comparison functions return arbitrary numbers, while python
* requires the result to be in {-1, 0, 1}.
diff --git a/python/py_module.c b/python/py_module.c
index e566376..841adf9 100644
--- a/python/py_module.c
+++ b/python/py_module.c
@@ -20,6 +20,7 @@
#include "py_rpm_package.h"
#include "py_metrics.h"
#include "py_operating_system.h"
+#include "py_report.h"

#include "distance.h"
#include "thread.h"
@@ -166,6 +167,12 @@ init_satyr()
return;
}

+ if (PyType_Ready(&sr_py_report_type) < 0)
+ {
+ puts("PyType_Ready(&sr_py_report_type) < 0");
+ return;
+ }
+
if (PyType_Ready(&sr_py_rpm_package_type) < 0)
{
puts("PyType_Ready(&sr_py_rpm_package_type) < 0");
@@ -283,6 +290,9 @@ init_satyr()
PyModule_AddObject(module, "OperatingSystem",
(PyObject *)&sr_py_operating_system_type);

+ Py_INCREF(&sr_py_report_type);
+ PyModule_AddObject(module, "Report", (PyObject *)&sr_py_report_type);
+
Py_INCREF(&sr_py_rpm_package_type);
PyModule_AddObject(module, "RpmPackage",
(PyObject *)&sr_py_rpm_package_type);
diff --git a/python/py_report.c b/python/py_report.c
new file mode 100644
index 0000000..678d661
--- /dev/null
+++ b/python/py_report.c
@@ -0,0 +1,491 @@
+/*
+ py_report.c
+
+ Copyright (C) 2013 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "py_common.h"
+#include "py_report.h"
+#include "py_rpm_package.h"
+#include "py_operating_system.h"
+
+#include "py_base_stacktrace.h"
+#include "py_core_stacktrace.h"
+#include "py_python_stacktrace.h"
+#include "py_koops_stacktrace.h"
+#include "py_java_stacktrace.h"
+
+#include "report.h"
+#include "operating_system.h"
+#include "strbuf.h"
+#include "rpm.h"
+
+#define report_doc "satyr.Report - report containing all data relevant to a software problem\n" \
+ "Usage:\n" \
+ "satyr.Report() - creates an empty report object\n" \
+ "satyr.Report(json_string) - creates a report from its JSON representation"
+
+#define to_json_doc "Usage: report.to_json()\n" \
+ "Returns: string - the report serialized as JSON"
+
+/* See python/py_common.h and python/py_gdb_frame.c for generic getters/setters documentation. */
+#define GSOFF_PY_STRUCT sr_py_report
+#define GSOFF_PY_MEMBER report
+#define GSOFF_C_STRUCT sr_report
+GSOFF_START
+GSOFF_MEMBER(reporter_name),
+GSOFF_MEMBER(reporter_version),
+GSOFF_MEMBER(user_root),
+GSOFF_MEMBER(user_local),
+GSOFF_MEMBER(component_name)
+GSOFF_END
+
+static PyGetSetDef
+report_getset[] =
+{
+ SR_ATTRIBUTE_STRING(reporter_name, "Name of the reporting software (string)" ),
+ SR_ATTRIBUTE_STRING(reporter_version, "Version of the reporting software (string)" ),
+ SR_ATTRIBUTE_BOOL(user_root, "Did the problem originate in a program running as root? (bool)" ),
+ SR_ATTRIBUTE_BOOL(user_local, "Did the problem originate in a program executed by local user? (bool)" ),
+ SR_ATTRIBUTE_STRING(component_name, "Name of the software component this report pertains to (string)" ),
+ { (char*)"report_version", sr_py_report_get_version, sr_py_setter_readonly, (char*)"Version of the report (int)", NULL },
+ { (char*)"report_type", sr_py_report_get_type, sr_py_report_set_type, (char*)"Report type (string)", NULL },
+ { NULL },
+};
+
+static PyMemberDef
+report_members[] =
+{
+ { (char*)"stacktrace", T_OBJECT_EX, offsetof(struct sr_py_report, stacktrace), 0, (char*)"Problem stacktrace" },
+ { (char*)"operating_system", T_OBJECT_EX, offsetof(struct sr_py_report, operating_system), 0, (char *)"Operating system" },
+ { (char*)"packages", T_OBJECT_EX, offsetof(struct sr_py_report, packages), 0, (char *)"List of packages" },
+ { NULL },
+};
+
+static PyMethodDef
+report_methods[] =
+{
+ { "to_json", sr_py_report_to_json, METH_NOARGS, to_json_doc },
+ { NULL },
+};
+
+PyTypeObject
+sr_py_report_type =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "satyr.Report", /* tp_name */
+ sizeof(struct sr_py_report), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ sr_py_report_free, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL, /* tp_hash */
+ NULL, /* tp_call */
+ sr_py_report_str, /* tp_str */
+ NULL, /* tp_getattro */
+ NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ report_doc, /* tp_doc */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ report_methods, /* tp_methods */
+ report_members, /* tp_members */
+ report_getset, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ NULL, /* tp_init */
+ NULL, /* tp_alloc */
+ sr_py_report_new, /* tp_new */
+ NULL, /* tp_free */
+ NULL, /* tp_is_gc */
+ NULL, /* tp_bases */
+ NULL, /* tp_mro */
+ NULL, /* tp_cache */
+ NULL, /* tp_subclasses */
+ NULL, /* tp_weaklist */
+};
+
+static PyObject *
+rpms_to_python_list(struct sr_rpm_package *rpm)
+{
+ PyObject *result = PyList_New(0);
+ if (!result)
+ return PyErr_NoMemory();
+
+ struct sr_py_rpm_package *item;
+ while (rpm)
+ {
+ item = PyObject_New(struct sr_py_rpm_package, &sr_py_rpm_package_type);
+ if (!item)
+ return PyErr_NoMemory();
+
+ item->rpm_package = rpm;
+ if (PyList_Append(result, (PyObject *)item) < 0)
+ return NULL;
+
+ rpm = rpm->next;
+ }
+
+ return result;
+}
+
+int
+rpms_prepare_linked_list(struct sr_py_report *report)
+{
+ if (!PyList_Check(report->packages))
+ {
+ PyErr_SetString(PyExc_TypeError, "Attribute 'packages' is not a list.");
+ return -1;
+ }
+
+ int i;
+ PyObject *item;
+ struct sr_py_rpm_package *current = NULL, *prev = NULL;
+
+ for (i = 0; i < PyList_Size(report->packages); ++i)
+ {
+ item = PyList_GetItem(report->packages, i);
+ if (!item)
+ return -1;
+
+ Py_INCREF(item);
+
+ if (!PyObject_TypeCheck(item, &sr_py_rpm_package_type))
+ {
+ Py_XDECREF(item);
+ Py_XDECREF(prev);
+ PyErr_SetString(PyExc_TypeError, "packages must be a list of RpmPackage objects");
+ return -1;
+ }
+
+ current = (struct sr_py_rpm_package*)item;
+ if (i == 0)
+ report->report->rpm_packages = current->rpm_package;
+ else
+ prev->rpm_package->next = current->rpm_package;
+
+ Py_XDECREF(prev);
+ prev = current;
+ }
+
+ if (current)
+ {
+ current->rpm_package->next = NULL;
+ Py_DECREF(current);
+ }
+
+ return 0;
+}
+
+static int
+stacktrace_prepare(struct sr_py_report *report, PyTypeObject *type, bool multi_thread)
+{
+ if (!PyObject_TypeCheck(report->stacktrace, type))
+ {
+ PyErr_Format(PyExc_TypeError, "stacktrace must be an %s object", type->tp_name);
+ return -1;
+ }
+
+ if (multi_thread)
+ {
+ report->report->stacktrace =
+ ((struct sr_py_multi_stacktrace *)report->stacktrace)->stacktrace;
+ }
+ else
+ {
+ report->report->stacktrace =
+ (struct sr_stacktrace *)((struct sr_py_base_thread *)report->stacktrace)->thread;
+ }
+
+ return 0;
+}
+
+static int
+report_prepare_subobjects(struct sr_py_report *report)
+{
+ /* packages */
+ if (rpms_prepare_linked_list(report) < 0)
+ return -1;
+
+ /* operating_system */
+ if (report->operating_system == Py_None)
+ {
+ report->report->operating_system = NULL;
+ }
+ else
+ {
+ if (!PyObject_TypeCheck(report->operating_system, &sr_py_operating_system_type))
+ {
+ PyErr_SetString(PyExc_TypeError, "operating_system must be an OperatingSystem object");
+ return -1;
+ }
+
+ report->report->operating_system =
+ ((struct sr_py_operating_system *)report->operating_system)->operating_system;
+ }
+
+ /* stacktrace */
+ if (report->stacktrace == Py_None)
+ {
+ report->report->stacktrace = NULL;
+ }
+ else
+ {
+ switch (report->report->report_type)
+ {
+ case SR_REPORT_CORE:
+ if(stacktrace_prepare(report, &sr_py_core_stacktrace_type, true) < 0)
+ return -1;
+ break;
+ case SR_REPORT_JAVA:
+ if (stacktrace_prepare(report, &sr_py_java_stacktrace_type, true) < 0)
+ return -1;
+ break;
+ case SR_REPORT_PYTHON:
+ if (stacktrace_prepare(report, &sr_py_python_stacktrace_type, false) < 0)
+ return -1;
+ break;
+ case SR_REPORT_KERNELOOPS:
+ if (stacktrace_prepare(report, &sr_py_koops_stacktrace_type, false) < 0)
+ return -1;
+ break;
+ default:
+ report->report->stacktrace = NULL;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+PyObject *
+report_to_python_obj(struct sr_report *report)
+{
+ struct sr_py_report *ro =
+ PyObject_New(struct sr_py_report, &sr_py_report_type);
+ if (!ro)
+ return PyErr_NoMemory();
+
+ ro->report = report;
+
+ /* wrap operating system in a python object */
+ if (report->operating_system)
+ {
+ struct sr_py_operating_system *os =
+ PyObject_New(struct sr_py_operating_system, &sr_py_operating_system_type);
+ if (!os)
+ return NULL;
+
+ os->operating_system = report->operating_system;
+ ro->operating_system = (PyObject *)os;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ ro->operating_system = Py_None;
+ }
+
+ /* packages */
+ ro->packages = rpms_to_python_list(report->rpm_packages);
+ if (ro->packages == NULL)
+ return NULL;
+
+ /* stacktrace */
+ /* XXX: this could be rewritten in a generic way */
+ if (report->stacktrace != NULL)
+ {
+ switch (report->report_type)
+ {
+ case SR_REPORT_CORE:
+ ro->stacktrace = core_stacktrace_to_python_obj(
+ (struct sr_core_stacktrace *)report->stacktrace);
+ break;
+ case SR_REPORT_JAVA:
+ ro->stacktrace = java_stacktrace_to_python_obj(
+ (struct sr_java_stacktrace *)report->stacktrace);
+ break;
+ case SR_REPORT_PYTHON:
+ ro->stacktrace = python_stacktrace_to_python_obj(
+ (struct sr_python_stacktrace *)report->stacktrace);
+ break;
+ case SR_REPORT_KERNELOOPS:
+ ro->stacktrace = koops_stacktrace_to_python_obj(
+ (struct sr_koops_stacktrace *)report->stacktrace);
+ break;
+ default:
+ Py_INCREF(Py_None);
+ ro->stacktrace = Py_None;
+ break;
+ }
+
+ if (ro->stacktrace == NULL)
+ return NULL;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ ro->stacktrace = Py_None;
+ }
+
+ return (PyObject *)ro;
+}
+
+/* constructor */
+PyObject *
+sr_py_report_new(PyTypeObject *object, PyObject *args, PyObject *kwds)
+{
+ const char *report_json = NULL;
+ if (!PyArg_ParseTuple(args, "|s", &report_json))
+ return NULL;
+
+ struct sr_report *report;
+
+ if (report_json)
+ {
+ char *error_msg;
+ report = sr_report_from_json_text(report_json, &error_msg);
+ if (!report)
+ {
+ PyErr_SetString(PyExc_ValueError, error_msg);
+ free(error_msg);
+ return NULL;
+ }
+ }
+ else
+ {
+ report = sr_report_new();
+ report->operating_system = sr_operating_system_new();
+ }
+
+ return report_to_python_obj(report);
+}
+
+/* destructor */
+void
+sr_py_report_free(PyObject *object)
+{
+ struct sr_py_report *this = (struct sr_py_report *)object;
+
+ /* python will free the subordinate objects once their refcount reaches zero */
+ /* XXX: is this correct wrt the warning on
+ * http://docs.python.org/2.7/c-api/refcounting.html?highlight=py_decref#Py_DECREF ? */
+ Py_DECREF(this->packages);
+ Py_DECREF(this->operating_system);
+ Py_DECREF(this->stacktrace);
+
+ /* if there was no other reference, these structs are free'd by now */
+ this->report->rpm_packages = NULL;
+ this->report->operating_system = NULL;
+ this->report->stacktrace = NULL;
+
+ sr_report_free(this->report);
+ PyObject_Del(object);
+}
+
+/* str */
+PyObject *
+sr_py_report_str(PyObject *object)
+{
+ struct sr_py_report *this = (struct sr_py_report*)object;
+ struct sr_strbuf *buf = sr_strbuf_new();
+
+ char *type = sr_report_type_to_string(this->report->report_type);
+ sr_strbuf_append_strf(buf, "Report, type: %s", type);
+ free(type);
+
+ if (this->report->component_name)
+ sr_strbuf_append_strf(buf, ", component: %s", this->report->component_name);
+
+ char *str = sr_strbuf_free_nobuf(buf);
+ PyObject *result = Py_BuildValue("s", str);
+ free(str);
+ return result;
+}
+
+PyObject *
+sr_py_report_get_version(PyObject *self, void *data)
+{
+ return PyInt_FromLong(((struct sr_py_report*)self)->report->report_version);
+}
+
+PyObject *
+sr_py_report_get_type(PyObject *self, void *data)
+{
+ struct sr_py_report *report = (struct sr_py_report *)self;
+
+ char *type = sr_report_type_to_string(report->report->report_type);
+ PyObject *res = PyString_FromString(type);
+
+ free(type);
+ return res;
+}
+
+int sr_py_report_set_type(PyObject *self, PyObject *rhs, void *data)
+{
+ struct sr_py_report *report = (struct sr_py_report *)self;
+
+ if (rhs == NULL)
+ {
+ PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute.");
+ return -1;
+ }
+
+ char *type_str = PyString_AsString(rhs);
+ if (!type_str)
+ return -1;
+
+ enum sr_report_type type = sr_report_type_from_string(type_str);
+ if (type == SR_REPORT_INVALID)
+ {
+ PyErr_SetString(PyExc_ValueError, "Invalid report type.");
+ return -1;
+ }
+
+ report->report->report_type = type;
+ return 0;
+}
+
+PyObject *
+sr_py_report_to_json(PyObject *self, PyObject *args)
+{
+ struct sr_py_report *this = (struct sr_py_report *)self;
+ if (report_prepare_subobjects(this) < 0)
+ return NULL;
+
+ char *json = sr_report_to_json(this->report);
+ if (!json)
+ return NULL;
+
+ PyObject *result = PyString_FromString(json);
+ free(json);
+ return result;
+}
diff --git a/python/py_report.h b/python/py_report.h
new file mode 100644
index 0000000..a451dbc
--- /dev/null
+++ b/python/py_report.h
@@ -0,0 +1,79 @@
+/*
+ py_report.h
+
+ Copyright (C) 2013 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef SATYR_PY_REPORT_H
+#define SATYR_PY_REPORT_H
+
+/**
+ * @file
+ * @brief Python bindings for struct sr_report.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Python.h>
+#include <structmember.h>
+
+PyTypeObject sr_py_report_type;
+
+struct sr_py_report
+{
+ PyObject_HEAD
+ struct sr_report *report;
+ PyObject *operating_system;
+ PyObject *packages;
+ PyObject *stacktrace;
+};
+
+/**
+ * Constructor.
+ */
+PyObject *sr_py_report_new(PyTypeObject *object,
+ PyObject *args, PyObject *kwds);
+
+/**
+ * Destructor.
+ */
+void sr_py_report_free(PyObject *object);
+
+/**
+ * str
+ */
+PyObject *sr_py_report_str(PyObject *self);
+
+/**
+ * getters & setters
+ */
+PyObject *sr_py_report_get_version(PyObject *self, void *data);
+PyObject *sr_py_report_get_type(PyObject *self, void *data);
+int sr_py_report_set_type(PyObject *self, PyObject *rhs, void *data);
+
+/**
+ * Methods.
+ */
+PyObject *
+sr_py_report_to_json(PyObject *self, PyObject *args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tests/json_files/ureport-1 b/tests/json_files/ureport-1
new file mode 100644
index 0000000..e71072c
--- /dev/null
+++ b/tests/json_files/ureport-1
@@ -0,0 +1,107 @@
+{
+ "ureport_version": 2,
+
+ "reason": "Program /usr/bin/sleep was terminated by signal 11",
+
+ "os": {
+ "name": "fedora",
+ "version": "18",
+ "architecture": "x86_64"
+ },
+
+ "problem": {
+ "type": "core",
+
+ "executable": "/usr/bin/sleep",
+
+ "signal": 11,
+
+ "component": "coreutils",
+
+ "user": {
+ "local": true,
+ "root": false
+ },
+
+ "stacktrace": [
+ {
+ "crash_thread": true,
+
+ "frames": [
+ {
+ "build_id": "5f6632d75fd027f5b7b410787f3f06c6bf73eee6",
+ "build_id_offset": 767024,
+ "file_name": "/lib64/libc.so.6",
+ "address": 251315074096,
+ "fingerprint": "6c1eb9626919a2a5f6a4fc4c2edc9b21b33b7354",
+ "function_name": "__nanosleep"
+ },
+ {
+ "build_id": "cd379d3bb5d07c96d491712e41c34bcd06b2ce32",
+ "build_id_offset": 16567,
+ "file_name": "/usr/bin/sleep",
+ "address": 4210871,
+ "fingerprint": "d24433b82a2c751fc580f47154823e0bed641a54",
+ "function_name": "close_stdout"
+ },
+ {
+ "build_id": "cd379d3bb5d07c96d491712e41c34bcd06b2ce32",
+ "build_id_offset": 16202,
+ "file_name": "/usr/bin/sleep",
+ "address": 4210506,
+ "fingerprint": "562719fb960d1c4dbf30c04b3cff37c82acc3d2d",
+ "function_name": "close_stdout"
+ },
+ {
+ "build_id": "cd379d3bb5d07c96d491712e41c34bcd06b2ce32",
+ "build_id_offset": 6404,
+ "fingerprint": "2e8fb95adafe21d035b9bcb9993810fecf4be657",
+ "file_name": "/usr/bin/sleep",
+ "address": 4200708
+ },
+ {
+ "build_id": "5f6632d75fd027f5b7b410787f3f06c6bf73eee6",
+ "build_id_offset": 137733,
+ "file_name": "/lib64/libc.so.6",
+ "address": 251314444805,
+ "fingerprint": "075acda5d3230e115cf7c88597eaba416bdaa6bb",
+ "function_name": "__libc_start_main"
+ }
+ ]
+ }
+ ]
+ },
+
+ "packages": [
+ {
+ "name": "coreutils",
+ "epoch": 0,
+ "version": "8.17",
+ "architecture": "x86_64",
+ "package_role": "affected",
+ "release": "8.fc18",
+ "install_time": 1371464601
+ },
+ {
+ "name": "glibc",
+ "epoch": 0,
+ "version": "2.16",
+ "architecture": "x86_64",
+ "release": "31.fc18",
+ "install_time": 1371464176
+ },
+ {
+ "name": "glibc-common",
+ "epoch": 0,
+ "version": "2.16",
+ "architecture": "x86_64",
+ "release": "31.fc18",
+ "install_time": 1371464184
+ }
+ ],
+
+ "reporter": {
+ "version": "0.3",
+ "name": "satyr"
+ }
+}
diff --git a/tests/python/report.py b/tests/python/report.py
index da00b08..9da2fa8 100755
--- a/tests/python/report.py
+++ b/tests/python/report.py
@@ -33,6 +33,55 @@ class TestRpmPackage(BindingsTestCase):
self.assertGetSetCorrect(self.rpm, 'install_time', 0, 1234565)
self.assertGetSetCorrect(self.rpm, 'role', satyr.ROLE_UNKNOWN, satyr.ROLE_AFFECTED)

+class TestReport(BindingsTestCase):
+ def setUp(self):
+ self.report_json = load_input_contents('../json_files/ureport-1')
+ self.report = satyr.Report(self.report_json)
+
+ def test_to_json(self):
+ '''
+ Check that loading a report and converting it to json again produces
+ the same output.
+ '''
+ import json
+
+ source = json.loads(self.report_json)
+ output = json.loads(self.report.to_json())
+ self.assertEqual(source, output)
+
+ def test_getset(self):
+ self.assertGetSetCorrect(self.report, 'reporter_name', 'satyr', 'abrt')
+ self.assertGetSetCorrect(self.report, 'reporter_version', '0.3', '0.2')
+ self.assertGetSetCorrect(self.report, 'user_root', False, True)
+ self.assertGetSetCorrect(self.report, 'user_local', True, False)
+ self.assertGetSetCorrect(self.report, 'component_name', 'coreutils', 'zsh')
+
+ self.assertGetSetCorrect(self.report, 'report_type', 'core', 'python')
+ self.assertRaises(ValueError, self.report.__setattr__, 'report_type', 'C#')
+
+ self.assertEqual(self.report.report_version, 2)
+ self.assertRaises(AttributeError, self.report.__setattr__, 'report_version', 42)
+
+ def test_attributes(self):
+ self.assertTrue(self.report.stacktrace != None)
+ self.assertTrue(isinstance(self.report.stacktrace, satyr.CoreStacktrace))
+ self.assertTrue(len(self.report.stacktrace.threads) == 1)
+ self.assertTrue(len(self.report.stacktrace.threads[0].frames) == 5)
+
+ self.assertTrue(self.report.operating_system != None)
+ self.assertTrue(isinstance(self.report.operating_system, satyr.OperatingSystem))
+ self.assertEqual(self.report.operating_system.name, 'fedora')
+ self.assertEqual(self.report.operating_system.version, '18')
+ self.assertEqual(self.report.operating_system.architecture, 'x86_64')
+ self.assertEqual(self.report.operating_system.cpe, None)
+
+ self.assertTrue(self.report.packages != None)
+ self.assertTrue(isinstance(self.report.packages, list))
+ self.assertTrue(isinstance(self.report.packages[0], satyr.RpmPackage))
+ self.assertTrue(len(self.report.packages) == 3)
+ self.assertEqual(self.report.packages[0].name, 'coreutils')
+ self.assertEqual(self.report.packages[0].role, satyr.ROLE_AFFECTED)
+

if __name__ == '__main__':
unittest.main()
--
1.8.3.1
Richard Marko
2013-08-28 13:36:35 UTC
Permalink
Pushed. Good job!
Post by Martin Milata
Please note that this patchset depends on following, as of yet unreviewed
[SATYR PATCHv3 1/7] Add sr_java_frame_append
[SATYR PATCHv3 2/7] Helper functions for json deserialization
[SATYR PATCHv3 3/7] Implement JSON deserialization for reports
[SATYR PATCHv3 4/7] Type-agnostic JSON deserialization
[SATYR PATCHv3 5/7] python: add version attribute to Kerneloops object
[SATYR PATCHv3 6/7] python: expose from_json for stacktraces
[SATYR PATCHv3 7/7] tests for json deserialization of stacktraces
[SATYR PATCHv3] python: treat UINT64_MAX as None
* * *
python: bindings for struct sr_operating_system
python: bindings for struct sr_rpm_package
Minor json parsing refactorization
report: function for parsing json text
Helpers for converting report type to/from string
report: use generic stacktrace type
python: factor out stacktrace object creation
python: bindings for struct sr_report
include/json.h | 2 +-
include/report.h | 14 +-
include/report_type.h | 8 +
lib/Makefile.am | 2 +-
lib/abrt.c | 34 +--
lib/core_stacktrace.c | 19 +-
lib/generic_stacktrace.c | 15 +-
lib/json.c | 10 +-
lib/report.c | 129 +++++------
python/Makefile.am | 6 +
python/py_common.c | 7 +
python/py_common.h | 4 +
python/py_core_stacktrace.c | 64 +++---
python/py_core_stacktrace.h | 3 +
python/py_java_stacktrace.c | 65 +++---
python/py_java_stacktrace.h | 3 +
python/py_koops_stacktrace.c | 59 +++--
python/py_koops_stacktrace.h | 3 +
python/py_module.c | 35 +++
python/py_operating_system.c | 167 ++++++++++++++
python/py_operating_system.h | 63 ++++++
python/py_python_stacktrace.c | 59 +++--
python/py_python_stacktrace.h | 3 +
python/py_report.c | 491 ++++++++++++++++++++++++++++++++++++++++++
python/py_report.h | 79 +++++++
python/py_rpm_package.c | 225 +++++++++++++++++++
python/py_rpm_package.h | 67 ++++++
tests/Makefile.am | 1 +
tests/json_files/ureport-1 | 107 +++++++++
tests/python/report.py | 88 ++++++++
tests/python_bindings.at | 1 +
tests/report.at | 59 +++++
tests/testsuite.at | 1 +
33 files changed, 1625 insertions(+), 268 deletions(-)
create mode 100644 python/py_operating_system.c
create mode 100644 python/py_operating_system.h
create mode 100644 python/py_report.c
create mode 100644 python/py_report.h
create mode 100644 python/py_rpm_package.c
create mode 100644 python/py_rpm_package.h
create mode 100644 tests/json_files/ureport-1
create mode 100755 tests/python/report.py
create mode 100644 tests/report.at
--
Richard Marko
Continue reading on narkive:
Loading...