Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 1 | """ |
| 2 | BitBake 'remotedata' module |
| 3 | |
| 4 | Provides support for using a datastore from the bitbake client |
| 5 | """ |
| 6 | |
| 7 | # Copyright (C) 2016 Intel Corporation |
| 8 | # |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 9 | # SPDX-License-Identifier: GPL-2.0-only |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 10 | # |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 11 | |
| 12 | import bb.data |
| 13 | |
| 14 | class 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 |