synapse 2.198.0__py311-none-any.whl → 2.200.0__py311-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synapse might be problematic. Click here for more details.
- synapse/cortex.py +0 -6
- synapse/datamodel.py +8 -1
- synapse/lib/hive.py +1 -265
- synapse/lib/snap.py +56 -28
- synapse/lib/storm.py +28 -10
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +2 -1
- synapse/tests/test_cortex.py +0 -6
- synapse/tests/test_datamodel.py +29 -5
- synapse/tests/test_lib_aha.py +11 -11
- synapse/tests/test_lib_cell.py +4 -4
- synapse/tests/test_lib_hive.py +0 -38
- synapse/tests/test_lib_storm.py +14 -0
- synapse/tests/test_tools_hiveload.py +19 -23
- synapse/tests/test_tools_hivesave.py +5 -7
- synapse/tests/utils.py +17 -19
- synapse/tools/hive/load.py +3 -9
- {synapse-2.198.0.dist-info → synapse-2.200.0.dist-info}/METADATA +2 -2
- {synapse-2.198.0.dist-info → synapse-2.200.0.dist-info}/RECORD +22 -23
- synapse/lib/hiveauth.py +0 -1336
- {synapse-2.198.0.dist-info → synapse-2.200.0.dist-info}/LICENSE +0 -0
- {synapse-2.198.0.dist-info → synapse-2.200.0.dist-info}/WHEEL +0 -0
- {synapse-2.198.0.dist-info → synapse-2.200.0.dist-info}/top_level.txt +0 -0
synapse/cortex.py
CHANGED
|
@@ -20,7 +20,6 @@ import synapse.lib.base as s_base
|
|
|
20
20
|
import synapse.lib.cell as s_cell
|
|
21
21
|
import synapse.lib.chop as s_chop
|
|
22
22
|
import synapse.lib.coro as s_coro
|
|
23
|
-
import synapse.lib.hive as s_hive
|
|
24
23
|
import synapse.lib.view as s_view
|
|
25
24
|
import synapse.lib.cache as s_cache
|
|
26
25
|
import synapse.lib.const as s_const
|
|
@@ -855,7 +854,6 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
855
854
|
cellapi = CoreApi
|
|
856
855
|
viewapi = s_view.ViewApi
|
|
857
856
|
layerapi = s_layer.LayerApi
|
|
858
|
-
hiveapi = s_hive.HiveApi
|
|
859
857
|
|
|
860
858
|
viewctor = s_view.View.anit
|
|
861
859
|
layrctor = s_layer.Layer.anit
|
|
@@ -4656,10 +4654,6 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
4656
4654
|
if not path:
|
|
4657
4655
|
return await self.cellapi.anit(self, link, user)
|
|
4658
4656
|
|
|
4659
|
-
if path[0] == 'hive' and user.isAdmin():
|
|
4660
|
-
s_common.deprecated('Cortex /hive telepath path', curv='2.198.0', eolv='2.199.0')
|
|
4661
|
-
return await self.hiveapi.anit(self.hive, user)
|
|
4662
|
-
|
|
4663
4657
|
if path[0] == 'layer':
|
|
4664
4658
|
|
|
4665
4659
|
if len(path) == 1:
|
synapse/datamodel.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'''
|
|
2
2
|
An API to assist with the creation and enforcement of cortex data models.
|
|
3
3
|
'''
|
|
4
|
+
import sys
|
|
4
5
|
import asyncio
|
|
5
6
|
import logging
|
|
6
7
|
import collections
|
|
@@ -15,6 +16,7 @@ import synapse.lib.cache as s_cache
|
|
|
15
16
|
import synapse.lib.types as s_types
|
|
16
17
|
import synapse.lib.dyndeps as s_dyndeps
|
|
17
18
|
import synapse.lib.grammar as s_grammar
|
|
19
|
+
import synapse.lib.msgpack as s_msgpack
|
|
18
20
|
|
|
19
21
|
logger = logging.getLogger(__name__)
|
|
20
22
|
|
|
@@ -142,6 +144,9 @@ class Prop:
|
|
|
142
144
|
async def depfunc(node, oldv):
|
|
143
145
|
mesg = f'The property {self.full} is deprecated or using a deprecated type and will be removed in 3.0.0'
|
|
144
146
|
await node.snap.warnonce(mesg)
|
|
147
|
+
if __debug__:
|
|
148
|
+
sys.audit('synapse.datamodel.Prop.deprecated', mesg, self.full)
|
|
149
|
+
|
|
145
150
|
self.onSet(depfunc)
|
|
146
151
|
|
|
147
152
|
def __repr__(self):
|
|
@@ -306,6 +311,8 @@ class Form:
|
|
|
306
311
|
async def depfunc(node):
|
|
307
312
|
mesg = f'The form {self.full} is deprecated or using a deprecated type and will be removed in 3.0.0'
|
|
308
313
|
await node.snap.warnonce(mesg)
|
|
314
|
+
if __debug__:
|
|
315
|
+
sys.audit('synapse.datamodel.Form.deprecated', mesg, self.full)
|
|
309
316
|
self.onAdd(depfunc)
|
|
310
317
|
|
|
311
318
|
def getStorNode(self, form):
|
|
@@ -1107,7 +1114,7 @@ class Model:
|
|
|
1107
1114
|
|
|
1108
1115
|
def _prepFormIface(self, form, iface):
|
|
1109
1116
|
|
|
1110
|
-
template = iface.get('template', {})
|
|
1117
|
+
template = s_msgpack.deepcopy(iface.get('template', {}))
|
|
1111
1118
|
template.update(form.type.info.get('template', {}))
|
|
1112
1119
|
|
|
1113
1120
|
def convert(item):
|
synapse/lib/hive.py
CHANGED
|
@@ -86,7 +86,7 @@ class Node(s_base.Base):
|
|
|
86
86
|
for name, node in self.kids.items():
|
|
87
87
|
yield name, node
|
|
88
88
|
|
|
89
|
-
class Hive(s_nexus.Pusher
|
|
89
|
+
class Hive(s_nexus.Pusher):
|
|
90
90
|
'''
|
|
91
91
|
An optionally persistent atomically accessed tree which implements
|
|
92
92
|
primitives for use in making distributed/clustered services.
|
|
@@ -95,8 +95,6 @@ class Hive(s_nexus.Pusher, s_telepath.Aware):
|
|
|
95
95
|
|
|
96
96
|
await s_nexus.Pusher.__anit__(self, 'hive', nexsroot=nexsroot)
|
|
97
97
|
|
|
98
|
-
s_telepath.Aware.__init__(self)
|
|
99
|
-
|
|
100
98
|
if conf is None:
|
|
101
99
|
conf = {}
|
|
102
100
|
|
|
@@ -161,24 +159,6 @@ class Hive(s_nexus.Pusher, s_telepath.Aware):
|
|
|
161
159
|
for cullname in culls:
|
|
162
160
|
await node.pop((cullname,))
|
|
163
161
|
|
|
164
|
-
async def getHiveAuth(self):
|
|
165
|
-
'''
|
|
166
|
-
Retrieve a HiveAuth for hive standalone or non-cell uses.
|
|
167
|
-
|
|
168
|
-
Note:
|
|
169
|
-
This is for the hive's own auth, or for non-cell auth. It isn't the same auth as for a cell
|
|
170
|
-
'''
|
|
171
|
-
import synapse.lib.hiveauth as s_hiveauth
|
|
172
|
-
if self.auth is None:
|
|
173
|
-
|
|
174
|
-
path = tuple(self.conf.get('auth:path').split('/'))
|
|
175
|
-
|
|
176
|
-
node = await self.open(path)
|
|
177
|
-
self.auth = await s_hiveauth.Auth.anit(node, nexsroot=self.nexsroot)
|
|
178
|
-
self.onfini(self.auth.fini)
|
|
179
|
-
|
|
180
|
-
return self.auth
|
|
181
|
-
|
|
182
162
|
async def _onHiveFini(self):
|
|
183
163
|
await self.root.fini()
|
|
184
164
|
|
|
@@ -423,27 +403,6 @@ class Hive(s_nexus.Pusher, s_telepath.Aware):
|
|
|
423
403
|
|
|
424
404
|
return node.valu
|
|
425
405
|
|
|
426
|
-
async def getTeleApi(self, link, mesg, path):
|
|
427
|
-
s_common.deprecated('Hive.getTeleApi', curv='2.198.0', eolv='2.199.0')
|
|
428
|
-
auth = await self.getHiveAuth()
|
|
429
|
-
|
|
430
|
-
if not self.conf.get('auth:en'):
|
|
431
|
-
user = await auth.getUserByName('root')
|
|
432
|
-
return await HiveApi.anit(self, user)
|
|
433
|
-
|
|
434
|
-
name, info = mesg[1].get('auth')
|
|
435
|
-
|
|
436
|
-
user = await auth.getUserByName(name)
|
|
437
|
-
if user is None:
|
|
438
|
-
raise s_exc.NoSuchUser(name=name)
|
|
439
|
-
|
|
440
|
-
# passwd None always fails...
|
|
441
|
-
passwd = info.get('passwd')
|
|
442
|
-
if not await user.tryPasswd(passwd):
|
|
443
|
-
raise s_exc.AuthDeny(mesg='Invalid password', user=user.iden, username=user.name)
|
|
444
|
-
|
|
445
|
-
return await HiveApi.anit(self, user)
|
|
446
|
-
|
|
447
406
|
async def _storLoadHive(self):
|
|
448
407
|
pass
|
|
449
408
|
|
|
@@ -480,224 +439,6 @@ class SlabHive(Hive):
|
|
|
480
439
|
lkey = '\x00'.join(full).encode('utf8')
|
|
481
440
|
self.slab.pop(lkey, db=self.db)
|
|
482
441
|
|
|
483
|
-
class HiveApi(s_base.Base):
|
|
484
|
-
|
|
485
|
-
async def __anit__(self, hive, user):
|
|
486
|
-
|
|
487
|
-
await s_base.Base.__anit__(self)
|
|
488
|
-
|
|
489
|
-
self.hive = hive
|
|
490
|
-
self.user = user
|
|
491
|
-
|
|
492
|
-
self.msgq = asyncio.Queue(maxsize=10000)
|
|
493
|
-
|
|
494
|
-
self.onfini(self._onHapiFini)
|
|
495
|
-
|
|
496
|
-
async def loadHiveTree(self, tree, path=(), trim=False):
|
|
497
|
-
s_common.deprecated('HiveApi.loadHiveTree', curv='2.167.0')
|
|
498
|
-
return await self.hive.loadHiveTree(tree, path=path, trim=trim)
|
|
499
|
-
|
|
500
|
-
async def saveHiveTree(self, path=()):
|
|
501
|
-
s_common.deprecated('HiveApi.saveHiveTree', curv='2.167.0')
|
|
502
|
-
return await self.hive.saveHiveTree(path=path)
|
|
503
|
-
|
|
504
|
-
async def treeAndSync(self, path, iden):
|
|
505
|
-
s_common.deprecated('HiveApi.treeAndSync', curv='2.167.0')
|
|
506
|
-
|
|
507
|
-
node = await self.hive.open(path)
|
|
508
|
-
|
|
509
|
-
# register handlers...
|
|
510
|
-
node.on('hive:add', self._onHiveEdit, base=self)
|
|
511
|
-
node.on('hive:set', self._onHiveEdit, base=self)
|
|
512
|
-
node.on('hive:pop', self._onHiveEdit, base=self)
|
|
513
|
-
|
|
514
|
-
# serialize the subtree into a message and return
|
|
515
|
-
# via the mesg queue so there is no get/update race
|
|
516
|
-
root = (node.valu, {})
|
|
517
|
-
|
|
518
|
-
todo = collections.deque([(node, root)])
|
|
519
|
-
|
|
520
|
-
# breadth first generator
|
|
521
|
-
while todo:
|
|
522
|
-
|
|
523
|
-
node, pode = todo.popleft()
|
|
524
|
-
|
|
525
|
-
for name, kidn in node.kids.items():
|
|
526
|
-
|
|
527
|
-
kidp = (kidn.valu, {})
|
|
528
|
-
pode[1][name] = kidp
|
|
529
|
-
|
|
530
|
-
todo.append((kidn, kidp))
|
|
531
|
-
|
|
532
|
-
await self.msgq.put(('hive:tree', {'path': path, 'tree': root}))
|
|
533
|
-
await self.msgq.put(('hive:sync', {'iden': iden}))
|
|
534
|
-
return
|
|
535
|
-
|
|
536
|
-
async def setAndSync(self, path, valu, iden, nexs=False):
|
|
537
|
-
s_common.deprecated('HiveApi.setAndSync', curv='2.167.0')
|
|
538
|
-
|
|
539
|
-
valu = await self.hive.set(path, valu, nexs=nexs)
|
|
540
|
-
await self.msgq.put(('hive:sync', {'iden': iden}))
|
|
541
|
-
return valu
|
|
542
|
-
|
|
543
|
-
async def addAndSync(self, path, valu, iden):
|
|
544
|
-
s_common.deprecated('HiveApi.addAndSync', curv='2.167.0')
|
|
545
|
-
|
|
546
|
-
valu = await self.hive.add(path, valu)
|
|
547
|
-
await self.msgq.put(('hive:sync', {'iden': iden}))
|
|
548
|
-
return valu
|
|
549
|
-
|
|
550
|
-
async def popAndSync(self, path, iden, nexs=False):
|
|
551
|
-
s_common.deprecated('HiveApi.popAndSync', curv='2.167.0')
|
|
552
|
-
|
|
553
|
-
valu = await self.hive.pop(path, nexs=nexs)
|
|
554
|
-
await self.msgq.put(('hive:sync', {'iden': iden}))
|
|
555
|
-
return valu
|
|
556
|
-
|
|
557
|
-
async def _onHapiFini(self):
|
|
558
|
-
await self.msgq.put(None)
|
|
559
|
-
|
|
560
|
-
async def _onHiveEdit(self, mesg):
|
|
561
|
-
self.msgq.put_nowait(mesg)
|
|
562
|
-
|
|
563
|
-
async def get(self, full):
|
|
564
|
-
s_common.deprecated('HiveApi.get', curv='2.167.0')
|
|
565
|
-
return await self.hive.get(full)
|
|
566
|
-
|
|
567
|
-
async def edits(self):
|
|
568
|
-
s_common.deprecated('HiveApi.edits', curv='2.167.0')
|
|
569
|
-
|
|
570
|
-
while not self.isfini:
|
|
571
|
-
|
|
572
|
-
item = await self.msgq.get()
|
|
573
|
-
if item is None:
|
|
574
|
-
return
|
|
575
|
-
|
|
576
|
-
yield item
|
|
577
|
-
|
|
578
|
-
class TeleHive(Hive):
|
|
579
|
-
'''
|
|
580
|
-
A Hive that acts as a consistent read cache for a telepath proxy Hive
|
|
581
|
-
'''
|
|
582
|
-
|
|
583
|
-
async def __anit__(self, proxy):
|
|
584
|
-
|
|
585
|
-
self.proxy = proxy
|
|
586
|
-
|
|
587
|
-
await Hive.__anit__(self)
|
|
588
|
-
|
|
589
|
-
self.lock = asyncio.Lock()
|
|
590
|
-
|
|
591
|
-
self.syncevents = {} # iden: asyncio.Event()
|
|
592
|
-
|
|
593
|
-
# fire a task to sync the sections of the tree we open
|
|
594
|
-
self.schedCoro(self._runHiveLoop())
|
|
595
|
-
|
|
596
|
-
self.mesgbus = await s_base.Base.anit()
|
|
597
|
-
self.mesgbus.on('hive:set', self._onHiveSet)
|
|
598
|
-
self.mesgbus.on('hive:pop', self._onHivePop)
|
|
599
|
-
self.mesgbus.on('hive:tree', self._onHiveTree)
|
|
600
|
-
self.mesgbus.on('hive:sync', self._onHiveSync)
|
|
601
|
-
|
|
602
|
-
self.onfini(self.mesgbus.fini)
|
|
603
|
-
|
|
604
|
-
self.onfini(proxy.fini)
|
|
605
|
-
|
|
606
|
-
async def _onHiveSync(self, mesg):
|
|
607
|
-
|
|
608
|
-
iden = mesg[1].get('iden')
|
|
609
|
-
evnt = self.syncevents.pop(iden, None)
|
|
610
|
-
if evnt is None:
|
|
611
|
-
return
|
|
612
|
-
|
|
613
|
-
evnt.set()
|
|
614
|
-
|
|
615
|
-
def _getSyncIden(self):
|
|
616
|
-
iden = s_common.guid()
|
|
617
|
-
evnt = asyncio.Event()
|
|
618
|
-
self.syncevents[iden] = evnt
|
|
619
|
-
return iden, evnt
|
|
620
|
-
|
|
621
|
-
async def _runHiveLoop(self):
|
|
622
|
-
while not self.isfini:
|
|
623
|
-
async for mesg in self.proxy.edits():
|
|
624
|
-
await self.mesgbus.dist(mesg)
|
|
625
|
-
|
|
626
|
-
async def _onHiveSet(self, mesg):
|
|
627
|
-
path = mesg[1].get('path')
|
|
628
|
-
valu = mesg[1].get('valu')
|
|
629
|
-
await Hive.set(self, path, valu)
|
|
630
|
-
|
|
631
|
-
async def _onHivePop(self, mesg):
|
|
632
|
-
path = mesg[1].get('path')
|
|
633
|
-
await Hive.pop(self, path)
|
|
634
|
-
|
|
635
|
-
async def _onHiveTree(self, mesg):
|
|
636
|
-
|
|
637
|
-
# get an entire tree update at once
|
|
638
|
-
path = mesg[1].get('path')
|
|
639
|
-
tree = mesg[1].get('tree')
|
|
640
|
-
|
|
641
|
-
node = await Hive.open(self, path)
|
|
642
|
-
|
|
643
|
-
todo = collections.deque([(node, path, tree)])
|
|
644
|
-
|
|
645
|
-
while todo:
|
|
646
|
-
|
|
647
|
-
node, path, (valu, kids) = todo.popleft()
|
|
648
|
-
|
|
649
|
-
# do *not* go through the set() API
|
|
650
|
-
node.valu = valu
|
|
651
|
-
for name, kidt in kids.items():
|
|
652
|
-
|
|
653
|
-
kidp = path + (name,)
|
|
654
|
-
kidn = await Hive.open(self, kidp)
|
|
655
|
-
|
|
656
|
-
todo.append((kidn, kidp, kidt))
|
|
657
|
-
|
|
658
|
-
async def set(self, path, valu, nexs=False):
|
|
659
|
-
iden, evnt = self._getSyncIden()
|
|
660
|
-
valu = await self.proxy.setAndSync(path, valu, iden, nexs=nexs)
|
|
661
|
-
await evnt.wait()
|
|
662
|
-
return valu
|
|
663
|
-
|
|
664
|
-
async def add(self, path, valu):
|
|
665
|
-
iden, evnt = self._getSyncIden()
|
|
666
|
-
valu = await self.proxy.addAndSync(path, valu, iden)
|
|
667
|
-
await evnt.wait()
|
|
668
|
-
return valu
|
|
669
|
-
|
|
670
|
-
async def pop(self, path, nexs=False):
|
|
671
|
-
iden, evnt = self._getSyncIden()
|
|
672
|
-
valu = await self.proxy.popAndSync(path, iden, nexs=nexs)
|
|
673
|
-
await evnt.wait()
|
|
674
|
-
return valu
|
|
675
|
-
|
|
676
|
-
async def get(self, path):
|
|
677
|
-
return await self.proxy.get(path)
|
|
678
|
-
|
|
679
|
-
async def open(self, path):
|
|
680
|
-
|
|
681
|
-
# try once pre-lock for speed
|
|
682
|
-
node = self.nodes.get(path)
|
|
683
|
-
if node is not None:
|
|
684
|
-
return node
|
|
685
|
-
|
|
686
|
-
async with self.lock:
|
|
687
|
-
|
|
688
|
-
# try again with lock to avoid race
|
|
689
|
-
node = self.nodes.get(path)
|
|
690
|
-
if node is not None:
|
|
691
|
-
return node
|
|
692
|
-
|
|
693
|
-
iden, evnt = self._getSyncIden()
|
|
694
|
-
|
|
695
|
-
await self.proxy.treeAndSync(path, iden)
|
|
696
|
-
|
|
697
|
-
await evnt.wait()
|
|
698
|
-
|
|
699
|
-
return self.nodes.get(path)
|
|
700
|
-
|
|
701
442
|
class HiveDict(s_base.Base):
|
|
702
443
|
'''
|
|
703
444
|
'''
|
|
@@ -758,11 +499,6 @@ def iterpath(path):
|
|
|
758
499
|
for i in range(len(path)):
|
|
759
500
|
yield path[:i + 1]
|
|
760
501
|
|
|
761
|
-
async def openurl(url, **opts):
|
|
762
|
-
s_common.deprecated('synapse.lib.hive.openurl()', curv='2.198.0', eolv='2.199.0')
|
|
763
|
-
prox = await s_telepath.openurl(url, **opts)
|
|
764
|
-
return await TeleHive.anit(prox)
|
|
765
|
-
|
|
766
502
|
async def opendir(dirn, conf=None):
|
|
767
503
|
slab = await s_slab.Slab.anit(dirn, map_size=s_const.gibibyte)
|
|
768
504
|
db = slab.initdb('hive')
|
synapse/lib/snap.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import sys
|
|
4
3
|
import types
|
|
5
4
|
import asyncio
|
|
6
5
|
import logging
|
|
@@ -12,14 +11,12 @@ import synapse.exc as s_exc
|
|
|
12
11
|
import synapse.common as s_common
|
|
13
12
|
|
|
14
13
|
import synapse.lib.base as s_base
|
|
15
|
-
import synapse.lib.coro as s_coro
|
|
16
14
|
import synapse.lib.node as s_node
|
|
17
15
|
import synapse.lib.time as s_time
|
|
18
16
|
import synapse.lib.cache as s_cache
|
|
19
17
|
import synapse.lib.layer as s_layer
|
|
20
18
|
import synapse.lib.storm as s_storm
|
|
21
19
|
import synapse.lib.types as s_types
|
|
22
|
-
import synapse.lib.spooled as s_spooled
|
|
23
20
|
|
|
24
21
|
logger = logging.getLogger(__name__)
|
|
25
22
|
|
|
@@ -138,16 +135,30 @@ class ProtoNode:
|
|
|
138
135
|
|
|
139
136
|
if not await self.ctx.snap.hasNodeEdge(self.buid, verb, s_common.uhex(n2iden)):
|
|
140
137
|
self.edges.add(tupl)
|
|
141
|
-
|
|
142
138
|
if len(self.edges) >= 1000:
|
|
143
|
-
|
|
144
|
-
await self.ctx.snap.applyNodeEdits(nodeedits)
|
|
145
|
-
self.edges.clear()
|
|
146
|
-
|
|
139
|
+
await self.flushEdits()
|
|
147
140
|
return True
|
|
148
141
|
|
|
149
142
|
return False
|
|
150
143
|
|
|
144
|
+
async def flushEdits(self):
|
|
145
|
+
if (nodeedit := self.getNodeEdit()) is not None:
|
|
146
|
+
nodecache = {self.buid: self.node}
|
|
147
|
+
nodes = await self.ctx.snap.applyNodeEdits((nodeedit,), nodecache=nodecache, meta=self.ctx.meta)
|
|
148
|
+
|
|
149
|
+
if self.node is None:
|
|
150
|
+
if nodes and nodes[0].buid == self.buid:
|
|
151
|
+
self.node = nodes[0]
|
|
152
|
+
else: # pragma: no cover
|
|
153
|
+
self.node = await self.ctx.snap.getNodeByBuid(self.buid)
|
|
154
|
+
|
|
155
|
+
self.tags.clear()
|
|
156
|
+
self.props.clear()
|
|
157
|
+
self.tagprops.clear()
|
|
158
|
+
self.edges.clear()
|
|
159
|
+
self.edgedels.clear()
|
|
160
|
+
self.nodedata.clear()
|
|
161
|
+
|
|
151
162
|
async def delEdge(self, verb, n2iden):
|
|
152
163
|
|
|
153
164
|
if not isinstance(verb, str):
|
|
@@ -175,12 +186,8 @@ class ProtoNode:
|
|
|
175
186
|
|
|
176
187
|
if await self.ctx.snap.layers[-1].hasNodeEdge(self.buid, verb, s_common.uhex(n2iden)):
|
|
177
188
|
self.edgedels.add(tupl)
|
|
178
|
-
|
|
179
189
|
if len(self.edgedels) >= 1000:
|
|
180
|
-
|
|
181
|
-
await self.ctx.snap.applyNodeEdits(nodeedits)
|
|
182
|
-
self.edgedels.clear()
|
|
183
|
-
|
|
190
|
+
await self.flushEdits()
|
|
184
191
|
return True
|
|
185
192
|
|
|
186
193
|
return False
|
|
@@ -429,6 +436,9 @@ class ProtoNode:
|
|
|
429
436
|
full = f'{prop.name}:{subname}'
|
|
430
437
|
subprop = self.form.props.get(full)
|
|
431
438
|
if subprop is not None and not subprop.locked:
|
|
439
|
+
if subprop.deprecated:
|
|
440
|
+
self.ctx.snap._skipPropDeprWarn(subprop.full)
|
|
441
|
+
|
|
432
442
|
await self.set(full, subvalu)
|
|
433
443
|
|
|
434
444
|
propadds = norminfo.get('adds')
|
|
@@ -438,11 +448,14 @@ class ProtoNode:
|
|
|
438
448
|
|
|
439
449
|
return True
|
|
440
450
|
|
|
441
|
-
async def
|
|
451
|
+
async def getSetSubOps(self, name, valu, norminfo=None):
|
|
442
452
|
prop = self.form.props.get(name)
|
|
443
|
-
if prop is None:
|
|
453
|
+
if prop is None or prop.locked:
|
|
444
454
|
return ()
|
|
445
455
|
|
|
456
|
+
if prop.deprecated:
|
|
457
|
+
self.ctx.snap._skipPropDeprWarn(prop.full)
|
|
458
|
+
|
|
446
459
|
retn = await self._set(prop, valu, norminfo=norminfo)
|
|
447
460
|
if retn is False:
|
|
448
461
|
return ()
|
|
@@ -459,9 +472,7 @@ class ProtoNode:
|
|
|
459
472
|
if propsubs is not None:
|
|
460
473
|
for subname, subvalu in propsubs.items():
|
|
461
474
|
full = f'{prop.name}:{subname}'
|
|
462
|
-
|
|
463
|
-
if subprop is not None and not subprop.locked:
|
|
464
|
-
ops.append(self.getSetOps(full, subvalu))
|
|
475
|
+
ops.append(self.getSetSubOps(full, subvalu))
|
|
465
476
|
|
|
466
477
|
propadds = norminfo.get('adds')
|
|
467
478
|
if propadds is not None:
|
|
@@ -474,7 +485,8 @@ class SnapEditor:
|
|
|
474
485
|
'''
|
|
475
486
|
A SnapEditor allows tracking node edits with subs/deps as a transaction.
|
|
476
487
|
'''
|
|
477
|
-
def __init__(self, snap):
|
|
488
|
+
def __init__(self, snap, meta=None):
|
|
489
|
+
self.meta = meta
|
|
478
490
|
self.snap = snap
|
|
479
491
|
self.protonodes = {}
|
|
480
492
|
self.maxnodes = snap.core.maxnodes
|
|
@@ -492,6 +504,19 @@ class SnapEditor:
|
|
|
492
504
|
nodeedits.append(nodeedit)
|
|
493
505
|
return nodeedits
|
|
494
506
|
|
|
507
|
+
async def flushEdits(self):
|
|
508
|
+
nodecache = {}
|
|
509
|
+
nodeedits = []
|
|
510
|
+
for protonode in self.protonodes.values():
|
|
511
|
+
if (nodeedit := protonode.getNodeEdit()) is not None:
|
|
512
|
+
nodeedits.append(nodeedit)
|
|
513
|
+
nodecache[protonode.buid] = protonode.node
|
|
514
|
+
|
|
515
|
+
if nodeedits:
|
|
516
|
+
await self.snap.applyNodeEdits(nodeedits, nodecache=nodecache, meta=self.meta)
|
|
517
|
+
|
|
518
|
+
self.protonodes.clear()
|
|
519
|
+
|
|
495
520
|
async def _addNode(self, form, valu, props=None, norminfo=None):
|
|
496
521
|
|
|
497
522
|
self.snap.core._checkMaxNodes()
|
|
@@ -568,7 +593,7 @@ class SnapEditor:
|
|
|
568
593
|
subs = norminfo.get('subs')
|
|
569
594
|
if subs is not None:
|
|
570
595
|
for prop, valu in subs.items():
|
|
571
|
-
ops.append(protonode.
|
|
596
|
+
ops.append(protonode.getSetSubOps(prop, valu))
|
|
572
597
|
|
|
573
598
|
adds = norminfo.get('adds')
|
|
574
599
|
if adds is not None:
|
|
@@ -604,7 +629,7 @@ class SnapEditor:
|
|
|
604
629
|
subs = norminfo.get('subs')
|
|
605
630
|
if subs is not None:
|
|
606
631
|
for prop, valu in subs.items():
|
|
607
|
-
ops.append(protonode.
|
|
632
|
+
ops.append(protonode.getSetSubOps(prop, valu))
|
|
608
633
|
|
|
609
634
|
while ops:
|
|
610
635
|
oset = ops.popleft()
|
|
@@ -861,6 +886,10 @@ class Snap(s_base.Base):
|
|
|
861
886
|
self._warnonce_keys.add(mesg)
|
|
862
887
|
await self.warn(mesg, log, **info)
|
|
863
888
|
|
|
889
|
+
def _skipPropDeprWarn(self, name):
|
|
890
|
+
mesg = f'The property {name} is deprecated or using a deprecated type and will be removed in 3.0.0'
|
|
891
|
+
self._warnonce_keys.add(mesg)
|
|
892
|
+
|
|
864
893
|
async def getNodeByBuid(self, buid):
|
|
865
894
|
'''
|
|
866
895
|
Retrieve a node tuple by binary id.
|
|
@@ -1218,11 +1247,13 @@ class Snap(s_base.Base):
|
|
|
1218
1247
|
if nodes:
|
|
1219
1248
|
return nodes[0]
|
|
1220
1249
|
|
|
1221
|
-
async def applyNodeEdits(self, edits, nodecache=None):
|
|
1250
|
+
async def applyNodeEdits(self, edits, nodecache=None, meta=None):
|
|
1222
1251
|
'''
|
|
1223
1252
|
Sends edits to the write layer and evaluates the consequences (triggers, node object updates)
|
|
1224
1253
|
'''
|
|
1225
|
-
meta
|
|
1254
|
+
if meta is None:
|
|
1255
|
+
meta = await self.getSnapMeta()
|
|
1256
|
+
|
|
1226
1257
|
saveoff, changes, nodes = await self._applyNodeEdits(edits, meta, nodecache=nodecache)
|
|
1227
1258
|
return nodes
|
|
1228
1259
|
|
|
@@ -1572,7 +1603,8 @@ class Snap(s_base.Base):
|
|
|
1572
1603
|
proptype = prop.type
|
|
1573
1604
|
for prop in prop.getAlts():
|
|
1574
1605
|
if prop.type.isarray and prop.type.arraytype == proptype:
|
|
1575
|
-
|
|
1606
|
+
arryvalu = node.get(prop.name)
|
|
1607
|
+
if arryvalu is not None and valu in arryvalu:
|
|
1576
1608
|
return True
|
|
1577
1609
|
else:
|
|
1578
1610
|
if node.get(prop.name) == valu:
|
|
@@ -1660,10 +1692,6 @@ class Snap(s_base.Base):
|
|
|
1660
1692
|
return tagnode
|
|
1661
1693
|
|
|
1662
1694
|
async def _raiseOnStrict(self, ctor, mesg, **info):
|
|
1663
|
-
if __debug__:
|
|
1664
|
-
if issubclass(ctor, s_exc.IsDeprLocked):
|
|
1665
|
-
sys.audit('synapse.exc.IsDeprLocked', (mesg, info))
|
|
1666
|
-
|
|
1667
1695
|
if self.strict:
|
|
1668
1696
|
raise ctor(mesg=mesg, **info)
|
|
1669
1697
|
await self.warn(mesg)
|
synapse/lib/storm.py
CHANGED
|
@@ -2077,7 +2077,7 @@ class Runtime(s_base.Base):
|
|
|
2077
2077
|
|
|
2078
2078
|
class Parser:
|
|
2079
2079
|
|
|
2080
|
-
def __init__(self, prog=None, descr=None, root=None, model=None):
|
|
2080
|
+
def __init__(self, prog=None, descr=None, root=None, model=None, cdef=None):
|
|
2081
2081
|
|
|
2082
2082
|
if root is None:
|
|
2083
2083
|
root = self
|
|
@@ -2088,6 +2088,7 @@ class Parser:
|
|
|
2088
2088
|
|
|
2089
2089
|
self.prog = prog
|
|
2090
2090
|
self.descr = descr
|
|
2091
|
+
self.cdef = cdef
|
|
2091
2092
|
|
|
2092
2093
|
self.exc = None
|
|
2093
2094
|
|
|
@@ -2365,6 +2366,21 @@ class Parser:
|
|
|
2365
2366
|
|
|
2366
2367
|
self._printf(f'Usage: {self.prog} [options] {posargs}')
|
|
2367
2368
|
|
|
2369
|
+
if self.cdef is not None and (endpoints := self.cdef.get('endpoints')):
|
|
2370
|
+
self._printf('')
|
|
2371
|
+
self._printf('Endpoints:')
|
|
2372
|
+
self._printf('')
|
|
2373
|
+
base_w = 32
|
|
2374
|
+
wrap_w = 120 - base_w
|
|
2375
|
+
for endpoint in endpoints:
|
|
2376
|
+
path = endpoint['path']
|
|
2377
|
+
desc = endpoint.get('desc', '')
|
|
2378
|
+
base = f' {path}'
|
|
2379
|
+
wrap_desc = self._wrap_text(desc, wrap_w) if desc else ['']
|
|
2380
|
+
self._printf(f'{base:<{base_w-2}}: {wrap_desc[0]}')
|
|
2381
|
+
for ln in wrap_desc[1:]:
|
|
2382
|
+
self._printf(f'{"":<{base_w}}{ln}')
|
|
2383
|
+
|
|
2368
2384
|
options = [x for x in self.allargs if x[0][0].startswith('-')]
|
|
2369
2385
|
|
|
2370
2386
|
self._printf('')
|
|
@@ -2655,6 +2671,7 @@ class PureCmd(Cmd):
|
|
|
2655
2671
|
if inputs:
|
|
2656
2672
|
pars.set_inputs(inputs)
|
|
2657
2673
|
|
|
2674
|
+
pars.cdef = self.cdef
|
|
2658
2675
|
return pars
|
|
2659
2676
|
|
|
2660
2677
|
async def execStormCmd(self, runt, genr):
|
|
@@ -3653,23 +3670,26 @@ class MergeCmd(Cmd):
|
|
|
3653
3670
|
|
|
3654
3671
|
genr = diffgenr()
|
|
3655
3672
|
|
|
3656
|
-
async with await runt.snap.view.parent.snap(user=runt.user
|
|
3673
|
+
async with await runt.snap.view.parent.snap(user=runt.user) as snap:
|
|
3657
3674
|
snap.strict = False
|
|
3658
3675
|
|
|
3659
3676
|
snap.on('warn', runt.snap.dist)
|
|
3660
3677
|
|
|
3678
|
+
meta = {'user': runt.user.iden}
|
|
3679
|
+
|
|
3680
|
+
if doapply:
|
|
3681
|
+
editor = s_snap.SnapEditor(snap, meta=meta)
|
|
3682
|
+
|
|
3661
3683
|
async for node, path in genr:
|
|
3662
3684
|
|
|
3663
3685
|
# the timestamp for the adds/subs of each node merge will match
|
|
3664
3686
|
nodeiden = node.iden()
|
|
3665
|
-
|
|
3687
|
+
|
|
3688
|
+
meta['time'] = s_common.now()
|
|
3666
3689
|
|
|
3667
3690
|
sodes = await node.getStorNodes()
|
|
3668
3691
|
sode = sodes[0]
|
|
3669
3692
|
|
|
3670
|
-
if doapply:
|
|
3671
|
-
editor = s_snap.SnapEditor(snap)
|
|
3672
|
-
|
|
3673
3693
|
subs = []
|
|
3674
3694
|
|
|
3675
3695
|
# check all node perms first
|
|
@@ -3818,13 +3838,11 @@ class MergeCmd(Cmd):
|
|
|
3818
3838
|
subs.append((s_layer.EDIT_NODE_DEL, valu, ()))
|
|
3819
3839
|
|
|
3820
3840
|
if doapply:
|
|
3821
|
-
|
|
3822
|
-
if addedits:
|
|
3823
|
-
await runt.snap.view.parent.storNodeEdits(addedits, meta=meta)
|
|
3841
|
+
await editor.flushEdits()
|
|
3824
3842
|
|
|
3825
3843
|
if subs:
|
|
3826
3844
|
subedits = [(node.buid, node.form.name, subs)]
|
|
3827
|
-
await runt.snap.
|
|
3845
|
+
await runt.snap.applyNodeEdits(subedits, nodecache={node.buid: node}, meta=meta)
|
|
3828
3846
|
|
|
3829
3847
|
runt.snap.clearCachedNode(node.buid)
|
|
3830
3848
|
yield await runt.snap.getNodeByBuid(node.buid), path
|
synapse/lib/version.py
CHANGED
|
@@ -223,6 +223,6 @@ def reqVersion(valu, reqver,
|
|
|
223
223
|
##############################################################################
|
|
224
224
|
# The following are touched during the release process by bumpversion.
|
|
225
225
|
# Do not modify these directly.
|
|
226
|
-
version = (2,
|
|
226
|
+
version = (2, 200, 0)
|
|
227
227
|
verstring = '.'.join([str(x) for x in version])
|
|
228
|
-
commit = '
|
|
228
|
+
commit = 'ab9ca513fe33d52df7a3122c0bf4eab6951b53d3'
|
synapse/lib/view.py
CHANGED
|
@@ -1474,7 +1474,8 @@ class View(s_nexus.Pusher): # type: ignore
|
|
|
1474
1474
|
|
|
1475
1475
|
meta = await snap.getSnapMeta()
|
|
1476
1476
|
async for nodeedits in fromlayr.iterLayerNodeEdits():
|
|
1477
|
-
|
|
1477
|
+
meta['time'] = s_common.now()
|
|
1478
|
+
await snap.saveNodeEdits([nodeedits], meta)
|
|
1478
1479
|
|
|
1479
1480
|
async def swapLayer(self):
|
|
1480
1481
|
oldlayr = self.layers[0]
|