remotedata.py 3.2 KB

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