commit 4c163f9e788ab323537df60336f54a471b68636e
parent a8a6074d4bcda4435b6457e1e57b0816c9135ae1
Author: lash <dev@holbrook.no>
Date: Mon, 7 Nov 2022 00:26:37 +0000
Proper handle alias in persistent tag store
Diffstat:
7 files changed, 79 insertions(+), 18 deletions(-)
diff --git a/piknik/basket.py b/piknik/basket.py
@@ -1,5 +1,7 @@
+# external imports
import shep
+# local imports
from .error import DeadIssue
from .issue import Issue
@@ -16,12 +18,11 @@ class Basket:
self.state.add('blocked')
self.state.alias('doingblocked', self.state.DOING | self.state.BLOCKED)
self.state.alias('pendingblocked', self.state.PENDING | self.state.BLOCKED)
-
self.limit = self.state.FINISHED
-
self.state.sync()
- self.tags = state_factory.create_tags()
+ self.__tags = state_factory.create_tags()
+ self.__tags.sync(ignore_auto=False)
self.issues_rev = {}
@@ -95,14 +96,33 @@ class Basket:
def tag(self, issue_id, tag):
v = 0
try:
- v = self.tags.from_name(tag)
+ v = self.__tags.from_name(tag)
except AttributeError:
- self.tags.add(tag)
- v = self.tags.from_name(tag)
-
+ self.__tags.add(tag)
+ v = self.__tags.from_name(tag)
+
+ move = False
try:
- self.tags.put(issue_id)
- except shep.error.StateItemExists:
- pass
+ r = self.__tags.state(issue_id)
+ if r == 0:
+ move = True
+ except shep.error.StateItemNotFound:
+ self.__tags.put(issue_id)
+ move = True
+
+ if move:
+ self.__tags.move(issue_id, v)
+ else:
+ self.__tags.set(issue_id, v)
+
+
+
+ def untag(self, issue_id, tag):
+ v = self.__tags.from_name(tag)
+ self.__tags.unset(issue_id, v, allow_base=True)
+
- self.tags.set(issue_id, v)
+ def tags(self, issue_id):
+ v = self.__tags.state(issue_id)
+ r = self.__tags.elements(v)
+ return shep.state.split_elements(r)
diff --git a/piknik/runnable/add.py b/piknik/runnable/add.py
@@ -12,7 +12,7 @@ argp.add_argument('title', type=str, nargs='*', help='issue title')
arg = argp.parse_args(sys.argv[1:])
store_factory = FileStoreFactory(arg.d)
-basket = Basket(store_factory.create)
+basket = Basket(store_factory)
def main():
diff --git a/piknik/runnable/list.py b/piknik/runnable/list.py
@@ -13,7 +13,7 @@ argp.add_argument('-r', '--renderer', type=str, default='ini', help='Renderer mo
arg = argp.parse_args(sys.argv[1:])
store_factory = FileStoreFactory(arg.d)
-basket = Basket(store_factory.create)
+basket = Basket(store_factory)
def render_ini(b, r):
diff --git a/piknik/runnable/mod.py b/piknik/runnable/mod.py
@@ -12,11 +12,13 @@ argp.add_argument('--block', action='store_true', help='Set issue as blocked')
argp.add_argument('--unblock', action='store_true', help='Set issue as unblocked')
argp.add_argument('--finish', action='store_true', help='Set issue as finished (alias of -s finish)')
argp.add_argument('-s', '--state', type=str, help='Move to state')
+argp.add_argument('-t', '--tag', type=str, action='append', default=[], help='Add tag to issue')
+argp.add_argument('-u', '--untag', type=str, action='append', default=[], help='Remove tag from issue')
argp.add_argument('issue_id', type=str, help='Issue id to modify')
arg = argp.parse_args(sys.argv[1:])
store_factory = FileStoreFactory(arg.d)
-basket = Basket(store_factory.create)
+basket = Basket(store_factory)
def main():
@@ -33,6 +35,12 @@ def main():
elif arg.finish:
basket.state_finish(arg.issue_id)
+ for v in arg.tag:
+ basket.tag(arg.issue_id, v)
+
+ for v in arg.untag:
+ basket.untag(arg.issue_id, v)
+
if __name__ == '__main__':
main()
diff --git a/piknik/store/__init__.py b/piknik/store/__init__.py
@@ -19,5 +19,20 @@ class FileStoreFactory:
def create_tags(self, logger=None, default_state=None, verifier=None):
directory = os.path.join(self.directory, '.tags')
- factory = SimpleFileStoreFactory(directory).add
- return PersistedState(factory, 0, logger=logger, check_alias=False, default_state='untagged')
+ os.makedirs(directory, exist_ok=True)
+ factory = SimpleFileStoreFactory(directory)
+ state = PersistedState(factory.add, 0, logger=logger, check_alias=False, default_state='untagged')
+ aliases = []
+ for k in factory.ls():
+ if k == 'UNTAGGED':
+ continue
+ elif k[0] == '_':
+ aliases.append(k)
+ continue
+ state.add(k)
+
+ for v in aliases:
+ s = state.from_elements(v)
+ state.alias(v, s)
+
+ return state
diff --git a/tests/test_store.py b/tests/test_store.py
@@ -38,7 +38,7 @@ class TestStore(unittest.TestCase):
def tearDown(self):
- shutil.rmtree(self.d)
+ #shutil.rmtree(self.d)
pass
@@ -57,9 +57,26 @@ class TestStore(unittest.TestCase):
self.b.advance(va)
b = Basket(self.store_factory)
- print('get va {}'.format(va))
r = b.get(va)
+ def test_load_tag(self):
+ o = Issue('foo')
+ va = self.b.add(o)
+ self.b.tag(va, 'inky')
+ self.b.tag(va, 'pinky')
+
+ b = Basket(self.store_factory)
+ r = b.tags(va)
+ self.assertIn('INKY', r)
+ self.assertIn('PINKY', r)
+
+ self.b.untag(va, 'inky')
+ b = Basket(self.store_factory)
+ r = b.tags(va)
+ self.assertNotIn('INKY', r)
+ self.assertIn('PINKY', r)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_tag.py b/tests/test_tag.py
@@ -35,6 +35,7 @@ class TestBasic(unittest.TestCase):
v = self.b.add(o)
self.b.tag(v, 'inky')
self.b.tag(v, 'pinky')
+ self.b.untag(v, 'pinky')
if __name__ == '__main__':