/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

43
43
                """
44
44
 
45
45
                # list of files that were copied-in (or at least given the opportunity
46
 
                # to be) and updated through the vcs update.  This means that, while
47
 
                # there may have been conflicts during the update (which the user will
48
 
                # have to have dealt with in the repo), any conflicts arising with these
49
 
                # files in the home directory are no longer important and can be
50
 
                # ignored.  In short, this is a list of files that can safely be
51
 
                # deployed, regardless of the state of the home directory.
52
 
                self.imported_files = None
 
46
        # to be) and updated through the vcs update.  This means that, while
 
47
        # there may have been conflicts during the update (which will be dealt
 
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.
 
52
                self.deploy_files = None
53
53
 
54
54
                # list of files that were affected by a recent vcs update (so only these
55
55
                # files need to be checked for deployment conflicts or copied-out)
67
67
                        return
68
68
 
69
69
                # read the file list
70
 
                if the.verbose >= 1: print "deployment state found; loading"
 
70
                if the.verbose: print "deployment state found; loading"
71
71
                f = open( file, 'r' )
72
72
                state = json.loads( f.read() )
73
73
 
74
74
                # unpack deployment state
75
 
                if 'imported_files' in state:
76
 
                        self.imported_files = state['imported_files'];
77
 
                if 'initial_revno' in state:
78
 
                        self.initial_revno = state['initial_revno'];
79
 
                if 'affected_files' in state:
80
 
                        self.affected_files = state['affected_files'];
 
75
                self.deploy_files = state['deploy_files'];
 
76
                self.initial_revno = state['initial_revno'];
 
77
                self.affected_files = state['affected_files'];
81
78
 
82
79
 
83
80
        def save_deployment_state( self ):
84
81
                """Save the current deployment state (so there will be a deployment ongoing).
85
82
                """
86
83
 
87
 
                if the.verbose >= 1: print "saving deployment state"
 
84
                if the.verbose: print "saving deployment state"
88
85
 
89
86
                # create metadata directory, as necessary
90
87
                if not os.path.isdir( the.full_mddir ):
92
89
 
93
90
                # pack deployment state
94
91
                state = {
95
 
                        'imported_files': self.imported_files,
 
92
                        'deploy_files': self.deploy_files,
96
93
                        'initial_revno': self.initial_revno,
97
94
                        'affected_files': self.affected_files,
98
95
                }
112
109
                if( os.path.isfile( file ) ):
113
110
 
114
111
                        # delete it
115
 
                        if the.verbose >= 1: print "removing deployment state"
 
112
                        if the.verbose: print "removing deployment state"
116
113
                        os.unlink( file )
117
114
 
118
115
 
120
117
                """Is there a deployment currently ongoing?
121
118
                """
122
119
 
123
 
                return False if self.imported_files is None else True
 
120
                return False if self.deploy_files is None else True
124
121
 
125
122
 
126
123
        def check_ongoing( self, ongoing = True ):
129
126
                """
130
127
 
131
128
                if( ongoing ):
132
 
                        if self.imported_files is None:
 
129
                        if self.deploy_files is None:
133
130
                                raise self.DeploymentOngoing( False )
134
131
                else:
135
 
                        if self.imported_files is not None:
 
132
                        if self.deploy_files is not None:
136
133
                                raise self.DeploymentOngoing( True )
137
134
 
138
135
 
153
150
 
154
151
                # if the repo doesn't exist, we have an empty file list
155
152
                if not os.path.exists( the.repo.full_dir ):
156
 
                        self.imported_files = list()
 
153
                        self.deploy_files = list()
157
154
                else:
158
155
                        # copy in
159
 
                        if the.verbose >= 1: print "importing files..."
 
156
                        if the.verbose: print "importing files..."
160
157
                        walker = CopyInWalker()
161
158
                        walker.walk()
162
 
                        self.imported_files = walker.walk_list
 
159
                        if( walker.changed ):
 
160
                                raise self.CopyInConflicts( walker.changed )
 
161
                        self.deploy_files = walker.walk_list
163
162
 
164
163
                        # obtain initial revno
165
164
                        self.initial_revno = the.repo.vcs.get_revno()
169
168
 
170
169
 
171
170
        def get_conflicts( self, affected_files = None ):
172
 
                """Check to see if there are any deployment conflicts.  If a list of affected
 
171
                """Check to see if there are any delpoyment conflicts.  If a list of affected
173
172
                files is supplied, then only those files are checked (and they are also
174
173
                saved with the deployment state).  Otherwise, all files in the
175
174
                repository are checked.
184
183
                        self.save_deployment_state()
185
184
 
186
185
                # check for deployment conflicts
187
 
                walker = ConflictWalker( self.imported_files, self.affected_files )
 
186
                walker = ConflictWalker( self.deploy_files, self.affected_files )
188
187
                walker.walk()
189
188
 
190
189
                self.conflicts_checked = True
191
190
                return walker.changed + walker.obstructed
192
191
 
193
192
 
194
 
        def copy_out( self, quiet ):
195
 
                """Copy-out changed files from the repository to the home directory.  If the
196
 
                deployment state includes a list of affected files, then only those
197
 
                files are copied-out.
 
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.
198
197
                """
199
198
 
200
199
                # check we have a file list
205
204
                        raise RuntimeError('logic error: deployment conflicts unchecked' )
206
205
 
207
206
                # copy out
208
 
                if the.verbose >= 1: print "exporting files..."
209
 
                walker = CopyOutWalker( self.affected_files, not quiet )
 
207
                if the.verbose: print "exporting files..."
 
208
                walker = CopyOutWalker( self.affected_files )
210
209
                walker.walk()
211
210
 
212
211
                # clear state
220
219
                                self.msg = "there is an ongoing deployment"
221
220
                        else:
222
221
                                self.msg = "there is no ongoing deployment"
 
222
 
 
223
 
 
224
        class CopyInConflicts( the.program.FatalError ):
 
225
 
 
226
                def __init__( self, conflicts ):
 
227
                        self.conflicts = conflicts