blob: 68ecffc198d4363e26bd27872deccd466f815af3 [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#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 2 as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
22import bb.data
23
24class RemoteDatastores:
25 """Used on the server side to manage references to server-side datastores"""
26 def __init__(self, cooker):
27 self.cooker = cooker
28 self.datastores = {}
29 self.locked = []
30 self.nextindex = 1
31
32 def __len__(self):
33 return len(self.datastores)
34
35 def __getitem__(self, key):
36 if key is None:
37 return self.cooker.data
38 else:
39 return self.datastores[key]
40
41 def items(self):
42 return self.datastores.items()
43
44 def store(self, d, locked=False):
45 """
46 Put a datastore into the collection. If locked=True then the datastore
47 is understood to be managed externally and cannot be released by calling
48 release().
49 """
50 idx = self.nextindex
51 self.datastores[idx] = d
52 if locked:
53 self.locked.append(idx)
54 self.nextindex += 1
55 return idx
56
57 def check_store(self, d, locked=False):
58 """
59 Put a datastore into the collection if it's not already in there;
60 in either case return the index
61 """
62 for key, val in self.datastores.items():
63 if val is d:
64 idx = key
65 break
66 else:
67 idx = self.store(d, locked)
68 return idx
69
70 def release(self, idx):
71 """Discard a datastore in the collection"""
72 if idx in self.locked:
73 raise Exception('Tried to release locked datastore %d' % idx)
74 del self.datastores[idx]
75
76 def receive_datastore(self, remote_data):
77 """Receive a datastore object sent from the client (as prepared by transmit_datastore())"""
78 dct = dict(remote_data)
79 d = bb.data_smart.DataSmart()
80 d.dict = dct
81 while True:
82 if '_remote_data' in dct:
83 dsindex = dct['_remote_data']['_content']
84 del dct['_remote_data']
85 if dsindex is None:
86 dct['_data'] = self.cooker.data.dict
87 else:
88 dct['_data'] = self.datastores[dsindex].dict
89 break
90 elif '_data' in dct:
91 idct = dict(dct['_data'])
92 dct['_data'] = idct
93 dct = idct
94 else:
95 break
96 return d
97
98 @staticmethod
99 def transmit_datastore(d):
100 """Prepare a datastore object for sending over IPC from the client end"""
101 # FIXME content might be a dict, need to turn that into a list as well
102 def copy_dicts(dct):
103 if '_remote_data' in dct:
104 dsindex = dct['_remote_data']['_content'].dsindex
105 newdct = dct.copy()
106 newdct['_remote_data'] = {'_content': dsindex}
107 return list(newdct.items())
108 elif '_data' in dct:
109 newdct = dct.copy()
110 newdata = copy_dicts(dct['_data'])
111 if newdata:
112 newdct['_data'] = newdata
113 return list(newdct.items())
114 return None
115 main_dict = copy_dicts(d.dict)
116 return main_dict