bzr branch
http://bzr.ed.am/stdhome
2
by Tim Marston
added global objects (the.repo, the.program), deployment object and implemented |
1 |
# deployment.py |
2 |
# |
|
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
3 |
# Copyright (C) 2013 to 2014 Tim Marston <tim@edm.am> |
2
by Tim Marston
added global objects (the.repo, the.program), deployment object and implemented |
4 |
# |
5 |
# This file is part of stdhome (hereafter referred to as "this program"). |
|
6 |
# See http://ed.am/dev/stdhome for more information. |
|
7 |
# |
|
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. |
|
12 |
# |
|
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. |
|
17 |
# |
|
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/>. |
|
20 |
||
21 |
||
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
22 |
import os, re, shutil, filecmp, json |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
23 |
import the, util |
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
24 |
from walker.copy_in import CopyInWalker |
25 |
from walker.conflict import ConflictWalker |
|
26 |
from walker.copy_out import CopyOutWalker |
|
27 |
||
2
by Tim Marston
added global objects (the.repo, the.program), deployment object and implemented |
28 |
|
29 |
class Deployment: |
|
30 |
||
31 |
||
32 |
def __init__( self ): |
|
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
33 |
if the.repo is None: |
34 |
raise RuntimeError( 'logic error: Deployment initialised when ' |
|
35 |
'the.repo is unset' ) |
|
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
36 |
self.load_deployment_state() |
37 |
self.conflicts_checked = False |
|
38 |
||
39 |
||
40 |
def load_deployment_state( self ): |
|
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
41 |
"""Load any deployment state. If one is found then a deployment will be |
42 |
considered to be ongoing. |
|
43 |
""" |
|
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
44 |
|
45 |
# list of files that were copied-in (or at least given the opportunity |
|
50
by Tim Marston
added checks to not die when information is missing in deployment |
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. |
|
30
by Tim Marston
minor tweaks to variable names and comments |
52 |
self.imported_files = None |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
53 |
|
6
by Tim Marston
renamed updated_files to affected_files |
54 |
# list of files that were affected by a recent vcs update (so only these |
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
55 |
# files need to be checked for deployment conflicts or copied-out) |
6
by Tim Marston
renamed updated_files to affected_files |
56 |
self.affected_files = None |
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
57 |
|
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
58 |
# the revno that the repo was as prior to a recent update |
59 |
self.initial_revno = None |
|
60 |
||
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
61 |
# do we have a repo? |
62 |
if not os.path.exists( the.repo.full_dir ): return |
|
63 |
||
64 |
# if no file list exists, we're done |
|
65 |
file = os.path.join( the.full_mddir, "deploy.%s" % the.repo.name ) |
|
66 |
if not os.path.isfile( file ): |
|
67 |
return |
|
68 |
||
69 |
# read the file list |
|
35
by Tim Marston
made checks for verbose >= 1 explicit |
70 |
if the.verbose >= 1: print "deployment state found; loading" |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
71 |
f = open( file, 'r' ) |
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
72 |
state = json.loads( f.read() ) |
73 |
||
74 |
# unpack deployment state |
|
50
by Tim Marston
added checks to not die when information is missing in deployment |
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']; |
|
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
81 |
|
82 |
||
83 |
def save_deployment_state( self ): |
|
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
84 |
"""Save the current deployment state (so there will be a deployment ongoing). |
85 |
""" |
|
86 |
||
35
by Tim Marston
made checks for verbose >= 1 explicit |
87 |
if the.verbose >= 1: print "saving deployment state" |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
88 |
|
89 |
# create metadata directory, as necessary |
|
90 |
if not os.path.isdir( the.full_mddir ): |
|
91 |
os.mkdir( the.full_mddir ) |
|
92 |
||
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
93 |
# pack deployment state |
94 |
state = { |
|
30
by Tim Marston
minor tweaks to variable names and comments |
95 |
'imported_files': self.imported_files, |
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
96 |
'initial_revno': self.initial_revno, |
6
by Tim Marston
renamed updated_files to affected_files |
97 |
'affected_files': self.affected_files, |
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
98 |
} |
99 |
||
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
100 |
# create file |
101 |
file = os.path.join( the.full_mddir, "deploy.%s" % the.repo.name ) |
|
102 |
f = open( file, 'w' ) |
|
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
103 |
f.write( json.dumps( state ) ); |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
104 |
|
105 |
||
106 |
def remove_deployment_state( self ): |
|
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
107 |
"""Remove the current deployment state (so no deployment will be ongoing). |
108 |
""" |
|
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
109 |
|
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
110 |
# check it exists |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
111 |
file = os.path.join( the.full_mddir, "deploy.%s" % the.repo.name ) |
112 |
if( os.path.isfile( file ) ): |
|
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
113 |
|
114 |
# delete it |
|
35
by Tim Marston
made checks for verbose >= 1 explicit |
115 |
if the.verbose >= 1: print "removing deployment state" |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
116 |
os.unlink( file ) |
117 |
||
118 |
||
119 |
def is_ongoing( self ): |
|
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
120 |
"""Is there a deployment currently ongoing? |
121 |
""" |
|
122 |
||
30
by Tim Marston
minor tweaks to variable names and comments |
123 |
return False if self.imported_files is None else True |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
124 |
|
125 |
||
126 |
def check_ongoing( self, ongoing = True ): |
|
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
127 |
"""Check that a deployment either is or is not ongoing and raise an error if |
128 |
not. |
|
129 |
""" |
|
130 |
||
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
131 |
if( ongoing ): |
30
by Tim Marston
minor tweaks to variable names and comments |
132 |
if self.imported_files is None: |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
133 |
raise self.DeploymentOngoing( False ) |
2
by Tim Marston
added global objects (the.repo, the.program), deployment object and implemented |
134 |
else: |
30
by Tim Marston
minor tweaks to variable names and comments |
135 |
if self.imported_files is not None: |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
136 |
raise self.DeploymentOngoing( True ) |
137 |
||
138 |
||
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
139 |
def get_initial_revno( self ): |
140 |
"""Get the initial revision identifier from the deployment state. |
|
141 |
""" |
|
142 |
||
143 |
return self.initial_revno |
|
144 |
||
145 |
||
146 |
def copy_in( self, initial_revno = None ): |
|
147 |
"""Copy-in changes from the home directory to the repository. When finished, |
|
148 |
the state of deployment is saved, meaning that a deployment is ongoing. |
|
149 |
""" |
|
2
by Tim Marston
added global objects (the.repo, the.program), deployment object and implemented |
150 |
|
151 |
# check we don't already have a file list |
|
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
152 |
self.check_ongoing( False ) |
153 |
||
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
154 |
# if the repo doesn't exist, we have an empty file list |
155 |
if not os.path.exists( the.repo.full_dir ): |
|
30
by Tim Marston
minor tweaks to variable names and comments |
156 |
self.imported_files = list() |
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
157 |
else: |
158 |
# copy in |
|
35
by Tim Marston
made checks for verbose >= 1 explicit |
159 |
if the.verbose >= 1: print "importing files..." |
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
160 |
walker = CopyInWalker() |
161 |
walker.walk() |
|
30
by Tim Marston
minor tweaks to variable names and comments |
162 |
self.imported_files = walker.walk_list |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
163 |
|
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
164 |
# obtain initial revno |
165 |
self.initial_revno = the.repo.vcs.get_revno() |
|
166 |
||
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
167 |
# save state |
168 |
self.save_deployment_state() |
|
2
by Tim Marston
added global objects (the.repo, the.program), deployment object and implemented |
169 |
|
170 |
||
6
by Tim Marston
renamed updated_files to affected_files |
171 |
def get_conflicts( self, affected_files = None ): |
30
by Tim Marston
minor tweaks to variable names and comments |
172 |
"""Check to see if there are any deployment conflicts. If a list of affected |
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
173 |
files is supplied, then only those files are checked (and they are also |
174 |
saved with the deployment state). Otherwise, all files in the |
|
175 |
repository are checked. |
|
176 |
""" |
|
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
177 |
|
178 |
# check we have a file list |
|
179 |
self.check_ongoing( True ) |
|
180 |
||
181 |
# set updated files |
|
6
by Tim Marston
renamed updated_files to affected_files |
182 |
if affected_files is not None: |
183 |
self.affected_files = affected_files |
|
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
184 |
self.save_deployment_state() |
185 |
||
186 |
# check for deployment conflicts |
|
30
by Tim Marston
minor tweaks to variable names and comments |
187 |
walker = ConflictWalker( self.imported_files, self.affected_files ) |
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
188 |
walker.walk() |
189 |
||
190 |
self.conflicts_checked = True |
|
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
191 |
return walker.changed + walker.obstructed |
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
192 |
|
193 |
||
61
by Tim Marston
added home directory change reporting to CopyOutWalker; added --quiet option to |
194 |
def copy_out( self, quiet ): |
30
by Tim Marston
minor tweaks to variable names and comments |
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. |
|
8
by Tim Marston
added diff command; moved all command to commands subdir; made stage-revert |
198 |
""" |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
199 |
|
200 |
# check we have a file list |
|
201 |
self.check_ongoing( True ) |
|
202 |
||
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
203 |
# check that deployment conflicts have been checked-for |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
204 |
if not self.conflicts_checked: |
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
205 |
raise RuntimeError('logic error: deployment conflicts unchecked' ) |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
206 |
|
207 |
# copy out |
|
35
by Tim Marston
made checks for verbose >= 1 explicit |
208 |
if the.verbose >= 1: print "exporting files..." |
82
by Tim Marston
added general reporting to CopyBase and configured it via copy-in and copy-out |
209 |
walker = CopyOutWalker( self.affected_files, not quiet ) |
5
by Tim Marston
moved copy-in, copy-out and deployment conflict checking to a set of "walkers"; |
210 |
walker.walk() |
3
by Tim Marston
added bzr as a vcs backend; finished init command; implemented deployment |
211 |
|
212 |
# clear state |
|
213 |
self.remove_deployment_state() |
|
214 |
||
215 |
||
216 |
class DeploymentOngoing( the.program.FatalError ): |
|
217 |
||
218 |
def __init__( self, ongoing ): |
|
219 |
if( ongoing ): |
|
220 |
self.msg = "there is an ongoing deployment" |
|
221 |
else: |
|
222 |
self.msg = "there is no ongoing deployment" |