/stdhome

To get this branch, use:
bzr branch http://bzr.ed.am/stdhome

« back to all changes in this revision

Viewing changes to lib/stdhome/deployment.py

  • Committer: Tim Marston
  • Date: 2014-03-08 00:47:23 UTC
  • Revision ID: tim@ed.am-20140308004723-hkl3s2hobsblf72o
added diff command; moved all command to commands subdir; made stage-revert
handle ongoing deployment automatically (now that initial revno is known); made
verbose level incremental; detect obstructing conflicts in ConflictWalker;
handle files deleted from repo during copy-out (update)

Show diffs side-by-side

added added

removed removed

21
21
 
22
22
import os, re, shutil, filecmp, json
23
23
import the, util
24
 
from walker.copy_in_walker import CopyInWalker
25
 
from walker.conflict_walker import ConflictWalker
26
 
from walker.copy_out_walker import CopyOutWalker
 
24
from walker.copy_in import CopyInWalker
 
25
from walker.conflict import ConflictWalker
 
26
from walker.copy_out import CopyOutWalker
 
27
 
27
28
 
28
29
class Deployment:
29
30
 
30
31
 
31
32
        def __init__( self ):
 
33
                if the.repo is None:
 
34
                        raise RuntimeError( 'logic error: Deployment initialised when '
 
35
                                                                'the.repo is unset' )
32
36
                self.load_deployment_state()
33
37
                self.conflicts_checked = False
34
38
 
35
39
 
36
40
        def load_deployment_state( self ):
 
41
                """Load any deployment state.  If one is found then a deployment will be
 
42
                considered to be ongoing.
 
43
                """
37
44
 
38
45
                # list of files that were copied-in (or at least given the opportunity
39
46
        # to be) and updated through the vcs update.  This means that, while
40
47
        # there may have been conflicts during the update (which will be dealt
41
 
        # with in the repo), any arising conflicts with the filesystem are now
42
 
        # assumed to be because of the vcs update and can be ignored (that is to
43
 
        # say, we no longer care about the file in the home directory).  In
44
 
        # short, this is a list of files that it is safe to deploy, regardless
45
 
        # of the state of the filesystem.
 
48
        # with in the repo), any conflicts arising with these files in the home
 
49
        # directory are no longer important and can be ignored.  In short, this
 
50
        # is a list of files that it is safe to deploy, regardless of their
 
51
        # state in the home directory.
46
52
                self.deploy_files = None
47
53
 
48
54
                # list of files that were affected by a recent vcs update (so only these
49
 
                # need to be checked for deployment conflicts or copied-out)
 
55
                # files need to be checked for deployment conflicts or copied-out)
50
56
                self.affected_files = None
51
57
 
 
58
                # the revno that the repo was as prior to a recent update
 
59
                self.initial_revno = None
 
60
 
52
61
                # do we have a repo?
53
62
                if not os.path.exists( the.repo.full_dir ): return
54
63
 
58
67
                        return
59
68
 
60
69
                # read the file list
61
 
                if the.verbose: print "loading deployment state"
 
70
                if the.verbose: print "deployment state found; loading"
62
71
                f = open( file, 'r' )
63
72
                state = json.loads( f.read() )
64
73
 
65
74
                # unpack deployment state
66
75
                self.deploy_files = state['deploy_files'];
 
76
                self.initial_revno = state['initial_revno'];
67
77
                self.affected_files = state['affected_files'];
68
78
 
69
79
 
70
80
        def save_deployment_state( self ):
 
81
                """Save the current deployment state (so there will be a deployment ongoing).
 
82
                """
 
83
 
71
84
                if the.verbose: print "saving deployment state"
72
85
 
73
86
                # create metadata directory, as necessary
77
90
                # pack deployment state
78
91
                state = {
79
92
                        'deploy_files': self.deploy_files,
 
93
                        'initial_revno': self.initial_revno,
80
94
                        'affected_files': self.affected_files,
81
95
                }
82
96
 
87
101
 
88
102
 
89
103
        def remove_deployment_state( self ):
 
104
                """Remove the current deployment state (so no deployment will be ongoing).
 
105
                """
90
106
 
91
107
                # check it exists
92
108
                file = os.path.join( the.full_mddir, "deploy.%s" % the.repo.name )
98
114
 
99
115
 
100
116
        def is_ongoing( self ):
 
117
                """Is there a deployment currently ongoing?
 
118
                """
 
119
 
101
120
                return False if self.deploy_files is None else True
102
121
 
103
122
 
104
123
        def check_ongoing( self, ongoing = True ):
 
124
                """Check that a deployment either is or is not ongoing and raise an error if
 
125
                not.
 
126
                """
 
127
 
105
128
                if( ongoing ):
106
129
                        if self.deploy_files is None:
107
130
                                raise self.DeploymentOngoing( False )
110
133
                                raise self.DeploymentOngoing( True )
111
134
 
112
135
 
113
 
        def copy_in( self ):
 
136
        def get_initial_revno( self ):
 
137
                """Get the initial revision identifier from the deployment state.
 
138
                """
 
139
 
 
140
                return self.initial_revno
 
141
 
 
142
 
 
143
        def copy_in( self, initial_revno = None ):
 
144
                """Copy-in changes from the home directory to the repository.  When finished,
 
145
                the state of deployment is saved, meaning that a deployment is ongoing.
 
146
                """
114
147
 
115
148
                # check we don't already have a file list
116
149
                self.check_ongoing( False )
127
160
                                raise self.CopyInConflicts( walker.changed )
128
161
                        self.deploy_files = walker.walk_list
129
162
 
 
163
                        # obtain initial revno
 
164
                        self.initial_revno = the.repo.vcs.get_revno()
 
165
 
130
166
                # save state
131
167
                self.save_deployment_state()
132
168
 
133
169
 
134
170
        def get_conflicts( self, affected_files = None ):
 
171
                """Check to see if there are any delpoyment conflicts.  If a list of affected
 
172
                files is supplied, then only those files are checked (and they are also
 
173
                saved with the deployment state).  Otherwise, all files in the
 
174
                repository are checked.
 
175
                """
135
176
 
136
177
                # check we have a file list
137
178
                self.check_ongoing( True )
146
187
                walker.walk()
147
188
 
148
189
                self.conflicts_checked = True
149
 
                return walker.changed
 
190
                return walker.changed + walker.obstructed
150
191
 
151
192
 
152
193
        def copy_out( self ):
 
194
                """Copy-out changed files frmo the repository to the home directory.  If the
 
195
                deployment state incudes a list of affected files, then only those fiels
 
196
                are copied-out.
 
197
                """
153
198
 
154
199
                # check we have a file list
155
200
                self.check_ongoing( True )