blob: 7391e1b45c350397c4cf26b13dbe32896ea8dd78 [file] [log] [blame]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001"""
2BitBake 'remotedata' module
3
4Provides support for using a datastore from the bitbake client
5"""
6
7# Copyright (C) 2016 Intel Corporation
8#
Brad Bishopc342db32019-05-15 21:57:59 -04009# SPDX-License-Identifier: GPL-2.0-only
Brad Bishop6e60e8b2018-02-01 10:27:11 -050010#
Brad Bishop6e60e8b2018-02-01 10:27:11 -050011
12import bb.data
13
14class RemoteDatastores:
15 """Used on the server side to manage references to server-side datastores"""
16 def __init__(self, cooker):
17 self.cooker = cooker
18 self.datastores = {}
19 self.locked = []
20 self.nextindex = 1
21
22 def __len__(self):
23 return len(self.datastores)
24
25 def __getitem__(self, key):
26 if key is None:
27 return self.cooker.data
28 else:
29 return self.datastores[key]
30
31 def items(self):
32 return self.datastores.items()
33
34 def store(self, d, locked=False):
35 """
36 Put a datastore into the collection. If locked=True then the datastore
37 is understood to be managed externally and cannot be released by calling
38 release().
39 """
40 idx = self.nextindex
41 self.datastores[idx] = d
42 if locked:
43 self.locked.append(idx)
44 self.nextindex += 1
45 return idx
46
47 def check_store(self, d, locked=False):
48 """
49 Put a datastore into the collection if it's not already in there;
50 in either case return the index
51 """
52 for key, val in self.datastores.items():
53 if val is d:
54 idx = key
55 break
56 else:
57 idx = self.store(d, locked)
58 return idx
59
60 def release(self, idx):
61 """Discard a datastore in the collection"""
62 if idx in self.locked:
63 raise Exception('Tried to release locked datastore %d' % idx)
64 del self.datastores[idx]
65
66 def receive_datastore(self, remote_data):
67 """Receive a datastore object sent from the client (as prepared by transmit_datastore())"""
68 dct = dict(remote_data)
69 d = bb.data_smart.DataSmart()
70 d.dict = dct
71 while True:
72 if '_remote_data' in dct:
73 dsindex = dct['_remote_data']['_content']
74 del dct['_remote_data']
75 if dsindex is None:
76 dct['_data'] = self.cooker.data.dict
77 else:
78 dct['_data'] = self.datastores[dsindex].dict
79 break
80 elif '_data' in dct:
81 idct = dict(dct['_data'])
82 dct['_data'] = idct
83 dct = idct
84 else:
85 break
86 return d
87
88 @staticmethod
89 def transmit_datastore(d):
90 """Prepare a datastore object for sending over IPC from the client end"""
91 # FIXME content might be a dict, need to turn that into a list as well
92 def copy_dicts(dct):
93 if '_remote_data' in dct:
94 dsindex = dct['_remote_data']['_content'].dsindex
95 newdct = dct.copy()
96 newdct['_remote_data'] = {'_content': dsindex}
97 return list(newdct.items())
98 elif '_data' in dct:
99 newdct = dct.copy()
100 newdata = copy_dicts(dct['_data'])
101 if newdata:
102 newdct['_data'] = newdata
103 return list(newdct.items())
104 return None
105 main_dict = copy_dicts(d.dict)
106 return main_dict