1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

# This file is part of Buildbot.  Buildbot is free software: you can 

# redistribute it and/or modify it under the terms of the GNU General Public 

# License as published by the Free Software Foundation, version 2. 

# 

# This program is distributed in the hope that it will be useful, but WITHOUT 

# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 

# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 

# details. 

# 

# You should have received a copy of the GNU General Public License along with 

# this program; if not, write to the Free Software Foundation, Inc., 51 

# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 

# 

# Copyright Buildbot Team Members 

 

from twisted.python import failure 

from twisted.internet import defer 

from buildbot.schedulers import base 

from buildbot.process.properties import Properties 

 

class Triggerable(base.BaseScheduler): 

 

    compare_attrs = base.BaseScheduler.compare_attrs 

 

    def __init__(self, name, builderNames, properties={}): 

        base.BaseScheduler.__init__(self, name, builderNames, properties) 

        self._waiters = {} 

        self._bsc_subscription = None 

        self.reason = "Triggerable(%s)" % name 

 

    def trigger(self, ss_setid, set_props=None): 

        """Trigger this scheduler with the given sourcestampset ID. Returns a 

        deferred that will fire when the buildset is finished.""" 

        # properties for this buildset are composed of our own properties, 

        # potentially overridden by anything from the triggering build 

        props = Properties() 

        props.updateFromProperties(self.properties) 

        if set_props: 

            props.updateFromProperties(set_props) 

 

        # note that this does not use the buildset subscriptions mechanism, as 

        # the duration of interest to the caller is bounded by the lifetime of 

        # this process. 

        if ss_setid: 

            d = self.addBuildsetForSourceStamp(reason=self.reason, setid=ss_setid, 

                    properties=props) 

        else: 

            d = self.addBuildsetForLatest(reason=self.reason, properties=props) 

        def setup_waiter((bsid,brids)): 

            d = defer.Deferred() 

            self._waiters[bsid] = (d, brids) 

            self._updateWaiters() 

            return d 

        d.addCallback(setup_waiter) 

        return d 

 

    def stopService(self): 

        # cancel any outstanding subscription 

        if self._bsc_subscription: 

            self._bsc_subscription.unsubscribe() 

            self._bsc_subscription = None 

 

        # and errback any outstanding deferreds 

        if self._waiters: 

            msg = 'Triggerable scheduler stopped before build was complete' 

            for d, brids in self._waiters.values(): 

                d.errback(failure.Failure(RuntimeError(msg))) 

            self._waiters = {} 

 

        return base.BaseScheduler.stopService(self) 

 

    def _updateWaiters(self): 

        if self._waiters and not self._bsc_subscription: 

            self._bsc_subscription = \ 

                    self.master.subscribeToBuildsetCompletions( 

                                                self._buildsetComplete) 

        elif not self._waiters and self._bsc_subscription: 

            self._bsc_subscription.unsubscribe() 

            self._bsc_subscription = None 

 

    def _buildsetComplete(self, bsid, result): 

        if bsid not in self._waiters: 

            return 

 

        # pop this bsid from the waiters list, and potentially unsubscribe 

        # from completion notifications 

        d, brids = self._waiters.pop(bsid) 

        self._updateWaiters() 

 

        # fire the callback to indicate that the triggered build is complete 

        d.callback((result, brids))