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 | # |
| 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 | |
| 22 | import bb.data |
| 23 | |
| 24 | class 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 |