diff options
author | Paul Eggleton <paul.eggleton@linux.intel.com> | 2017-03-20 17:05:53 +1300 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2017-03-22 11:35:22 +0000 |
commit | 5b1807021e932b1150095f3d1744d8411a28a1f0 (patch) | |
tree | b949a92af026dfb0334be4fa627c48920538fa42 | |
parent | 99414bdb1c64f7f03e12c347cc16c43c2fa336b2 (diff) | |
download | poky-5b1807021e932b1150095f3d1744d8411a28a1f0.tar.gz |
bitbake: data_smart: implement missing remote datastore operations
Enable the following operations from a remote datastore to affect the
other end:
* setVarFlag()
* delVar()
* delVarFlag()
* renameVar()
In practice I don't expect these to be used much, but they should be
present so that the implementation is at least reasonably filled out
and that the tests pass.
Also add tests for the interface, mostly by subclassing the existing
local test classes so that they are using a remote datastore. (These
don't actually test remote usage via tinfoil, just that the
datastore's interface can be used.)
(Bitbake rev: 282dc0719d22a39df746eea762ebe05c66aa8f8a)
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r-- | bitbake/lib/bb/command.py | 25 | ||||
-rw-r--r-- | bitbake/lib/bb/data_smart.py | 29 | ||||
-rw-r--r-- | bitbake/lib/bb/tests/data.py | 128 | ||||
-rw-r--r-- | bitbake/lib/bb/tinfoil.py | 30 |
4 files changed, 192 insertions, 20 deletions
diff --git a/bitbake/lib/bb/command.py b/bitbake/lib/bb/command.py index 222a76e580..78a86ac4dc 100644 --- a/bitbake/lib/bb/command.py +++ b/bitbake/lib/bb/command.py | |||
@@ -505,6 +505,31 @@ class CommandsSync: | |||
505 | raise CommandError('dataStoreConnectorRelease: invalid index %d' % dsindex) | 505 | raise CommandError('dataStoreConnectorRelease: invalid index %d' % dsindex) |
506 | command.remotedatastores.release(dsindex) | 506 | command.remotedatastores.release(dsindex) |
507 | 507 | ||
508 | def dataStoreConnectorSetVarFlag(self, command, params): | ||
509 | dsindex = params[0] | ||
510 | name = params[1] | ||
511 | flag = params[2] | ||
512 | value = params[3] | ||
513 | datastore = command.remotedatastores[dsindex] | ||
514 | datastore.setVarFlag(name, flag, value) | ||
515 | |||
516 | def dataStoreConnectorDelVar(self, command, params): | ||
517 | dsindex = params[0] | ||
518 | name = params[1] | ||
519 | datastore = command.remotedatastores[dsindex] | ||
520 | if len(params) > 2: | ||
521 | flag = params[2] | ||
522 | datastore.delVarFlag(name, flag) | ||
523 | else: | ||
524 | datastore.delVar(name) | ||
525 | |||
526 | def dataStoreConnectorRenameVar(self, command, params): | ||
527 | dsindex = params[0] | ||
528 | name = params[1] | ||
529 | newname = params[2] | ||
530 | datastore = command.remotedatastores[dsindex] | ||
531 | datastore.renameVar(name, newname) | ||
532 | |||
508 | def parseRecipeFile(self, command, params): | 533 | def parseRecipeFile(self, command, params): |
509 | """ | 534 | """ |
510 | Parse the specified recipe file (with or without bbappends) | 535 | Parse the specified recipe file (with or without bbappends) |
diff --git a/bitbake/lib/bb/data_smart.py b/bitbake/lib/bb/data_smart.py index 5777d545a8..d6dd698eff 100644 --- a/bitbake/lib/bb/data_smart.py +++ b/bitbake/lib/bb/data_smart.py | |||
@@ -609,6 +609,12 @@ class DataSmart(MutableMapping): | |||
609 | """ | 609 | """ |
610 | Rename the variable key to newkey | 610 | Rename the variable key to newkey |
611 | """ | 611 | """ |
612 | if '_remote_data' in self.dict: | ||
613 | connector = self.dict["_remote_data"]["_content"] | ||
614 | res = connector.renameVar(key, newkey) | ||
615 | if not res: | ||
616 | return | ||
617 | |||
612 | val = self.getVar(key, 0, parsing=True) | 618 | val = self.getVar(key, 0, parsing=True) |
613 | if val is not None: | 619 | if val is not None: |
614 | loginfo['variable'] = newkey | 620 | loginfo['variable'] = newkey |
@@ -652,6 +658,12 @@ class DataSmart(MutableMapping): | |||
652 | self.setVar(var + "_prepend", value, ignore=True, parsing=True) | 658 | self.setVar(var + "_prepend", value, ignore=True, parsing=True) |
653 | 659 | ||
654 | def delVar(self, var, **loginfo): | 660 | def delVar(self, var, **loginfo): |
661 | if '_remote_data' in self.dict: | ||
662 | connector = self.dict["_remote_data"]["_content"] | ||
663 | res = connector.delVar(var) | ||
664 | if not res: | ||
665 | return | ||
666 | |||
655 | loginfo['detail'] = "" | 667 | loginfo['detail'] = "" |
656 | loginfo['op'] = 'del' | 668 | loginfo['op'] = 'del' |
657 | self.varhistory.record(**loginfo) | 669 | self.varhistory.record(**loginfo) |
@@ -678,6 +690,12 @@ class DataSmart(MutableMapping): | |||
678 | override = None | 690 | override = None |
679 | 691 | ||
680 | def setVarFlag(self, var, flag, value, **loginfo): | 692 | def setVarFlag(self, var, flag, value, **loginfo): |
693 | if '_remote_data' in self.dict: | ||
694 | connector = self.dict["_remote_data"]["_content"] | ||
695 | res = connector.setVarFlag(var, flag, value) | ||
696 | if not res: | ||
697 | return | ||
698 | |||
681 | self.expand_cache = {} | 699 | self.expand_cache = {} |
682 | if 'op' not in loginfo: | 700 | if 'op' not in loginfo: |
683 | loginfo['op'] = "set" | 701 | loginfo['op'] = "set" |
@@ -796,6 +814,12 @@ class DataSmart(MutableMapping): | |||
796 | return value | 814 | return value |
797 | 815 | ||
798 | def delVarFlag(self, var, flag, **loginfo): | 816 | def delVarFlag(self, var, flag, **loginfo): |
817 | if '_remote_data' in self.dict: | ||
818 | connector = self.dict["_remote_data"]["_content"] | ||
819 | res = connector.delVarFlag(var, flag) | ||
820 | if not res: | ||
821 | return | ||
822 | |||
799 | self.expand_cache = {} | 823 | self.expand_cache = {} |
800 | local_var, _ = self._findVar(var) | 824 | local_var, _ = self._findVar(var) |
801 | if not local_var: | 825 | if not local_var: |
@@ -938,7 +962,10 @@ class DataSmart(MutableMapping): | |||
938 | 962 | ||
939 | if "_remote_data" in d: | 963 | if "_remote_data" in d: |
940 | connector = d["_remote_data"]["_content"] | 964 | connector = d["_remote_data"]["_content"] |
941 | klist |= connector.getKeys() | 965 | for key in connector.getKeys(): |
966 | if key in deleted: | ||
967 | continue | ||
968 | klist.add(key) | ||
942 | 969 | ||
943 | return klist | 970 | return klist |
944 | 971 | ||
diff --git a/bitbake/lib/bb/tests/data.py b/bitbake/lib/bb/tests/data.py index da3f4e66f8..fe947f5ba7 100644 --- a/bitbake/lib/bb/tests/data.py +++ b/bitbake/lib/bb/tests/data.py | |||
@@ -460,26 +460,43 @@ class Serialize(unittest.TestCase): | |||
460 | self.assertEqual(newd.getVarFlag('HELLO', 'other'), 'planet') | 460 | self.assertEqual(newd.getVarFlag('HELLO', 'other'), 'planet') |
461 | 461 | ||
462 | 462 | ||
463 | # Remote datastore tests | ||
464 | # These really only test the interface, since in actual usage we have a | ||
465 | # tinfoil connector that does everything over RPC, and this doesn't test | ||
466 | # that. | ||
467 | |||
468 | class TestConnector: | ||
469 | d = None | ||
470 | def __init__(self, d): | ||
471 | self.d = d | ||
472 | def getVar(self, name): | ||
473 | return self.d._findVar(name) | ||
474 | def getKeys(self): | ||
475 | return set(self.d.keys()) | ||
476 | def getVarHistory(self, name): | ||
477 | return self.d.varhistory.variable(name) | ||
478 | def expandPythonRef(self, varname, expr, d): | ||
479 | localdata = self.d.createCopy() | ||
480 | for key in d.localkeys(): | ||
481 | localdata.setVar(d.getVar(key)) | ||
482 | varparse = bb.data_smart.VariableParse(varname, localdata) | ||
483 | return varparse.python_sub(expr) | ||
484 | def setVar(self, name, value): | ||
485 | self.d.setVar(name, value) | ||
486 | def setVarFlag(self, name, flag, value): | ||
487 | self.d.setVarFlag(name, flag, value) | ||
488 | def delVar(self, name): | ||
489 | self.d.delVar(name) | ||
490 | return False | ||
491 | def delVarFlag(self, name, flag): | ||
492 | self.d.delVarFlag(name, flag) | ||
493 | return False | ||
494 | def renameVar(self, name, newname): | ||
495 | self.d.renameVar(name, newname) | ||
496 | return False | ||
497 | |||
463 | class Remote(unittest.TestCase): | 498 | class Remote(unittest.TestCase): |
464 | def test_remote(self): | 499 | def test_remote(self): |
465 | class TestConnector: | ||
466 | d = None | ||
467 | def __init__(self, d): | ||
468 | self.d = d | ||
469 | def getVar(self, name): | ||
470 | return self.d._findVar(name) | ||
471 | def getKeys(self): | ||
472 | return self.d.localkeys() | ||
473 | def getVarHistory(self, name): | ||
474 | return self.d.varhistory.variable(name) | ||
475 | def expandPythonRef(self, varname, expr, d): | ||
476 | localdata = self.d.createCopy() | ||
477 | for key in d.localkeys(): | ||
478 | localdata.setVar(d.getVar(key)) | ||
479 | varparse = bb.data_smart.VariableParse(varname, localdata) | ||
480 | return varparse.python_sub(expr) | ||
481 | def setVar(self, name, value): | ||
482 | self.d.setVar(name, value) | ||
483 | 500 | ||
484 | d1 = bb.data.init() | 501 | d1 = bb.data.init() |
485 | d1.enableTracking() | 502 | d1.enableTracking() |
@@ -500,6 +517,9 @@ class Remote(unittest.TestCase): | |||
500 | # Test setVar on client side affects server | 517 | # Test setVar on client side affects server |
501 | d2.setVar('HELLO', 'other-world') | 518 | d2.setVar('HELLO', 'other-world') |
502 | self.assertEqual(d1.getVar('HELLO'), 'other-world') | 519 | self.assertEqual(d1.getVar('HELLO'), 'other-world') |
520 | # Test setVarFlag on client side affects server | ||
521 | d2.setVarFlag('HELLO', 'flagname', 'flagvalue') | ||
522 | self.assertEqual(d1.getVarFlag('HELLO', 'flagname'), 'flagvalue') | ||
503 | # Test client side data is incorporated in python expansion (which is done on server) | 523 | # Test client side data is incorporated in python expansion (which is done on server) |
504 | d2.setVar('FOO', 'bar') | 524 | d2.setVar('FOO', 'bar') |
505 | self.assertEqual(d2.expand('${@d.getVar("FOO")}'), 'bar') | 525 | self.assertEqual(d2.expand('${@d.getVar("FOO")}'), 'bar') |
@@ -507,3 +527,75 @@ class Remote(unittest.TestCase): | |||
507 | d1.setVar('FOO_test', 'baz') | 527 | d1.setVar('FOO_test', 'baz') |
508 | d1.appendVar('OVERRIDES', ':test') | 528 | d1.appendVar('OVERRIDES', ':test') |
509 | self.assertEqual(d2.getVar('FOO'), 'baz') | 529 | self.assertEqual(d2.getVar('FOO'), 'baz') |
530 | |||
531 | |||
532 | # Remote equivalents of local test classes | ||
533 | # Note that these aren't perfect since we only test in one direction | ||
534 | |||
535 | class RemoteDataExpansions(DataExpansions): | ||
536 | def setUp(self): | ||
537 | self.d1 = bb.data.init() | ||
538 | self.d = bb.data.init() | ||
539 | self.d1["foo"] = "value_of_foo" | ||
540 | self.d1["bar"] = "value_of_bar" | ||
541 | self.d1["value_of_foo"] = "value_of_'value_of_foo'" | ||
542 | connector = TestConnector(self.d1) | ||
543 | self.d.setVar('_remote_data', connector) | ||
544 | |||
545 | class TestRemoteNestedExpansions(TestNestedExpansions): | ||
546 | def setUp(self): | ||
547 | self.d1 = bb.data.init() | ||
548 | self.d = bb.data.init() | ||
549 | self.d1["foo"] = "foo" | ||
550 | self.d1["bar"] = "bar" | ||
551 | self.d1["value_of_foobar"] = "187" | ||
552 | connector = TestConnector(self.d1) | ||
553 | self.d.setVar('_remote_data', connector) | ||
554 | |||
555 | class TestRemoteConcat(TestConcat): | ||
556 | def setUp(self): | ||
557 | self.d1 = bb.data.init() | ||
558 | self.d = bb.data.init() | ||
559 | self.d1.setVar("FOO", "foo") | ||
560 | self.d1.setVar("VAL", "val") | ||
561 | self.d1.setVar("BAR", "bar") | ||
562 | connector = TestConnector(self.d1) | ||
563 | self.d.setVar('_remote_data', connector) | ||
564 | |||
565 | class TestRemoteConcatOverride(TestConcatOverride): | ||
566 | def setUp(self): | ||
567 | self.d1 = bb.data.init() | ||
568 | self.d = bb.data.init() | ||
569 | self.d1.setVar("FOO", "foo") | ||
570 | self.d1.setVar("VAL", "val") | ||
571 | self.d1.setVar("BAR", "bar") | ||
572 | connector = TestConnector(self.d1) | ||
573 | self.d.setVar('_remote_data', connector) | ||
574 | |||
575 | class TestRemoteOverrides(TestOverrides): | ||
576 | def setUp(self): | ||
577 | self.d1 = bb.data.init() | ||
578 | self.d = bb.data.init() | ||
579 | self.d1.setVar("OVERRIDES", "foo:bar:local") | ||
580 | self.d1.setVar("TEST", "testvalue") | ||
581 | connector = TestConnector(self.d1) | ||
582 | self.d.setVar('_remote_data', connector) | ||
583 | |||
584 | class TestRemoteKeyExpansion(TestKeyExpansion): | ||
585 | def setUp(self): | ||
586 | self.d1 = bb.data.init() | ||
587 | self.d = bb.data.init() | ||
588 | self.d1.setVar("FOO", "foo") | ||
589 | self.d1.setVar("BAR", "foo") | ||
590 | connector = TestConnector(self.d1) | ||
591 | self.d.setVar('_remote_data', connector) | ||
592 | |||
593 | class TestRemoteFlags(TestFlags): | ||
594 | def setUp(self): | ||
595 | self.d1 = bb.data.init() | ||
596 | self.d = bb.data.init() | ||
597 | self.d1.setVar("foo", "value of foo") | ||
598 | self.d1.setVarFlag("foo", "flag1", "value of flag1") | ||
599 | self.d1.setVarFlag("foo", "flag2", "value of flag2") | ||
600 | connector = TestConnector(self.d1) | ||
601 | self.d.setVar('_remote_data', connector) | ||
diff --git a/bitbake/lib/bb/tinfoil.py b/bitbake/lib/bb/tinfoil.py index 00cec59b83..19b41be46c 100644 --- a/bitbake/lib/bb/tinfoil.py +++ b/bitbake/lib/bb/tinfoil.py | |||
@@ -1,6 +1,6 @@ | |||
1 | # tinfoil: a simple wrapper around cooker for bitbake-based command-line utilities | 1 | # tinfoil: a simple wrapper around cooker for bitbake-based command-line utilities |
2 | # | 2 | # |
3 | # Copyright (C) 2012-2016 Intel Corporation | 3 | # Copyright (C) 2012-2017 Intel Corporation |
4 | # Copyright (C) 2011 Mentor Graphics Corporation | 4 | # Copyright (C) 2011 Mentor Graphics Corporation |
5 | # | 5 | # |
6 | # This program is free software; you can redistribute it and/or modify | 6 | # This program is free software; you can redistribute it and/or modify |
@@ -84,6 +84,34 @@ class TinfoilDataStoreConnector: | |||
84 | # Not currently implemented - indicate that setting should | 84 | # Not currently implemented - indicate that setting should |
85 | # be redirected to local side | 85 | # be redirected to local side |
86 | return True | 86 | return True |
87 | def setVarFlag(self, varname, flagname, value): | ||
88 | if self.dsindex is None: | ||
89 | self.tinfoil.run_command('dataStoreConnectorSetVarFlag', self.dsindex, varname, flagname, value) | ||
90 | else: | ||
91 | # Not currently implemented - indicate that setting should | ||
92 | # be redirected to local side | ||
93 | return True | ||
94 | def delVar(self, varname): | ||
95 | if self.dsindex is None: | ||
96 | self.tinfoil.run_command('dataStoreConnectorDelVar', self.dsindex, varname) | ||
97 | else: | ||
98 | # Not currently implemented - indicate that setting should | ||
99 | # be redirected to local side | ||
100 | return True | ||
101 | def delVarFlag(self, varname, flagname): | ||
102 | if self.dsindex is None: | ||
103 | self.tinfoil.run_command('dataStoreConnectorDelVar', self.dsindex, varname, flagname) | ||
104 | else: | ||
105 | # Not currently implemented - indicate that setting should | ||
106 | # be redirected to local side | ||
107 | return True | ||
108 | def renameVar(self, name, newname): | ||
109 | if self.dsindex is None: | ||
110 | self.tinfoil.run_command('dataStoreConnectorRenameVar', self.dsindex, name, newname) | ||
111 | else: | ||
112 | # Not currently implemented - indicate that setting should | ||
113 | # be redirected to local side | ||
114 | return True | ||
87 | 115 | ||
88 | class TinfoilCookerAdapter: | 116 | class TinfoilCookerAdapter: |
89 | """ | 117 | """ |