Package: python3-augeas
Version: 0.5.0-1
Severity: wishlist
Tags: patch

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Dear Maintainer,

The newer version of package available in upstream git repository use cffi
library instead of ctypes to load the C augeas library. This sidesteps the
problem described in #944364. One could also take this opportunity to migrate
the git repository to Salsa (perhaps under the python-team).

I have done the necessary work for the new release, the patches are attached
with following changes:

  * control: Update list of dependencies
  * control: Remove unnecessary python version fields
  * control: Specify that rules file does not require root
  * control: Update standards version to 4.4.1. No changes required.
  * control: Enable autopkgtest-pkg-python
  * control: Update debhelper compatibility level to 12
  * rules: Run tests during build

Thank you,

- --
Sunil



- -- System Information:
Debian Release: 10.2
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable')
Architecture: amd64 (x86_64)

Kernel: Linux 4.19.0-6-amd64 (SMP w/4 CPU cores)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=en_IN.UTF-8, LC_CTYPE=en_IN.UTF-8 (charmap=UTF-8), 
LANGUAGE=en_IN.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages python3-augeas depends on:
ii  libaugeas0  1.11.0-3
ii  python3     3.7.3-1

python3-augeas recommends no packages.

python3-augeas suggests no packages.

- -- no debconf information

-----BEGIN PGP SIGNATURE-----

iQJFBAEBCgAvFiEE5xPDY9ZyWnWupXSBQ+oc/wqnxfIFAl39hzoRHHN1bmlsQG1l
ZGhhcy5vcmcACgkQQ+oc/wqnxfJoYA/+NOZEDuYybEq9g1CfHNx23xUINGysjxAp
qNEpuUYWRkvtHHDKjuCtaKeUsim0TQ4tWcbCpv7xNzMIOZY6PuZv75Jm3Kn8hAo7
ocO9c4osIVUhj05+hkaBA5xVXDFnulZDqn63LY69Df6PKN/0k4ov1kLsBpZ/Wle0
cUFynK5018ticnDVTaI/F6Lzu6gOr6+0H4TABW4PV+pRAMHz0l286rRMOFurid5A
MlmQlAug3yyrKwDP7WQiuujTxGisNWJYmIqkfETe/ibExkNNbUaJF73gyrmJu2e/
lIrtG4E+ysJrmGXAR+eoP/HNRczbjnXdwgdexD2A26RTyVB5lSi1kMS0COZRf0PE
/EckOm7hOXtk2IHmNHJJyIwlXTGjuA6kqo9Jnt6gKvWzwRdTaAfLmI4rh8mEIELG
1n5OUKXDNrJUNEQlWzqBNbNV7L876qSLcAHlSc0/1FatFMvGqsosggnmDyCuTkQN
TzM1xuAksbiUfOKUN9z+rsx9sjCwIewDWuoG5oL5NVHWskijTOrcK6Sowo3ukV3D
t1RxCF34nHWpsBy54E4kYOXs+IcUOnU8fztSfbI2M77XGuVUWQeTU3LyryTPMESd
1v1461vorHTa1+WwSEeZ3EQusOCzWWO3CdRdy0uJbTBS7ljqplIMbwo+O0obaOps
CTnyx2IAyig=
=ePp7
-----END PGP SIGNATURE-----
>From 7f8cb9c9adbb8cc0bf16f394ff0bae23db9f1a8d Mon Sep 17 00:00:00 2001
From: Sandro Tosi <mo...@debian.org>
Date: Fri, 20 Dec 2019 16:30:56 -0800
Subject: [PATCH 01/10] Release 0.5.0-1.1, non-maintainer upload

---
 debian/changelog |  7 +++++++
 debian/control   | 15 ---------------
 debian/rules     |  3 +--
 3 files changed, 8 insertions(+), 17 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 465320f..cabcd63 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+python-augeas (0.5.0-1.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Drop python2 support; Closes: #937588, #734557
+
+ -- Sandro Tosi <mo...@debian.org>  Wed, 16 Oct 2019 22:17:14 -0400
+
 python-augeas (0.5.0-1) unstable; urgency=low
 
   * New upstream release
diff --git a/debian/control b/debian/control
index 2e7be81..f2e571e 100644
--- a/debian/control
+++ b/debian/control
@@ -6,7 +6,6 @@ Build-Depends:
  debhelper (>= 9~),
  dh-python,
  libaugeas0 (>= 0.7.2),
- python-all (>= 2.6.5),
  python3-all
 Standards-Version: 3.9.6
 X-Python-Version: >= 2.6
@@ -15,20 +14,6 @@ Homepage: http://augeas.net/
 Vcs-Git: git://anonscm.debian.org/collab-maint/python-augeas.git
 Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/python-augeas.git
 
-Package: python-augeas
-Architecture: all
-Depends:
- libaugeas0 (>= 0.7.2),
- ${misc:Depends},
- ${python:Depends}
-Description: Python bindings for Augeas
- Augeas is a library and command line tool that focuses
- on the most basic problem in handling Linux configurations
- programmatically: editing actual configuration files in a
- controlled manner.
- .
- This module provides a Python interface to the Augeas API.
-
 Package: python3-augeas
 Architecture: all
 Depends:
diff --git a/debian/rules b/debian/rules
index 9b2702b..94d7f97 100755
--- a/debian/rules
+++ b/debian/rules
@@ -2,8 +2,7 @@
 
 export DH_VERBOSE=1
 export PYBUILD_NAME=augeas
-export PYBUILD_DESTDIR_python2=debian/python-augeas/
 export PYBUILD_DESTDIR_python3=debian/python3-augeas/
 
 %:
-       dh $@ --buildsystem=pybuild --with python2,python3
+       dh $@ --buildsystem=pybuild --with python3
-- 
2.20.1

>From 45c94f8f71d8db4bba7bd308fa3bc83e68275758 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa <su...@medhas.org>
Date: Fri, 20 Dec 2019 16:35:38 -0800
Subject: [PATCH 02/10] New upstream version 1.0.3

---
 .gitignore                      | 101 +++++++++++++++++
 .travis.yml                     |  31 ++++--
 Makefile                        |   5 +-
 augeas.py => augeas/__init__.py | 192 ++++++++++++++++----------------
 augeas/ffi.py                   |  45 ++++++++
 setup.py                        |  11 +-
 test/test_augeas.py             |  60 ++++++++--
 7 files changed, 326 insertions(+), 119 deletions(-)
 rename augeas.py => augeas/__init__.py (83%)
 create mode 100644 augeas/ffi.py
 mode change 100644 => 100755 setup.py

diff --git a/.gitignore b/.gitignore
index b408e6c..02c0586 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,102 @@
 /.pc
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*,cover
+.hypothesis/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# dotenv
+.env
+
+# virtualenv
+.venv
+venv/
+ENV/
+
+# Spyder project settings
+.spyderproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# augeas logs
+*.out
diff --git a/.travis.yml b/.travis.yml
index 5102158..634ef4b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,15 +1,26 @@
 language: python
 python:
-  - 2.6
-  - 2.7
-  - 3.2
-  - 3.3
+- 2.6
+- 2.7
+- 3.3
+- 3.4
+- 3.5
+- pypy
 notifications:
   email:
-   - raphael.pin...@camptocamp.com
+  - raphael.pin...@camptocamp.com
 install:
-  # Use latest Augeas
-  - sudo add-apt-repository -y ppa:raphink/augeas-dev
-  - sudo apt-get update
-  - sudo apt-get install libaugeas-dev libxml2-dev
-script: make && make check
+- sudo add-apt-repository -y ppa:raphink/augeas
+- sudo apt-get update
+- sudo apt-get install libaugeas-dev
+- pip install .
+script: make check
+deploy:
+  provider: pypi
+  user: the_drow
+  password:
+    secure: 
FAsA8tIeTBhQQsJflaUwlE8XLIBjPMdmoT8WRVNkFght6ANdaW7+W9HznQvPc8qMbOpT8/K6ToTd8bIb678VRPhzxBkmpStj78wPPET5Q8MANakik73azqfvu6OMKXwpbcLtbaeeqZkRE5LP0ueYyGKtyyvR7iGtBmJbawYiEjo=
+  on:
+    tags: true
+    distributions: sdist bdist_wheel
+    repo: hercules-team/python-augeas
diff --git a/Makefile b/Makefile
index 7c7b9bf..cfd40b6 100644
--- a/Makefile
+++ b/Makefile
@@ -6,12 +6,13 @@ all: build
 
 clean:
        PREFIX=$(PREFIX) python setup.py clean
-       rm -f augeas.py* 
+       rm -f augeas.py*
 
 distclean: clean
        rm -fr build dist MANIFEST
 
-build: augeas.py
+build:
+       PREFIX=$(PREFIX) python setup.py build
 
 install:
        PREFIX=$(PREFIX) python setup.py install
diff --git a/augeas.py b/augeas/__init__.py
similarity index 83%
rename from augeas.py
rename to augeas/__init__.py
index ca5e191..b9e75f4 100644
--- a/augeas.py
+++ b/augeas/__init__.py
@@ -37,18 +37,16 @@ __credits__ = """Jeff Schroeder <jeffschroe...@computer.org>
 Harald Hoyer <har...@redhat.com> - initial python bindings, packaging
 Nils Philippsen <n...@redhat.com>
 """
-
-import types
-import ctypes
-import ctypes.util
-from sys import version_info as _pyver
 from functools import reduce
+from sys import version_info as _pyver
 
+import cffi
+import types
+from augeas.ffi import ffi, lib
 
 PY3 = _pyver >= (3,)
 AUGENC = 'utf8'
 
-
 if PY3:
     string_types = str
 else:
@@ -58,30 +56,19 @@ else:
 def enc(st):
     if st:
         return st.encode(AUGENC)
+    else:
+        return b''
 
 
 def dec(st):
     if st:
         return st.decode(AUGENC)
+    else:
+        return b''
 
 
-def _dlopen(*args):
-    """Search for one of the libraries given as arguments and load it.
-    Returns the library.
-    """
-    libs = [l for l in [ ctypes.util.find_library(a) for a in args ] if l]
-    lib  = reduce(lambda x, y: x or ctypes.cdll.LoadLibrary(y), libs, None)
-    if not lib:
-        raise ImportError("Unable to import lib%s!" % args[0])
-    return lib
-
 class Augeas(object):
     "Class wrapper for the augeas library"
-
-    # Load libaugeas
-    _libaugeas = _dlopen("augeas")
-    _libaugeas.aug_init.restype = ctypes.c_void_p
-
     # Augeas Flags
     NONE = 0
     SAVE_BACKUP = 1 << 0
@@ -114,15 +101,13 @@ class Augeas(object):
         if not isinstance(flags, int):
             raise TypeError("flag MUST be a flag!")
 
+        root = enc(root) if root else ffi.NULL
+        loadpath = enc(loadpath) if loadpath else ffi.NULL
+
         # Create the Augeas object
-        self.__handle = Augeas._libaugeas.aug_init(enc(root), enc(loadpath), 
flags)
+        self.__handle = ffi.gc(lib.aug_init(root, loadpath, flags), lambda x: 
self.close)
         if not self.__handle:
             raise RuntimeError("Unable to create Augeas object!")
-        # Make sure self.__handle is a void*, not an integer
-        self.__handle = ctypes.c_void_p(self.__handle)
-
-    def __del__(self):
-        self.close()
 
     def get(self, path):
         """Lookup the value associated with 'path'.
@@ -136,15 +121,14 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Create the char * value
-        value = ctypes.c_char_p()
+        value = ffi.new("char*[]", 1)
 
         # Call the function and pass value by reference (char **)
-        ret = Augeas._libaugeas.aug_get(self.__handle, enc(path),
-                                        ctypes.byref(value))
-        if ret > 1:
-            raise ValueError("path specified had too many matches!")
+        ret = lib.aug_get(self.__handle, enc(path), value)
+        if ret < 0:
+            raise ValueError("path specified had too many matches or is 
illegal!")
 
-        return dec(value.value)
+        return dec(ffi.string(value[0])) if value[0] != ffi.NULL else None
 
     def label(self, path):
         """Lookup the label associated with 'path'.
@@ -158,15 +142,14 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Create the char * value
-        label = ctypes.c_char_p()
+        label = ffi.new("char*[]", 1)
 
         # Call the function and pass value by reference (char **)
-        ret = Augeas._libaugeas.aug_label(self.__handle, enc(path),
-                                          ctypes.byref(label))
-        if ret > 1:
-            raise ValueError("path specified had too many matches!")
+        ret = lib.aug_label(self.__handle, enc(path), label)
+        if ret < 0:
+            raise ValueError("path specified had too many matches or is 
illegal!")
 
-        return dec(label.value)
+        return dec(ffi.string(label[0])) if label[0] != ffi.NULL else None
 
     def set(self, path, value):
         """Set the value associated with 'path' to 'value'.
@@ -182,7 +165,7 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Call the function
-        ret = Augeas._libaugeas.aug_set(self.__handle, enc(path), enc(value))
+        ret = lib.aug_set(self.__handle, enc(path), enc(value))
         if ret != 0:
             raise ValueError("Unable to set value to path!")
 
@@ -198,13 +181,13 @@ class Augeas(object):
             raise TypeError("base MUST be a string!")
         if type(sub) != str and sub != None:
             raise TypeError("sub MUST be a string or None!")
-        if type(value) != str:
-            raise TypeError("value MUST be a string!")
+        if type(value) != str and value != None:
+            raise TypeError("value MUST be a string or None!")
         if not self.__handle:
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Call the function
-        ret = Augeas._libaugeas.aug_setm(
+        ret = lib.aug_setm(
             self.__handle, enc(base), enc(sub), enc(value))
         if ret < 0:
             raise ValueError("Unable to set value to path!")
@@ -226,7 +209,7 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Call the function
-        ret = Augeas._libaugeas.aug_text_store(
+        ret = lib.aug_text_store(
             self.__handle, enc(lens), enc(node), enc(path))
         if ret != 0:
             raise ValueError("Unable to store text at node!")
@@ -250,7 +233,7 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Call the function
-        ret = Augeas._libaugeas.aug_text_retrieve(
+        ret = lib.aug_text_retrieve(
             self.__handle, enc(lens), enc(node_in), enc(path), enc(node_out))
         if ret != 0:
             raise ValueError("Unable to store text at node!")
@@ -260,10 +243,10 @@ class Augeas(object):
         """Define a variable 'name' whose value is the result of
         evaluating 'expr'. If a variable 'name' already exists, its
         name will be replaced with the result of evaluating 'expr'.
- 
+
         If 'expr' is None, the variable 'name' will be removed if it
         is defined.
- 
+
         Path variables can be used in path expressions later on by
         prefixing them with '$'."""
 
@@ -276,7 +259,7 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Call the function
-        ret = Augeas._libaugeas.aug_defvar(self.__handle, enc(name), enc(expr))
+        ret = lib.aug_defvar(self.__handle, enc(name), enc(expr))
         if ret < 0:
             raise ValueError("Unable to register variable!")
         return ret
@@ -286,7 +269,7 @@ class Augeas(object):
         evaluating 'expr', which must not be None and evaluate to a
         nodeset. If a variable 'name' already exists, its name will
         be replaced with the result of evaluating 'expr'.
- 
+
         If 'expr' evaluates to an empty nodeset, a node is created,
         equivalent to calling set(expr, value) and 'name' will be the
         nodeset containing that single node."""
@@ -302,8 +285,8 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Call the function
-        ret = Augeas._libaugeas.aug_defnode(
-            self.__handle, enc(name), enc(expr), enc(value), None)
+        ret = lib.aug_defnode(
+            self.__handle, enc(name), enc(expr), enc(value), ffi.NULL)
         if ret < 0:
             raise ValueError("Unable to register node!")
         return ret
@@ -324,10 +307,30 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Call the function
-        ret = Augeas._libaugeas.aug_mv(self.__handle, enc(src), enc(dst))
+        ret = lib.aug_mv(self.__handle, enc(src), enc(dst))
         if ret != 0:
             raise ValueError("Unable to move src to dst!")
 
+    def copy(self, src, dst):
+        """Copy the node 'src' to 'dst'. 'src' must match exactly one node
+           in the tree. 'dst' must either match exactly one node in the
+           tree, or may not exist yet. If 'dst' exists already, it and all
+           its descendants are deleted before copying 'src' there. If 'dst'
+           does not exist yet, it and all its missing ancestors are created."""
+
+        # Sanity checks
+        if not isinstance(src, string_types):
+            raise TypeError("src MUST be a string!")
+        if not isinstance(dst, string_types):
+            raise TypeError("dst MUST be a string!")
+        if not self.__handle:
+            raise RuntimeError("The Augeas object has already been closed!")
+
+        # Call the function
+        ret = lib.aug_cp(self.__handle, enc(src), enc(dst))
+        if ret != 0:
+            raise ValueError("Unable to copy src to dst!")
+
     def rename(self, src, dst):
         """Rename the label of all nodes matching 'src' to 'lbl'."""
 
@@ -340,7 +343,7 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Call the function
-        ret = Augeas._libaugeas.aug_rename(self.__handle, enc(src), enc(dst))
+        ret = lib.aug_rename(self.__handle, enc(src), enc(dst))
         if ret < 0:
             raise ValueError("Unable to rename src as dst!")
         return ret
@@ -363,8 +366,8 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Call the function
-        ret = Augeas._libaugeas.aug_insert(self.__handle, enc(path),
-                                           enc(label), before and 1 or 0)
+        ret = lib.aug_insert(self.__handle, enc(path),
+                             enc(label), before and 1 or 0)
         if ret != 0:
             raise ValueError("Unable to insert label!")
 
@@ -380,7 +383,7 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Call the function
-        return Augeas._libaugeas.aug_rm(self.__handle, enc(path))
+        return lib.aug_rm(self.__handle, enc(path))
 
     def match(self, path):
         """Return the matches of the path expression 'path'. The returned paths
@@ -404,31 +407,22 @@ class Augeas(object):
         if not self.__handle:
             raise RuntimeError("The Augeas object has already been closed!")
 
-        # Create a void ** (this is so python won't mangle the char **,
-        # when we free it)
-        array = ctypes.POINTER(ctypes.c_void_p)()
+        parray = ffi.new('char***')
 
-        # Call the function and pass the void ** by reference (void ***)
-        ret = Augeas._libaugeas.aug_match(self.__handle, enc(path),
-                                          ctypes.byref(array))
+        ret = lib.aug_match(self.__handle, enc(path), parray)
         if ret < 0:
             raise RuntimeError("Error during match procedure!", path)
 
         # Loop through the string array
+        array = parray[0]
         matches = []
         for i in range(ret):
-            if array[i]:
+            if array[i] != ffi.NULL:
                 # Create a python string and append it to our matches list
-                matches.append(dec(ctypes.cast(array[i],
-                                               ctypes.c_char_p).value))
-
-                # Free the string at this point in the array
-                # Wrap the string as a void* as it was not allocated by Python
-                ctypes.pythonapi.PyMem_Free(ctypes.c_void_p(array[i]))
-
-        # Free the array itself
-        ctypes.pythonapi.PyMem_Free(array)
-
+                item = ffi.string(array[i])
+                matches.append(dec(item))
+                lib.free(array[i])
+        lib.free(array)
         return matches
 
     def span(self, path):
@@ -444,26 +438,26 @@ class Augeas(object):
         if not self.__handle:
             raise RuntimeError("The Augeas object has already been closed!")
 
-        filename = ctypes.c_char_p()
-        label_start = ctypes.c_uint()
-        label_end = ctypes.c_uint()
-        value_start = ctypes.c_uint()
-        value_end = ctypes.c_uint()
-        span_start = ctypes.c_uint()
-        span_end = ctypes.c_uint()
+        # TODO: Rewrite this
 
-        r = ctypes.byref
+        filename = ffi.new('char **')
+        label_start = ffi.new('unsigned int *')
+        label_end = ffi.new('unsigned int *')
+        value_start = ffi.new('unsigned int *')
+        value_end = ffi.new('unsigned int *')
+        span_start = ffi.new('unsigned int *')
+        span_end = ffi.new('unsigned int *')
 
-        ret = Augeas._libaugeas.aug_span(self.__handle, enc(path), r(filename),
-                                         r(label_start), r(label_end),
-                                         r(value_start), r(value_end),
-                                         r(span_start), r(span_end))
+        ret = lib.aug_span(self.__handle, enc(path), filename,
+                           label_start, label_end,
+                           value_start, value_end,
+                           span_start, span_end)
         if (ret < 0):
             raise ValueError("Error during span procedure")
-
-        return (dec(filename.value), label_start.value, label_end.value,
-                value_start.value, value_end.value,
-                span_start.value, span_end.value)
+        fname = dec(ffi.string(filename[0])) if filename != ffi.NULL else None
+        return (fname, int(label_start[0]), int(label_end[0]),
+                int(value_start[0]), int(value_end[0]),
+                int(span_start[0]), int(span_end[0]))
 
     def save(self):
         """Write all pending changes to disk. Only files that had any changes
@@ -483,7 +477,7 @@ class Augeas(object):
             raise RuntimeError("The Augeas object has already been closed!")
 
         # Call the function
-        ret = Augeas._libaugeas.aug_save(self.__handle)
+        ret = lib.aug_save(self.__handle)
         if ret != 0:
             raise IOError("Unable to save to file!")
 
@@ -515,7 +509,7 @@ class Augeas(object):
         if not self.__handle:
             raise RuntimeError("The Augeas object has already been closed!")
 
-        ret = Augeas._libaugeas.aug_load(self.__handle)
+        ret = lib.aug_load(self.__handle)
         if ret != 0:
             raise RuntimeError("aug_load() failed!")
 
@@ -537,9 +531,9 @@ class Augeas(object):
             import warnings
             warnings.warn("name is now deprecated in this function", 
DeprecationWarning,
                           stacklevel=2)
-        if isinstance (incl, string_types):
+        if isinstance(incl, string_types):
             incl = [incl]
-        if isinstance (excl, string_types):
+        if isinstance(excl, string_types):
             excl = [excl]
 
         for i in range(len(incl)):
@@ -564,7 +558,7 @@ class Augeas(object):
         if not self.__handle:
             raise RuntimeError("The Augeas object has already been closed!")
 
-        ret = Augeas._libaugeas.aug_transform(self.__handle, enc(lens), 
enc(file), excl)
+        ret = lib.aug_transform(self.__handle, enc(lens), enc(file), excl)
         if ret != 0:
             raise RuntimeError("Unable to add transform!")
 
@@ -574,15 +568,16 @@ class Augeas(object):
         for any more operations."""
 
         # If we are already closed, return
-        if not self.__handle:
+        if not self.__handle or self.__handle == ffi.NULL:
             return
 
         # Call the function
-        Augeas._libaugeas.aug_close(self.__handle)
+        lib.aug_close(self.__handle)
 
         # Mark the object as closed
         self.__handle = None
 
+
 # for backwards compatibility
 # pylint: disable-msg=C0103
 class augeas(Augeas):
@@ -591,5 +586,8 @@ class augeas(Augeas):
     def __init__(self, *p, **k):
         import warnings
         warnings.warn("use Augeas instead of augeas", DeprecationWarning,
-                stacklevel=2)
+                      stacklevel=2)
         super(augeas, self).__init__(*p, **k)
+
+
+__all__ = ['Augeas', 'augeas']
diff --git a/augeas/ffi.py b/augeas/ffi.py
new file mode 100644
index 0000000..6bc7719
--- /dev/null
+++ b/augeas/ffi.py
@@ -0,0 +1,45 @@
+from cffi import FFI
+
+ffi = FFI()
+ffi.set_source("augeas",
+               None,
+               libraries=['augeas'])
+
+ffi.cdef("""
+typedef struct augeas augeas;
+
+augeas *aug_init(const char *root, const char *loadpath, unsigned int flags);
+int aug_defvar(augeas *aug, const char *name, const char *expr);
+int aug_defnode(augeas *aug, const char *name, const char *expr,
+                const char *value, int *created);
+int aug_get(const augeas *aug, const char *path, const char **value);
+int aug_label(const augeas *aug, const char *path, const char **label);
+int aug_set(augeas *aug, const char *path, const char *value);
+int aug_setm(augeas *aug, const char *base, const char *sub, const char 
*value);
+int aug_span(augeas *aug, const char *path, char **filename,
+        unsigned int *label_start, unsigned int *label_end,
+        unsigned int *value_start, unsigned int *value_end,
+        unsigned int *span_start, unsigned int *span_end);
+int aug_insert(augeas *aug, const char *path, const char *label, int before);
+int aug_rm(augeas *aug, const char *path);
+int aug_mv(augeas *aug, const char *src, const char *dst);
+int aug_cp(augeas *aug, const char *src, const char *dst);
+int aug_rename(augeas *aug, const char *src, const char *lbl);
+int aug_match(const augeas *aug, const char *path, char ***matches);
+int aug_save(augeas *aug);
+int aug_load(augeas *aug);
+int aug_text_store(augeas *aug, const char *lens, const char *node,
+                   const char *path);
+int aug_text_retrieve(struct augeas *aug, const char *lens,
+                      const char *node_in, const char *path,
+                      const char *node_out);
+int aug_transform(augeas *aug, const char *lens, const char *file, int excl);
+void aug_close(augeas *aug);
+
+void free(void *);
+""")
+
+lib = ffi.dlopen("augeas")
+
+if __name__ == "__main__":
+    ffi.compile(verbose=True)
diff --git a/setup.py b/setup.py
old mode 100644
new mode 100755
index 4f7554d..aaa5be4
--- a/setup.py
+++ b/setup.py
@@ -5,15 +5,20 @@ setup.py file for augeas
 """
 
 import os
+
+from setuptools import setup, find_packages
+
 prefix = os.environ.get("prefix", "/usr")
 
-from distutils.core import setup
 
 setup (name = 'python-augeas',
-       version = '0.5.0',
+       version = '1.0.3',
        author      = "Harald Hoyer",
        author_email = "augeas-de...@redhat.com",
        description = """Python bindings for Augeas""",
-       py_modules = [ "augeas" ],
+       packages=find_packages(exclude=('test')),
+       setup_requires=["cffi>=1.0.0"],
+       cffi_modules=["augeas/ffi.py:ffi"],
+       install_requires=["cffi>=1.0.0"],
        url = "http://augeas.net/";,
        )
diff --git a/test/test_augeas.py b/test/test_augeas.py
index 10edbe6..68bdc2e 100644
--- a/test/test_augeas.py
+++ b/test/test_augeas.py
@@ -1,8 +1,8 @@
 from __future__ import print_function
 
-import unittest
-import sys
 import os
+import sys
+import unittest
 
 __mydir = os.path.dirname(sys.argv[0])
 if not os.path.isdir(__mydir):
@@ -33,10 +33,22 @@ def recurmatch(aug, path):
                     yield x
 
 class TestAugeas(unittest.TestCase):
-    def test01Get(self):
-        "test aug_get"
+    def test01aGetNone(self):
+        "test aug_get with non-existing path"
+        a = augeas.Augeas(root=MYROOT)
+        self.failUnless(a.get("/wrong/path") is None)
+        del a
+
+    def test01bGetValue(self):
+        "test aug_get with existing path"
         a = augeas.Augeas(root=MYROOT)
-        self.failUnless(a.get("/wrong/path") == None)
+        self.assertEqual(a.get("/files/etc/hosts/1/ipaddr"), "127.0.0.1")
+        del a
+
+    def test01cGetException(self):
+        "test aug_get with incorrect path"
+        a = augeas.Augeas(root=MYROOT)
+        self.assertRaises(ValueError, a.get, "/files//[1]/")
         del a
 
     def test02Match(self):
@@ -86,7 +98,7 @@ class TestAugeas(unittest.TestCase):
             for attr in a.match(i+"/*"):
                 self.failUnless(a.get(attr) != None)
         del a
-        
+
     def test06Defnode(self):
         "test defnode"
         a = augeas.Augeas(root=MYROOT)
@@ -158,6 +170,10 @@ class TestAugeas(unittest.TestCase):
             error = e
         self.assertTrue(isinstance(error, ValueError))
 
+    def testSetNone(self):
+        a = augeas.Augeas(root=MYROOT)
+        r = a.set("/raw/hosts", None);
+
     def test10TextRetrieve(self):
         hosts = "192.168.0.1 rtr.example.com router\n"
         a = augeas.Augeas(root=MYROOT)
@@ -212,12 +228,42 @@ class TestAugeas(unittest.TestCase):
         excl = a.get("/augeas/load/Foo/excl")
         self.assertEqual(excl, "/tmp/baz")
 
-    def test14Label(self):
+    def test14aLabelOk(self):
+        """test aug_label with valid input"""
         a = augeas.Augeas(root=MYROOT)
 
         lbl = a.label("/augeas/version")
         self.assertEqual(lbl, "version")
 
+    def test14bLabelException(self):
+        """test aug_label with invalid input"""
+        a = augeas.Augeas(root=MYROOT)
+
+        self.assertRaises(ValueError, a.label, "/augeas/version/[1]/")
+
+    def test15Copy(self):
+        a = augeas.Augeas(root=MYROOT)
+
+        orig_path = '/tmp/src/copy_test/a'
+        copy_path = '/tmp/dst/copy_test/a'
+        orig_value = 'test value'
+
+        a.set(orig_path, orig_value)
+
+        matches = a.match(orig_path)
+        self.failUnless(matches)
+
+        a.copy(orig_path, copy_path)
+
+        matches = a.match(copy_path)
+        self.failUnless(matches)
+        self.assertEqual(a.get(copy_path), a.get(orig_path))
+
+    def testClose(self):
+        a = augeas.Augeas(root=MYROOT)
+        a.close()
+
+
 def getsuite():
     suite = unittest.TestSuite()
     suite = unittest.makeSuite(TestAugeas, 'test')
-- 
2.20.1

>From 4ee4b627d7b6892667023717cea462d42f55199e Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa <su...@medhas.org>
Date: Fri, 20 Dec 2019 16:40:13 -0800
Subject: [PATCH 03/10] Prepare for release 1.0.3-1

Signed-off-by: Sunil Mohan Adapa <su...@medhas.org>
---
 debian/changelog | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index cabcd63..ddf874f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+python-augeas (1.0.3-1) UNRELEASED; urgency=medium
+
+  * New upstream release
+
+ -- Sunil Mohan Adapa <su...@medhas.org>  Fri, 20 Dec 2019 16:39:33 -0800
+
 python-augeas (0.5.0-1.1) unstable; urgency=medium
 
   * Non-maintainer upload.
-- 
2.20.1

>From ce69a6c36309439d811076f6e5f1eea710c9e79f Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa <su...@medhas.org>
Date: Fri, 20 Dec 2019 16:43:59 -0800
Subject: [PATCH 04/10] control: Update list of dependencies

Signed-off-by: Sunil Mohan Adapa <su...@medhas.org>
---
 debian/changelog | 1 +
 debian/control   | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/debian/changelog b/debian/changelog
index ddf874f..c0e5cc7 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,7 @@
 python-augeas (1.0.3-1) UNRELEASED; urgency=medium
 
   * New upstream release
+  * control: Update list of dependencies
 
  -- Sunil Mohan Adapa <su...@medhas.org>  Fri, 20 Dec 2019 16:39:33 -0800
 
diff --git a/debian/control b/debian/control
index f2e571e..360eb9a 100644
--- a/debian/control
+++ b/debian/control
@@ -6,7 +6,9 @@ Build-Depends:
  debhelper (>= 9~),
  dh-python,
  libaugeas0 (>= 0.7.2),
- python3-all
+ python3-all,
+ python3-cffi (>= 1.0.0),
+ python3-setuptools
 Standards-Version: 3.9.6
 X-Python-Version: >= 2.6
 X-Python3-Version: >= 3.3
-- 
2.20.1

>From d7c5abcbeb252be62222111970184315c277a46e Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa <su...@medhas.org>
Date: Fri, 20 Dec 2019 16:48:54 -0800
Subject: [PATCH 05/10] control: Remove unnecessary python version fields

Signed-off-by: Sunil Mohan Adapa <su...@medhas.org>
---
 debian/changelog | 1 +
 debian/control   | 2 --
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index c0e5cc7..146fed9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,6 +2,7 @@ python-augeas (1.0.3-1) UNRELEASED; urgency=medium
 
   * New upstream release
   * control: Update list of dependencies
+  * control: Remove unnecessary python version fields
 
  -- Sunil Mohan Adapa <su...@medhas.org>  Fri, 20 Dec 2019 16:39:33 -0800
 
diff --git a/debian/control b/debian/control
index 360eb9a..c494a71 100644
--- a/debian/control
+++ b/debian/control
@@ -10,8 +10,6 @@ Build-Depends:
  python3-cffi (>= 1.0.0),
  python3-setuptools
 Standards-Version: 3.9.6
-X-Python-Version: >= 2.6
-X-Python3-Version: >= 3.3
 Homepage: http://augeas.net/
 Vcs-Git: git://anonscm.debian.org/collab-maint/python-augeas.git
 Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/python-augeas.git
-- 
2.20.1

>From d7c5abcbeb252be62222111970184315c277a46e Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa <su...@medhas.org>
Date: Fri, 20 Dec 2019 16:48:54 -0800
Subject: [PATCH 05/10] control: Remove unnecessary python version fields

Signed-off-by: Sunil Mohan Adapa <su...@medhas.org>
---
 debian/changelog | 1 +
 debian/control   | 2 --
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index c0e5cc7..146fed9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,6 +2,7 @@ python-augeas (1.0.3-1) UNRELEASED; urgency=medium
 
   * New upstream release
   * control: Update list of dependencies
+  * control: Remove unnecessary python version fields
 
  -- Sunil Mohan Adapa <su...@medhas.org>  Fri, 20 Dec 2019 16:39:33 -0800
 
diff --git a/debian/control b/debian/control
index 360eb9a..c494a71 100644
--- a/debian/control
+++ b/debian/control
@@ -10,8 +10,6 @@ Build-Depends:
  python3-cffi (>= 1.0.0),
  python3-setuptools
 Standards-Version: 3.9.6
-X-Python-Version: >= 2.6
-X-Python3-Version: >= 3.3
 Homepage: http://augeas.net/
 Vcs-Git: git://anonscm.debian.org/collab-maint/python-augeas.git
 Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/python-augeas.git
-- 
2.20.1

>From 5d5379c03593349b43cda799650869fe993c3d51 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa <su...@medhas.org>
Date: Fri, 20 Dec 2019 17:12:23 -0800
Subject: [PATCH 06/10] control: Specify that rules file does not require root

Signed-off-by: Sunil Mohan Adapa <su...@medhas.org>
---
 debian/changelog | 1 +
 debian/control   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 146fed9..ea7336f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -3,6 +3,7 @@ python-augeas (1.0.3-1) UNRELEASED; urgency=medium
   * New upstream release
   * control: Update list of dependencies
   * control: Remove unnecessary python version fields
+  * control: Specify that rules file does not require root
 
  -- Sunil Mohan Adapa <su...@medhas.org>  Fri, 20 Dec 2019 16:39:33 -0800
 
diff --git a/debian/control b/debian/control
index c494a71..aa8aa6b 100644
--- a/debian/control
+++ b/debian/control
@@ -11,6 +11,7 @@ Build-Depends:
  python3-setuptools
 Standards-Version: 3.9.6
 Homepage: http://augeas.net/
+Rules-Requires-Root: no
 Vcs-Git: git://anonscm.debian.org/collab-maint/python-augeas.git
 Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/python-augeas.git
 
-- 
2.20.1

>From 7597c7b57d6ea410a2d0c996a7b65cf96bec7abd Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa <su...@medhas.org>
Date: Fri, 20 Dec 2019 17:17:35 -0800
Subject: [PATCH 07/10] control: Update standards version to 4.4.1. No changes
 required

Signed-off-by: Sunil Mohan Adapa <su...@medhas.org>
---
 debian/changelog | 1 +
 debian/control   | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/debian/changelog b/debian/changelog
index ea7336f..05c0bb8 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -4,6 +4,7 @@ python-augeas (1.0.3-1) UNRELEASED; urgency=medium
   * control: Update list of dependencies
   * control: Remove unnecessary python version fields
   * control: Specify that rules file does not require root
+  * control: Update standards version to 4.4.1. No changes required.
 
  -- Sunil Mohan Adapa <su...@medhas.org>  Fri, 20 Dec 2019 16:39:33 -0800
 
diff --git a/debian/control b/debian/control
index aa8aa6b..55bf0cb 100644
--- a/debian/control
+++ b/debian/control
@@ -9,7 +9,7 @@ Build-Depends:
  python3-all,
  python3-cffi (>= 1.0.0),
  python3-setuptools
-Standards-Version: 3.9.6
+Standards-Version: 4.4.1
 Homepage: http://augeas.net/
 Rules-Requires-Root: no
 Vcs-Git: git://anonscm.debian.org/collab-maint/python-augeas.git
-- 
2.20.1

>From 6e55a4747d3773324d97db774259f59d8eefeb8d Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa <su...@medhas.org>
Date: Fri, 20 Dec 2019 17:23:15 -0800
Subject: [PATCH 08/10] control: Enable autopkgtest-pkg-python

Signed-off-by: Sunil Mohan Adapa <su...@medhas.org>
---
 debian/changelog | 1 +
 debian/control   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 05c0bb8..ad4841d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -5,6 +5,7 @@ python-augeas (1.0.3-1) UNRELEASED; urgency=medium
   * control: Remove unnecessary python version fields
   * control: Specify that rules file does not require root
   * control: Update standards version to 4.4.1. No changes required.
+  * control: Enable autopkgtest-pkg-python
 
  -- Sunil Mohan Adapa <su...@medhas.org>  Fri, 20 Dec 2019 16:39:33 -0800
 
diff --git a/debian/control b/debian/control
index 55bf0cb..82114e6 100644
--- a/debian/control
+++ b/debian/control
@@ -12,6 +12,7 @@ Build-Depends:
 Standards-Version: 4.4.1
 Homepage: http://augeas.net/
 Rules-Requires-Root: no
+Testsuite: autopkgtest-pkg-python
 Vcs-Git: git://anonscm.debian.org/collab-maint/python-augeas.git
 Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/python-augeas.git
 
-- 
2.20.1

>From ef221fe1a78c8c16bfac17abdedbd079656ff83f Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa <su...@medhas.org>
Date: Fri, 20 Dec 2019 17:25:07 -0800
Subject: [PATCH 09/10] control: Update debhelper compatibility level to 12

Signed-off-by: Sunil Mohan Adapa <su...@medhas.org>
---
 debian/changelog | 1 +
 debian/compat    | 1 -
 debian/control   | 2 +-
 3 files changed, 2 insertions(+), 2 deletions(-)
 delete mode 100644 debian/compat

diff --git a/debian/changelog b/debian/changelog
index ad4841d..2fc4ae6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -6,6 +6,7 @@ python-augeas (1.0.3-1) UNRELEASED; urgency=medium
   * control: Specify that rules file does not require root
   * control: Update standards version to 4.4.1. No changes required.
   * control: Enable autopkgtest-pkg-python
+  * control: Update debhelper compatibility level to 12
 
  -- Sunil Mohan Adapa <su...@medhas.org>  Fri, 20 Dec 2019 16:39:33 -0800
 
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index ec63514..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/debian/control b/debian/control
index 82114e6..ca50068 100644
--- a/debian/control
+++ b/debian/control
@@ -3,7 +3,7 @@ Section: python
 Priority: optional
 Maintainer: Free Ekanayaka <fr...@debian.org>
 Build-Depends:
- debhelper (>= 9~),
+ debhelper-compat (= 12),
  dh-python,
  libaugeas0 (>= 0.7.2),
  python3-all,
-- 
2.20.1

>From 813a419f16c380fc98b1a871c30c2227727a62f3 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa <su...@medhas.org>
Date: Fri, 20 Dec 2019 18:28:53 -0800
Subject: [PATCH 10/10] rules: Run tests during build

Signed-off-by: Sunil Mohan Adapa <su...@medhas.org>
---
 debian/changelog | 1 +
 debian/rules     | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 2fc4ae6..3ec575e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -7,6 +7,7 @@ python-augeas (1.0.3-1) UNRELEASED; urgency=medium
   * control: Update standards version to 4.4.1. No changes required.
   * control: Enable autopkgtest-pkg-python
   * control: Update debhelper compatibility level to 12
+  * rules: Run tests during build
 
  -- Sunil Mohan Adapa <su...@medhas.org>  Fri, 20 Dec 2019 16:39:33 -0800
 
diff --git a/debian/rules b/debian/rules
index 94d7f97..8b9cd61 100755
--- a/debian/rules
+++ b/debian/rules
@@ -6,3 +6,6 @@ export PYBUILD_DESTDIR_python3=debian/python3-augeas/
 
 %:
        dh $@ --buildsystem=pybuild --with python3
+
+override_dh_auto_test:
+       python3 test/test_augeas.py
-- 
2.20.1

Reply via email to