22
22
import os, re, shutil, filecmp, json
24
from walker.copy_in import CopyInWalker
25
from walker.conflict import ConflictWalker
26
from walker.copy_out import CopyOutWalker
24
from walker.copy_in_walker import CopyInWalker
25
from walker.conflict_walker import ConflictWalker
26
from walker.copy_out_walker import CopyOutWalker
32
31
def __init__( self ):
34
raise RuntimeError( 'logic error: Deployment initialised when '
36
32
self.load_deployment_state()
37
33
self.conflicts_checked = False
40
36
def load_deployment_state( self ):
41
"""Load any deployment state. If one is found then a deployment will be
42
considered to be ongoing.
45
38
# list of files that were copied-in (or at least given the opportunity
46
39
# 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
54
# list of files that were affected by a recent vcs update (so only these
55
# files need to be checked for deployment conflicts or copied-out)
56
self.affected_files = None
58
# the revno that the repo was as prior to a recent update
59
self.initial_revno = None
40
# 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.
46
self.deploy_files = None
48
# list of files that were changed by a recent vcs update (so only these
49
# need to be checked for deployment conflicts or copied-out)
50
self.updated_files = None
61
52
# do we have a repo?
62
53
if not os.path.exists( the.repo.full_dir ): return
69
60
# read the file list
70
if the.verbose >= 1: print "deployment state found; loading"
61
if the.verbose: print "loading deployment state"
71
62
f = open( file, 'r' )
72
63
state = json.loads( f.read() )
74
65
# unpack deployment state
75
self.imported_files = state['imported_files'];
76
self.initial_revno = state['initial_revno'];
77
self.affected_files = state['affected_files'];
66
self.deploy_files = state['deploy_files'];
67
self.updated_files = state['updated_files'];
80
70
def save_deployment_state( self ):
81
"""Save the current deployment state (so there will be a deployment ongoing).
84
if the.verbose >= 1: print "saving deployment state"
71
if the.verbose: print "saving deployment state"
86
73
# create metadata directory, as necessary
87
74
if not os.path.isdir( the.full_mddir ):
103
89
def remove_deployment_state( self ):
104
"""Remove the current deployment state (so no deployment will be ongoing).
108
92
file = os.path.join( the.full_mddir, "deploy.%s" % the.repo.name )
109
93
if( os.path.isfile( file ) ):
112
if the.verbose >= 1: print "removing deployment state"
96
if the.verbose: print "removing deployment state"
116
100
def is_ongoing( self ):
117
"""Is there a deployment currently ongoing?
120
return False if self.imported_files is None else True
101
return False if self.deploy_files is None else True
123
104
def check_ongoing( self, ongoing = True ):
124
"""Check that a deployment either is or is not ongoing and raise an error if
129
if self.imported_files is None:
106
if self.deploy_files is None:
130
107
raise self.DeploymentOngoing( False )
132
if self.imported_files is not None:
109
if self.deploy_files is not None:
133
110
raise self.DeploymentOngoing( True )
136
def get_initial_revno( self ):
137
"""Get the initial revision identifier from the deployment state.
140
return self.initial_revno
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.
148
115
# check we don't already have a file list
149
116
self.check_ongoing( False )
151
118
# if the repo doesn't exist, we have an empty file list
152
119
if not os.path.exists( the.repo.full_dir ):
153
self.imported_files = list()
120
self.deploy_files = list()
156
if the.verbose >= 1: print "importing files..."
123
if the.verbose: print "importing files..."
157
124
walker = CopyInWalker()
159
self.imported_files = walker.walk_list
161
# obtain initial revno
162
self.initial_revno = the.repo.vcs.get_revno()
126
if( walker.changed ):
127
raise self.CopyInConflicts( walker.changed )
128
self.deploy_files = walker.walk_list
165
131
self.save_deployment_state()
168
def get_conflicts( self, affected_files = None ):
169
"""Check to see if there are any deployment conflicts. If a list of affected
170
files is supplied, then only those files are checked (and they are also
171
saved with the deployment state). Otherwise, all files in the
172
repository are checked.
134
def get_conflicts( self, updated_files = None ):
175
136
# check we have a file list
176
137
self.check_ongoing( True )
178
139
# set updated files
179
if affected_files is not None:
180
self.affected_files = affected_files
140
if updated_files is not None:
141
self.updated_files = updated_files
181
142
self.save_deployment_state()
183
144
# check for deployment conflicts
184
walker = ConflictWalker( self.imported_files, self.affected_files )
145
walker = ConflictWalker( self.deploy_files, self.updated_files )
187
148
self.conflicts_checked = True
188
return walker.changed + walker.obstructed
149
return walker.changed
191
152
def copy_out( self ):
192
"""Copy-out changed files from the repository to the home directory. If the
193
deployment state includes a list of affected files, then only those
194
files are copied-out.
197
154
# check we have a file list
198
155
self.check_ongoing( True )