3
# Copyright (C) 2013 to 2014 Tim Marston <tim@edm.am>
5
# This file is part of stdhome (hereafter referred to as "this program").
6
# See http://ed.am/dev/stdhome for more information.
8
# This program is free software: you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation, either version 3 of the License, or
11
# (at your option) any later version.
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
18
# You should have received a copy of the GNU General Public License
19
# along with this program. If not, see <http://www.gnu.org/licenses/>.
22
import os, re, shutil, filecmp, json
24
from walker.copy_in_walker import CopyInWalker
25
from walker.conflict_walker import ConflictWalker
26
from walker.copy_out_walker import CopyOutWalker
32
self.load_deployment_state()
33
self.conflicts_checked = False
36
def load_deployment_state( self ):
38
# list of files that were copied-in (or at least given the opportunity
39
# to be) and updated through the vcs update. This means that, while
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 affected by a recent vcs update (so only these
49
# need to be checked for deployment conflicts or copied-out)
50
self.affected_files = None
53
if not os.path.exists( the.repo.full_dir ): return
55
# if no file list exists, we're done
56
file = os.path.join( the.full_mddir, "deploy.%s" % the.repo.name )
57
if not os.path.isfile( file ):
61
if the.verbose: print "loading deployment state"
63
state = json.loads( f.read() )
65
# unpack deployment state
66
self.deploy_files = state['deploy_files'];
67
self.affected_files = state['affected_files'];
70
def save_deployment_state( self ):
71
if the.verbose: print "saving deployment state"
73
# create metadata directory, as necessary
74
if not os.path.isdir( the.full_mddir ):
75
os.mkdir( the.full_mddir )
77
# pack deployment state
79
'deploy_files': self.deploy_files,
80
'affected_files': self.affected_files,
84
file = os.path.join( the.full_mddir, "deploy.%s" % the.repo.name )
86
f.write( json.dumps( state ) );
89
def remove_deployment_state( self ):
92
file = os.path.join( the.full_mddir, "deploy.%s" % the.repo.name )
93
if( os.path.isfile( file ) ):
96
if the.verbose: print "removing deployment state"
100
def is_ongoing( self ):
101
return False if self.deploy_files is None else True
104
def check_ongoing( self, ongoing = True ):
106
if self.deploy_files is None:
107
raise self.DeploymentOngoing( False )
109
if self.deploy_files is not None:
110
raise self.DeploymentOngoing( True )
115
# check we don't already have a file list
116
self.check_ongoing( False )
118
# if the repo doesn't exist, we have an empty file list
119
if not os.path.exists( the.repo.full_dir ):
120
self.deploy_files = list()
123
if the.verbose: print "importing files..."
124
walker = CopyInWalker()
126
if( walker.changed ):
127
raise self.CopyInConflicts( walker.changed )
128
self.deploy_files = walker.walk_list
131
self.save_deployment_state()
134
def get_conflicts( self, affected_files = None ):
136
# check we have a file list
137
self.check_ongoing( True )
140
if affected_files is not None:
141
self.affected_files = affected_files
142
self.save_deployment_state()
144
# check for deployment conflicts
145
walker = ConflictWalker( self.deploy_files, self.affected_files )
148
self.conflicts_checked = True
149
return walker.changed
152
def copy_out( self ):
154
# check we have a file list
155
self.check_ongoing( True )
157
# check that deployment conflicts have been checked-for
158
if not self.conflicts_checked:
159
raise RuntimeError('logic error: deployment conflicts unchecked' )
162
if the.verbose: print "exporting files..."
163
walker = CopyOutWalker( self.affected_files )
167
self.remove_deployment_state()
170
class DeploymentOngoing( the.program.FatalError ):
172
def __init__( self, ongoing ):
174
self.msg = "there is an ongoing deployment"
176
self.msg = "there is no ongoing deployment"
179
class CopyInConflicts( the.program.FatalError ):
181
def __init__( self, conflicts ):
182
self.conflicts = conflicts