public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-07-01 20:51 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-07-01 20:51 UTC (permalink / raw
  To: gentoo-commits

commit:     6faf8d5ab5dc16f193acc1d344bf473e1eaa4808
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Mon Jul  1 20:14:03 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Mon Jul  1 20:14:03 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=6faf8d5a

g_sorcery/fileutils: file utilities moved to separate module

---
 g_sorcery/fileutils.py   |  72 ++++++++++++++++++++++++++++
 g_sorcery/package_db.py  |  64 ++-----------------------
 tests/test_fileutils.py  | 121 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/test_package_db.py | 100 ---------------------------------------
 4 files changed, 198 insertions(+), 159 deletions(-)

diff --git a/g_sorcery/fileutils.py b/g_sorcery/fileutils.py
new file mode 100644
index 0000000..1920495
--- /dev/null
+++ b/g_sorcery/fileutils.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+    fileutils.py
+    ~~~~~~~~~~~~
+    
+    file utilities
+    
+    :copyright: (c) 2013 by Jauhien Piatlicki
+    :license: GPL-2, see LICENSE for more details.
+"""
+
+import json, os, shutil
+
+from .exceptions import FileJSONError
+
+class FileJSON:
+    def __init__(self, directory, name, mandatories):
+        """
+        Initialize
+
+        mandatories -- list of mandatory keys
+        """
+        self.directory = os.path.abspath(directory)
+        self.name = name
+        self.path = os.path.join(directory, name)
+        self.mandatories = mandatories
+
+    def read(self):
+        if not os.path.exists(self.directory):
+            os.makedirs(self.directory)
+        content = {}
+        if not os.path.isfile(self.path):
+            for key in self.mandatories:
+                content[key] = ""
+            with open(self.path, 'w') as f:
+                json.dump(content, f, indent=2, sort_keys=True)
+        else:
+            with open(self.path, 'r') as f:
+                content = json.load(f)
+            for key in self.mandatories:
+                if not key in content:
+                    raise FileJSONError('lack of mandatory key: ' + key)
+        return content
+
+    def write(self, content):
+        for key in self.mandatories:
+            if not key in content:
+                raise FileJSONError('lack of mandatory key: ' + key)
+        if not os.path.exists(self.directory):
+            os.makedirs(self.directory)
+        with open(self.path, 'w') as f:
+            json.dump(content, f, indent=2, sort_keys=True)
+
+
+def hash_file(name, hasher, blocksize=65536):
+    with open(name, 'rb') as f:
+        buf = f.read(blocksize)
+        while len(buf) > 0:
+            hasher.update(buf)
+            buf = f.read(blocksize)
+    return hasher.hexdigest()
+
+def copy_all(src, dst):
+    for f_name in os.listdir(src):
+        src_name = os.path.join(src, f_name)
+        dst_name = os.path.join(dst, f_name)
+        if os.path.isdir(src_name):
+            shutil.copytree(src_name, dst_name)
+        else:
+            shutil.copy2(src_name, dst_name)

diff --git a/g_sorcery/package_db.py b/g_sorcery/package_db.py
index 561129d..fc59878 100644
--- a/g_sorcery/package_db.py
+++ b/g_sorcery/package_db.py
@@ -11,70 +11,16 @@
     :license: GPL-2, see LICENSE for more details.
 """
 
-from .exceptions import DBStructureError, FileJSONError, IntegrityError, \
+from .exceptions import DBStructureError, IntegrityError, \
      InvalidKeyError, SyncError
 
-import portage
-     
-import collections, glob, hashlib, json, os, shutil, tarfile, tempfile
+from .fileutils import FileJSON, hash_file, copy_all
 
-Package = collections.namedtuple("Package", "category name version")
+import portage
 
-class FileJSON:
-    def __init__(self, directory, name, mandatories):
-        """
-        Initialize
+import collections, glob, hashlib, os, shutil, tarfile, tempfile
 
-        mandatories -- list of mandatory keys
-        """
-        self.directory = os.path.abspath(directory)
-        self.name = name
-        self.path = os.path.join(directory, name)
-        self.mandatories = mandatories
-
-    def read(self):
-        if not os.path.exists(self.directory):
-            os.makedirs(self.directory)
-        content = {}
-        if not os.path.isfile(self.path):
-            for key in self.mandatories:
-                content[key] = ""
-            with open(self.path, 'w') as f:
-                json.dump(content, f, indent=2, sort_keys=True)
-        else:
-            with open(self.path, 'r') as f:
-                content = json.load(f)
-            for key in self.mandatories:
-                if not key in content:
-                    raise FileJSONError('lack of mandatory key: ' + key)
-        return content
-
-    def write(self, content):
-        for key in self.mandatories:
-            if not key in content:
-                raise FileJSONError('lack of mandatory key: ' + key)
-        if not os.path.exists(self.directory):
-            os.makedirs(self.directory)
-        with open(self.path, 'w') as f:
-            json.dump(content, f, indent=2, sort_keys=True)
-
-
-def hash_file(name, hasher, blocksize=65536):
-    with open(name, 'rb') as f:
-        buf = f.read(blocksize)
-        while len(buf) > 0:
-            hasher.update(buf)
-            buf = f.read(blocksize)
-    return hasher.hexdigest()
-
-def copy_all(src, dst):
-    for f_name in os.listdir(src):
-        src_name = os.path.join(src, f_name)
-        dst_name = os.path.join(dst, f_name)
-        if os.path.isdir(src_name):
-            shutil.copytree(src_name, dst_name)
-        else:
-            shutil.copy2(src_name, dst_name)
+Package = collections.namedtuple("Package", "category name version")
 
 class PackageDB:
     def __init__(self, directory, repo_uri="", db_uri=""):

diff --git a/tests/test_fileutils.py b/tests/test_fileutils.py
new file mode 100644
index 0000000..1760444
--- /dev/null
+++ b/tests/test_fileutils.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+    fileutils.py
+    ~~~~~~~~~~~~
+    
+    file utilities test suite
+    
+    :copyright: (c) 2013 by Jauhien Piatlicki
+    :license: GPL-2, see LICENSE for more details.
+"""
+
+import json, os, shutil, tempfile, unittest
+
+from g_sorcery import exceptions, fileutils
+
+
+class TestFileJSON(unittest.TestCase):
+    
+    def setUp(self):
+        self.tempdir = tempfile.TemporaryDirectory()
+        self.path = os.path.join(self.tempdir.name, 'tst')
+        self.name = 'tst.json'
+
+    def tearDown(self):
+        del self.tempdir
+
+    def do_test_read_ok(self, mandatories, value_suffix=""):
+        f = fileutils.FileJSON(self.path, self.name, mandatories)
+        content = f.read()
+        for key in mandatories:
+            self.assertTrue(key in content)
+            if value_suffix:
+                value = key + value_suffix
+            else:
+                value = ""
+            self.assertEqual(content[key], value)
+        self.assertTrue(os.path.isfile(os.path.join(self.path, self.name)))
+        with open(os.path.join(self.path, self.name), 'r') as f:
+            content_f = json.load(f)
+        self.assertEqual(content, content_f)
+        
+    def test_read_dir_does_not_exist(self):
+        mandatories = ['tst1', 'tst2', 'tst3']
+        self.do_test_read_ok(mandatories)
+
+    def test_read_file_does_not_exist(self):
+        os.makedirs(self.path)
+        mandatories = ['tst1', 'tst2', 'tst3']
+        self.do_test_read_ok(mandatories)
+
+    def test_read_all_keys(self):
+        os.makedirs(self.path)
+        mandatories = ['tst1', 'tst2', 'tst3']
+        content = {}
+        for key in mandatories:
+            content[key] = key + "_v"
+        with open(os.path.join(self.path, self.name), 'w') as f:
+            json.dump(content, f)
+        self.do_test_read_ok(mandatories, "_v")
+
+    def test_read_missing_keys(self):
+        os.makedirs(self.path)
+        mandatories = ['tst1', 'tst2', 'tst3']
+        content = {}
+        for key in mandatories:
+            content[key] = key + "_v"
+        with open(os.path.join(self.path, self.name), 'w') as f:
+            json.dump(content, f)
+        f = fileutils.FileJSON(self.path, self.name, mandatories)
+        mandatories.append("tst4")
+        self.assertRaises(exceptions.FileJSONError, f.read)
+
+    def do_test_write_ok(self):
+        mandatories = ['tst1', 'tst2', 'tst3']
+        content = {}
+        for key in mandatories:
+            content[key] = key + '_v'
+        f = fileutils.FileJSON(self.path, self.name, mandatories)
+        f.write(content)
+        self.assertTrue(os.path.isfile(os.path.join(self.path, self.name)))
+        with open(os.path.join(self.path, self.name), 'r') as f:
+            content_f = json.load(f)
+        self.assertEqual(content, content_f)
+
+    def test_write_missing_keys(self):
+        content = {'tst1' : '', 'tst2' : ''}
+        mandatories = ['tst1', 'tst2', 'tst3']
+        f = fileutils.FileJSON(self.path, self.name, mandatories)
+        self.assertRaises(exceptions.FileJSONError, f.write, content)
+
+    def test_write_dir_does_not_exist(self):
+        self.do_test_write_ok()
+
+    def test_write_file_does_not_exist(self):
+        os.makedirs(self.path)
+        self.do_test_write_ok()
+
+    def test_write_all_keys(self):
+        os.makedirs(self.path)
+        mandatories = ['tst11', 'tst12']
+        content = {}
+        for key in mandatories:
+            content[key] = key + "_v"
+        with open(os.path.join(self.path, self.name), 'w') as f:
+            json.dump(content, f)
+        self.do_test_write_ok()
+
+        
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(TestFileJSON('test_read_dir_does_not_exist'))
+    suite.addTest(TestFileJSON('test_read_file_does_not_exist'))
+    suite.addTest(TestFileJSON('test_read_all_keys'))
+    suite.addTest(TestFileJSON('test_read_missing_keys'))
+    suite.addTest(TestFileJSON('test_write_missing_keys'))
+    suite.addTest(TestFileJSON('test_write_dir_does_not_exist'))
+    suite.addTest(TestFileJSON('test_write_file_does_not_exist'))
+    suite.addTest(TestFileJSON('test_write_all_keys'))
+    return suite

diff --git a/tests/test_package_db.py b/tests/test_package_db.py
index c5d7074..2994157 100644
--- a/tests/test_package_db.py
+++ b/tests/test_package_db.py
@@ -30,98 +30,6 @@ class Server(threading.Thread):
         self.httpd.shutdown()
 
 
-class TestFileJSON(unittest.TestCase):
-    
-    def setUp(self):
-        self.tempdir = tempfile.TemporaryDirectory()
-        self.path = os.path.join(self.tempdir.name, 'tst')
-        self.name = 'tst.json'
-
-    def tearDown(self):
-        del self.tempdir
-
-    def do_test_read_ok(self, mandatories, value_suffix=""):
-        f = package_db.FileJSON(self.path, self.name, mandatories)
-        content = f.read()
-        for key in mandatories:
-            self.assertTrue(key in content)
-            if value_suffix:
-                value = key + value_suffix
-            else:
-                value = ""
-            self.assertEqual(content[key], value)
-        self.assertTrue(os.path.isfile(os.path.join(self.path, self.name)))
-        with open(os.path.join(self.path, self.name), 'r') as f:
-            content_f = json.load(f)
-        self.assertEqual(content, content_f)
-        
-    def test_read_dir_does_not_exist(self):
-        mandatories = ['tst1', 'tst2', 'tst3']
-        self.do_test_read_ok(mandatories)
-
-    def test_read_file_does_not_exist(self):
-        os.makedirs(self.path)
-        mandatories = ['tst1', 'tst2', 'tst3']
-        self.do_test_read_ok(mandatories)
-
-    def test_read_all_keys(self):
-        os.makedirs(self.path)
-        mandatories = ['tst1', 'tst2', 'tst3']
-        content = {}
-        for key in mandatories:
-            content[key] = key + "_v"
-        with open(os.path.join(self.path, self.name), 'w') as f:
-            json.dump(content, f)
-        self.do_test_read_ok(mandatories, "_v")
-
-    def test_read_missing_keys(self):
-        os.makedirs(self.path)
-        mandatories = ['tst1', 'tst2', 'tst3']
-        content = {}
-        for key in mandatories:
-            content[key] = key + "_v"
-        with open(os.path.join(self.path, self.name), 'w') as f:
-            json.dump(content, f)
-        f = package_db.FileJSON(self.path, self.name, mandatories)
-        mandatories.append("tst4")
-        self.assertRaises(exceptions.FileJSONError, f.read)
-
-    def do_test_write_ok(self):
-        mandatories = ['tst1', 'tst2', 'tst3']
-        content = {}
-        for key in mandatories:
-            content[key] = key + '_v'
-        f = package_db.FileJSON(self.path, self.name, mandatories)
-        f.write(content)
-        self.assertTrue(os.path.isfile(os.path.join(self.path, self.name)))
-        with open(os.path.join(self.path, self.name), 'r') as f:
-            content_f = json.load(f)
-        self.assertEqual(content, content_f)
-
-    def test_write_missing_keys(self):
-        content = {'tst1' : '', 'tst2' : ''}
-        mandatories = ['tst1', 'tst2', 'tst3']
-        f = package_db.FileJSON(self.path, self.name, mandatories)
-        self.assertRaises(exceptions.FileJSONError, f.write, content)
-
-    def test_write_dir_does_not_exist(self):
-        self.do_test_write_ok()
-
-    def test_write_file_does_not_exist(self):
-        os.makedirs(self.path)
-        self.do_test_write_ok()
-
-    def test_write_all_keys(self):
-        os.makedirs(self.path)
-        mandatories = ['tst11', 'tst12']
-        content = {}
-        for key in mandatories:
-            content[key] = key + "_v"
-        with open(os.path.join(self.path, self.name), 'w') as f:
-            json.dump(content, f)
-        self.do_test_write_ok()
-
-
 class DummyDB(package_db.PackageDB):
     def __init__(self, directory, packages):
         super().__init__(directory)
@@ -227,14 +135,6 @@ class TestDummyDB(unittest.TestCase):
             
 def suite():
     suite = unittest.TestSuite()
-    suite.addTest(TestFileJSON('test_read_dir_does_not_exist'))
-    suite.addTest(TestFileJSON('test_read_file_does_not_exist'))
-    suite.addTest(TestFileJSON('test_read_all_keys'))
-    suite.addTest(TestFileJSON('test_read_missing_keys'))
-    suite.addTest(TestFileJSON('test_write_missing_keys'))
-    suite.addTest(TestFileJSON('test_write_dir_does_not_exist'))
-    suite.addTest(TestFileJSON('test_write_file_does_not_exist'))
-    suite.addTest(TestFileJSON('test_write_all_keys'))
     suite.addTest(TestDummyDB('test_manifest'))
     suite.addTest(TestDummyDB('test_read'))
     suite.addTest(TestDummyDB('test_list_categories'))


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2015-04-22  7:35 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2015-04-22  7:35 UTC (permalink / raw
  To: gentoo-commits

commit:     15e264af65e08505ec85d8cb0dd53170ac044985
Author:     Jauhien Piatlicki <jauhien <AT> gentoo <DOT> org>
AuthorDate: Fri Apr 17 09:31:25 2015 +0000
Commit:     Jauhien Piatlicki <jauhien <AT> gentoo <DOT> org>
CommitDate: Fri Apr 17 17:10:08 2015 +0000
URL:        https://gitweb.gentoo.org/proj/g-sorcery.git/commit/?id=15e264af

[g_sorcery/package_db] add category common data setter and getter to DB API

 g_sorcery/package_db.py | 38 ++++++++++++++++++++++++++++++++++++++
 tests/test_PackageDB.py | 17 +++++++++++++----
 2 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/g_sorcery/package_db.py b/g_sorcery/package_db.py
index ec2d45f..5374ae5 100644
--- a/g_sorcery/package_db.py
+++ b/g_sorcery/package_db.py
@@ -105,6 +105,7 @@ class PackageDB(object):
                             self.pkg_name, self.pkg_data = next(self.pkgs_iter)
                             self.vers_iter = iter(self.pkg_data.items())
 
+                ebuild_data = dict(ebuild_data)
                 ebuild_data.update(self.cat_data['common_data'])
                 return (Package(self.cat_name, self.pkg_name, ver), ebuild_data)
 
@@ -129,6 +130,7 @@ class PackageDB(object):
                             self.pkg_name, self.pkg_data = next(self.pkgs_iter)
                             self.vers_iter = iter(self.pkg_data.items())
 
+                ebuild_data = dict(ebuild_data)
                 ebuild_data.update(self.cat_data['common_data'])
                 return (Package(self.cat_name, self.pkg_name, ver), ebuild_data)
 
@@ -275,6 +277,42 @@ class PackageDB(object):
         self.categories[category] = description
 
 
+    def set_common_data(self, category, common_data):
+        """
+        Set common data for a category.
+
+        Args:
+            category: Category name.
+            common_data: Category common data.
+        """
+        if not category in self.categories:
+            raise InvalidKeyError('Non-existent category: ' + category)
+
+        if not category in self.database:
+            self.database[category] = {'common_data': common_data, 'packages': {}}
+        else:
+            self.database[category]['common_data'] = common_data
+
+
+    def get_common_data(self, category):
+        """
+        Get common data for a category.
+
+        Args:
+            category: Category name.
+
+        Returns:
+            Dictionary with category common data.
+        """
+        if not category in self.categories:
+            raise InvalidKeyError('Non-existent category: ' + category)
+
+        if not category in self.database:
+            return {}
+        else:
+            return self.database[category]['common_data']
+
+
     def add_package(self, package, ebuild_data=None):
         """
         Add a package.

diff --git a/tests/test_PackageDB.py b/tests/test_PackageDB.py
index f73f006..2a67385 100644
--- a/tests/test_PackageDB.py
+++ b/tests/test_PackageDB.py
@@ -38,11 +38,15 @@ class TestPackageDB(BaseTest):
         orig_db = PackageDB(orig_path)
         orig_db.add_category("app-test1")
         orig_db.add_category("app-test2")
-        ebuild_data = {"test1": "test1", "test2": "test2"}
+        ebuild_data = {"test1": "tst1", "test2": "tst2"}
+        common_data = {"common1": "cmn1", "common2": "cmn2"}
         packages = [Package("app-test1", "test", "1"), Package("app-test1", "test", "2"),
                     Package("app-test1", "test1", "1"), Package("app-test2", "test2", "1")]
         for package in packages:
             orig_db.add_package(package, ebuild_data)
+        orig_db.set_common_data("app-test1", common_data)
+        full_data = dict(ebuild_data)
+        full_data.update(common_data)
 
         orig_db.write()
         os.system("cd " + orig_tempdir.name + " && tar cvzf good.tar.gz db")
@@ -61,6 +65,8 @@ class TestPackageDB(BaseTest):
         srv.join()
         test_db.read()
         self.assertEqual(orig_db.database, test_db.database)
+        self.assertEqual(orig_db.get_common_data("app-test1"), test_db.get_common_data("app-test1"))
+        self.assertEqual(orig_db.get_common_data("app-test2"), test_db.get_common_data("app-test2"))
         self.assertEqual(set(test_db.list_categories()), set(["app-test1", "app-test2"]))
         self.assertTrue(test_db.in_category("app-test1", "test"))
         self.assertFalse(test_db.in_category("app-test2", "test"))
@@ -71,7 +77,7 @@ class TestPackageDB(BaseTest):
         self.assertRaises(InvalidKeyError, test_db.list_package_versions, "app-test1", "invalid")
         self.assertEqual(set(test_db.list_package_versions("app-test1", "test")), set(['1', '2']))
         self.assertEqual(set(test_db.list_all_packages()), set(packages))
-        self.assertEqual(test_db.get_package_description(packages[0]), ebuild_data)
+        self.assertEqual(test_db.get_package_description(packages[0]), full_data)
         self.assertRaises(KeyError, test_db.get_package_description, Package("invalid", "invalid", "1"))
         self.assertEqual(test_db.get_max_version("app-test1", "test"), "2")
         self.assertEqual(test_db.get_max_version("app-test1", "test1"), "1")
@@ -79,10 +85,13 @@ class TestPackageDB(BaseTest):
         pkg_set = set(packages)
         for package, data in test_db:
             self.assertTrue(package in pkg_set)
-            self.assertEqual(data, ebuild_data)
+            if package.category == "app-test1":
+                self.assertEqual(data, full_data)
+            else:
+                self.assertEqual(data, ebuild_data)
             pkg_set.remove(package)
         self.assertTrue(not pkg_set)
-
+        self.assertEqual(orig_db.database, test_db.database)
 
 def suite():
     suite = unittest.TestSuite()


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-07-04 20:24 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-07-04 20:24 UTC (permalink / raw
  To: gentoo-commits

commit:     976ba56c16c4035f81bacae5db057778863732d5
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Thu Jul  4 20:23:03 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Thu Jul  4 20:23:03 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=976ba56c

g_sorcery/ebuild: substitute_list

---
 g_sorcery/ebuild.py     | 43 +++++++++++++++++++++++++++++++++++++++++++
 g_sorcery/exceptions.py |  3 +++
 tests/test_ebuild.py    | 16 ++++++++++++++--
 3 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/g_sorcery/ebuild.py b/g_sorcery/ebuild.py
index 9529220..83fcb13 100644
--- a/g_sorcery/ebuild.py
+++ b/g_sorcery/ebuild.py
@@ -11,8 +11,51 @@
     :license: GPL-2, see LICENSE for more details.
 """
 
+import copy
+import re
 import string
 
+from .exceptions import DescriptionError
+
+def substitute_list(text, values):
+    """
+    Performs the template substitution. Variables are
+    substituted by lists.
+
+    Variable format.
+    ~~~~~~~~~~~~~~~~
+
+    #[n ]#name#
+    'n': Separate list entries with '\n'.
+    ' ': Separate list entries with ' '.
+    name: Key in values dict.
+
+    Args:
+        text: List with template strings.
+        values: Dictionary with values.
+    """
+    result = copy.deepcopy(text)
+    regex = re.compile('#[n ]#\w+#')
+    for idx, line in enumerate(result):
+        match = regex.search(line)
+        if not match:
+                continue
+        group = match.group()
+        new_line = (group[1] == 'n')
+        key = group[3:-1]
+        if not key in values:
+            error = "missing key: " + key
+            raise DescriptionError(error)
+        lst = values[key]
+        if new_line:
+            sep = '\n'
+        else:
+            sep = ' '
+        repl = sep.join(lst)
+        result[idx] = regex.sub(repl, line)
+    return result
+
+
 class EbuildGenerator(object):
     """
     Ebuild generator.

diff --git a/g_sorcery/exceptions.py b/g_sorcery/exceptions.py
index 38a80b2..a05cfa5 100644
--- a/g_sorcery/exceptions.py
+++ b/g_sorcery/exceptions.py
@@ -34,3 +34,6 @@ class FileJSONError(GSorceryError):
 
 class XMLGeneratorError(GSorceryError):
     pass
+
+class DescriptionError(GSorceryError):
+    pass

diff --git a/tests/test_ebuild.py b/tests/test_ebuild.py
index 69222e8..6a97249 100644
--- a/tests/test_ebuild.py
+++ b/tests/test_ebuild.py
@@ -13,7 +13,7 @@
 
 import os, tempfile, unittest
 
-from g_sorcery import ebuild, package_db
+from g_sorcery import ebuild, package_db, exceptions
 
 from tests.base import BaseTest
 
@@ -81,10 +81,22 @@ var: $$var""")
         self.assertEqual(ebuild, ['test', 'author: jauhien',
                                   'homepage: 127.0.0.1', 'var: $var'])
         
-    
+
+class TestSubstituteList(BaseTest):
+
+    def test_substitute_list(self):
+        text = ['a', 'test', 'DEPEND="#n#depend#"', 'IUSE="# #iuse#"']
+        desc = {'depend' : ['app-test/test1', 'app-test/test2'],
+                'iuse' : ['test', 'check']}
+        result = ['a', 'test', 'DEPEND="app-test/test1\napp-test/test2"', 'IUSE="test check"']
+        self.assertEqual(ebuild.substitute_list(text, desc), result)
+        self.assertRaises(exceptions.DescriptionError, ebuild.substitute_list, text, {})
+
+        
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(TestEbuildGenerator('test_process'))
     suite.addTest(TestEbuildGenerator('test_generate'))
     suite.addTest(TestEbuildGeneratorFromFile('test_generate'))
+    suite.addTest(TestSubstituteList('test_substitute_list'))
     return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-07-03 22:54 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-07-03 22:54 UTC (permalink / raw
  To: gentoo-commits

commit:     1cc214be6a43cf6c68353650bf6938756366b05e
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Wed Jul  3 22:36:49 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Wed Jul  3 22:36:49 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=1cc214be

g_sorcery/package_db: hiding pylint swearing

---
 g_sorcery/package_db.py  | 210 +++++++++++++++++++++++++++++++++++++++++------
 tests/test_package_db.py |   4 +-
 2 files changed, 188 insertions(+), 26 deletions(-)

diff --git a/g_sorcery/package_db.py b/g_sorcery/package_db.py
index 12577ad..bb3b6e2 100644
--- a/g_sorcery/package_db.py
+++ b/g_sorcery/package_db.py
@@ -25,7 +25,37 @@ import collections, glob, hashlib, os, shutil, tarfile
 Package = collections.namedtuple("Package", "category name version")
 
 class PackageDB(object):
+    """
+    Package database.
+    Database is a directory and related data structure.
+
+    Directory layout.
+    ~~~~~~~~~~~~~~~~~
+    db dir
+        manifest.json: database manifest
+        uri.json: URIes
+        info.json: information about database
+        categories.json: information about categories
+        category1
+            packages.json: list of packages
+            package1
+                versions.json: list of versions
+                version1.json: description of a package
+                version2.json: description of a package
+                ...
+            package2
+            ...
+        category2
+        ...
+    
+    """
     def __init__(self, directory, repo_uri="", db_uri=""):
+        """
+        Args:
+            directory: database directory.
+            repo_uri: Repository URI.
+            db_uri: URI for synchronization with remote database.
+        """
         self.URI_NAME = 'uri.json'
         self.INFO_NAME = 'info.json'
         self.CATEGORIES_NAME = 'categories.json'
@@ -36,6 +66,13 @@ class PackageDB(object):
         self.reset_db()
 
     def reset_uri(self, repo_uri="", db_uri=""):
+        """
+        Reset URI information.
+
+        Args:
+            repo_uri: Repository URI.
+            db_uri: URI for synchronization with remote database.
+        """
         uri_f = FileJSON(self.directory, self.URI_NAME, ['repo_uri', 'db_uri'])
         uri = uri_f.read()
         if not repo_uri:
@@ -51,16 +88,19 @@ class PackageDB(object):
         uri_f.write(uri)
 
     def reset_db(self):
-        self.db = {}
+        """
+        Reset database.
+        """
+        self.database = {}
         self.info = {}
         self.categories = {}
-        self.db = {}
 
     def generate(self, repo_uri=""):
         """
-        Generates a new package database
+        Generate new package database
 
-        repo_uri -- repository uri
+        Args:
+            repo_uri: Repository URI
         """
         if repo_uri:
             self.repo_uri = repo_uri
@@ -78,6 +118,12 @@ class PackageDB(object):
         pass
 
     def sync(self, db_uri=""):
+        """
+        Synchronize local database with remote database.
+
+        Args:
+            db_uri: URI for synchronization with remote database.
+        """
         if db_uri:
             self.db_uri = db_uri
         self.clean()
@@ -116,9 +162,19 @@ class PackageDB(object):
         self.read()
 
     def get_real_db_uri(self):
+        """
+        Convert self.db_uri to URI where remote database can be
+        fetched from.
+
+        Returns:
+            URI of remote database file.
+        """
         return self.db_uri
             
     def manifest(self):
+        """
+        Generate database manifest.
+        """
         categories = FileJSON(self.directory, self.CATEGORIES_NAME, [])
         categories = categories.read()
         manifest = {}
@@ -134,12 +190,19 @@ class PackageDB(object):
                 for f in files:
                     manifest[os.path.join(root[len(self.directory)+1:], f)] = \
                     hash_file(os.path.join(root, f), hashlib.md5())
-        m = FileJSON(self.directory, 'manifest.json', [])
-        m.write(manifest)
+        m_f = FileJSON(self.directory, 'manifest.json', [])
+        m_f.write(manifest)
 
     def check_manifest(self):
-        m = FileJSON(self.directory, 'manifest.json', [])
-        manifest = m.read()
+        """
+        Check database manifest.
+
+        Returns:
+            Tuple with first element containing result of manifest check
+            as boolean and second element containing list of files with errors.
+        """
+        m_f = FileJSON(self.directory, 'manifest.json', [])
+        manifest = m_f.read()
         
         result = True
         errors = []
@@ -158,17 +221,23 @@ class PackageDB(object):
         return (result, errors)
 
     def clean(self):
+        """
+        Clean database.
+        """
         shutil.rmtree(self.directory)
         self.reset_uri(self.repo_uri, self.db_uri)
         self.reset_db()
 
     def write(self):
+        """
+        Write database.
+        """
         info_f = FileJSON(self.directory, self.INFO_NAME, [])
         categories_f = FileJSON(self.directory, self.CATEGORIES_NAME, [])
         info_f.write(self.info)
         categories_f.write(self.categories)
 
-        for pkgname, versions in self.db.items():
+        for pkgname, versions in self.database.items():
             category, name = pkgname.split('/')
             if not category or (not category in self.categories):
                 raise DBStructureError('Non existent: ' + category)
@@ -195,18 +264,33 @@ class PackageDB(object):
         self.additional_write()
 
     def additional_write_version(self, category, package, version):
+        """
+        Hook to be overrided.
+        """
         pass
 
     def additional_write_package(self, category, package):
+        """
+        Hook to be overrided.
+        """
         pass
 
     def additional_write_category(self, category):
+        """
+        Hook to be overrided.
+        """
         pass
 
     def additional_write(self):
+        """
+        Hook to be overrided.
+        """
         pass
 
     def read(self):
+        """
+        Read database.
+        """
         sane, errors = self.check_manifest()
         if not sane:
             raise IntegrityError('Manifest error: ' + str(errors))
@@ -227,42 +311,70 @@ class PackageDB(object):
             for name in packages:
                 package_path = os.path.join(category_path, name)
                 if not os.path.isdir(category_path):
-                    raise DBStructureError('Empty package: ' + category + '/' + name)
+                    error_msg = 'Empty package: ' + category + '/' + name
+                    raise DBStructureError(error_msg)
                 
                 f = FileJSON(package_path, self.VERSIONS_NAME, [])
                 versions = f.read()
                 if not versions:
-                    raise DBStructureError('Empty package: ' + category + '/' + name)
+                    error_msg = 'Empty package: ' + category + '/' + name
+                    raise DBStructureError(error_msg)
 
                 pkgname = category + '/' + name
-                self.db[pkgname] = {}
+                self.database[pkgname] = {}
                 for version in versions:
                     f = FileJSON(package_path, version + '.json', [])
                     description = f.read()
-                    self.db[pkgname][version] = description
+                    self.database[pkgname][version] = description
                     self.additional_read_version(category, name, version)
                 self.additional_read_package(category, name)
             self.additional_read_category(category)
         self.additional_read()
 
     def additional_read_version(self, category, package, version):
+        """
+        Hook to be overrided.
+        """
         pass
 
     def additional_read_package(self, category, package):
+        """
+        Hook to be overrided.
+        """
         pass
 
     def additional_read_category(self, category):
+        """
+        Hook to be overrided.
+        """
         pass
 
     def additional_read(self):
+        """
+        Hook to be overrided.
+        """
         pass
         
     def add_category(self, category, description=None):
+        """
+        Add a category.
+
+        Args:
+            category: Category name.
+            description: Category description.
+        """
         if not description:
             description = {}
-        self.categories[category] = description;
+        self.categories[category] = description
 
     def add_package(self, package, description=None):
+        """
+        Add a package.
+
+        Args:
+            package: package_db.Package instance.
+            description: Dictionary with package description.
+        """
         if not description:
             description = {}
         category = package.category
@@ -271,44 +383,94 @@ class PackageDB(object):
         pkgname = category + '/' + name
         if category and not category in self.categories:
             raise InvalidKeyError('Non-existent category: ' + category)
-        if pkgname and not pkgname in self.db:
-            self.db[pkgname] = {}
-        self.db[pkgname][version] = description
+        if pkgname and not pkgname in self.database:
+            self.database[pkgname] = {}
+        self.database[pkgname][version] = description
 
     def list_categories(self):
+        """
+        List all categories.
+
+        Returns:
+            List with category names.
+        """
         return list(self.categories)
 
     def list_package_names(self, category):
+        """
+        List package names in a category.
+
+        Args:
+            category: Category name.
+
+        Returns:
+            List of package names.
+        """
         if not category or (not category in self.categories):
             raise InvalidKeyError('No such category: ' + category)
-        res = [x.split('/')[1] for x in self.db if x.split('/')[0] == category]
+        res = [x.split('/')[1] for x in self.database if x.split('/')[0] == category]
         return res
 
     def list_package_versions(self, category, name):
+        """
+        List package versions.
+
+        Args:
+            category: Category name.
+            name: package name.
+
+        Returns:
+            List of package versions.
+        """
         if not category or (not category in self.categories):
             raise InvalidKeyError('No such category: ' + category)
         pkgname = category + '/' + name
-        if not pkgname in self.db:
+        if not pkgname in self.database:
             raise InvalidKeyError('No such package: ' + pkgname)
-        return list(self.db[pkgname])
+        return list(self.database[pkgname])
 
     def list_all_packages(self):
+        """
+        List all packages in a database.
+
+        Returns:
+            List of package_db.Package instances.
+        """
         result = []
-        for pkgname, versions in self.db.items():
+        for pkgname, versions in self.database.items():
             for version in versions:
                 category, name = pkgname.split('/')
                 result.append(Package(category, name, version))
         return result
 
     def get_package_description(self, package):
+        """
+        Get package description.
+
+        Args:
+            package: package_db.Package instance.
+
+        Returns:
+            Dictionary with package description.
+        """
         #a possible exception should be catched in the caller
-        return self.db[package.category + '/' + package.name][package.version]
+        return self.database[package.category + '/' + package.name][package.version]
 
     def get_max_version(self, category, name):
+        """
+        Get the recent available version of a package.
+
+        Args:
+            category: Category name.
+            name: package name.
+
+        Returns:
+            The recent version of a package.
+        """
         pkgname = category + '/' + name
-        if not pkgname in self.db:
+        if not pkgname in self.database:
             raise InvalidKeyError('No such package: ' + pkgname)
-        versions = list(self.db[pkgname])
+        versions = list(self.database[pkgname])
         max_ver = versions[0]
         for version in versions[1:]:
             if portage.pkgcmp(portage.pkgsplit(pkgname + '-' + version),

diff --git a/tests/test_package_db.py b/tests/test_package_db.py
index 0f82129..d491152 100644
--- a/tests/test_package_db.py
+++ b/tests/test_package_db.py
@@ -58,7 +58,7 @@ class TestDummyDB(BaseTest):
         db.generate()
         db2 = DummyDB(self.tempdir.name, self.packages)
         db2.read()
-        self.assertEqual(db.db, db2.db)
+        self.assertEqual(db.database, db2.database)
 
     def test_list_categories(self):
         db = DummyDB(self.tempdir.name, self.packages)
@@ -107,7 +107,7 @@ class TestDummyDB(BaseTest):
 
         os.chdir(prev)
 
-        self.assertEqual(src_db.db, db.db)
+        self.assertEqual(src_db.database, db.database)
 
     def test_sync_fail(self):
         db = DummyDB(os.path.join(self.tempdir.name, 'testdb'), self.packages)


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-07-02 14:48 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-07-02 14:48 UTC (permalink / raw
  To: gentoo-commits

commit:     72ebc34dc4ff6fa2c56a3629f267b74c32723951
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Tue Jul  2 13:55:50 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Tue Jul  2 13:55:50 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=72ebc34d

py2: encoding unicode -> utf-8 (in xml.etree.ElementTree.tostring)

---
 g_sorcery/metadata.py  |  2 +-
 tests/test_metadata.py | 13 ++++++++-----
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/g_sorcery/metadata.py b/g_sorcery/metadata.py
index da4d291..1ce8fdc 100644
--- a/g_sorcery/metadata.py
+++ b/g_sorcery/metadata.py
@@ -17,7 +17,7 @@ import xml.etree.ElementTree as ET
 import xml.dom.minidom as minidom
 
 def prettify(tree):
-    rough_str = ET.tostring(tree, 'unicode')
+    rough_str = ET.tostring(tree, "utf-8").decode("utf-8")
     reparsed = minidom.parseString(rough_str)
     return reparsed.toprettyxml(encoding="utf-8").decode("utf-8")
 

diff --git a/tests/test_metadata.py b/tests/test_metadata.py
index 39155fb..288d8b1 100644
--- a/tests/test_metadata.py
+++ b/tests/test_metadata.py
@@ -19,6 +19,9 @@ from g_sorcery import exceptions, metadata, package_db
 
 from tests.base import BaseTest
 
+def tostring(element):
+    return ET.tostring(element, encoding='utf-8').decode('utf-8')
+
 class TestXMLGenerator(BaseTest):
 
     def test_generate(self):
@@ -52,22 +55,22 @@ class TestXMLGenerator(BaseTest):
         xg = metadata.XMLGenerator('test_ext', schema)
         self.assertRaises(exceptions.XMLGeneratorError, xg.generate, {})
         tree = xg.generate({'desc' : 'test xml'})
-        self.assertEqual(ET.tostring(tree, encoding='unicode'),
+        self.assertEqual(tostring(tree),
                          '<test_ext><desc>test xml</desc></test_ext>')
         tree = xg.generate({'desc' : 'test xml', 
                             'contact' : {'email' : 'test@example.com',
                                          'phone' : '00-0'}})
-        self.assertEqual(ET.tostring(tree, encoding='unicode'),
+        self.assertEqual(tostring(tree),
                     '<test_ext><desc>test xml</desc><contact><email>test@example.com\
 </email><phone>00-0</phone></contact></test_ext>')
         tree = xg.generate({'desc' : 'test xml', 
                             'multiple' : ['test1', 'test2', 'test3']})
-        self.assertEqual(ET.tostring(tree, encoding='unicode'),
+        self.assertEqual(tostring(tree),
                          '<test_ext><desc>test xml</desc><multiple>test1</multiple>\
 <multiple>test2</multiple><multiple>test3</multiple></test_ext>')
         tree = xg.generate({'desc' : 'test xml', 
                             'flag' : [('flag1', 'test1'), ('flag2', 'test2')]})
-        self.assertEqual(ET.tostring(tree, encoding='unicode'),
+        self.assertEqual(tostring(tree),
                          '<test_ext><desc>test xml</desc><flag name="flag1">test1</flag>\
 <flag name="flag2">test2</flag></test_ext>')
 
@@ -109,7 +112,7 @@ class TestMetadataGenerator(BaseTest):
 
     def test_process(self):
         mg = DummyMetadataGenerator(None)
-        self.assertEqual(ET.tostring(mg.process(None, description), encoding='unicode'),
+        self.assertEqual(tostring(mg.process(None, description)),
                          '<pkgmetadata><herd>test</herd><maintainer><email>test@example.com</email>\
 <name>testor</name></maintainer><longdescription>test metadata</longdescription><use>\
 <flag name="flag1">test flag1</flag><flag name="flag2">test flag2</flag></use>\


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-07-02 12:25 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-07-02 12:25 UTC (permalink / raw
  To: gentoo-commits

commit:     7c3f2ef461e92ef610ea835997c21921a8b4d05f
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Tue Jul  2 12:26:25 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Tue Jul  2 12:26:25 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=7c3f2ef4

base class for tests and initial commit for py2 compatibility module

---
 g_sorcery/compatibility.py | 21 +++++++++++++++++++++
 tests/base.py              | 24 ++++++++++++++++++++++++
 tests/test_backend.py      | 10 +++-------
 tests/test_dummy.py        |  7 +++----
 tests/test_ebuild.py       | 18 ++++--------------
 tests/test_elpa_db.py      |  7 ++-----
 tests/test_fileutils.py    |  8 +++-----
 tests/test_g_sorcery.py    | 16 +++++-----------
 tests/test_metadata.py     | 14 +++-----------
 tests/test_package_db.py   |  8 +++++---
 10 files changed, 73 insertions(+), 60 deletions(-)

diff --git a/g_sorcery/compatibility.py b/g_sorcery/compatibility.py
new file mode 100644
index 0000000..ea6f3bf
--- /dev/null
+++ b/g_sorcery/compatibility.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+    compatibility.py
+    ~~~~~~~~~~~~~~~~
+    
+    utilities for py2 compatibility
+    
+    :copyright: (c) 2013 by Jauhien Piatlicki
+    :license: GPL-2, see LICENSE for more details.
+"""
+
+import sys
+
+py2k = sys.version_info < (3, 0)
+
+if py2k:
+    pass
+else:
+    from tempfile import TemporaryDirectory

diff --git a/tests/base.py b/tests/base.py
new file mode 100644
index 0000000..0c3270a
--- /dev/null
+++ b/tests/base.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+    base.py
+    ~~~~~~~
+    
+    base class for tests
+    
+    :copyright: (c) 2013 by Jauhien Piatlicki
+    :license: GPL-2, see LICENSE for more details.
+"""
+
+import unittest
+
+from g_sorcery.compatibility import TemporaryDirectory
+
+class BaseTest(unittest.TestCase):
+
+    def setUp(self):
+        self.tempdir = TemporaryDirectory()
+
+    def tearDown(self):
+        del self.tempdir

diff --git a/tests/test_backend.py b/tests/test_backend.py
index 65e136d..2c28f79 100644
--- a/tests/test_backend.py
+++ b/tests/test_backend.py
@@ -17,6 +17,8 @@ from g_sorcery import backend, ebuild, metadata, package_db
 
 from tests import test_ebuild, test_metadata
 
+from tests.base import BaseTest
+
 class DummyBackend(backend.Backend):
     def __init__(self, PackageDB, EbuildGenrator, MetadataGenerator, directory,
                  sync_db=True, eclass_dir=""):
@@ -24,14 +26,8 @@ class DummyBackend(backend.Backend):
                          sync_db=sync_db, eclass_dir=eclass_dir)
 
 
-class TestBackend(unittest.TestCase):
+class TestBackend(BaseTest):
     
-    def setUp(self):
-        self.tempdir = tempfile.TemporaryDirectory()
-
-    def tearDown(self):
-        del self.tempdir
-
     def test_list_eclasses(self):
         backend = DummyBackend(package_db.PackageDB, ebuild.EbuildGenerator,
                                metadata.MetadataGenerator,

diff --git a/tests/test_dummy.py b/tests/test_dummy.py
index dfa9700..58df716 100644
--- a/tests/test_dummy.py
+++ b/tests/test_dummy.py
@@ -13,10 +13,9 @@
 
 import unittest
 
-class TestDummy(unittest.TestCase):
-    
-    def setUp(self):
-        pass
+from tests.base import BaseTest
+
+class TestDummy(BaseTest):
     
     def test_dummy(self):
         self.assertEqual('works', 'works')

diff --git a/tests/test_ebuild.py b/tests/test_ebuild.py
index 52c34f5..8e7aca4 100644
--- a/tests/test_ebuild.py
+++ b/tests/test_ebuild.py
@@ -15,6 +15,8 @@ import os, tempfile, unittest
 
 from g_sorcery import ebuild, package_db
 
+from tests.base import BaseTest
+
 package = package_db.Package("app-test", "test", "0.1")
 package2 = package_db.Package("app-test", "tst", "1")
 
@@ -36,13 +38,7 @@ class DummyEbuildGenerator(ebuild.EbuildGenerator):
         return tmpl
 
 
-class TestEbuildGenerator(unittest.TestCase):
-    
-    def setUp(self):
-        self.tempdir = tempfile.TemporaryDirectory()
-
-    def tearDown(self):
-        del self.tempdir
+class TestEbuildGenerator(BaseTest):
 
     def test_process(self):
         eg = DummyEbuildGenerator(None)
@@ -69,13 +65,7 @@ class DummyEbuildGeneratorFromFile(ebuild.EbuildGeneratorFromFile):
         return self.path
 
 
-class TestEbuildGeneratorFromFile(unittest.TestCase):
-    
-    def setUp(self):
-        self.tempdir = tempfile.TemporaryDirectory()
-
-    def tearDown(self):
-        del self.tempdir
+class TestEbuildGeneratorFromFile(BaseTest):
 
     def test_generate(self):
         db = DummyDB(os.path.join(self.tempdir.name, 'tstdb'))

diff --git a/tests/test_elpa_db.py b/tests/test_elpa_db.py
index 97ce4e2..874ee96 100644
--- a/tests/test_elpa_db.py
+++ b/tests/test_elpa_db.py
@@ -19,12 +19,9 @@ from g_sorcery import exceptions, package_db
 
 from tests.server import Server
 
-class TestElpaDB(unittest.TestCase):
-    def setUp(self):
-        self.tempdir = tempfile.TemporaryDirectory()
+from tests.base import BaseTest
 
-    def tearDown(self):
-        del self.tempdir
+class TestElpaDB(BaseTest):
 
     def test_generate(self):
         prev = os.getcwd()

diff --git a/tests/test_fileutils.py b/tests/test_fileutils.py
index 1760444..1e3ab1f 100644
--- a/tests/test_fileutils.py
+++ b/tests/test_fileutils.py
@@ -15,17 +15,15 @@ import json, os, shutil, tempfile, unittest
 
 from g_sorcery import exceptions, fileutils
 
+from tests.base import BaseTest
 
-class TestFileJSON(unittest.TestCase):
+class TestFileJSON(BaseTest):
     
     def setUp(self):
-        self.tempdir = tempfile.TemporaryDirectory()
+        super().setUp()
         self.path = os.path.join(self.tempdir.name, 'tst')
         self.name = 'tst.json'
 
-    def tearDown(self):
-        del self.tempdir
-
     def do_test_read_ok(self, mandatories, value_suffix=""):
         f = fileutils.FileJSON(self.path, self.name, mandatories)
         content = f.read()

diff --git a/tests/test_g_sorcery.py b/tests/test_g_sorcery.py
index 4b18474..bc91e97 100644
--- a/tests/test_g_sorcery.py
+++ b/tests/test_g_sorcery.py
@@ -17,17 +17,16 @@ from g_sorcery import g_sorcery
 
 from tests.dummy_backend import backend as dummyBackend
 
-class TestBin(unittest.TestCase):
+from tests.base import BaseTest
+
+class TestBin(BaseTest):
     def setUp(self):
-        self.tempdir = tempfile.TemporaryDirectory()
+        super().setUp()
         
         binpath = os.path.join(os.path.dirname(
             os.path.dirname(os.path.realpath(__file__))), 'bin')
         self.binary = os.path.join(binpath, 'g-sorcery')
 
-    def tearDown(self):
-        del self.tempdir
-
     def test_g_sorcery(self):
         self.assertEqual(subprocess.check_output(self.binary),  b'g-sorcery\n')
 
@@ -55,12 +54,7 @@ class TestBin(unittest.TestCase):
                          dummyBackend.instance.test())
         os.chdir(prev)
 
-class TestGSorcery(unittest.TestCase):
-    def setUp(self):
-        self.tempdir = tempfile.TemporaryDirectory()
-
-    def tearDown(self):
-        del self.tempdir
+class TestGSorcery(BaseTest):
 
     def test_get_backend(self):
         self.assertEqual(g_sorcery.get_backend('nonexistent_backend'), None)

diff --git a/tests/test_metadata.py b/tests/test_metadata.py
index 9bb1f43..4906541 100644
--- a/tests/test_metadata.py
+++ b/tests/test_metadata.py
@@ -17,12 +17,9 @@ import tempfile, unittest
 
 from g_sorcery import exceptions, metadata, package_db
 
-class TestXMLGenerator(unittest.TestCase):
-    def setUp(self):
-        pass
+from tests.base import BaseTest
 
-    def tearDown(self):
-        pass
+class TestXMLGenerator(BaseTest):
 
     def test_generate(self):
         schema = [{'name' : 'desc',
@@ -108,12 +105,7 @@ class DummyDB(package_db.PackageDB):
         self.add_package(package, description)
         
 
-class TestMetadataGenerator(unittest.TestCase):
-    def setUp(self):
-        self.tempdir = tempfile.TemporaryDirectory()
-
-    def tearDown(self):
-        del self.tempdir
+class TestMetadataGenerator(BaseTest):
 
     def test_process(self):
         mg = DummyMetadataGenerator(None)

diff --git a/tests/test_package_db.py b/tests/test_package_db.py
index 1433eb7..6b1004e 100644
--- a/tests/test_package_db.py
+++ b/tests/test_package_db.py
@@ -17,6 +17,8 @@ from g_sorcery import package_db, exceptions
 
 from tests.server import Server
 
+from tests.base import BaseTest
+
 class DummyDB(package_db.PackageDB):
     def __init__(self, directory, packages):
         super().__init__(directory)
@@ -33,10 +35,10 @@ class DummyDB(package_db.PackageDB):
         return self.db_uri + '/dummy.tar.gz'
 
 
-class TestDummyDB(unittest.TestCase):
+class TestDummyDB(BaseTest):
     
     def setUp(self):
-        self.tempdir = tempfile.TemporaryDirectory()
+        super().setUp()
         category1 = 'app-test'
         category2 = 'dev-test'
         self.packages = [package_db.Package(category1, 'test', '0.2'),
@@ -47,7 +49,7 @@ class TestDummyDB(unittest.TestCase):
             package_db.Package(category2, 'tst', '0.1')]
 
     def tearDown(self):
-        del self.tempdir
+        super().tearDown()
 
     def test_manifest(self):
         db = DummyDB(self.tempdir.name, self.packages)


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-07-01 20:51 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-07-01 20:51 UTC (permalink / raw
  To: gentoo-commits

commit:     32e17174a95099bbbbcce8cdb83bb4573308753e
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Mon Jul  1 20:52:46 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Mon Jul  1 20:52:46 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=32e17174

g_sorcery/g_sorcery: backend config, initial commit

---
 g_sorcery/g_sorcery.py  | 29 +++++++++++++++++++++++++++--
 tests/test_g_sorcery.py | 25 +++++++++++++++++++++----
 2 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/g_sorcery/g_sorcery.py b/g_sorcery/g_sorcery.py
index dd90c96..4b1784a 100644
--- a/g_sorcery/g_sorcery.py
+++ b/g_sorcery/g_sorcery.py
@@ -11,10 +11,35 @@
     :license: GPL-2, see LICENSE for more details.
 """
 
-import sys
+import os, sys
+
+from .fileutils import FileJSON
+
+from .exceptions import FileJSONError
 
 def main():
-    print('it works')
+    name = os.path.basename(sys.argv[0])
+    if name == 'g-sorcery':
+        print(name)
+        return 0
+    else:
+        cfg = name + '.json'
+        cfg_path = None
+        for path in '.', '/etc/g-sorcery', '~':
+            current = os.path.join(path, cfg)
+            if (os.path.isfile(current)):
+                cfg_path = path
+                break
+        if not cfg_path:
+            sys.stderr.write('g-sorcery error: no config file for ' + name + ' backend\n')
+            return -1
+        cfg_f = FileJSON(cfg_path, cfg, ['package'])
+        try:
+            config = cfg_f.read()
+        except FileJSONError as e:
+            sys.stderr.write('g-sorcery error in config file for ' + name + ': ' + str(e) + '\n')
+            return -1
+        pass
 
 if __name__ == "__main__":
     sys.exit(main())

diff --git a/tests/test_g_sorcery.py b/tests/test_g_sorcery.py
index 7241b19..7ff9992 100644
--- a/tests/test_g_sorcery.py
+++ b/tests/test_g_sorcery.py
@@ -16,18 +16,35 @@ import os, subprocess, tempfile, unittest
 class TestBin(unittest.TestCase):
     def setUp(self):
         self.tempdir = tempfile.TemporaryDirectory()
+        
+        binpath = os.path.join(os.path.dirname(
+            os.path.dirname(os.path.realpath(__file__))), 'bin')
+        self.binary = os.path.join(binpath, 'g-sorcery')
 
     def tearDown(self):
         del self.tempdir
 
     def test_g_sorcery(self):
-        binpath = os.path.join(os.path.split(
-            os.path.dirname(os.path.realpath(__file__)))[0], 'bin')
-        binary = os.path.join(binpath, 'g-sorcery')
-        self.assertEqual(subprocess.check_output(binary),  b'it works\n')
+        self.assertEqual(subprocess.check_output(self.binary),  b'g-sorcery\n')
 
+    def test_nonexistent_backend(self):
+        prev = os.getcwd()
+        os.chdir(self.tempdir.name)
+        os.system('ln -s ' + self.binary + ' g-nonexistent')
+        self.assertRaises(subprocess.CalledProcessError, subprocess.check_output, './g-nonexistent')
+        os.chdir(prev)
+
+    def test_empty_config(self):
+        prev = os.getcwd()
+        os.chdir(self.tempdir.name)
+        os.system('ln -s ' + self.binary + ' g-empty')
+        os.system('echo {} > ./g-empty.json')
+        self.assertRaises(subprocess.CalledProcessError, subprocess.check_output, './g-empty')
+        os.chdir(prev)
 
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(TestBin('test_g_sorcery'))
+    suite.addTest(TestBin('test_nonexistent_backend'))
+    suite.addTest(TestBin('test_empty_config'))
     return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-07-01  0:05 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-07-01  0:05 UTC (permalink / raw
  To: gentoo-commits

commit:     e34a7a1d98b0a3b1ff1a8ea35d1a70134989e555
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Mon Jul  1 00:06:52 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Mon Jul  1 00:06:52 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=e34a7a1d

g_sorcery/backend: generate_metadata

---
 g_sorcery/backend.py     |  9 +++++++--
 g_sorcery/package_db.py  | 14 ++++++++++++++
 tests/test_backend.py    | 23 +++++++++++++++++++----
 tests/test_metadata.py   | 26 ++++++++++++++------------
 tests/test_package_db.py |  6 ++++++
 5 files changed, 60 insertions(+), 18 deletions(-)

diff --git a/g_sorcery/backend.py b/g_sorcery/backend.py
index 476a8a4..f472a85 100644
--- a/g_sorcery/backend.py
+++ b/g_sorcery/backend.py
@@ -13,8 +13,10 @@
 
 import glob, os
 
+from .package_db import Package
+
 class Backend:
-    def __init__(self, PackageDB, EbuildGenrator, directory,
+    def __init__(self, PackageDB, EbuildGenrator, MetadataGenerator, directory,
                  repo_uri="", db_uri="", sync_db=True, eclass_dir=""):
         self.sync_db = sync_db
         self.repo_uri = repo_uri
@@ -32,6 +34,7 @@ class Backend:
         self.db_uri = self.db.db_uri
 
         self.eg = EbuildGenrator(self.db)
+        self.mg = MetadataGenerator(self.db)
 
     def sync(self):
         if self.sync_db and not self.db_uri:
@@ -69,4 +72,6 @@ class Backend:
         return eclass
 
     def generate_metadata(self, category, name):
-        pass
+        version = self.db.get_max_version(category, name)
+        metadata = self.mg.generate(Package(category, name, version))
+        return metadata

diff --git a/g_sorcery/package_db.py b/g_sorcery/package_db.py
index b4f6193..561129d 100644
--- a/g_sorcery/package_db.py
+++ b/g_sorcery/package_db.py
@@ -14,6 +14,8 @@
 from .exceptions import DBStructureError, FileJSONError, IntegrityError, \
      InvalidKeyError, SyncError
 
+import portage
+     
 import collections, glob, hashlib, json, os, shutil, tarfile, tempfile
 
 Package = collections.namedtuple("Package", "category name version")
@@ -353,3 +355,15 @@ class PackageDB:
     def get_package_description(self, package):
         #a possible exception should be catched in the caller
         return self.db[package.category + '/' + package.name][package.version]
+
+    def get_max_version(self, category, name):
+        pkgname = category + '/' + name
+        if not pkgname in self.db:
+            raise InvalidKeyError('No such package: ' + pkgname)
+        versions = list(self.db[pkgname])
+        max_ver = versions[0]
+        for version in versions[1:]:
+            if portage.pkgcmp(portage.pkgsplit(pkgname + '-' + version),
+                              portage.pkgsplit(pkgname + '-' + max_ver)) > 0:
+                max_ver = version
+        return max_ver

diff --git a/tests/test_backend.py b/tests/test_backend.py
index 027f4a8..65e136d 100644
--- a/tests/test_backend.py
+++ b/tests/test_backend.py
@@ -13,14 +13,14 @@
 
 import os, tempfile, unittest
 
-from g_sorcery import backend, ebuild, package_db
+from g_sorcery import backend, ebuild, metadata, package_db
 
-from tests import test_ebuild
+from tests import test_ebuild, test_metadata
 
 class DummyBackend(backend.Backend):
-    def __init__(self, PackageDB, EbuildGenrator, directory,
+    def __init__(self, PackageDB, EbuildGenrator, MetadataGenerator, directory,
                  sync_db=True, eclass_dir=""):
-        super().__init__(PackageDB, EbuildGenrator, directory,
+        super().__init__(PackageDB, EbuildGenrator, MetadataGenerator, directory,
                          sync_db=sync_db, eclass_dir=eclass_dir)
 
 
@@ -34,6 +34,7 @@ class TestBackend(unittest.TestCase):
 
     def test_list_eclasses(self):
         backend = DummyBackend(package_db.PackageDB, ebuild.EbuildGenerator,
+                               metadata.MetadataGenerator,
                                self.tempdir.name, eclass_dir = self.tempdir.name)
         self.assertEqual(backend.list_eclasses(), [])
         lst = ['test', 'supertest', 'anothertest']
@@ -44,6 +45,7 @@ class TestBackend(unittest.TestCase):
 
     def test_generate_eclass(self):
         backend = DummyBackend(package_db.PackageDB, ebuild.EbuildGenerator,
+                               metadata.MetadataGenerator,
                                self.tempdir.name, eclass_dir = self.tempdir.name)
         eclass = ["testing eclass", "nothing interesting here"]
         eclass_name = "test"
@@ -55,6 +57,7 @@ class TestBackend(unittest.TestCase):
 
     def test_list_ebuilds(self):
         backend = DummyBackend(test_ebuild.DummyDB, test_ebuild.DummyEbuildGenerator,
+                               metadata.MetadataGenerator,
                                self.tempdir.name, eclass_dir = self.tempdir.name, sync_db = False)
         backend.sync()
         ebuilds = backend.list_ebuilds()
@@ -62,16 +65,28 @@ class TestBackend(unittest.TestCase):
 
     def test_generate_ebuild(self):
         backend = DummyBackend(test_ebuild.DummyDB, test_ebuild.DummyEbuildGenerator,
+                               metadata.MetadataGenerator,
                                self.tempdir.name, eclass_dir = self.tempdir.name, sync_db = False)
         backend.sync()
         ebuild = backend.generate_ebuild(test_ebuild.package)
         self.assertEqual(ebuild, ['test', 'author: jauhien',
                                   'homepage: 127.0.0.1', 'var: $var'])
 
+    def test_generate_metadata(self):
+        backend = DummyBackend(test_metadata.DummyDB, ebuild.EbuildGenerator,
+                               metadata.MetadataGenerator,
+                               self.tempdir.name, eclass_dir = self.tempdir.name, sync_db = False)
+        backend.sync()
+        self.assertEqual(backend.generate_metadata("app-test", "test"),
+                         test_metadata.resulting_metadata)
+                         
+        
+
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(TestBackend('test_list_eclasses'))
     suite.addTest(TestBackend('test_generate_eclass'))
     suite.addTest(TestBackend('test_list_ebuilds'))
     suite.addTest(TestBackend('test_generate_ebuild'))
+    suite.addTest(TestBackend('test_generate_metadata'))
     return suite

diff --git a/tests/test_metadata.py b/tests/test_metadata.py
index 2398733..9bb1f43 100644
--- a/tests/test_metadata.py
+++ b/tests/test_metadata.py
@@ -87,6 +87,18 @@ description = {'herd' : ['test'],
                'use' : {'flag' : [('flag1', 'test flag1'), ('flag2', 'test flag2')]},
                'upstream' : {'maintainer' : [{'name' : 'TEST'}], 'remote-id' : '001'}}
 
+resulting_metadata = ['<?xml version="1.0" encoding="utf-8"?>',
+                      '<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">',
+                      '<pkgmetadata>', '\t<herd>test</herd>',
+                      '\t<maintainer>', '\t\t<email>test@example.com</email>',
+                      '\t\t<name>testor</name>', '\t</maintainer>',
+                      '\t<longdescription>test metadata</longdescription>',
+                      '\t<use>', '\t\t<flag name="flag1">test flag1</flag>',
+                      '\t\t<flag name="flag2">test flag2</flag>', '\t</use>',
+                      '\t<upstream>', '\t\t<maintainer>', '\t\t\t<name>TEST</name>',
+                      '\t\t</maintainer>', '\t\t<remote-id>001</remote-id>',
+                      '\t</upstream>', '</pkgmetadata>']
+
 class DummyDB(package_db.PackageDB):
     def __init__(self, directory, repo_uri="", db_uri=""):
         super().__init__(directory, repo_uri, db_uri)
@@ -116,19 +128,9 @@ class TestMetadataGenerator(unittest.TestCase):
         db.generate()
         mg = DummyMetadataGenerator(db)
         metadata = mg.generate(package)
-        self.assertEqual(metadata,
-                          ['<?xml version="1.0" encoding="utf-8"?>',
-                           '<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">',
-                           '<pkgmetadata>', '\t<herd>test</herd>',
-                           '\t<maintainer>', '\t\t<email>test@example.com</email>',
-                           '\t\t<name>testor</name>', '\t</maintainer>',
-                           '\t<longdescription>test metadata</longdescription>',
-                           '\t<use>', '\t\t<flag name="flag1">test flag1</flag>',
-                           '\t\t<flag name="flag2">test flag2</flag>', '\t</use>',
-                           '\t<upstream>', '\t\t<maintainer>', '\t\t\t<name>TEST</name>',
-                           '\t\t</maintainer>', '\t\t<remote-id>001</remote-id>',
-                           '\t</upstream>', '</pkgmetadata>'])
+        self.assertEqual(metadata, resulting_metadata)
 
+        
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(TestXMLGenerator('test_generate'))

diff --git a/tests/test_package_db.py b/tests/test_package_db.py
index 2b8c482..c5d7074 100644
--- a/tests/test_package_db.py
+++ b/tests/test_package_db.py
@@ -219,6 +219,11 @@ class TestDummyDB(unittest.TestCase):
         db = DummyDB(os.path.join(self.tempdir.name, 'testdb'), self.packages)
         self.assertRaises(exceptions.SyncError, db.sync, db_uri='127.0.0.1:8080')
 
+    def test_get_max_version(self):
+        db = DummyDB(os.path.join(self.tempdir.name, 'testdb'), self.packages)
+        db.generate()
+        self.assertEqual(db.get_max_version('dev-test', 'test'), '0.2')
+
             
 def suite():
     suite = unittest.TestSuite()
@@ -237,4 +242,5 @@ def suite():
     suite.addTest(TestDummyDB('test_list_package_versions'))
     suite.addTest(TestDummyDB('test_sync'))
     suite.addTest(TestDummyDB('test_sync_fail'))
+    suite.addTest(TestDummyDB('test_get_max_version'))
     return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-30 23:29 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-30 23:29 UTC (permalink / raw
  To: gentoo-commits

commit:     ad2315d5c047be8696c84d76b64a0cac39aaf2da
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Sun Jun 30 22:19:51 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Sun Jun 30 22:19:51 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=ad2315d5

g_sorcery/metadata: MetadataGenerator, initial commit

---
 g_sorcery/metadata.py  | 16 ++++++++++++++++
 tests/test_metadata.py | 16 ++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/g_sorcery/metadata.py b/g_sorcery/metadata.py
index ccc344a..c945f70 100644
--- a/g_sorcery/metadata.py
+++ b/g_sorcery/metadata.py
@@ -60,3 +60,19 @@ class XMLGenerator:
         else:
             child.text = value
         
+
+class MetadataGenerator:
+    def __init__(self, db):
+        self.db = db
+        
+    def generate(self, package):
+        description = self.db.get_package_description(package)
+        metadata = self.process(package, description)
+        metadata = self.postprocess(package, description, metadata)
+        return metadata
+
+    def process(self, package, description):
+        pass
+        
+    def postprocess(self, package, description, metadata):
+        return metadata

diff --git a/tests/test_metadata.py b/tests/test_metadata.py
index 91da5bc..8bec86b 100644
--- a/tests/test_metadata.py
+++ b/tests/test_metadata.py
@@ -75,7 +75,23 @@ class TestXMLGenerator(unittest.TestCase):
 <flag name="flag2">test2</flag></test_ext>')
 
 
+class DummyMetadataGenerator(metadata.MetadataGenerator):
+    def __init__(self, db):
+        super().__init__(db)
+
+class TestMetadataGenerator(unittest.TestCase):
+    def setUp(self):
+        self.tempdir = tempfile.TemporaryDirectory()
+
+    def tearDown(self):
+        del self.tempdir
+
+    def test_process(self):
+        mg = DummyMetadataGenerator(None)
+
+
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(TestXMLGenerator('test_generate'))
+    suite.addTest(TestMetadataGenerator('test_process'))
     return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-30 23:29 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-30 23:29 UTC (permalink / raw
  To: gentoo-commits

commit:     fa7c0ac5f53757d538483c449df7fd5ae233eb7e
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Sun Jun 30 23:30:54 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Sun Jun 30 23:30:54 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=fa7c0ac5

g_sorcery/metadata: MetadataGenerator, generate

---
 g_sorcery/metadata.py  |  7 ++++++-
 tests/test_metadata.py | 43 +++++++++++++++++++++++++++++++++++++------
 2 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/g_sorcery/metadata.py b/g_sorcery/metadata.py
index 1ead07a..89d071e 100644
--- a/g_sorcery/metadata.py
+++ b/g_sorcery/metadata.py
@@ -19,7 +19,7 @@ import xml.dom.minidom as minidom
 def prettify(tree):
     rough_str = ET.tostring(tree, 'unicode')
     reparsed = minidom.parseString(rough_str)
-    return reparsed.toprettyxml()
+    return reparsed.toprettyxml(encoding="utf-8").decode("utf-8")
 
 class XMLGenerator:
     def __init__(self, external, schema):
@@ -140,6 +140,11 @@ class MetadataGenerator:
         description = self.db.get_package_description(package)
         metadata = self.process(package, description)
         metadata = self.postprocess(package, description, metadata)
+        metadata = prettify(metadata)
+        metadata = metadata.split('\n')
+        if metadata[-1] == '':
+                metadata = metadata[:-1]
+        metadata.insert(1, '<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">')
         return metadata
 
     def process(self, package, description):

diff --git a/tests/test_metadata.py b/tests/test_metadata.py
index aeaac6d..2398733 100644
--- a/tests/test_metadata.py
+++ b/tests/test_metadata.py
@@ -15,7 +15,7 @@ import xml.etree.ElementTree as ET
 
 import tempfile, unittest
 
-from g_sorcery import exceptions, metadata
+from g_sorcery import exceptions, metadata, package_db
 
 class TestXMLGenerator(unittest.TestCase):
     def setUp(self):
@@ -79,6 +79,23 @@ class DummyMetadataGenerator(metadata.MetadataGenerator):
     def __init__(self, db):
         super().__init__(db)
 
+package = package_db.Package("app-test", "test", "0.1")
+
+description = {'herd' : ['test'],
+               'maintainer' : [{'email' : 'test@example.com', 'name' : 'testor'}],
+               'longdescription' : 'test metadata',
+               'use' : {'flag' : [('flag1', 'test flag1'), ('flag2', 'test flag2')]},
+               'upstream' : {'maintainer' : [{'name' : 'TEST'}], 'remote-id' : '001'}}
+
+class DummyDB(package_db.PackageDB):
+    def __init__(self, directory, repo_uri="", db_uri=""):
+        super().__init__(directory, repo_uri, db_uri)
+
+    def generate_tree(self):
+        self.add_category("app-test")
+        self.add_package(package, description)
+        
+
 class TestMetadataGenerator(unittest.TestCase):
     def setUp(self):
         self.tempdir = tempfile.TemporaryDirectory()
@@ -88,19 +105,33 @@ class TestMetadataGenerator(unittest.TestCase):
 
     def test_process(self):
         mg = DummyMetadataGenerator(None)
-        description = {'herd' : ['test'],
-                       'maintainer' : [{'email' : 'test@example.com', 'name' : 'testor'}],
-                       'longdescription' : 'test metadata',
-                       'use' : {'flag' : [('flag1', 'test flag1'), ('flag2', 'test flag2')]},
-                       'upstream' : {'maintainer' : [{'name' : 'TEST'}], 'remote-id' : '001'}}
         self.assertEqual(ET.tostring(mg.process(None, description), encoding='unicode'),
                          '<pkgmetadata><herd>test</herd><maintainer><email>test@example.com</email>\
 <name>testor</name></maintainer><longdescription>test metadata</longdescription><use>\
 <flag name="flag1">test flag1</flag><flag name="flag2">test flag2</flag></use>\
 <upstream><maintainer><name>TEST</name></maintainer><remote-id>001</remote-id></upstream></pkgmetadata>')
 
+    def test_generate(self):
+        db = DummyDB(self.tempdir.name)
+        db.generate()
+        mg = DummyMetadataGenerator(db)
+        metadata = mg.generate(package)
+        self.assertEqual(metadata,
+                          ['<?xml version="1.0" encoding="utf-8"?>',
+                           '<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">',
+                           '<pkgmetadata>', '\t<herd>test</herd>',
+                           '\t<maintainer>', '\t\t<email>test@example.com</email>',
+                           '\t\t<name>testor</name>', '\t</maintainer>',
+                           '\t<longdescription>test metadata</longdescription>',
+                           '\t<use>', '\t\t<flag name="flag1">test flag1</flag>',
+                           '\t\t<flag name="flag2">test flag2</flag>', '\t</use>',
+                           '\t<upstream>', '\t\t<maintainer>', '\t\t\t<name>TEST</name>',
+                           '\t\t</maintainer>', '\t\t<remote-id>001</remote-id>',
+                           '\t</upstream>', '</pkgmetadata>'])
+
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(TestXMLGenerator('test_generate'))
     suite.addTest(TestMetadataGenerator('test_process'))
+    suite.addTest(TestMetadataGenerator('test_generate'))
     return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-30 23:29 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-30 23:29 UTC (permalink / raw
  To: gentoo-commits

commit:     5f037f6a973754545e32272abf677a9c48a473e6
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Sun Jun 30 23:07:51 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Sun Jun 30 23:07:51 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=5f037f6a

g_sorcery/metadata: MetadataGenerator, xml generation by description

---
 g_sorcery/metadata.py  |  3 ++-
 tests/test_metadata.py | 11 ++++++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/g_sorcery/metadata.py b/g_sorcery/metadata.py
index 7ef949a..1ead07a 100644
--- a/g_sorcery/metadata.py
+++ b/g_sorcery/metadata.py
@@ -143,7 +143,8 @@ class MetadataGenerator:
         return metadata
 
     def process(self, package, description):
-        pass
+        metadata = self.xmlg.generate(description)
+        return metadata
         
     def postprocess(self, package, description, metadata):
         return metadata

diff --git a/tests/test_metadata.py b/tests/test_metadata.py
index 8bec86b..aeaac6d 100644
--- a/tests/test_metadata.py
+++ b/tests/test_metadata.py
@@ -88,7 +88,16 @@ class TestMetadataGenerator(unittest.TestCase):
 
     def test_process(self):
         mg = DummyMetadataGenerator(None)
-
+        description = {'herd' : ['test'],
+                       'maintainer' : [{'email' : 'test@example.com', 'name' : 'testor'}],
+                       'longdescription' : 'test metadata',
+                       'use' : {'flag' : [('flag1', 'test flag1'), ('flag2', 'test flag2')]},
+                       'upstream' : {'maintainer' : [{'name' : 'TEST'}], 'remote-id' : '001'}}
+        self.assertEqual(ET.tostring(mg.process(None, description), encoding='unicode'),
+                         '<pkgmetadata><herd>test</herd><maintainer><email>test@example.com</email>\
+<name>testor</name></maintainer><longdescription>test metadata</longdescription><use>\
+<flag name="flag1">test flag1</flag><flag name="flag2">test flag2</flag></use>\
+<upstream><maintainer><name>TEST</name></maintainer><remote-id>001</remote-id></upstream></pkgmetadata>')
 
 def suite():
     suite = unittest.TestSuite()


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-30 19:55 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-30 19:55 UTC (permalink / raw
  To: gentoo-commits

commit:     e2456139f555f531c6a2a13d002b81725a7c389d
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Sun Jun 30 19:52:17 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Sun Jun 30 19:52:17 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=e2456139

g_sorcery/metadata: XMLGenerator

---
 g_sorcery/exceptions.py |  5 ++-
 g_sorcery/metadata.py   | 62 +++++++++++++++++++++++++++++++++++++
 tests/test_metadata.py  | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 147 insertions(+), 1 deletion(-)

diff --git a/g_sorcery/exceptions.py b/g_sorcery/exceptions.py
index 857e4ea..38a80b2 100644
--- a/g_sorcery/exceptions.py
+++ b/g_sorcery/exceptions.py
@@ -29,5 +29,8 @@ class IntegrityError(DBError):
 class DBStructureError(DBError):
     pass
 
-class FileJSONError(Exception):
+class FileJSONError(GSorceryError):
+    pass
+
+class XMLGeneratorError(GSorceryError):
     pass

diff --git a/g_sorcery/metadata.py b/g_sorcery/metadata.py
new file mode 100644
index 0000000..ccc344a
--- /dev/null
+++ b/g_sorcery/metadata.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+    metadata.py
+    ~~~~~~~~~~~
+    
+    metadata generation
+    
+    :copyright: (c) 2013 by Jauhien Piatlicki
+    :license: GPL-2, see LICENSE for more details.
+"""
+
+from .exceptions import XMLGeneratorError
+
+import xml.etree.ElementTree as ET
+import xml.dom.minidom as minidom
+
+def prettify(tree):
+    rough_str = ET.tostring(tree, 'unicode')
+    reparsed = minidom.parseString(rough_str)
+    return reparsed.toprettyxml()
+
+class XMLGenerator:
+    def __init__(self, external, schema):
+        self.external = external
+        self.schema = schema        
+
+    def generate(self, values):
+        root = ET.Element(self.external)
+        for tag in self.schema:
+            self.add_tag(root, tag, values)
+        return root
+
+    def add_tag(self, root, tag, values):
+        name = tag['name']
+        if not name in values:
+            if tag['required']:
+                raise XMLGeneratorError('Required tag not found: ' + name)
+            return
+        value = values[name]
+        multiple, attr = tag['multiple']
+        if multiple:
+            for v in value:
+                self.add_single_tag(root, name, tag, v, attr)
+        else:
+            self.add_single_tag(root, name, tag, value)
+            
+    def add_single_tag(self, root, name, tag, value, attr=None):
+        child = ET.SubElement(root, name)
+        if attr:
+            child.set(attr, value[0])
+            value = value[1]
+        subtags = tag['subtags']
+        if subtags:
+            if 'text' in value:
+                child.text = value[text]
+            for child_tag in subtags:
+                self.add_tag(child, child_tag, value)
+        else:
+            child.text = value
+        

diff --git a/tests/test_metadata.py b/tests/test_metadata.py
new file mode 100644
index 0000000..91da5bc
--- /dev/null
+++ b/tests/test_metadata.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+    test_metadata.py
+    ~~~~~~~~~~~~~~~~
+    
+    metadata generator test suite
+    
+    :copyright: (c) 2013 by Jauhien Piatlicki
+    :license: GPL-2, see LICENSE for more details.
+"""
+
+import xml.etree.ElementTree as ET
+
+import tempfile, unittest
+
+from g_sorcery import exceptions, metadata
+
+class TestXMLGenerator(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_generate(self):
+        schema = [{'name' : 'desc',
+                   'subtags' : [],
+                   'multiple' : (False, ""),
+                   'required' : True},
+                   {'name' : 'contact',
+                   'multiple' : (False, ""),
+                   'required' : False,
+                   'subtags' : [
+                       {'name' : 'email',
+                        'subtags' : [],
+                        'multiple' : (False, ""),
+                        'required' : True},
+                        
+                        {'name' : 'phone',
+                        'subtags' : [],
+                        'multiple' : (False, ""),
+                        'required' : False},
+                    ]},
+                    {'name' : 'multiple',
+                     'subtags' : [],
+                     'multiple' : (True, ""),
+                     'required' : False},
+                     {'name' : 'flag',
+                     'subtags' : [],
+                     'multiple' : (True, "name"),
+                     'required' : False},
+                   ]
+        xg = metadata.XMLGenerator('test_ext', schema)
+        self.assertRaises(exceptions.XMLGeneratorError, xg.generate, {})
+        tree = xg.generate({'desc' : 'test xml'})
+        self.assertEqual(ET.tostring(tree, encoding='unicode'),
+                         '<test_ext><desc>test xml</desc></test_ext>')
+        tree = xg.generate({'desc' : 'test xml', 
+                            'contact' : {'email' : 'test@example.com',
+                                         'phone' : '00-0'}})
+        self.assertEqual(ET.tostring(tree, encoding='unicode'),
+                    '<test_ext><desc>test xml</desc><contact><email>test@example.com\
+</email><phone>00-0</phone></contact></test_ext>')
+        tree = xg.generate({'desc' : 'test xml', 
+                            'multiple' : ['test1', 'test2', 'test3']})
+        self.assertEqual(ET.tostring(tree, encoding='unicode'),
+                         '<test_ext><desc>test xml</desc><multiple>test1</multiple>\
+<multiple>test2</multiple><multiple>test3</multiple></test_ext>')
+        tree = xg.generate({'desc' : 'test xml', 
+                            'flag' : [('flag1', 'test1'), ('flag2', 'test2')]})
+        self.assertEqual(ET.tostring(tree, encoding='unicode'),
+                         '<test_ext><desc>test xml</desc><flag name="flag1">test1</flag>\
+<flag name="flag2">test2</flag></test_ext>')
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(TestXMLGenerator('test_generate'))
+    return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-29 12:13 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-29 12:13 UTC (permalink / raw
  To: gentoo-commits

commit:     f56eb9904accf9ab6f9d02ee6c30f2811020c97f
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Sat Jun 29 12:09:08 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Sat Jun 29 12:09:08 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=f56eb990

g_sorcery/package_db: exceptions hierarchy, g_sorcery/exceptions: initial commit

---
 g_sorcery/exceptions.py  | 33 +++++++++++++++++++++++++++++++++
 g_sorcery/package_db.py  | 37 ++++++++++++++++++++-----------------
 tests/test_package_db.py | 15 ++++++++-------
 3 files changed, 61 insertions(+), 24 deletions(-)

diff --git a/g_sorcery/exceptions.py b/g_sorcery/exceptions.py
new file mode 100644
index 0000000..857e4ea
--- /dev/null
+++ b/g_sorcery/exceptions.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+    exceptions.py
+    ~~~~~~~~~~~~~
+    
+    Exceptions hierarchy
+    
+    :copyright: (c) 2013 by Jauhien Piatlicki
+    :license: GPL-2, see LICENSE for more details.
+"""
+
+class GSorceryError(Exception):
+    pass
+
+class DBError(GSorceryError):
+    pass
+
+class InvalidKeyError(DBError):
+    pass
+
+class SyncError(DBError):
+    pass
+
+class IntegrityError(DBError):
+    pass
+
+class DBStructureError(DBError):
+    pass
+
+class FileJSONError(Exception):
+    pass

diff --git a/g_sorcery/package_db.py b/g_sorcery/package_db.py
index 1fe4b38..e2cd40d 100644
--- a/g_sorcery/package_db.py
+++ b/g_sorcery/package_db.py
@@ -11,6 +11,9 @@
     :license: GPL-2, see LICENSE for more details.
 """
 
+from .exceptions import DBStructureError, FileJSONError, IntegrityError, \
+     InvalidKeyError, SyncError
+
 import collections, glob, hashlib, json, os, shutil, tarfile, tempfile
 
 Package = collections.namedtuple("Package", "category name version")
@@ -41,13 +44,13 @@ class FileJSON:
                 content = json.load(f)
             for key in self.mandatories:
                 if not key in content:
-                    raise KeyError
+                    raise FileJSONError('lack of mandatory key: ' + key)
         return content
 
     def write(self, content):
         for key in self.mandatories:
             if not key in content:
-                raise KeyError
+                raise FileJSONError('lack of mandatory key: ' + key)
         if not os.path.exists(self.directory):
             os.makedirs(self.directory)
         with open(self.path, 'w') as f:
@@ -131,7 +134,7 @@ class PackageDB:
         real_db_uri = self.get_real_db_uri()
         download_dir = tempfile.TemporaryDirectory()
         if os.system('wget -P ' + download_dir.name + ' ' + real_db_uri):
-            raise Exception('sync failed: ' + real_db_uri)
+            raise SyncError('sync failed: ' + real_db_uri)
         
         temp_dir = tempfile.TemporaryDirectory()
         for f_name in glob.iglob(os.path.join(download_dir.name, '*.tar.gz')):
@@ -148,13 +151,13 @@ class PackageDB:
             copy_all(current_dir, tempdb_dir.name)
 
         if not tempdb.check_manifest():
-            raise Exception('Manifest check failed.')
+            raise IntegrityError('Manifest check failed.')
 
         self.clean()
         copy_all(tempdb_dir.name, self.directory)
         
         if not self.check_manifest():
-            raise Exception('Manifest check failed, db inconsistent.')
+            raise IntegrityError('Manifest check failed, db inconsistent.')
                 
         del download_dir
         del temp_dir
@@ -176,7 +179,7 @@ class PackageDB:
         for category in categories:
             category_path = os.path.join(self.directory, category)
             if not os.path.isdir(category_path):
-                raise Exception('Empty category: ' + category)
+                raise DBStructureError('Empty category: ' + category)
             for root, dirs, files in os.walk(category_path):
                 for f in files:
                     manifest[os.path.join(root[len(self.directory)+1:], f)] = \
@@ -194,7 +197,7 @@ class PackageDB:
         names = [self.INFO_NAME, self.CATEGORIES_NAME, self.URI_NAME]
         for name in names:
             if not name in manifest:
-                raise Exception('Bad manifest: no ' + name + ' entry')
+                raise DBStructureError('Bad manifest: no ' + name + ' entry')
 
         for name, value in manifest.items():
             if hash_file(os.path.join(self.directory, name), hashlib.md5()) != \
@@ -216,7 +219,7 @@ class PackageDB:
         categories_f.write(self.db['categories'])
         for category in self.db['categories']:
             if not category in self.db['packages']:
-                raise Exception('Empty category: ' + category)
+                raise DBStructureError('Empty category: ' + category)
             for package, versions in self.db['packages'][category].items():
                 for version, content in versions.items():
                     f = FileJSON(os.path.join(self.directory, category, package),
@@ -248,7 +251,7 @@ class PackageDB:
     def read(self):
         sane, errors = self.check_manifest()
         if not sane:
-            raise Exception('Manifest error: ' + str(errors))
+            raise IntegrityError('Manifest error: ' + str(errors))
         info_f = FileJSON(self.directory, self.INFO_NAME, [])
         categories_f = FileJSON(self.directory, self.CATEGORIES_NAME, [])
         self.db['info'] = info_f.read()
@@ -256,23 +259,23 @@ class PackageDB:
         for category in self.db['categories']:
             category_path = os.path.join(self.directory, category)
             if not os.path.isdir(category_path):
-                raise Exception('Empty category: ' + category)
+                raise DBStructureError('Empty category: ' + category)
             
             f = FileJSON(category_path, self.PACKAGES_NAME, [])
             packages = f.read()
             if not packages:
-                raise Exception('Empty category: ' + category)
+                raise DBStructureError('Empty category: ' + category)
             
             self.db['packages'][category] = {}
             for name in packages:
                 package_path = os.path.join(category_path, name)
                 if not os.path.isdir(category_path):
-                    raise Exception('Empty package: ' + category + '/' + name)
+                    raise DBStructureError('Empty package: ' + category + '/' + name)
                 
                 f = FileJSON(package_path, self.VERSIONS_NAME, [])
                 versions = f.read()
                 if not versions:
-                    raise Exception('Empty package: ' + category + '/' + name)
+                    raise DBStructureError('Empty package: ' + category + '/' + name)
                 
                 self.db['packages'][category][name] = {}
                 for version in versions:
@@ -309,7 +312,7 @@ class PackageDB:
         name = package.name
         version = package.version
         if category and not category in self.db['packages']:
-            raise Exception('Non-existent category: ' + category)
+            raise InvalidKeyError('Non-existent category: ' + category)
         if name and not name in self.db['packages'][category]:
             self.db['packages'][category][name] = {}
         self.db['packages'][category][name][version] = description
@@ -319,14 +322,14 @@ class PackageDB:
 
     def list_package_names(self, category):
         if category and not category in self.db['packages']:
-            raise Exception('No such category: ' + category)
+            raise InvalidKeyError('No such category: ' + category)
         return list(self.db['packages'][category])
 
     def list_package_versions(self, category, name):
         if category and not category in self.db['packages']:
-            raise Exception('No such category: ' + category)
+            raise InvalidKeyError('No such category: ' + category)
         if name and not name in self.db['packages'][category]:
-            raise Exception('No such package: ' + name)
+            raise InvalidKeyError('No such package: ' + name)
         return list(self.db['packages'][category][name])
 
     def list_all_packages(self):

diff --git a/tests/test_package_db.py b/tests/test_package_db.py
index 94693d8..2b8c482 100644
--- a/tests/test_package_db.py
+++ b/tests/test_package_db.py
@@ -14,7 +14,7 @@
 import json, http.server, os, shutil, tempfile, threading, \
   unittest
 
-from g_sorcery import package_db
+from g_sorcery import package_db, exceptions
 
 
 class Server(threading.Thread):
@@ -84,7 +84,7 @@ class TestFileJSON(unittest.TestCase):
             json.dump(content, f)
         f = package_db.FileJSON(self.path, self.name, mandatories)
         mandatories.append("tst4")
-        self.assertRaises(KeyError, f.read)
+        self.assertRaises(exceptions.FileJSONError, f.read)
 
     def do_test_write_ok(self):
         mandatories = ['tst1', 'tst2', 'tst3']
@@ -102,7 +102,7 @@ class TestFileJSON(unittest.TestCase):
         content = {'tst1' : '', 'tst2' : ''}
         mandatories = ['tst1', 'tst2', 'tst3']
         f = package_db.FileJSON(self.path, self.name, mandatories)
-        self.assertRaises(KeyError, f.write, content)
+        self.assertRaises(exceptions.FileJSONError, f.write, content)
 
     def test_write_dir_does_not_exist(self):
         self.do_test_write_ok()
@@ -179,7 +179,7 @@ class TestDummyDB(unittest.TestCase):
         for category in categories:
             package_names = list(set([x.name for x in self.packages if x.category == category]))
             self.assertEqual(package_names, db.list_package_names(category))
-        self.assertRaises(Exception, db.list_package_names, 'no_such_category')
+        self.assertRaises(exceptions.InvalidKeyError, db.list_package_names, 'no_such_category')
 
     def test_list_package_versions(self):
         db = DummyDB(self.tempdir.name, self.packages)
@@ -190,8 +190,9 @@ class TestDummyDB(unittest.TestCase):
             for name in package_names:
                 versions = [x.version for x in self.packages if x.category == category and x.name == name]
                 self.assertEqual(versions, db.list_package_versions(category, name))
-        self.assertRaises(Exception, db.list_package_names, 'no_such_category', 'a')
-        self.assertRaises(Exception, db.list_package_names, categories[0], 'no_such_package')
+        self.assertRaises(exceptions.InvalidKeyError, db.list_package_versions, 'no_such_category', 'a')
+        self.assertRaises(exceptions.InvalidKeyError, db.list_package_versions,
+                          categories[0], 'no_such_package')
 
     def test_sync(self):
         src_db = DummyDB(os.path.join(self.tempdir.name, 'src_testdb'), self.packages)
@@ -216,7 +217,7 @@ class TestDummyDB(unittest.TestCase):
 
     def test_sync_fail(self):
         db = DummyDB(os.path.join(self.tempdir.name, 'testdb'), self.packages)
-        self.assertRaises(Exception, db.sync, db_uri='127.0.0.1:8080')
+        self.assertRaises(exceptions.SyncError, db.sync, db_uri='127.0.0.1:8080')
 
             
 def suite():


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-23 21:39 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-23 21:39 UTC (permalink / raw
  To: gentoo-commits

commit:     b6cf7231ae7425288746e5d28228744288637dbc
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Sun Jun 23 21:40:01 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Sun Jun 23 21:40:01 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=b6cf7231

g_sorcery/backend

---
 g_sorcery/backend.py    | 58 ++++++++++++++++++++++++++++++++++++-
 g_sorcery/package_db.py | 16 ++++++++--
 tests/__init__.py       |  2 ++
 tests/test_backend.py   | 77 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/test_ebuild.py    |  7 +++--
 5 files changed, 155 insertions(+), 5 deletions(-)

diff --git a/g_sorcery/backend.py b/g_sorcery/backend.py
index 0fb194d..476a8a4 100644
--- a/g_sorcery/backend.py
+++ b/g_sorcery/backend.py
@@ -11,6 +11,62 @@
     :license: GPL-2, see LICENSE for more details.
 """
 
+import glob, os
+
 class Backend:
-    def __init__(self):
+    def __init__(self, PackageDB, EbuildGenrator, directory,
+                 repo_uri="", db_uri="", sync_db=True, eclass_dir=""):
+        self.sync_db = sync_db
+        self.repo_uri = repo_uri
+        self.db_uri = db_uri
+        self.eclass_dir = eclass_dir
+
+        self.directory = directory
+        self.backend_data_dir = os.path.join(directory, '.backend_data')
+        os.makedirs(self.backend_data_dir)
+        self.db = PackageDB(os.path.join(self.backend_data_dir, 'db'),
+                            repo_uri = self.repo_uri,
+                            db_uri = self.db_uri)
+
+        self.repo_uri = self.db.repo_uri
+        self.db_uri = self.db.db_uri
+
+        self.eg = EbuildGenrator(self.db)
+
+    def sync(self):
+        if self.sync_db and not self.db_uri:
+            Exception("No uri for syncing provided.")
+        if not self.sync_db and not self.repo_uri:
+            Exception("No repo uri provided.")
+        if self.sync_db:
+            self.db.sync()
+        else:
+            self.db.generate()
+
+    def list_ebuilds(self):
+        return self.db.list_all_packages()
+
+    def generate_ebuild(self, package):
+        return self.eg.generate(package)
+
+    def list_eclasses(self):
+        result = []
+        if self.eclass_dir:
+            for f_name in glob.iglob(os.path.join(self.eclass_dir, '*.eclass')):
+                result.append(os.path.basename(f_name)[:-7])
+        return result
+
+    def generate_eclass(self, eclass):
+        if not self.eclass_dir:
+            Exception('No eclass dir')
+        f_name = os.path.join(self.eclass_dir, eclass + '.eclass')
+        if not os.path.isfile(f_name):
+            Exception('No eclass ' + eclass)
+        with open(f_name, 'r') as f:
+            eclass = f.read().split('\n')
+            if eclass[-1] == '':
+                eclass = eclass[:-1]
+        return eclass
+
+    def generate_metadata(self, category, name):
         pass

diff --git a/g_sorcery/package_db.py b/g_sorcery/package_db.py
index 48101a2..a85a704 100644
--- a/g_sorcery/package_db.py
+++ b/g_sorcery/package_db.py
@@ -86,9 +86,13 @@ class PackageDB:
         uri_f = FileJSON(self.directory, self.URI_NAME, ['repo_uri', 'db_uri'])
         uri = uri_f.read()
         if not repo_uri:
-                self.repo_uri = uri['repo_uri']
+            self.repo_uri = uri['repo_uri']
+        else:
+            self.repo_uri = repo_uri
         if not db_uri:
-                self.db_uri = uri['db_uri']
+            self.db_uri = uri['db_uri']
+        else:
+            self.db_uri = db_uri
         uri['repo_uri'] = self.repo_uri
         uri['db_uri'] = self.db_uri
         uri_f.write(uri)
@@ -321,6 +325,14 @@ class PackageDB:
             raise Exception('No such package: ' + name)
         return list(self.db['packages'][category][name])
 
+    def list_all_packages(self):
+        result = []
+        for category in self.db['packages']:
+            for name in self.db['packages'][category]:
+                for version in self.db['packages'][category][name]:
+                    result.append(Package(category, name, version))
+        return result
+
     def get_package_description(self, package):
         #a possible exception should be catched in the caller
         return self.db['packages'][package.category][package.name][package.version]

diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..faa18be
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,2 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-

diff --git a/tests/test_backend.py b/tests/test_backend.py
new file mode 100644
index 0000000..027f4a8
--- /dev/null
+++ b/tests/test_backend.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+    test_backend.py
+    ~~~~~~~~~~~~~~~
+    
+    backend test suite
+    
+    :copyright: (c) 2013 by Jauhien Piatlicki
+    :license: GPL-2, see LICENSE for more details.
+"""
+
+import os, tempfile, unittest
+
+from g_sorcery import backend, ebuild, package_db
+
+from tests import test_ebuild
+
+class DummyBackend(backend.Backend):
+    def __init__(self, PackageDB, EbuildGenrator, directory,
+                 sync_db=True, eclass_dir=""):
+        super().__init__(PackageDB, EbuildGenrator, directory,
+                         sync_db=sync_db, eclass_dir=eclass_dir)
+
+
+class TestBackend(unittest.TestCase):
+    
+    def setUp(self):
+        self.tempdir = tempfile.TemporaryDirectory()
+
+    def tearDown(self):
+        del self.tempdir
+
+    def test_list_eclasses(self):
+        backend = DummyBackend(package_db.PackageDB, ebuild.EbuildGenerator,
+                               self.tempdir.name, eclass_dir = self.tempdir.name)
+        self.assertEqual(backend.list_eclasses(), [])
+        lst = ['test', 'supertest', 'anothertest']
+        for f_name in lst:
+            with open(os.path.join(self.tempdir.name, f_name + '.eclass'), 'w') as f:
+                f.write("test")
+        self.assertEqual(set(backend.list_eclasses()), set(lst))
+
+    def test_generate_eclass(self):
+        backend = DummyBackend(package_db.PackageDB, ebuild.EbuildGenerator,
+                               self.tempdir.name, eclass_dir = self.tempdir.name)
+        eclass = ["testing eclass", "nothing interesting here"]
+        eclass_name = "test"
+        with open(os.path.join(self.tempdir.name, eclass_name + '.eclass'), 'w') as f:
+            for line in eclass:
+                f.write(line + '\n')
+        g_eclass = backend.generate_eclass(eclass_name)
+        self.assertEqual(eclass, g_eclass)
+
+    def test_list_ebuilds(self):
+        backend = DummyBackend(test_ebuild.DummyDB, test_ebuild.DummyEbuildGenerator,
+                               self.tempdir.name, eclass_dir = self.tempdir.name, sync_db = False)
+        backend.sync()
+        ebuilds = backend.list_ebuilds()
+        self.assertEqual(set(ebuilds), set([test_ebuild.package, test_ebuild.package2]))
+
+    def test_generate_ebuild(self):
+        backend = DummyBackend(test_ebuild.DummyDB, test_ebuild.DummyEbuildGenerator,
+                               self.tempdir.name, eclass_dir = self.tempdir.name, sync_db = False)
+        backend.sync()
+        ebuild = backend.generate_ebuild(test_ebuild.package)
+        self.assertEqual(ebuild, ['test', 'author: jauhien',
+                                  'homepage: 127.0.0.1', 'var: $var'])
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(TestBackend('test_list_eclasses'))
+    suite.addTest(TestBackend('test_generate_eclass'))
+    suite.addTest(TestBackend('test_list_ebuilds'))
+    suite.addTest(TestBackend('test_generate_ebuild'))
+    return suite

diff --git a/tests/test_ebuild.py b/tests/test_ebuild.py
index 03b5d37..52c34f5 100644
--- a/tests/test_ebuild.py
+++ b/tests/test_ebuild.py
@@ -16,15 +16,18 @@ import os, tempfile, unittest
 from g_sorcery import ebuild, package_db
 
 package = package_db.Package("app-test", "test", "0.1")
+package2 = package_db.Package("app-test", "tst", "1")
 
 class DummyDB(package_db.PackageDB):
-    def __init__(self, directory):
-        super().__init__(directory)
+    def __init__(self, directory, repo_uri="", db_uri=""):
+        super().__init__(directory, repo_uri, db_uri)
 
     def generate_tree(self):
         self.add_category("app-test")
         self.add_package(package,
                          {"author" : "jauhien", "homepage" : "127.0.0.1"})
+        self.add_package(package2,
+                         {"author" : "unknown", "homepage" : "example.com"})
 
 
 class DummyEbuildGenerator(ebuild.EbuildGenerator):


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-23  0:44 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-23  0:44 UTC (permalink / raw
  To: gentoo-commits

commit:     d86e2f7db9b29f2fb38f3d6db223bc4dfaea9e3c
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Sun Jun 23 00:44:55 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Sun Jun 23 00:44:55 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=d86e2f7d

g_sorcery/ebuild: EbuildGeneratorFromFile

---
 g_sorcery/ebuild.py  | 15 +++++++++++++++
 tests/test_ebuild.py | 37 ++++++++++++++++++++++++++++++++++---
 2 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/g_sorcery/ebuild.py b/g_sorcery/ebuild.py
index 88e9acd..ea27afe 100644
--- a/g_sorcery/ebuild.py
+++ b/g_sorcery/ebuild.py
@@ -38,3 +38,18 @@ class EbuildGenerator:
         
     def postprocess(self, ebuild, description):
         return ebuild
+
+class EbuildGeneratorFromFile(EbuildGenerator):
+    def __init__(self, db):
+        super().__init__(db)
+
+    def get_template(self, package, description):
+        name = self.get_template_file(package, description)
+        with open(name, 'r') as f:
+            ebuild = f.read().split('\n')
+            if ebuild[-1] == '':
+                ebuild = ebuild[:-1]
+        return ebuild
+
+    def get_template_file(self, package, description):
+        return ""

diff --git a/tests/test_ebuild.py b/tests/test_ebuild.py
index 029e2df..03b5d37 100644
--- a/tests/test_ebuild.py
+++ b/tests/test_ebuild.py
@@ -11,7 +11,7 @@
     :license: GPL-2, see LICENSE for more details.
 """
 
-import tempfile, unittest
+import os, tempfile, unittest
 
 from g_sorcery import ebuild, package_db
 
@@ -37,11 +37,9 @@ class TestEbuildGenerator(unittest.TestCase):
     
     def setUp(self):
         self.tempdir = tempfile.TemporaryDirectory()
-        pass
 
     def tearDown(self):
         del self.tempdir
-        pass
 
     def test_process(self):
         eg = DummyEbuildGenerator(None)
@@ -58,9 +56,42 @@ class TestEbuildGenerator(unittest.TestCase):
         self.assertEqual(ebuild, ['test', 'author: jauhien',
                                   'homepage: 127.0.0.1', 'var: $var'])
 
+
+class DummyEbuildGeneratorFromFile(ebuild.EbuildGeneratorFromFile):
+    def __init__(self, db, path):
+        super().__init__(db)
+        self.path = path
+    
+    def get_template_file(self, package, description):
+        return self.path
+
+
+class TestEbuildGeneratorFromFile(unittest.TestCase):
+    
+    def setUp(self):
+        self.tempdir = tempfile.TemporaryDirectory()
+
+    def tearDown(self):
+        del self.tempdir
+
+    def test_generate(self):
+        db = DummyDB(os.path.join(self.tempdir.name, 'tstdb'))
+        db.generate()
+        tmpl = os.path.join(self.tempdir.name, 'tst.tmpl')
+        with open(tmpl, 'w') as f:
+            f.write("""test
+author: $author
+homepage: $homepage
+var: $$var""")
+        eg = DummyEbuildGeneratorFromFile(db, tmpl)
+        ebuild = eg.generate(package)
+        self.assertEqual(ebuild, ['test', 'author: jauhien',
+                                  'homepage: 127.0.0.1', 'var: $var'])
         
+    
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(TestEbuildGenerator('test_process'))
     suite.addTest(TestEbuildGenerator('test_generate'))
+    suite.addTest(TestEbuildGeneratorFromFile('test_generate'))
     return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-23  0:44 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-23  0:44 UTC (permalink / raw
  To: gentoo-commits

commit:     404e62bfbc2b579260a5bbc6a98af112a9237246
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Sat Jun 22 22:22:31 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Sat Jun 22 22:22:31 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=404e62bf

g_sorcery/package_db: sync

---
 g_sorcery/package_db.py  | 55 ++++++++++++++++++++++++++++++++++++++----------
 tests/test_package_db.py | 40 ++++++++++++++++++++++++++++++++++-
 2 files changed, 83 insertions(+), 12 deletions(-)

diff --git a/g_sorcery/package_db.py b/g_sorcery/package_db.py
index 9c477f7..b97a688 100644
--- a/g_sorcery/package_db.py
+++ b/g_sorcery/package_db.py
@@ -11,7 +11,7 @@
     :license: GPL-2, see LICENSE for more details.
 """
 
-import collections, hashlib, json, os, shutil
+import collections, glob, hashlib, json, os, shutil, tarfile, tempfile
 
 Package = collections.namedtuple("Package", "category name version")
 
@@ -61,7 +61,15 @@ def hash_file(name, hasher, blocksize=65536):
             hasher.update(buf)
             buf = f.read(blocksize)
     return hasher.hexdigest()
-    
+
+def copy_all(src, dst):
+    for f_name in os.listdir(src):
+        src_name = os.path.join(src, f_name)
+        dst_name = os.path.join(dst, f_name)
+        if os.path.isdir(src_name):
+            shutil.copytree(src_name, dst_name)
+        else:
+            shutil.copy2(src_name, dst_name)
 
 class PackageDB:
     def __init__(self, directory, repo_uri="", db_uri=""):
@@ -112,18 +120,43 @@ class PackageDB:
         """
         pass
 
-    def sync(self, repo_uri="", db_uri=""):
-        if repo_uri:
-            self.repo_uri = repo_uri
+    def sync(self, db_uri=""):
         if db_uri:
             self.db_uri = db_uri
         self.clean()
         real_db_uri = self.get_real_db_uri()
-        """
-        TODO
-        code that downloads tarball from the real_db_uri
-        and unpacks it
-        """
+        download_dir = tempfile.TemporaryDirectory()
+        if os.system('wget -P ' + download_dir.name + ' ' + real_db_uri):
+            raise Exception('sync failed: ' + real_db_uri)
+        
+        temp_dir = tempfile.TemporaryDirectory()
+        for f_name in glob.iglob(os.path.join(download_dir.name, '*.tar.gz')):
+            with tarfile.open(f_name) as f:
+                f.extractall(temp_dir.name)
+
+        tempdb_dir = tempfile.TemporaryDirectory()
+        tempdb = PackageDB(tempdb_dir.name)
+
+        for d_name in os.listdir(temp_dir.name):
+            current_dir = os.path.join(temp_dir.name, d_name)
+            if not os.path.isdir(current_dir):
+                continue
+            copy_all(current_dir, tempdb_dir.name)
+
+        if not tempdb.check_manifest():
+            raise Exception('Manifest check failed.')
+
+        self.clean()
+        copy_all(tempdb_dir.name, self.directory)
+        
+        if not self.check_manifest():
+            raise Exception('Manifest check failed, db inconsistent.')
+                
+        del download_dir
+        del temp_dir
+        del tempdb_dir
+        
+        self.read()
 
     def get_real_db_uri():
         return self.db_uri
@@ -157,7 +190,7 @@ class PackageDB:
         names = [self.INFO_NAME, self.CATEGORIES_NAME, self.URI_NAME]
         for name in names:
             if not name in manifest:
-                raise RunTimeError('Bad manifest: no ' + name + ' entry')
+                raise Exception('Bad manifest: no ' + name + ' entry')
 
         for name, value in manifest.items():
             if hash_file(os.path.join(self.directory, name), hashlib.md5()) != \

diff --git a/tests/test_package_db.py b/tests/test_package_db.py
index 9fc0267..62b073f 100644
--- a/tests/test_package_db.py
+++ b/tests/test_package_db.py
@@ -11,10 +11,25 @@
     :license: GPL-2, see LICENSE for more details.
 """
 
-import json, os, tempfile, unittest
+import json, http.server, os, shutil, tempfile, threading, \
+  unittest
 
 from g_sorcery import package_db
 
+
+class Server(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        server_address = ('127.0.0.1', 8080)
+        self.httpd = http.server.HTTPServer(server_address, http.server.SimpleHTTPRequestHandler)
+    
+    def run(self):
+        self.httpd.serve_forever()
+
+    def shutdown(self):
+        self.httpd.shutdown()
+
+
 class TestFileJSON(unittest.TestCase):
     
     def setUp(self):
@@ -118,6 +133,10 @@ class DummyDB(package_db.PackageDB):
         for package in self.packages:
             self.add_package(package)
 
+    def get_real_db_uri(self):
+        print(self.db_uri)
+        return self.db_uri + '/dummy.tar.gz'
+
 
 class TestDummyDB(unittest.TestCase):
     
@@ -174,6 +193,24 @@ class TestDummyDB(unittest.TestCase):
         self.assertRaises(Exception, db.list_package_names, 'no_such_category', 'a')
         self.assertRaises(Exception, db.list_package_names, categories[0], 'no_such_package')
 
+    def test_sync(self):
+        src_db = DummyDB(os.path.join(self.tempdir.name, 'src_testdb'), self.packages)
+        src_db.generate()
+
+        os.chdir(self.tempdir.name)
+        os.system('tar cvzf dummy.tar.gz src_testdb')
+        
+        server = Server()
+        server.start()
+
+        db = DummyDB(os.path.join(self.tempdir.name, 'testdb'), self.packages)
+        db.sync(db_uri='127.0.0.1:8080')
+        
+        server.shutdown()
+        server.join()
+
+        self.assertEqual(src_db.db, db.db)
+
             
 def suite():
     suite = unittest.TestSuite()
@@ -190,4 +227,5 @@ def suite():
     suite.addTest(TestDummyDB('test_list_categories'))
     suite.addTest(TestDummyDB('test_list_package_names'))
     suite.addTest(TestDummyDB('test_list_package_versions'))
+    suite.addTest(TestDummyDB('test_sync'))
     return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-23  0:44 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-23  0:44 UTC (permalink / raw
  To: gentoo-commits

commit:     a8ec7786e12dab514996b60b4b79f1f57dc58a66
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Sun Jun 23 00:22:27 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Sun Jun 23 00:22:27 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=a8ec7786

g_sorcery/ebuild: EbuildGenerator

---
 g_sorcery/ebuild.py  | 28 ++++++++++++++++++++++
 tests/test_ebuild.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 94 insertions(+)

diff --git a/g_sorcery/ebuild.py b/g_sorcery/ebuild.py
index 47c727a..88e9acd 100644
--- a/g_sorcery/ebuild.py
+++ b/g_sorcery/ebuild.py
@@ -10,3 +10,31 @@
     :copyright: (c) 2013 by Jauhien Piatlicki
     :license: GPL-2, see LICENSE for more details.
 """
+
+import string
+
+class EbuildGenerator:
+    def __init__(self, db):
+        self.db = db
+
+    def generate(self, package):
+        #a possible exception should be catched in the caller
+        description = self.db.get_package_description(package)
+        ebuild = self.get_template(package, description)
+        ebuild = self.process(ebuild, description)
+        ebuild = self.postprocess(ebuild, description)
+        return ebuild
+
+    def process(self, ebuild, description):
+        result = []
+        for line in ebuild:
+            tmpl = string.Template(line)
+            result.append(tmpl.substitute(description))
+        return result
+        
+    def get_template(self, package, description):
+        ebuild = []
+        return ebuild
+        
+    def postprocess(self, ebuild, description):
+        return ebuild

diff --git a/tests/test_ebuild.py b/tests/test_ebuild.py
new file mode 100644
index 0000000..029e2df
--- /dev/null
+++ b/tests/test_ebuild.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+    test_ebuild.py
+    ~~~~~~~~~~~~~~~~~~
+    
+    ebuild generator test suite
+    
+    :copyright: (c) 2013 by Jauhien Piatlicki
+    :license: GPL-2, see LICENSE for more details.
+"""
+
+import tempfile, unittest
+
+from g_sorcery import ebuild, package_db
+
+package = package_db.Package("app-test", "test", "0.1")
+
+class DummyDB(package_db.PackageDB):
+    def __init__(self, directory):
+        super().__init__(directory)
+
+    def generate_tree(self):
+        self.add_category("app-test")
+        self.add_package(package,
+                         {"author" : "jauhien", "homepage" : "127.0.0.1"})
+
+
+class DummyEbuildGenerator(ebuild.EbuildGenerator):
+    def get_template(self, ebuild, description):
+        tmpl = ["test", "author: $author", "homepage: $homepage", "var: $$var"]
+        return tmpl
+
+
+class TestEbuildGenerator(unittest.TestCase):
+    
+    def setUp(self):
+        self.tempdir = tempfile.TemporaryDirectory()
+        pass
+
+    def tearDown(self):
+        del self.tempdir
+        pass
+
+    def test_process(self):
+        eg = DummyEbuildGenerator(None)
+        tst_dict = {"a" : "d", "b" : "e", "c" : "f"}
+        ebuild = ["$a", "$b", "$c"]
+        ebuild = eg.process(ebuild, tst_dict)
+        self.assertEqual(ebuild, ["d", "e", "f"])
+
+    def test_generate(self):
+        db = DummyDB(self.tempdir.name)
+        db.generate()
+        eg = DummyEbuildGenerator(db)
+        ebuild = eg.generate(package)
+        self.assertEqual(ebuild, ['test', 'author: jauhien',
+                                  'homepage: 127.0.0.1', 'var: $var'])
+
+        
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(TestEbuildGenerator('test_process'))
+    suite.addTest(TestEbuildGenerator('test_generate'))
+    return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-20 23:21 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-20 23:21 UTC (permalink / raw
  To: gentoo-commits

commit:     707603adc020c074d473fad77bd8163bc4abdefe
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Thu Jun 20 23:07:48 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Thu Jun 20 23:07:48 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=707603ad

g_sorcery/package_db.py: list_package_names

---
 g_sorcery/package_db.py  |  5 +++++
 tests/test_package_db.py | 12 +++++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/g_sorcery/package_db.py b/g_sorcery/package_db.py
index a925af4..aae3abc 100644
--- a/g_sorcery/package_db.py
+++ b/g_sorcery/package_db.py
@@ -263,3 +263,8 @@ class PackageDB:
 
     def list_categories(self):
         return list(self.db['categories'].keys())
+
+    def list_package_names(self, category):
+        if not category in self.db['packages']:
+            raise Exception('No such category: ' + category)
+        return list(self.db['packages'][category].keys())

diff --git a/tests/test_package_db.py b/tests/test_package_db.py
index 1b3600b..9977d8c 100644
--- a/tests/test_package_db.py
+++ b/tests/test_package_db.py
@@ -152,7 +152,16 @@ class TestDummyDB(unittest.TestCase):
         db.generate()
         categories = list(set([x.category for x in self.packages]))
         self.assertEqual(categories, db.list_categories())
-                
+
+    def test_list_package_names(self):
+        db = DummyDB(self.tempdir.name, self.packages)
+        db.generate()
+        categories = list(set([x.category for x in self.packages]))
+        for category in categories:
+            package_names = list(set([x.name for x in self.packages if x.category == category]))
+            self.assertEqual(package_names, db.list_package_names(category))
+        self.assertRaises(Exception, db.list_package_names, 'no_such_category')
+
             
 def suite():
     suite = unittest.TestSuite()
@@ -167,4 +176,5 @@ def suite():
     suite.addTest(TestDummyDB('test_manifest'))
     suite.addTest(TestDummyDB('test_read'))
     suite.addTest(TestDummyDB('test_list_categories'))
+    suite.addTest(TestDummyDB('test_list_package_names'))
     return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-20 23:21 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-20 23:21 UTC (permalink / raw
  To: gentoo-commits

commit:     a6bcb6178365e66ac619d42e0a356f8498a206ea
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Thu Jun 20 23:13:18 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Thu Jun 20 23:13:18 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=a6bcb617

g_sorcery/package_db.py: list_package_versions

---
 g_sorcery/package_db.py  |  7 +++++++
 tests/test_package_db.py | 13 +++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/g_sorcery/package_db.py b/g_sorcery/package_db.py
index aae3abc..0a2bdfb 100644
--- a/g_sorcery/package_db.py
+++ b/g_sorcery/package_db.py
@@ -268,3 +268,10 @@ class PackageDB:
         if not category in self.db['packages']:
             raise Exception('No such category: ' + category)
         return list(self.db['packages'][category].keys())
+
+    def list_package_versions(self, category, name):
+        if not category in self.db['packages']:
+            raise Exception('No such category: ' + category)
+        if not name in self.db['packages'][category]:
+            raise Exception('No such package: ' + name)
+        return list(self.db['packages'][category][name])

diff --git a/tests/test_package_db.py b/tests/test_package_db.py
index 9977d8c..9fc0267 100644
--- a/tests/test_package_db.py
+++ b/tests/test_package_db.py
@@ -162,6 +162,18 @@ class TestDummyDB(unittest.TestCase):
             self.assertEqual(package_names, db.list_package_names(category))
         self.assertRaises(Exception, db.list_package_names, 'no_such_category')
 
+    def test_list_package_versions(self):
+        db = DummyDB(self.tempdir.name, self.packages)
+        db.generate()
+        categories = list(set([x.category for x in self.packages]))
+        for category in categories:
+            package_names = list(set([x.name for x in self.packages if x.category == category]))
+            for name in package_names:
+                versions = [x.version for x in self.packages if x.category == category and x.name == name]
+                self.assertEqual(versions, db.list_package_versions(category, name))
+        self.assertRaises(Exception, db.list_package_names, 'no_such_category', 'a')
+        self.assertRaises(Exception, db.list_package_names, categories[0], 'no_such_package')
+
             
 def suite():
     suite = unittest.TestSuite()
@@ -177,4 +189,5 @@ def suite():
     suite.addTest(TestDummyDB('test_read'))
     suite.addTest(TestDummyDB('test_list_categories'))
     suite.addTest(TestDummyDB('test_list_package_names'))
+    suite.addTest(TestDummyDB('test_list_package_versions'))
     return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread
* [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/
@ 2013-06-20 22:53 Jauhien Piatlicki
  0 siblings, 0 replies; 20+ messages in thread
From: Jauhien Piatlicki @ 2013-06-20 22:53 UTC (permalink / raw
  To: gentoo-commits

commit:     9707236329bf00fd198149eb73ef5bee1bc68f77
Author:     Jauhien Piatlicki (jauhien) <piatlicki <AT> gmail <DOT> com>
AuthorDate: Thu Jun 20 22:53:59 2013 +0000
Commit:     Jauhien Piatlicki <piatlicki <AT> gmail <DOT> com>
CommitDate: Thu Jun 20 22:53:59 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/g-sorcery.git;a=commit;h=97072363

g_sorcery/package_db.py: initial commit

---
 g_sorcery/package_db.py  | 265 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/test_package_db.py | 170 ++++++++++++++++++++++++++++++
 2 files changed, 435 insertions(+)

diff --git a/g_sorcery/package_db.py b/g_sorcery/package_db.py
new file mode 100644
index 0000000..a925af4
--- /dev/null
+++ b/g_sorcery/package_db.py
@@ -0,0 +1,265 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+    package_db.py
+    ~~~~~~~~~~~~~
+    
+    package database
+    
+    :copyright: (c) 2013 by Jauhien Piatlicki
+    :license: GPL-2, see LICENSE for more details.
+"""
+
+import collections, hashlib, json, os, shutil
+
+Package = collections.namedtuple("Package", "category name version")
+
+class FileJSON:
+    def __init__(self, directory, name, mandatories):
+        """
+        Initialize
+
+        mandatories -- list of mandatory keys
+        """
+        self.directory = os.path.abspath(directory)
+        self.name = name
+        self.path = os.path.join(directory, name)
+        self.mandatories = mandatories
+
+    def read(self):
+        if not os.path.exists(self.directory):
+            os.makedirs(self.directory)
+        content = {}
+        if not os.path.isfile(self.path):
+            for key in self.mandatories:
+                content[key] = ""
+            with open(self.path, 'w') as f:
+                json.dump(content, f, indent=2, sort_keys=True)
+        else:
+            with open(self.path, 'r') as f:
+                content = json.load(f)
+            for key in self.mandatories:
+                if not key in content:
+                    raise KeyError
+        return content
+
+    def write(self, content):
+        for key in self.mandatories:
+            if not key in content:
+                raise KeyError
+        if not os.path.exists(self.directory):
+            os.makedirs(self.directory)
+        with open(self.path, 'w') as f:
+            json.dump(content, f, indent=2, sort_keys=True)
+
+
+def hash_file(name, hasher, blocksize=65536):
+    with open(name, 'rb') as f:
+        buf = f.read(blocksize)
+        while len(buf) > 0:
+            hasher.update(buf)
+            buf = f.read(blocksize)
+    return hasher.hexdigest()
+    
+
+class PackageDB:
+    def __init__(self, directory, repo_uri="", db_uri=""):
+        self.URI_NAME = 'uri.json'
+        self.INFO_NAME = 'info.json'
+        self.CATEGORIES_NAME = 'categories.json'
+        self.PACKAGES_NAME = 'packages.json'
+        self.VERSIONS_NAME = 'versions.json'
+        self.directory = os.path.abspath(directory)
+        self.reset_uri(repo_uri, db_uri)
+        self.reset_db()
+
+    def reset_uri(self, repo_uri="", db_uri=""):
+        uri_f = FileJSON(self.directory, self.URI_NAME, ['repo_uri', 'db_uri'])
+        uri = uri_f.read()
+        if not repo_uri:
+                self.repo_uri = uri['repo_uri']
+        if not db_uri:
+                self.db_uri = uri['db_uri']
+        uri['repo_uri'] = self.repo_uri
+        uri['db_uri'] = self.db_uri
+        uri_f.write(uri)
+
+    def reset_db(self):
+        self.db = {}
+        self.db['info'] = {}
+        self.db['categories'] = {}
+        self.db['packages'] = {}
+
+    def generate(self, repo_uri=""):
+        """
+        Generates a new package database
+
+        repo_uri -- repository uri
+        """
+        if repo_uri:
+            self.repo_uri = repo_uri
+        self.clean()
+        self.generate_tree()
+        self.write()
+        self.manifest()
+
+    def generate_tree(self):
+        """
+        Generate tree with JSON files containing info
+        about packages in a repository
+
+        Should be implemented in a subclass
+
+        repo_uri -- repository uri
+        if repo_uri is an empty string should use self.repo_uri
+        """
+        pass
+
+    def manifest(self):
+        categories = FileJSON(self.directory, self.CATEGORIES_NAME, [])
+        categories = categories.read()
+        manifest = {}
+        names = [self.INFO_NAME, self.CATEGORIES_NAME, self.URI_NAME]
+        for name in names:
+            manifest[name] = hash_file(os.path.join(self.directory, name),
+                                      hashlib.md5())
+        for category in categories:
+            category_path = os.path.join(self.directory, category)
+            if not os.path.isdir(category_path):
+                raise Exception('Empty category: ' + category)
+            for root, dirs, files in os.walk(category_path):
+                for f in files:
+                    manifest[os.path.join(root[len(self.directory)+1:], f)] = \
+                    hash_file(os.path.join(root, f), hashlib.md5())
+        m = FileJSON(self.directory, 'manifest.json', [])
+        m.write(manifest)
+
+    def check_manifest(self):
+        m = FileJSON(self.directory, 'manifest.json', [])
+        manifest = m.read()
+        
+        result = True
+        errors = []
+        
+        names = [self.INFO_NAME, self.CATEGORIES_NAME, self.URI_NAME]
+        for name in names:
+            if not name in manifest:
+                raise RunTimeError('Bad manifest: no ' + name + ' entry')
+
+        for name, value in manifest.items():
+            if hash_file(os.path.join(self.directory, name), hashlib.md5()) != \
+                value:
+                result = False
+                errors.append(name)
+
+        return (result, errors)
+
+    def clean(self):
+        shutil.rmtree(self.directory)
+        self.reset_uri(self.repo_uri, self.db_uri)
+        self.reset_db()
+
+    def write(self):
+        info_f = FileJSON(self.directory, self.INFO_NAME, [])
+        categories_f = FileJSON(self.directory, self.CATEGORIES_NAME, [])
+        info_f.write(self.db['info'])
+        categories_f.write(self.db['categories'])
+        for category in self.db['categories']:
+            if not category in self.db['packages']:
+                raise Exception('Empty category: ' + category)
+            for package, versions in self.db['packages'][category].items():
+                for version, content in versions.items():
+                    f = FileJSON(os.path.join(self.directory, category, package),
+                                 version + '.json', [])
+                    f.write(content)
+                    self.additional_write_version(category, package, version)
+                f = FileJSON(os.path.join(self.directory, category, package),
+                                     self.VERSIONS_NAME, [])
+                f.write(list(versions.keys()))
+                self.additional_write_package(category, package)
+            f = FileJSON(os.path.join(self.directory, category),
+                                     self.PACKAGES_NAME, [])
+            f.write(list(self.db['packages'][category].keys()))
+            self.additional_write_category(category)
+        self.additional_write()
+
+    def additional_write_version(self, category, package, version):
+        pass
+
+    def additional_write_package(self, category, package):
+        pass
+
+    def additional_write_category(self, category):
+        pass
+
+    def additional_write(self):
+        pass
+
+    def read(self):
+        sane, errors = self.check_manifest()
+        if not sane:
+            raise Exception('Manifest error: ' + str(errors))
+        info_f = FileJSON(self.directory, self.INFO_NAME, [])
+        categories_f = FileJSON(self.directory, self.CATEGORIES_NAME, [])
+        self.db['info'] = info_f.read()
+        self.db['categories'] = categories_f.read()
+        for category in self.db['categories']:
+            category_path = os.path.join(self.directory, category)
+            if not os.path.isdir(category_path):
+                raise Exception('Empty category: ' + category)
+            
+            f = FileJSON(category_path, self.PACKAGES_NAME, [])
+            packages = f.read()
+            if not packages:
+                raise Exception('Empty category: ' + category)
+            
+            self.db['packages'][category] = {}
+            for name in packages:
+                package_path = os.path.join(category_path, name)
+                if not os.path.isdir(category_path):
+                    raise Exception('Empty package: ' + category + '/' + name)
+                
+                f = FileJSON(package_path, self.VERSIONS_NAME, [])
+                versions = f.read()
+                if not versions:
+                    raise Exception('Empty package: ' + category + '/' + name)
+                
+                self.db['packages'][category][name] = {}
+                for version in versions:
+                    f = FileJSON(package_path, version + '.json', [])
+                    description = f.read()
+                    self.db['packages'][category][name][version] = description
+                    self.additional_read_version(category, name, version)
+                self.additional_read_package(category, name)
+            self.additional_read_category(category)
+        self.additional_read()
+
+    def additional_read_version(self, category, package, version):
+        pass
+
+    def additional_read_package(self, category, package):
+        pass
+
+    def additional_read_category(self, category):
+        pass
+
+    def additional_read(self):
+        pass
+        
+    def add_category(self, category, description={}):
+        self.db['categories'][category] = description;
+        self.db['packages'][category] = {}
+
+    def add_package(self, package, description={}):
+        category = package.category
+        name = package.name
+        version = package.version
+        if not category in self.db['packages']:
+            raise Exception('Non-existent category: ' + category)
+        if not name in self.db['packages'][category]:
+            self.db['packages'][category][name] = {}
+        self.db['packages'][category][name][version] = description
+
+    def list_categories(self):
+        return list(self.db['categories'].keys())

diff --git a/tests/test_package_db.py b/tests/test_package_db.py
new file mode 100644
index 0000000..1b3600b
--- /dev/null
+++ b/tests/test_package_db.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+    test_package_db.py
+    ~~~~~~~~~~~~~~~~~~
+    
+    package database test suite
+    
+    :copyright: (c) 2013 by Jauhien Piatlicki
+    :license: GPL-2, see LICENSE for more details.
+"""
+
+import json, os, tempfile, unittest
+
+from g_sorcery import package_db
+
+class TestFileJSON(unittest.TestCase):
+    
+    def setUp(self):
+        self.tempdir = tempfile.TemporaryDirectory()
+        self.path = os.path.join(self.tempdir.name, 'tst')
+        self.name = 'tst.json'
+
+    def tearDown(self):
+        del self.tempdir
+
+    def do_test_read_ok(self, mandatories, value_suffix=""):
+        f = package_db.FileJSON(self.path, self.name, mandatories)
+        content = f.read()
+        for key in mandatories:
+            self.assertTrue(key in content)
+            if value_suffix:
+                value = key + value_suffix
+            else:
+                value = ""
+            self.assertEqual(content[key], value)
+        self.assertTrue(os.path.isfile(os.path.join(self.path, self.name)))
+        with open(os.path.join(self.path, self.name), 'r') as f:
+            content_f = json.load(f)
+        self.assertEqual(content, content_f)
+        
+    def test_read_dir_does_not_exist(self):
+        mandatories = ['tst1', 'tst2', 'tst3']
+        self.do_test_read_ok(mandatories)
+
+    def test_read_file_does_not_exist(self):
+        os.makedirs(self.path)
+        mandatories = ['tst1', 'tst2', 'tst3']
+        self.do_test_read_ok(mandatories)
+
+    def test_read_all_keys(self):
+        os.makedirs(self.path)
+        mandatories = ['tst1', 'tst2', 'tst3']
+        content = {}
+        for key in mandatories:
+            content[key] = key + "_v"
+        with open(os.path.join(self.path, self.name), 'w') as f:
+            json.dump(content, f)
+        self.do_test_read_ok(mandatories, "_v")
+
+    def test_read_missing_keys(self):
+        os.makedirs(self.path)
+        mandatories = ['tst1', 'tst2', 'tst3']
+        content = {}
+        for key in mandatories:
+            content[key] = key + "_v"
+        with open(os.path.join(self.path, self.name), 'w') as f:
+            json.dump(content, f)
+        f = package_db.FileJSON(self.path, self.name, mandatories)
+        mandatories.append("tst4")
+        self.assertRaises(KeyError, f.read)
+
+    def do_test_write_ok(self):
+        mandatories = ['tst1', 'tst2', 'tst3']
+        content = {}
+        for key in mandatories:
+            content[key] = key + '_v'
+        f = package_db.FileJSON(self.path, self.name, mandatories)
+        f.write(content)
+        self.assertTrue(os.path.isfile(os.path.join(self.path, self.name)))
+        with open(os.path.join(self.path, self.name), 'r') as f:
+            content_f = json.load(f)
+        self.assertEqual(content, content_f)
+
+    def test_write_missing_keys(self):
+        content = {'tst1' : '', 'tst2' : ''}
+        mandatories = ['tst1', 'tst2', 'tst3']
+        f = package_db.FileJSON(self.path, self.name, mandatories)
+        self.assertRaises(KeyError, f.write, content)
+
+    def test_write_dir_does_not_exist(self):
+        self.do_test_write_ok()
+
+    def test_write_file_does_not_exist(self):
+        os.makedirs(self.path)
+        self.do_test_write_ok()
+
+    def test_write_all_keys(self):
+        os.makedirs(self.path)
+        mandatories = ['tst11', 'tst12']
+        content = {}
+        for key in mandatories:
+            content[key] = key + "_v"
+        with open(os.path.join(self.path, self.name), 'w') as f:
+            json.dump(content, f)
+        self.do_test_write_ok()
+
+
+class DummyDB(package_db.PackageDB):
+    def __init__(self, directory, packages):
+        super().__init__(directory)
+        self.packages = packages
+
+    def generate_tree(self):
+        for category in [x.category for x in self.packages]:
+            self.add_category(category)
+        for package in self.packages:
+            self.add_package(package)
+
+
+class TestDummyDB(unittest.TestCase):
+    
+    def setUp(self):
+        self.tempdir = tempfile.TemporaryDirectory()
+        category1 = 'app-test'
+        category2 = 'dev-test'
+        self.packages = [package_db.Package(category1, 'test', '0.2'),
+            package_db.Package(category1, 'tst', '0.1'),
+            package_db.Package(category1, 'dummy', '1'),
+            package_db.Package(category2, 'test', '0.1'),
+            package_db.Package(category2, 'test', '0.2'),
+            package_db.Package(category2, 'tst', '0.1')]
+
+    def tearDown(self):
+        del self.tempdir
+
+    def test_manifest(self):
+        db = DummyDB(self.tempdir.name, self.packages)
+        db.generate()
+        self.assertEqual(db.check_manifest(), (True, []))
+
+    def test_read(self):
+        db = DummyDB(self.tempdir.name, self.packages)
+        db.generate()
+        db2 = DummyDB(self.tempdir.name, self.packages)
+        db2.read()
+        self.assertEqual(db.db, db2.db)
+
+    def test_list_categories(self):
+        db = DummyDB(self.tempdir.name, self.packages)
+        db.generate()
+        categories = list(set([x.category for x in self.packages]))
+        self.assertEqual(categories, db.list_categories())
+                
+            
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(TestFileJSON('test_read_dir_does_not_exist'))
+    suite.addTest(TestFileJSON('test_read_file_does_not_exist'))
+    suite.addTest(TestFileJSON('test_read_all_keys'))
+    suite.addTest(TestFileJSON('test_read_missing_keys'))
+    suite.addTest(TestFileJSON('test_write_missing_keys'))
+    suite.addTest(TestFileJSON('test_write_dir_does_not_exist'))
+    suite.addTest(TestFileJSON('test_write_file_does_not_exist'))
+    suite.addTest(TestFileJSON('test_write_all_keys'))
+    suite.addTest(TestDummyDB('test_manifest'))
+    suite.addTest(TestDummyDB('test_read'))
+    suite.addTest(TestDummyDB('test_list_categories'))
+    return suite


^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2015-04-22  7:35 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-01 20:51 [gentoo-commits] proj/g-sorcery:master commit in: g_sorcery/, tests/ Jauhien Piatlicki
  -- strict thread matches above, loose matches on Subject: below --
2015-04-22  7:35 Jauhien Piatlicki
2013-07-04 20:24 Jauhien Piatlicki
2013-07-03 22:54 Jauhien Piatlicki
2013-07-02 14:48 Jauhien Piatlicki
2013-07-02 12:25 Jauhien Piatlicki
2013-07-01 20:51 Jauhien Piatlicki
2013-07-01  0:05 Jauhien Piatlicki
2013-06-30 23:29 Jauhien Piatlicki
2013-06-30 23:29 Jauhien Piatlicki
2013-06-30 23:29 Jauhien Piatlicki
2013-06-30 19:55 Jauhien Piatlicki
2013-06-29 12:13 Jauhien Piatlicki
2013-06-23 21:39 Jauhien Piatlicki
2013-06-23  0:44 Jauhien Piatlicki
2013-06-23  0:44 Jauhien Piatlicki
2013-06-23  0:44 Jauhien Piatlicki
2013-06-20 23:21 Jauhien Piatlicki
2013-06-20 23:21 Jauhien Piatlicki
2013-06-20 22:53 Jauhien Piatlicki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox